#!/usr/bin/perl

# BEGIN DATAPACK CODE
{
    my $toc;
    my $data_linepos = 1;
    unshift @INC, sub {
        $toc ||= do {

            my $fh = \*DATA;

        my $header_line;
        my $header_found;
        while (1) {
            my $header_line = <$fh>;
            defined($header_line)
                or die "Unexpected end of data section while reading header line";
            chomp($header_line);
            if ($header_line eq 'Data::Section::Seekable v1') {
                $header_found++;
                last;
            }
        }
        die "Can't find header 'Data::Section::Seekable v1'"
            unless $header_found;

        my %toc;
        my $i = 0;
        while (1) {
            $i++;
            my $toc_line = <$fh>;
            defined($toc_line)
                or die "Unexpected end of data section while reading TOC line #$i";
            chomp($toc_line);
            $toc_line =~ /\S/ or last;
            $toc_line =~ /^([^,]+),(\d+),(\d+)(?:,(.*))?$/
                or die "Invalid TOC line #$i in data section: $toc_line";
            $toc{$1} = [$2, $3, $4];
        }
        my $pos = tell $fh;
        $toc{$_}[0] += $pos for keys %toc;


            # calculate the line number of data section
            my $data_pos = tell(DATA);
            seek DATA, 0, 0;
            my $pos = 0;
            while (1) {
                my $line = <DATA>;
                $pos += length($line);
                $data_linepos++;
                last if $pos >= $data_pos;
            }
            seek DATA, $data_pos, 0;

            \%toc;
        };
        if ($toc->{$_[1]}) {
            seek DATA, $toc->{$_[1]}[0], 0;
            read DATA, my($content), $toc->{$_[1]}[1];
            my ($order, $lineoffset) = split(';', $toc->{$_[1]}[2]);
            $content =~ s/^ //gm;
            $content = "# line ".($data_linepos + $order+1 + $lineoffset)." \"".__FILE__."\"\n" . $content;
            open my $fh, '<', \$content
                or die "DataPacker error loading $_[1]: $!";
            return $fh;
        }
        return;
    };
}
# END DATAPACK CODE

our $DATE = '2015-10-21'; # DATE
our $DIST = 'File-RsyBak'; # DIST
our $VERSION = '0.28'; # VERSION

use 5.010001;
use strict;
use warnings;

require Perinci::CmdLine::Classic;

Perinci::CmdLine::Classic->new(
    url => "/File/RsyBak/backup",
    program_name => "rsybak",
)->run;

# ABSTRACT: Backup files/directories with histories, using rsync
# PODNAME: rsybak

__END__

=pod

=encoding UTF-8

=head1 NAME

rsybak - Backup files/directories with histories, using rsync

=head1 VERSION

This document describes version 0.28 of rsybak (from Perl distribution File-RsyBak), released on 2015-10-21.

=head1 SYNOPSIS

Usage:

 % rsybak [options] <source> <target>

Examples:

 % rsybak /home/jajang/mydata /backup/jajang/mydata
 ERROR 500: Error: Can't create target directory : No such file or directory

=head1 COMPLETION

This script has shell tab completion capability with support for several
shells.

=head2 bash

To activate bash completion for this script, put:

 complete -C rsybak rsybak

in your bash startup (e.g. C<~/.bashrc>). Your next shell session will then
recognize tab completion for the command. Or, you can also directly execute the
line above in your shell to activate immediately.

It is recommended, however, that you install L<shcompgen> which allows you to
activate completion scripts for several kinds of scripts on multiple shells.
Some CPAN distributions (those that are built with
L<Dist::Zilla::Plugin::GenShellCompletion>) will even automatically enable shell
completion for their included scripts (using C<shcompgen>) at installation time,
so you can immadiately have tab completion.

=head2 tcsh

To activate tcsh completion for this script, put:

 complete rsybak 'p/*/`rsybak`/'

in your tcsh startup (e.g. C<~/.tcshrc>). Your next shell session will then
recognize tab completion for the command. Or, you can also directly execute the
line above in your shell to activate immediately.

It is also recommended to install C<shcompgen> (see above).

=head2 other shells

For fish and zsh, install C<shcompgen> as described above.

=head1 ENVIRONMENT

=head2 RSYBAK_OPT => str

Specify additional command-line options

=head1 CONFIGURATION FILE

This script can read configuration file, which by default is searched at C<~/.config/rsybak.conf>, C<~/rsybak.conf> or C</etc/rsybak.conf> (can be changed by specifying C<--config-path>). All found files will be read and merged.

To disable searching for configuration files, pass C<--no-config>.

Configuration file is in the format of L<IOD>, which is basically INI with some extra features. 

You can put multiple profiles in a single file by using section names like C<[profile=SOMENAME]>. Those sections will only be read if you specify the matching C<--config-profile SOMENAME>.

List of available configuration parameters:

 backup (see --no-backup)
 extra_dir (see --extra-dir)
 extra_rsync_opts (see --extra-rsync-opts)
 format (see --format)
 format_options (see --format-options)
 histories (see --histories)
 naked_res (see --naked-res)
 rotate (see --no-rotate)
 source (see --source)
 target (see --target)

=head1 FILES

~/.config/rsybak.conf

~/rsybak.conf

/etc/rsybak.conf

=head1 HOMEPAGE

Please visit the project's homepage at L<https://metacpan.org/release/File-RsyBak>.

=head1 SOURCE

Source repository is at L<https://github.com/perlancar/perl-File-RsyBak>.

=head1 BUGS

Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=File-RsyBak>

When submitting a bug or request, please include a test-file or a
patch to an existing test-file that illustrates the bug or desired
feature.

=head1 AUTHOR

perlancar <perlancar@cpan.org>

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2015 by perlancar@cpan.org.

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 OPTIONS

C<*> marks required options.

=head2 Configuration options

=over

=item B<--config-path>=I<filename>

Set path to configuration file.

Can be specified multiple times.

=item B<--config-profile>=I<s>

Set configuration profile to use.

=item B<--no-config>

Do not use any configuration file.

=back

=head2 Environment options

=over

=item B<--no-env>

Do not read environment for default options.

=back

=head2 Output options

=over

=item B<--format-options>=I<s>

Pass options to formatter.

=item B<--format>=I<s>

Choose output format, e.g. json, text.

Default value:

 undef

=item B<--json>

Equivalent to --format=json-pretty.

=item B<--naked-res>

When outputing as JSON, strip result envelope.

Default value:

 0

By default, when outputing as JSON, the full enveloped result is returned, e.g.:

    [200,"OK",[1,2,3],{"func.extra"=>4}]

The reason is so you can get the status (1st element), status message (2nd
element) as well as result metadata/extra result (4th element) instead of just
the result (3rd element). However, sometimes you want just the result, e.g. when
you want to pipe the result for more post-processing. In this case you can use
`--naked-res` so you just get:

    [1,2,3]


=back

=head2 Other options

=over

=item B<--extra-dir>

Whether to force creation of source directory in target.

If set to 1, then backup(source => '/a', target => '/backup/a') will create
another 'a' directory in target, i.e. /backup/a/current/a. Otherwise, contents
of a/ will be directly copied under /backup/a/current/.

Will always be set to 1 if source is more than one, but default to 0 if source
is a single directory. You can set this to 1 to so that behaviour when there is
a single source is the same as behaviour when there are several sources.


=item B<--extra-rsync-opts-json>=I<s>

Pass extra options to rsync command (JSON-encoded).

See C<--extra-rsync-opts>.

=item B<--extra-rsync-opts-yaml>=I<s>

Pass extra options to rsync command (YAML-encoded).

See C<--extra-rsync-opts>.

=item B<--extra-rsync-opts>=I<s@>

Pass extra options to rsync command.

Extra options to pass to rsync command when doing backup. Note that the options
will be shell quoted, , so you should pass it unquoted, e.g. ['--exclude',
'/Program Files'].


Can be specified multiple times.

=item B<--help>, B<-h>, B<-?>

Display help message and exit.

=item B<--histories-json>=I<s>

Histories/history levels (JSON-encoded).

See C<--histories>.

=item B<--histories-yaml>=I<s>

Histories/history levels (YAML-encoded).

See C<--histories>.

=item B<--histories>=I<s@>

Histories/history levels.

Default value:

 [-7,4,3]

Specifies number of backup histories to keep for level 1, 2, and so on. If
number is negative, specifies number of days to keep instead (regardless of
number of histories).


Can be specified multiple times.

=item B<--no-backup>

If backup=1 and rotate=0 then will only create new backup without rotating
histories.


=item B<--no-rotate>

If backup=0 and rotate=1 then will only do history rotating.


=item B<--source>=I<s>*

Director(y|ies) to backup.

=item B<--target>=I<s>*

Backup destination.

=item B<--version>, B<-v>

Display program's version and exit.

=back

=cut

__DATA__
Data::Section::Seekable v1
AE.pm,14,5574,0;0
Algorithm/Dependency.pm,5620,11449,1;178
Algorithm/Dependency/Item.pm,17106,2097,2;572
Algorithm/Dependency/Ordered.pm,19243,3217,3;679
Algorithm/Dependency/Source.pm,22499,6706,4;803
Algorithm/Dependency/Source/File.pm,29249,3841,5;1068
Algorithm/Dependency/Source/HoA.pm,33133,2635,6;1229
Algorithm/Dependency/Source/Invert.pm,35814,1766,7;1359
Algorithm/Dependency/Weight.pm,37619,6966,8;1446
AnyEvent.pm,44605,115926,9;1730
AnyEvent/DNS.pm,160555,42321,10;4832
AnyEvent/Debug.pm,202902,21739,11;6337
AnyEvent/Handle.pm,224668,87403,12;7082
AnyEvent/IO.pm,312094,22717,13;9763
AnyEvent/IO/IOAIO.pm,334840,3561,14;10401
AnyEvent/IO/Perl.pm,338429,2731,15;10551
AnyEvent/Impl/Cocoa.pm,341191,1527,16;10696
AnyEvent/Impl/EV.pm,342746,2096,17;10767
AnyEvent/Impl/Event.pm,344873,2258,18;10874
AnyEvent/Impl/EventLib.pm,347165,4340,19;10970
AnyEvent/Impl/FLTK.pm,351535,3248,20;11121
AnyEvent/Impl/Glib.pm,354813,4882,21;11243
AnyEvent/Impl/IOAsync.pm,359728,7738,22;11424
AnyEvent/Impl/Irssi.pm,367497,3723,23;11700
AnyEvent/Impl/POE.pm,371249,15644,24;11861
AnyEvent/Impl/Perl.pm,386923,1790,25;12282
AnyEvent/Impl/Qt.pm,388741,3254,26;12361
AnyEvent/Impl/Tk.pm,392023,4657,27;12499
AnyEvent/Impl/UV.pm,396708,3950,28;12659
AnyEvent/Log.pm,400682,47054,29;12834
AnyEvent/Loop.pm,447761,10635,30;14349
AnyEvent/Socket.pm,458423,41659,31;14708
AnyEvent/Strict.pm,500109,6205,32;16011
AnyEvent/TLS.pm,506338,44766,33;16258
AnyEvent/Util.pm,551129,28416,34;17422
B/Hooks/EndOfScope.pm,579575,4139,35;18390
B/Hooks/EndOfScope/PP.pm,583747,3282,36;18573
B/Hooks/EndOfScope/XS.pm,587062,2734,37;18699
Border/Style.pm,589820,2310,38;18815
Border/Style/Role.pm,592159,4612,39;18897
Class/Inspector.pm,596798,17761,40;19072
Class/Inspector/Functions.pm,614596,2738,41;19710
Class/Method/Modifiers.pm,617368,16485,42;19845
Clone/PP.pm,633873,6331,43;20338
Color/ANSI/Util.pm,640231,16216,44;20531
Color/RGB/Util.pm,656473,7419,45;21023
Color/Theme.pm,663915,2677,46;21293
Color/Theme/Role.pm,666620,6780,47;21373
Color/Theme/Role/ANSI.pm,673433,4205,48;21615
Color/Theme/Util.pm,677666,3227,49;21761
Complete.pm,680913,6205,50;21878
Complete/Bash.pm,687143,29069,51;22070
Complete/Env.pm,716236,3390,52;22900
Complete/File.pm,719651,9899,53;23041
Complete/Fish.pm,729575,6955,54;23373
Complete/Getopt/Long.pm,736562,27951,55;23633
Complete/Path.pm,764538,15418,56;24410
Complete/Setting.pm,779984,4617,57;24872
Complete/Tcsh.pm,784626,6638,58;25018
Complete/Util.pm,791289,14321,59;25261
Complete/Zsh.pm,805634,5723,60;25820
Config/IOD/Base.pm,811384,19126,61;26034
Config/IOD/Expr.pm,830537,2368,62;26686
Config/IOD/Reader.pm,832934,13350,63;26812
Data/Check/Structure.pm,846316,8570,64;27250
Data/Clean/Base.pm,854913,12371,65;27586
Data/Clean/FromJSON.pm,867315,2936,66;27998
Data/Clean/JSON.pm,870278,6576,67;28115
Data/Dmp.pm,876874,9555,68;28324
Data/Dump.pm,886450,19051,69;28639
Data/Dump/FilterContext.pm,905536,1773,70;29359
Data/Dump/Filtered.pm,907339,5537,71;29453
Data/Dump/OneLine.pm,912905,1992,72;29661
Data/Dump/Partial.pm,914926,10545,73;29743
Data/Dump/Trace.pm,925498,10177,74;30066
Data/Format/Pretty.pm,935705,3306,75;30477
Data/Format/Pretty/CompactJSON.pm,939053,2656,76;30621
Data/Format/Pretty/Console.pm,941747,20943,77;30747
Data/Format/Pretty/HTML.pm,962725,7644,78;31478
Data/Format/Pretty/JSON.pm,970404,3146,79;31782
Data/Format/Pretty/SimpleText.pm,973591,2287,80;31923
Data/Format/Pretty/Text.pm,975913,2291,81;32029
Data/ModeMerge.pm,978230,27119,82;32137
Data/ModeMerge/Config.pm,1005382,14454,83;32928
Data/ModeMerge/Mode/ADD.pm,1019871,2657,84;33452
Data/ModeMerge/Mode/Base.pm,1022564,22127,85;33572
Data/ModeMerge/Mode/CONCAT.pm,1044729,1741,86;34243
Data/ModeMerge/Mode/DELETE.pm,1046508,2738,87;34322
Data/ModeMerge/Mode/KEEP.pm,1049282,2463,88;34452
Data/ModeMerge/Mode/NORMAL.pm,1051783,2800,89;34571
Data/ModeMerge/Mode/SUBTRACT.pm,1054623,3373,90;34715
Data/Sah.pm,1058016,20981,91;34858
Data/Sah/Compiler.pm,1079026,34671,92;35556
Data/Sah/Compiler/Prog.pm,1113731,34851,93;36665
Data/Sah/Compiler/Prog/TH.pm,1148619,4654,94;37763
Data/Sah/Compiler/Prog/TH/all.pm,1153314,1789,95;37937
Data/Sah/Compiler/Prog/TH/any.pm,1155144,1787,96;38013
Data/Sah/Compiler/TH.pm,1156963,2561,97;38089
Data/Sah/Compiler/TextResultRole.pm,1159568,2776,98;38202
Data/Sah/Compiler/human.pm,1162379,19808,99;38324
Data/Sah/Compiler/human/TH.pm,1182225,2405,100;38967
Data/Sah/Compiler/human/TH/Comparable.pm,1184679,1909,101;39082
Data/Sah/Compiler/human/TH/HasElems.pm,1186635,3201,102;39158
Data/Sah/Compiler/human/TH/Sortable.pm,1189883,2780,103;39274
Data/Sah/Compiler/human/TH/all.pm,1192705,3108,104;39385
Data/Sah/Compiler/human/TH/any.pm,1195855,3076,105;39510
Data/Sah/Compiler/human/TH/array.pm,1198975,4139,106;39635
Data/Sah/Compiler/human/TH/bool.pm,1203157,2371,107;39792
Data/Sah/Compiler/human/TH/buf.pm,1205570,1687,108;39894
Data/Sah/Compiler/human/TH/cistr.pm,1207301,1489,109;39968
Data/Sah/Compiler/human/TH/code.pm,1208833,1665,110;40030
Data/Sah/Compiler/human/TH/date.pm,1210541,1785,111;40103
Data/Sah/Compiler/human/TH/duration.pm,1212373,1719,112;40177
Data/Sah/Compiler/human/TH/float.pm,1214136,3338,113;40249
Data/Sah/Compiler/human/TH/hash.pm,1217517,9670,114;40390
Data/Sah/Compiler/human/TH/int.pm,1227229,2958,115;40758
Data/Sah/Compiler/human/TH/num.pm,1230229,1785,116;40881
Data/Sah/Compiler/human/TH/obj.pm,1232056,2146,117;40955
Data/Sah/Compiler/human/TH/re.pm,1234243,1727,118;41051
Data/Sah/Compiler/human/TH/str.pm,1236012,3581,119;41126
Data/Sah/Compiler/human/TH/undef.pm,1239637,1751,120;41277
Data/Sah/Compiler/js.pm,1241420,6668,121;41352
Data/Sah/Compiler/js/TH.pm,1248123,2489,122;41682
Data/Sah/Compiler/js/TH/all.pm,1250651,1646,123;41770
Data/Sah/Compiler/js/TH/any.pm,1252336,1647,124;41840
Data/Sah/Compiler/js/TH/array.pm,1254024,5474,125;41910
Data/Sah/Compiler/js/TH/bool.pm,1259538,3549,126;42088
Data/Sah/Compiler/js/TH/buf.pm,1263126,1498,127;42217
Data/Sah/Compiler/js/TH/cistr.pm,1264665,4812,128;42280
Data/Sah/Compiler/js/TH/code.pm,1269517,1642,129;42451
Data/Sah/Compiler/js/TH/date.pm,1271199,6561,130;42522
Data/Sah/Compiler/js/TH/float.pm,1277801,4159,131;42736
Data/Sah/Compiler/js/TH/hash.pm,1282000,17495,132;42903
Data/Sah/Compiler/js/TH/int.pm,1299534,2072,133;43448
Data/Sah/Compiler/js/TH/num.pm,1301645,3528,134;43537
Data/Sah/Compiler/js/TH/obj.pm,1305212,2156,135;43673
Data/Sah/Compiler/js/TH/re.pm,1307406,1681,136;43765
Data/Sah/Compiler/js/TH/str.pm,1309126,6766,137;43838
Data/Sah/Compiler/js/TH/undef.pm,1315933,1652,138;44072
Data/Sah/Compiler/perl.pm,1317619,14297,139;44143
Data/Sah/Compiler/perl/TH.pm,1331953,2474,140;44721
Data/Sah/Compiler/perl/TH/all.pm,1334468,1660,141;44813
Data/Sah/Compiler/perl/TH/any.pm,1336169,1660,142;44883
Data/Sah/Compiler/perl/TH/array.pm,1337872,5582,143;44953
Data/Sah/Compiler/perl/TH/bool.pm,1343496,3603,144;45135
Data/Sah/Compiler/perl/TH/buf.pm,1347140,1481,145;45265
Data/Sah/Compiler/perl/TH/cistr.pm,1348664,5764,146;45328
Data/Sah/Compiler/perl/TH/code.pm,1354470,1649,147;45524
Data/Sah/Compiler/perl/TH/date.pm,1356161,8913,148;45595
Data/Sah/Compiler/perl/TH/duration.pm,1365120,7085,149;45856
Data/Sah/Compiler/perl/TH/float.pm,1372248,7567,150;46047
Data/Sah/Compiler/perl/TH/hash.pm,1379857,16759,151;46276
Data/Sah/Compiler/perl/TH/int.pm,1396657,2254,152;46787
Data/Sah/Compiler/perl/TH/num.pm,1398952,3306,153;46882
Data/Sah/Compiler/perl/TH/obj.pm,1402299,2063,154;47004
Data/Sah/Compiler/perl/TH/re.pm,1404402,1759,155;47094
Data/Sah/Compiler/perl/TH/str.pm,1406202,6214,156;47168
Data/Sah/Compiler/perl/TH/undef.pm,1412459,1650,157;47385
Data/Sah/Human.pm,1414135,2416,158;47456
Data/Sah/JS.pm,1416574,4831,159;47567
Data/Sah/Lang.pm,1421430,1466,160;47749
Data/Sah/Lang/fr_FR.pm,1422927,2895,161;47815
Data/Sah/Lang/id_ID.pm,1425853,9671,162;47975
Data/Sah/Lang/zh_CN.pm,1435555,2784,163;48436
Data/Sah/Normalize.pm,1438369,9024,164;48596
Data/Sah/Type/BaseType.pm,1447427,4173,165;48870
Data/Sah/Type/Comparable.pm,1451636,1972,166;49048
Data/Sah/Type/HasElems.pm,1453642,3649,167;49128
Data/Sah/Type/Sortable.pm,1457325,3001,168;49280
Data/Sah/Type/all.pm,1460355,1465,169;49400
Data/Sah/Type/any.pm,1461849,1465,170;49464
Data/Sah/Type/array.pm,1463345,1742,171;49528
Data/Sah/Type/bool.pm,1465117,1503,172;49601
Data/Sah/Type/buf.pm,1466649,1264,173;49667
Data/Sah/Type/cistr.pm,1467944,1274,174;49724
Data/Sah/Type/code.pm,1469248,1274,175;49781
Data/Sah/Type/date.pm,1470552,1886,176;49838
Data/Sah/Type/duration.pm,1472472,1448,177;49920
Data/Sah/Type/float.pm,1473951,1895,178;49982
Data/Sah/Type/hash.pm,1475876,4766,179;50068
Data/Sah/Type/int.pm,1480671,1597,180;50246
Data/Sah/Type/num.pm,1482297,1341,181;50315
Data/Sah/Type/obj.pm,1483667,1577,182;50374
Data/Sah/Type/re.pm,1485272,1305,183;50443
Data/Sah/Type/str.pm,1486606,1793,184;50501
Data/Sah/Type/undef.pm,1488430,1260,185;50580
Data/Sah/Util/Func.pm,1489720,1696,186;50635
Data/Sah/Util/Role.pm,1491446,6639,187;50712
Data/Sah/Util/Type.pm,1498115,5847,188;50965
Data/Sah/Util/Type/Date.pm,1503997,7070,189;51186
Data/Sah/Util/TypeX.pm,1511098,2623,190;51401
Devel/GlobalDestruction.pm,1513756,2885,191;51515
Dist/CheckConflicts.pm,1516672,10076,192;51625
Exporter/Lite.pm,1526773,7533,193;51986
File/Flock.pm,1534328,8760,194;52245
File/Flock/Forking.pm,1543118,1491,195;52636
File/Flock/Retry.pm,1544637,5439,196;52695
File/Flock/Subprocess.pm,1550109,12686,197;52928
File/HomeDir.pm,1562819,22675,198;53479
File/HomeDir/Darwin.pm,1585525,3413,199;54199
File/HomeDir/Darwin/Carbon.pm,1588976,4809,200;54351
File/HomeDir/Darwin/Cocoa.pm,1593822,3750,201;54561
File/HomeDir/Driver.pm,1597603,1176,202;54726
File/HomeDir/FreeDesktop.pm,1598815,3771,203;54780
File/HomeDir/MacOS9.pm,1602617,3154,204;54916
File/HomeDir/Test.pm,1605800,3148,205;55066
File/HomeDir/Unix.pm,1608977,3599,206;55203
File/HomeDir/Windows.pm,1612608,6550,207;55389
File/Path.pm,1619179,34172,208;55630
File/RsyBak.pm,1653374,24356,209;56615
File/RsyBak/Packed.pm,1677760,1348,210;57386
File/Slurp.pm,1679130,35057,211;57439
File/Slurp/Tiny.pm,1714214,4934,212;58700
File/Which.pm,1719170,9904,213;58893
File/Write/Rotate.pm,1729103,26419,214;59228
File/chdir.pm,1755544,11304,215;60047
Function/Fallback/CoreOrPP.pm,1766886,4596,216;60507
Getopt/Long/Negate/EN.pm,1771515,3149,217;60685
Getopt/Long/Util.pm,1774692,11978,218;60789
HTML/Entities.pm,1786695,15478,219;61220
HTML/Filter.pm,1802196,2797,220;61703
HTML/HeadParser.pm,1805020,8841,221;61815
HTML/LinkExtor.pm,1813887,4690,222;62130
HTML/Parser.pm,1818600,41029,223;62315
HTML/PullParser.pm,1859656,5890,224;63555
HTML/Tagset.pm,1865569,13418,225;63764
HTML/TokeParser.pm,1879014,10475,226;64235
HTTP/Tiny.pm,1889510,69761,227;64606
HTTP/Tiny/UNIX.pm,1959297,4562,228;66751
IO/Event.pm,1963879,28955,229;66930
IO/Event/AnyEvent.pm,1992863,4229,230;68250
IO/Event/Callback.pm,1997121,3517,231;68488
IO/Event/Emulate.pm,2000666,9479,232;68649
IO/Event/Event.pm,2010171,1955,233;69163
IO/Socket/UNIX/Util.pm,2012157,3974,234;69274
JSON.pm,2016147,72813,235;69426
JSON/Color.pm,2088982,7271,236;71743
JSON/PP.pm,2096272,84628,237;72040
JSON/PP/Boolean.pm,2180927,451,238;74835
LWP.pm,2181393,22327,239;74861
LWP/Authen/Basic.pm,2203748,2118,240;75530
LWP/Authen/Digest.pm,2205895,2030,241;75595
LWP/Authen/Ntlm.pm,2207952,5566,242;75670
LWP/ConnCache.pm,2213543,7934,243;75850
LWP/Debug.pm,2221498,2683,244;76163
LWP/DebugFile.pm,2224206,48,245;76273
LWP/MemberMixin.pm,2224281,890,246;76278
LWP/Protocol.pm,2225195,8206,247;76322
LWP/Protocol/GHTTP.pm,2233431,1839,248;76613
LWP/Protocol/cpan.pm,2235299,1452,249;76686
LWP/Protocol/data.pm,2236780,1304,250;76758
LWP/Protocol/file.pm,2238113,3979,251;76810
LWP/Protocol/ftp.pm,2242120,17360,252;76956
LWP/Protocol/gopher.pm,2259511,5964,253;77499
LWP/Protocol/http.pm,2265504,15420,254;77712
LWP/Protocol/http/SocketUnixAlt.pm,2280967,8904,255;78227
LWP/Protocol/loopback.pm,2289904,627,256;78578
LWP/Protocol/mailto.pm,2290562,4611,257;78604
LWP/Protocol/nntp.pm,2295202,4018,258;78787
LWP/Protocol/nogo.pm,2299249,654,259;78932
LWP/RobotUA.pm,2299926,8016,260;78956
LWP/Simple.pm,2307964,6579,261;79259
LWP/UserAgent.pm,2314568,61663,262;79512
Lingua/EN/Numbers/Ordinate.pm,2376269,5047,263;81373
Lingua/EN/PluralToSingular.pm,2381354,7617,264;81562
Locale/Messages.pm,2388998,32180,265;81936
Locale/Recode.pm,2421203,10365,266;83015
Locale/Recode/_Aliases.pm,2431602,24747,267;83379
Locale/Recode/_Conversions.pm,2456387,11258,268;84122
Locale/RecodeData.pm,2467674,4273,269;84578
Locale/RecodeData/ASMO_449.pm,2471985,18734,270;84751
Locale/RecodeData/ATARI_ST.pm,2490757,28027,271;85620
Locale/RecodeData/ATARI_ST_EURO.pm,2518827,28071,272;86760
Locale/RecodeData/CP10007.pm,2546935,27893,273;87900
Locale/RecodeData/CP1250.pm,2574864,28262,274;89037
Locale/RecodeData/CP1251.pm,2603162,28212,275;90167
Locale/RecodeData/CP1252.pm,2631410,28077,276;91305
Locale/RecodeData/CP1253.pm,2659523,26948,277;92435
Locale/RecodeData/CP1254.pm,2686507,27910,278;93541
Locale/RecodeData/CP1256.pm,2714453,27607,279;94667
Locale/RecodeData/CP1257.pm,2742096,27544,280;95807
Locale/RecodeData/CSN_369103.pm,2769680,28748,281;96922
Locale/RecodeData/CWI.pm,2798461,28903,282;98062
Locale/RecodeData/DEC_MCS.pm,2827401,27473,283;99202
Locale/RecodeData/EBCDIC_AT_DE.pm,2854916,21558,284;100311
Locale/RecodeData/EBCDIC_AT_DE_A.pm,2876518,21286,285;101257
Locale/RecodeData/EBCDIC_CA_FR.pm,2897846,23175,286;102193
Locale/RecodeData/EBCDIC_DK_NO.pm,2921063,21560,287;103181
Locale/RecodeData/EBCDIC_DK_NO_A.pm,2942667,21229,288;104128
Locale/RecodeData/EBCDIC_ES.pm,2963935,21416,289;105064
Locale/RecodeData/EBCDIC_ES_A.pm,2985392,21139,290;106010
Locale/RecodeData/EBCDIC_ES_S.pm,3006572,21418,291;106946
Locale/RecodeData/EBCDIC_FI_SE.pm,3028032,21615,292;107892
Locale/RecodeData/EBCDIC_FI_SE_A.pm,3049691,21263,293;108838
Locale/RecodeData/EBCDIC_FR.pm,3070993,21472,294;109774
Locale/RecodeData/EBCDIC_IS_FRISS.pm,3092510,20545,295;110720
Locale/RecodeData/EBCDIC_IT.pm,3113094,21517,296;111637
Locale/RecodeData/EBCDIC_PT.pm,3134650,21269,297;112583
Locale/RecodeData/EBCDIC_UK.pm,3155958,21365,298;113519
Locale/RecodeData/EBCDIC_US.pm,3177362,21353,299;114465
Locale/RecodeData/ECMA_CYRILLIC.pm,3198758,28399,300;115411
Locale/RecodeData/GEORGIAN_ACADEMY.pm,3227203,27805,301;116550
Locale/RecodeData/GEORGIAN_PS.pm,3255049,27779,302;117678
Locale/RecodeData/GOST_19768_74.pm,3282871,26243,303;118806
Locale/RecodeData/GREEK7.pm,3309150,19261,304;119890
Locale/RecodeData/GREEK7_OLD.pm,3328451,19418,305;120768
Locale/RecodeData/GREEK_CCITT.pm,3347910,19227,306;121649
Locale/RecodeData/HP_ROMAN8.pm,3367176,28584,307;122525
Locale/RecodeData/IBM037.pm,3395796,28508,308;123664
Locale/RecodeData/IBM038.pm,3424340,21389,309;124807
Locale/RecodeData/IBM1004.pm,3445766,27794,310;125755
Locale/RecodeData/IBM1026.pm,3473597,28436,311;126877
Locale/RecodeData/IBM1047.pm,3502070,28481,312;128017
Locale/RecodeData/IBM256.pm,3530587,28443,313;129158
Locale/RecodeData/IBM273.pm,3559066,28430,314;130297
Locale/RecodeData/IBM274.pm,3587532,21494,315;131436
Locale/RecodeData/IBM275.pm,3609062,21542,316;132384
Locale/RecodeData/IBM277.pm,3630640,28458,317;133332
Locale/RecodeData/IBM278.pm,3659134,28472,318;134472
Locale/RecodeData/IBM280.pm,3687642,28451,319;135613
Locale/RecodeData/IBM281.pm,3716129,21381,320;136753
Locale/RecodeData/IBM284.pm,3737546,28451,321;137701
Locale/RecodeData/IBM285.pm,3766033,28451,322;138841
Locale/RecodeData/IBM290.pm,3794520,24043,323;139981
Locale/RecodeData/IBM297.pm,3818599,28451,324;140999
Locale/RecodeData/IBM420.pm,3847086,27783,325;142139
Locale/RecodeData/IBM423.pm,3874905,27840,326;143260
Locale/RecodeData/IBM424.pm,3902781,24982,327;144380
Locale/RecodeData/IBM437.pm,3927799,28887,328;145442
Locale/RecodeData/IBM500.pm,3956722,28492,329;146582
Locale/RecodeData/IBM850.pm,3985250,28679,330;147725
Locale/RecodeData/IBM851.pm,4013965,28623,331;148866
Locale/RecodeData/IBM852.pm,4042624,28967,332;150004
Locale/RecodeData/IBM855.pm,4071627,28620,333;151144
Locale/RecodeData/IBM857.pm,4100283,28430,334;152284
Locale/RecodeData/IBM860.pm,4128749,28928,335;153418
Locale/RecodeData/IBM861.pm,4157713,28974,336;154558
Locale/RecodeData/IBM862.pm,4186723,28486,337;155699
Locale/RecodeData/IBM863.pm,4215245,28806,338;156839
Locale/RecodeData/IBM864.pm,4244087,28385,339;157979
Locale/RecodeData/IBM865.pm,4272508,28913,340;159105
Locale/RecodeData/IBM866.pm,4301457,28580,341;160245
Locale/RecodeData/IBM868.pm,4330073,26661,342;161384
Locale/RecodeData/IBM869.pm,4356770,27878,343;162474
Locale/RecodeData/IBM870.pm,4384684,27826,344;163597
Locale/RecodeData/IBM871.pm,4412546,28445,345;164716
Locale/RecodeData/IBM874.pm,4441027,25783,346;165856
Locale/RecodeData/IBM875.pm,4466846,27763,347;166932
Locale/RecodeData/IBM880.pm,4494645,27728,348;168058
Locale/RecodeData/IBM891.pm,4522409,19072,349;169178
Locale/RecodeData/IBM903.pm,4541517,19072,350;170061
Locale/RecodeData/IBM904.pm,4560625,19249,351;170944
Locale/RecodeData/IBM905.pm,4579910,28039,352;171834
Locale/RecodeData/IBM918.pm,4607985,26282,353;172956
Locale/RecodeData/IEC_P27_1.pm,4634306,27688,354;174044
Locale/RecodeData/INIS.pm,4662028,18323,355;175183
Locale/RecodeData/INIS_8.pm,4680387,16069,356;176040
Locale/RecodeData/INIS_CYRILLIC.pm,4696499,19372,357;176812
Locale/RecodeData/ISO_10367_BOX.pm,4715914,23686,358;177671
Locale/RecodeData/ISO_2033_1983.pm,4739643,14396,359;178676
Locale/RecodeData/ISO_5427.pm,4754077,19695,360;179401
Locale/RecodeData/ISO_5427_EXT.pm,4773814,16692,361;180285
Locale/RecodeData/ISO_5428.pm,4790544,19158,362;181066
Locale/RecodeData/ISO_8859_1.pm,4809742,17810,363;181908
Locale/RecodeData/ISO_8859_10.pm,4827593,28940,364;182515
Locale/RecodeData/ISO_8859_11.pm,4856574,25529,365;183658
Locale/RecodeData/ISO_8859_13.pm,4882144,28371,366;184721
Locale/RecodeData/ISO_8859_14.pm,4910556,28814,367;185861
Locale/RecodeData/ISO_8859_15.pm,4939411,28264,368;187000
Locale/RecodeData/ISO_8859_16.pm,4967716,28664,369;188137
Locale/RecodeData/ISO_8859_2.pm,4996420,28788,370;189277
Locale/RecodeData/ISO_8859_3.pm,5025248,28219,371;190420
Locale/RecodeData/ISO_8859_4.pm,5053507,28788,372;191549
Locale/RecodeData/ISO_8859_5.pm,5082335,28443,373;192692
Locale/RecodeData/ISO_8859_6.pm,5110818,24731,374;193834
Locale/RecodeData/ISO_8859_7.pm,5135589,27934,375;194888
Locale/RecodeData/ISO_8859_8.pm,5163563,25200,376;196021
Locale/RecodeData/ISO_8859_9.pm,5188803,28480,377;197091
Locale/RecodeData/KOI8_R.pm,5217319,28775,378;198234
Locale/RecodeData/KOI8_RU.pm,5246131,28625,379;199373
Locale/RecodeData/KOI8_T.pm,5274792,26724,380;200512
Locale/RecodeData/KOI8_U.pm,5301552,28650,381;201612
Locale/RecodeData/KOI_8.pm,5330237,23572,382;202751
Locale/RecodeData/LATIN_GREEK.pm,5353850,19236,383;203759
Locale/RecodeData/LATIN_GREEK_1.pm,5373129,19254,384;204640
Locale/RecodeData/MACARABIC.pm,5392422,26172,385;205523
Locale/RecodeData/MACCROATIAN.pm,5418635,28290,386;206610
Locale/RecodeData/MACCYRILLIC.pm,5446966,28102,387;207747
Locale/RecodeData/MACGREEK.pm,5475106,28261,388;208886
Locale/RecodeData/MACHEBREW.pm,5503406,25261,389;210023
Locale/RecodeData/MACICELAND.pm,5528707,28141,390;211078
Locale/RecodeData/MACINTOSH.pm,5556887,28333,391;212215
Locale/RecodeData/MACROMANIA.pm,5585260,28189,392;213354
Locale/RecodeData/MACTHAI.pm,5613486,27608,393;214491
Locale/RecodeData/MACTURKISH.pm,5641134,28100,394;215618
Locale/RecodeData/MACUKRAINE.pm,5669274,28140,395;216753
Locale/RecodeData/MAC_IS.pm,5697450,28101,396;217892
Locale/RecodeData/MAC_SAMI.pm,5725589,28539,397;219025
Locale/RecodeData/MAC_UK.pm,5754164,27896,398;220165
Locale/RecodeData/NATS_DANO.pm,5782099,19311,399;221302
Locale/RecodeData/NATS_SEFI.pm,5801449,19279,400;222185
Locale/RecodeData/NEXTSTEP.pm,5820766,28167,401;223068
Locale/RecodeData/SAMI_WS2.pm,5848971,28502,402;224203
Locale/RecodeData/TIS_620.pm,5877510,25431,403;225333
Locale/RecodeData/US_ASCII.pm,5902979,7700,404;226394
Locale/RecodeData/UTF_8.pm,5910714,5227,405;226616
Locale/RecodeData/VISCII.pm,5915977,30247,406;226805
Locale/RecodeData/_Encode.pm,5946261,2348,407;227933
Locale/TextDomain.pm,5948638,34535,408;228027
Locale/TextDomain/UTF8.pm,5983207,2535,409;229091
Locale/Util.pm,5985765,36464,410;229198
Locale/gettext_dumb.pm,6022260,12608,411;230406
Locale/gettext_pp.pm,6034897,28679,412;230759
Locale/gettext_xs.pm,6063605,5203,413;231850
Log/Any.pm,6068827,12741,414;232049
Log/Any/Adapter.pm,6081595,5999,415;232478
Log/Any/Adapter/Base.pm,6087626,948,416;232716
Log/Any/Adapter/File.pm,6088606,3153,417;232756
Log/Any/Adapter/Log4perl.pm,6091795,2931,418;232886
Log/Any/Adapter/Null.pm,6094758,1288,419;233027
Log/Any/Adapter/Screen.pm,6096080,7375,420;233099
Log/Any/Adapter/Stderr.pm,6103489,2335,421;233354
Log/Any/Adapter/Stdout.pm,6105858,2335,422;233463
Log/Any/Adapter/Test.pm,6108225,4661,423;233572
Log/Any/Adapter/Util.pm,6112918,8116,424;233756
Log/Any/App.pm,6121057,81834,425;234096
Log/Any/IfLOG.pm,6202916,4516,426;236381
Log/Any/Manager.pm,6207459,5580,427;236560
Log/Any/Proxy.pm,6213064,7419,428;236756
Log/Any/Proxy/Test.pm,6220513,475,429;237073
Log/Any/Test.pm,6221012,3513,430;237103
Log/Dispatch.pm,6224549,20655,431;237249
Log/Dispatch/ApacheLog.pm,6245238,2092,432;238008
Log/Dispatch/ArrayWithLimits.pm,6247370,3966,433;238123
Log/Dispatch/Base.pm,6251365,1509,434;238269
Log/Dispatch/Code.pm,6252903,2027,435;238360
Log/Dispatch/Dir.pm,6254958,12436,436;238482
Log/Dispatch/Email.pm,6267424,4656,437;238917
Log/Dispatch/Email/MIMELite.pm,6272119,1610,438;239124
Log/Dispatch/Email/MailSend.pm,6273768,2183,439;239207
Log/Dispatch/Email/MailSender.pm,6275992,4255,440;239309
Log/Dispatch/Email/MailSendmail.pm,6280290,1682,441;239492
Log/Dispatch/File.pm,6282001,6459,442;239575
Log/Dispatch/File/Locked.pm,6288496,2081,443;239860
Log/Dispatch/FileWriteRotate.pm,6290617,3530,444;239956
Log/Dispatch/Handle.pm,6294178,1957,445;240092
Log/Dispatch/Null.pm,6296164,1153,446;240194
Log/Dispatch/Output.pm,6297348,7675,447;240263
Log/Dispatch/Screen.pm,6305054,3067,448;240578
Log/Dispatch/Syslog.pm,6308152,5170,449;240718
Log/Log4perl.pm,6313346,106535,450;240943
Log/Log4perl/Appender.pm,6419914,25022,451;243899
Log/Log4perl/Appender/Buffer.pm,6444976,8707,452;244632
Log/Log4perl/Appender/DBI.pm,6453720,20688,453;244911
Log/Log4perl/Appender/File.pm,6474446,17025,454;245554
Log/Log4perl/Appender/Limit.pm,6491510,11165,455;246099
Log/Log4perl/Appender/RRDs.pm,6502713,3925,456;246439
Log/Log4perl/Appender/Screen.pm,6506678,3301,457;246573
Log/Log4perl/Appender/ScreenColoredLevels.pm,6510032,6126,458;246697
Log/Log4perl/Appender/Socket.pm,6516198,6713,459;246932
Log/Log4perl/Appender/String.pm,6522951,2844,460;247158
Log/Log4perl/Appender/Synchronized.pm,6525841,10714,461;247268
Log/Log4perl/Appender/TestArrayBuffer.pm,6536604,2765,462;247560
Log/Log4perl/Appender/TestBuffer.pm,6539413,5188,463;247654
Log/Log4perl/Appender/TestFileCreeper.pm,6544650,2472,464;247843
Log/Log4perl/Catalyst.pm,6547155,11101,465;247932
Log/Log4perl/Config.pm,6558287,40899,466;248300
Log/Log4perl/Config/BaseConfigurator.pm,6599234,9002,467;249513
Log/Log4perl/Config/DOMConfigurator.pm,6608283,28222,468;249858
Log/Log4perl/Config/PropertyConfigurator.pm,6636557,6197,469;250770
Log/Log4perl/Config/Watch.pm,6642791,10655,470;250990
Log/Log4perl/DateFormat.pm,6653481,14582,471;251343
Log/Log4perl/Filter.pm,6668094,12822,472;251804
Log/Log4perl/Filter/Boolean.pm,6680955,6811,473;252172
Log/Log4perl/Filter/LevelMatch.pm,6687808,3353,474;252383
Log/Log4perl/Filter/LevelRange.pm,6691203,3751,475;252501
Log/Log4perl/Filter/MDC.pm,6694989,2507,476;252627
Log/Log4perl/Filter/StringMatch.pm,6697539,3642,477;252724
Log/Log4perl/InternalDebug.pm,6701219,3062,478;252850
Log/Log4perl/JavaMap.pm,6704313,6011,479;252972
Log/Log4perl/JavaMap/ConsoleAppender.pm,6710372,2358,480;253156
Log/Log4perl/JavaMap/FileAppender.pm,6712775,3367,481;253251
Log/Log4perl/JavaMap/JDBCAppender.pm,6716187,3791,482;253368
Log/Log4perl/JavaMap/NTEventLogAppender.pm,6720029,2228,483;253501
Log/Log4perl/JavaMap/RollingFileAppender.pm,6722309,4130,484;253592
Log/Log4perl/JavaMap/SyslogAppender.pm,6726486,3032,485;253735
Log/Log4perl/JavaMap/TestBuffer.pm,6729561,1814,486;253844
Log/Log4perl/Layout.pm,6731406,2518,487;253914
Log/Log4perl/Layout/NoopLayout.pm,6733966,2189,488;254006
Log/Log4perl/Layout/PatternLayout.pm,6736200,30382,489;254087
Log/Log4perl/Layout/PatternLayout/Multiline.pm,6766637,2656,490;254975
Log/Log4perl/Layout/SimpleLayout.pm,6769337,2641,491;255068
Log/Log4perl/Level.pm,6772008,10224,492;255165
Log/Log4perl/Logger.pm,6782263,35186,493;255523
Log/Log4perl/MDC.pm,6817477,3622,494;256688
Log/Log4perl/NDC.pm,6821127,4403,495;256824
Log/Log4perl/Resurrector.pm,6825566,5740,496;256975
Log/Log4perl/Util.pm,6831335,3294,497;257189
Log/Log4perl/Util/Semaphore.pm,6834668,7492,498;257307
Log/Log4perl/Util/TimeTracker.pm,6842201,7603,499;257571
Method/Generate/Accessor.pm,6849840,20332,500;257830
Method/Generate/BuildAll.pm,6870208,931,501;258503
Method/Generate/Constructor.pm,6871178,7831,502;258539
Method/Generate/DemolishAll.pm,6879048,1330,503;258797
Method/Inliner.pm,6880404,1459,504;258848
Mo.pm,6881877,563,505;258901
Mo/Golf.pm,6882459,8172,506;258904
Mo/Inline.pm,6890652,3469,507;259140
Mo/Moose.pm,6894141,467,508;259281
Mo/Mouse.pm,6894628,497,509;259284
Mo/build.pm,6895145,215,510;259287
Mo/builder.pm,6895382,303,511;259290
Mo/chain.pm,6895705,183,512;259293
Mo/coerce.pm,6895909,296,513;259296
Mo/default.pm,6896227,400,514;259299
Mo/exporter.pm,6896650,140,515;259302
Mo/import.pm,6896811,151,516;259305
Mo/importer.pm,6896985,171,517;259308
Mo/is.pm,6897173,198,518;259311
Mo/nonlazy.pm,6897393,94,519;259314
Mo/option.pm,6897508,225,520;259317
Mo/required.pm,6897756,304,521;259320
Mo/xs.pm,6898077,226,522;259323
Module/Implementation.pm,6898336,8245,523;259326
Module/List.pm,6906604,6620,524;259616
Module/Path/More.pm,6913252,10895,525;259826
Module/Runtime.pm,6924173,17118,526;260224
Monkey/Patch/Action.pm,6941322,7248,527;260729
Monkey/Patch/Action/Handle.pm,6948608,3290,528;261009
Moo.pm,6951913,32182,529;261148
Moo/HandleMoose.pm,6984122,7714,530;262152
Moo/HandleMoose/FakeMetaClass.pm,6991877,920,531;262373
Moo/HandleMoose/_TypeMap.pm,6992833,1652,532;262405
Moo/Object.pm,6994507,2115,533;262480
Moo/Role.pm,6996642,14511,534;262560
Moo/_Utils.pm,7011175,3832,535;263072
Moo/_mro.pm,7015027,124,536;263204
Moo/_strictures.pm,7015178,290,537;263214
Moo/sification.pm,7015494,710,538;263232
PERLANCAR/File/HomeDir.pm,7016238,2901,539;263264
Package/MoreUtil.pm,7019167,5053,540;263379
Package/Stash.pm,7024245,8398,541;263589
Package/Stash/PP.pm,7032671,15039,542;263873
Params/Util.pm,7047733,23241,543;264403
Params/Validate.pm,7071001,26408,544;265269
Params/Validate/Constants.pm,7097446,611,545;266169
Params/Validate/PP.pm,7098087,21109,546;266208
Params/Validate/XS.pm,7119226,993,547;266943
Parse/VarName.pm,7120244,3380,548;266994
Perinci/Access.pm,7123650,9303,549;267140
Perinci/Access/Base.pm,7132984,3508,550;267435
Perinci/Access/HTTP/Client.pm,7136530,13884,551;267570
Perinci/Access/Lite.pm,7150445,9537,552;268026
Perinci/Access/Perl.pm,7160013,4583,553;268333
Perinci/Access/Schemeless.pm,7164633,38321,554;268510
Perinci/Access/Simple/Client.pm,7202994,16379,555;269777
Perinci/AccessUtil.pm,7219403,5814,556;270275
Perinci/CmdLine/Base.pm,7225249,78952,557;270461
Perinci/CmdLine/Classic.pm,7304236,32036,558;272784
Perinci/CmdLine/Classic/ColorTheme/Default.pm,7336326,2230,559;273843
Perinci/CmdLine/Classic/Role/Help.pm,7338601,17493,560;273932
Perinci/CmdLine/Help.pm,7356126,9365,561;274492
Perinci/CmdLine/Lite.pm,7365523,19575,562;274809
Perinci/CmdLine/Util/Config.pm,7385137,9046,563;275499
Perinci/Object.pm,7394209,5316,564;275811
Perinci/Object/EnvResult.pm,7399561,4472,565;276014
Perinci/Object/EnvResultMulti.pm,7404074,4038,566;276210
Perinci/Object/Function.pm,7408147,3783,567;276359
Perinci/Object/Metadata.pm,7411965,5160,568;276514
Perinci/Object/Package.pm,7417159,1400,569;276743
Perinci/Object/ResMeta.pm,7418593,1434,570;276807
Perinci/Object/Variable.pm,7420062,1407,571;276871
Perinci/Result/Format.pm,7421502,10348,572;276935
Perinci/Result/Format/Lite.pm,7431888,8240,573;277285
Perinci/Sub/CoerceArgs.pm,7440162,15227,574;277551
Perinci/Sub/Complete.pm,7455421,49480,575;278011
Perinci/Sub/ConvertArgs/Argv.pm,7504941,5957,576;279378
Perinci/Sub/ConvertArgs/Array.pm,7510939,4818,577;279598
Perinci/Sub/DepChecker.pm,7515791,10117,578;279779
Perinci/Sub/GetArgs/Argv.pm,7525944,49807,579;280113
Perinci/Sub/GetArgs/Array.pm,7575788,6872,580;281475
Perinci/Sub/Normalize.pm,7582693,7303,581;281720
Perinci/Sub/To/CLIDocData.pm,7590033,26124,582;281956
Perinci/Sub/Util.pm,7616185,17431,583;282681
Perinci/Sub/Util/ResObj.pm,7633651,1545,584;283302
Perinci/Sub/Util/Sort.pm,7635229,1957,585;283363
Perinci/Sub/Wrapper.pm,7637217,65695,586;283454
Proc/PID/File.pm,7702937,12118,587;285336
Progress/Any.pm,7715079,29565,588;285733
Progress/Any/Output.pm,7744675,3677,589;286747
Progress/Any/Output/Null.pm,7748388,1328,590;286904
Progress/Any/Output/TermProgressBarColor.pm,7749768,10408,591;286968
Regexp/Stringify.pm,7760204,5363,592;287341
Rinci.pm,7765584,1115,593;287537
Role/Tiny.pm,7766720,20266,594;287586
Role/Tiny/With.pm,7787012,800,595;288284
Sah/Schema/Rinci.pm,7787840,5671,596;288334
Scalar/Util/Numeric/PP.pm,7793545,3090,597;288566
String/Elide/Parts.pm,7796665,8223,598;288707
String/Indent.pm,7804913,2450,599;288964
String/LineNumber.pm,7807392,2512,600;289070
String/PerlQuote.pm,7809932,3387,601;289188
String/ShellQuote.pm,7813348,4321,602;289313
String/Trim/More.pm,7817697,4061,603;289509
String/Wildcard/Bash.pm,7821790,5287,604;289692
Sub/Defer.pm,7827098,4281,605;289885
Sub/Delete.pm,7831401,3921,606;290050
Sub/Exporter/Progressive.pm,7835358,4707,607;290180
Sub/Install.pm,7840088,12978,608;290338
Sub/Quote.pm,7853087,9554,609;290789
Sys/Syslog.pm,7862663,48150,610;291155
Term/ANSIColor.pm,7910839,48716,611;292929
Term/App/Role/Attrs.pm,7959586,10536,612;294151
Term/App/Roles.pm,7970148,1257,613;294508
Term/Detect/Software.pm,7971437,12597,614;294560
Test/Config/IOD/Common.pm,7984068,7276,615;294920
Test/Data/Sah.pm,7991369,3595,616;295234
Test/Perinci/Sub/Wrapper.pm,7995000,10389,617;295352
Test/SharedFork.pm,8005416,4631,618;295620
Test/SharedFork/Array.pm,8010080,1004,619;295794
Test/SharedFork/Scalar.pm,8011118,556,620;295843
Test/SharedFork/Store.pm,8011707,2666,621;295869
Text/ANSI/BaseUtil.pm,8014403,29715,622;295988
Text/ANSI/NonWideUtil.pm,8044151,8719,623;296856
Text/ANSI/Util.pm,8052896,14696,624;297118
Text/ANSITable.pm,8067618,92935,625;297557
Text/ANSITable/BorderStyle/Default.pm,8160599,19943,626;300469
Text/ANSITable/ColorTheme/Default.pm,8180587,5487,627;301252
Text/ANSITable/StyleSet/AltRow.pm,8186116,2498,628;301447
Text/Table/Tiny.pm,8188641,5652,629;301547
Text/sprintfn.pm,8194318,9361,630;301759
Tie/Cache.pm,8203700,19300,631;302068
Tie/IxHash.pm,8223022,15565,632;302767
Time/Duration.pm,8238612,15991,633;303418
Try/Tiny.pm,8254623,18791,634;303891
URI.pm,8273429,35750,635;304568
URI/Escape.pm,8309201,7242,636;305723
URI/Find.pm,8316463,15257,637;305943
URI/Find/Schemeless.pm,8331751,13209,638;306520
URI/Heuristic.pm,8344985,6777,639;307303
URI/IRI.pm,8351781,841,640;307556
URI/QueryParam.pm,8352648,5068,641;307603
URI/Split.pm,8357737,2450,642;307810
URI/URL.pm,8360206,5790,643;307907
URI/WithBase.pm,8366020,4031,644;308210
URI/_foreign.pm,8370075,117,645;308384
URI/_generic.pm,8370216,6078,646;308394
URI/_idna.pm,8376315,2168,647;308650
URI/_ldap.pm,8378504,3389,648;308741
URI/_login.pm,8381915,244,649;308881
URI/_punycode.pm,8382184,4825,650;308894
URI/_query.pm,8387031,2628,651;309097
URI/_segment.pm,8389683,440,652;309194
URI/_server.pm,8390146,3890,653;309218
URI/_userpass.pm,8394061,1089,654;309384
URI/data.pm,8395170,3533,655;309439
URI/file.pm,8398723,10088,656;309581
URI/file/Base.pm,8408836,1559,657;309908
URI/file/FAT.pm,8410419,524,658;309992
URI/file/Mac.pm,8410967,2606,659;310019
URI/file/OS2.pm,8413597,593,660;310140
URI/file/QNX.pm,8414214,357,661;310172
URI/file/Unix.pm,8414596,1080,662;310192
URI/file/Win32.pm,8415702,1844,663;310250
URI/ftp.pm,8417565,1102,664;310337
URI/gopher.pm,8418689,2525,665;310383
URI/http.pm,8421234,452,666;310480
URI/https.pm,8421707,158,667;310507
URI/ldap.pm,8421885,3044,668;310521
URI/ldapi.pm,8424950,470,669;310641
URI/ldaps.pm,8425441,158,670;310670
URI/mailto.pm,8425621,1349,671;310684
URI/mms.pm,8426989,137,672;310757
URI/news.pm,8427146,1525,673;310769
URI/nntp.pm,8428691,137,674;310840
URI/pop.pm,8428847,1278,675;310850
URI/rlogin.pm,8430147,141,676;310921
URI/rsync.pm,8430309,221,677;310933
URI/rtsp.pm,8430550,137,678;310947
URI/rtspu.pm,8430708,138,679;310959
URI/sftp.pm,8430866,108,680;310971
URI/sip.pm,8430993,1794,681;310981
URI/sips.pm,8432807,157,682;311066
URI/snews.pm,8432985,186,683;311080
URI/ssh.pm,8433190,191,684;311094
URI/telnet.pm,8433403,140,685;311110
URI/tn3270.pm,8433565,140,686;311122
URI/urn.pm,8433724,2074,687;311134
URI/urn/isbn.pm,8435822,2620,688;311234
URI/urn/oid.pm,8438465,303,689;311337
UUID/Random.pm,8438791,1164,690;311357
Version/Util.pm,8439979,2927,691;311413
YAML.pm,8442922,2733,692;311555
YAML/Any.pm,8445675,2772,693;311655
YAML/Dumper.pm,8448470,17610,694;311777
YAML/Dumper/Base.pm,8466108,3705,695;312352
YAML/Error.pm,8469835,5882,696;312463
YAML/Loader.pm,8475740,24381,697;312652
YAML/Loader/Base.pm,8500149,1015,698;313405
YAML/Marshall.pm,8501189,914,699;313438
YAML/Mo.pm,8502122,3056,700;313485
YAML/Node.pm,8505199,4642,701;313565
YAML/Tag.pm,8509861,235,702;313783
YAML/Types.pm,8510118,6574,703;313802
experimental.pm,8516716,5715,704;314037
namespace/clean.pm,8522458,13344,705;314237
oo.pm,8535816,1266,706;314698

### AE.pm ###
 =head1 NAME
 
 AE - simpler/faster/newer/cooler AnyEvent API
 
 =head1 SYNOPSIS
 
   use AnyEvent; # not AE
 
   # file handle or descriptor readable
   my $w = AE::io $fh, 0, sub { ...  };
 
   # one-shot or repeating timers
   my $w = AE::timer $seconds,         0, sub { ... }; # once
   my $w = AE::timer $seconds, $interval, sub { ... }; # repeated
 
   print AE::now;  # prints current event loop time
   print AE::time; # think Time::HiRes::time or simply CORE::time.
 
   # POSIX signal
   my $w = AE::signal TERM => sub { ... };
 
   # child process exit
   my $w = AE::child $pid, sub {
      my ($pid, $status) = @_;
      ...
   };
 
   # called when event loop idle (if applicable)
   my $w = AE::idle sub { ... };
 
   my $cv = AE::cv; # stores whether a condition was flagged
   $cv->send; # wake up current and all future recv's
   $cv->recv; # enters "main loop" till $condvar gets ->send
   # use a condvar in callback mode:
   $cv->cb (sub { $_[0]->recv });
 
 
 =head1 DESCRIPTION
 
 This module documents the new simpler AnyEvent API.
 
 The rationale for the new API is that experience with L<EV> shows that
 this API actually "works", despite its lack of extensibility, leading to
 a shorter, easier and faster API.
 
 The main differences from AnyEvent is that function calls are used
 instead of method calls, and that no named arguments are used.
 
 This makes calls to watcher creation functions really short, which can
 make a program more readable despite the lack of named parameters.
 Function calls also allow more static type checking than method calls, so
 many mistakes are caught at compile-time with this API.
 
 Also, some backends (Perl and EV) are so fast that the method call
 overhead is very noticeable (with EV it increases the execution time five-
 to six-fold, with Perl the method call overhead is about a factor of two).
 
 Note that the C<AE> API is an alternative to, not the future version of,
 the AnyEvent API. Both APIs can be used interchangeably and there are
 no plans to "switch", so if in doubt, feel free to use the L<AnyEvent>
 API in new code.
 
 As the AE API is complementary, not everything in the AnyEvent API is
 available, and you still need to use AnyEvent for the finer stuff. Also,
 you should not C<use AE> directly, C<use AnyEvent> will provide the AE
 namespace.
 
 At the moment, these functions will become slower then their method-call
 counterparts when using L<AnyEvent::Strict> or L<AnyEvent::Debug>::wrap.
 
 =head2 FUNCTIONS
 
 This section briefly describes the alternative watcher constructors and
 other functions available inside the C<AE> namespace. Semantics are not
 described here; please refer to the description of the function or method
 with the same name in the L<AnyEvent> manpage for the details.
 
 =over 4
 
 =cut
 
 package AE;
 
 use AnyEvent (); # BEGIN { AnyEvent::common_sense }
 
 our $VERSION = $AnyEvent::VERSION;
 
 =item $w = AE::io $fh_or_fd, $watch_write, $cb
 
 Creates an I/O watcher that listens for read events (C<$watch_write>
 false) or write events (C<$watch_write> is true) on the file handle or
 file descriptor C<$fh_or_fd>.
 
 The callback C<$cb> is invoked as soon and as long as I/O of the type
 specified by C<$watch_write>) can be done on the file handle/descriptor.
 
 Example: wait until STDIN becomes readable.
 
   $stdin_ready = AE::io *STDIN, 0, sub { scalar <STDIN> };
 
 Example: wait until STDOUT becomes writable and print something.
 
   $stdout_ready = AE::io *STDOUT, 1, sub { print STDOUT "woaw\n" };
 
 =item $w = AE::timer $after, $interval, $cb
 
 Creates a timer watcher that invokes the callback C<$cb> after at least
 C<$after> second have passed (C<$after> can be negative or C<0>).
 
 If C<$interval> is C<0>, then the callback will only be invoked once,
 otherwise it must be a positive number of seconds that specifies the
 interval between successive invocations of the callback.
 
 Example: print "too late" after at least one second has passed.
 
   $timer_once = AE::timer 1, 0, sub { print "too late\n" };
 
 Example: print "blubb" once a second, starting as soon as possible.
 
   $timer_repeated = AE::timer 0, 1, sub { print "blubb\n" };
 
 =item $w = AE::signal $signame, $cb
 
 Invoke the callback C<$cb> each time one or more occurrences of the
 named signal C<$signame> are detected.
 
 =item $w = AE::child $pid, $cb
 
 Invokes the callback C<$cb> when the child with the given C<$pid> exits
 (or all children, when C<$pid> is zero).
 
 The callback will get the actual pid and exit status as arguments.
 
 =item $w = AE::idle $cb
 
 Invoke the callback C<$cb> each time the event loop is "idle" (has no
 events outstanding), but do not prevent the event loop from polling for
 more events.
 
 =item $cv = AE::cv
 
 =item $cv = AE::cv { BLOCK }
 
 Create a new condition variable. The first form is identical to C<<
 AnyEvent->condvar >>, the second form additionally sets the callback (as
 if the C<cb> method is called on the condition variable).
 
 =item AE::now
 
 Returns the current event loop time (may be cached by the event loop).
 
 =item AE::now_update
 
 Ensures that the current event loop time is up to date.
 
 =item AE::time
 
 Return the current time (not cached, always consults a hardware clock).
 
 =item AE::postpone { BLOCK }
 
 Exactly the same as C<AnyEvent:::postpone>.
 
 =item AE::log $level, $msg[, @args]
 
 Exactly the same as C<AnyEvent::log> (or C<AnyEvent::Log::log>).
 
 =back
 
 =head1 AUTHOR
 
  Marc Lehmann <schmorp@schmorp.de>
  http://anyevent.schmorp.de
 
 =cut
 
 1
 
### Algorithm/Dependency.pm ###
 package Algorithm::Dependency;
 
 =pod
 
 =head1 NAME
 
 Algorithm::Dependency - Base class for implementing various dependency trees
 
 =head1 SYNOPSIS
 
   use Algorithm::Dependency;
   use Algorithm::Dependency::Source::File;
   
   # Load the data from a simple text file
   my $data_source = Algorithm::Dependency::Source::File->new( 'foo.txt' );
   
   # Create the dependency object, and indicate the items that are already
   # selected/installed/etc in the database
   my $dep = Algorithm::Dependency->new(
       source   => $data_source,
       selected => [ 'This', 'That' ]
       ) or die 'Failed to set up dependency algorithm';
   
   # For the item 'Foo', find out the other things we also have to select.
   # This WON'T include the item we selected, 'Foo'.
   my $also = $dep->depends( 'Foo' );
   print $also
   	? "By selecting 'Foo', you are also selecting the following items: "
   		. join( ', ', @$also )
   	: "Nothing else to select for 'Foo'";
   
   # Find out the order we need to act on the items in.
   # This WILL include the item we selected, 'Foo'.
   my $schedule = $dep->schedule( 'Foo' );
 
 =head1 DESCRIPTION
 
 Algorithm::Dependency is a framework for creating simple read-only
 dependency heirachies, where you have a set of items that rely on other
 items in the set, and require actions on them as well.
 
 Despite the most visible of these being software installation systems like
 the CPAN installer, or debian apt-get, they are usefull in other situations.
 This module intentionally uses implementation-neutral words, to avoid
 confusion.
 
 =head2 Terminology
 
 The term C<ITEM> refers to a single entity, such as a single software
 package, in the overall set of possible entities. Internally, this is a
 fairly simple object. See L<Algorithm::Dependency::Item> for details.
 
 The term C<SELECT> means that a particular item, for your purposes, has
 already been acted up in the required way. For example, if the software
 package had already been installed, and didn't need to be re-installed,
 it would be C<SELECTED>.
 
 The term C<SOURCE> refers to a location that contains the master set of
 items. This will be very application specific, and might be a flat file,
 some form of database, the list of files in a folder, or generated
 dynamically.
 
 =head2 General Description
 
 Algorithm::Dependency implements algorithms relating to dependency
 heirachies. To use this framework, all you need is a source for the master
 list of all the items, and a list of those already selected. If your
 dependency heirachy doesn't require the concept of items that are already
 selected, simply don't pass anything to the constructor for it.
 
 Please note that the class Algorithm::Dependency does NOT implement an
 ordering, for speed and simplicity reasons. That is, the C<schedule> it
 provides is not in any particular order. If item 'A' depends on item 'B',
 it will not place B before A in the schedule. This makes it unsuitable for
 things like software installers, as they typically would need B to be
 installed before A, or the installation of A would fail.
 
 For dependency heirachies requiring the items to be acted on in a particular
 order, either top down or bottom up, see L<Algorithm::Dependency::Ordered>.
 It should be more applicable for your needs. This is the the subclass you
 would probably use to implement a simple ( non-versioned ) package
 installation system. Please note that an ordered heirachy has additional
 constraints. For example, circular dependencies ARE legal in a
 non-ordered heirachy, but ARE NOT legal in an ordered heirachy.
 
 =head2 Extending
 
 A module for creating a source from a simple flat file is included. For
 details see L<Algorithm::Dependency::Source::File>. Information on creating
 a source for your particular use is in L<Algorithm::Dependency::Source>.
 
 =head1 METHODS
 
 =cut
 
 use 5.005;
 use strict;
 use Algorithm::Dependency::Item   ();
 use Algorithm::Dependency::Source ();
 use Params::Util qw{_INSTANCE _ARRAY};
 
 use vars qw{$VERSION};
 BEGIN {
 	$VERSION = '1.110';
 }
 
 
 
 
 
 #####################################################################
 # Constructor
 
 =pod
 
 =head2 new %args
 
 The constructor creates a new context object for the dependency algorithms to
 act in. It takes as argument a series of options for creating the object.
 
 =over 4
 
 =item source => $Source
 
 The only compulsory option is the source of the dependency items. This is
 an object of a subclass of L<Algorithm::Dependency::Source>. In practical terms,
 this means you will create the source object before creating the
 Algorithm::Dependency object.
 
 =item selected => [ 'A', 'B', 'C', etc... ]
 
 The C<selected> option provides a list of those items that have already been
 'selected', acted upon, installed, or whatever. If another item depends on one
 in this list, we don't have to include it in the output of the C<schedule> or
 C<depends> methods.
 
 =item ignore_orphans => 1
 
 Normally, the item source is expected to be largely perfect and error free.
 An 'orphan' is an item name that appears as a dependency of another item, but
 doesn't exist, or has been deleted.
 
 By providing the C<ignore_orphans> flag, orphans are simply ignored. Without
 the C<ignore_orphans> flag, an error will be returned if an orphan is found.
 
 =back
 
 The C<new> constructor returns a new Algorithm::Dependency object on success,
 or C<undef> on error.
 
 =cut
 
 sub new {
 	my $class  = shift;
 	my %args   = @_;
 	my $source = _INSTANCE($args{source}, 'Algorithm::Dependency::Source')
 		or return undef;
 
 	# Create the object
 	my $self = bless {
 		source   => $source, # Source object
 		selected => {},
 		}, $class;
 
 	# Were we given the 'ignore_orphans' flag?
 	if ( $args{ignore_orphans} ) {
 		$self->{ignore_orphans} = 1;
 	}
 
 	# Done, unless we have been given some selected items
 	_ARRAY($args{selected}) or return $self;
 
 	# Make sure each of the selected ids exists
 	my %selected = ();
 	foreach my $id ( @{ $args{selected} } ) {
 		# Does the item exist?
 		return undef unless $source->item($id);
 
 		# Is it a duplicate
 		return undef if $selected{$id};
 
 		# Add to the selected index
 		$selected{$id} = 1;
 	}
 
 	$self->{selected} = \%selected;
 	$self;
 }
 
 
 
 
 
 #####################################################################
 # Basic methods
 
 =pod
 
 =head2 source
 
 The C<source> method retrieves the L<Algorithm::Dependency::Source> object
 for the algorithm context.
 
 =cut
 
 sub source { $_[0]->{source} }
 
 =pod
 
 =head2 selected_list
 
 The C<selected_list> method returns, as a list and in alphabetical order,
 the list of the names of the selected items.
 
 =cut
 
 sub selected_list { sort keys %{$_[0]->{selected}} }
 
 =pod
 
 =head2 selected $name
 
 Given an item name, the C<selected> method will return true if the item is
 selected, false is not, or C<undef> if the item does not exist, or an error
 occurs.
 
 =cut
 
 sub selected { $_[0]->{selected}->{$_[1]} }
 
 =pod
 
 =head2 item $name
 
 The C<item> method fetches and returns the item object, as specified by the
 name argument.
 
 Returns an L<Algorithm::Dependency::Item> object on success, or C<undef> if
 an item does not exist for the argument provided.
 
 =cut
 
 sub item { $_[0]->{source}->item($_[1]) }
 
 
 
 
 
 #####################################################################
 # Main algorithm methods
 
 =pod
 
 =head2 depends $name1, ..., $nameN
 
 Given a list of one or more item names, the C<depends> method will return
 a reference to an array containing a list of the names of all the OTHER
 items that also have to be selected to meet dependencies.
 
 That is, if item A depends on B and C then the C<depends> method would
 return a reference to an array with B and C. ( C<[ 'B', 'C' ]> )
 
 If multiple item names are provided, the same applies. The list returned
 will not contain duplicates.
 
 The method returns a reference to an array of item names on success, a
 reference to an empty array if no other items are needed, or C<undef>
 on error.
 
 =cut
 
 sub depends {
 	my $self    = shift;
 	my @stack   = @_ or return undef;
 	my @depends = ();
 	my %checked = ();
 
 	# Process the stack
 	while ( my $id = shift @stack ) {
 		# Does the id exist?
 		my $Item = $self->{source}->item($id)
 		or $self->{ignore_orphans} ? next : return undef;
 
 		# Skip if selected or checked
 		next if $checked{$id};
 
 		# Add its depends to the stack
 		push @stack, $Item->depends;
 		$checked{$id} = 1;
 
 		# Add anything to the final output that wasn't one of
 		# the original input.
 		unless ( scalar grep { $id eq $_ } @_ ) {
 			push @depends, $id;
 		}
 	}
 
 	# Remove any items already selected
 	my $s = $self->{selected};
 	return [ sort grep { ! $s->{$_} } @depends ];
 }
 
 =pod
 
 =head2 schedule $name1, ..., $nameN
 
 Given a list of one or more item names, the C<depends> method will return,
 as a reference to an array, the ordered list of items you should act upon.
 
 This would be the original names provided, plus those added to satisfy
 dependencies, in the prefered order of action. For the normal algorithm,
 where order it not important, this is alphabetical order. This makes it
 easier for someone watching a program operate on the items to determine
 how far you are through the task and makes any logs easier to read.
 
 If any of the names you provided in the arguments is already selected, it
 will not be included in the list.
 
 The method returns a reference to an array of item names on success, a
 reference to an empty array if no items need to be acted upon, or C<undef>
 on error.
 
 =cut
 
 sub schedule {
 	my $self  = shift;
 	my @items = @_ or return undef;
 
 	# Get their dependencies
 	my $depends = $self->depends( @items ) or return undef;
 
 	# Now return a combined list, removing any items already selected.
 	# We are allowed to return an empty list.
 	my $s = $self->{selected};
 	return [ sort grep { ! $s->{$_} } @items, @$depends ];
 }
 
 =pod
 
 =head2 schedule_all;
 
 The C<schedule_all> method acts the same as the C<schedule> method, but 
 returns a schedule that selected all the so-far unselected items.
 
 =cut
 
 sub schedule_all {
 	my $self = shift;
 	$self->schedule( map { $_->id } $self->source->items );
 }
 
 1;
 
 =pod
 
 =head1 TO DO
 
 Add the C<check_source> method, to verify the integrity of the source.
 
 Possibly add Algorithm::Dependency::Versions, to implement an ordered
 dependency tree with versions, like for perl modules.
 
 Currently readonly. Make the whole thing writable, so the module can be
 used as the core of an actual dependency application, as opposed to just
 being a tool.
 
 =head1 SUPPORT
 
 Bugs should be submitted via the CPAN bug tracker, located at
 
 L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Algorithm-Dependency>
 
 For general comments, contact the author.
 
 =head1 AUTHOR
 
 Adam Kennedy E<lt>adamk@cpan.orgE<gt>
 
 =head1 SEE ALSO
 
 L<Algorithm::Dependency::Ordered>, L<Algorithm::Dependency::Item>,
 L<Algorithm::Dependency::Source>, L<Algorithm::Dependency::Source::File>
 
 =head1 COPYRIGHT
 
 Copyright 2003 - 2009 Adam Kennedy.
 
 This program is free software; you can redistribute
 it and/or modify it under the same terms as Perl itself.
 
 The full text of the license can be found in the
 LICENSE file included with this module.
 
 =cut
### Algorithm/Dependency/Item.pm ###
 package Algorithm::Dependency::Item;
 
 =pod
 
 =head1 NAME
 
 Algorithm::Dependency::Item - Implements an item in a dependency heirachy.
 
 =head1 DESCRIPTION
 
 The Algorithm::Dependency::Item class implements a single item within the
 dependency heirachy. It's quite simple, usually created from within a source,
 and not typically created directly. This is provided for those implementing
 their own source. ( See L<Algorithm::Dependency::Source> for details ).
 
 =head1 METHODS
 
 =cut
 
 use 5.005;
 use strict;
 use Algorithm::Dependency ();
 
 use vars qw{$VERSION};
 BEGIN {
 	$VERSION = '1.110';
 }
 
 
 
 
 
 #####################################################################
 # Constructor
 
 =pod
 
 =head2 new $id, @depends
 
 The C<new> constructor takes as its first argument the id ( name ) of the
 item, and any further arguments are assumed to be the ids of other items that
 this one depends on.
 
 Returns a new C<Algorithm::Dependency::Item> on success, or C<undef>
 on error.
 
 =cut
 
 sub new {
 	my $class = shift;
 	my $id    = (defined $_[0] and ! ref $_[0] and $_[0] ne '') ? shift : return undef;
 	bless { id => $id, depends => [ @_ ] }, $class;
 }
 
 =pod
 
 =head2 id
 
 The C<id> method returns the id of the item.
 
 =cut
 
 sub id { $_[0]->{id} }
 
 =pod
 
 =head2 depends
 
 The C<depends> method returns, as a list, the names of the other items that
 this item depends on.
 
 =cut
 
 sub depends { @{$_[0]->{depends}} }
 
 1;
 
 =pod
 
 =head1 SUPPORT
 
 For general comments, contact the author.
 
 To file a bug against this module, in a way you can keep track of, see the
 CPAN bug tracking system.
 
 L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Algorithm-Dependency>
 
 =head1 AUTHOR
 
 Adam Kennedy E<lt>adamk@cpan.orgE<gt>
 
 =head1 SEE ALSO
 
 L<Algorithm::Dependency>
 
 =head1 COPYRIGHT
 
 Copyright 2003 - 2009 Adam Kennedy.
 
 This program is free software; you can redistribute
 it and/or modify it under the same terms as Perl itself.
 
 The full text of the license can be found in the
 LICENSE file included with this module.
 
 =cut
### Algorithm/Dependency/Ordered.pm ###
 package Algorithm::Dependency::Ordered;
 
 =pod
 
 =head1 NAME
 
 Algorithm::Dependency::Ordered - Implements an ordered dependency heirachy
 
 =head1 DESCRIPTION
 
 Algorithm::Dependency::Ordered implements the most common variety of
 L<Algorithm::Dependency>, the one in which the dependencies of an item must
 be acted upon before the item itself can be acted upon.
 
 In use and semantics, this should be used in exactly the same way as for the
 main parent class. Please note that the output of the C<depends> method is
 NOT changed, as the order of the depends is not assumed to be important.
 Only the output of the C<schedule> method is modified to ensure the correct
 order.
 
 For API details, see L<Algorithm::Dependency>.
 
 =cut
 
 use 5.005;
 use strict;
 use Algorithm::Dependency ();
 
 use vars qw{$VERSION @ISA};
 BEGIN {
 	$VERSION = '1.110';
 	@ISA     = 'Algorithm::Dependency';
 }
 
 
 
 
 
 sub schedule {
 	my $self   = shift;
 	my $source = $self->{source};
 	my @items  = @_ or return undef;
 	return undef if grep { ! $source->item($_) } @items;
 
 	# The actual items to select will be the same as for the unordered
 	# version, so we can simplify the algorithm greatly by using the
 	# normal unordered ->schedule method to get the starting list.
 	my $rv    = $self->SUPER::schedule( @items );
 	my @queue = $rv ? @$rv : return undef;
 
 	# Get a working copy of the selected index
 	my %selected = %{ $self->{selected} };
 
 	# If at any time we check every item in the stack without finding
 	# a suitable candidate for addition to the schedule, we have found
 	# a circular reference error. We need to create a marker to track this.
 	my $error_marker = '';
 
 	# Begin the processing loop
 	my @schedule = ();
 	while ( my $id = shift @queue ) {
 		# Have we checked every item in the stack?
 		return undef if $id eq $error_marker;
 
 		# Are there any un-met dependencies
 		my $Item    = $self->{source}->item($id) or return undef;
 		my @missing = grep { ! $selected{$_} } $Item->depends;
 
 		# Remove orphans if we are ignoring them
 		if ( $self->{ignore_orphans} ) {
 			@missing = grep { $self->{source}->item($_) } @missing;
 		}
 
 		if ( @missing ) {
 			# Set the error marker if not already
 			$error_marker = $id unless $error_marker;
 
 			# Add the id back to the end of the queue
 			push @queue, $id;
 			next;
 		}
 
 		# All dependencies have been met. Add the item to the schedule and
 		# to the selected index, and clear the error marker.
 		push @schedule, $id;
 		$selected{$id} = 1;
 		$error_marker  = '';
 	}
 
 	# All items have been added
 	\@schedule;
 }
 
 1;
 
 =pod
 
 =head1 SUPPORT
 
 Bugs should be submitted via the CPAN bug tracker, located at
 
 L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Algorithm-Dependency>
 
 For general comments, contact the author.
 
 =head1 AUTHOR
 
 Adam Kennedy E<lt>adamk@cpan.orgE<gt>
 
 =head1 SEE ALSO
 
 L<Algorithm::Dependency>
 
 =head1 COPYRIGHT
 
 Copyright 2003 - 2009 Adam Kennedy.
 
 This program is free software; you can redistribute
 it and/or modify it under the same terms as Perl itself.
 
 The full text of the license can be found in the
 LICENSE file included with this module.
 
 =cut
### Algorithm/Dependency/Source.pm ###
 package Algorithm::Dependency::Source;
 
 =pod
 
 =head1 NAME
 
 Algorithm::Dependency::Source - Implements a source of heirachy items
 
 =head1 DESCRIPTION
 
 The Algorithm::Dependency::Source class provides an abstract parent class for
 implementing sources for the heirachy data the algorithm will use. For an
 example of an implementation of this, see
 L<Algorithm::Dependency::Source::File>, which is bundled with the main
 L<Algorithm::Dependency> package.
 
 =head1 METHODS
 
 =cut
 
 use 5.005;
 use strict;
 use Algorithm::Dependency ();
 use Params::Util qw{_SET};
 
 use vars qw{$VERSION};
 BEGIN {
 	$VERSION = '1.110';
 }
 
 
 
 
 
 #####################################################################
 # Constructor
 
 =pod
 
 =head2 new @arguments
 
 Although you cannot directly use the C<new> constructor for
 C<Algorithm::Dependency::Source>, it will work the same in all subclasses.
 
 The constructor takes zero or more subclass specific arguments to define the
 location of the source of the items, and returns a new object. Alrough it
 may check that the arguments you passed are valid, the source will usually
 NOT actually load the items from the source, instead defering the loading
 until you need to use the items.
 
 Returns a new object on success, or C<undef> on error.
 
 =cut
 
 sub new {
 	my $class = shift;
 
 	# This can't be created directly, it must be through
 	# a SUPER::new call
 	if ( $class eq __PACKAGE__ ) {
 		die "Cannot directly instantiate Algorithm::Dependency::Source."
 			. " You must use a subclass";
 	}
 
 	# Create the basic object
 	my $self = bless {
 		# Has the source been loaded
 		loaded      => 0,
 
 		# Indexes
 		items_hash  => undef,
 		items_array => undef,
 		}, $class;
 
 	$self;
 }
 
 =pod
 
 =head2 load
 
 The C<load> method is the public method used to actually load the items from
 their storage location into the the source object. The method will
 automatically called, as needed, in most circumstances. You would generally
 only want to use C<load> manually if you think there may be some uncertainty
 that the source will load correctly, and want to check it will work.
 
 Returns true if the items are loaded successfully, or C<undef> on error.
 
 =cut
 
 sub load {
 	my $self = shift;
 
 	# If this is a reload, clean up in preperation
 	if ( $self->{loaded} ) {
 		$self->{loaded}      = 0;
 		$self->{items_hash}  = undef;
 		$self->{items_array} = undef;
 	}
 
 	# Pass through to the real loader
 	my $items = $self->_load_item_list;
 	return $items unless $items;
 	unless ( _SET($items, 'Algorithm::Dependency::Item') ) {
 		die( ref($self) . "::_load_item_list did not return an Algorithm::Dependency::Item set" );
 	}
 
 	# Add the items
 	foreach my $item ( @$items ) {
 		# Have we added this one already?
 		my $id = $item->id;
 		if ( $self->{items_hash}->{ $id } ) {
 			# Duplicate entry
 			return undef;
 		}
 
 		# Add it
 		push @{ $self->{items_array} }, $item;
 		$self->{items_hash}->{$id} = $item;
 	}
 
 	$self->{loaded} = 1;
 }
 
 =pod
 
 =head2 item $name
 
 The C<item> method fetches and returns the item object specified by the
 name argument.
 
 Returns an L<Algorithm::Dependency::Item> object on success, or C<undef> if
 the named item does not exist in the source.
 
 =cut
 
 sub item {
 	my $self = shift;
 	my $id   = (defined $_[0] and ! ref $_[0] and $_[0] ne '') ? shift : return undef;
 	$self->{loaded} or $self->load or return undef;
 
 	# Return the item (or undef)
 	$self->{items_hash}->{$id};
 }
 
 =pod
 
 =head2 items
 
 The C<items> method returns, as a list of objects, all of the items
 contained in the source. The item objects will be returned in the same order
 as that in the storage location.
 
 Returns a list of L<Algorithm::Dependency::Item> objects on success, or
 C<undef> on error.
 
 =cut
 
 sub items {
 	my $self = shift;
 	$self->{loaded} or $self->load or return undef;
 	@{ $self->{items_array} };
 }
 
 =pod
 
 =head2 missing_dependencies
 
 By default, we are leniant with missing dependencies if the item is neved 
 used. For systems where having a missing dependency can be very bad, the 
 C<missing_dependencies> method checks all Items to make sure their 
 dependencies exist.
 
 If there are any missing dependencies, returns a reference to an array of
 their ids. If there are no missing dependencies, returns 0. Returns 
 C<undef> on error.
 
 =cut
 
 sub missing_dependencies {
 	my $self = shift;
 	$self->{loaded} or $self->load or return undef;
 	
 	# Merged the depends of all the items, and see if
 	# any are missing.
 	my %missing = map  { $_ => 1           }
 	              grep { ! $self->item($_) }
 	              map  { $_->depends       }
 	              $self->items;
 	%missing ? [ sort keys %missing ] : 0;
 }
 
 
 
 
 
 #####################################################################
 # Catch unimplemented methods in subclasses
 
 sub _load_item_list {
 	die "Class $_[0] failed to define the method _load_item_list";
 }
 
 1;
 
 =pod
 
 =head1 EXTENDING
 
 C<Algorithm::Dependency::Source> itself is a fairly thin module, and it
 is intended that you will probably need to extend it to be able to
 extract item data from whatever location you have stored them.
 
 This is usually a fairly simple two step process.
 
 =over 4
 
 =item Overload the C<new> method.
 
 Assuming your subclass takes some form or argument on creation, you will
 need to overload the C<new> method to accept the arguments, validate them,
 and store them in the source object.
 
 =item Define the method C<_load_item_list>.
 
 Leaving our parent's C<load> method to take care of conflict, errors, and
 whatever, the C<_load_item_list> method is used to simply create a list of
 L<Algorithm::Dependency::Item> objects from wherever you store the item,
 and return them as a list.
 
 =back
 
 Having completed these two things, your subclass should be completed. For
 an example of the code, have a look at the source for the simple subclass
 L<Algorithm::Dependency::Source::File>.
 
 =head1 SUPPORT
 
 For general comments, contact the author.
 
 To file a bug against this module, in a way you can keep track of, see the
 CPAN bug tracking system.
 
 L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Algorithm-Dependency>
 
 =head1 AUTHOR
 
 Adam Kennedy E<lt>adamk@cpan.orgE<gt>
 
 =head1 SEE ALSO
 
 L<Algorithm::Dependency>, L<Algorithm::Dependency::Source::File>
 
 =head1 COPYRIGHT
 
 Copyright 2003 - 2009 Adam Kennedy.
 
 This program is free software; you can redistribute
 it and/or modify it under the same terms as Perl itself.
 
 The full text of the license can be found in the
 LICENSE file included with this module.
 
 =cut
### Algorithm/Dependency/Source/File.pm ###
 package Algorithm::Dependency::Source::File;
 
 =pod
 
 =head1 NAME
 
 Algorithm::Dependency::Source::File - File source for dependency heirachys
 
 =head1 DESCRIPTION
 
 Algorithm::Dependency::Source::File implements a
 L<source|Algorithm::Dependency::Source> where the items are stored in a flat
 file or a relatively simple format.
 
 =head2 File Format
 
 The file should be an ordinary text file, consisting of a series of lines,
 with each line completely containing the information for a single item.
 Blank lines, or lines beginning with the hash character '#' will be
 ignored as comments.
 
 For a single item line, only word characters will be used. A 'word character'
 consists of all letters and numbers, and the underscore '_' character.
 Anything that is not a word character will be assumed to be a seperator.
 
 The first word will be used as the name or id of the item, and any further
 words in the line will be used as other items that this one depends on. For
 example, all of the following are legal.
 
   # A single item with no dependencies
   Foo
 
   # Another item that depends on the first one
   Bar Foo
 
   # Depending on multiple others
   Bin Foo Bar
 
   # We can use different seperators
   One:Two|Three-Four+Five=Six Seven
 
   # We can also use multiple non-word characters as seperators
   This&*&^*&File:  is& & & :::REALLY()Neat
 
 From the examples above, it should be easy to create your own files.
 
 =head1 METHODS
 
 This documents the methods differing from the ordinary
 L<Algorithm::Dependency::Source> methods.
 
 =cut
 
 use 5.005;
 use strict;
 use Algorithm::Dependency::Source ();
 
 use vars qw{$VERSION @ISA};
 BEGIN {
 	$VERSION = '1.110';
 	@ISA     = 'Algorithm::Dependency::Source';
 }
 
 
 
 
 
 #####################################################################
 # Constructor
 
 =pod
 
 =head2 new $filename
 
 When constructing a new Algorithm::Dependency::Source::File object, an
 argument should be provided of the name of the file to use. The constructor
 will check that the file exists, and is readable, returning C<undef>
 otherwise.
 
 =cut
 
 sub new {
 	my $class    = shift;
 	my $filename = shift or return undef;
 	return undef unless -r $filename;
 
 	# Get the basic source object
 	my $self = $class->SUPER::new() or return undef;
 
 	# Add our arguments
 	$self->{filename} = $filename;
 
 	$self;
 }
 
 
 
 
 
 #####################################################################
 # Private Methods
 
 sub _load_item_list {
 	my $self = shift;
 
 	# Load the contents of the file
 	local $/ = undef;
 	open( FILE, $self->{filename} ) or return undef;
 	defined(my $source = <FILE>)    or return undef;
 	close( FILE )                   or return undef;
 
 	# Split, trim, clean and remove comments
 	my @content = grep { ! /^\s*(?:\#|$)/ } 
 		split /\s*[\015\012][\s\015\012]*/, $source;
 
 	# Parse and build the item list
 	my @Items = ();
 	foreach my $line ( @content ) {
 		# Split the line by non-word characters
 		my @sections = grep { length $_ } split /\W+/, $line;
 		return undef unless scalar @sections;
 
 		# Create the new item
 		my $Item = Algorithm::Dependency::Item->new( @sections ) or return undef;
 		push @Items, $Item;
 	}
 
 	\@Items;
 }
 
 1;
 
 =pod
 
 =head1 SUPPORT
 
 To file a bug against this module, use the CPAN bug tracking system
 
 L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Algorithm-Dependency>
 
 For other comments, contact the author.
 
 =head1 AUTHOR
 
 Adam Kennedy <adamk@cpan.org>
 
 =head1 SEE ALSO
 
 L<Algorithm::Dependency>
 
 =head1 COPYRIGHT
 
 Copyright 2003 - 2009 Adam Kennedy.
 
 This program is free software; you can redistribute
 it and/or modify it under the same terms as Perl itself.
 
 The full text of the license can be found in the
 LICENSE file included with this module.
 
 =cut
### Algorithm/Dependency/Source/HoA.pm ###
 package Algorithm::Dependency::Source::HoA;
 
 =pod
 
 =head1 NAME
 
 Algorithm::Dependency::Source::HoA - Source for a HASH of ARRAYs
 
 =head1 SYNOPSIS
 
   # The basic data structure
   my $deps = {
       foo => [ 'bar', 'baz' ],
       bar => [],
       baz => [ 'bar' ],
       };
   
   # Create the source from it
   my $Source = Algorithm::Dependency::Source::HoA->new( $deps );
 
 =head1 DESCRIPTION
 
 C<Algorithm::Dependency::Source::HoA> implements a
 L<source|Algorithm::Dependency::Source> where the items names are provided
 in the most simple form, a reference to a C<HASH> of C<ARRAY> references.
 
 =head1 METHODS
 
 This documents the methods differing from the ordinary
 L<Algorithm::Dependency::Source> methods.
 
 =cut
 
 use 5.005;
 use strict;
 use Algorithm::Dependency::Source ();
 use Params::Util qw{_HASH _ARRAY0};
 
 use vars qw{$VERSION @ISA};
 BEGIN {
 	$VERSION = '1.110';
 	@ISA     = 'Algorithm::Dependency::Source';
 }
 
 
 
 
 
 #####################################################################
 # Constructor
 
 =pod
 
 =head2 new $filename
 
 When constructing a new C<Algorithm::Dependency::Source::HoA> object, an
 argument should be provided of a reference to a HASH of ARRAY references,
 containing the names of other HASH elements.
 
 Returns the object, or C<undef> if the structure is not correct.
 
 =cut
 
 sub new {
 	my $class = shift;
 	my $hash  = _HASH(shift) or return undef;
 	foreach my $deps ( values %$hash ) {
 		_ARRAY0($deps) or return undef;
 	}
 
 	# Get the basic source object
 	my $self = $class->SUPER::new() or return undef;
 
 	# Add our arguments
 	$self->{hash} = $hash;
 
 	$self;
 }
 
 
 
 
 
 #####################################################################
 # Private Methods
 
 sub _load_item_list {
 	my $self = shift;
 
 	# Build the item objects from the data
 	my $hash  = $self->{hash};
 	my @items = map {
 		Algorithm::Dependency::Item->new( $_, @{$hash->{$_}} )
 		or return undef;
 		} keys %$hash;
 
 	\@items;
 }
 
 1;
 
 =pod
 
 =head1 SUPPORT
 
 To file a bug against this module, use the CPAN bug tracking system
 
 L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Algorithm-Dependency>
 
 For other comments, contact the author.
 
 =head1 AUTHOR
 
 Adam Kennedy <adamk@cpan.org>
 
 =head1 SEE ALSO
 
 L<Algorithm::Dependency>, L<Algorithm::Dependency::Source>
 
 =head1 COPYRIGHT
 
 Copyright 2003 - 2009 Adam Kennedy.
 
 This program is free software; you can redistribute
 it and/or modify it under the same terms as Perl itself.
 
 The full text of the license can be found in the
 LICENSE file included with this module.
 
 =cut
### Algorithm/Dependency/Source/Invert.pm ###
 package Algorithm::Dependency::Source::Invert;
 
 =pod
 
 =head1 NAME
 
 Algorithm::Dependency::Source::Invert - Logically invert a source
 
 =head1 SYNOPSIS
 
   my $inverted = Algorithm::Dependency::Source::Invert->new( $source );
 
 =head1 DESCRIPTION
 
 This class creates a source from another source, but with all dependencies
 reversed.
 
 =cut
 
 use 5.005;
 use strict;
 use Params::Util '_INSTANCE';
 use Algorithm::Dependency::Source::HoA ();
 
 use vars qw{$VERSION @ISA};
 BEGIN {
 	$VERSION = '1.110';
 	@ISA     = 'Algorithm::Dependency::Source::HoA';
 }
 
 
 
 
 
 #####################################################################
 # Constructor
 
 sub new {
 	my $class  = shift;
 	my $source = _INSTANCE(shift, 'Algorithm::Dependency::Source') or return undef;
 
 	# Derive a HoA from the original source
 	my @items = $source->items;
 	my %hoa   = map { $_->id => [ ] } @items;
 	foreach my $item ( @items ) {
 		my $id   = $item->id;
 		my @deps = $item->depends;
 		foreach my $dep ( @deps ) {
 			push @{ $hoa{$dep} }, $id;
 		}
 	}
 
 	# Hand off to the parent class
 	$class->SUPER::new( \%hoa );
 }
 
 1;
 
 =pod
 
 =head1 SUPPORT
 
 To file a bug against this module, use the CPAN bug tracking system
 
 L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Algorithm-Dependency>
 
 For other comments, contact the author.
 
 =head1 AUTHOR
 
 Adam Kennedy <adamk@cpan.org>
 
 =head1 SEE ALSO
 
 L<Algorithm::Dependency::Source>, L<Algorithm::Dependency::Source::HoA>
 
 =head1 COPYRIGHT
 
 Copyright 2003 - 2009 Adam Kennedy.
 
 This program is free software; you can redistribute
 it and/or modify it under the same terms as Perl itself.
 
 The full text of the license can be found in the
 LICENSE file included with this module.
 
 =cut
### Algorithm/Dependency/Weight.pm ###
 package Algorithm::Dependency::Weight;
 
 =pod
 
 =head1 NAME
 
 Algorithm::Dependency::Weight - Calculate dependency 'weights'
 
 =head1 SYNOPSIS
 
   # Create a source from a file
   my $Source = Algorithm::Dependency::Source->new( 'file.txt' );
   
   # Create a Weight algorithm object
   my $alg = Algorithm::Dependency::Weight->new( source => $Source );
   
   # Find the weight for a single item
   my $weight = $alg->weight('foo');
   print "The weight of 'foo' is $weight\n";
   
   # Or a group
   my $hash = $alg->weight_hash('foo', 'bar', 'baz');
   print "The weight of 'foo', 'bar', and 'bar' are $hash->{foo},"
       . " $hash->{bar} and $hash->{baz} respectively\n";
   
   # Or all of the items
   my $all = $alg->weight_all;
   print "The following is a list from heaviest to lightest:\n";
   foreach ( sort { $all->{$b} <=> $all->{$a} } keys %$all ) {
       print "$_: $all->{$_}\n";
   }
 
 =head1 DESCRIPTION
 
 In dependency systems, it can often be very useful to calculate
 an aggregate or sum for one or all items. For example, to find
 the "naive install weight" of a Perl distribution (where "naive"
 means you treat each distribution equally), you would want the
 distribtion (1) + all its dependencies (n) + all B<their>
 dependencies (n2) recursively downwards.
 
 If calculated using a normal L<Algorithm::Dependency> object, the
 result would be (in a simple systems) equal to:
 
   # Create your normal (non-ordered alg:dep)
   my $dependency = Algorithm::Dependency->new( ... );
   
   # Find the naive weight for an item
   my $weight = scalar($dependency->schedule('itemname'));
 
 C<Algorithm::Dependency::Weight> provides a way of doing this
 with a little more sophistication, and in a way that should work
 reasonable well across all the L<Algorithm::Dependency> family.
 
 Please note that the this might be a little (or more than a little)
 slower than it could be for the limited case of generating weights
 for all of the items at once in a dependency system with no selected
 items and no circular dependencies. BUT you can at least rely on
 this class to do the job properly regardless of the particulars of
 the situation, which is probably more important.
 
 =head2 METHODS
 
 =cut
 
 use 5.005;
 use strict;
 use List::Util            ();
 use Algorithm::Dependency ();
 use Params::Util qw{_INSTANCE _STRING};
 
 use vars qw{$VERSION};
 BEGIN {
 	$VERSION = '1.110';
 }
 
 
 
 
 
 #####################################################################
 # Constructor and Accessors
 
 =pod
 
 =head2 new @params
 
 The C<new> constructor creates a new C<Algorithm::Dependency::Weight>
 object. It takes a number of key/value pairs as parameters (although
 at the present time only one).
 
 =over 4
 
 =item source => $Source
 
 The C<source> param is mostly the same as for L<Algorithm::Dependency>.
 The one addition is that as a source you can provide an
 L<Algorithm::Dependency> object, and the L<Algorithm::Dependency::Source>
 for that will be used.
 
 =back
 
 Returns a new C<Algorithm::Dependency::Weight> object, or C<undef> on error.
 
 =cut
 
 sub new {
 	my $class = shift;
 	my %args  = @_;
 
 	# Get the source object, or derive it from an existing alg-dep
 	my $source = _INSTANCE($args{source}, 'Algorithm::Dependency')
 		? $args{source}->source
 		: _INSTANCE($args{source}, 'Algorithm::Dependency::Source')
 		or return undef;
 
 	# Build the alg-dep object we use
 	my $algdep = Algorithm::Dependency->new(
 		source         => $source,
 		ignore_orphans => 1,
 		) or return undef;
 
 	# Create the basic object
 	my $self = bless {
 		source => $source,
 		algdep => $algdep,
 		weight => {},
 		}, $class;
 
 	$self;
 }
 
 =pod
 
 =head2 source
 
 The C<source> accessor returns the source used for the weight calculations.
 
 This will be either the one passed to the constructor, or the source from
 inside the C<Algorithm::Dependency> object passed as the C<source> param
 (B<not> the object itself, B<its> source).
 
 =cut
 
 sub source {
 	$_[0]->{source}
 }
 
 
 
 
 
 #####################################################################
 # Algorithm::Dependency::Weight Methods
 
 =pod
 
 =head2 weight $name
 
 The C<weight> method takes the name of a single item and calculates its
 weight based on the configuration of the C<Algorithm::Dependency::Weight>
 object.
 
 Returns the weight as a scalar (which in the naive case will be an
 integer, but in more complex uses may be any real number), or C<undef>
 on error.
 
 =cut
 
 sub weight {
 	my $self = shift;
 	my $id   = defined(_STRING($_[0])) ? shift : return undef;
 	$self->{weight}->{$id} or
 	$self->{weight}->{$id} = $self->_weight($id);
 }
 
 sub _weight {
 	my $self  = shift;
 	my $items = $self->{algdep}->schedule($_[0]) or return undef;
 	scalar(@$items);
 }
 
 =pod
 
 =head2 weight_merged @names
 
 The C<weight_merged> method takes the name of a set of items and
 calculates an aggregated weight for the whole set.
 
 Returns the weight as a scalar, or C<undef> on error.
 
 =cut
 
 sub weight_merged {
 	my $self  = shift;
 	my $items = $self->{algdep}->schedule(@_) or return undef;
 	scalar(@$items);
 }
 
 =pod
 
 =head2 weight_hash @names
 
 The C<weight_hash> method takes a list of item names, and calculates
 their weights.
 
 Returns a reference to a C<HASH> with the item names as keys and weights
 as values, or C<undef> on error.
 
 =cut
 
 sub weight_hash {
 	my $self  = shift;
 	my @names = @_;
 
 	# Iterate over the list
 	my %hash = ();
 	foreach my $name ( @names ) {
 		if ( $self->{weight}->{$name} ) {
 			$hash{$name} = $self->{weight}->{$name};
 			next;
 		}
 		$hash{$name} = $self->weight($name) or return undef;
 	}
 
 	\%hash;
 }
 
 =pod
 
 =head2 weight_all
 
 The C<weight_all> method provides the one-shot method for getting the
 weights of all items at once. Please note that this does not do
 anything different or special, but is slightly faster than iterating
 yourself.
 
 Returns a reference to a C<HASH> with the item names as keys and weights
 as values, or C<undef> on error.
 
 =cut
 
 sub weight_all {
 	my $self  = shift;
 	my @items = $self->source->items;
 	defined $items[0] or return undef;
 	$self->weight_hash( map { $_->id } @items );
 }
 
 1;
 
 =pod
 
 =head1 TO DO
 
 - Add support for non-naive weights via either custom code or method name
 
 =head1 SUPPORT
 
 Bugs should be submitted via the CPAN bug tracker, located at
 
 L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Algorithm-Dependency>
 
 For general comments, contact the author.
 
 =head1 AUTHOR
 
 Adam Kennedy E<lt>adamk@cpan.orgE<gt>
 
 =head1 SEE ALSO
 
 L<Algorithm::Dependency>, L<Algorithm::Dependency::Source>
 
 =head1 COPYRIGHT
 
 Copyright 2003 - 2009 Adam Kennedy.
 
 This program is free software; you can redistribute
 it and/or modify it under the same terms as Perl itself.
 
 The full text of the license can be found in the
 LICENSE file included with this module.
 
 =cut
### AnyEvent.pm ###
 =head1 NAME
 
 AnyEvent - the DBI of event loop programming
 
 EV, Event, Glib, Tk, UV, Perl, Event::Lib, Irssi, rxvt-unicode, IO::Async,
 Qt, FLTK and POE are various supported event loops/environments.
 
 =head1 SYNOPSIS
 
    use AnyEvent;
 
    # if you prefer function calls, look at the AE manpage for
    # an alternative API.
 
    # file handle or descriptor readable
    my $w = AnyEvent->io (fh => $fh, poll => "r", cb => sub { ...  });
 
    # one-shot or repeating timers
    my $w = AnyEvent->timer (after => $seconds, cb => sub { ...  });
    my $w = AnyEvent->timer (after => $seconds, interval => $seconds, cb => ...);
 
    print AnyEvent->now;  # prints current event loop time
    print AnyEvent->time; # think Time::HiRes::time or simply CORE::time.
 
    # POSIX signal
    my $w = AnyEvent->signal (signal => "TERM", cb => sub { ... });
 
    # child process exit
    my $w = AnyEvent->child (pid => $pid, cb => sub {
       my ($pid, $status) = @_;
       ...
    });
 
    # called when event loop idle (if applicable)
    my $w = AnyEvent->idle (cb => sub { ... });
 
    my $w = AnyEvent->condvar; # stores whether a condition was flagged
    $w->send; # wake up current and all future recv's
    $w->recv; # enters "main loop" till $condvar gets ->send
    # use a condvar in callback mode:
    $w->cb (sub { $_[0]->recv });
 
 =head1 INTRODUCTION/TUTORIAL
 
 This manpage is mainly a reference manual. If you are interested
 in a tutorial or some gentle introduction, have a look at the
 L<AnyEvent::Intro> manpage.
 
 =head1 SUPPORT
 
 An FAQ document is available as L<AnyEvent::FAQ>.
 
 There also is a mailinglist for discussing all things AnyEvent, and an IRC
 channel, too.
 
 See the AnyEvent project page at the B<Schmorpforge Ta-Sa Software
 Repository>, at L<http://anyevent.schmorp.de>, for more info.
 
 =head1 WHY YOU SHOULD USE THIS MODULE (OR NOT)
 
 Glib, POE, IO::Async, Event... CPAN offers event models by the dozen
 nowadays. So what is different about AnyEvent?
 
 Executive Summary: AnyEvent is I<compatible>, AnyEvent is I<free of
 policy> and AnyEvent is I<small and efficient>.
 
 First and foremost, I<AnyEvent is not an event model> itself, it only
 interfaces to whatever event model the main program happens to use, in a
 pragmatic way. For event models and certain classes of immortals alike,
 the statement "there can only be one" is a bitter reality: In general,
 only one event loop can be active at the same time in a process. AnyEvent
 cannot change this, but it can hide the differences between those event
 loops.
 
 The goal of AnyEvent is to offer module authors the ability to do event
 programming (waiting for I/O or timer events) without subscribing to a
 religion, a way of living, and most importantly: without forcing your
 module users into the same thing by forcing them to use the same event
 model you use.
 
 For modules like POE or IO::Async (which is a total misnomer as it is
 actually doing all I/O I<synchronously>...), using them in your module is
 like joining a cult: After you join, you are dependent on them and you
 cannot use anything else, as they are simply incompatible to everything
 that isn't them. What's worse, all the potential users of your
 module are I<also> forced to use the same event loop you use.
 
 AnyEvent is different: AnyEvent + POE works fine. AnyEvent + Glib works
 fine. AnyEvent + Tk works fine etc. etc. but none of these work together
 with the rest: POE + EV? No go. Tk + Event? No go. Again: if your module
 uses one of those, every user of your module has to use it, too. But if
 your module uses AnyEvent, it works transparently with all event models it
 supports (including stuff like IO::Async, as long as those use one of the
 supported event loops. It is easy to add new event loops to AnyEvent, too,
 so it is future-proof).
 
 In addition to being free of having to use I<the one and only true event
 model>, AnyEvent also is free of bloat and policy: with POE or similar
 modules, you get an enormous amount of code and strict rules you have to
 follow. AnyEvent, on the other hand, is lean and to the point, by only
 offering the functionality that is necessary, in as thin as a wrapper as
 technically possible.
 
 Of course, AnyEvent comes with a big (and fully optional!) toolbox
 of useful functionality, such as an asynchronous DNS resolver, 100%
 non-blocking connects (even with TLS/SSL, IPv6 and on broken platforms
 such as Windows) and lots of real-world knowledge and workarounds for
 platform bugs and differences.
 
 Now, if you I<do want> lots of policy (this can arguably be somewhat
 useful) and you want to force your users to use the one and only event
 model, you should I<not> use this module.
 
 =head1 DESCRIPTION
 
 L<AnyEvent> provides a uniform interface to various event loops. This
 allows module authors to use event loop functionality without forcing
 module users to use a specific event loop implementation (since more
 than one event loop cannot coexist peacefully).
 
 The interface itself is vaguely similar, but not identical to the L<Event>
 module.
 
 During the first call of any watcher-creation method, the module tries
 to detect the currently loaded event loop by probing whether one of the
 following modules is already loaded: L<EV>, L<AnyEvent::Loop>,
 L<Event>, L<Glib>, L<Tk>, L<Event::Lib>, L<Qt>, L<POE>. The first one
 found is used. If none are detected, the module tries to load the first
 four modules in the order given; but note that if L<EV> is not
 available, the pure-perl L<AnyEvent::Loop> should always work, so
 the other two are not normally tried.
 
 Because AnyEvent first checks for modules that are already loaded, loading
 an event model explicitly before first using AnyEvent will likely make
 that model the default. For example:
 
    use Tk;
    use AnyEvent;
 
    # .. AnyEvent will likely default to Tk
 
 The I<likely> means that, if any module loads another event model and
 starts using it, all bets are off - this case should be very rare though,
 as very few modules hardcode event loops without announcing this very
 loudly.
 
 The pure-perl implementation of AnyEvent is called C<AnyEvent::Loop>. Like
 other event modules you can load it explicitly and enjoy the high
 availability of that event loop :)
 
 =head1 WATCHERS
 
 AnyEvent has the central concept of a I<watcher>, which is an object that
 stores relevant data for each kind of event you are waiting for, such as
 the callback to call, the file handle to watch, etc.
 
 These watchers are normal Perl objects with normal Perl lifetime. After
 creating a watcher it will immediately "watch" for events and invoke the
 callback when the event occurs (of course, only when the event model
 is in control).
 
 Note that B<callbacks must not permanently change global variables>
 potentially in use by the event loop (such as C<$_> or C<$[>) and that B<<
 callbacks must not C<die> >>. The former is good programming practice in
 Perl and the latter stems from the fact that exception handling differs
 widely between event loops.
 
 To disable a watcher you have to destroy it (e.g. by setting the
 variable you store it in to C<undef> or otherwise deleting all references
 to it).
 
 All watchers are created by calling a method on the C<AnyEvent> class.
 
 Many watchers either are used with "recursion" (repeating timers for
 example), or need to refer to their watcher object in other ways.
 
 One way to achieve that is this pattern:
 
    my $w; $w = AnyEvent->type (arg => value ..., cb => sub {
       # you can use $w here, for example to undef it
       undef $w;
    });
 
 Note that C<my $w; $w => combination. This is necessary because in Perl,
 my variables are only visible after the statement in which they are
 declared.
 
 =head2 I/O WATCHERS
 
    $w = AnyEvent->io (
       fh   => <filehandle_or_fileno>,
       poll => <"r" or "w">,
       cb   => <callback>,
    );
 
 You can create an I/O watcher by calling the C<< AnyEvent->io >> method
 with the following mandatory key-value pairs as arguments:
 
 C<fh> is the Perl I<file handle> (or a naked file descriptor) to watch
 for events (AnyEvent might or might not keep a reference to this file
 handle). Note that only file handles pointing to things for which
 non-blocking operation makes sense are allowed. This includes sockets,
 most character devices, pipes, fifos and so on, but not for example files
 or block devices.
 
 C<poll> must be a string that is either C<r> or C<w>, which creates a
 watcher waiting for "r"eadable or "w"ritable events, respectively.
 
 C<cb> is the callback to invoke each time the file handle becomes ready.
 
 Although the callback might get passed parameters, their value and
 presence is undefined and you cannot rely on them. Portable AnyEvent
 callbacks cannot use arguments passed to I/O watcher callbacks.
 
 The I/O watcher might use the underlying file descriptor or a copy of it.
 You must not close a file handle as long as any watcher is active on the
 underlying file descriptor.
 
 Some event loops issue spurious readiness notifications, so you should
 always use non-blocking calls when reading/writing from/to your file
 handles.
 
 Example: wait for readability of STDIN, then read a line and disable the
 watcher.
 
    my $w; $w = AnyEvent->io (fh => \*STDIN, poll => 'r', cb => sub {
       chomp (my $input = <STDIN>);
       warn "read: $input\n";
       undef $w;
    });
 
 =head2 TIME WATCHERS
 
    $w = AnyEvent->timer (after => <seconds>, cb => <callback>);
 
    $w = AnyEvent->timer (
       after    => <fractional_seconds>,
       interval => <fractional_seconds>,
       cb       => <callback>,
    );
 
 You can create a time watcher by calling the C<< AnyEvent->timer >>
 method with the following mandatory arguments:
 
 C<after> specifies after how many seconds (fractional values are
 supported) the callback should be invoked. C<cb> is the callback to invoke
 in that case.
 
 Although the callback might get passed parameters, their value and
 presence is undefined and you cannot rely on them. Portable AnyEvent
 callbacks cannot use arguments passed to time watcher callbacks.
 
 The callback will normally be invoked only once. If you specify another
 parameter, C<interval>, as a strictly positive number (> 0), then the
 callback will be invoked regularly at that interval (in fractional
 seconds) after the first invocation. If C<interval> is specified with a
 false value, then it is treated as if it were not specified at all.
 
 The callback will be rescheduled before invoking the callback, but no
 attempt is made to avoid timer drift in most backends, so the interval is
 only approximate.
 
 Example: fire an event after 7.7 seconds.
 
    my $w = AnyEvent->timer (after => 7.7, cb => sub {
       warn "timeout\n";
    });
 
    # to cancel the timer:
    undef $w;
 
 Example 2: fire an event after 0.5 seconds, then roughly every second.
 
    my $w = AnyEvent->timer (after => 0.5, interval => 1, cb => sub {
       warn "timeout\n";
    });
 
 =head3 TIMING ISSUES
 
 There are two ways to handle timers: based on real time (relative, "fire
 in 10 seconds") and based on wallclock time (absolute, "fire at 12
 o'clock").
 
 While most event loops expect timers to specified in a relative way, they
 use absolute time internally. This makes a difference when your clock
 "jumps", for example, when ntp decides to set your clock backwards from
 the wrong date of 2014-01-01 to 2008-01-01, a watcher that is supposed to
 fire "after a second" might actually take six years to finally fire.
 
 AnyEvent cannot compensate for this. The only event loop that is conscious
 of these issues is L<EV>, which offers both relative (ev_timer, based
 on true relative time) and absolute (ev_periodic, based on wallclock time)
 timers.
 
 AnyEvent always prefers relative timers, if available, matching the
 AnyEvent API.
 
 AnyEvent has two additional methods that return the "current time":
 
 =over 4
 
 =item AnyEvent->time
 
 This returns the "current wallclock time" as a fractional number of
 seconds since the Epoch (the same thing as C<time> or C<Time::HiRes::time>
 return, and the result is guaranteed to be compatible with those).
 
 It progresses independently of any event loop processing, i.e. each call
 will check the system clock, which usually gets updated frequently.
 
 =item AnyEvent->now
 
 This also returns the "current wallclock time", but unlike C<time>, above,
 this value might change only once per event loop iteration, depending on
 the event loop (most return the same time as C<time>, above). This is the
 time that AnyEvent's timers get scheduled against.
 
 I<In almost all cases (in all cases if you don't care), this is the
 function to call when you want to know the current time.>
 
 This function is also often faster then C<< AnyEvent->time >>, and
 thus the preferred method if you want some timestamp (for example,
 L<AnyEvent::Handle> uses this to update its activity timeouts).
 
 The rest of this section is only of relevance if you try to be very exact
 with your timing; you can skip it without a bad conscience.
 
 For a practical example of when these times differ, consider L<Event::Lib>
 and L<EV> and the following set-up:
 
 The event loop is running and has just invoked one of your callbacks at
 time=500 (assume no other callbacks delay processing). In your callback,
 you wait a second by executing C<sleep 1> (blocking the process for a
 second) and then (at time=501) you create a relative timer that fires
 after three seconds.
 
 With L<Event::Lib>, C<< AnyEvent->time >> and C<< AnyEvent->now >> will
 both return C<501>, because that is the current time, and the timer will
 be scheduled to fire at time=504 (C<501> + C<3>).
 
 With L<EV>, C<< AnyEvent->time >> returns C<501> (as that is the current
 time), but C<< AnyEvent->now >> returns C<500>, as that is the time the
 last event processing phase started. With L<EV>, your timer gets scheduled
 to run at time=503 (C<500> + C<3>).
 
 In one sense, L<Event::Lib> is more exact, as it uses the current time
 regardless of any delays introduced by event processing. However, most
 callbacks do not expect large delays in processing, so this causes a
 higher drift (and a lot more system calls to get the current time).
 
 In another sense, L<EV> is more exact, as your timer will be scheduled at
 the same time, regardless of how long event processing actually took.
 
 In either case, if you care (and in most cases, you don't), then you
 can get whatever behaviour you want with any event loop, by taking the
 difference between C<< AnyEvent->time >> and C<< AnyEvent->now >> into
 account.
 
 =item AnyEvent->now_update
 
 Some event loops (such as L<EV> or L<AnyEvent::Loop>) cache the current
 time for each loop iteration (see the discussion of L<< AnyEvent->now >>,
 above).
 
 When a callback runs for a long time (or when the process sleeps), then
 this "current" time will differ substantially from the real time, which
 might affect timers and time-outs.
 
 When this is the case, you can call this method, which will update the
 event loop's idea of "current time".
 
 A typical example would be a script in a web server (e.g. C<mod_perl>) -
 when mod_perl executes the script, then the event loop will have the wrong
 idea about the "current time" (being potentially far in the past, when the
 script ran the last time). In that case you should arrange a call to C<<
 AnyEvent->now_update >> each time the web server process wakes up again
 (e.g. at the start of your script, or in a handler).
 
 Note that updating the time I<might> cause some events to be handled.
 
 =back
 
 =head2 SIGNAL WATCHERS
 
    $w = AnyEvent->signal (signal => <uppercase_signal_name>, cb => <callback>);
 
 You can watch for signals using a signal watcher, C<signal> is the signal
 I<name> in uppercase and without any C<SIG> prefix, C<cb> is the Perl
 callback to be invoked whenever a signal occurs.
 
 Although the callback might get passed parameters, their value and
 presence is undefined and you cannot rely on them. Portable AnyEvent
 callbacks cannot use arguments passed to signal watcher callbacks.
 
 Multiple signal occurrences can be clumped together into one callback
 invocation, and callback invocation will be synchronous. Synchronous means
 that it might take a while until the signal gets handled by the process,
 but it is guaranteed not to interrupt any other callbacks.
 
 The main advantage of using these watchers is that you can share a signal
 between multiple watchers, and AnyEvent will ensure that signals will not
 interrupt your program at bad times.
 
 This watcher might use C<%SIG> (depending on the event loop used),
 so programs overwriting those signals directly will likely not work
 correctly.
 
 Example: exit on SIGINT
 
    my $w = AnyEvent->signal (signal => "INT", cb => sub { exit 1 });
 
 =head3 Restart Behaviour
 
 While restart behaviour is up to the event loop implementation, most will
 not restart syscalls (that includes L<Async::Interrupt> and AnyEvent's
 pure perl implementation).
 
 =head3 Safe/Unsafe Signals
 
 Perl signals can be either "safe" (synchronous to opcode handling)
 or "unsafe" (asynchronous) - the former might delay signal delivery
 indefinitely, the latter might corrupt your memory.
 
 AnyEvent signal handlers are, in addition, synchronous to the event loop,
 i.e. they will not interrupt your running perl program but will only be
 called as part of the normal event handling (just like timer, I/O etc.
 callbacks, too).
 
 =head3 Signal Races, Delays and Workarounds
 
 Many event loops (e.g. Glib, Tk, Qt, IO::Async) do not support
 attaching callbacks to signals in a generic way, which is a pity,
 as you cannot do race-free signal handling in perl, requiring
 C libraries for this. AnyEvent will try to do its best, which
 means in some cases, signals will be delayed. The maximum time
 a signal might be delayed is 10 seconds by default, but can
 be overriden via C<$ENV{PERL_ANYEVENT_MAX_SIGNAL_LATENCY}> or
 C<$AnyEvent::MAX_SIGNAL_LATENCY> - see the L<ENVIRONMENT VARIABLES>
 section for details.
 
 All these problems can be avoided by installing the optional
 L<Async::Interrupt> module, which works with most event loops. It will not
 work with inherently broken event loops such as L<Event> or L<Event::Lib>
 (and not with L<POE> currently). For those, you just have to suffer the
 delays.
 
 =head2 CHILD PROCESS WATCHERS
 
    $w = AnyEvent->child (pid => <process id>, cb => <callback>);
 
 You can also watch for a child process exit and catch its exit status.
 
 The child process is specified by the C<pid> argument (on some backends,
 using C<0> watches for any child process exit, on others this will
 croak). The watcher will be triggered only when the child process has
 finished and an exit status is available, not on any trace events
 (stopped/continued).
 
 The callback will be called with the pid and exit status (as returned by
 waitpid), so unlike other watcher types, you I<can> rely on child watcher
 callback arguments.
 
 This watcher type works by installing a signal handler for C<SIGCHLD>,
 and since it cannot be shared, nothing else should use SIGCHLD or reap
 random child processes (waiting for specific child processes, e.g. inside
 C<system>, is just fine).
 
 There is a slight catch to child watchers, however: you usually start them
 I<after> the child process was created, and this means the process could
 have exited already (and no SIGCHLD will be sent anymore).
 
 Not all event models handle this correctly (neither POE nor IO::Async do,
 see their AnyEvent::Impl manpages for details), but even for event models
 that I<do> handle this correctly, they usually need to be loaded before
 the process exits (i.e. before you fork in the first place). AnyEvent's
 pure perl event loop handles all cases correctly regardless of when you
 start the watcher.
 
 This means you cannot create a child watcher as the very first
 thing in an AnyEvent program, you I<have> to create at least one
 watcher before you C<fork> the child (alternatively, you can call
 C<AnyEvent::detect>).
 
 As most event loops do not support waiting for child events, they will be
 emulated by AnyEvent in most cases, in which case the latency and race
 problems mentioned in the description of signal watchers apply.
 
 Example: fork a process and wait for it
 
    my $done = AnyEvent->condvar;
   
    # this forks and immediately calls exit in the child. this
    # normally has all sorts of bad consequences for your parent,
    # so take this as an example only. always fork and exec,
    # or call POSIX::_exit, in real code.
    my $pid = fork or exit 5;
   
    my $w = AnyEvent->child (
       pid => $pid,
       cb  => sub {
          my ($pid, $status) = @_;
          warn "pid $pid exited with status $status";
          $done->send;
       },
    );
   
    # do something else, then wait for process exit
    $done->recv;
 
 =head2 IDLE WATCHERS
 
    $w = AnyEvent->idle (cb => <callback>);
 
 This will repeatedly invoke the callback after the process becomes idle,
 until either the watcher is destroyed or new events have been detected.
 
 Idle watchers are useful when there is a need to do something, but it
 is not so important (or wise) to do it instantly. The callback will be
 invoked only when there is "nothing better to do", which is usually
 defined as "all outstanding events have been handled and no new events
 have been detected". That means that idle watchers ideally get invoked
 when the event loop has just polled for new events but none have been
 detected. Instead of blocking to wait for more events, the idle watchers
 will be invoked.
 
 Unfortunately, most event loops do not really support idle watchers (only
 EV, Event and Glib do it in a usable fashion) - for the rest, AnyEvent
 will simply call the callback "from time to time".
 
 Example: read lines from STDIN, but only process them when the
 program is otherwise idle:
 
    my @lines; # read data
    my $idle_w;
    my $io_w = AnyEvent->io (fh => \*STDIN, poll => 'r', cb => sub {
       push @lines, scalar <STDIN>;
 
       # start an idle watcher, if not already done
       $idle_w ||= AnyEvent->idle (cb => sub {
          # handle only one line, when there are lines left
          if (my $line = shift @lines) {
             print "handled when idle: $line";
          } else {
             # otherwise disable the idle watcher again
             undef $idle_w;
          }
       });
    });
 
 =head2 CONDITION VARIABLES
 
    $cv = AnyEvent->condvar;
 
    $cv->send (<list>);
    my @res = $cv->recv;
 
 If you are familiar with some event loops you will know that all of them
 require you to run some blocking "loop", "run" or similar function that
 will actively watch for new events and call your callbacks.
 
 AnyEvent is slightly different: it expects somebody else to run the event
 loop and will only block when necessary (usually when told by the user).
 
 The tool to do that is called a "condition variable", so called because
 they represent a condition that must become true.
 
 Now is probably a good time to look at the examples further below.
 
 Condition variables can be created by calling the C<< AnyEvent->condvar
 >> method, usually without arguments. The only argument pair allowed is
 C<cb>, which specifies a callback to be called when the condition variable
 becomes true, with the condition variable as the first argument (but not
 the results).
 
 After creation, the condition variable is "false" until it becomes "true"
 by calling the C<send> method (or calling the condition variable as if it
 were a callback, read about the caveats in the description for the C<<
 ->send >> method).
 
 Since condition variables are the most complex part of the AnyEvent API, here are
 some different mental models of what they are - pick the ones you can connect to:
 
 =over 4
 
 =item * Condition variables are like callbacks - you can call them (and pass them instead
 of callbacks). Unlike callbacks however, you can also wait for them to be called.
 
 =item * Condition variables are signals - one side can emit or send them,
 the other side can wait for them, or install a handler that is called when
 the signal fires.
 
 =item * Condition variables are like "Merge Points" - points in your program
 where you merge multiple independent results/control flows into one.
 
 =item * Condition variables represent a transaction - functions that start
 some kind of transaction can return them, leaving the caller the choice
 between waiting in a blocking fashion, or setting a callback.
 
 =item * Condition variables represent future values, or promises to deliver
 some result, long before the result is available.
 
 =back
 
 Condition variables are very useful to signal that something has finished,
 for example, if you write a module that does asynchronous http requests,
 then a condition variable would be the ideal candidate to signal the
 availability of results. The user can either act when the callback is
 called or can synchronously C<< ->recv >> for the results.
 
 You can also use them to simulate traditional event loops - for example,
 you can block your main program until an event occurs - for example, you
 could C<< ->recv >> in your main program until the user clicks the Quit
 button of your app, which would C<< ->send >> the "quit" event.
 
 Note that condition variables recurse into the event loop - if you have
 two pieces of code that call C<< ->recv >> in a round-robin fashion, you
 lose. Therefore, condition variables are good to export to your caller, but
 you should avoid making a blocking wait yourself, at least in callbacks,
 as this asks for trouble.
 
 Condition variables are represented by hash refs in perl, and the keys
 used by AnyEvent itself are all named C<_ae_XXX> to make subclassing
 easy (it is often useful to build your own transaction class on top of
 AnyEvent). To subclass, use C<AnyEvent::CondVar> as base class and call
 its C<new> method in your own C<new> method.
 
 There are two "sides" to a condition variable - the "producer side" which
 eventually calls C<< -> send >>, and the "consumer side", which waits
 for the send to occur.
 
 Example: wait for a timer.
 
    # condition: "wait till the timer is fired"
    my $timer_fired = AnyEvent->condvar;
 
    # create the timer - we could wait for, say
    # a handle becomign ready, or even an
    # AnyEvent::HTTP request to finish, but
    # in this case, we simply use a timer:
    my $w = AnyEvent->timer (
       after => 1,
       cb    => sub { $timer_fired->send },
    );
 
    # this "blocks" (while handling events) till the callback
    # calls ->send
    $timer_fired->recv;
 
 Example: wait for a timer, but take advantage of the fact that condition
 variables are also callable directly.
 
    my $done = AnyEvent->condvar;
    my $delay = AnyEvent->timer (after => 5, cb => $done);
    $done->recv;
 
 Example: Imagine an API that returns a condvar and doesn't support
 callbacks. This is how you make a synchronous call, for example from
 the main program:
 
    use AnyEvent::CouchDB;
 
    ...
 
    my @info = $couchdb->info->recv;
 
 And this is how you would just set a callback to be called whenever the
 results are available:
 
    $couchdb->info->cb (sub {
       my @info = $_[0]->recv;
    });
 
 =head3 METHODS FOR PRODUCERS
 
 These methods should only be used by the producing side, i.e. the
 code/module that eventually sends the signal. Note that it is also
 the producer side which creates the condvar in most cases, but it isn't
 uncommon for the consumer to create it as well.
 
 =over 4
 
 =item $cv->send (...)
 
 Flag the condition as ready - a running C<< ->recv >> and all further
 calls to C<recv> will (eventually) return after this method has been
 called. If nobody is waiting the send will be remembered.
 
 If a callback has been set on the condition variable, it is called
 immediately from within send.
 
 Any arguments passed to the C<send> call will be returned by all
 future C<< ->recv >> calls.
 
 Condition variables are overloaded so one can call them directly (as if
 they were a code reference). Calling them directly is the same as calling
 C<send>.
 
 =item $cv->croak ($error)
 
 Similar to send, but causes all calls to C<< ->recv >> to invoke
 C<Carp::croak> with the given error message/object/scalar.
 
 This can be used to signal any errors to the condition variable
 user/consumer. Doing it this way instead of calling C<croak> directly
 delays the error detection, but has the overwhelming advantage that it
 diagnoses the error at the place where the result is expected, and not
 deep in some event callback with no connection to the actual code causing
 the problem.
 
 =item $cv->begin ([group callback])
 
 =item $cv->end
 
 These two methods can be used to combine many transactions/events into
 one. For example, a function that pings many hosts in parallel might want
 to use a condition variable for the whole process.
 
 Every call to C<< ->begin >> will increment a counter, and every call to
 C<< ->end >> will decrement it.  If the counter reaches C<0> in C<< ->end
 >>, the (last) callback passed to C<begin> will be executed, passing the
 condvar as first argument. That callback is I<supposed> to call C<< ->send
 >>, but that is not required. If no group callback was set, C<send> will
 be called without any arguments.
 
 You can think of C<< $cv->send >> giving you an OR condition (one call
 sends), while C<< $cv->begin >> and C<< $cv->end >> giving you an AND
 condition (all C<begin> calls must be C<end>'ed before the condvar sends).
 
 Let's start with a simple example: you have two I/O watchers (for example,
 STDOUT and STDERR for a program), and you want to wait for both streams to
 close before activating a condvar:
 
    my $cv = AnyEvent->condvar;
 
    $cv->begin; # first watcher
    my $w1 = AnyEvent->io (fh => $fh1, cb => sub {
       defined sysread $fh1, my $buf, 4096
          or $cv->end;
    });
 
    $cv->begin; # second watcher
    my $w2 = AnyEvent->io (fh => $fh2, cb => sub {
       defined sysread $fh2, my $buf, 4096
          or $cv->end;
    });
 
    $cv->recv;
 
 This works because for every event source (EOF on file handle), there is
 one call to C<begin>, so the condvar waits for all calls to C<end> before
 sending.
 
 The ping example mentioned above is slightly more complicated, as the
 there are results to be passed back, and the number of tasks that are
 begun can potentially be zero:
 
    my $cv = AnyEvent->condvar;
 
    my %result;
    $cv->begin (sub { shift->send (\%result) });
 
    for my $host (@list_of_hosts) {
       $cv->begin;
       ping_host_then_call_callback $host, sub {
          $result{$host} = ...;
          $cv->end;
       };
    }
 
    $cv->end;
 
    ...
 
    my $results = $cv->recv;
 
 This code fragment supposedly pings a number of hosts and calls
 C<send> after results for all then have have been gathered - in any
 order. To achieve this, the code issues a call to C<begin> when it starts
 each ping request and calls C<end> when it has received some result for
 it. Since C<begin> and C<end> only maintain a counter, the order in which
 results arrive is not relevant.
 
 There is an additional bracketing call to C<begin> and C<end> outside the
 loop, which serves two important purposes: first, it sets the callback
 to be called once the counter reaches C<0>, and second, it ensures that
 C<send> is called even when C<no> hosts are being pinged (the loop
 doesn't execute once).
 
 This is the general pattern when you "fan out" into multiple (but
 potentially zero) subrequests: use an outer C<begin>/C<end> pair to set
 the callback and ensure C<end> is called at least once, and then, for each
 subrequest you start, call C<begin> and for each subrequest you finish,
 call C<end>.
 
 =back
 
 =head3 METHODS FOR CONSUMERS
 
 These methods should only be used by the consuming side, i.e. the
 code awaits the condition.
 
 =over 4
 
 =item $cv->recv
 
 Wait (blocking if necessary) until the C<< ->send >> or C<< ->croak
 >> methods have been called on C<$cv>, while servicing other watchers
 normally.
 
 You can only wait once on a condition - additional calls are valid but
 will return immediately.
 
 If an error condition has been set by calling C<< ->croak >>, then this
 function will call C<croak>.
 
 In list context, all parameters passed to C<send> will be returned,
 in scalar context only the first one will be returned.
 
 Note that doing a blocking wait in a callback is not supported by any
 event loop, that is, recursive invocation of a blocking C<< ->recv >> is
 not allowed and the C<recv> call will C<croak> if such a condition is
 detected. This requirement can be dropped by relying on L<Coro::AnyEvent>
 , which allows you to do a blocking C<< ->recv >> from any thread
 that doesn't run the event loop itself. L<Coro::AnyEvent> is loaded
 automatically when L<Coro> is used with L<AnyEvent>, so code does not need
 to do anything special to take advantage of that: any code that would
 normally block your program because it calls C<recv>, be executed in an
 C<async> thread instead without blocking other threads.
 
 Not all event models support a blocking wait - some die in that case
 (programs might want to do that to stay interactive), so I<if you are
 using this from a module, never require a blocking wait>. Instead, let the
 caller decide whether the call will block or not (for example, by coupling
 condition variables with some kind of request results and supporting
 callbacks so the caller knows that getting the result will not block,
 while still supporting blocking waits if the caller so desires).
 
 You can ensure that C<< ->recv >> never blocks by setting a callback and
 only calling C<< ->recv >> from within that callback (or at a later
 time). This will work even when the event loop does not support blocking
 waits otherwise.
 
 =item $bool = $cv->ready
 
 Returns true when the condition is "true", i.e. whether C<send> or
 C<croak> have been called.
 
 =item $cb = $cv->cb ($cb->($cv))
 
 This is a mutator function that returns the callback set and optionally
 replaces it before doing so.
 
 The callback will be called when the condition becomes "true", i.e. when
 C<send> or C<croak> are called, with the only argument being the
 condition variable itself. If the condition is already true, the
 callback is called immediately when it is set. Calling C<recv> inside
 the callback or at any later time is guaranteed not to block.
 
 =back
 
 =head1 SUPPORTED EVENT LOOPS/BACKENDS
 
 The available backend classes are (every class has its own manpage):
 
 =over 4
 
 =item Backends that are autoprobed when no other event loop can be found.
 
 EV is the preferred backend when no other event loop seems to be in
 use. If EV is not installed, then AnyEvent will fall back to its own
 pure-perl implementation, which is available everywhere as it comes with
 AnyEvent itself.
 
    AnyEvent::Impl::EV        based on EV (interface to libev, best choice).
    AnyEvent::Impl::Perl      pure-perl AnyEvent::Loop, fast and portable.
 
 =item Backends that are transparently being picked up when they are used.
 
 These will be used if they are already loaded when the first watcher
 is created, in which case it is assumed that the application is using
 them. This means that AnyEvent will automatically pick the right backend
 when the main program loads an event module before anything starts to
 create watchers. Nothing special needs to be done by the main program.
 
    AnyEvent::Impl::Event     based on Event, very stable, few glitches.
    AnyEvent::Impl::Glib      based on Glib, slow but very stable.
    AnyEvent::Impl::Tk        based on Tk, very broken.
    AnyEvent::Impl::UV        based on UV, innovated square wheels.
    AnyEvent::Impl::EventLib  based on Event::Lib, leaks memory and worse.
    AnyEvent::Impl::POE       based on POE, very slow, some limitations.
    AnyEvent::Impl::Irssi     used when running within irssi.
    AnyEvent::Impl::IOAsync   based on IO::Async.
    AnyEvent::Impl::Cocoa     based on Cocoa::EventLoop.
    AnyEvent::Impl::FLTK      based on FLTK (fltk 2 binding).
 
 =item Backends with special needs.
 
 Qt requires the Qt::Application to be instantiated first, but will
 otherwise be picked up automatically. As long as the main program
 instantiates the application before any AnyEvent watchers are created,
 everything should just work.
 
    AnyEvent::Impl::Qt        based on Qt.
 
 =item Event loops that are indirectly supported via other backends.
 
 Some event loops can be supported via other modules:
 
 There is no direct support for WxWidgets (L<Wx>) or L<Prima>.
 
 B<WxWidgets> has no support for watching file handles. However, you can
 use WxWidgets through the POE adaptor, as POE has a Wx backend that simply
 polls 20 times per second, which was considered to be too horrible to even
 consider for AnyEvent.
 
 B<Prima> is not supported as nobody seems to be using it, but it has a POE
 backend, so it can be supported through POE.
 
 AnyEvent knows about both L<Prima> and L<Wx>, however, and will try to
 load L<POE> when detecting them, in the hope that POE will pick them up,
 in which case everything will be automatic.
 
 =back
 
 =head1 GLOBAL VARIABLES AND FUNCTIONS
 
 These are not normally required to use AnyEvent, but can be useful to
 write AnyEvent extension modules.
 
 =over 4
 
 =item $AnyEvent::MODEL
 
 Contains C<undef> until the first watcher is being created, before the
 backend has been autodetected.
 
 Afterwards it contains the event model that is being used, which is the
 name of the Perl class implementing the model. This class is usually one
 of the C<AnyEvent::Impl::xxx> modules, but can be any other class in the
 case AnyEvent has been extended at runtime (e.g. in I<rxvt-unicode> it
 will be C<urxvt::anyevent>).
 
 =item AnyEvent::detect
 
 Returns C<$AnyEvent::MODEL>, forcing autodetection of the event model
 if necessary. You should only call this function right before you would
 have created an AnyEvent watcher anyway, that is, as late as possible at
 runtime, and not e.g. during initialisation of your module.
 
 The effect of calling this function is as if a watcher had been created
 (specifically, actions that happen "when the first watcher is created"
 happen when calling detetc as well).
 
 If you need to do some initialisation before AnyEvent watchers are
 created, use C<post_detect>.
 
 =item $guard = AnyEvent::post_detect { BLOCK }
 
 Arranges for the code block to be executed as soon as the event model is
 autodetected (or immediately if that has already happened).
 
 The block will be executed I<after> the actual backend has been detected
 (C<$AnyEvent::MODEL> is set), but I<before> any watchers have been
 created, so it is possible to e.g. patch C<@AnyEvent::ISA> or do
 other initialisations - see the sources of L<AnyEvent::Strict> or
 L<AnyEvent::AIO> to see how this is used.
 
 The most common usage is to create some global watchers, without forcing
 event module detection too early, for example, L<AnyEvent::AIO> creates
 and installs the global L<IO::AIO> watcher in a C<post_detect> block to
 avoid autodetecting the event module at load time.
 
 If called in scalar or list context, then it creates and returns an object
 that automatically removes the callback again when it is destroyed (or
 C<undef> when the hook was immediately executed). See L<AnyEvent::AIO> for
 a case where this is useful.
 
 Example: Create a watcher for the IO::AIO module and store it in
 C<$WATCHER>, but do so only do so after the event loop is initialised.
 
    our WATCHER;
 
    my $guard = AnyEvent::post_detect {
       $WATCHER = AnyEvent->io (fh => IO::AIO::poll_fileno, poll => 'r', cb => \&IO::AIO::poll_cb);
    };
 
    # the ||= is important in case post_detect immediately runs the block,
    # as to not clobber the newly-created watcher. assigning both watcher and
    # post_detect guard to the same variable has the advantage of users being
    # able to just C<undef $WATCHER> if the watcher causes them grief.
 
    $WATCHER ||= $guard;
 
 =item @AnyEvent::post_detect
 
 If there are any code references in this array (you can C<push> to it
 before or after loading AnyEvent), then they will be called directly
 after the event loop has been chosen.
 
 You should check C<$AnyEvent::MODEL> before adding to this array, though:
 if it is defined then the event loop has already been detected, and the
 array will be ignored.
 
 Best use C<AnyEvent::post_detect { BLOCK }> when your application allows
 it, as it takes care of these details.
 
 This variable is mainly useful for modules that can do something useful
 when AnyEvent is used and thus want to know when it is initialised, but do
 not need to even load it by default. This array provides the means to hook
 into AnyEvent passively, without loading it.
 
 Example: To load Coro::AnyEvent whenever Coro and AnyEvent are used
 together, you could put this into Coro (this is the actual code used by
 Coro to accomplish this):
 
    if (defined $AnyEvent::MODEL) {
       # AnyEvent already initialised, so load Coro::AnyEvent
       require Coro::AnyEvent;
    } else {
       # AnyEvent not yet initialised, so make sure to load Coro::AnyEvent
       # as soon as it is
       push @AnyEvent::post_detect, sub { require Coro::AnyEvent };
    }
 
 =item AnyEvent::postpone { BLOCK }
 
 Arranges for the block to be executed as soon as possible, but not before
 the call itself returns. In practise, the block will be executed just
 before the event loop polls for new events, or shortly afterwards.
 
 This function never returns anything (to make the C<return postpone { ...
 }> idiom more useful.
 
 To understand the usefulness of this function, consider a function that
 asynchronously does something for you and returns some transaction
 object or guard to let you cancel the operation. For example,
 C<AnyEvent::Socket::tcp_connect>:
 
    # start a connection attempt unless one is active
    $self->{connect_guard} ||= AnyEvent::Socket::tcp_connect "www.example.net", 80, sub {
       delete $self->{connect_guard};
       ...
    };
 
 Imagine that this function could instantly call the callback, for
 example, because it detects an obvious error such as a negative port
 number. Invoking the callback before the function returns causes problems
 however: the callback will be called and will try to delete the guard
 object. But since the function hasn't returned yet, there is nothing to
 delete. When the function eventually returns it will assign the guard
 object to C<< $self->{connect_guard} >>, where it will likely never be
 deleted, so the program thinks it is still trying to connect.
 
 This is where C<AnyEvent::postpone> should be used. Instead of calling the
 callback directly on error:
 
    $cb->(undef), return # signal error to callback, BAD!
       if $some_error_condition;
 
 It should use C<postpone>:
 
    AnyEvent::postpone { $cb->(undef) }, return # signal error to callback, later
       if $some_error_condition;
 
 =item AnyEvent::log $level, $msg[, @args]
 
 Log the given C<$msg> at the given C<$level>.
 
 If L<AnyEvent::Log> is not loaded then this function makes a simple test
 to see whether the message will be logged. If the test succeeds it will
 load AnyEvent::Log and call C<AnyEvent::Log::log> - consequently, look at
 the L<AnyEvent::Log> documentation for details.
 
 If the test fails it will simply return. Right now this happens when a
 numerical loglevel is used and it is larger than the level specified via
 C<$ENV{PERL_ANYEVENT_VERBOSE}>.
 
 If you want to sprinkle loads of logging calls around your code, consider
 creating a logger callback with the C<AnyEvent::Log::logger> function,
 which can reduce typing, codesize and can reduce the logging overhead
 enourmously.
 
 =item AnyEvent::fh_block $filehandle
 
 =item AnyEvent::fh_unblock $filehandle
 
 Sets blocking or non-blocking behaviour for the given filehandle.
 
 =back
 
 =head1 WHAT TO DO IN A MODULE
 
 As a module author, you should C<use AnyEvent> and call AnyEvent methods
 freely, but you should not load a specific event module or rely on it.
 
 Be careful when you create watchers in the module body - AnyEvent will
 decide which event module to use as soon as the first method is called, so
 by calling AnyEvent in your module body you force the user of your module
 to load the event module first.
 
 Never call C<< ->recv >> on a condition variable unless you I<know> that
 the C<< ->send >> method has been called on it already. This is
 because it will stall the whole program, and the whole point of using
 events is to stay interactive.
 
 It is fine, however, to call C<< ->recv >> when the user of your module
 requests it (i.e. if you create a http request object ad have a method
 called C<results> that returns the results, it may call C<< ->recv >>
 freely, as the user of your module knows what she is doing. Always).
 
 =head1 WHAT TO DO IN THE MAIN PROGRAM
 
 There will always be a single main program - the only place that should
 dictate which event model to use.
 
 If the program is not event-based, it need not do anything special, even
 when it depends on a module that uses an AnyEvent. If the program itself
 uses AnyEvent, but does not care which event loop is used, all it needs
 to do is C<use AnyEvent>. In either case, AnyEvent will choose the best
 available loop implementation.
 
 If the main program relies on a specific event model - for example, in
 Gtk2 programs you have to rely on the Glib module - you should load the
 event module before loading AnyEvent or any module that uses it: generally
 speaking, you should load it as early as possible. The reason is that
 modules might create watchers when they are loaded, and AnyEvent will
 decide on the event model to use as soon as it creates watchers, and it
 might choose the wrong one unless you load the correct one yourself.
 
 You can chose to use a pure-perl implementation by loading the
 C<AnyEvent::Loop> module, which gives you similar behaviour
 everywhere, but letting AnyEvent chose the model is generally better.
 
 =head2 MAINLOOP EMULATION
 
 Sometimes (often for short test scripts, or even standalone programs who
 only want to use AnyEvent), you do not want to run a specific event loop.
 
 In that case, you can use a condition variable like this:
 
    AnyEvent->condvar->recv;
 
 This has the effect of entering the event loop and looping forever.
 
 Note that usually your program has some exit condition, in which case
 it is better to use the "traditional" approach of storing a condition
 variable somewhere, waiting for it, and sending it when the program should
 exit cleanly.
 
 
 =head1 OTHER MODULES
 
 The following is a non-exhaustive list of additional modules that use
 AnyEvent as a client and can therefore be mixed easily with other
 AnyEvent modules and other event loops in the same program. Some of the
 modules come as part of AnyEvent, the others are available via CPAN (see
 L<http://search.cpan.org/search?m=module&q=anyevent%3A%3A*> for
 a longer non-exhaustive list), and the list is heavily biased towards
 modules of the AnyEvent author himself :)
 
 =over 4
 
 =item L<AnyEvent::Util> (part of the AnyEvent distribution)
 
 Contains various utility functions that replace often-used blocking
 functions such as C<inet_aton> with event/callback-based versions.
 
 =item L<AnyEvent::Socket> (part of the AnyEvent distribution)
 
 Provides various utility functions for (internet protocol) sockets,
 addresses and name resolution. Also functions to create non-blocking tcp
 connections or tcp servers, with IPv6 and SRV record support and more.
 
 =item L<AnyEvent::Handle> (part of the AnyEvent distribution)
 
 Provide read and write buffers, manages watchers for reads and writes,
 supports raw and formatted I/O, I/O queued and fully transparent and
 non-blocking SSL/TLS (via L<AnyEvent::TLS>).
 
 =item L<AnyEvent::DNS> (part of the AnyEvent distribution)
 
 Provides rich asynchronous DNS resolver capabilities.
 
 =item L<AnyEvent::HTTP>, L<AnyEvent::IRC>, L<AnyEvent::XMPP>, L<AnyEvent::GPSD>, L<AnyEvent::IGS>, L<AnyEvent::FCP>
 
 Implement event-based interfaces to the protocols of the same name (for
 the curious, IGS is the International Go Server and FCP is the Freenet
 Client Protocol).
 
 =item L<AnyEvent::AIO> (part of the AnyEvent distribution)
 
 Truly asynchronous (as opposed to non-blocking) I/O, should be in the
 toolbox of every event programmer. AnyEvent::AIO transparently fuses
 L<IO::AIO> and AnyEvent together, giving AnyEvent access to event-based
 file I/O, and much more.
 
 =item L<AnyEvent::Fork>, L<AnyEvent::Fork::RPC>, L<AnyEvent::Fork::Pool>, L<AnyEvent::Fork::Remote>
 
 These let you safely fork new subprocesses, either locally or
 remotely (e.g.v ia ssh), using some RPC protocol or not, without
 the limitations normally imposed by fork (AnyEvent works fine for
 example). Dynamically-resized worker pools are obviously included as well.
 
 And they are quite tiny and fast as well - "abusing" L<AnyEvent::Fork>
 just to exec external programs can easily beat using C<fork> and C<exec>
 (or even C<system>) in most programs.
 
 =item L<AnyEvent::Filesys::Notify>
 
 AnyEvent is good for non-blocking stuff, but it can't detect file or
 path changes (e.g. "watch this directory for new files", "watch this
 file for changes"). The L<AnyEvent::Filesys::Notify> module promises to
 do just that in a portbale fashion, supporting inotify on GNU/Linux and
 some weird, without doubt broken, stuff on OS X to monitor files. It can
 fall back to blocking scans at regular intervals transparently on other
 platforms, so it's about as portable as it gets.
 
 (I haven't used it myself, but it seems the biggest problem with it is
 it quite bad performance).
 
 =item L<AnyEvent::DBI>
 
 Executes L<DBI> requests asynchronously in a proxy process for you,
 notifying you in an event-based way when the operation is finished.
 
 =item L<AnyEvent::FastPing>
 
 The fastest ping in the west.
 
 =item L<Coro>
 
 Has special support for AnyEvent via L<Coro::AnyEvent>, which allows you
 to simply invert the flow control - don't call us, we will call you:
 
    async {
       Coro::AnyEvent::sleep 5; # creates a 5s timer and waits for it
       print "5 seconds later!\n";
 
       Coro::AnyEvent::readable *STDIN; # uses an I/O watcher
       my $line = <STDIN>; # works for ttys
 
       AnyEvent::HTTP::http_get "url", Coro::rouse_cb;
       my ($body, $hdr) = Coro::rouse_wait;
    };
 
 =back
 
 =cut
 
 package AnyEvent;
 
 BEGIN {
    require "AnyEvent/constants.pl";
    &AnyEvent::common_sense;
 }
 
 use Carp ();
 
 our $VERSION = 7.11;
 our $MODEL;
 our @ISA;
 our @REGISTRY;
 our $VERBOSE;
 our %PROTOCOL; # (ipv4|ipv6) => (1|2), higher numbers are preferred
 our $MAX_SIGNAL_LATENCY = $ENV{PERL_ANYEVENT_MAX_SIGNAL_LATENCY} || 10; # executes after the BEGIN block below (tainting!)
 
 BEGIN {
    eval "sub TAINT (){" . (${^TAINT}*1) . "}";
 
    delete @ENV{grep /^PERL_ANYEVENT_/, keys %ENV}
       if ${^TAINT};
 
    $ENV{"PERL_ANYEVENT_$_"} = $ENV{"AE_$_"}
       for grep s/^AE_// && !exists $ENV{"PERL_ANYEVENT_$_"}, keys %ENV;
 
    @ENV{grep /^PERL_ANYEVENT_/, keys %ENV} = ()
       if ${^TAINT};
 
    # $ENV{PERL_ANYEVENT_xxx} now valid
 
    $VERBOSE = length $ENV{PERL_ANYEVENT_VERBOSE} ? $ENV{PERL_ANYEVENT_VERBOSE}*1 : 4;
 
    my $idx;
    $PROTOCOL{$_} = ++$idx
       for reverse split /\s*,\s*/,
              $ENV{PERL_ANYEVENT_PROTOCOLS} || "ipv4,ipv6";
 }
 
 our @post_detect;
 
 sub post_detect(&) {
    my ($cb) = @_;
 
    push @post_detect, $cb;
 
    defined wantarray
       ? bless \$cb, "AnyEvent::Util::postdetect"
       : ()
 }
 
 sub AnyEvent::Util::postdetect::DESTROY {
    @post_detect = grep $_ != ${$_[0]}, @post_detect;
 }
 
 our $POSTPONE_W;
 our @POSTPONE;
 
 sub _postpone_exec {
    undef $POSTPONE_W;
 
    &{ shift @POSTPONE }
       while @POSTPONE;
 }
 
 sub postpone(&) {
    push @POSTPONE, shift;
 
    $POSTPONE_W ||= AE::timer (0, 0, \&_postpone_exec);
 
    ()
 }
 
 sub log($$;@) {
    # only load the big bloated module when we actually are about to log something
    if ($_[0] <= ($VERBOSE || 1)) { # also catches non-numeric levels(!) and fatal
       local ($!, $@);
       require AnyEvent::Log; # among other things, sets $VERBOSE to 9
       # AnyEvent::Log overwrites this function
       goto &log;
    }
 
    0 # not logged
 }
 
 sub _logger($;$) {
    my ($level, $renabled) = @_;
 
    $$renabled = $level <= $VERBOSE;
 
    my $logger = [(caller)[0], $level, $renabled];
 
    $AnyEvent::Log::LOGGER{$logger+0} = $logger;
 
 #   return unless defined wantarray;
 # 
 #   require AnyEvent::Util;
 #   my $guard = AnyEvent::Util::guard (sub {
 #      # "clean up"
 #      delete $LOGGER{$logger+0};
 #   });
 # 
 #   sub {
 #      return 0 unless $$renabled;
 # 
 #      $guard if 0; # keep guard alive, but don't cause runtime overhead
 #      require AnyEvent::Log unless $AnyEvent::Log::VERSION;
 #      package AnyEvent::Log;
 #      _log ($logger->[0], $level, @_) # logger->[0] has been converted at load time
 #   }
 }
 
 if (length $ENV{PERL_ANYEVENT_LOG}) {
    require AnyEvent::Log; # AnyEvent::Log does the thing for us
 }
 
 BEGIN {
    *_fh_nonblocking = AnyEvent::WIN32
       ? sub($$) {
           ioctl $_[0], 0x8004667e, pack "L", $_[1]; # FIONBIO
         }
       : sub($$) {
           fcntl $_[0], AnyEvent::F_SETFL, $_[1] ? AnyEvent::O_NONBLOCK : 0;
         }
    ;
 }
 
 sub fh_block($) {
    _fh_nonblocking shift, 0
 }
 
 sub fh_unblock($) {
    _fh_nonblocking shift, 1
 }
 
 our @models = (
    [EV::                   => AnyEvent::Impl::EV::],
    [AnyEvent::Loop::       => AnyEvent::Impl::Perl::],
    # everything below here will not (normally) be autoprobed
    # as the pure perl backend should work everywhere
    # and is usually faster
    [Irssi::                => AnyEvent::Impl::Irssi::],    # Irssi has a bogus "Event" package, so msut be near the top
    [Event::                => AnyEvent::Impl::Event::],    # slow, stable
    [Glib::                 => AnyEvent::Impl::Glib::],     # becomes extremely slow with many watchers
    # everything below here should not be autoloaded
    [Event::Lib::           => AnyEvent::Impl::EventLib::], # too buggy
    [Tk::                   => AnyEvent::Impl::Tk::],       # crashes with many handles
    [UV::                   => AnyEvent::Impl::UV::],       # switched from libev, added back all bugs imaginable
    [Qt::                   => AnyEvent::Impl::Qt::],       # requires special main program
    [POE::Kernel::          => AnyEvent::Impl::POE::],      # lasciate ogni speranza
    [Wx::                   => AnyEvent::Impl::POE::],
    [Prima::                => AnyEvent::Impl::POE::],
    [IO::Async::Loop::      => AnyEvent::Impl::IOAsync::],  # a bitch to autodetect
    [Cocoa::EventLoop::     => AnyEvent::Impl::Cocoa::],
    [FLTK::                 => AnyEvent::Impl::FLTK::],
 );
 
 our @isa_hook;
 
 sub _isa_set {
    my @pkg = ("AnyEvent", (map $_->[0], grep defined, @isa_hook), $MODEL);
 
    @{"$pkg[$_-1]::ISA"} = $pkg[$_]
       for 1 .. $#pkg;
 
    grep $_ && $_->[1], @isa_hook
       and AE::_reset ();
 }
 
 # used for hooking AnyEvent::Strict and AnyEvent::Debug::Wrap into the class hierarchy
 sub _isa_hook($$;$) {
    my ($i, $pkg, $reset_ae) = @_;
 
    $isa_hook[$i] = $pkg ? [$pkg, $reset_ae] : undef;
 
    _isa_set;
 }
 
 # all autoloaded methods reserve the complete glob, not just the method slot.
 # due to bugs in perls method cache implementation.
 our @methods = qw(io timer time now now_update signal child idle condvar);
 
 sub detect() {
    return $MODEL if $MODEL; # some programs keep references to detect
 
    # IO::Async::Loop::AnyEvent is extremely evil, refuse to work with it
    # the author knows about the problems and what it does to AnyEvent as a whole
    # (and the ability of others to use AnyEvent), but simply wants to abuse AnyEvent
    # anyway.
    AnyEvent::log fatal => "IO::Async::Loop::AnyEvent detected - that module is broken by\n"
                         . "design, abuses internals and breaks AnyEvent - will not continue."
       if exists $INC{"IO/Async/Loop/AnyEvent.pm"};
 
    local $!; # for good measure
    local $SIG{__DIE__}; # we use eval
 
    # free some memory
    *detect = sub () { $MODEL };
    # undef &func doesn't correctly update the method cache. grmbl.
    # so we delete the whole glob. grmbl.
    # otoh, perl doesn't let me undef an active usb, but it lets me free
    # a glob with an active sub. hrm. i hope it works, but perl is
    # usually buggy in this department. sigh.
    delete @{"AnyEvent::"}{@methods};
    undef @methods;
 
    if ($ENV{PERL_ANYEVENT_MODEL} =~ /^([a-zA-Z0-9:]+)$/) {
       my $model = $1;
       $model = "AnyEvent::Impl::$model" unless $model =~ s/::$//;
       if (eval "require $model") {
          AnyEvent::log 7 => "Loaded model '$model' (forced by \$ENV{PERL_ANYEVENT_MODEL}), using it.";
          $MODEL = $model;
       } else {
          AnyEvent::log 4 => "Unable to load model '$model' (from \$ENV{PERL_ANYEVENT_MODEL}):\n$@";
       }
    }
 
    # check for already loaded models
    unless ($MODEL) {
       for (@REGISTRY, @models) {
          my ($package, $model) = @$_;
          if (${"$package\::VERSION"} > 0) {
             if (eval "require $model") {
                AnyEvent::log 7 => "Autodetected model '$model', using it.";
                $MODEL = $model;
                last;
             } else {
                AnyEvent::log 8 => "Detected event loop $package, but cannot load '$model', skipping: $@";
             }
          }
       }
 
       unless ($MODEL) {
          # try to autoload a model
          for (@REGISTRY, @models) {
             my ($package, $model) = @$_;
             if (
                eval "require $package"
                and ${"$package\::VERSION"} > 0
                and eval "require $model"
             ) {
                AnyEvent::log 7 => "Autoloaded model '$model', using it.";
                $MODEL = $model;
                last;
             }
          }
 
          $MODEL
            or AnyEvent::log fatal => "Backend autodetection failed - did you properly install AnyEvent?";
       }
    }
 
    # free memory only needed for probing
    undef @models;
    undef @REGISTRY;
 
    push @{"$MODEL\::ISA"}, "AnyEvent::Base";
 
    # now nuke some methods that are overridden by the backend.
    # SUPER usage is not allowed in these.
    for (qw(time signal child idle)) {
       undef &{"AnyEvent::Base::$_"}
          if defined &{"$MODEL\::$_"};
    }
 
    _isa_set;
 
    # we're officially open!
 
    if ($ENV{PERL_ANYEVENT_STRICT}) {
       require AnyEvent::Strict;
    }
 
    if ($ENV{PERL_ANYEVENT_DEBUG_WRAP}) {
       require AnyEvent::Debug;
       AnyEvent::Debug::wrap ($ENV{PERL_ANYEVENT_DEBUG_WRAP});
    }
 
    if (length $ENV{PERL_ANYEVENT_DEBUG_SHELL}) {
       require AnyEvent::Socket;
       require AnyEvent::Debug;
 
       my $shell = $ENV{PERL_ANYEVENT_DEBUG_SHELL};
       $shell =~ s/\$\$/$$/g;
 
       my ($host, $service) = AnyEvent::Socket::parse_hostport ($shell);
       $AnyEvent::Debug::SHELL = AnyEvent::Debug::shell ($host, $service);
    }
 
    # now the anyevent environment is set up as the user told us to, so
    # call the actual user code - post detects
 
    (shift @post_detect)->() while @post_detect;
    undef @post_detect;
 
    *post_detect = sub(&) {
       shift->();
 
       undef
    };
 
    $MODEL
 }
 
 for my $name (@methods) {
    *$name = sub {
       detect;
       # we use goto because
       # a) it makes the thunk more transparent
       # b) it allows us to delete the thunk later
       goto &{ UNIVERSAL::can AnyEvent => "SUPER::$name" }
    };
 }
 
 # utility function to dup a filehandle. this is used by many backends
 # to support binding more than one watcher per filehandle (they usually
 # allow only one watcher per fd, so we dup it to get a different one).
 sub _dupfh($$;$$) {
    my ($poll, $fh, $r, $w) = @_;
 
    # cygwin requires the fh mode to be matching, unix doesn't
    my ($rw, $mode) = $poll eq "r" ? ($r, "<&") : ($w, ">&");
 
    open my $fh2, $mode, $fh
       or die "AnyEvent->io: cannot dup() filehandle in mode '$poll': $!,";
 
    # we assume CLOEXEC is already set by perl in all important cases
 
    ($fh2, $rw)
 }
 
 =head1 SIMPLIFIED AE API
 
 Starting with version 5.0, AnyEvent officially supports a second, much
 simpler, API that is designed to reduce the calling, typing and memory
 overhead by using function call syntax and a fixed number of parameters.
 
 See the L<AE> manpage for details.
 
 =cut
 
 package AE;
 
 our $VERSION = $AnyEvent::VERSION;
 
 sub _reset() {
    eval q{
       # fall back to the main API by default - backends and AnyEvent::Base
       # implementations can overwrite these.
 
       sub io($$$) {
          AnyEvent->io (fh => $_[0], poll => $_[1] ? "w" : "r", cb => $_[2])
       }
 
       sub timer($$$) {
          AnyEvent->timer (after => $_[0], interval => $_[1], cb => $_[2])
       }
 
       sub signal($$) {
          AnyEvent->signal (signal => $_[0], cb => $_[1])
       }
 
       sub child($$) {
          AnyEvent->child (pid => $_[0], cb => $_[1])
       }
 
       sub idle($) {
          AnyEvent->idle (cb => $_[0]);
       }
 
       sub cv(;&) {
          AnyEvent->condvar (@_ ? (cb => $_[0]) : ())
       }
 
       sub now() {
          AnyEvent->now
       }
 
       sub now_update() {
          AnyEvent->now_update
       }
 
       sub time() {
          AnyEvent->time
       }
 
       *postpone = \&AnyEvent::postpone;
       *log      = \&AnyEvent::log;
    };
    die if $@;
 }
 
 BEGIN { _reset }
 
 package AnyEvent::Base;
 
 # default implementations for many methods
 
 sub time {
    eval q{ # poor man's autoloading {}
       # probe for availability of Time::HiRes
       if (eval "use Time::HiRes (); Time::HiRes::time (); 1") {
          *time     = sub { Time::HiRes::time () };
          *AE::time = \&    Time::HiRes::time     ;
          *now      = \&time;
          AnyEvent::log 8 => "using Time::HiRes for sub-second timing accuracy.";
          # if (eval "use POSIX (); (POSIX::times())...
       } else {
          *time     = sub   { CORE::time };
          *AE::time = sub (){ CORE::time };
          *now      = \&time;
          AnyEvent::log 3 => "Using built-in time(), no sub-second resolution!";
       }
    };
    die if $@;
 
    &time
 }
 
 *now = \&time;
 sub now_update { }
 
 sub _poll {
    Carp::croak "$AnyEvent::MODEL does not support blocking waits. Caught";
 }
 
 # default implementation for ->condvar
 # in fact, the default should not be overwritten
 
 sub condvar {
    eval q{ # poor man's autoloading {}
       *condvar = sub {
          bless { @_ == 3 ? (_ae_cb => $_[2]) : () }, "AnyEvent::CondVar"
       };
 
       *AE::cv = sub (;&) {
          bless { @_ ? (_ae_cb => shift) : () }, "AnyEvent::CondVar"
       };
    };
    die if $@;
 
    &condvar
 }
 
 # default implementation for ->signal
 
 our $HAVE_ASYNC_INTERRUPT;
 
 sub _have_async_interrupt() {
    $HAVE_ASYNC_INTERRUPT = 1*(!$ENV{PERL_ANYEVENT_AVOID_ASYNC_INTERRUPT}
                               && eval "use Async::Interrupt 1.02 (); 1")
       unless defined $HAVE_ASYNC_INTERRUPT;
 
    $HAVE_ASYNC_INTERRUPT
 }
 
 our ($SIGPIPE_R, $SIGPIPE_W, %SIG_CB, %SIG_EV, $SIG_IO);
 our (%SIG_ASY, %SIG_ASY_W);
 our ($SIG_COUNT, $SIG_TW);
 
 # install a dummy wakeup watcher to reduce signal catching latency
 # used by Impls
 sub _sig_add() {
    unless ($SIG_COUNT++) {
       # try to align timer on a full-second boundary, if possible
       my $NOW = AE::now;
 
       $SIG_TW = AE::timer
          $MAX_SIGNAL_LATENCY - ($NOW - int $NOW),
          $MAX_SIGNAL_LATENCY,
          sub { } # just for the PERL_ASYNC_CHECK
       ;
    }
 }
 
 sub _sig_del {
    undef $SIG_TW
       unless --$SIG_COUNT;
 }
 
 our $_sig_name_init; $_sig_name_init = sub {
    eval q{ # poor man's autoloading {}
       undef $_sig_name_init;
 
       if (_have_async_interrupt) {
          *sig2num  = \&Async::Interrupt::sig2num;
          *sig2name = \&Async::Interrupt::sig2name;
       } else {
          require Config;
 
          my %signame2num;
          @signame2num{ split ' ', $Config::Config{sig_name} }
                         = split ' ', $Config::Config{sig_num};
 
          my @signum2name;
          @signum2name[values %signame2num] = keys %signame2num;
 
          *sig2num = sub($) {
             $_[0] > 0 ? shift : $signame2num{+shift}
          };
          *sig2name = sub ($) {
             $_[0] > 0 ? $signum2name[+shift] : shift
          };
       }
    };
    die if $@;
 };
 
 sub sig2num ($) { &$_sig_name_init; &sig2num  }
 sub sig2name($) { &$_sig_name_init; &sig2name }
 
 sub signal {
    eval q{ # poor man's autoloading {}
       # probe for availability of Async::Interrupt 
       if (_have_async_interrupt) {
          AnyEvent::log 8 => "Using Async::Interrupt for race-free signal handling.";
 
          $SIGPIPE_R = new Async::Interrupt::EventPipe;
          $SIG_IO = AE::io $SIGPIPE_R->fileno, 0, \&_signal_exec;
 
       } else {
          AnyEvent::log 8 => "Using emulated perl signal handling with latency timer.";
 
          if (AnyEvent::WIN32) {
             require AnyEvent::Util;
 
             ($SIGPIPE_R, $SIGPIPE_W) = AnyEvent::Util::portable_pipe ();
             AnyEvent::Util::fh_nonblocking ($SIGPIPE_R, 1) if $SIGPIPE_R;
             AnyEvent::Util::fh_nonblocking ($SIGPIPE_W, 1) if $SIGPIPE_W; # just in case
          } else {
             pipe $SIGPIPE_R, $SIGPIPE_W;
             fcntl $SIGPIPE_R, AnyEvent::F_SETFL, AnyEvent::O_NONBLOCK if $SIGPIPE_R;
             fcntl $SIGPIPE_W, AnyEvent::F_SETFL, AnyEvent::O_NONBLOCK if $SIGPIPE_W; # just in case
 
             # not strictly required, as $^F is normally 2, but let's make sure...
             fcntl $SIGPIPE_R, AnyEvent::F_SETFD, AnyEvent::FD_CLOEXEC;
             fcntl $SIGPIPE_W, AnyEvent::F_SETFD, AnyEvent::FD_CLOEXEC;
          }
 
          $SIGPIPE_R
             or Carp::croak "AnyEvent: unable to create a signal reporting pipe: $!\n";
 
          $SIG_IO = AE::io $SIGPIPE_R, 0, \&_signal_exec;
       }
 
       *signal = $HAVE_ASYNC_INTERRUPT
          ? sub {
               my (undef, %arg) = @_;
 
               # async::interrupt
               my $signal = sig2num $arg{signal};
               $SIG_CB{$signal}{$arg{cb}} = $arg{cb};
 
               $SIG_ASY{$signal} ||= new Async::Interrupt
                  cb             => sub { undef $SIG_EV{$signal} },
                  signal         => $signal,
                  pipe           => [$SIGPIPE_R->filenos],
                  pipe_autodrain => 0,
               ;
 
               bless [$signal, $arg{cb}], "AnyEvent::Base::signal"
            }
          : sub {
               my (undef, %arg) = @_;
 
               # pure perl
               my $signal = sig2name $arg{signal};
               $SIG_CB{$signal}{$arg{cb}} = $arg{cb};
 
               $SIG{$signal} ||= sub {
                  local $!;
                  syswrite $SIGPIPE_W, "\x00", 1 unless %SIG_EV;
                  undef $SIG_EV{$signal};
               };
 
               # can't do signal processing without introducing races in pure perl,
               # so limit the signal latency.
               _sig_add;
 
               bless [$signal, $arg{cb}], "AnyEvent::Base::signal"
            }
       ;
 
       *AnyEvent::Base::signal::DESTROY = sub {
          my ($signal, $cb) = @{$_[0]};
 
          _sig_del;
 
          delete $SIG_CB{$signal}{$cb};
 
          $HAVE_ASYNC_INTERRUPT
             ? delete $SIG_ASY{$signal}
             : # delete doesn't work with older perls - they then
               # print weird messages, or just unconditionally exit
               # instead of getting the default action.
               undef $SIG{$signal}
             unless keys %{ $SIG_CB{$signal} };
       };
 
       *_signal_exec = sub {
          $HAVE_ASYNC_INTERRUPT
             ? $SIGPIPE_R->drain
             : sysread $SIGPIPE_R, (my $dummy), 9;
 
          while (%SIG_EV) {
             for (keys %SIG_EV) {
                delete $SIG_EV{$_};
                &$_ for values %{ $SIG_CB{$_} || {} };
             }
          }
       };
    };
    die if $@;
 
    &signal
 }
 
 # default implementation for ->child
 
 our %PID_CB;
 our $CHLD_W;
 our $CHLD_DELAY_W;
 
 # used by many Impl's
 sub _emit_childstatus($$) {
    my (undef, $rpid, $rstatus) = @_;
 
    $_->($rpid, $rstatus)
       for values %{ $PID_CB{$rpid} || {} },
           values %{ $PID_CB{0}     || {} };
 }
 
 sub child {
    eval q{ # poor man's autoloading {}
       *_sigchld = sub {
          my $pid;
 
          AnyEvent->_emit_childstatus ($pid, $?)
             while ($pid = waitpid -1, WNOHANG) > 0;
       };
 
       *child = sub {
          my (undef, %arg) = @_;
 
          my $pid = $arg{pid};
          my $cb  = $arg{cb};
 
          $PID_CB{$pid}{$cb+0} = $cb;
 
          unless ($CHLD_W) {
             $CHLD_W = AE::signal CHLD => \&_sigchld;
             # child could be a zombie already, so make at least one round
             &_sigchld;
          }
 
          bless [$pid, $cb+0], "AnyEvent::Base::child"
       };
 
       *AnyEvent::Base::child::DESTROY = sub {
          my ($pid, $icb) = @{$_[0]};
 
          delete $PID_CB{$pid}{$icb};
          delete $PID_CB{$pid} unless keys %{ $PID_CB{$pid} };
 
          undef $CHLD_W unless keys %PID_CB;
       };
    };
    die if $@;
 
    &child
 }
 
 # idle emulation is done by simply using a timer, regardless
 # of whether the process is idle or not, and not letting
 # the callback use more than 50% of the time.
 sub idle {
    eval q{ # poor man's autoloading {}
       *idle = sub {
          my (undef, %arg) = @_;
 
          my ($cb, $w, $rcb) = $arg{cb};
 
          $rcb = sub {
             if ($cb) {
                $w = AE::time;
                &$cb;
                $w = AE::time - $w;
 
                # never use more then 50% of the time for the idle watcher,
                # within some limits
                $w = 0.0001 if $w < 0.0001;
                $w = 5      if $w > 5;
 
                $w = AE::timer $w, 0, $rcb;
             } else {
                # clean up...
                undef $w;
                undef $rcb;
             }
          };
 
          $w = AE::timer 0.05, 0, $rcb;
 
          bless \\$cb, "AnyEvent::Base::idle"
       };
 
       *AnyEvent::Base::idle::DESTROY = sub {
          undef $${$_[0]};
       };
    };
    die if $@;
 
    &idle
 }
 
 package AnyEvent::CondVar;
 
 our @ISA = AnyEvent::CondVar::Base::;
 
 # only to be used for subclassing
 sub new {
    my $class = shift;
    bless AnyEvent->condvar (@_), $class
 }
 
 package AnyEvent::CondVar::Base;
 
 #use overload
 #   '&{}'    => sub { my $self = shift; sub { $self->send (@_) } },
 #   fallback => 1;
 
 # save 300+ kilobytes by dirtily hardcoding overloading
 ${"AnyEvent::CondVar::Base::OVERLOAD"}{dummy}++; # Register with magic by touching.
 *{'AnyEvent::CondVar::Base::()'}   = sub { }; # "Make it findable via fetchmethod."
 *{'AnyEvent::CondVar::Base::(&{}'} = sub { my $self = shift; sub { $self->send (@_) } }; # &{}
 ${'AnyEvent::CondVar::Base::()'}   = 1; # fallback
 
 our $WAITING;
 
 sub _send {
    # nop
 }
 
 sub _wait {
    AnyEvent->_poll until $_[0]{_ae_sent};
 }
 
 sub send {
    my $cv = shift;
    $cv->{_ae_sent} = [@_];
    (delete $cv->{_ae_cb})->($cv) if $cv->{_ae_cb};
    $cv->_send;
 }
 
 sub croak {
    $_[0]{_ae_croak} = $_[1];
    $_[0]->send;
 }
 
 sub ready {
    $_[0]{_ae_sent}
 }
 
 sub recv {
    unless ($_[0]{_ae_sent}) {
       $WAITING
          and Carp::croak "AnyEvent::CondVar: recursive blocking wait attempted";
 
       local $WAITING = 1;
       $_[0]->_wait;
    }
 
    $_[0]{_ae_croak}
       and Carp::croak $_[0]{_ae_croak};
 
    wantarray
       ? @{ $_[0]{_ae_sent} }
       : $_[0]{_ae_sent}[0]
 }
 
 sub cb {
    my $cv = shift;
 
    @_
       and $cv->{_ae_cb} = shift
       and $cv->{_ae_sent}
       and (delete $cv->{_ae_cb})->($cv);
 
    $cv->{_ae_cb}
 }
 
 sub begin {
    ++$_[0]{_ae_counter};
    $_[0]{_ae_end_cb} = $_[1] if @_ > 1;
 }
 
 sub end {
    return if --$_[0]{_ae_counter};
    &{ $_[0]{_ae_end_cb} || sub { $_[0]->send } };
 }
 
 # undocumented/compatibility with pre-3.4
 *broadcast = \&send;
 *wait      = \&recv;
 
 =head1 ERROR AND EXCEPTION HANDLING
 
 In general, AnyEvent does not do any error handling - it relies on the
 caller to do that if required. The L<AnyEvent::Strict> module (see also
 the C<PERL_ANYEVENT_STRICT> environment variable, below) provides strict
 checking of all AnyEvent methods, however, which is highly useful during
 development.
 
 As for exception handling (i.e. runtime errors and exceptions thrown while
 executing a callback), this is not only highly event-loop specific, but
 also not in any way wrapped by this module, as this is the job of the main
 program.
 
 The pure perl event loop simply re-throws the exception (usually
 within C<< condvar->recv >>), the L<Event> and L<EV> modules call C<<
 $Event/EV::DIED->() >>, L<Glib> uses C<< install_exception_handler >> and
 so on.
 
 =head1 ENVIRONMENT VARIABLES
 
 AnyEvent supports a number of environment variables that tune the
 runtime behaviour. They are usually evaluated when AnyEvent is
 loaded, initialised, or a submodule that uses them is loaded. Many of
 them also cause AnyEvent to load additional modules - for example,
 C<PERL_ANYEVENT_DEBUG_WRAP> causes the L<AnyEvent::Debug> module to be
 loaded.
 
 All the environment variables documented here start with
 C<PERL_ANYEVENT_>, which is what AnyEvent considers its own
 namespace. Other modules are encouraged (but by no means required) to use
 C<PERL_ANYEVENT_SUBMODULE> if they have registered the AnyEvent::Submodule
 namespace on CPAN, for any submodule. For example, L<AnyEvent::HTTP> could
 be expected to use C<PERL_ANYEVENT_HTTP_PROXY> (it should not access env
 variables starting with C<AE_>, see below).
 
 All variables can also be set via the C<AE_> prefix, that is, instead
 of setting C<PERL_ANYEVENT_VERBOSE> you can also set C<AE_VERBOSE>. In
 case there is a clash btween anyevent and another program that uses
 C<AE_something> you can set the corresponding C<PERL_ANYEVENT_something>
 variable to the empty string, as those variables take precedence.
 
 When AnyEvent is first loaded, it copies all C<AE_xxx> env variables
 to their C<PERL_ANYEVENT_xxx> counterpart unless that variable already
 exists. If taint mode is on, then AnyEvent will remove I<all> environment
 variables starting with C<PERL_ANYEVENT_> from C<%ENV> (or replace them
 with C<undef> or the empty string, if the corresaponding C<AE_> variable
 is set).
 
 The exact algorithm is currently:
 
    1. if taint mode enabled, delete all PERL_ANYEVENT_xyz variables from %ENV
    2. copy over AE_xyz to PERL_ANYEVENT_xyz unless the latter alraedy exists
    3. if taint mode enabled, set all PERL_ANYEVENT_xyz variables to undef.
 
 This ensures that child processes will not see the C<AE_> variables.
 
 The following environment variables are currently known to AnyEvent:
 
 =over 4
 
 =item C<PERL_ANYEVENT_VERBOSE>
 
 By default, AnyEvent will log messages with loglevel C<4> (C<error>) or
 higher (see L<AnyEvent::Log>). You can set this environment variable to a
 numerical loglevel to make AnyEvent more (or less) talkative.
 
 If you want to do more than just set the global logging level
 you should have a look at C<PERL_ANYEVENT_LOG>, which allows much more
 complex specifications.
 
 When set to C<0> (C<off>), then no messages whatsoever will be logged with
 everything else at defaults.
 
 When set to C<5> or higher (C<warn>), AnyEvent warns about unexpected
 conditions, such as not being able to load the event model specified by
 C<PERL_ANYEVENT_MODEL>, or a guard callback throwing an exception - this
 is the minimum recommended level for use during development.
 
 When set to C<7> or higher (info), AnyEvent reports which event model it
 chooses.
 
 When set to C<8> or higher (debug), then AnyEvent will report extra
 information on which optional modules it loads and how it implements
 certain features.
 
 =item C<PERL_ANYEVENT_LOG>
 
 Accepts rather complex logging specifications. For example, you could log
 all C<debug> messages of some module to stderr, warnings and above to
 stderr, and errors and above to syslog, with:
 
    PERL_ANYEVENT_LOG=Some::Module=debug,+log:filter=warn,+%syslog:%syslog=error,syslog
 
 For the rather extensive details, see L<AnyEvent::Log>.
 
 This variable is evaluated when AnyEvent (or L<AnyEvent::Log>) is loaded,
 so will take effect even before AnyEvent has initialised itself.
 
 Note that specifying this environment variable causes the L<AnyEvent::Log>
 module to be loaded, while C<PERL_ANYEVENT_VERBOSE> does not, so only
 using the latter saves a few hundred kB of memory unless a module
 explicitly needs the extra features of AnyEvent::Log.
 
 =item C<PERL_ANYEVENT_STRICT>
 
 AnyEvent does not do much argument checking by default, as thorough
 argument checking is very costly. Setting this variable to a true value
 will cause AnyEvent to load C<AnyEvent::Strict> and then to thoroughly
 check the arguments passed to most method calls. If it finds any problems,
 it will croak.
 
 In other words, enables "strict" mode.
 
 Unlike C<use strict> (or its modern cousin, C<< use L<common::sense>
 >>, it is definitely recommended to keep it off in production. Keeping
 C<PERL_ANYEVENT_STRICT=1> in your environment while developing programs
 can be very useful, however.
 
 =item C<PERL_ANYEVENT_DEBUG_SHELL>
 
 If this env variable is nonempty, then its contents will be interpreted by
 C<AnyEvent::Socket::parse_hostport> and C<AnyEvent::Debug::shell> (after
 replacing every occurance of C<$$> by the process pid). The shell object
 is saved in C<$AnyEvent::Debug::SHELL>.
 
 This happens when the first watcher is created.
 
 For example, to bind a debug shell on a unix domain socket in
 F<< /tmp/debug<pid>.sock >>, you could use this:
 
    PERL_ANYEVENT_DEBUG_SHELL=/tmp/debug\$\$.sock perlprog
    # connect with e.g.: socat readline /tmp/debug123.sock
 
 Or to bind to tcp port 4545 on localhost:
 
    PERL_ANYEVENT_DEBUG_SHELL=127.0.0.1:4545 perlprog
    # connect with e.g.: telnet localhost 4545
 
 Note that creating sockets in F</tmp> or on localhost is very unsafe on
 multiuser systems.
 
 =item C<PERL_ANYEVENT_DEBUG_WRAP>
 
 Can be set to C<0>, C<1> or C<2> and enables wrapping of all watchers for
 debugging purposes. See C<AnyEvent::Debug::wrap> for details.
 
 =item C<PERL_ANYEVENT_MODEL>
 
 This can be used to specify the event model to be used by AnyEvent, before
 auto detection and -probing kicks in.
 
 It normally is a string consisting entirely of ASCII letters (e.g. C<EV>
 or C<IOAsync>). The string C<AnyEvent::Impl::> gets prepended and the
 resulting module name is loaded and - if the load was successful - used as
 event model backend. If it fails to load then AnyEvent will proceed with
 auto detection and -probing.
 
 If the string ends with C<::> instead (e.g. C<AnyEvent::Impl::EV::>) then
 nothing gets prepended and the module name is used as-is (hint: C<::> at
 the end of a string designates a module name and quotes it appropriately).
 
 For example, to force the pure perl model (L<AnyEvent::Loop::Perl>) you
 could start your program like this:
 
    PERL_ANYEVENT_MODEL=Perl perl ...
 
 =item C<PERL_ANYEVENT_IO_MODEL>
 
 The current file I/O model - see L<AnyEvent::IO> for more info.
 
 At the moment, only C<Perl> (small, pure-perl, synchronous) and
 C<IOAIO> (truly asynchronous) are supported. The default is C<IOAIO> if
 L<AnyEvent::AIO> can be loaded, otherwise it is C<Perl>.
 
 =item C<PERL_ANYEVENT_PROTOCOLS>
 
 Used by both L<AnyEvent::DNS> and L<AnyEvent::Socket> to determine preferences
 for IPv4 or IPv6. The default is unspecified (and might change, or be the result
 of auto probing).
 
 Must be set to a comma-separated list of protocols or address families,
 current supported: C<ipv4> and C<ipv6>. Only protocols mentioned will be
 used, and preference will be given to protocols mentioned earlier in the
 list.
 
 This variable can effectively be used for denial-of-service attacks
 against local programs (e.g. when setuid), although the impact is likely
 small, as the program has to handle connection and other failures anyways.
 
 Examples: C<PERL_ANYEVENT_PROTOCOLS=ipv4,ipv6> - prefer IPv4 over IPv6,
 but support both and try to use both.  C<PERL_ANYEVENT_PROTOCOLS=ipv4>
 - only support IPv4, never try to resolve or contact IPv6
 addresses. C<PERL_ANYEVENT_PROTOCOLS=ipv6,ipv4> support either IPv4 or
 IPv6, but prefer IPv6 over IPv4.
 
 =item C<PERL_ANYEVENT_HOSTS>
 
 This variable, if specified, overrides the F</etc/hosts> file used by
 L<AnyEvent::Socket>C<::resolve_sockaddr>, i.e. hosts aliases will be read
 from that file instead.
 
 =item C<PERL_ANYEVENT_EDNS0>
 
 Used by L<AnyEvent::DNS> to decide whether to use the EDNS0 extension for
 DNS. This extension is generally useful to reduce DNS traffic, especially
 when DNSSEC is involved, but some (broken) firewalls drop such DNS
 packets, which is why it is off by default.
 
 Setting this variable to C<1> will cause L<AnyEvent::DNS> to announce
 EDNS0 in its DNS requests.
 
 =item C<PERL_ANYEVENT_MAX_FORKS>
 
 The maximum number of child processes that C<AnyEvent::Util::fork_call>
 will create in parallel.
 
 =item C<PERL_ANYEVENT_MAX_OUTSTANDING_DNS>
 
 The default value for the C<max_outstanding> parameter for the default DNS
 resolver - this is the maximum number of parallel DNS requests that are
 sent to the DNS server.
 
 =item C<PERL_ANYEVENT_MAX_SIGNAL_LATENCY>
 
 Perl has inherently racy signal handling (you can basically choose between
 losing signals and memory corruption) - pure perl event loops (including
 C<AnyEvent::Loop>, when C<Async::Interrupt> isn't available) therefore
 have to poll regularly to avoid losing signals.
 
 Some event loops are racy, but don't poll regularly, and some event loops
 are written in C but are still racy. For those event loops, AnyEvent
 installs a timer that regularly wakes up the event loop.
 
 By default, the interval for this timer is C<10> seconds, but you can
 override this delay with this environment variable (or by setting
 the C<$AnyEvent::MAX_SIGNAL_LATENCY> variable before creating signal
 watchers).
 
 Lower values increase CPU (and energy) usage, higher values can introduce
 long delays when reaping children or waiting for signals.
 
 The L<AnyEvent::Async> module, if available, will be used to avoid this
 polling (with most event loops).
 
 =item C<PERL_ANYEVENT_RESOLV_CONF>
 
 The absolute path to a F<resolv.conf>-style file to use instead of
 F</etc/resolv.conf> (or the OS-specific configuration) in the default
 resolver, or the empty string to select the default configuration.
 
 =item C<PERL_ANYEVENT_CA_FILE>, C<PERL_ANYEVENT_CA_PATH>.
 
 When neither C<ca_file> nor C<ca_path> was specified during
 L<AnyEvent::TLS> context creation, and either of these environment
 variables are nonempty, they will be used to specify CA certificate
 locations instead of a system-dependent default.
 
 =item C<PERL_ANYEVENT_AVOID_GUARD> and C<PERL_ANYEVENT_AVOID_ASYNC_INTERRUPT>
 
 When these are set to C<1>, then the respective modules are not
 loaded. Mostly good for testing AnyEvent itself.
 
 =back
 
 =head1 SUPPLYING YOUR OWN EVENT MODEL INTERFACE
 
 This is an advanced topic that you do not normally need to use AnyEvent in
 a module. This section is only of use to event loop authors who want to
 provide AnyEvent compatibility.
 
 If you need to support another event library which isn't directly
 supported by AnyEvent, you can supply your own interface to it by
 pushing, before the first watcher gets created, the package name of
 the event module and the package name of the interface to use onto
 C<@AnyEvent::REGISTRY>. You can do that before and even without loading
 AnyEvent, so it is reasonably cheap.
 
 Example:
 
    push @AnyEvent::REGISTRY, [urxvt => urxvt::anyevent::];
 
 This tells AnyEvent to (literally) use the C<urxvt::anyevent::>
 package/class when it finds the C<urxvt> package/module is already loaded.
 
 When AnyEvent is loaded and asked to find a suitable event model, it
 will first check for the presence of urxvt by trying to C<use> the
 C<urxvt::anyevent> module.
 
 The class should provide implementations for all watcher types. See
 L<AnyEvent::Impl::EV> (source code), L<AnyEvent::Impl::Glib> (Source code)
 and so on for actual examples. Use C<perldoc -m AnyEvent::Impl::Glib> to
 see the sources.
 
 If you don't provide C<signal> and C<child> watchers than AnyEvent will
 provide suitable (hopefully) replacements.
 
 The above example isn't fictitious, the I<rxvt-unicode> (a.k.a. urxvt)
 terminal emulator uses the above line as-is. An interface isn't included
 in AnyEvent because it doesn't make sense outside the embedded interpreter
 inside I<rxvt-unicode>, and it is updated and maintained as part of the
 I<rxvt-unicode> distribution.
 
 I<rxvt-unicode> also cheats a bit by not providing blocking access to
 condition variables: code blocking while waiting for a condition will
 C<die>. This still works with most modules/usages, and blocking calls must
 not be done in an interactive application, so it makes sense.
 
 =head1 EXAMPLE PROGRAM
 
 The following program uses an I/O watcher to read data from STDIN, a timer
 to display a message once per second, and a condition variable to quit the
 program when the user enters quit:
 
    use AnyEvent;
 
    my $cv = AnyEvent->condvar;
 
    my $io_watcher = AnyEvent->io (
       fh   => \*STDIN,
       poll => 'r',
       cb   => sub {
          warn "io event <$_[0]>\n";   # will always output <r>
          chomp (my $input = <STDIN>); # read a line
          warn "read: $input\n";       # output what has been read
          $cv->send if $input =~ /^q/i; # quit program if /^q/i
       },
    );
 
    my $time_watcher = AnyEvent->timer (after => 1, interval => 1, cb => sub {
       warn "timeout\n"; # print 'timeout' at most every second
    });
 
    $cv->recv; # wait until user enters /^q/i
 
 =head1 REAL-WORLD EXAMPLE
 
 Consider the L<Net::FCP> module. It features (among others) the following
 API calls, which are to freenet what HTTP GET requests are to http:
 
    my $data = $fcp->client_get ($url); # blocks
 
    my $transaction = $fcp->txn_client_get ($url); # does not block
    $transaction->cb ( sub { ... } ); # set optional result callback
    my $data = $transaction->result; # possibly blocks
 
 The C<client_get> method works like C<LWP::Simple::get>: it requests the
 given URL and waits till the data has arrived. It is defined to be:
 
    sub client_get { $_[0]->txn_client_get ($_[1])->result }
 
 And in fact is automatically generated. This is the blocking API of
 L<Net::FCP>, and it works as simple as in any other, similar, module.
 
 More complicated is C<txn_client_get>: It only creates a transaction
 (completion, result, ...) object and initiates the transaction.
 
    my $txn = bless { }, Net::FCP::Txn::;
 
 It also creates a condition variable that is used to signal the completion
 of the request:
 
    $txn->{finished} = AnyAvent->condvar;
 
 It then creates a socket in non-blocking mode.
 
    socket $txn->{fh}, ...;
    fcntl $txn->{fh}, F_SETFL, O_NONBLOCK;
    connect $txn->{fh}, ...
       and !$!{EWOULDBLOCK}
       and !$!{EINPROGRESS}
       and Carp::croak "unable to connect: $!\n";
 
 Then it creates a write-watcher which gets called whenever an error occurs
 or the connection succeeds:
 
    $txn->{w} = AnyEvent->io (fh => $txn->{fh}, poll => 'w', cb => sub { $txn->fh_ready_w });
 
 And returns this transaction object. The C<fh_ready_w> callback gets
 called as soon as the event loop detects that the socket is ready for
 writing.
 
 The C<fh_ready_w> method makes the socket blocking again, writes the
 request data and replaces the watcher by a read watcher (waiting for reply
 data). The actual code is more complicated, but that doesn't matter for
 this example:
 
    fcntl $txn->{fh}, F_SETFL, 0;
    syswrite $txn->{fh}, $txn->{request}
       or die "connection or write error";
    $txn->{w} = AnyEvent->io (fh => $txn->{fh}, poll => 'r', cb => sub { $txn->fh_ready_r });
 
 Again, C<fh_ready_r> waits till all data has arrived, and then stores the
 result and signals any possible waiters that the request has finished:
 
    sysread $txn->{fh}, $txn->{buf}, length $txn->{$buf};
 
    if (end-of-file or data complete) {
      $txn->{result} = $txn->{buf};
      $txn->{finished}->send;
      $txb->{cb}->($txn) of $txn->{cb}; # also call callback
    }
 
 The C<result> method, finally, just waits for the finished signal (if the
 request was already finished, it doesn't wait, of course, and returns the
 data:
 
    $txn->{finished}->recv;
    return $txn->{result};
 
 The actual code goes further and collects all errors (C<die>s, exceptions)
 that occurred during request processing. The C<result> method detects
 whether an exception as thrown (it is stored inside the $txn object)
 and just throws the exception, which means connection errors and other
 problems get reported to the code that tries to use the result, not in a
 random callback.
 
 All of this enables the following usage styles:
 
 1. Blocking:
 
    my $data = $fcp->client_get ($url);
 
 2. Blocking, but running in parallel:
 
    my @datas = map $_->result,
                   map $fcp->txn_client_get ($_),
                      @urls;
 
 Both blocking examples work without the module user having to know
 anything about events.
 
 3a. Event-based in a main program, using any supported event module:
 
    use EV;
 
    $fcp->txn_client_get ($url)->cb (sub {
       my $txn = shift;
       my $data = $txn->result;
       ...
    });
 
    EV::loop;
 
 3b. The module user could use AnyEvent, too:
 
    use AnyEvent;
 
    my $quit = AnyEvent->condvar;
 
    $fcp->txn_client_get ($url)->cb (sub {
       ...
       $quit->send;
    });
 
    $quit->recv;
 
 
 =head1 BENCHMARKS
 
 To give you an idea of the performance and overheads that AnyEvent adds
 over the event loops themselves and to give you an impression of the speed
 of various event loops I prepared some benchmarks.
 
 =head2 BENCHMARKING ANYEVENT OVERHEAD
 
 Here is a benchmark of various supported event models used natively and
 through AnyEvent. The benchmark creates a lot of timers (with a zero
 timeout) and I/O watchers (watching STDOUT, a pty, to become writable,
 which it is), lets them fire exactly once and destroys them again.
 
 Source code for this benchmark is found as F<eg/bench> in the AnyEvent
 distribution. It uses the L<AE> interface, which makes a real difference
 for the EV and Perl backends only.
 
 =head3 Explanation of the columns
 
 I<watcher> is the number of event watchers created/destroyed. Since
 different event models feature vastly different performances, each event
 loop was given a number of watchers so that overall runtime is acceptable
 and similar between tested event loop (and keep them from crashing): Glib
 would probably take thousands of years if asked to process the same number
 of watchers as EV in this benchmark.
 
 I<bytes> is the number of bytes (as measured by the resident set size,
 RSS) consumed by each watcher. This method of measuring captures both C
 and Perl-based overheads.
 
 I<create> is the time, in microseconds (millionths of seconds), that it
 takes to create a single watcher. The callback is a closure shared between
 all watchers, to avoid adding memory overhead. That means closure creation
 and memory usage is not included in the figures.
 
 I<invoke> is the time, in microseconds, used to invoke a simple
 callback. The callback simply counts down a Perl variable and after it was
 invoked "watcher" times, it would C<< ->send >> a condvar once to
 signal the end of this phase.
 
 I<destroy> is the time, in microseconds, that it takes to destroy a single
 watcher.
 
 =head3 Results
 
           name watchers bytes create invoke destroy comment
          EV/EV   100000   223   0.47   0.43    0.27 EV native interface
         EV/Any   100000   223   0.48   0.42    0.26 EV + AnyEvent watchers
   Coro::EV/Any   100000   223   0.47   0.42    0.26 coroutines + Coro::Signal
       Perl/Any   100000   431   2.70   0.74    0.92 pure perl implementation
    Event/Event    16000   516  31.16  31.84    0.82 Event native interface
      Event/Any    16000  1203  42.61  34.79    1.80 Event + AnyEvent watchers
    IOAsync/Any    16000  1911  41.92  27.45   16.81 via IO::Async::Loop::IO_Poll
    IOAsync/Any    16000  1726  40.69  26.37   15.25 via IO::Async::Loop::Epoll
       Glib/Any    16000  1118  89.00  12.57   51.17 quadratic behaviour
         Tk/Any     2000  1346  20.96  10.75    8.00 SEGV with >> 2000 watchers
        POE/Any     2000  6951 108.97 795.32   14.24 via POE::Loop::Event
        POE/Any     2000  6648  94.79 774.40  575.51 via POE::Loop::Select
 
 =head3 Discussion
 
 The benchmark does I<not> measure scalability of the event loop very
 well. For example, a select-based event loop (such as the pure perl one)
 can never compete with an event loop that uses epoll when the number of
 file descriptors grows high. In this benchmark, all events become ready at
 the same time, so select/poll-based implementations get an unnatural speed
 boost.
 
 Also, note that the number of watchers usually has a nonlinear effect on
 overall speed, that is, creating twice as many watchers doesn't take twice
 the time - usually it takes longer. This puts event loops tested with a
 higher number of watchers at a disadvantage.
 
 To put the range of results into perspective, consider that on the
 benchmark machine, handling an event takes roughly 1600 CPU cycles with
 EV, 3100 CPU cycles with AnyEvent's pure perl loop and almost 3000000 CPU
 cycles with POE.
 
 C<EV> is the sole leader regarding speed and memory use, which are both
 maximal/minimal, respectively. When using the L<AE> API there is zero
 overhead (when going through the AnyEvent API create is about 5-6 times
 slower, with other times being equal, so still uses far less memory than
 any other event loop and is still faster than Event natively).
 
 The pure perl implementation is hit in a few sweet spots (both the
 constant timeout and the use of a single fd hit optimisations in the perl
 interpreter and the backend itself). Nevertheless this shows that it
 adds very little overhead in itself. Like any select-based backend its
 performance becomes really bad with lots of file descriptors (and few of
 them active), of course, but this was not subject of this benchmark.
 
 The C<Event> module has a relatively high setup and callback invocation
 cost, but overall scores in on the third place.
 
 C<IO::Async> performs admirably well, about on par with C<Event>, even
 when using its pure perl backend.
 
 C<Glib>'s memory usage is quite a bit higher, but it features a
 faster callback invocation and overall ends up in the same class as
 C<Event>. However, Glib scales extremely badly, doubling the number of
 watchers increases the processing time by more than a factor of four,
 making it completely unusable when using larger numbers of watchers
 (note that only a single file descriptor was used in the benchmark, so
 inefficiencies of C<poll> do not account for this).
 
 The C<Tk> adaptor works relatively well. The fact that it crashes with
 more than 2000 watchers is a big setback, however, as correctness takes
 precedence over speed. Nevertheless, its performance is surprising, as the
 file descriptor is dup()ed for each watcher. This shows that the dup()
 employed by some adaptors is not a big performance issue (it does incur a
 hidden memory cost inside the kernel which is not reflected in the figures
 above).
 
 C<POE>, regardless of underlying event loop (whether using its pure perl
 select-based backend or the Event module, the POE-EV backend couldn't
 be tested because it wasn't working) shows abysmal performance and
 memory usage with AnyEvent: Watchers use almost 30 times as much memory
 as EV watchers, and 10 times as much memory as Event (the high memory
 requirements are caused by requiring a session for each watcher). Watcher
 invocation speed is almost 900 times slower than with AnyEvent's pure perl
 implementation.
 
 The design of the POE adaptor class in AnyEvent can not really account
 for the performance issues, though, as session creation overhead is
 small compared to execution of the state machine, which is coded pretty
 optimally within L<AnyEvent::Impl::POE> (and while everybody agrees that
 using multiple sessions is not a good approach, especially regarding
 memory usage, even the author of POE could not come up with a faster
 design).
 
 =head3 Summary
 
 =over 4
 
 =item * Using EV through AnyEvent is faster than any other event loop
 (even when used without AnyEvent), but most event loops have acceptable
 performance with or without AnyEvent.
 
 =item * The overhead AnyEvent adds is usually much smaller than the overhead of
 the actual event loop, only with extremely fast event loops such as EV
 does AnyEvent add significant overhead.
 
 =item * You should avoid POE like the plague if you want performance or
 reasonable memory usage.
 
 =back
 
 =head2 BENCHMARKING THE LARGE SERVER CASE
 
 This benchmark actually benchmarks the event loop itself. It works by
 creating a number of "servers": each server consists of a socket pair, a
 timeout watcher that gets reset on activity (but never fires), and an I/O
 watcher waiting for input on one side of the socket. Each time the socket
 watcher reads a byte it will write that byte to a random other "server".
 
 The effect is that there will be a lot of I/O watchers, only part of which
 are active at any one point (so there is a constant number of active
 fds for each loop iteration, but which fds these are is random). The
 timeout is reset each time something is read because that reflects how
 most timeouts work (and puts extra pressure on the event loops).
 
 In this benchmark, we use 10000 socket pairs (20000 sockets), of which 100
 (1%) are active. This mirrors the activity of large servers with many
 connections, most of which are idle at any one point in time.
 
 Source code for this benchmark is found as F<eg/bench2> in the AnyEvent
 distribution. It uses the L<AE> interface, which makes a real difference
 for the EV and Perl backends only.
 
 =head3 Explanation of the columns
 
 I<sockets> is the number of sockets, and twice the number of "servers" (as
 each server has a read and write socket end).
 
 I<create> is the time it takes to create a socket pair (which is
 nontrivial) and two watchers: an I/O watcher and a timeout watcher.
 
 I<request>, the most important value, is the time it takes to handle a
 single "request", that is, reading the token from the pipe and forwarding
 it to another server. This includes deleting the old timeout and creating
 a new one that moves the timeout into the future.
 
 =head3 Results
 
      name sockets create  request 
        EV   20000  62.66     7.99 
      Perl   20000  68.32    32.64 
   IOAsync   20000 174.06   101.15 epoll
   IOAsync   20000 174.67   610.84 poll
     Event   20000 202.69   242.91 
      Glib   20000 557.01  1689.52 
       POE   20000 341.54 12086.32 uses POE::Loop::Event
 
 =head3 Discussion
 
 This benchmark I<does> measure scalability and overall performance of the
 particular event loop.
 
 EV is again fastest. Since it is using epoll on my system, the setup time
 is relatively high, though.
 
 Perl surprisingly comes second. It is much faster than the C-based event
 loops Event and Glib.
 
 IO::Async performs very well when using its epoll backend, and still quite
 good compared to Glib when using its pure perl backend.
 
 Event suffers from high setup time as well (look at its code and you will
 understand why). Callback invocation also has a high overhead compared to
 the C<< $_->() for .. >>-style loop that the Perl event loop uses. Event
 uses select or poll in basically all documented configurations.
 
 Glib is hit hard by its quadratic behaviour w.r.t. many watchers. It
 clearly fails to perform with many filehandles or in busy servers.
 
 POE is still completely out of the picture, taking over 1000 times as long
 as EV, and over 100 times as long as the Perl implementation, even though
 it uses a C-based event loop in this case.
 
 =head3 Summary
 
 =over 4
 
 =item * The pure perl implementation performs extremely well.
 
 =item * Avoid Glib or POE in large projects where performance matters.
 
 =back
 
 =head2 BENCHMARKING SMALL SERVERS
 
 While event loops should scale (and select-based ones do not...) even to
 large servers, most programs we (or I :) actually write have only a few
 I/O watchers.
 
 In this benchmark, I use the same benchmark program as in the large server
 case, but it uses only eight "servers", of which three are active at any
 one time. This should reflect performance for a small server relatively
 well.
 
 The columns are identical to the previous table.
 
 =head3 Results
 
     name sockets create request 
       EV      16  20.00    6.54 
     Perl      16  25.75   12.62 
    Event      16  81.27   35.86 
     Glib      16  32.63   15.48 
      POE      16 261.87  276.28 uses POE::Loop::Event
 
 =head3 Discussion
 
 The benchmark tries to test the performance of a typical small
 server. While knowing how various event loops perform is interesting, keep
 in mind that their overhead in this case is usually not as important, due
 to the small absolute number of watchers (that is, you need efficiency and
 speed most when you have lots of watchers, not when you only have a few of
 them).
 
 EV is again fastest.
 
 Perl again comes second. It is noticeably faster than the C-based event
 loops Event and Glib, although the difference is too small to really
 matter.
 
 POE also performs much better in this case, but is is still far behind the
 others.
 
 =head3 Summary
 
 =over 4
 
 =item * C-based event loops perform very well with small number of
 watchers, as the management overhead dominates.
 
 =back
 
 =head2 THE IO::Lambda BENCHMARK
 
 Recently I was told about the benchmark in the IO::Lambda manpage, which
 could be misinterpreted to make AnyEvent look bad. In fact, the benchmark
 simply compares IO::Lambda with POE, and IO::Lambda looks better (which
 shouldn't come as a surprise to anybody). As such, the benchmark is
 fine, and mostly shows that the AnyEvent backend from IO::Lambda isn't
 very optimal. But how would AnyEvent compare when used without the extra
 baggage? To explore this, I wrote the equivalent benchmark for AnyEvent.
 
 The benchmark itself creates an echo-server, and then, for 500 times,
 connects to the echo server, sends a line, waits for the reply, and then
 creates the next connection. This is a rather bad benchmark, as it doesn't
 test the efficiency of the framework or much non-blocking I/O, but it is a
 benchmark nevertheless.
 
    name                    runtime
    Lambda/select           0.330 sec
       + optimized          0.122 sec
    Lambda/AnyEvent         0.327 sec
       + optimized          0.138 sec
    Raw sockets/select      0.077 sec
    POE/select, components  0.662 sec
    POE/select, raw sockets 0.226 sec
    POE/select, optimized   0.404 sec
 
    AnyEvent/select/nb      0.085 sec
    AnyEvent/EV/nb          0.068 sec
       +state machine       0.134 sec
 
 The benchmark is also a bit unfair (my fault): the IO::Lambda/POE
 benchmarks actually make blocking connects and use 100% blocking I/O,
 defeating the purpose of an event-based solution. All of the newly
 written AnyEvent benchmarks use 100% non-blocking connects (using
 AnyEvent::Socket::tcp_connect and the asynchronous pure perl DNS
 resolver), so AnyEvent is at a disadvantage here, as non-blocking connects
 generally require a lot more bookkeeping and event handling than blocking
 connects (which involve a single syscall only).
 
 The last AnyEvent benchmark additionally uses L<AnyEvent::Handle>, which
 offers similar expressive power as POE and IO::Lambda, using conventional
 Perl syntax. This means that both the echo server and the client are 100%
 non-blocking, further placing it at a disadvantage.
 
 As you can see, the AnyEvent + EV combination even beats the
 hand-optimised "raw sockets benchmark", while AnyEvent + its pure perl
 backend easily beats IO::Lambda and POE.
 
 And even the 100% non-blocking version written using the high-level (and
 slow :) L<AnyEvent::Handle> abstraction beats both POE and IO::Lambda
 higher level ("unoptimised") abstractions by a large margin, even though
 it does all of DNS, tcp-connect and socket I/O in a non-blocking way.
 
 The two AnyEvent benchmarks programs can be found as F<eg/ae0.pl> and
 F<eg/ae2.pl> in the AnyEvent distribution, the remaining benchmarks are
 part of the IO::Lambda distribution and were used without any changes.
 
 
 =head1 SIGNALS
 
 AnyEvent currently installs handlers for these signals:
 
 =over 4
 
 =item SIGCHLD
 
 A handler for C<SIGCHLD> is installed by AnyEvent's child watcher
 emulation for event loops that do not support them natively. Also, some
 event loops install a similar handler.
 
 Additionally, when AnyEvent is loaded and SIGCHLD is set to IGNORE, then
 AnyEvent will reset it to default, to avoid losing child exit statuses.
 
 =item SIGPIPE
 
 A no-op handler is installed for C<SIGPIPE> when C<$SIG{PIPE}> is C<undef>
 when AnyEvent gets loaded.
 
 The rationale for this is that AnyEvent users usually do not really depend
 on SIGPIPE delivery (which is purely an optimisation for shell use, or
 badly-written programs), but C<SIGPIPE> can cause spurious and rare
 program exits as a lot of people do not expect C<SIGPIPE> when writing to
 some random socket.
 
 The rationale for installing a no-op handler as opposed to ignoring it is
 that this way, the handler will be restored to defaults on exec.
 
 Feel free to install your own handler, or reset it to defaults.
 
 =back
 
 =cut
 
 undef $SIG{CHLD}
    if $SIG{CHLD} eq 'IGNORE';
 
 $SIG{PIPE} = sub { }
    unless defined $SIG{PIPE};
 
 =head1 RECOMMENDED/OPTIONAL MODULES
 
 One of AnyEvent's main goals is to be 100% Pure-Perl(tm): only perl (and
 its built-in modules) are required to use it.
 
 That does not mean that AnyEvent won't take advantage of some additional
 modules if they are installed.
 
 This section explains which additional modules will be used, and how they
 affect AnyEvent's operation.
 
 =over 4
 
 =item L<Async::Interrupt>
 
 This slightly arcane module is used to implement fast signal handling: To
 my knowledge, there is no way to do completely race-free and quick
 signal handling in pure perl. To ensure that signals still get
 delivered, AnyEvent will start an interval timer to wake up perl (and
 catch the signals) with some delay (default is 10 seconds, look for
 C<$AnyEvent::MAX_SIGNAL_LATENCY>).
 
 If this module is available, then it will be used to implement signal
 catching, which means that signals will not be delayed, and the event loop
 will not be interrupted regularly, which is more efficient (and good for
 battery life on laptops).
 
 This affects not just the pure-perl event loop, but also other event loops
 that have no signal handling on their own (e.g. Glib, Tk, Qt).
 
 Some event loops (POE, Event, Event::Lib) offer signal watchers natively,
 and either employ their own workarounds (POE) or use AnyEvent's workaround
 (using C<$AnyEvent::MAX_SIGNAL_LATENCY>). Installing L<Async::Interrupt>
 does nothing for those backends.
 
 =item L<EV>
 
 This module isn't really "optional", as it is simply one of the backend
 event loops that AnyEvent can use. However, it is simply the best event
 loop available in terms of features, speed and stability: It supports
 the AnyEvent API optimally, implements all the watcher types in XS, does
 automatic timer adjustments even when no monotonic clock is available,
 can take avdantage of advanced kernel interfaces such as C<epoll> and
 C<kqueue>, and is the fastest backend I<by far>. You can even embed
 L<Glib>/L<Gtk2> in it (or vice versa, see L<EV::Glib> and L<Glib::EV>).
 
 If you only use backends that rely on another event loop (e.g. C<Tk>),
 then this module will do nothing for you.
 
 =item L<Guard>
 
 The guard module, when used, will be used to implement
 C<AnyEvent::Util::guard>. This speeds up guards considerably (and uses a
 lot less memory), but otherwise doesn't affect guard operation much. It is
 purely used for performance.
 
 =item L<JSON> and L<JSON::XS>
 
 One of these modules is required when you want to read or write JSON data
 via L<AnyEvent::Handle>. L<JSON> is also written in pure-perl, but can take
 advantage of the ultra-high-speed L<JSON::XS> module when it is installed.
 
 =item L<Net::SSLeay>
 
 Implementing TLS/SSL in Perl is certainly interesting, but not very
 worthwhile: If this module is installed, then L<AnyEvent::Handle> (with
 the help of L<AnyEvent::TLS>), gains the ability to do TLS/SSL.
 
 =item L<Time::HiRes>
 
 This module is part of perl since release 5.008. It will be used when the
 chosen event library does not come with a timing source of its own. The
 pure-perl event loop (L<AnyEvent::Loop>) will additionally load it to
 try to use a monotonic clock for timing stability.
 
 =item L<AnyEvent::AIO> (and L<IO::AIO>)
 
 The default implementation of L<AnyEvent::IO> is to do I/O synchronously,
 stopping programs while they access the disk, which is fine for a lot of
 programs.
 
 Installing AnyEvent::AIO (and its IO::AIO dependency) makes it switch to
 a true asynchronous implementation, so event processing can continue even
 while waiting for disk I/O.
 
 =back
 
 
 =head1 FORK
 
 Most event libraries are not fork-safe. The ones who are usually are
 because they rely on inefficient but fork-safe C<select> or C<poll> calls
 - higher performance APIs such as BSD's kqueue or the dreaded Linux epoll
 are usually badly thought-out hacks that are incompatible with fork in
 one way or another. Only L<EV> is fully fork-aware and ensures that you
 continue event-processing in both parent and child (or both, if you know
 what you are doing).
 
 This means that, in general, you cannot fork and do event processing in
 the child if the event library was initialised before the fork (which
 usually happens when the first AnyEvent watcher is created, or the library
 is loaded).
 
 If you have to fork, you must either do so I<before> creating your first
 watcher OR you must not use AnyEvent at all in the child OR you must do
 something completely out of the scope of AnyEvent (see below).
 
 The problem of doing event processing in the parent I<and> the child
 is much more complicated: even for backends that I<are> fork-aware or
 fork-safe, their behaviour is not usually what you want: fork clones all
 watchers, that means all timers, I/O watchers etc. are active in both
 parent and child, which is almost never what you want. Using C<exec>
 to start worker children from some kind of manage prrocess is usually
 preferred, because it is much easier and cleaner, at the expense of having
 to have another binary.
 
 In addition to logical problems with fork, there are also implementation
 problems. For example, on POSIX systems, you cannot fork at all in Perl
 code if a thread (I am talking of pthreads here) was ever created in the
 process, and this is just the tip of the iceberg. In general, using fork
 from Perl is difficult, and attempting to use fork without an exec to
 implement some kind of parallel processing is almost certainly doomed.
 
 To safely fork and exec, you should use a module such as
 L<Proc::FastSpawn> that let's you safely fork and exec new processes.
 
 If you want to do multiprocessing using processes, you can
 look at the L<AnyEvent::Fork> module (and some related modules
 such as L<AnyEvent::Fork::RPC>, L<AnyEvent::Fork::Pool> and
 L<AnyEvent::Fork::Remote>). This module allows you to safely create
 subprocesses without any limitations - you can use X11 toolkits or
 AnyEvent in the children created by L<AnyEvent::Fork> safely and without
 any special precautions.
 
 
 =head1 SECURITY CONSIDERATIONS
 
 AnyEvent can be forced to load any event model via
 $ENV{PERL_ANYEVENT_MODEL}. While this cannot (to my knowledge) be used to
 execute arbitrary code or directly gain access, it can easily be used to
 make the program hang or malfunction in subtle ways, as AnyEvent watchers
 will not be active when the program uses a different event model than
 specified in the variable.
 
 You can make AnyEvent completely ignore this variable by deleting it
 before the first watcher gets created, e.g. with a C<BEGIN> block:
 
    BEGIN { delete $ENV{PERL_ANYEVENT_MODEL} }
   
    use AnyEvent;
 
 Similar considerations apply to $ENV{PERL_ANYEVENT_VERBOSE}, as that can
 be used to probe what backend is used and gain other information (which is
 probably even less useful to an attacker than PERL_ANYEVENT_MODEL), and
 $ENV{PERL_ANYEVENT_STRICT}.
 
 Note that AnyEvent will remove I<all> environment variables starting with
 C<PERL_ANYEVENT_> from C<%ENV> when it is loaded while taint mode is
 enabled.
 
 
 =head1 BUGS
 
 Perl 5.8 has numerous memleaks that sometimes hit this module and are hard
 to work around. If you suffer from memleaks, first upgrade to Perl 5.10
 and check wether the leaks still show up. (Perl 5.10.0 has other annoying
 memleaks, such as leaking on C<map> and C<grep> but it is usually not as
 pronounced).
 
 
 =head1 SEE ALSO
 
 Tutorial/Introduction: L<AnyEvent::Intro>.
 
 FAQ: L<AnyEvent::FAQ>.
 
 Utility functions: L<AnyEvent::Util> (misc. grab-bag), L<AnyEvent::Log>
 (simply logging).
 
 Development/Debugging: L<AnyEvent::Strict> (stricter checking),
 L<AnyEvent::Debug> (interactive shell, watcher tracing).
 
 Supported event modules: L<AnyEvent::Loop>, L<EV>, L<EV::Glib>,
 L<Glib::EV>, L<Event>, L<Glib::Event>, L<Glib>, L<Tk>, L<Event::Lib>,
 L<Qt>, L<POE>, L<FLTK>, L<Cocoa::EventLoop>, L<UV>.
 
 Implementations: L<AnyEvent::Impl::EV>, L<AnyEvent::Impl::Event>,
 L<AnyEvent::Impl::Glib>, L<AnyEvent::Impl::Tk>, L<AnyEvent::Impl::Perl>,
 L<AnyEvent::Impl::EventLib>, L<AnyEvent::Impl::Qt>,
 L<AnyEvent::Impl::POE>, L<AnyEvent::Impl::IOAsync>, L<AnyEvent::Impl::Irssi>,
 L<AnyEvent::Impl::FLTK>, L<AnyEvent::Impl::Cocoa>, L<AnyEvent::Impl::UV>.
 
 Non-blocking handles, pipes, stream sockets, TCP clients and
 servers: L<AnyEvent::Handle>, L<AnyEvent::Socket>, L<AnyEvent::TLS>.
 
 Asynchronous File I/O: L<AnyEvent::IO>.
 
 Asynchronous DNS: L<AnyEvent::DNS>.
 
 Thread support: L<Coro>, L<Coro::AnyEvent>, L<Coro::EV>, L<Coro::Event>.
 
 Nontrivial usage examples: L<AnyEvent::GPSD>, L<AnyEvent::IRC>,
 L<AnyEvent::HTTP>.
 
 
 =head1 AUTHOR
 
    Marc Lehmann <schmorp@schmorp.de>
    http://anyevent.schmorp.de
 
 =cut
 
 1
 
### AnyEvent/DNS.pm ###
 =head1 NAME
 
 AnyEvent::DNS - fully asynchronous DNS resolution
 
 =head1 SYNOPSIS
 
    use AnyEvent::DNS;
    
    my $cv = AnyEvent->condvar;
    AnyEvent::DNS::a "www.google.de", $cv;
    # ... later
    my @addrs = $cv->recv;
 
 =head1 DESCRIPTION
 
 This module offers both a number of DNS convenience functions as well
 as a fully asynchronous and high-performance pure-perl stub resolver.
 
 The stub resolver supports DNS over IPv4 and IPv6, UDP and TCP, optional
 EDNS0 support for up to 4kiB datagrams and automatically falls back to
 virtual circuit mode for large responses.
 
 =head2 CONVENIENCE FUNCTIONS
 
 =over 4
 
 =cut
 
 package AnyEvent::DNS;
 
 use Carp ();
 use Socket qw(AF_INET SOCK_DGRAM SOCK_STREAM);
 
 use AnyEvent (); BEGIN { AnyEvent::common_sense }
 use AnyEvent::Util qw(AF_INET6);
 
 our $VERSION = $AnyEvent::VERSION;
 our @DNS_FALLBACK; # some public dns servers as fallback
 
 {
    my $prep = sub {
       $_ = $_->[rand @$_] for @_;
       push @_, splice @_, rand $_, 1 for reverse 1..@_; # shuffle
       $_ = pack "H*", $_ for @_;
       \@_
    };
 
    my $ipv4 = $prep->(
       ["08080808", "08080404"], # 8.8.8.8, 8.8.4.4 - google public dns
 ##      ["d1f40003", "d1f30004"], # v209.244.0.3/4 - resolver1/2.level3.net - status unknown
 ##      ["04020201", "04020203", "04020204", "04020205", "04020206"], # v4.2.2.1/3/4/5/6 - vnsc-pri.sys.gtei.net - effectively public
 ##      ["cdd22ad2", "4044c8c8"], # 205.210.42.205, 64.68.200.200 - cache1/2.dnsresolvers.com - verified public
 #      ["8d010101"], # 141.1.1.1 - cable&wireless - status unknown
    );
 
    my $ipv6 = $prep->(
       ["20014860486000000000000000008888", "20014860486000000000000000008844"], # 2001:4860:4860::8888/8844 - google ipv6
    );
 
    undef $ipv4 unless $AnyEvent::PROTOCOL{ipv4};
    undef $ipv6 unless $AnyEvent::PROTOCOL{ipv6};
 
    ($ipv6, $ipv4) = ($ipv4, $ipv6)
       if $AnyEvent::PROTOCOL{ipv6} > $AnyEvent::PROTOCOL{ipv4};
 
    @DNS_FALLBACK = (@$ipv4, @$ipv6);
 }
 
 =item AnyEvent::DNS::a $domain, $cb->(@addrs)
 
 Tries to resolve the given domain to IPv4 address(es).
 
 =item AnyEvent::DNS::aaaa $domain, $cb->(@addrs)
 
 Tries to resolve the given domain to IPv6 address(es).
 
 =item AnyEvent::DNS::mx $domain, $cb->(@hostnames)
 
 Tries to resolve the given domain into a sorted (lower preference value
 first) list of domain names.
 
 =item AnyEvent::DNS::ns $domain, $cb->(@hostnames)
 
 Tries to resolve the given domain name into a list of name servers.
 
 =item AnyEvent::DNS::txt $domain, $cb->(@hostnames)
 
 Tries to resolve the given domain name into a list of text records. Only
 the first text string per record will be returned. If you want all
 strings, you need to call the resolver manually:
 
    resolver->resolve ($domain => "txt", sub {
       for my $record (@_) {
          my (undef, undef, undef, @txt) = @$record;
          # strings now in @txt
       }
    });
 
 =item AnyEvent::DNS::srv $service, $proto, $domain, $cb->(@srv_rr)
 
 Tries to resolve the given service, protocol and domain name into a list
 of service records.
 
 Each C<$srv_rr> is an array reference with the following contents: 
 C<[$priority, $weight, $transport, $target]>.
 
 They will be sorted with lowest priority first, then randomly
 distributed by weight as per RFC 2782.
 
 Example:
 
    AnyEvent::DNS::srv "sip", "udp", "schmorp.de", sub { ...
    # @_ = ( [10, 10, 5060, "sip1.schmorp.de" ] )
 
 =item AnyEvent::DNS::any $domain, $cb->(@rrs)
 
 Tries to resolve the given domain and passes all resource records found to
 the callback.
 
 =item AnyEvent::DNS::ptr $domain, $cb->(@hostnames)
 
 Tries to make a PTR lookup on the given domain. See C<reverse_lookup>
 and C<reverse_verify> if you want to resolve an IP address to a hostname
 instead.
 
 =item AnyEvent::DNS::reverse_lookup $ipv4_or_6, $cb->(@hostnames)
 
 Tries to reverse-resolve the given IPv4 or IPv6 address (in textual form)
 into its hostname(s). Handles V4MAPPED and V4COMPAT IPv6 addresses
 transparently.
 
 =item AnyEvent::DNS::reverse_verify $ipv4_or_6, $cb->(@hostnames)
 
 The same as C<reverse_lookup>, but does forward-lookups to verify that
 the resolved hostnames indeed point to the address, which makes spoofing
 harder.
 
 If you want to resolve an address into a hostname, this is the preferred
 method: The DNS records could still change, but at least this function
 verified that the hostname, at one point in the past, pointed at the IP
 address you originally resolved.
 
 Example:
 
    AnyEvent::DNS::reverse_verify "2001:500:2f::f", sub { print shift };
    # => f.root-servers.net
 
 =cut
 
 sub MAX_PKT() { 4096 } # max packet size we advertise and accept
 
 sub DOMAIN_PORT() { 53 } # if this changes drop me a note
 
 sub resolver ();
 
 sub a($$) {
    my ($domain, $cb) = @_;
 
    resolver->resolve ($domain => "a", sub {
       $cb->(map $_->[4], @_);
    });
 }
 
 sub aaaa($$) {
    my ($domain, $cb) = @_;
 
    resolver->resolve ($domain => "aaaa", sub {
       $cb->(map $_->[4], @_);
    });
 }
 
 sub mx($$) {
    my ($domain, $cb) = @_;
 
    resolver->resolve ($domain => "mx", sub {
       $cb->(map $_->[5], sort { $a->[4] <=> $b->[4] } @_);
    });
 }
 
 sub ns($$) {
    my ($domain, $cb) = @_;
 
    resolver->resolve ($domain => "ns", sub {
       $cb->(map $_->[4], @_);
    });
 }
 
 sub txt($$) {
    my ($domain, $cb) = @_;
 
    resolver->resolve ($domain => "txt", sub {
       $cb->(map $_->[4], @_);
    });
 }
 
 sub srv($$$$) {
    my ($service, $proto, $domain, $cb) = @_;
 
    # todo, ask for any and check glue records
    resolver->resolve ("_$service._$proto.$domain" => "srv", sub {
       my @res;
 
       # classify by priority
       my %pri;
       push @{ $pri{$_->[4]} }, [ @$_[4,5,6,7] ]
          for @_;
 
       # order by priority
       for my $pri (sort { $a <=> $b } keys %pri) {
          # order by weight
          my @rr = sort { $a->[1] <=> $b->[1] } @{ delete $pri{$pri} };
 
          my $sum; $sum += $_->[1] for @rr;
 
          while (@rr) {
             my $w = int rand $sum + 1;
             for (0 .. $#rr) {
                if (($w -= $rr[$_][1]) <= 0) {
                   $sum -= $rr[$_][1];
                   push @res, splice @rr, $_, 1, ();
                   last;
                }
             }
          }
       }
 
       $cb->(@res);
    });
 }
 
 sub ptr($$) {
    my ($domain, $cb) = @_;
 
    resolver->resolve ($domain => "ptr", sub {
       $cb->(map $_->[4], @_);
    });
 }
 
 sub any($$) {
    my ($domain, $cb) = @_;
 
    resolver->resolve ($domain => "*", $cb);
 }
 
 # convert textual ip address into reverse lookup form
 sub _munge_ptr($) {
    my $ipn = $_[0]
       or return;
 
    my $ptr;
 
    my $af = AnyEvent::Socket::address_family ($ipn);
 
    if ($af == AF_INET6) {
       $ipn = substr $ipn, 0, 16; # anticipate future expansion
 
       # handle v4mapped and v4compat
       if ($ipn =~ s/^\x00{10}(?:\xff\xff|\x00\x00)//) {
          $af = AF_INET;
       } else {
          $ptr = join ".", (reverse split //, unpack "H32", $ipn), "ip6.arpa.";
       }
    }
 
    if ($af == AF_INET) {
       $ptr = join ".", (reverse unpack "C4", $ipn), "in-addr.arpa.";
    }
 
    $ptr
 }
 
 sub reverse_lookup($$) {
    my ($ip, $cb) = @_;
 
    $ip = _munge_ptr AnyEvent::Socket::parse_address ($ip)
       or return $cb->();
 
    resolver->resolve ($ip => "ptr", sub {
       $cb->(map $_->[4], @_);
    });
 }
 
 sub reverse_verify($$) {
    my ($ip, $cb) = @_;
    
    my $ipn = AnyEvent::Socket::parse_address ($ip)
       or return $cb->();
 
    my $af = AnyEvent::Socket::address_family ($ipn);
 
    my @res;
    my $cnt;
 
    my $ptr = _munge_ptr $ipn
       or return $cb->();
 
    $ip = AnyEvent::Socket::format_address ($ipn); # normalise into the same form
 
    ptr $ptr, sub {
       for my $name (@_) {
          ++$cnt;
          
          # () around AF_INET to work around bug in 5.8
          resolver->resolve ("$name." => ($af == (AF_INET) ? "a" : "aaaa"), sub {
             for (@_) {
                push @res, $name
                   if $_->[4] eq $ip;
             }
             $cb->(@res) unless --$cnt;
          });
       }
 
       $cb->() unless $cnt;
    };
 }
 
 #################################################################################
 
 =back
 
 =head2 LOW-LEVEL DNS EN-/DECODING FUNCTIONS
 
 =over 4
 
 =item $AnyEvent::DNS::EDNS0
 
 This variable decides whether dns_pack automatically enables EDNS0
 support. By default, this is disabled (C<0>), unless overridden by
 C<$ENV{PERL_ANYEVENT_EDNS0}>, but when set to C<1>, AnyEvent::DNS will use
 EDNS0 in all requests.
 
 =cut
 
 our $EDNS0 = $ENV{PERL_ANYEVENT_EDNS0}*1; # set to 1 to enable (partial) edns0
 
 our %opcode_id = (
    query  => 0,
    iquery => 1,
    status => 2,
    notify => 4,
    update => 5,
    map +($_ => $_), 3, 6..15
 );
 
 our %opcode_str = reverse %opcode_id;
 
 our %rcode_id = (
    noerror  =>  0,
    formerr  =>  1,
    servfail =>  2,
    nxdomain =>  3,
    notimp   =>  4,
    refused  =>  5,
    yxdomain =>  6, # Name Exists when it should not     [RFC 2136]
    yxrrset  =>  7, # RR Set Exists when it should not   [RFC 2136]
    nxrrset  =>  8, # RR Set that should exist does not  [RFC 2136]
    notauth  =>  9, # Server Not Authoritative for zone  [RFC 2136]
    notzone  => 10, # Name not contained in zone         [RFC 2136]
 # EDNS0  16    BADVERS   Bad OPT Version                    [RFC 2671]
 # EDNS0  16    BADSIG    TSIG Signature Failure             [RFC 2845]
 # EDNS0  17    BADKEY    Key not recognized                 [RFC 2845]
 # EDNS0  18    BADTIME   Signature out of time window       [RFC 2845]
 # EDNS0  19    BADMODE   Bad TKEY Mode                      [RFC 2930]
 # EDNS0  20    BADNAME   Duplicate key name                 [RFC 2930]
 # EDNS0  21    BADALG    Algorithm not supported            [RFC 2930]
    map +($_ => $_), 11..15
 );
 
 our %rcode_str = reverse %rcode_id;
 
 our %type_id = (
    a     =>   1,
    ns    =>   2,
    md    =>   3,
    mf    =>   4,
    cname =>   5,
    soa   =>   6,
    mb    =>   7,
    mg    =>   8,
    mr    =>   9,
    null  =>  10,
    wks   =>  11,
    ptr   =>  12,
    hinfo =>  13,
    minfo =>  14,
    mx    =>  15,
    txt   =>  16,
    aaaa  =>  28,
    srv   =>  33,
    naptr =>  35, # rfc2915
    dname =>  39, # rfc2672
    opt   =>  41,
    spf   =>  99,
    tkey  => 249,
    tsig  => 250,
    ixfr  => 251,
    axfr  => 252,
    mailb => 253,
    "*"   => 255,
 );
 
 our %type_str = reverse %type_id;
 
 our %class_id = (
    in   =>   1,
    ch   =>   3,
    hs   =>   4,
    none => 254,
    "*"  => 255,
 );
 
 our %class_str = reverse %class_id;
 
 sub _enc_name($) {
    pack "(C/a*)*", (split /\./, shift), ""
 }
 
 if ($] < 5.008) {
    # special slower 5.6 version
    *_enc_name = sub ($) {
       join "", map +(pack "C/a*", $_), (split /\./, shift), ""
    };
 }
 
 sub _enc_qd() {
    (_enc_name $_->[0]) . pack "nn",
      ($_->[1] > 0 ? $_->[1] : $type_id {$_->[1]}),
      ($_->[3] > 0 ? $_->[2] : $class_id{$_->[2] || "in"})
 }
 
 sub _enc_rr() {
    die "encoding of resource records is not supported";
 }
 
 =item $pkt = AnyEvent::DNS::dns_pack $dns
 
 Packs a perl data structure into a DNS packet. Reading RFC 1035 is strongly
 recommended, then everything will be totally clear. Or maybe not.
 
 Resource records are not yet encodable.
 
 Examples:
 
    # very simple request, using lots of default values:
    { rd => 1, qd => [ [ "host.domain", "a"] ] }
   
    # more complex example, showing how flags etc. are named:
   
    {
       id => 10000,
       op => "query",
       rc => "nxdomain",
   
       # flags
       qr => 1,
       aa => 0,
       tc => 0,
       rd => 0,
       ra => 0,
       ad => 0,
       cd => 0,
   
       qd => [@rr], # query section
       an => [@rr], # answer section
       ns => [@rr], # authority section
       ar => [@rr], # additional records section
    }
 
 =cut
 
 sub dns_pack($) {
    my ($req) = @_;
 
    pack "nn nnnn a* a* a* a* a*",
       $req->{id},
 
       ! !$req->{qr}   * 0x8000
       + $opcode_id{$req->{op}} * 0x0800
       + ! !$req->{aa} * 0x0400
       + ! !$req->{tc} * 0x0200
       + ! !$req->{rd} * 0x0100
       + ! !$req->{ra} * 0x0080
       + ! !$req->{ad} * 0x0020
       + ! !$req->{cd} * 0x0010
       + $rcode_id{$req->{rc}} * 0x0001,
 
       scalar @{ $req->{qd} || [] },
       scalar @{ $req->{an} || [] },
       scalar @{ $req->{ns} || [] },
       $EDNS0 + scalar @{ $req->{ar} || [] }, # EDNS0 option included here
 
       (join "", map _enc_qd, @{ $req->{qd} || [] }),
       (join "", map _enc_rr, @{ $req->{an} || [] }),
       (join "", map _enc_rr, @{ $req->{ns} || [] }),
       (join "", map _enc_rr, @{ $req->{ar} || [] }),
 
       ($EDNS0 ? pack "C nnNn", 0, 41, MAX_PKT, 0, 0 : "") # EDNS0 option
 }
 
 our $ofs;
 our $pkt;
 
 # bitches
 sub _dec_name {
    my @res;
    my $redir;
    my $ptr = $ofs;
    my $cnt;
 
    while () {
       return undef if ++$cnt >= 256; # to avoid DoS attacks
 
       my $len = ord substr $pkt, $ptr++, 1;
 
       if ($len >= 0xc0) {
          $ptr++;
          $ofs = $ptr if $ptr > $ofs;
          $ptr = (unpack "n", substr $pkt, $ptr - 2, 2) & 0x3fff;
       } elsif ($len) {
          push @res, substr $pkt, $ptr, $len;
          $ptr += $len;
       } else {
          $ofs = $ptr if $ptr > $ofs;
          return join ".", @res;
       }
    }
 }
 
 sub _dec_qd {
    my $qname = _dec_name;
    my ($qt, $qc) = unpack "nn", substr $pkt, $ofs; $ofs += 4;
    [$qname, $type_str{$qt} || $qt, $class_str{$qc} || $qc]
 }
 
 our %dec_rr = (
      1 => sub { join ".", unpack "C4", $_ }, # a
      2 => sub { local $ofs = $ofs - length; _dec_name }, # ns
      5 => sub { local $ofs = $ofs - length; _dec_name }, # cname
      6 => sub { 
              local $ofs = $ofs - length;
              my $mname = _dec_name;
              my $rname = _dec_name;
              ($mname, $rname, unpack "NNNNN", substr $pkt, $ofs)
           }, # soa
     11 => sub { ((join ".", unpack "C4", $_), unpack "C a*", substr $_, 4) }, # wks
     12 => sub { local $ofs = $ofs - length; _dec_name }, # ptr
     13 => sub { unpack "C/a* C/a*", $_ }, # hinfo
     15 => sub { local $ofs = $ofs + 2 - length; ((unpack "n", $_), _dec_name) }, # mx
     16 => sub { unpack "(C/a*)*", $_ }, # txt
     28 => sub { AnyEvent::Socket::format_ipv6 ($_) }, # aaaa
     33 => sub { local $ofs = $ofs + 6 - length; ((unpack "nnn", $_), _dec_name) }, # srv
     35 => sub { # naptr
        # requires perl 5.10, sorry
        my ($order, $preference, $flags, $service, $regexp, $offset) = unpack "nn C/a* C/a* C/a* .", $_;
        local $ofs = $ofs + $offset - length;
        ($order, $preference, $flags, $service, $regexp, _dec_name)
     },
     39 => sub { local $ofs = $ofs - length; _dec_name }, # dname
     99 => sub { unpack "(C/a*)*", $_ }, # spf
 );
 
 sub _dec_rr {
    my $name = _dec_name;
 
    my ($rt, $rc, $ttl, $rdlen) = unpack "nn N n", substr $pkt, $ofs; $ofs += 10;
    local $_ = substr $pkt, $ofs, $rdlen; $ofs += $rdlen;
 
    [
       $name,
       $type_str{$rt}  || $rt,
       $class_str{$rc} || $rc,
       $ttl,
       ($dec_rr{$rt} || sub { $_ })->(),
    ]
 }
 
 =item $dns = AnyEvent::DNS::dns_unpack $pkt
 
 Unpacks a DNS packet into a perl data structure.
 
 Examples:
 
    # an unsuccessful reply
    {
      'qd' => [
                [ 'ruth.plan9.de.mach.uni-karlsruhe.de', '*', 'in' ]
              ],
      'rc' => 'nxdomain',
      'ar' => [],
      'ns' => [
                [
                  'uni-karlsruhe.de',
                  'soa',
                  'in',
                  600,
                  'netserv.rz.uni-karlsruhe.de',
                  'hostmaster.rz.uni-karlsruhe.de',
                  2008052201, 10800, 1800, 2592000, 86400
                ]
              ],
      'tc' => '',
      'ra' => 1,
      'qr' => 1,
      'id' => 45915,
      'aa' => '',
      'an' => [],
      'rd' => 1,
      'op' => 'query'
    }
    
    # a successful reply
    
    {
      'qd' => [ [ 'www.google.de', 'a', 'in' ] ],
      'rc' => 0,
      'ar' => [
                [ 'a.l.google.com', 'a', 'in', 3600, '209.85.139.9' ],
                [ 'b.l.google.com', 'a', 'in', 3600, '64.233.179.9' ],
                [ 'c.l.google.com', 'a', 'in', 3600, '64.233.161.9' ],
              ],
      'ns' => [
                [ 'l.google.com', 'ns', 'in', 3600, 'a.l.google.com' ],
                [ 'l.google.com', 'ns', 'in', 3600, 'b.l.google.com' ],
              ],
      'tc' => '',
      'ra' => 1,
      'qr' => 1,
      'id' => 64265,
      'aa' => '',
      'an' => [
                [ 'www.google.de', 'cname', 'in', 3600, 'www.google.com' ],
                [ 'www.google.com', 'cname', 'in', 3600, 'www.l.google.com' ],
                [ 'www.l.google.com', 'a', 'in', 3600, '66.249.93.104' ],
                [ 'www.l.google.com', 'a', 'in', 3600, '66.249.93.147' ],
              ],
      'rd' => 1,
      'op' => 0
    }
 
 =cut
 
 sub dns_unpack($) {
    local $pkt = shift;
    my ($id, $flags, $qd, $an, $ns, $ar)
       = unpack "nn nnnn A*", $pkt;
 
    local $ofs = 6 * 2;
 
    {
       id => $id,
       qr => ! ! ($flags & 0x8000),
       aa => ! ! ($flags & 0x0400),
       tc => ! ! ($flags & 0x0200),
       rd => ! ! ($flags & 0x0100),
       ra => ! ! ($flags & 0x0080),
       ad => ! ! ($flags & 0x0020),
       cd => ! ! ($flags & 0x0010),
       op => $opcode_str{($flags & 0x001e) >> 11},
       rc => $rcode_str{($flags & 0x000f)},
 
       qd => [map _dec_qd, 1 .. $qd],
       an => [map _dec_rr, 1 .. $an],
       ns => [map _dec_rr, 1 .. $ns],
       ar => [map _dec_rr, 1 .. $ar],
    }
 }
 
 #############################################################################
 
 =back
 
 =head2 THE AnyEvent::DNS RESOLVER CLASS
 
 This is the class which does the actual protocol work.
 
 =over 4
 
 =cut
 
 use Carp ();
 use Scalar::Util ();
 use Socket ();
 
 our $NOW;
 
 =item AnyEvent::DNS::resolver
 
 This function creates and returns a resolver that is ready to use and
 should mimic the default resolver for your system as good as possible. It
 is used by AnyEvent itself as well.
 
 It only ever creates one resolver and returns this one on subsequent calls
 - see C<$AnyEvent::DNS::RESOLVER>, below, for details.
 
 Unless you have special needs, prefer this function over creating your own
 resolver object.
 
 The resolver is created with the following parameters:
 
    untaint          enabled
    max_outstanding  $ENV{PERL_ANYEVENT_MAX_OUTSTANDING_DNS} (default 10)
 
 C<os_config> will be used for OS-specific configuration, unless
 C<$ENV{PERL_ANYEVENT_RESOLV_CONF}> is specified, in which case that file
 gets parsed.
 
 =item $AnyEvent::DNS::RESOLVER
 
 This variable stores the default resolver returned by
 C<AnyEvent::DNS::resolver>, or C<undef> when the default resolver hasn't
 been instantiated yet.
 
 One can provide a custom resolver (e.g. one with caching functionality)
 by storing it in this variable, causing all subsequent resolves done via
 C<AnyEvent::DNS::resolver> to be done via the custom one.
 
 =cut
 
 our $RESOLVER;
 
 sub resolver() {
    $RESOLVER || do {
       $RESOLVER = new AnyEvent::DNS
          untaint         => 1,
          max_outstanding => $ENV{PERL_ANYEVENT_MAX_OUTSTANDING_DNS}*1 || 10,
       ;
 
       $ENV{PERL_ANYEVENT_RESOLV_CONF}
          ? $RESOLVER->_load_resolv_conf_file ($ENV{PERL_ANYEVENT_RESOLV_CONF})
          : $RESOLVER->os_config;
 
       $RESOLVER
    }
 }
 
 =item $resolver = new AnyEvent::DNS key => value...
 
 Creates and returns a new resolver.
 
 The following options are supported:
 
 =over 4
 
 =item server => [...]
 
 A list of server addresses (default: C<v127.0.0.1> or C<::1>) in network
 format (i.e. as returned by C<AnyEvent::Socket::parse_address> - both IPv4
 and IPv6 are supported).
 
 =item timeout => [...]
 
 A list of timeouts to use (also determines the number of retries). To make
 three retries with individual time-outs of 2, 5 and 5 seconds, use C<[2,
 5, 5]>, which is also the default.
 
 =item search => [...]
 
 The default search list of suffixes to append to a domain name (default: none).
 
 =item ndots => $integer
 
 The number of dots (default: C<1>) that a name must have so that the resolver
 tries to resolve the name without any suffixes first.
 
 =item max_outstanding => $integer
 
 Most name servers do not handle many parallel requests very well. This
 option limits the number of outstanding requests to C<$integer>
 (default: C<10>), that means if you request more than this many requests,
 then the additional requests will be queued until some other requests have
 been resolved.
 
 =item reuse => $seconds
 
 The number of seconds (default: C<300>) that a query id cannot be re-used
 after a timeout. If there was no time-out then query ids can be reused
 immediately.
 
 =item untaint => $boolean
 
 When true, then the resolver will automatically untaint results, and might
 also ignore certain environment variables.
 
 =back
 
 =cut
 
 sub new {
    my ($class, %arg) = @_;
 
    my $self = bless {
       server  => [],
       timeout => [2, 5, 5],
       search  => [],
       ndots   => 1,
       max_outstanding => 10,
       reuse   => 300,
       %arg,
       inhibit => 0,
       reuse_q => [],
    }, $class;
 
    # search should default to gethostname's domain
    # but perl lacks a good posix module
 
    # try to create an ipv4 and an ipv6 socket
    # only fail when we cannot create either
    my $got_socket;
 
    Scalar::Util::weaken (my $wself = $self);
 
    if (socket my $fh4, AF_INET , Socket::SOCK_DGRAM(), 0) {
       ++$got_socket;
 
       AnyEvent::fh_unblock $fh4;
       $self->{fh4} = $fh4;
       $self->{rw4} = AE::io $fh4, 0, sub {
          if (my $peer = recv $fh4, my $pkt, MAX_PKT, 0) {
             $wself->_recv ($pkt, $peer);
          }
       };
    }
 
    if (AF_INET6 && socket my $fh6, AF_INET6, Socket::SOCK_DGRAM(), 0) {
       ++$got_socket;
 
       $self->{fh6} = $fh6;
       AnyEvent::fh_unblock $fh6;
       $self->{rw6} = AE::io $fh6, 0, sub {
          if (my $peer = recv $fh6, my $pkt, MAX_PKT, 0) {
             $wself->_recv ($pkt, $peer);
          }
       };
    }
 
    $got_socket
       or Carp::croak "unable to create either an IPv4 or an IPv6 socket";
 
    $self->_compile;
 
    $self
 }
 
 # called to start asynchronous configuration
 sub _config_begin {
    ++$_[0]{inhibit};
 }
 
 # called when done with async config
 sub _config_done {
    --$_[0]{inhibit};
    $_[0]->_compile;
    $_[0]->_scheduler;
 }
 
 =item $resolver->parse_resolv_conf ($string)
 
 Parses the given string as if it were a F<resolv.conf> file. The following
 directives are supported (but not necessarily implemented).
 
 C<#>- and C<;>-style comments, C<nameserver>, C<domain>, C<search>, C<sortlist>,
 C<options> (C<timeout>, C<attempts>, C<ndots>).
 
 Everything else is silently ignored.
 
 =cut
 
 sub parse_resolv_conf {
    my ($self, $resolvconf) = @_;
 
    $self->{server} = [];
    $self->{search} = [];
 
    my $attempts;
 
    for (split /\n/, $resolvconf) {
       s/\s*[;#].*$//; # not quite legal, but many people insist
 
       if (/^\s*nameserver\s+(\S+)\s*$/i) {
          my $ip = $1;
          if (my $ipn = AnyEvent::Socket::parse_address ($ip)) {
             push @{ $self->{server} }, $ipn;
          } else {
             AE::log 5 => "nameserver $ip invalid and ignored, while parsing resolver config.";
          }
       } elsif (/^\s*domain\s+(\S*)\s*$/i) {
          $self->{search} = [$1];
       } elsif (/^\s*search\s+(.*?)\s*$/i) {
          $self->{search} = [split /\s+/, $1];
       } elsif (/^\s*sortlist\s+(.*?)\s*$/i) {
          # ignored, NYI
       } elsif (/^\s*options\s+(.*?)\s*$/i) {
          for (split /\s+/, $1) {
             if (/^timeout:(\d+)$/) {
                $self->{timeout} = [$1];
             } elsif (/^attempts:(\d+)$/) {
                $attempts = $1;
             } elsif (/^ndots:(\d+)$/) {
                $self->{ndots} = $1;
             } else {
                # debug, rotate, no-check-names, inet6
             }
          }
       } else {
          # silently skip stuff we don't understand
       }
    }
 
    $self->{timeout} = [($self->{timeout}[0]) x $attempts]
       if $attempts;
 
    $self->_compile;
 }
 
 sub _load_resolv_conf_file {
    my ($self, $resolv_conf) = @_;
 
    $self->_config_begin;
 
    require AnyEvent::IO;
    AnyEvent::IO::aio_load ($resolv_conf, sub {
       if (my ($contents) = @_) {
          $self->parse_resolv_conf ($contents);
       } else {
          AE::log 4 => "$resolv_conf: $!";
       }
 
       $self->_config_done;
    });
 }
 
 =item $resolver->os_config
 
 Tries so load and parse F</etc/resolv.conf> on portable operating
 systems. Tries various egregious hacks on windows to force the DNS servers
 and searchlist out of the system.
 
 This method must be called at most once before trying to resolve anything.
 
 =cut
 
 sub os_config {
    my ($self) = @_;
 
    $self->_config_begin;
 
    $self->{server} = [];
    $self->{search} = [];
 
    if ((AnyEvent::WIN32 || $^O =~ /cygwin/i)) {
       # TODO: this blocks the program, but should not, but I
       # am too lazy to implement and test it. need to boot windows. ugh.
 
       #no strict 'refs';
 
       # there are many options to find the current nameservers etc. on windows
       # all of them don't work consistently:
       # - the registry thing needs separate code on win32 native vs. cygwin
       # - the registry layout differs between windows versions
       # - calling windows api functions doesn't work on cygwin
       # - ipconfig uses locale-specific messages
 
       # we use Net::DNS::Resolver first, and if it fails, will fall back to
       # ipconfig parsing.
       unless (eval {
          # Net::DNS::Resolver uses a LOT of ram (~10mb), but what can we do :/
          # (this seems mostly to be due to Win32::API).
          require Net::DNS::Resolver;
          my $r = Net::DNS::Resolver->new;
 
          $r->nameservers
             or die;
 
          for my $s ($r->nameservers) {
             if (my $ipn = AnyEvent::Socket::parse_address ($s)) {
                push @{ $self->{server} }, $ipn;
             }
          }
          $self->{search} = [$r->searchlist];
 
          1
       }) {
          # we use ipconfig parsing because, despite all its brokenness,
          # it seems quite stable in practise.
          # unfortunately it wants a console window.
          # for good measure, we append a fallback nameserver to our list.
 
          if (open my $fh, "ipconfig /all |") {
             # parsing strategy: we go through the output and look for
             # :-lines with DNS in them. everything in those is regarded as
             # either a nameserver (if it parses as an ip address), or a suffix
             # (all else).
 
             my $dns;
             local $_;
             while (<$fh>) {
                if (s/^\s.*\bdns\b.*://i) {
                   $dns = 1;
                } elsif (/^\S/ || /^\s[^:]{16,}: /) {
                   $dns = 0;
                }
                if ($dns && /^\s*(\S+)\s*$/) {
                   my $s = $1;
                   $s =~ s/%\d+(?!\S)//; # get rid of ipv6 scope id
                   if (my $ipn = AnyEvent::Socket::parse_address ($s)) {
                      push @{ $self->{server} }, $ipn;
                   } else {
                      push @{ $self->{search} }, $s;
                   }
                }
             }
          }
       }
 
       # always add the fallback servers on windows
       push @{ $self->{server} }, @DNS_FALLBACK;
 
       $self->_config_done;
    } else {
       # try /etc/resolv.conf everywhere else
 
       require AnyEvent::IO;
       AnyEvent::IO::aio_stat ("/etc/resolv.conf", sub {
          $self->_load_resolv_conf_file ("/etc/resolv.conf")
             if @_;
          $self->_config_done;
       });
    }
 }
 
 =item $resolver->timeout ($timeout, ...)
 
 Sets the timeout values. See the C<timeout> constructor argument (and
 note that this method expects the timeout values themselves, not an
 array-reference).
 
 =cut
 
 sub timeout {
    my ($self, @timeout) = @_;
 
    $self->{timeout} = \@timeout;
    $self->_compile;
 }
 
 =item $resolver->max_outstanding ($nrequests)
 
 Sets the maximum number of outstanding requests to C<$nrequests>. See the
 C<max_outstanding> constructor argument.
 
 =cut
 
 sub max_outstanding {
    my ($self, $max) = @_;
 
    $self->{max_outstanding} = $max;
    $self->_compile;
 }
 
 sub _compile {
    my $self = shift;
 
    my %search; $self->{search} = [grep 0 < length, grep !$search{$_}++, @{ $self->{search} }];
    my %server; $self->{server} = [grep 0 < length, grep !$server{$_}++, @{ $self->{server} }];
 
    unless (@{ $self->{server} }) {
       # use 127.0.0.1/::1 by default, add public nameservers as fallback
       my $default = $AnyEvent::PROTOCOL{ipv6} > $AnyEvent::PROTOCOL{ipv4}
                     ? "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1" : "\x7f\x00\x00\x01";
       $self->{server} = [$default, @DNS_FALLBACK];
    }
 
    my @retry;
 
    for my $timeout (@{ $self->{timeout} }) {
       for my $server (@{ $self->{server} }) {
          push @retry, [$server, $timeout];
       }
    }
 
    $self->{retry} = \@retry;
 }
 
 sub _feed {
    my ($self, $res) = @_;
 
    ($res) = $res =~ /^(.*)$/s
       if AnyEvent::TAINT && $self->{untaint};
 
    $res = dns_unpack $res
       or return;
 
    my $id = $self->{id}{$res->{id}};
 
    return unless ref $id;
 
    $NOW = time;
    $id->[1]->($res);
 }
 
 sub _recv {
    my ($self, $pkt, $peer) = @_;
 
    # we ignore errors (often one gets port unreachable, but there is
    # no good way to take advantage of that.
 
    my ($port, $host) = AnyEvent::Socket::unpack_sockaddr ($peer);
 
    return unless $port == DOMAIN_PORT && grep $_ eq $host, @{ $self->{server} };
 
    $self->_feed ($pkt);
 }
 
 sub _free_id {
    my ($self, $id, $timeout) = @_;
 
    if ($timeout) {
       # we need to block the id for a while
       $self->{id}{$id} = 1;
       push @{ $self->{reuse_q} }, [$NOW + $self->{reuse}, $id];
    } else {
       # we can quickly recycle the id
       delete $self->{id}{$id};
    }
 
    --$self->{outstanding};
    $self->_scheduler;
 }
 
 # execute a single request, involves sending it with timeouts to multiple servers
 sub _exec {
    my ($self, $req) = @_;
 
    my $retry; # of retries
    my $do_retry;
 
    $do_retry = sub {
       my $retry_cfg = $self->{retry}[$retry++]
          or do {
             # failure
             $self->_free_id ($req->[2], $retry > 1);
             undef $do_retry; return $req->[1]->();
          };
 
       my ($server, $timeout) = @$retry_cfg;
       
       $self->{id}{$req->[2]} = [(AE::timer $timeout, 0, sub {
          $NOW = time;
 
          # timeout, try next
          &$do_retry if $do_retry;
       }), sub {
          my ($res) = @_;
 
          if ($res->{tc}) {
             # success, but truncated, so use tcp
             AnyEvent::Socket::tcp_connect (AnyEvent::Socket::format_address ($server), DOMAIN_PORT, sub {
                return unless $do_retry; # some other request could have invalidated us already
 
                my ($fh) = @_
                   or return &$do_retry;
 
                require AnyEvent::Handle;
 
                my $handle; $handle = new AnyEvent::Handle
                   fh       => $fh,
                   timeout  => $timeout,
                   on_error => sub {
                      undef $handle;
                      return unless $do_retry; # some other request could have invalidated us already
                      # failure, try next
                      &$do_retry;
                   };
 
                $handle->push_write (pack "n/a*", $req->[0]);
                $handle->push_read (chunk => 2, sub {
                   $handle->unshift_read (chunk => (unpack "n", $_[1]), sub {
                      undef $handle;
                      $self->_feed ($_[1]);
                   });
                });
 
             }, sub { $timeout });
 
          } else {
             # success
             $self->_free_id ($req->[2], $retry > 1);
             undef $do_retry; return $req->[1]->($res);
          }
       }];
       
       my $sa = AnyEvent::Socket::pack_sockaddr (DOMAIN_PORT, $server);
 
       my $fh = AF_INET == AnyEvent::Socket::sockaddr_family ($sa)
                ? $self->{fh4} : $self->{fh6}
          or return &$do_retry;
 
       send $fh, $req->[0], 0, $sa;
    };
 
    &$do_retry;
 }
 
 sub _scheduler {
    my ($self) = @_;
 
    return if $self->{inhibit};
 
    #no strict 'refs';
 
    $NOW = time;
 
    # first clear id reuse queue
    delete $self->{id}{ (shift @{ $self->{reuse_q} })->[1] }
       while @{ $self->{reuse_q} } && $self->{reuse_q}[0][0] <= $NOW;
 
    while ($self->{outstanding} < $self->{max_outstanding}) {
 
       if (@{ $self->{reuse_q} } >= 30000) {
          # we ran out of ID's, wait a bit
          $self->{reuse_to} ||= AE::timer $self->{reuse_q}[0][0] - $NOW, 0, sub {
             delete $self->{reuse_to};
             $self->_scheduler;
          };
          last;
       }
 
       if (my $req = shift @{ $self->{queue} }) {
          # found a request in the queue, execute it
          while () {
             $req->[2] = int rand 65536;
             last unless exists $self->{id}{$req->[2]};
          }
 
          ++$self->{outstanding};
          $self->{id}{$req->[2]} = 1;
          substr $req->[0], 0, 2, pack "n", $req->[2];
 
          $self->_exec ($req);
 
       } elsif (my $cb = shift @{ $self->{wait} }) {
          # found a wait_for_slot callback
          $cb->($self);
 
       } else {
          # nothing to do, just exit
          last;
       }
    }
 }
 
 =item $resolver->request ($req, $cb->($res))
 
 This is the main low-level workhorse for sending DNS requests.
 
 This function sends a single request (a hash-ref formated as specified
 for C<dns_pack>) to the configured nameservers in turn until it gets a
 response. It handles timeouts, retries and automatically falls back to
 virtual circuit mode (TCP) when it receives a truncated reply. It does not
 handle anything else, such as the domain searchlist or relative names -
 use C<< ->resolve >> for that.
 
 Calls the callback with the decoded response packet if a reply was
 received, or no arguments in case none of the servers answered.
 
 =cut
 
 sub request($$) {
    my ($self, $req, $cb) = @_;
 
    # _enc_name barfs on names that are too long, which is often outside
    # program control, so check for too long names here.
    for (@{ $req->{qd} }) {
       return AE::postpone sub { $cb->(undef) }
          if 255 < length $_->[0];
    }
 
    push @{ $self->{queue} }, [dns_pack $req, $cb];
    $self->_scheduler;
 }
 
 =item $resolver->resolve ($qname, $qtype, %options, $cb->(@rr))
 
 Queries the DNS for the given domain name C<$qname> of type C<$qtype>.
 
 A C<$qtype> is either a numerical query type (e.g. C<1> for A records) or
 a lowercase name (you have to look at the source to see which aliases are
 supported, but all types from RFC 1035, C<aaaa>, C<srv>, C<spf> and a few
 more are known to this module). A C<$qtype> of "*" is supported and means
 "any" record type.
 
 The callback will be invoked with a list of matching result records or
 none on any error or if the name could not be found.
 
 CNAME chains (although illegal) are followed up to a length of 10.
 
 The callback will be invoked with arraryefs of the form C<[$name,
 $type, $class, $ttl, @data>], where C<$name> is the domain name,
 C<$type> a type string or number, C<$class> a class name, C<$ttl> is the
 remaining time-to-live and C<@data> is resource-record-dependent data, in
 seconds. For C<a> records, this will be the textual IPv4 addresses, for
 C<ns> or C<cname> records this will be a domain name, for C<txt> records
 these are all the strings and so on.
 
 All types mentioned in RFC 1035, C<aaaa>, C<srv>, C<naptr> and C<spf> are
 decoded. All resource records not known to this module will have the raw
 C<rdata> field as fifth array element.
 
 Note that this resolver is just a stub resolver: it requires a name server
 supporting recursive queries, will not do any recursive queries itself and
 is not secure when used against an untrusted name server.
 
 The following options are supported:
 
 =over 4
 
 =item search => [$suffix...]
 
 Use the given search list (which might be empty), by appending each one
 in turn to the C<$qname>. If this option is missing then the configured
 C<ndots> and C<search> values define its value (depending on C<ndots>, the
 empty suffix will be prepended or appended to that C<search> value). If
 the C<$qname> ends in a dot, then the searchlist will be ignored.
 
 =item accept => [$type...]
 
 Lists the acceptable result types: only result types in this set will be
 accepted and returned. The default includes the C<$qtype> and nothing
 else. If this list includes C<cname>, then CNAME-chains will not be
 followed (because you asked for the CNAME record).
 
 =item class => "class"
 
 Specify the query class ("in" for internet, "ch" for chaosnet and "hs" for
 hesiod are the only ones making sense). The default is "in", of course.
 
 =back
 
 Examples:
 
    # full example, you can paste this into perl:
    use Data::Dumper;
    use AnyEvent::DNS;
    AnyEvent::DNS::resolver->resolve (
       "google.com", "*", my $cv = AnyEvent->condvar);
    warn Dumper [$cv->recv];
 
    # shortened result:
    # [
    #   [ 'google.com', 'soa', 'in', 3600, 'ns1.google.com', 'dns-admin.google.com',
    #     2008052701, 7200, 1800, 1209600, 300 ],
    #   [
    #     'google.com', 'txt', 'in', 3600,
    #     'v=spf1 include:_netblocks.google.com ~all'
    #   ],
    #   [ 'google.com', 'a', 'in', 3600, '64.233.187.99' ],
    #   [ 'google.com', 'mx', 'in', 3600, 10, 'smtp2.google.com' ],
    #   [ 'google.com', 'ns', 'in', 3600, 'ns2.google.com' ],
    # ]
 
    # resolve a records:
    $res->resolve ("ruth.plan9.de", "a", sub { warn Dumper [@_] });
 
    # result:
    # [
    #   [ 'ruth.schmorp.de', 'a', 'in', 86400, '129.13.162.95' ]
    # ]
 
    # resolve any records, but return only a and aaaa records:
    $res->resolve ("test1.laendle", "*",
       accept => ["a", "aaaa"],
       sub {
          warn Dumper [@_];
       }
    );
 
    # result:
    # [
    #   [ 'test1.laendle', 'a', 'in', 86400, '10.0.0.255' ],
    #   [ 'test1.laendle', 'aaaa', 'in', 60, '3ffe:1900:4545:0002:0240:0000:0000:f7e1' ]
    # ]
 
 =cut
 
 sub resolve($%) {
    my $cb = pop;
    my ($self, $qname, $qtype, %opt) = @_;
 
    $self->wait_for_slot (sub {
       my $self = shift;
 
       my @search = $qname =~ s/\.$//
          ? ""
          : $opt{search}
            ? @{ $opt{search} }
            : ($qname =~ y/.//) >= $self->{ndots}
              ? ("", @{ $self->{search} })
              : (@{ $self->{search} }, "");
 
       my $class = $opt{class} || "in";
 
       my %atype = $opt{accept}
          ? map +($_ => 1), @{ $opt{accept} }
          : ($qtype => 1);
 
       # advance in searchlist
       my ($do_search, $do_req);
       
       $do_search = sub {
          @search
             or (undef $do_search), (undef $do_req), return $cb->();
 
          (my $name = lc "$qname." . shift @search) =~ s/\.$//;
          my $depth = 10;
 
          # advance in cname-chain
          $do_req = sub {
             $self->request ({
                rd => 1,
                qd => [[$name, $qtype, $class]],
             }, sub {
                my ($res) = @_
                   or return $do_search->();
 
                my $cname;
 
                while () {
                   # results found?
                   my @rr = grep $name eq lc $_->[0] && ($atype{"*"} || $atype{$_->[1]}), @{ $res->{an} };
 
                   (undef $do_search), (undef $do_req), return $cb->(@rr)
                      if @rr;
 
                   # see if there is a cname we can follow
                   my @rr = grep $name eq lc $_->[0] && $_->[1] eq "cname", @{ $res->{an} };
 
                   if (@rr) {
                      $depth--
                         or return $do_search->(); # cname chain too long
 
                      $cname = 1;
                      $name = lc $rr[0][4];
 
                   } elsif ($cname) {
                      # follow the cname
                      return $do_req->();
 
                   } else {
                      # no, not found anything
                      return $do_search->();
                   }
                 }
             });
          };
 
          $do_req->();
       };
 
       $do_search->();
    });
 }
 
 =item $resolver->wait_for_slot ($cb->($resolver))
 
 Wait until a free request slot is available and call the callback with the
 resolver object.
 
 A request slot is used each time a request is actually sent to the
 nameservers: There are never more than C<max_outstanding> of them.
 
 Although you can submit more requests (they will simply be queued until
 a request slot becomes available), sometimes, usually for rate-limiting
 purposes, it is useful to instead wait for a slot before generating the
 request (or simply to know when the request load is low enough so one can
 submit requests again).
 
 This is what this method does: The callback will be called when submitting
 a DNS request will not result in that request being queued. The callback
 may or may not generate any requests in response.
 
 Note that the callback will only be invoked when the request queue is
 empty, so this does not play well if somebody else keeps the request queue
 full at all times.
 
 =cut
 
 sub wait_for_slot {
    my ($self, $cb) = @_;
 
    push @{ $self->{wait} }, $cb;
    $self->_scheduler;
 }
 
 use AnyEvent::Socket (); # circular dependency, so do not import anything and do it at the end
 
 =back
 
 =head1 AUTHOR
 
    Marc Lehmann <schmorp@schmorp.de>
    http://anyevent.schmorp.de
 
 =cut
 
 1
### AnyEvent/Debug.pm ###
 =head1 NAME
 
 AnyEvent::Debug - debugging utilities for AnyEvent
 
 =head1 SYNOPSIS
 
    use AnyEvent::Debug;
 
    # create an interactive shell into the program
    my $shell = AnyEvent::Debug::shell "unix/", "/home/schmorp/myshell";
    # then on the shell: "socat readline /home/schmorp/myshell"
 
 =head1 DESCRIPTION
 
 This module provides functionality hopefully useful for debugging.
 
 At the moment, "only" an interactive shell is implemented. This shell
 allows you to interactively "telnet into" your program and execute Perl
 code, e.g. to look at global variables.
 
 =head1 FUNCTIONS
 
 =over 4
 
 =cut
 
 package AnyEvent::Debug;
 
 use B ();
 use Carp ();
 use Errno ();
 
 use AnyEvent (); BEGIN { AnyEvent::common_sense }
 use AnyEvent::Util ();
 use AnyEvent::Socket ();
 use AnyEvent::Log ();
 
 our $TRACE = 1; # trace status
 
 our ($TRACE_LOGGER, $TRACE_ENABLED);
 
 # cache often-used strings, purely to save memory, at the expense of speed
 our %STRCACHE;
 
 =item $shell = AnyEvent::Debug::shell $host, $service
 
 This function binds on the given host and service port and returns a
 shell object, which determines the lifetime of the shell. Any number
 of connections are accepted on the port, and they will give you a very
 primitive shell that simply executes every line you enter.
 
 All commands will be executed "blockingly" with the socket C<select>ed for
 output. For a less "blocking" interface see L<Coro::Debug>.
 
 The commands will be executed in the C<AnyEvent::Debug::shell> package,
 which currently has "help" and a few other commands, and can be freely
 modified by all shells. Code is evaluated under C<use strict 'subs'>.
 
 Every shell has a logging context (C<$LOGGER>) that is attached to
 C<$AnyEvent::Log::COLLECT>), which is especially useful to gether debug
 and trace messages.
 
 As a general programming guide, consider the beneficial aspects of
 using more global (C<our>) variables than local ones (C<my>) in package
 scope: Earlier all my modules tended to hide internal variables inside
 C<my> variables, so users couldn't accidentally access them. Having
 interactive access to your programs changed that: having internal
 variables still in the global scope means you can debug them easier.
 
 As no authentication is done, in most cases it is best not to use a TCP
 port, but a unix domain socket, whcih can be put wherever you can access
 it, but not others:
 
    our $SHELL = AnyEvent::Debug::shell "unix/", "/home/schmorp/shell";
 
 Then you can use a tool to connect to the shell, such as the ever
 versatile C<socat>, which in addition can give you readline support:
 
    socat readline /home/schmorp/shell
    # or:
    cd /home/schmorp; socat readline unix:shell
 
 Socat can even give you a persistent history:
 
    socat readline,history=.anyevent-history unix:shell
 
 Binding on C<127.0.0.1> (or C<::1>) might be a less secure but sitll not
 totally insecure (on single-user machines) alternative to let you use
 other tools, such as telnet:
 
    our $SHELL = AnyEvent::Debug::shell "127.1", "1357";
 
 And then:
 
    telnet localhost 1357
 
 =cut
 
 sub shell($$) {
    local $TRACE = 0;
 
    AnyEvent::Socket::tcp_server $_[0], $_[1], sub {
       my ($fh, $host, $port) = @_;
 
       syswrite $fh, "Welcome, $host:$port, use 'help' for more info!\015\012> ";
       my $rbuf;
 
       my $logger = new AnyEvent::Log::Ctx
          log_cb => sub {
             syswrite $fh, shift;
             0
          };
 
       my $logger_guard = AnyEvent::Util::guard {
          $AnyEvent::Log::COLLECT->detach ($logger);
       };
       $AnyEvent::Log::COLLECT->attach ($logger);
 
       local $TRACE = 0;
       my $rw; $rw = AE::io $fh, 0, sub {
          my $len = sysread $fh, $rbuf, 1024, length $rbuf;
 
          $logger_guard if 0; # reference it
 
          if (defined $len ? $len == 0 : ($! != Errno::EAGAIN && $! != Errno::EWOULDBLOCK)) {
             undef $rw;
          } else {
             while ($rbuf =~ s/^(.*)\015?\012//) {
                my $line = $1;
 
                AnyEvent::fh_block $fh;
 
                if ($line =~ /^\s*exit\b/) {
                   syswrite $fh, "sorry, no... if you want to execute exit, try CORE::exit.\015\012";
                } elsif ($line =~ /^\s*coro\b\s*(.*)/) {
                   my $arg = $1;
                   if (eval { require Coro; require Coro::Debug }) {
                      if ($arg =~ /\S/) {
                         Coro::async (sub {
                            select $fh;
                            Coro::Debug::command ($arg);
                            local $| = 1; # older Coro versions do not flush
                            syswrite $fh, "> ";
                         });
                         return;
                      } else {
                         undef $rw;
                         syswrite $fh, "switching to Coro::Debug...\015\012";
                         Coro::async (sub { Coro::Debug::session ($fh) });
                         return;
                      }
                   } else {
                      syswrite $fh, "Coro not available.\015\012";
                   }
 
                } else {
                   package AnyEvent::Debug::shell;
 
                   no strict 'vars';
                   local $LOGGER = $logger;
                   my $old_stdout = select $fh;
                   local $| = 1;
 
                   my @res = eval $line;
 
                   select $old_stdout;
                   syswrite $fh, "$@" if $@;
                   syswrite $fh, "\015\012";
 
                   if (@res > 1) {
                      syswrite $fh, "$_: $res[$_]\015\012" for 0 .. $#res;
                   } elsif (@res == 1) {
                      syswrite $fh, "$res[0]\015\012";
                   }
                }
 
                syswrite $fh, "> ";
                AnyEvent::fh_unblock $fh;
             }
          }
       };
    }
 }
 
 {
    package AnyEvent::Debug::shell;
 
    our $LOGGER;
 
    sub help() {
       <<EOF
 help         this command
 wr [level]   sets wrap level to level (or toggles if missing)
 v [level]    sets verbosity (or toggles between 0 and 9 if missing)
 wl 'regex'   print wrapped watchers matching the regex (or all if missing)
 i id,...     prints the watcher with the given ids in more detail
 t            enable tracing for newly created watchers (enabled by default)
 ut           disable tracing for newly created watchers
 t  id,...    enable tracing for the given watcher (enabled by default)
 ut id,...    disable tracing for the given watcher
 w id,...     converts the watcher ids to watcher objects (for scripting)
 coro xxx     run xxx as Coro::Debug shell command, if available
 coro         switch to Coro::Debug shell, if available
 EOF
    }
 
    sub wl(;$) {
       my $re = @_ ? qr<$_[0]>i : qr<.>;
 
       my %res;
 
       while (my ($k, $v) = each %AnyEvent::Debug::Wrapped) {
          my $s = "$v";
          $res{$s} = $k . (exists $v->{error} ? "*" : " ")
             if $s =~ $re;
       }
 
       join "", map "$res{$_} $_\n", sort keys %res
    }
 
    sub w {
       map {
          $AnyEvent::Debug::Wrapped{$_} || do {
             print "$_: no such wrapped watcher.\n";
             ()
          }
       } @_
    }
 
    sub i {
       join "",
          map $_->id . " $_\n" . $_->verbose . "\n",
             &w
    }
 
    sub wr {
       AnyEvent::Debug::wrap (@_);
 
       "wrap level now $AnyEvent::Debug::WRAP_LEVEL"
    }
 
    sub t {
       if (@_) {
          @_ = &w;
          $_->trace (1)
             for @_;
          "tracing enabled for @_."
       } else {
          $AnyEvent::Debug::TRACE = 1;
          "tracing for newly created watchers is now enabled."
       }
    }
 
    sub u {
       if (@_) {
          @_ = &w;
          $_->trace (0)
             for @_;
          "tracing disabled for @_."
       } else {
          $AnyEvent::Debug::TRACE = 0;
          "tracing for newly created watchers is now disabled."
       }
    }
 
    sub v {
       $LOGGER->level (@_ ? $_[0] : $LOGGER->[1] ? 0 : 9);
 
       "verbose logging is now " . ($LOGGER->[1] ? "enabled" : "disabled") . "."
    }
 }
 
 =item AnyEvent::Debug::wrap [$level]
 
 Sets the instrumenting/wrapping level of all watchers that are being
 created after this call. If no C<$level> has been specified, then it
 toggles between C<0> and C<1>.
 
 The default wrap level is C<0>, or whatever
 C<$ENV{PERL_ANYEVENT_DEBUG_WRAP}> specifies.
 
 A level of C<0> disables wrapping, i.e. AnyEvent works normally, and in
 its most efficient mode.
 
 A level of C<1> or higher enables wrapping, which replaces all watchers
 by AnyEvent::Debug::Wrapped objects, stores the location where a
 watcher was created and wraps the callback to log all invocations at
 "trace" loglevel if tracing is enabled fore the watcher. The initial
 state of tracing when creating a watcher is taken from the global
 variable C<$AnyEvent:Debug::TRACE>. The default value of that variable
 is C<1>, but it can make sense to set it to C<0> and then do C<< local
 $AnyEvent::Debug::TRACE = 1 >> in a block where you create "interesting"
 watchers. Tracing can also be enabled and disabled later by calling the
 watcher's C<trace> method.
 
 The wrapper will also count how many times the callback was invoked and
 will record up to ten runtime errors with corresponding backtraces. It
 will also log runtime errors at "error" loglevel.
 
 To see the trace messages, you can invoke your program with
 C<PERL_ANYEVENT_VERBOSE=9>, or you can use AnyEvent::Log to divert
 the trace messages in any way you like (the EXAMPLES section in
 L<AnyEvent::Log> has some examples).
 
 A level of C<2> does everything that level C<1> does, but also stores a
 full backtrace of the location the watcher was created, which slows down
 watcher creation considerably.
 
 Every wrapped watcher will be linked into C<%AnyEvent::Debug::Wrapped>,
 with its address as key. The C<wl> command in the debug shell can be used
 to list watchers.
 
 Instrumenting can increase the size of each watcher multiple times, and,
 especially when backtraces are involved, also slows down watcher creation
 a lot.
 
 Also, enabling and disabling instrumentation will not recover the full
 performance that you had before wrapping (the AE::xxx functions will stay
 slower, for example).
 
 If you are developing your program, also consider using AnyEvent::Strict
 to check for common mistakes.
 
 =cut
 
 our $WRAP_LEVEL;
 our $TRACE_CUR;
 our $POST_DETECT;
 
 sub wrap(;$) {
    my $PREV_LEVEL = $WRAP_LEVEL;
    $WRAP_LEVEL = @_ ? 0+shift : $WRAP_LEVEL ? 0 : 1;
 
    if ($AnyEvent::MODEL) {
       if ($WRAP_LEVEL && !$PREV_LEVEL) {
          $TRACE_LOGGER = AnyEvent::Log::logger trace => \$TRACE_ENABLED;
          AnyEvent::_isa_hook 0 => "AnyEvent::Debug::Wrap", 1;
          AnyEvent::Debug::Wrap::_reset ();
       } elsif (!$WRAP_LEVEL && $PREV_LEVEL) {
          AnyEvent::_isa_hook 0 => undef;
       }
    } else {
       $POST_DETECT ||= AnyEvent::post_detect {
          undef $POST_DETECT;
          return unless $WRAP_LEVEL;
 
          (my $level, $WRAP_LEVEL) = ($WRAP_LEVEL, undef);
 
          require AnyEvent::Strict unless $AnyEvent::Strict::VERSION;
 
          AnyEvent::post_detect { # make sure we run after AnyEvent::Strict
             wrap ($level);
          };
       };
    }
 }
 
 =item AnyEvent::Debug::path2mod $path
 
 Tries to replace a path (e.g. the file name returned by caller)
 by a module name. Returns the path unchanged if it fails.
 
 Example:
 
    print AnyEvent::Debug::path2mod "/usr/lib/perl5/AnyEvent/Debug.pm";
    # might print "AnyEvent::Debug"
 
 =cut
 
 sub path2mod($) {
    keys %INC; # reset iterator
 
    while (my ($k, $v) = each %INC) {
       if ($_[0] eq $v) {
          $k =~ s%/%::%g if $k =~ s/\.pm$//;
          return $k;
       }
    }
 
    my $path = shift;
 
    $path =~ s%^\./%%;
 
    $path
 }
 
 =item AnyEvent::Debug::cb2str $cb
 
 Using various gambits, tries to convert a callback (e.g. a code reference)
 into a more useful string.
 
 Very useful if you debug a program and have some callback, but you want to
 know where in the program the callback is actually defined.
 
 =cut
 
 sub cb2str($) {
    my $cb = shift;
 
    "CODE" eq ref $cb
       or return "$cb";
 
    eval {
       my $cv = B::svref_2object ($cb);
 
       my $gv = $cv->GV
          or return "$cb";
 
       my $name = $gv->NAME;
 
       return (AnyEvent::Debug::path2mod $gv->FILE) . ":" . $gv->LINE
          if $name eq "__ANON__";
 
       $gv->STASH->NAME . "::" . $name;
    } || "$cb"
 }
 
 sub sv2str($) {
    if (ref $_[0]) {
       if (ref $_[0] eq "CODE") {
          return "$_[0]=" . cb2str $_[0];
       } else {
          return "$_[0]";
       }
    } else {
       for ("\'$_[0]\'") { # make copy
          substr $_, $Carp::MaxArgLen, length, "'..."
             if length > $Carp::MaxArgLen;
          return $_;
       }
    }
 }
 
 =item AnyEvent::Debug::backtrace [$skip]
 
 Creates a backtrace (actually an AnyEvent::Debug::Backtrace object
 that you can stringify), not unlike the Carp module would. Unlike the
 Carp module it resolves some references (such as callbacks) to more
 user-friendly strings, has a more succinct output format and most
 importantly: doesn't leak memory like hell.
 
 The reason it creates an object is to save time, as formatting can be
 done at a later time. Still, creating a backtrace is a relatively slow
 operation.
 
 =cut
 
 sub backtrace(;$) {
    my $w = shift;
 
    my (@bt, @c);
    my ($modlen, $sub);
 
    for (;;) {
       #         0          1      2            3         4           5          6            7       8         9         10
       # ($package, $filename, $line, $subroutine, $hasargs, $wantarray, $evaltext, $is_require, $hints, $bitmask, $hinthash)
       package DB;
       @c = caller $w++
          or last;
       package AnyEvent::Debug; # no block for speed reasons
 
       if ($c[7]) {
          $sub = "require $c[6]";
       } elsif (defined $c[6]) {
          $sub = "eval \"\"";
       } else {
          $sub = ($c[4] ? "" : "&") . $c[3];
 
          $sub .= "("
                  . (join ",",
                        map sv2str $DB::args[$_],
                           0 .. (@DB::args < $Carp::MaxArgNums ? @DB::args : $Carp::MaxArgNums) - 1)
                  . ")"
             if $c[4];
       }
 
       push @bt, [\($STRCACHE{$c[1]} ||= $c[1]), $c[2], $sub];
    }
 
    @DB::args = ();
 
    bless \@bt, "AnyEvent::Debug::Backtrace"
 }
 
 =back
 
 =cut
 
 package AnyEvent::Debug::Wrap;
 
 use AnyEvent (); BEGIN { AnyEvent::common_sense }
 use Scalar::Util ();
 use Carp ();
 
 sub _reset {
    for my $name (qw(io timer signal child idle)) {
       my $super = "SUPER::$name";
 
       *$name = sub {
          my ($self, %arg) = @_;
 
          my $w;
 
          my $t = $TRACE;
 
          my ($pkg, $file, $line, $sub);
          
          $w = 0;
          do {
             ($pkg, $file, $line) = caller $w++;
          } while $pkg =~ /^(?:AE|AnyEvent::(?:Socket|Handle|Util|Debug|Strict|Base|CondVar|CondVar::Base|Impl::.*)|Coro::AnyEvent::CondVar)$/;
 
          $sub = (caller $w)[3];
 
          my $cb = $arg{cb};
          $arg{cb} = sub {
             ++$w->{called};
 
             local $TRACE_CUR = $w;
 
             $TRACE_LOGGER->("enter $w") if $TRACE_ENABLED && $t;
             eval {
                local $SIG{__DIE__} = sub {
                   die $_[0] . AnyEvent::Debug::backtrace
                      if defined $^S;
                };
                &$cb;
             };
             if ($@) {
                my $err = "$@";
                push @{ $w->{error} }, [AE::now, $err]
                   if @{ $w->{error} } < 10;
                AE::log die => "($w) $err"
                   or warn "($w) $err";
             }
             $TRACE_LOGGER->("leave $w") if $TRACE_ENABLED && $t;
          };
 
          $self = bless {
             type   => $name,
             w      => $self->$super (%arg),
             rfile  => \($STRCACHE{$file} ||= $file),
             line   => $line,
             sub    => $sub,
             cur    => "$TRACE_CUR",
             now    => AE::now,
             arg    => \%arg,
             cb     => $cb,
             called => 0,
             rt     => \$t,
          }, "AnyEvent::Debug::Wrapped";
 
          delete $arg{cb};
 
          $self->{bt} = AnyEvent::Debug::backtrace 1
             if $WRAP_LEVEL >= 2;
 
          Scalar::Util::weaken ($w = $self);
          Scalar::Util::weaken ($AnyEvent::Debug::Wrapped{Scalar::Util::refaddr $self} = $self);
 
          $TRACE_LOGGER->("creat $w") if $TRACE_ENABLED && $t;
 
          $self
       };
    }
 }
 
 package AnyEvent::Debug::Wrapped;
 
 =head1 THE AnyEvent::Debug::Wrapped CLASS
 
 All watchers created while the wrap level is non-zero will be wrapped
 inside an AnyEvent::Debug::Wrapped object. The address of the
 wrapped watcher will become its ID - every watcher will be stored in
 C<$AnyEvent::Debug::Wrapped{$id}>.
 
 These wrapper objects can be stringified and have some methods defined on
 them.
 
 For debugging, of course, it can be helpful to look into these objects,
 which is why this is documented here, but this might change at any time in
 future versions.
 
 Each object is a relatively standard hash with the following members:
 
    type   => name of the method used ot create the watcher (e.g. C<io>, C<timer>).
    w      => the actual watcher
    rfile  => reference to the filename of the file the watcher was created in
    line   => line number where it was created
    sub    => function name (or a special string) which created the watcher
    cur    => if created inside another watcher callback, this is the string rep of the other watcher
    now    => the timestamp (AE::now) when the watcher was created
    arg    => the arguments used to create the watcher (sans C<cb>)
    cb     => the original callback used to create the watcher
    called => the number of times the callback was called
 
 Each object supports the following mehtods (warning: these are only
 available on wrapped watchers, so are best for interactive use via the
 debug shell).
 
 =over 4
 
 =cut
 
 use AnyEvent (); BEGIN { AnyEvent::common_sense }
 
 use overload
    '""'     => sub {
       $_[0]{str} ||= do {
          my ($pkg, $line) = @{ $_[0]{caller} };
 
          my $mod = AnyEvent::Debug::path2mod ${ $_[0]{rfile} };
          my $sub = $_[0]{sub};
 
          if (defined $sub) {
             $sub =~ s/^\Q$mod\E:://;
             $sub = "($sub)";
          }
 
          "$mod:$_[0]{line}$sub>$_[0]{type}>"
          . (AnyEvent::Debug::cb2str $_[0]{cb})
       };
    },
    fallback => 1,
 ;
 
 =item $w->id
 
 Returns the numerical id of the watcher, as used in the debug shell.
 
 =cut
 
 sub id {
    Scalar::Util::refaddr shift
 }
 
 =item $w->verbose
 
 Returns a multiline textual description of the watcher, including the
 first ten exceptions caught while executing the callback.
 
 =cut
 
 sub verbose {
    my ($self) = @_;
 
    my $res = "type:    $self->{type} watcher\n"
            . "args:    " . (join " ", %{ $self->{arg} }) . "\n" # TODO: decode fh?
            . "created: " . (AnyEvent::Log::format_time $self->{now}) . " ($self->{now})\n"
            . "file:    ${ $self->{rfile} }\n"
            . "line:    $self->{line}\n"
            . "subname: $self->{sub}\n"
            . "context: $self->{cur}\n"
            . "tracing: " . (${ $self->{rt} } ? "enabled" : "disabled") . "\n"
            . "cb:      $self->{cb} (" . (AnyEvent::Debug::cb2str $self->{cb}) . ")\n"
            . "invoked: $self->{called} times\n";
 
    if (exists $self->{bt}) {
       $res .= "created\n$self->{bt}";
    }
 
    if (exists $self->{error}) {
       $res .= "errors:   " . @{$self->{error}} . "\n";
 
       $res .= "error: " . (AnyEvent::Log::format_time $_->[0]) . " ($_->[0]) $_->[1]\n"
          for @{$self->{error}};
    }
 
    $res
 }
 
 =item $w->trace ($on)
 
 Enables (C<$on> is true) or disables (C<$on> is false) tracing on this
 watcher.
 
 To get tracing messages, both the global logging settings must have trace
 messages enabled for the context C<AnyEvent::Debug> and tracing must be
 enabled for the wrapped watcher.
 
 To enable trace messages globally, the simplest way is to start the
 program with C<PERL_ANYEVENT_VERBOSE=9> in the environment.
 
 Tracing for each individual watcher is enabled by default (unless
 C<$AnyEvent::Debug::TRACE> has been set to false).
 
 =cut
 
 sub trace {
    ${ $_[0]{rt} } = $_[1];
 }
 
 sub DESTROY {
    $TRACE_LOGGER->("dstry $_[0]") if $TRACE_ENABLED && ${ $_[0]{rt} };
 
    delete $AnyEvent::Debug::Wrapped{Scalar::Util::refaddr $_[0]};
 }
 
 =back
 
 =cut
 
 package AnyEvent::Debug::Backtrace;
 
 use AnyEvent (); BEGIN { AnyEvent::common_sense }
 
 sub as_string {
    my ($self) = @_;
 
    my @bt;
    my $modlen;
 
    for (@$self) {
       my ($rpath, $line, $sub) = @$_;
 
       $rpath = (AnyEvent::Debug::path2mod $$rpath) . " line $line";
       $modlen = length $rpath if $modlen < length $rpath;
 
       $sub =~ s/\r/\\r/g;
       $sub =~ s/\n/\\n/g;
       $sub =~ s/([\x00-\x1f\x7e-\xff])/sprintf "\\x%02x", ord $1/ge;
       $sub =~ s/([^\x20-\x7e])/sprintf "\\x{%x}", ord $1/ge;
 
       push @bt, [$rpath, $sub];
    }
 
    join "",
       map { sprintf "%*s %s\n", -$modlen, $_->[0], $_->[1] }
          @bt
 }
 
 use overload
    '""'     => \&as_string,
    fallback => 1,
 ;
 
 =head1 AUTHOR
 
  Marc Lehmann <schmorp@schmorp.de>
  http://anyevent.schmorp.de
 
 =cut
 
 1
 
### AnyEvent/Handle.pm ###
 =head1 NAME
 
 AnyEvent::Handle - non-blocking I/O on streaming handles via AnyEvent
 
 =head1 SYNOPSIS
 
    use AnyEvent;
    use AnyEvent::Handle;
 
    my $cv = AnyEvent->condvar;
 
    my $hdl; $hdl = new AnyEvent::Handle
       fh => \*STDIN,
       on_error => sub {
          my ($hdl, $fatal, $msg) = @_;
          AE::log error => $msg;
          $hdl->destroy;
          $cv->send;
       };
 
    # send some request line
    $hdl->push_write ("getinfo\015\012");
 
    # read the response line
    $hdl->push_read (line => sub {
       my ($hdl, $line) = @_;
       say "got line <$line>";
       $cv->send;
    });
 
    $cv->recv;
 
 =head1 DESCRIPTION
 
 This is a helper module to make it easier to do event-based I/O
 on stream-based filehandles (sockets, pipes, and other stream
 things). Specifically, it doesn't work as expected on files, packet-based
 sockets or similar things.
 
 The L<AnyEvent::Intro> tutorial contains some well-documented
 AnyEvent::Handle examples.
 
 In the following, where the documentation refers to "bytes", it means
 characters. As sysread and syswrite are used for all I/O, their
 treatment of characters applies to this module as well.
 
 At the very minimum, you should specify C<fh> or C<connect>, and the
 C<on_error> callback.
 
 All callbacks will be invoked with the handle object as their first
 argument.
 
 =cut
 
 package AnyEvent::Handle;
 
 use Scalar::Util ();
 use List::Util ();
 use Carp ();
 use Errno qw(EAGAIN EWOULDBLOCK EINTR);
 
 use AnyEvent (); BEGIN { AnyEvent::common_sense }
 use AnyEvent::Util qw(WSAEWOULDBLOCK);
 
 our $VERSION = $AnyEvent::VERSION;
 
 sub _load_func($) {
    my $func = $_[0];
 
    unless (defined &$func) {
       my $pkg = $func;
       do {
          $pkg =~ s/::[^:]+$//
             or return;
          eval "require $pkg";
       } until defined &$func;
    }
 
    \&$func
 }
 
 sub MAX_READ_SIZE() { 131072 }
 
 =head1 METHODS
 
 =over 4
 
 =item $handle = B<new> AnyEvent::Handle fh => $filehandle, key => value...
 
 The constructor supports these arguments (all as C<< key => value >> pairs).
 
 =over 4
 
 =item fh => $filehandle     [C<fh> or C<connect> MANDATORY]
 
 The filehandle this L<AnyEvent::Handle> object will operate on.
 NOTE: The filehandle will be set to non-blocking mode (using
 C<AnyEvent::fh_unblock>) by the constructor and needs to stay in
 that mode.
 
 =item connect => [$host, $service]      [C<fh> or C<connect> MANDATORY]
 
 Try to connect to the specified host and service (port), using
 C<AnyEvent::Socket::tcp_connect>. The C<$host> additionally becomes the
 default C<peername>.
 
 You have to specify either this parameter, or C<fh>, above.
 
 It is possible to push requests on the read and write queues, and modify
 properties of the stream, even while AnyEvent::Handle is connecting.
 
 When this parameter is specified, then the C<on_prepare>,
 C<on_connect_error> and C<on_connect> callbacks will be called under the
 appropriate circumstances:
 
 =over 4
 
 =item on_prepare => $cb->($handle)
 
 This (rarely used) callback is called before a new connection is
 attempted, but after the file handle has been created (you can access that
 file handle via C<< $handle->{fh} >>). It could be used to prepare the
 file handle with parameters required for the actual connect (as opposed to
 settings that can be changed when the connection is already established).
 
 The return value of this callback should be the connect timeout value in
 seconds (or C<0>, or C<undef>, or the empty list, to indicate that the
 default timeout is to be used).
 
 =item on_connect => $cb->($handle, $host, $port, $retry->())
 
 This callback is called when a connection has been successfully established.
 
 The peer's numeric host and port (the socket peername) are passed as
 parameters, together with a retry callback. At the time it is called the
 read and write queues, EOF status, TLS status and similar properties of
 the handle will have been reset.
 
 If, for some reason, the handle is not acceptable, calling C<$retry> will
 continue with the next connection target (in case of multi-homed hosts or
 SRV records there can be multiple connection endpoints). The C<$retry>
 callback can be invoked after the connect callback returns, i.e. one can
 start a handshake and then decide to retry with the next host if the
 handshake fails.
 
 In most cases, you should ignore the C<$retry> parameter.
 
 =item on_connect_error => $cb->($handle, $message)
 
 This callback is called when the connection could not be
 established. C<$!> will contain the relevant error code, and C<$message> a
 message describing it (usually the same as C<"$!">).
 
 If this callback isn't specified, then C<on_error> will be called with a
 fatal error instead.
 
 =back
 
 =item on_error => $cb->($handle, $fatal, $message)
 
 This is the error callback, which is called when, well, some error
 occured, such as not being able to resolve the hostname, failure to
 connect, or a read error.
 
 Some errors are fatal (which is indicated by C<$fatal> being true). On
 fatal errors the handle object will be destroyed (by a call to C<< ->
 destroy >>) after invoking the error callback (which means you are free to
 examine the handle object). Examples of fatal errors are an EOF condition
 with active (but unsatisfiable) read watchers (C<EPIPE>) or I/O errors. In
 cases where the other side can close the connection at will, it is
 often easiest to not report C<EPIPE> errors in this callback.
 
 AnyEvent::Handle tries to find an appropriate error code for you to check
 against, but in some cases (TLS errors), this does not work well.
 
 If you report the error to the user, it is recommended to always output
 the C<$message> argument in human-readable error messages (you don't need
 to report C<"$!"> if you report C<$message>).
 
 If you want to react programmatically to the error, then looking at C<$!>
 and comparing it against some of the documented C<Errno> values is usually
 better than looking at the C<$message>.
 
 Non-fatal errors can be retried by returning, but it is recommended
 to simply ignore this parameter and instead abondon the handle object
 when this callback is invoked. Examples of non-fatal errors are timeouts
 C<ETIMEDOUT>) or badly-formatted data (C<EBADMSG>).
 
 On entry to the callback, the value of C<$!> contains the operating
 system error code (or C<ENOSPC>, C<EPIPE>, C<ETIMEDOUT>, C<EBADMSG> or
 C<EPROTO>).
 
 While not mandatory, it is I<highly> recommended to set this callback, as
 you will not be notified of errors otherwise. The default just calls
 C<croak>.
 
 =item on_read => $cb->($handle)
 
 This sets the default read callback, which is called when data arrives
 and no read request is in the queue (unlike read queue callbacks, this
 callback will only be called when at least one octet of data is in the
 read buffer).
 
 To access (and remove data from) the read buffer, use the C<< ->rbuf >>
 method or access the C<< $handle->{rbuf} >> member directly. Note that you
 must not enlarge or modify the read buffer, you can only remove data at
 the beginning from it.
 
 You can also call C<< ->push_read (...) >> or any other function that
 modifies the read queue. Or do both. Or ...
 
 When an EOF condition is detected, AnyEvent::Handle will first try to
 feed all the remaining data to the queued callbacks and C<on_read> before
 calling the C<on_eof> callback. If no progress can be made, then a fatal
 error will be raised (with C<$!> set to C<EPIPE>).
 
 Note that, unlike requests in the read queue, an C<on_read> callback
 doesn't mean you I<require> some data: if there is an EOF and there
 are outstanding read requests then an error will be flagged. With an
 C<on_read> callback, the C<on_eof> callback will be invoked.
 
 =item on_eof => $cb->($handle)
 
 Set the callback to be called when an end-of-file condition is detected,
 i.e. in the case of a socket, when the other side has closed the
 connection cleanly, and there are no outstanding read requests in the
 queue (if there are read requests, then an EOF counts as an unexpected
 connection close and will be flagged as an error).
 
 For sockets, this just means that the other side has stopped sending data,
 you can still try to write data, and, in fact, one can return from the EOF
 callback and continue writing data, as only the read part has been shut
 down.
 
 If an EOF condition has been detected but no C<on_eof> callback has been
 set, then a fatal error will be raised with C<$!> set to <0>.
 
 =item on_drain => $cb->($handle)
 
 This sets the callback that is called once when the write buffer becomes
 empty (and immediately when the handle object is created).
 
 To append to the write buffer, use the C<< ->push_write >> method.
 
 This callback is useful when you don't want to put all of your write data
 into the queue at once, for example, when you want to write the contents
 of some file to the socket you might not want to read the whole file into
 memory and push it into the queue, but instead only read more data from
 the file when the write queue becomes empty.
 
 =item timeout => $fractional_seconds
 
 =item rtimeout => $fractional_seconds
 
 =item wtimeout => $fractional_seconds
 
 If non-zero, then these enables an "inactivity" timeout: whenever this
 many seconds pass without a successful read or write on the underlying
 file handle (or a call to C<timeout_reset>), the C<on_timeout> callback
 will be invoked (and if that one is missing, a non-fatal C<ETIMEDOUT>
 error will be raised).
 
 There are three variants of the timeouts that work independently of each
 other, for both read and write (triggered when nothing was read I<OR>
 written), just read (triggered when nothing was read), and just write:
 C<timeout>, C<rtimeout> and C<wtimeout>, with corresponding callbacks
 C<on_timeout>, C<on_rtimeout> and C<on_wtimeout>, and reset functions
 C<timeout_reset>, C<rtimeout_reset>, and C<wtimeout_reset>.
 
 Note that timeout processing is active even when you do not have any
 outstanding read or write requests: If you plan to keep the connection
 idle then you should disable the timeout temporarily or ignore the
 timeout in the corresponding C<on_timeout> callback, in which case
 AnyEvent::Handle will simply restart the timeout.
 
 Zero (the default) disables the corresponding timeout.
 
 =item on_timeout => $cb->($handle)
 
 =item on_rtimeout => $cb->($handle)
 
 =item on_wtimeout => $cb->($handle)
 
 Called whenever the inactivity timeout passes. If you return from this
 callback, then the timeout will be reset as if some activity had happened,
 so this condition is not fatal in any way.
 
 =item rbuf_max => <bytes>
 
 If defined, then a fatal error will be raised (with C<$!> set to C<ENOSPC>)
 when the read buffer ever (strictly) exceeds this size. This is useful to
 avoid some forms of denial-of-service attacks.
 
 For example, a server accepting connections from untrusted sources should
 be configured to accept only so-and-so much data that it cannot act on
 (for example, when expecting a line, an attacker could send an unlimited
 amount of data without a callback ever being called as long as the line
 isn't finished).
 
 =item wbuf_max => <bytes>
 
 If defined, then a fatal error will be raised (with C<$!> set to C<ENOSPC>)
 when the write buffer ever (strictly) exceeds this size. This is useful to
 avoid some forms of denial-of-service attacks.
 
 Although the units of this parameter is bytes, this is the I<raw> number
 of bytes not yet accepted by the kernel. This can make a difference when
 you e.g. use TLS, as TLS typically makes your write data larger (but it
 can also make it smaller due to compression).
 
 As an example of when this limit is useful, take a chat server that sends
 chat messages to a client. If the client does not read those in a timely
 manner then the send buffer in the server would grow unbounded.
 
 =item autocork => <boolean>
 
 When disabled (the default), C<push_write> will try to immediately
 write the data to the handle if possible. This avoids having to register
 a write watcher and wait for the next event loop iteration, but can
 be inefficient if you write multiple small chunks (on the wire, this
 disadvantage is usually avoided by your kernel's nagle algorithm, see
 C<no_delay>, but this option can save costly syscalls).
 
 When enabled, writes will always be queued till the next event loop
 iteration. This is efficient when you do many small writes per iteration,
 but less efficient when you do a single write only per iteration (or when
 the write buffer often is full). It also increases write latency.
 
 =item no_delay => <boolean>
 
 When doing small writes on sockets, your operating system kernel might
 wait a bit for more data before actually sending it out. This is called
 the Nagle algorithm, and usually it is beneficial.
 
 In some situations you want as low a delay as possible, which can be
 accomplishd by setting this option to a true value.
 
 The default is your operating system's default behaviour (most likely
 enabled). This option explicitly enables or disables it, if possible.
 
 =item keepalive => <boolean>
 
 Enables (default disable) the SO_KEEPALIVE option on the stream socket:
 normally, TCP connections have no time-out once established, so TCP
 connections, once established, can stay alive forever even when the other
 side has long gone. TCP keepalives are a cheap way to take down long-lived
 TCP connections when the other side becomes unreachable. While the default
 is OS-dependent, TCP keepalives usually kick in after around two hours,
 and, if the other side doesn't reply, take down the TCP connection some 10
 to 15 minutes later.
 
 It is harmless to specify this option for file handles that do not support
 keepalives, and enabling it on connections that are potentially long-lived
 is usually a good idea.
 
 =item oobinline => <boolean>
 
 BSD majorly fucked up the implementation of TCP urgent data. The result
 is that almost no OS implements TCP according to the specs, and every OS
 implements it slightly differently.
 
 If you want to handle TCP urgent data, then setting this flag (the default
 is enabled) gives you the most portable way of getting urgent data, by
 putting it into the stream.
 
 Since BSD emulation of OOB data on top of TCP's urgent data can have
 security implications, AnyEvent::Handle sets this flag automatically
 unless explicitly specified. Note that setting this flag after
 establishing a connection I<may> be a bit too late (data loss could
 already have occured on BSD systems), but at least it will protect you
 from most attacks.
 
 =item read_size => <bytes>
 
 The initial read block size, the number of bytes this module will try
 to read during each loop iteration. Each handle object will consume
 at least this amount of memory for the read buffer as well, so when
 handling many connections watch out for memory requirements). See also
 C<max_read_size>. Default: C<2048>.
 
 =item max_read_size => <bytes>
 
 The maximum read buffer size used by the dynamic adjustment
 algorithm: Each time AnyEvent::Handle can read C<read_size> bytes in
 one go it will double C<read_size> up to the maximum given by this
 option. Default: C<131072> or C<read_size>, whichever is higher.
 
 =item low_water_mark => <bytes>
 
 Sets the number of bytes (default: C<0>) that make up an "empty" write
 buffer: If the buffer reaches this size or gets even samller it is
 considered empty.
 
 Sometimes it can be beneficial (for performance reasons) to add data to
 the write buffer before it is fully drained, but this is a rare case, as
 the operating system kernel usually buffers data as well, so the default
 is good in almost all cases.
 
 =item linger => <seconds>
 
 If this is non-zero (default: C<3600>), the destructor of the
 AnyEvent::Handle object will check whether there is still outstanding
 write data and will install a watcher that will write this data to the
 socket. No errors will be reported (this mostly matches how the operating
 system treats outstanding data at socket close time).
 
 This will not work for partial TLS data that could not be encoded
 yet. This data will be lost. Calling the C<stoptls> method in time might
 help.
 
 =item peername => $string
 
 A string used to identify the remote site - usually the DNS hostname
 (I<not> IDN!) used to create the connection, rarely the IP address.
 
 Apart from being useful in error messages, this string is also used in TLS
 peername verification (see C<verify_peername> in L<AnyEvent::TLS>). This
 verification will be skipped when C<peername> is not specified or is
 C<undef>.
 
 =item tls => "accept" | "connect" | Net::SSLeay::SSL object
 
 When this parameter is given, it enables TLS (SSL) mode, that means
 AnyEvent will start a TLS handshake as soon as the connection has been
 established and will transparently encrypt/decrypt data afterwards.
 
 All TLS protocol errors will be signalled as C<EPROTO>, with an
 appropriate error message.
 
 TLS mode requires Net::SSLeay to be installed (it will be loaded
 automatically when you try to create a TLS handle): this module doesn't
 have a dependency on that module, so if your module requires it, you have
 to add the dependency yourself. If Net::SSLeay cannot be loaded or is too
 old, you get an C<EPROTO> error.
 
 Unlike TCP, TLS has a server and client side: for the TLS server side, use
 C<accept>, and for the TLS client side of a connection, use C<connect>
 mode.
 
 You can also provide your own TLS connection object, but you have
 to make sure that you call either C<Net::SSLeay::set_connect_state>
 or C<Net::SSLeay::set_accept_state> on it before you pass it to
 AnyEvent::Handle. Also, this module will take ownership of this connection
 object.
 
 At some future point, AnyEvent::Handle might switch to another TLS
 implementation, then the option to use your own session object will go
 away.
 
 B<IMPORTANT:> since Net::SSLeay "objects" are really only integers,
 passing in the wrong integer will lead to certain crash. This most often
 happens when one uses a stylish C<< tls => 1 >> and is surprised about the
 segmentation fault.
 
 Use the C<< ->starttls >> method if you need to start TLS negotiation later.
 
 =item tls_ctx => $anyevent_tls
 
 Use the given C<AnyEvent::TLS> object to create the new TLS connection
 (unless a connection object was specified directly). If this
 parameter is missing (or C<undef>), then AnyEvent::Handle will use
 C<AnyEvent::Handle::TLS_CTX>.
 
 Instead of an object, you can also specify a hash reference with C<< key
 => value >> pairs. Those will be passed to L<AnyEvent::TLS> to create a
 new TLS context object.
 
 =item on_starttls => $cb->($handle, $success[, $error_message])
 
 This callback will be invoked when the TLS/SSL handshake has finished. If
 C<$success> is true, then the TLS handshake succeeded, otherwise it failed
 (C<on_stoptls> will not be called in this case).
 
 The session in C<< $handle->{tls} >> can still be examined in this
 callback, even when the handshake was not successful.
 
 TLS handshake failures will not cause C<on_error> to be invoked when this
 callback is in effect, instead, the error message will be passed to C<on_starttls>.
 
 Without this callback, handshake failures lead to C<on_error> being
 called as usual.
 
 Note that you cannot just call C<starttls> again in this callback. If you
 need to do that, start an zero-second timer instead whose callback can
 then call C<< ->starttls >> again.
 
 =item on_stoptls => $cb->($handle)
 
 When a SSLv3/TLS shutdown/close notify/EOF is detected and this callback is
 set, then it will be invoked after freeing the TLS session. If it is not,
 then a TLS shutdown condition will be treated like a normal EOF condition
 on the handle.
 
 The session in C<< $handle->{tls} >> can still be examined in this
 callback.
 
 This callback will only be called on TLS shutdowns, not when the
 underlying handle signals EOF.
 
 =item json => L<JSON>, L<JSON::PP> or L<JSON::XS> object
 
 This is the json coder object used by the C<json> read and write types.
 
 If you don't supply it, then AnyEvent::Handle will create and use a
 suitable one (on demand), which will write and expect UTF-8 encoded
 JSON texts (either using L<JSON::XS> or L<JSON>). The written texts are
 guaranteed not to contain any newline character.
 
 For security reasons, this encoder will likely I<not> handle numbers and
 strings, only arrays and objects/hashes. The reason is that originally
 JSON was self-delimited, but Dougles Crockford thought it was a splendid
 idea to redefine JSON incompatibly, so this is no longer true.
 
 For protocols that used back-to-back JSON texts, this might lead to
 run-ins, where two or more JSON texts will be interpreted as one JSON
 text.
 
 For this reason, if the default encoder uses L<JSON::XS>, it will default
 to not allowing anything but arrays and objects/hashes, at least for the
 forseeable future (it will change at some point). This might or might not
 be true for the L<JSON> module, so this might cause a security issue.
 
 If you depend on either behaviour, you should create your own json object
 and pass it in explicitly.
 
 =item cbor => L<CBOR::XS> object
 
 This is the cbor coder object used by the C<cbor> read and write types.
 
 If you don't supply it, then AnyEvent::Handle will create and use a
 suitable one (on demand), which will write CBOR without using extensions,
 if possible.
 
 Note that you are responsible to depend on the L<CBOR::XS> module if you
 want to use this functionality, as AnyEvent does not have a dependency on
 it itself.
 
 =back
 
 =cut
 
 sub new {
    my $class = shift;
    my $self = bless { @_ }, $class;
 
    if ($self->{fh}) {
       $self->_start;
       return unless $self->{fh}; # could be gone by now
 
    } elsif ($self->{connect}) {
       require AnyEvent::Socket;
 
       $self->{peername} = $self->{connect}[0]
          unless exists $self->{peername};
 
       $self->{_skip_drain_rbuf} = 1;
 
       {
          Scalar::Util::weaken (my $self = $self);
 
          $self->{_connect} =
             AnyEvent::Socket::tcp_connect (
                $self->{connect}[0],
                $self->{connect}[1],
                sub {
                   my ($fh, $host, $port, $retry) = @_;
 
                   delete $self->{_connect}; # no longer needed
 
                   if ($fh) {
                      $self->{fh} = $fh;
 
                      delete $self->{_skip_drain_rbuf};
                      $self->_start;
 
                      $self->{on_connect}
                         and $self->{on_connect}($self, $host, $port, sub {
                                delete @$self{qw(fh _tw _rtw _wtw _ww _rw _eof _queue rbuf _wbuf tls _tls_rbuf _tls_wbuf)};
                                $self->{_skip_drain_rbuf} = 1;
                                &$retry;
                             });
 
                   } else {
                      if ($self->{on_connect_error}) {
                         $self->{on_connect_error}($self, "$!");
                         $self->destroy if $self;
                      } else {
                         $self->_error ($!, 1);
                      }
                   }
                },
                sub {
                   local $self->{fh} = $_[0];
 
                   $self->{on_prepare}
                      ? $self->{on_prepare}->($self)
                      : ()
                }
             );
       }
 
    } else {
       Carp::croak "AnyEvent::Handle: either an existing fh or the connect parameter must be specified";
    }
 
    $self
 }
 
 sub _start {
    my ($self) = @_;
 
    # too many clueless people try to use udp and similar sockets
    # with AnyEvent::Handle, do them a favour.
    my $type = getsockopt $self->{fh}, Socket::SOL_SOCKET (), Socket::SO_TYPE ();
    Carp::croak "AnyEvent::Handle: only stream sockets supported, anything else will NOT work!"
       if Socket::SOCK_STREAM () != (unpack "I", $type) && defined $type;
 
    AnyEvent::fh_unblock $self->{fh};
 
    $self->{_activity}  =
    $self->{_ractivity} =
    $self->{_wactivity} = AE::now;
 
    $self->{read_size} ||= 2048;
    $self->{max_read_size} = $self->{read_size}
       if $self->{read_size} > ($self->{max_read_size} || MAX_READ_SIZE);
 
    $self->timeout   (delete $self->{timeout}  ) if $self->{timeout};
    $self->rtimeout  (delete $self->{rtimeout} ) if $self->{rtimeout};
    $self->wtimeout  (delete $self->{wtimeout} ) if $self->{wtimeout};
 
    $self->no_delay  (delete $self->{no_delay} ) if exists $self->{no_delay}  && $self->{no_delay};
    $self->keepalive (delete $self->{keepalive}) if exists $self->{keepalive} && $self->{keepalive};
 
    $self->oobinline (exists $self->{oobinline} ? delete $self->{oobinline} : 1);
 
    $self->starttls  (delete $self->{tls}, delete $self->{tls_ctx})
       if $self->{tls};
 
    $self->on_drain  (delete $self->{on_drain} ) if $self->{on_drain};
 
    $self->start_read
       if $self->{on_read} || @{ $self->{_queue} };
 
    $self->_drain_wbuf;
 }
 
 sub _error {
    my ($self, $errno, $fatal, $message) = @_;
 
    $! = $errno;
    $message ||= "$!";
 
    if ($self->{on_error}) {
       $self->{on_error}($self, $fatal, $message);
       $self->destroy if $fatal;
    } elsif ($self->{fh} || $self->{connect}) {
       $self->destroy;
       Carp::croak "AnyEvent::Handle uncaught error: $message";
    }
 }
 
 =item $fh = $handle->fh
 
 This method returns the file handle used to create the L<AnyEvent::Handle> object.
 
 =cut
 
 sub fh { $_[0]{fh} }
 
 =item $handle->on_error ($cb)
 
 Replace the current C<on_error> callback (see the C<on_error> constructor argument).
 
 =cut
 
 sub on_error {
    $_[0]{on_error} = $_[1];
 }
 
 =item $handle->on_eof ($cb)
 
 Replace the current C<on_eof> callback (see the C<on_eof> constructor argument).
 
 =cut
 
 sub on_eof {
    $_[0]{on_eof} = $_[1];
 }
 
 =item $handle->on_timeout ($cb)
 
 =item $handle->on_rtimeout ($cb)
 
 =item $handle->on_wtimeout ($cb)
 
 Replace the current C<on_timeout>, C<on_rtimeout> or C<on_wtimeout>
 callback, or disables the callback (but not the timeout) if C<$cb> =
 C<undef>. See the C<timeout> constructor argument and method.
 
 =cut
 
 # see below
 
 =item $handle->autocork ($boolean)
 
 Enables or disables the current autocork behaviour (see C<autocork>
 constructor argument). Changes will only take effect on the next write.
 
 =cut
 
 sub autocork {
    $_[0]{autocork} = $_[1];
 }
 
 =item $handle->no_delay ($boolean)
 
 Enables or disables the C<no_delay> setting (see constructor argument of
 the same name for details).
 
 =cut
 
 sub no_delay {
    $_[0]{no_delay} = $_[1];
 
    setsockopt $_[0]{fh}, Socket::IPPROTO_TCP (), Socket::TCP_NODELAY (), int $_[1]
       if $_[0]{fh};
 }
 
 =item $handle->keepalive ($boolean)
 
 Enables or disables the C<keepalive> setting (see constructor argument of
 the same name for details).
 
 =cut
 
 sub keepalive {
    $_[0]{keepalive} = $_[1];
 
    eval {
       local $SIG{__DIE__};
       setsockopt $_[0]{fh}, Socket::SOL_SOCKET (), Socket::SO_KEEPALIVE (), int $_[1]
          if $_[0]{fh};
    };
 }
 
 =item $handle->oobinline ($boolean)
 
 Enables or disables the C<oobinline> setting (see constructor argument of
 the same name for details).
 
 =cut
 
 sub oobinline {
    $_[0]{oobinline} = $_[1];
 
    eval {
       local $SIG{__DIE__};
       setsockopt $_[0]{fh}, Socket::SOL_SOCKET (), Socket::SO_OOBINLINE (), int $_[1]
          if $_[0]{fh};
    };
 }
 
 =item $handle->keepalive ($boolean)
 
 Enables or disables the C<keepalive> setting (see constructor argument of
 the same name for details).
 
 =cut
 
 sub keepalive {
    $_[0]{keepalive} = $_[1];
 
    eval {
       local $SIG{__DIE__};
       setsockopt $_[0]{fh}, Socket::SOL_SOCKET (), Socket::SO_KEEPALIVE (), int $_[1]
          if $_[0]{fh};
    };
 }
 
 =item $handle->on_starttls ($cb)
 
 Replace the current C<on_starttls> callback (see the C<on_starttls> constructor argument).
 
 =cut
 
 sub on_starttls {
    $_[0]{on_starttls} = $_[1];
 }
 
 =item $handle->on_stoptls ($cb)
 
 Replace the current C<on_stoptls> callback (see the C<on_stoptls> constructor argument).
 
 =cut
 
 sub on_stoptls {
    $_[0]{on_stoptls} = $_[1];
 }
 
 =item $handle->rbuf_max ($max_octets)
 
 Configures the C<rbuf_max> setting (C<undef> disables it).
 
 =item $handle->wbuf_max ($max_octets)
 
 Configures the C<wbuf_max> setting (C<undef> disables it).
 
 =cut
 
 sub rbuf_max {
    $_[0]{rbuf_max} = $_[1];
 }
 
 sub wbuf_max {
    $_[0]{wbuf_max} = $_[1];
 }
 
 #############################################################################
 
 =item $handle->timeout ($seconds)
 
 =item $handle->rtimeout ($seconds)
 
 =item $handle->wtimeout ($seconds)
 
 Configures (or disables) the inactivity timeout.
 
 The timeout will be checked instantly, so this method might destroy the
 handle before it returns.
 
 =item $handle->timeout_reset
 
 =item $handle->rtimeout_reset
 
 =item $handle->wtimeout_reset
 
 Reset the activity timeout, as if data was received or sent.
 
 These methods are cheap to call.
 
 =cut
 
 for my $dir ("", "r", "w") {
    my $timeout    = "${dir}timeout";
    my $tw         = "_${dir}tw";
    my $on_timeout = "on_${dir}timeout";
    my $activity   = "_${dir}activity";
    my $cb;
 
    *$on_timeout = sub {
       $_[0]{$on_timeout} = $_[1];
    };
 
    *$timeout = sub {
       my ($self, $new_value) = @_;
 
       $new_value >= 0
          or Carp::croak "AnyEvent::Handle->$timeout called with negative timeout ($new_value), caught";
 
       $self->{$timeout} = $new_value;
       delete $self->{$tw}; &$cb;
    };
 
    *{"${dir}timeout_reset"} = sub {
       $_[0]{$activity} = AE::now;
    };
 
    # main workhorse:
    # reset the timeout watcher, as neccessary
    # also check for time-outs
    $cb = sub {
       my ($self) = @_;
 
       if ($self->{$timeout} && $self->{fh}) {
          my $NOW = AE::now;
 
          # when would the timeout trigger?
          my $after = $self->{$activity} + $self->{$timeout} - $NOW;
 
          # now or in the past already?
          if ($after <= 0) {
             $self->{$activity} = $NOW;
 
             if ($self->{$on_timeout}) {
                $self->{$on_timeout}($self);
             } else {
                $self->_error (Errno::ETIMEDOUT);
             }
 
             # callback could have changed timeout value, optimise
             return unless $self->{$timeout};
 
             # calculate new after
             $after = $self->{$timeout};
          }
 
          Scalar::Util::weaken $self;
          return unless $self; # ->error could have destroyed $self
 
          $self->{$tw} ||= AE::timer $after, 0, sub {
             delete $self->{$tw};
             $cb->($self);
          };
       } else {
          delete $self->{$tw};
       }
    }
 }
 
 #############################################################################
 
 =back
 
 =head2 WRITE QUEUE
 
 AnyEvent::Handle manages two queues per handle, one for writing and one
 for reading.
 
 The write queue is very simple: you can add data to its end, and
 AnyEvent::Handle will automatically try to get rid of it for you.
 
 When data could be written and the write buffer is shorter then the low
 water mark, the C<on_drain> callback will be invoked once.
 
 =over 4
 
 =item $handle->on_drain ($cb)
 
 Sets the C<on_drain> callback or clears it (see the description of
 C<on_drain> in the constructor).
 
 This method may invoke callbacks (and therefore the handle might be
 destroyed after it returns).
 
 =cut
 
 sub on_drain {
    my ($self, $cb) = @_;
 
    $self->{on_drain} = $cb;
 
    $cb->($self)
       if $cb && $self->{low_water_mark} >= (length $self->{wbuf}) + (length $self->{_tls_wbuf});
 }
 
 =item $handle->push_write ($data)
 
 Queues the given scalar to be written. You can push as much data as
 you want (only limited by the available memory and C<wbuf_max>), as
 C<AnyEvent::Handle> buffers it independently of the kernel.
 
 This method may invoke callbacks (and therefore the handle might be
 destroyed after it returns).
 
 =cut
 
 sub _drain_wbuf {
    my ($self) = @_;
 
    if (!$self->{_ww} && length $self->{wbuf}) {
 
       Scalar::Util::weaken $self;
 
       my $cb = sub {
          my $len = syswrite $self->{fh}, $self->{wbuf};
 
          if (defined $len) {
             substr $self->{wbuf}, 0, $len, "";
 
             $self->{_activity} = $self->{_wactivity} = AE::now;
 
             $self->{on_drain}($self)
                if $self->{low_water_mark} >= (length $self->{wbuf}) + (length $self->{_tls_wbuf})
                   && $self->{on_drain};
 
             delete $self->{_ww} unless length $self->{wbuf};
          } elsif ($! != EAGAIN && $! != EINTR && $! != EWOULDBLOCK && $! != WSAEWOULDBLOCK) {
             $self->_error ($!, 1);
          }
       };
 
       # try to write data immediately
       $cb->() unless $self->{autocork};
 
       # if still data left in wbuf, we need to poll
       $self->{_ww} = AE::io $self->{fh}, 1, $cb
          if length $self->{wbuf};
 
       if (
          defined $self->{wbuf_max}
          && $self->{wbuf_max} < length $self->{wbuf}
       ) {
          $self->_error (Errno::ENOSPC, 1), return;
       }
    };
 }
 
 our %WH;
 
 # deprecated
 sub register_write_type($$) {
    $WH{$_[0]} = $_[1];
 }
 
 sub push_write {
    my $self = shift;
 
    if (@_ > 1) {
       my $type = shift;
 
       @_ = ($WH{$type} ||= _load_func "$type\::anyevent_write_type"
             or Carp::croak "unsupported/unloadable type '$type' passed to AnyEvent::Handle::push_write")
            ->($self, @_);
    }
 
    # we downgrade here to avoid hard-to-track-down bugs,
    # and diagnose the problem earlier and better.
 
    if ($self->{tls}) {
       utf8::downgrade $self->{_tls_wbuf} .= $_[0];
       &_dotls ($self)    if $self->{fh};
    } else {
       utf8::downgrade $self->{wbuf}      .= $_[0];
       $self->_drain_wbuf if $self->{fh};
    }
 }
 
 =item $handle->push_write (type => @args)
 
 Instead of formatting your data yourself, you can also let this module
 do the job by specifying a type and type-specific arguments. You
 can also specify the (fully qualified) name of a package, in which
 case AnyEvent tries to load the package and then expects to find the
 C<anyevent_write_type> function inside (see "custom write types", below).
 
 Predefined types are (if you have ideas for additional types, feel free to
 drop by and tell us):
 
 =over 4
 
 =item netstring => $string
 
 Formats the given value as netstring
 (http://cr.yp.to/proto/netstrings.txt, this is not a recommendation to use them).
 
 =cut
 
 register_write_type netstring => sub {
    my ($self, $string) = @_;
 
    (length $string) . ":$string,"
 };
 
 =item packstring => $format, $data
 
 An octet string prefixed with an encoded length. The encoding C<$format>
 uses the same format as a Perl C<pack> format, but must specify a single
 integer only (only one of C<cCsSlLqQiInNvVjJw> is allowed, plus an
 optional C<!>, C<< < >> or C<< > >> modifier).
 
 =cut
 
 register_write_type packstring => sub {
    my ($self, $format, $string) = @_;
 
    pack "$format/a*", $string
 };
 
 =item json => $array_or_hashref
 
 Encodes the given hash or array reference into a JSON object. Unless you
 provide your own JSON object, this means it will be encoded to JSON text
 in UTF-8.
 
 The default encoder might or might not handle every type of JSON value -
 it might be limited to arrays and objects for security reasons. See the
 C<json> constructor attribute for more details.
 
 JSON objects (and arrays) are self-delimiting, so if you only use arrays
 and hashes, you can write JSON at one end of a handle and read them at the
 other end without using any additional framing.
 
 The JSON text generated by the default encoder is guaranteed not to
 contain any newlines: While this module doesn't need delimiters after or
 between JSON texts to be able to read them, many other languages depend on
 them.
 
 A simple RPC protocol that interoperates easily with other languages is
 to send JSON arrays (or objects, although arrays are usually the better
 choice as they mimic how function argument passing works) and a newline
 after each JSON text:
 
    $handle->push_write (json => ["method", "arg1", "arg2"]); # whatever
    $handle->push_write ("\012");
  
 An AnyEvent::Handle receiver would simply use the C<json> read type and
 rely on the fact that the newline will be skipped as leading whitespace:
 
    $handle->push_read (json => sub { my $array = $_[1]; ... });
 
 Other languages could read single lines terminated by a newline and pass
 this line into their JSON decoder of choice.
 
 =item cbor => $perl_scalar
 
 Encodes the given scalar into a CBOR value. Unless you provide your own
 L<CBOR::XS> object, this means it will be encoded to a CBOR string not
 using any extensions, if possible.
 
 CBOR values are self-delimiting, so you can write CBOR at one end of
 a handle and read them at the other end without using any additional
 framing.
 
 A simple nd very very fast RPC protocol that interoperates with
 other languages is to send CBOR and receive CBOR values (arrays are
 recommended):
 
    $handle->push_write (cbor => ["method", "arg1", "arg2"]); # whatever
  
 An AnyEvent::Handle receiver would simply use the C<cbor> read type:
 
    $handle->push_read (cbor => sub { my $array = $_[1]; ... });
 
 =cut
 
 sub json_coder() {
    eval { require JSON::XS; JSON::XS->new->utf8 }
       || do { require JSON::PP; JSON::PP->new->utf8 }
 }
 
 register_write_type json => sub {
    my ($self, $ref) = @_;
 
    ($self->{json} ||= json_coder)
       ->encode ($ref)
 };
 
 sub cbor_coder() {
    require CBOR::XS;
    CBOR::XS->new
 }
 
 register_write_type cbor => sub {
    my ($self, $scalar) = @_;
 
    ($self->{cbor} ||= cbor_coder)
       ->encode ($scalar)
 };
 
 =item storable => $reference
 
 Freezes the given reference using L<Storable> and writes it to the
 handle. Uses the C<nfreeze> format.
 
 =cut
 
 register_write_type storable => sub {
    my ($self, $ref) = @_;
 
    require Storable unless $Storable::VERSION;
 
    pack "w/a*", Storable::nfreeze ($ref)
 };
 
 =back
 
 =item $handle->push_shutdown
 
 Sometimes you know you want to close the socket after writing your data
 before it was actually written. One way to do that is to replace your
 C<on_drain> handler by a callback that shuts down the socket (and set
 C<low_water_mark> to C<0>). This method is a shorthand for just that, and
 replaces the C<on_drain> callback with:
 
    sub { shutdown $_[0]{fh}, 1 }
 
 This simply shuts down the write side and signals an EOF condition to the
 the peer.
 
 You can rely on the normal read queue and C<on_eof> handling
 afterwards. This is the cleanest way to close a connection.
 
 This method may invoke callbacks (and therefore the handle might be
 destroyed after it returns).
 
 =cut
 
 sub push_shutdown {
    my ($self) = @_;
 
    delete $self->{low_water_mark};
    $self->on_drain (sub { shutdown $_[0]{fh}, 1 });
 }
 
 =item custom write types - Package::anyevent_write_type $handle, @args
 
 Instead of one of the predefined types, you can also specify the name of
 a package. AnyEvent will try to load the package and then expects to find
 a function named C<anyevent_write_type> inside. If it isn't found, it
 progressively tries to load the parent package until it either finds the
 function (good) or runs out of packages (bad).
 
 Whenever the given C<type> is used, C<push_write> will the function with
 the handle object and the remaining arguments.
 
 The function is supposed to return a single octet string that will be
 appended to the write buffer, so you can mentally treat this function as a
 "arguments to on-the-wire-format" converter.
 
 Example: implement a custom write type C<join> that joins the remaining
 arguments using the first one.
 
    $handle->push_write (My::Type => " ", 1,2,3);
 
    # uses the following package, which can be defined in the "My::Type" or in
    # the "My" modules to be auto-loaded, or just about anywhere when the
    # My::Type::anyevent_write_type is defined before invoking it.
 
    package My::Type;
 
    sub anyevent_write_type {
       my ($handle, $delim, @args) = @_;
 
       join $delim, @args
    }
 
 =cut
 
 #############################################################################
 
 =back
 
 =head2 READ QUEUE
 
 AnyEvent::Handle manages two queues per handle, one for writing and one
 for reading.
 
 The read queue is more complex than the write queue. It can be used in two
 ways, the "simple" way, using only C<on_read> and the "complex" way, using
 a queue.
 
 In the simple case, you just install an C<on_read> callback and whenever
 new data arrives, it will be called. You can then remove some data (if
 enough is there) from the read buffer (C<< $handle->rbuf >>). Or you can
 leave the data there if you want to accumulate more (e.g. when only a
 partial message has been received so far), or change the read queue with
 e.g. C<push_read>.
 
 In the more complex case, you want to queue multiple callbacks. In this
 case, AnyEvent::Handle will call the first queued callback each time new
 data arrives (also the first time it is queued) and remove it when it has
 done its job (see C<push_read>, below).
 
 This way you can, for example, push three line-reads, followed by reading
 a chunk of data, and AnyEvent::Handle will execute them in order.
 
 Example 1: EPP protocol parser. EPP sends 4 byte length info, followed by
 the specified number of bytes which give an XML datagram.
 
    # in the default state, expect some header bytes
    $handle->on_read (sub {
       # some data is here, now queue the length-header-read (4 octets)
       shift->unshift_read (chunk => 4, sub {
          # header arrived, decode
          my $len = unpack "N", $_[1];
 
          # now read the payload
          shift->unshift_read (chunk => $len, sub {
             my $xml = $_[1];
             # handle xml
          });
       });
    });
 
 Example 2: Implement a client for a protocol that replies either with "OK"
 and another line or "ERROR" for the first request that is sent, and 64
 bytes for the second request. Due to the availability of a queue, we can
 just pipeline sending both requests and manipulate the queue as necessary
 in the callbacks.
 
 When the first callback is called and sees an "OK" response, it will
 C<unshift> another line-read. This line-read will be queued I<before> the
 64-byte chunk callback.
 
    # request one, returns either "OK + extra line" or "ERROR"
    $handle->push_write ("request 1\015\012");
 
    # we expect "ERROR" or "OK" as response, so push a line read
    $handle->push_read (line => sub {
       # if we got an "OK", we have to _prepend_ another line,
       # so it will be read before the second request reads its 64 bytes
       # which are already in the queue when this callback is called
       # we don't do this in case we got an error
       if ($_[1] eq "OK") {
          $_[0]->unshift_read (line => sub {
             my $response = $_[1];
             ...
          });
       }
    });
 
    # request two, simply returns 64 octets
    $handle->push_write ("request 2\015\012");
 
    # simply read 64 bytes, always
    $handle->push_read (chunk => 64, sub {
       my $response = $_[1];
       ...
    });
 
 =over 4
 
 =cut
 
 sub _drain_rbuf {
    my ($self) = @_;
 
    # avoid recursion
    return if $self->{_skip_drain_rbuf};
    local $self->{_skip_drain_rbuf} = 1;
 
    while () {
       # we need to use a separate tls read buffer, as we must not receive data while
       # we are draining the buffer, and this can only happen with TLS.
       $self->{rbuf} .= delete $self->{_tls_rbuf}
          if exists $self->{_tls_rbuf};
 
       my $len = length $self->{rbuf};
 
       if (my $cb = shift @{ $self->{_queue} }) {
          unless ($cb->($self)) {
             # no progress can be made
             # (not enough data and no data forthcoming)
             $self->_error (Errno::EPIPE, 1), return
                if $self->{_eof};
 
             unshift @{ $self->{_queue} }, $cb;
             last;
          }
       } elsif ($self->{on_read}) {
          last unless $len;
 
          $self->{on_read}($self);
 
          if (
             $len == length $self->{rbuf} # if no data has been consumed
             && !@{ $self->{_queue} }     # and the queue is still empty
             && $self->{on_read}          # but we still have on_read
          ) {
             # no further data will arrive
             # so no progress can be made
             $self->_error (Errno::EPIPE, 1), return
                if $self->{_eof};
 
             last; # more data might arrive
          }
       } else {
          # read side becomes idle
          delete $self->{_rw} unless $self->{tls};
          last;
       }
    }
 
    if ($self->{_eof}) {
       $self->{on_eof}
          ? $self->{on_eof}($self)
          : $self->_error (0, 1, "Unexpected end-of-file");
 
       return;
    }
 
    if (
       defined $self->{rbuf_max}
       && $self->{rbuf_max} < length $self->{rbuf}
    ) {
       $self->_error (Errno::ENOSPC, 1), return;
    }
 
    # may need to restart read watcher
    unless ($self->{_rw}) {
       $self->start_read
          if $self->{on_read} || @{ $self->{_queue} };
    }
 }
 
 =item $handle->on_read ($cb)
 
 This replaces the currently set C<on_read> callback, or clears it (when
 the new callback is C<undef>). See the description of C<on_read> in the
 constructor.
 
 This method may invoke callbacks (and therefore the handle might be
 destroyed after it returns).
 
 =cut
 
 sub on_read {
    my ($self, $cb) = @_;
 
    $self->{on_read} = $cb;
    $self->_drain_rbuf if $cb;
 }
 
 =item $handle->rbuf
 
 Returns the read buffer (as a modifiable lvalue). You can also access the
 read buffer directly as the C<< ->{rbuf} >> member, if you want (this is
 much faster, and no less clean).
 
 The only operation allowed on the read buffer (apart from looking at it)
 is removing data from its beginning. Otherwise modifying or appending to
 it is not allowed and will lead to hard-to-track-down bugs.
 
 NOTE: The read buffer should only be used or modified in the C<on_read>
 callback or when C<push_read> or C<unshift_read> are used with a single
 callback (i.e. untyped). Typed C<push_read> and C<unshift_read> methods
 will manage the read buffer on their own.
 
 =cut
 
 sub rbuf : lvalue {
    $_[0]{rbuf}
 }
 
 =item $handle->push_read ($cb)
 
 =item $handle->unshift_read ($cb)
 
 Append the given callback to the end of the queue (C<push_read>) or
 prepend it (C<unshift_read>).
 
 The callback is called each time some additional read data arrives.
 
 It must check whether enough data is in the read buffer already.
 
 If not enough data is available, it must return the empty list or a false
 value, in which case it will be called repeatedly until enough data is
 available (or an error condition is detected).
 
 If enough data was available, then the callback must remove all data it is
 interested in (which can be none at all) and return a true value. After returning
 true, it will be removed from the queue.
 
 These methods may invoke callbacks (and therefore the handle might be
 destroyed after it returns).
 
 =cut
 
 our %RH;
 
 sub register_read_type($$) {
    $RH{$_[0]} = $_[1];
 }
 
 sub push_read {
    my $self = shift;
    my $cb = pop;
 
    if (@_) {
       my $type = shift;
 
       $cb = ($RH{$type} ||= _load_func "$type\::anyevent_read_type"
              or Carp::croak "unsupported/unloadable type '$type' passed to AnyEvent::Handle::push_read")
             ->($self, $cb, @_);
    }
 
    push @{ $self->{_queue} }, $cb;
    $self->_drain_rbuf;
 }
 
 sub unshift_read {
    my $self = shift;
    my $cb = pop;
 
    if (@_) {
       my $type = shift;
 
       $cb = ($RH{$type} ||= _load_func "$type\::anyevent_read_type"
              or Carp::croak "unsupported/unloadable type '$type' passed to AnyEvent::Handle::unshift_read")
             ->($self, $cb, @_);
    }
 
    unshift @{ $self->{_queue} }, $cb;
    $self->_drain_rbuf;
 }
 
 =item $handle->push_read (type => @args, $cb)
 
 =item $handle->unshift_read (type => @args, $cb)
 
 Instead of providing a callback that parses the data itself you can chose
 between a number of predefined parsing formats, for chunks of data, lines
 etc. You can also specify the (fully qualified) name of a package, in
 which case AnyEvent tries to load the package and then expects to find the
 C<anyevent_read_type> function inside (see "custom read types", below).
 
 Predefined types are (if you have ideas for additional types, feel free to
 drop by and tell us):
 
 =over 4
 
 =item chunk => $octets, $cb->($handle, $data)
 
 Invoke the callback only once C<$octets> bytes have been read. Pass the
 data read to the callback. The callback will never be called with less
 data.
 
 Example: read 2 bytes.
 
    $handle->push_read (chunk => 2, sub {
       say "yay " . unpack "H*", $_[1];
    });
 
 =cut
 
 register_read_type chunk => sub {
    my ($self, $cb, $len) = @_;
 
    sub {
       $len <= length $_[0]{rbuf} or return;
       $cb->($_[0], substr $_[0]{rbuf}, 0, $len, "");
       1
    }
 };
 
 =item line => [$eol, ]$cb->($handle, $line, $eol)
 
 The callback will be called only once a full line (including the end of
 line marker, C<$eol>) has been read. This line (excluding the end of line
 marker) will be passed to the callback as second argument (C<$line>), and
 the end of line marker as the third argument (C<$eol>).
 
 The end of line marker, C<$eol>, can be either a string, in which case it
 will be interpreted as a fixed record end marker, or it can be a regex
 object (e.g. created by C<qr>), in which case it is interpreted as a
 regular expression.
 
 The end of line marker argument C<$eol> is optional, if it is missing (NOT
 undef), then C<qr|\015?\012|> is used (which is good for most internet
 protocols).
 
 Partial lines at the end of the stream will never be returned, as they are
 not marked by the end of line marker.
 
 =cut
 
 register_read_type line => sub {
    my ($self, $cb, $eol) = @_;
 
    if (@_ < 3) {
       # this is faster then the generic code below
       sub {
          (my $pos = index $_[0]{rbuf}, "\012") >= 0
             or return;
 
          (my $str = substr $_[0]{rbuf}, 0, $pos + 1, "") =~ s/(\015?\012)\Z// or die;
          $cb->($_[0], $str, "$1");
          1
       }
    } else {
       $eol = quotemeta $eol unless ref $eol;
       $eol = qr|^(.*?)($eol)|s;
 
       sub {
          $_[0]{rbuf} =~ s/$eol// or return;
 
          $cb->($_[0], "$1", "$2");
          1
       }
    }
 };
 
 =item regex => $accept[, $reject[, $skip], $cb->($handle, $data)
 
 Makes a regex match against the regex object C<$accept> and returns
 everything up to and including the match. All the usual regex variables
 ($1, %+ etc.) from the regex match are available in the callback.
 
 Example: read a single line terminated by '\n'.
 
    $handle->push_read (regex => qr<\n>, sub { ... });
 
 If C<$reject> is given and not undef, then it determines when the data is
 to be rejected: it is matched against the data when the C<$accept> regex
 does not match and generates an C<EBADMSG> error when it matches. This is
 useful to quickly reject wrong data (to avoid waiting for a timeout or a
 receive buffer overflow).
 
 Example: expect a single decimal number followed by whitespace, reject
 anything else (not the use of an anchor).
 
    $handle->push_read (regex => qr<^[0-9]+\s>, qr<[^0-9]>, sub { ... });
 
 If C<$skip> is given and not C<undef>, then it will be matched against
 the receive buffer when neither C<$accept> nor C<$reject> match,
 and everything preceding and including the match will be accepted
 unconditionally. This is useful to skip large amounts of data that you
 know cannot be matched, so that the C<$accept> or C<$reject> regex do not
 have to start matching from the beginning. This is purely an optimisation
 and is usually worth it only when you expect more than a few kilobytes.
 
 Example: expect a http header, which ends at C<\015\012\015\012>. Since we
 expect the header to be very large (it isn't in practice, but...), we use
 a skip regex to skip initial portions. The skip regex is tricky in that
 it only accepts something not ending in either \015 or \012, as these are
 required for the accept regex.
 
    $handle->push_read (regex =>
       qr<\015\012\015\012>,
       undef, # no reject
       qr<^.*[^\015\012]>,
       sub { ... });
 
 =cut
 
 register_read_type regex => sub {
    my ($self, $cb, $accept, $reject, $skip) = @_;
 
    my $data;
    my $rbuf = \$self->{rbuf};
 
    sub {
       # accept
       if ($$rbuf =~ $accept) {
          $data .= substr $$rbuf, 0, $+[0], "";
          $cb->($_[0], $data);
          return 1;
       }
       
       # reject
       if ($reject && $$rbuf =~ $reject) {
          $_[0]->_error (Errno::EBADMSG);
       }
 
       # skip
       if ($skip && $$rbuf =~ $skip) {
          $data .= substr $$rbuf, 0, $+[0], "";
       }
 
       ()
    }
 };
 
 =item netstring => $cb->($handle, $string)
 
 A netstring (http://cr.yp.to/proto/netstrings.txt, this is not an endorsement).
 
 Throws an error with C<$!> set to EBADMSG on format violations.
 
 =cut
 
 register_read_type netstring => sub {
    my ($self, $cb) = @_;
 
    sub {
       unless ($_[0]{rbuf} =~ s/^(0|[1-9][0-9]*)://) {
          if ($_[0]{rbuf} =~ /[^0-9]/) {
             $_[0]->_error (Errno::EBADMSG);
          }
          return;
       }
 
       my $len = $1;
 
       $_[0]->unshift_read (chunk => $len, sub {
          my $string = $_[1];
          $_[0]->unshift_read (chunk => 1, sub {
             if ($_[1] eq ",") {
                $cb->($_[0], $string);
             } else {
                $_[0]->_error (Errno::EBADMSG);
             }
          });
       });
 
       1
    }
 };
 
 =item packstring => $format, $cb->($handle, $string)
 
 An octet string prefixed with an encoded length. The encoding C<$format>
 uses the same format as a Perl C<pack> format, but must specify a single
 integer only (only one of C<cCsSlLqQiInNvVjJw> is allowed, plus an
 optional C<!>, C<< < >> or C<< > >> modifier).
 
 For example, DNS over TCP uses a prefix of C<n> (2 octet network order),
 EPP uses a prefix of C<N> (4 octtes).
 
 Example: read a block of data prefixed by its length in BER-encoded
 format (very efficient).
 
    $handle->push_read (packstring => "w", sub {
       my ($handle, $data) = @_;
    });
 
 =cut
 
 register_read_type packstring => sub {
    my ($self, $cb, $format) = @_;
 
    sub {
       # when we can use 5.10 we can use ".", but for 5.8 we use the re-pack method
       defined (my $len = eval { unpack $format, $_[0]{rbuf} })
          or return;
 
       $format = length pack $format, $len;
 
       # bypass unshift if we already have the remaining chunk
       if ($format + $len <= length $_[0]{rbuf}) {
          my $data = substr $_[0]{rbuf}, $format, $len;
          substr $_[0]{rbuf}, 0, $format + $len, "";
          $cb->($_[0], $data);
       } else {
          # remove prefix
          substr $_[0]{rbuf}, 0, $format, "";
 
          # read remaining chunk
          $_[0]->unshift_read (chunk => $len, $cb);
       }
 
       1
    }
 };
 
 =item json => $cb->($handle, $hash_or_arrayref)
 
 Reads a JSON object or array, decodes it and passes it to the
 callback. When a parse error occurs, an C<EBADMSG> error will be raised.
 
 If a C<json> object was passed to the constructor, then that will be
 used for the final decode, otherwise it will create a L<JSON::XS> or
 L<JSON::PP> coder object expecting UTF-8.
 
 This read type uses the incremental parser available with JSON version
 2.09 (and JSON::XS version 2.2) and above.
 
 Since JSON texts are fully self-delimiting, the C<json> read and write
 types are an ideal simple RPC protocol: just exchange JSON datagrams. See
 the C<json> write type description, above, for an actual example.
 
 =cut
 
 register_read_type json => sub {
    my ($self, $cb) = @_;
 
    my $json = $self->{json} ||= json_coder;
 
    my $data;
 
    sub {
       my $ref = eval { $json->incr_parse ($_[0]{rbuf}) };
 
       if ($ref) {
          $_[0]{rbuf} = $json->incr_text;
          $json->incr_text = "";
          $cb->($_[0], $ref);
 
          1
       } elsif ($@) {
          # error case
          $json->incr_skip;
 
          $_[0]{rbuf} = $json->incr_text;
          $json->incr_text = "";
 
          $_[0]->_error (Errno::EBADMSG);
 
          ()
       } else {
          $_[0]{rbuf} = "";
 
          ()
       }
    }
 };
 
 =item cbor => $cb->($handle, $scalar)
 
 Reads a CBOR value, decodes it and passes it to the callback. When a parse
 error occurs, an C<EBADMSG> error will be raised.
 
 If a L<CBOR::XS> object was passed to the constructor, then that will be
 used for the final decode, otherwise it will create a CBOR coder without
 enabling any options.
 
 You have to provide a dependency to L<CBOR::XS> on your own: this module
 will load the L<CBOR::XS> module, but AnyEvent does not depend on it
 itself.
 
 Since CBOR values are fully self-delimiting, the C<cbor> read and write
 types are an ideal simple RPC protocol: just exchange CBOR datagrams. See
 the C<cbor> write type description, above, for an actual example.
 
 =cut
 
 register_read_type cbor => sub {
    my ($self, $cb) = @_;
 
    my $cbor = $self->{cbor} ||= cbor_coder;
 
    my $data;
 
    sub {
       my (@value) = eval { $cbor->incr_parse ($_[0]{rbuf}) };
 
       if (@value) {
          $cb->($_[0], @value);
 
          1
       } elsif ($@) {
          # error case
          $cbor->incr_reset;
 
          $_[0]->_error (Errno::EBADMSG);
 
          ()
       } else {
          ()
       }
    }
 };
 
 =item storable => $cb->($handle, $ref)
 
 Deserialises a L<Storable> frozen representation as written by the
 C<storable> write type (BER-encoded length prefix followed by nfreeze'd
 data).
 
 Raises C<EBADMSG> error if the data could not be decoded.
 
 =cut
 
 register_read_type storable => sub {
    my ($self, $cb) = @_;
 
    require Storable unless $Storable::VERSION;
 
    sub {
       # when we can use 5.10 we can use ".", but for 5.8 we use the re-pack method
       defined (my $len = eval { unpack "w", $_[0]{rbuf} })
          or return;
 
       my $format = length pack "w", $len;
 
       # bypass unshift if we already have the remaining chunk
       if ($format + $len <= length $_[0]{rbuf}) {
          my $data = substr $_[0]{rbuf}, $format, $len;
          substr $_[0]{rbuf}, 0, $format + $len, "";
 
          eval { $cb->($_[0], Storable::thaw ($data)); 1 }
             or return $_[0]->_error (Errno::EBADMSG);
       } else {
          # remove prefix
          substr $_[0]{rbuf}, 0, $format, "";
 
          # read remaining chunk
          $_[0]->unshift_read (chunk => $len, sub {
             eval { $cb->($_[0], Storable::thaw ($_[1])); 1 }
                or $_[0]->_error (Errno::EBADMSG);
          });
       }
 
       1
    }
 };
 
 =item tls_detect => $cb->($handle, $detect, $major, $minor)
 
 Checks the input stream for a valid SSL or TLS handshake TLSPaintext
 record without consuming anything. Only SSL version 3 or higher
 is handled, up to the fictituous protocol 4.x (but both SSL3+ and
 SSL2-compatible framing is supported).
 
 If it detects that the input data is likely TLS, it calls the callback
 with a true value for C<$detect> and the (on-wire) TLS version as second
 and third argument (C<$major> is C<3>, and C<$minor> is 0..3 for SSL
 3.0, TLS 1.0, 1.1 and 1.2, respectively).  If it detects the input to
 be definitely not TLS, it calls the callback with a false value for
 C<$detect>.
 
 The callback could use this information to decide whether or not to start
 TLS negotiation.
 
 In all cases the data read so far is passed to the following read
 handlers.
 
 Usually you want to use the C<tls_autostart> read type instead.
 
 If you want to design a protocol that works in the presence of TLS
 dtection, make sure that any non-TLS data doesn't start with the octet 22
 (ASCII SYN, 16 hex) or 128-255 (i.e. highest bit set). The checks this
 read type does are a bit more strict, but might losen in the future to
 accomodate protocol changes.
 
 This read type does not rely on L<AnyEvent::TLS> (and thus, not on
 L<Net::SSLeay>).
 
 =item tls_autostart => $tls[, $tls_ctx]
 
 Tries to detect a valid SSL or TLS handshake. If one is detected, it tries
 to start tls by calling C<starttls> with the given arguments.
 
 In practise, C<$tls> must be C<accept>, or a Net::SSLeay context that has
 been configured to accept, as servers do not normally send a handshake on
 their own and ths cannot be detected in this way.
 
 See C<tls_detect> above for more details.
 
 Example: give the client a chance to start TLS before accepting a text
 line.
 
    $hdl->push_read (tls_detect => "accept");
    $hdl->push_read (line => sub {
       print "received ", ($_[0]{tls} ? "encrypted" : "cleartext"), " <$_[1]>\n";
    });
 
 =cut
 
 register_read_type tls_detect => sub {
    my ($self, $cb) = @_;
 
    sub {
       # this regex matches a full or partial tls record
       if (
          # ssl3+: type(22=handshake) major(=3) minor(any) length_hi
          $self->{rbuf} =~ /^(?:\z| \x16 (\z| [\x03\x04] (?:\z| . (?:\z| [\x00-\x40] ))))/xs
          # ssl2 comapatible: len_hi len_lo type(1) major minor dummy(forlength)
          or $self->{rbuf} =~ /^(?:\z| [\x80-\xff] (?:\z| . (?:\z| \x01 (\z| [\x03\x04] (?:\z| . (?:\z| . ))))))/xs
       ) {
          return if 3 != length $1; # partial match, can't decide yet
 
          # full match, valid TLS record
          my ($major, $minor) = unpack "CC", $1;
          $cb->($self, "accept", $major + $minor * 0.1);
       } else {
          # mismatch == guaranteed not TLS
          $cb->($self, undef);
       }
 
       1
    }
 };
 
 register_read_type tls_autostart => sub {
    my ($self, @tls) = @_;
 
    $RH{tls_detect}($self, sub {
       return unless $_[1];
       $_[0]->starttls (@tls);
    })
 };
 
 =back
 
 =item custom read types - Package::anyevent_read_type $handle, $cb, @args
 
 Instead of one of the predefined types, you can also specify the name
 of a package. AnyEvent will try to load the package and then expects to
 find a function named C<anyevent_read_type> inside. If it isn't found, it
 progressively tries to load the parent package until it either finds the
 function (good) or runs out of packages (bad).
 
 Whenever this type is used, C<push_read> will invoke the function with the
 handle object, the original callback and the remaining arguments.
 
 The function is supposed to return a callback (usually a closure) that
 works as a plain read callback (see C<< ->push_read ($cb) >>), so you can
 mentally treat the function as a "configurable read type to read callback"
 converter.
 
 It should invoke the original callback when it is done reading (remember
 to pass C<$handle> as first argument as all other callbacks do that,
 although there is no strict requirement on this).
 
 For examples, see the source of this module (F<perldoc -m
 AnyEvent::Handle>, search for C<register_read_type>)).
 
 =item $handle->stop_read
 
 =item $handle->start_read
 
 In rare cases you actually do not want to read anything from the
 socket. In this case you can call C<stop_read>. Neither C<on_read> nor
 any queued callbacks will be executed then. To start reading again, call
 C<start_read>.
 
 Note that AnyEvent::Handle will automatically C<start_read> for you when
 you change the C<on_read> callback or push/unshift a read callback, and it
 will automatically C<stop_read> for you when neither C<on_read> is set nor
 there are any read requests in the queue.
 
 In older versions of this module (<= 5.3), these methods had no effect,
 as TLS does not support half-duplex connections. In current versions they
 work as expected, as this behaviour is required to avoid certain resource
 attacks, where the program would be forced to read (and buffer) arbitrary
 amounts of data before being able to send some data. The drawback is that
 some readings of the the SSL/TLS specifications basically require this
 attack to be working, as SSL/TLS implementations might stall sending data
 during a rehandshake.
 
 As a guideline, during the initial handshake, you should not stop reading,
 and as a client, it might cause problems, depending on your application.
 
 =cut
 
 sub stop_read {
    my ($self) = @_;
 
    delete $self->{_rw};
 }
 
 sub start_read {
    my ($self) = @_;
 
    unless ($self->{_rw} || $self->{_eof} || !$self->{fh}) {
       Scalar::Util::weaken $self;
 
       $self->{_rw} = AE::io $self->{fh}, 0, sub {
          my $rbuf = \($self->{tls} ? my $buf : $self->{rbuf});
          my $len = sysread $self->{fh}, $$rbuf, $self->{read_size}, length $$rbuf;
 
          if ($len > 0) {
             $self->{_activity} = $self->{_ractivity} = AE::now;
 
             if ($self->{tls}) {
                Net::SSLeay::BIO_write ($self->{_rbio}, $$rbuf);
 
                &_dotls ($self);
             } else {
                $self->_drain_rbuf;
             }
 
             if ($len == $self->{read_size}) {
                $self->{read_size} *= 2;
                $self->{read_size} = $self->{max_read_size} || MAX_READ_SIZE
                   if $self->{read_size} > ($self->{max_read_size} || MAX_READ_SIZE);
             }
 
          } elsif (defined $len) {
             delete $self->{_rw};
             $self->{_eof} = 1;
             $self->_drain_rbuf;
 
          } elsif ($! != EAGAIN && $! != EINTR && $! != EWOULDBLOCK && $! != WSAEWOULDBLOCK) {
             return $self->_error ($!, 1);
          }
       };
    }
 }
 
 our $ERROR_SYSCALL;
 our $ERROR_WANT_READ;
 
 sub _tls_error {
    my ($self, $err) = @_;
 
    return $self->_error ($!, 1)
       if $err == Net::SSLeay::ERROR_SYSCALL ();
 
    my $err = Net::SSLeay::ERR_error_string (Net::SSLeay::ERR_get_error ());
 
    # reduce error string to look less scary
    $err =~ s/^error:[0-9a-fA-F]{8}:[^:]+:([^:]+):/\L$1: /;
 
    if ($self->{_on_starttls}) {
       (delete $self->{_on_starttls})->($self, undef, $err);
       &_freetls;
    } else {
       &_freetls;
       $self->_error (Errno::EPROTO, 1, $err);
    }
 }
 
 # poll the write BIO and send the data if applicable
 # also decode read data if possible
 # this is basiclaly our TLS state machine
 # more efficient implementations are possible with openssl,
 # but not with the buggy and incomplete Net::SSLeay.
 sub _dotls {
    my ($self) = @_;
 
    my $tmp;
 
    while (length $self->{_tls_wbuf}) {
       if (($tmp = Net::SSLeay::write ($self->{tls}, $self->{_tls_wbuf})) <= 0) {
          $tmp = Net::SSLeay::get_error ($self->{tls}, $tmp);
 
          return $self->_tls_error ($tmp)
             if $tmp != $ERROR_WANT_READ
                && ($tmp != $ERROR_SYSCALL || $!);
 
          last;
       }
 
       substr $self->{_tls_wbuf}, 0, $tmp, "";
    }
 
    while (defined ($tmp = Net::SSLeay::read ($self->{tls}))) {
       unless (length $tmp) {
          $self->{_on_starttls}
             and (delete $self->{_on_starttls})->($self, undef, "EOF during handshake"); # ???
          &_freetls;
 
          if ($self->{on_stoptls}) {
             $self->{on_stoptls}($self);
             return;
          } else {
             # let's treat SSL-eof as we treat normal EOF
             delete $self->{_rw};
             $self->{_eof} = 1;
          }
       }
 
       $self->{_tls_rbuf} .= $tmp;
       $self->_drain_rbuf;
       $self->{tls} or return; # tls session might have gone away in callback
    }
 
    $tmp = Net::SSLeay::get_error ($self->{tls}, -1); # -1 is not neccessarily correct, but Net::SSLeay doesn't tell us
    return $self->_tls_error ($tmp)
       if $tmp != $ERROR_WANT_READ
          && ($tmp != $ERROR_SYSCALL || $!);
 
    while (length ($tmp = Net::SSLeay::BIO_read ($self->{_wbio}))) {
       $self->{wbuf} .= $tmp;
       $self->_drain_wbuf;
       $self->{tls} or return; # tls session might have gone away in callback
    }
 
    $self->{_on_starttls}
       and Net::SSLeay::state ($self->{tls}) == Net::SSLeay::ST_OK ()
       and (delete $self->{_on_starttls})->($self, 1, "TLS/SSL connection established");
 }
 
 =item $handle->starttls ($tls[, $tls_ctx])
 
 Instead of starting TLS negotiation immediately when the AnyEvent::Handle
 object is created, you can also do that at a later time by calling
 C<starttls>. See the C<tls> constructor argument for general info.
 
 Starting TLS is currently an asynchronous operation - when you push some
 write data and then call C<< ->starttls >> then TLS negotiation will start
 immediately, after which the queued write data is then sent. This might
 change in future versions, so best make sure you have no outstanding write
 data when calling this method.
 
 The first argument is the same as the C<tls> constructor argument (either
 C<"connect">, C<"accept"> or an existing Net::SSLeay object).
 
 The second argument is the optional C<AnyEvent::TLS> object that is used
 when AnyEvent::Handle has to create its own TLS connection object, or
 a hash reference with C<< key => value >> pairs that will be used to
 construct a new context.
 
 The TLS connection object will end up in C<< $handle->{tls} >>, the TLS
 context in C<< $handle->{tls_ctx} >> after this call and can be used or
 changed to your liking. Note that the handshake might have already started
 when this function returns.
 
 Due to bugs in OpenSSL, it might or might not be possible to do multiple
 handshakes on the same stream. It is best to not attempt to use the
 stream after stopping TLS.
 
 This method may invoke callbacks (and therefore the handle might be
 destroyed after it returns).
 
 =cut
 
 our %TLS_CACHE; #TODO not yet documented, should we?
 
 sub starttls {
    my ($self, $tls, $ctx) = @_;
 
    Carp::croak "It is an error to call starttls on an AnyEvent::Handle object while TLS is already active, caught"
       if $self->{tls};
 
    unless (defined $AnyEvent::TLS::VERSION) {
       eval {
          require Net::SSLeay;
          require AnyEvent::TLS;
          1
       } or return $self->_error (Errno::EPROTO, 1, "TLS support not available on this system");
    }
 
    $self->{tls}     = $tls;
    $self->{tls_ctx} = $ctx if @_ > 2;
 
    return unless $self->{fh};
 
    $ERROR_SYSCALL   = Net::SSLeay::ERROR_SYSCALL     ();
    $ERROR_WANT_READ = Net::SSLeay::ERROR_WANT_READ   ();
 
    $tls = delete $self->{tls};
    $ctx = $self->{tls_ctx};
 
    local $Carp::CarpLevel = 1; # skip ourselves when creating a new context or session
 
    if ("HASH" eq ref $ctx) {
       if ($ctx->{cache}) {
          my $key = $ctx+0;
          $ctx = $TLS_CACHE{$key} ||= new AnyEvent::TLS %$ctx;
       } else {
          $ctx = new AnyEvent::TLS %$ctx;
       }
    }
    
    $self->{tls_ctx} = $ctx || TLS_CTX ();
    $self->{tls}     = $tls = $self->{tls_ctx}->_get_session ($tls, $self, $self->{peername});
 
    # basically, this is deep magic (because SSL_read should have the same issues)
    # but the openssl maintainers basically said: "trust us, it just works".
    # (unfortunately, we have to hardcode constants because the abysmally misdesigned
    # and mismaintained ssleay-module doesn't even offer them).
    # http://www.mail-archive.com/openssl-dev@openssl.org/msg22420.html
    #
    # in short: this is a mess.
    # 
    # note that we do not try to keep the length constant between writes as we are required to do.
    # we assume that most (but not all) of this insanity only applies to non-blocking cases,
    # and we drive openssl fully in blocking mode here. Or maybe we don't - openssl seems to
    # have identity issues in that area.
 #   Net::SSLeay::CTX_set_mode ($ssl,
 #      (eval { local $SIG{__DIE__}; Net::SSLeay::MODE_ENABLE_PARTIAL_WRITE () } || 1)
 #      | (eval { local $SIG{__DIE__}; Net::SSLeay::MODE_ACCEPT_MOVING_WRITE_BUFFER () } || 2));
    Net::SSLeay::CTX_set_mode ($tls, 1|2);
 
    $self->{_rbio} = Net::SSLeay::BIO_new (Net::SSLeay::BIO_s_mem ());
    $self->{_wbio} = Net::SSLeay::BIO_new (Net::SSLeay::BIO_s_mem ());
 
    Net::SSLeay::BIO_write ($self->{_rbio}, $self->{rbuf});
    $self->{rbuf} = "";
 
    Net::SSLeay::set_bio ($tls, $self->{_rbio}, $self->{_wbio});
 
    $self->{_on_starttls} = sub { $_[0]{on_starttls}(@_) }
       if $self->{on_starttls};
 
    &_dotls; # need to trigger the initial handshake
    $self->start_read; # make sure we actually do read
 }
 
 =item $handle->stoptls
 
 Shuts down the SSL connection - this makes a proper EOF handshake by
 sending a close notify to the other side, but since OpenSSL doesn't
 support non-blocking shut downs, it is not guaranteed that you can re-use
 the stream afterwards.
 
 This method may invoke callbacks (and therefore the handle might be
 destroyed after it returns).
 
 =cut
 
 sub stoptls {
    my ($self) = @_;
 
    if ($self->{tls} && $self->{fh}) {
       Net::SSLeay::shutdown ($self->{tls});
 
       &_dotls;
 
 #      # we don't give a shit. no, we do, but we can't. no...#d#
 #      # we, we... have to use openssl :/#d#
 #      &_freetls;#d#
    }
 }
 
 sub _freetls {
    my ($self) = @_;
 
    return unless $self->{tls};
 
    $self->{tls_ctx}->_put_session (delete $self->{tls})
       if $self->{tls} > 0;
    
    delete @$self{qw(_rbio _wbio _tls_wbuf _on_starttls)};
 }
 
 =item $handle->resettls
 
 This rarely-used method simply resets and TLS state on the handle, usually
 causing data loss.
 
 One case where it may be useful is when you want to skip over the data in
 the stream but you are not interested in interpreting it, so data loss is
 no concern.
 
 =cut
 
 *resettls = \&_freetls;
 
 sub DESTROY {
    my ($self) = @_;
 
    &_freetls;
 
    my $linger = exists $self->{linger} ? $self->{linger} : 3600;
 
    if ($linger && length $self->{wbuf} && $self->{fh}) {
       my $fh   = delete $self->{fh};
       my $wbuf = delete $self->{wbuf};
 
       my @linger;
 
       push @linger, AE::io $fh, 1, sub {
          my $len = syswrite $fh, $wbuf, length $wbuf;
 
          if ($len > 0) {
             substr $wbuf, 0, $len, "";
          } elsif (defined $len || ($! != EAGAIN && $! != EINTR && $! != EWOULDBLOCK && $! != WSAEWOULDBLOCK)) {
             @linger = (); # end
          }
       };
       push @linger, AE::timer $linger, 0, sub {
          @linger = ();
       };
    }
 }
 
 =item $handle->destroy
 
 Shuts down the handle object as much as possible - this call ensures that
 no further callbacks will be invoked and as many resources as possible
 will be freed. Any method you will call on the handle object after
 destroying it in this way will be silently ignored (and it will return the
 empty list).
 
 Normally, you can just "forget" any references to an AnyEvent::Handle
 object and it will simply shut down. This works in fatal error and EOF
 callbacks, as well as code outside. It does I<NOT> work in a read or write
 callback, so when you want to destroy the AnyEvent::Handle object from
 within such an callback. You I<MUST> call C<< ->destroy >> explicitly in
 that case.
 
 Destroying the handle object in this way has the advantage that callbacks
 will be removed as well, so if those are the only reference holders (as
 is common), then one doesn't need to do anything special to break any
 reference cycles.
 
 The handle might still linger in the background and write out remaining
 data, as specified by the C<linger> option, however.
 
 =cut
 
 sub destroy {
    my ($self) = @_;
 
    $self->DESTROY;
    %$self = ();
    bless $self, "AnyEvent::Handle::destroyed";
 }
 
 sub AnyEvent::Handle::destroyed::AUTOLOAD {
    #nop
 }
 
 =item $handle->destroyed
 
 Returns false as long as the handle hasn't been destroyed by a call to C<<
 ->destroy >>, true otherwise.
 
 Can be useful to decide whether the handle is still valid after some
 callback possibly destroyed the handle. For example, C<< ->push_write >>,
 C<< ->starttls >> and other methods can call user callbacks, which in turn
 can destroy the handle, so work can be avoided by checking sometimes:
 
    $hdl->starttls ("accept");
    return if $hdl->destroyed;
    $hdl->push_write (...
 
 Note that the call to C<push_write> will silently be ignored if the handle
 has been destroyed, so often you can just ignore the possibility of the
 handle being destroyed.
 
 =cut
 
 sub destroyed { 0 }
 sub AnyEvent::Handle::destroyed::destroyed { 1 }
 
 =item AnyEvent::Handle::TLS_CTX
 
 This function creates and returns the AnyEvent::TLS object used by default
 for TLS mode.
 
 The context is created by calling L<AnyEvent::TLS> without any arguments.
 
 =cut
 
 our $TLS_CTX;
 
 sub TLS_CTX() {
    $TLS_CTX ||= do {
       require AnyEvent::TLS;
 
       new AnyEvent::TLS
    }
 }
 
 =back
 
 
 =head1 NONFREQUENTLY ASKED QUESTIONS
 
 =over 4
 
 =item I C<undef> the AnyEvent::Handle reference inside my callback and
 still get further invocations!
 
 That's because AnyEvent::Handle keeps a reference to itself when handling
 read or write callbacks.
 
 It is only safe to "forget" the reference inside EOF or error callbacks,
 from within all other callbacks, you need to explicitly call the C<<
 ->destroy >> method.
 
 =item Why is my C<on_eof> callback never called?
 
 Probably because your C<on_error> callback is being called instead: When
 you have outstanding requests in your read queue, then an EOF is
 considered an error as you clearly expected some data.
 
 To avoid this, make sure you have an empty read queue whenever your handle
 is supposed to be "idle" (i.e. connection closes are O.K.). You can set
 an C<on_read> handler that simply pushes the first read requests in the
 queue.
 
 See also the next question, which explains this in a bit more detail.
 
 =item How can I serve requests in a loop?
 
 Most protocols consist of some setup phase (authentication for example)
 followed by a request handling phase, where the server waits for requests
 and handles them, in a loop.
 
 There are two important variants: The first (traditional, better) variant
 handles requests until the server gets some QUIT command, causing it to
 close the connection first (highly desirable for a busy TCP server). A
 client dropping the connection is an error, which means this variant can
 detect an unexpected detection close.
 
 To handle this case, always make sure you have a non-empty read queue, by
 pushing the "read request start" handler on it:
 
    # we assume a request starts with a single line
    my @start_request; @start_request = (line => sub {
       my ($hdl, $line) = @_;
 
       ... handle request
 
       # push next request read, possibly from a nested callback
       $hdl->push_read (@start_request);
    });
 
    # auth done, now go into request handling loop
    # now push the first @start_request
    $hdl->push_read (@start_request);
 
 By always having an outstanding C<push_read>, the handle always expects
 some data and raises the C<EPIPE> error when the connction is dropped
 unexpectedly.
 
 The second variant is a protocol where the client can drop the connection
 at any time. For TCP, this means that the server machine may run out of
 sockets easier, and in general, it means you cannot distinguish a protocl
 failure/client crash from a normal connection close. Nevertheless, these
 kinds of protocols are common (and sometimes even the best solution to the
 problem).
 
 Having an outstanding read request at all times is possible if you ignore
 C<EPIPE> errors, but this doesn't help with when the client drops the
 connection during a request, which would still be an error.
 
 A better solution is to push the initial request read in an C<on_read>
 callback. This avoids an error, as when the server doesn't expect data
 (i.e. is idly waiting for the next request, an EOF will not raise an
 error, but simply result in an C<on_eof> callback. It is also a bit slower
 and simpler:
 
    # auth done, now go into request handling loop
    $hdl->on_read (sub {
       my ($hdl) = @_;
 
       # called each time we receive data but the read queue is empty
       # simply start read the request
 
       $hdl->push_read (line => sub {
          my ($hdl, $line) = @_;
 
          ... handle request
 
          # do nothing special when the request has been handled, just
          # let the request queue go empty.
       });
    });
 
 =item I get different callback invocations in TLS mode/Why can't I pause
 reading?
 
 Unlike, say, TCP, TLS connections do not consist of two independent
 communication channels, one for each direction. Or put differently, the
 read and write directions are not independent of each other: you cannot
 write data unless you are also prepared to read, and vice versa.
 
 This means that, in TLS mode, you might get C<on_error> or C<on_eof>
 callback invocations when you are not expecting any read data - the reason
 is that AnyEvent::Handle always reads in TLS mode.
 
 During the connection, you have to make sure that you always have a
 non-empty read-queue, or an C<on_read> watcher. At the end of the
 connection (or when you no longer want to use it) you can call the
 C<destroy> method.
 
 =item How do I read data until the other side closes the connection?
 
 If you just want to read your data into a perl scalar, the easiest way
 to achieve this is by setting an C<on_read> callback that does nothing,
 clearing the C<on_eof> callback and in the C<on_error> callback, the data
 will be in C<$_[0]{rbuf}>:
 
    $handle->on_read (sub { });
    $handle->on_eof (undef);
    $handle->on_error (sub {
       my $data = delete $_[0]{rbuf};
    });
 
 Note that this example removes the C<rbuf> member from the handle object,
 which is not normally allowed by the API. It is expressly permitted in
 this case only, as the handle object needs to be destroyed afterwards.
 
 The reason to use C<on_error> is that TCP connections, due to latencies
 and packets loss, might get closed quite violently with an error, when in
 fact all data has been received.
 
 It is usually better to use acknowledgements when transferring data,
 to make sure the other side hasn't just died and you got the data
 intact. This is also one reason why so many internet protocols have an
 explicit QUIT command.
 
 =item I don't want to destroy the handle too early - how do I wait until
 all data has been written?
 
 After writing your last bits of data, set the C<on_drain> callback
 and destroy the handle in there - with the default setting of
 C<low_water_mark> this will be called precisely when all data has been
 written to the socket:
 
    $handle->push_write (...);
    $handle->on_drain (sub {
       AE::log debug => "All data submitted to the kernel.";
       undef $handle;
    });
 
 If you just want to queue some data and then signal EOF to the other side,
 consider using C<< ->push_shutdown >> instead.
 
 =item I want to contact a TLS/SSL server, I don't care about security.
 
 If your TLS server is a pure TLS server (e.g. HTTPS) that only speaks TLS,
 connect to it and then create the AnyEvent::Handle with the C<tls>
 parameter:
 
    tcp_connect $host, $port, sub {
       my ($fh) = @_;
 
       my $handle = new AnyEvent::Handle
          fh  => $fh,
          tls => "connect",
          on_error => sub { ... };
 
       $handle->push_write (...);
    };
 
 =item I want to contact a TLS/SSL server, I do care about security.
 
 Then you should additionally enable certificate verification, including
 peername verification, if the protocol you use supports it (see
 L<AnyEvent::TLS>, C<verify_peername>).
 
 E.g. for HTTPS:
 
    tcp_connect $host, $port, sub {
       my ($fh) = @_;
 
        my $handle = new AnyEvent::Handle
           fh       => $fh,
           peername => $host,
           tls      => "connect",
           tls_ctx  => { verify => 1, verify_peername => "https" },
           ...
 
 Note that you must specify the hostname you connected to (or whatever
 "peername" the protocol needs) as the C<peername> argument, otherwise no
 peername verification will be done.
 
 The above will use the system-dependent default set of trusted CA
 certificates. If you want to check against a specific CA, add the
 C<ca_file> (or C<ca_cert>) arguments to C<tls_ctx>:
 
        tls_ctx  => {
           verify          => 1,
           verify_peername => "https",
           ca_file         => "my-ca-cert.pem",
        },
 
 =item I want to create a TLS/SSL server, how do I do that?
 
 Well, you first need to get a server certificate and key. You have
 three options: a) ask a CA (buy one, use cacert.org etc.) b) create a
 self-signed certificate (cheap. check the search engine of your choice,
 there are many tutorials on the net) or c) make your own CA (tinyca2 is a
 nice program for that purpose).
 
 Then create a file with your private key (in PEM format, see
 L<AnyEvent::TLS>), followed by the certificate (also in PEM format). The
 file should then look like this:
 
    -----BEGIN RSA PRIVATE KEY-----
    ...header data
    ... lots of base64'y-stuff
    -----END RSA PRIVATE KEY-----
 
    -----BEGIN CERTIFICATE-----
    ... lots of base64'y-stuff
    -----END CERTIFICATE-----
 
 The important bits are the "PRIVATE KEY" and "CERTIFICATE" parts.  Then
 specify this file as C<cert_file>:
 
    tcp_server undef, $port, sub {
       my ($fh) = @_;
 
       my $handle = new AnyEvent::Handle
          fh       => $fh,
          tls      => "accept",
          tls_ctx  => { cert_file => "my-server-keycert.pem" },
          ...
 
 When you have intermediate CA certificates that your clients might not
 know about, just append them to the C<cert_file>.
 
 =back
 
 =head1 SUBCLASSING AnyEvent::Handle
 
 In many cases, you might want to subclass AnyEvent::Handle.
 
 To make this easier, a given version of AnyEvent::Handle uses these
 conventions:
 
 =over 4
 
 =item * all constructor arguments become object members.
 
 At least initially, when you pass a C<tls>-argument to the constructor it
 will end up in C<< $handle->{tls} >>. Those members might be changed or
 mutated later on (for example C<tls> will hold the TLS connection object).
 
 =item * other object member names are prefixed with an C<_>.
 
 All object members not explicitly documented (internal use) are prefixed
 with an underscore character, so the remaining non-C<_>-namespace is free
 for use for subclasses.
 
 =item * all members not documented here and not prefixed with an underscore
 are free to use in subclasses.
 
 Of course, new versions of AnyEvent::Handle may introduce more "public"
 member variables, but that's just life. At least it is documented.
 
 =back
 
 =head1 AUTHOR
 
 Robin Redeker C<< <elmex at ta-sa.org> >>, Marc Lehmann <schmorp@schmorp.de>.
 
 =cut
 
 1
 
### AnyEvent/IO.pm ###
 =head1 NAME
 
 AnyEvent::IO - the DBI of asynchronous I/O implementations
 
 =head1 SYNOPSIS
 
    use AnyEvent::IO;
 
    # load /etc/passwd, call clalback with the file data when done.
    aio_load "/etc/passwd", sub {
       my ($data) = @_
          or return AE::log error => "/etc/passwd: $!";
 
       warn "/etc/passwd contains ", ($data =~ y/://) , " colons.\n";
    };
 
    # the rest of the SYNOPSIS does the same, but with individual I/O calls
 
    # also import O_XXX flags
    use AnyEvent::IO qw(:DEFAULT :flags);
 
    my $filedata = AE::cv;
 
    # first open the file
    aio_open "/etc/passwd", O_RDONLY, 0, sub {
       my ($fh) = @_
          or return AE::log error => "/etc/passwd: $!";
 
       # now stat the file to get the size
       aio_stat $fh, sub {
          @_
             or return AE::log error => "/etc/passwd: $!";
 
          my $size = -s _;
 
          # now read all the file data
          aio_read $fh, $size, sub {
             my ($data) = @_
                or return AE::log error => "/etc/passwd: $!";
 
             $size == length $data
                or return AE::log error => "/etc/passwd: short read, file changed?";
 
             # mostly the same as aio_load, above - $data contains
             # the file contents now.
             $filedata->($data);
          };
       };
    };
 
    my $passwd = $filedata->recv;
    warn length $passwd, " octets.\n";
 
 =head1 DESCRIPTION
 
 This module provides functions that do I/O in an asynchronous fashion. It
 is to I/O the same as L<AnyEvent> is to event libraries - it only
 I<interfaces> to other implementations or to a portable pure-perl
 implementation (which does not, however, do asynchronous I/O).
 
 The only other implementation that is supported (or even known to the
 author) is L<IO::AIO>, which is used automatically when it can be loaded
 (via L<AnyEvent::AIO>, which also needs to be installed). If it is not
 available, then L<AnyEvent::IO> falls back to its synchronous pure-perl
 implementation.
 
 Unlike L<AnyEvent>, which model to use is currently decided at module load
 time, not at first use. Future releases might change this.
 
 =head2 RATIONALE
 
 While disk I/O often seems "instant" compared to, say, socket I/O, there
 are many situations where your program can block for extended time periods
 when doing disk I/O. For example, you access a disk on an NFS server and
 it is gone - can take ages to respond again, if ever. Or your system is
 extremely busy because it creates or restores a backup - reading data from
 disk can then take seconds. Or you use Linux, which for so many years has
 a close-to-broken VM/IO subsystem that can often induce minutes or more of
 delay for disk I/O, even under what I would consider light I/O loads.
 
 Whatever the situation, some programs just can't afford to block for long
 times (say, half a second or more), because they need to respond as fast
 as possible.
 
 For those cases, you need asynchronous I/O.
 
 The problem is, AnyEvent itself sometimes reads disk files (for example,
 when looking at F</etc/hosts>), and under the above situations, this can
 bring your program to a complete halt even if your program otherwise
 takes care to only use asynchronous I/O for everything (e.g. by using
 L<IO::AIO>).
 
 On the other hand, requiring L<IO::AIO> for AnyEvent is clearly
 impossible, as AnyEvent promises to stay pure-perl, and the overhead of
 IO::AIO for small programs would be immense, especially when asynchronous
 I/O isn't even needed.
 
 Clearly, this calls for an abstraction layer, and that is what you are
 looking at right now :-)
 
 =head2 ASYNCHRONOUS VS. NON-BLOCKING
 
 Many people are continuously confused on what the difference is between
 asynchronous I/O and non-blocking I/O. In fact, those two terms are
 not well defined, which often makes it hard to even talk about the
 difference. Here is a short guideline that should leave you less
 confused. It only talks about read operations, but the reasoning works
 with other I/O operations as well.
 
 Non-blocking I/O means that data is delivered by some external means,
 automatically - that is, something I<pushes> data towards your file
 handle, without you having to do anything. Non-blocking means that if
 your operating system currently has no data (or EOF, or some error)
 available for you, it will not wait ("block") as it would normally do,
 but immediately return with an error (e.g. C<EWOULDBLOCK> - "I would have
 blocked, but you forbid it").
 
 Your program can then wait for data to arrive by other means, for example,
 an I/O watcher which tells you when to re-attempt the read, after which it
 can try to read again, and so on.
 
 Often, you would expect this to work for disk files as well - if the data
 isn't already in memory, one might want to wait for it and then re-attempt
 the read for example. While this is sound reasoning, the POSIX API does
 not support this, because disk drives and file systems do not send data
 "on their own", and more so, the OS already knows that data is there, it
 doesn't need to "wait" until it arrives from some external entity, it only
 needs to transfer the data from disk to your memory buffer.
 
 So basically, while the concept is sound, the existing OS APIs do not
 support this. Therefore, it makes no sense to switch a disk file handle
 into non-blocking mode - it will behave exactly the same as in blocking
 mode, namely it will block until the data has been read from the disk.
 
 The alternative to non-blocking I/O that actually works with disk files
 is usually called I<asynchronous I/O>. Asynchronous, because the actual
 I/O is done while your program does something else: there is no need to
 call the read function to see if data is there, you only order the read
 once, and it will notify you when the read has finished and the data is
 your buffer - all the work is done in the background.
 
 This works with disk files, and even with sockets and other sources. It
 is, however, not very efficient when used with sources that could be
 driven in a non-blocking way, because it usually has higher overhead
 in the OS than non-blocking I/O, because it ties memory buffers for a
 potentially unlimited time and often only a limited number of operations
 can be done in parallel.
 
 That's why asynchronous I/O makes most sense when confronted with disk
 files, and non-blocking I/O only makes sense with sockets, pipes and
 similar streaming sources.
 
 =head1 IMPORT TAGS
 
 By default, this module exports all C<aio_>xxx functions. In addition,
 the following import tags can be used:
 
    :aio       all aio_* functions, same as :DEFAULT
    :flags     the fcntl open flags (O_CREAT, O_RDONLY, ...)
 
 =head1 API NOTES
 
 The functions in this module are not meant to be the most versatile or
 the highest-performers (they are not very slow either, of course). They
 are primarily meant to give users of your code the option to do the I/O
 asynchronously (by installing L<IO::AIO> and L<AnyEvent::AIO>),
 without adding a dependency on those modules.
 
 =head2 NAMING
 
 All the functions in this module implement an I/O operation, usually with
 the same or similar name as the Perl built-in that they mimic, but with
 an C<aio_> prefix. If you like you can think of the C<aio_>xxx functions as
 "AnyEvent I/O" or "Asynchronous I/O" variants of Perl built-ins.
 
 =head2 CALLING CONVENTIONS AND ERROR REPORTING
 
 Each function expects a callback as their last argument. The callback is
 usually called with the result data or result code. An error is usually
 signalled by passing no arguments to the callback, which is then free to
 look at C<$!> for the error code.
 
 This makes all of the following forms of error checking valid:
 
    aio_open ...., sub {
       my $fh = shift   # scalar assignment - will assign undef on error
          or return AE::log error => "...";
 
       my ($fh) = @_    # list assignment - will be 0 elements on error
          or return AE::log error => "...";
 
       @_               # check the number of elements directly
          or return AE::log error => "...";
 
 =head2 CAVEAT: RELATIVE PATHS
 
 When a path is specified, this path I<must be an absolute> path, unless
 you make certain that nothing in your process calls C<chdir> or an
 equivalent function while the request executes.
 
 =head2 CAVEAT: OTHER SHARED STATE
 
 Changing the C<umask> while any requests execute that create files (or
 otherwise rely on the current umask) results in undefined behaviour -
 likewise changing anything else that would change the outcome, such as
 your effective user or group ID.
 
 =head2 CALLBACKS MIGHT BE CALLED BEFORE FUNCTION RETURNS TO CALLER
 
 Unlike other functions in the AnyEvent module family, these functions
 I<may> call your callback instantly, before returning. This should not be
 a real problem, as these functions never return anything useful.
 
 =head2 BEHAVIOUR AT PROGRAM EXIT
 
 Both L<AnyEvent::IO::Perl> and L<AnyEvent::IO::IOAIO> implementations
 make sure that operations that have started will be finished on a clean
 programs exit. That makes programs work that start some I/O operations and
 then exit. For example this complete program:
 
    use AnyEvent::IO;
 
    aio_stat "path1", sub {
       aio_stat "path2", sub {
          warn "both stats done\n";
       };
    };
 
 Starts a C<stat> operation and then exits by "falling off the end" of
 the program. Nevertheless, I<both> C<stat> operations will be executed,
 as AnyEvent::IO waits for all outstanding requests to finish and you can
 start new requests from request callbacks.
 
 In fact, since L<AnyEvent::IO::Perl> is currently synchronous, the
 program will do both stats before falling off the end, but with
 L<AnyEvent::IO::IOAIO>, the program first falls of the end, then the stats
 are executed.
 
 While not guaranteed, this behaviour will be present in future versions,
 if reasonably possible (which is extreemly likely :).
 
 =cut
 
 package AnyEvent::IO;
 
 use AnyEvent (); BEGIN { AnyEvent::common_sense }
 
 use base "Exporter";
 
 our @AIO_REQ = qw(
    aio_load aio_open aio_close aio_seek aio_read aio_write aio_truncate
    aio_utime aio_chown aio_chmod aio_stat aio_lstat
    aio_link aio_symlink aio_readlink aio_rename aio_unlink
    aio_mkdir aio_rmdir aio_readdir
 );
 *EXPORT = \@AIO_REQ;
 our @FLAGS = qw(O_RDONLY O_WRONLY O_RDWR O_CREAT O_EXCL O_TRUNC O_APPEND);
 *EXPORT_OK = \@FLAGS;
 our %EXPORT_TAGS = (flags => \@FLAGS, aio => \@AIO_REQ);
 
 our $MODEL;
 
 if ($MODEL) {
    AE::log 7 => "Found preloaded IO model '$MODEL', using it.";
 } else {
    if ($ENV{PERL_ANYEVENT_IO_MODEL} =~ /^([a-zA-Z0-9:]+)$/) {
       if (eval { require "AnyEvent/IO/$ENV{PERL_ANYEVENT_IO_MODEL}.pm" }) {
          AE::log 7 => "Loaded IO model '$MODEL' (forced by \$ENV{PERL_ANYEVENT_IO_MODEL}), using it.";
       } else {
          undef $MODEL;
          AE::log 4 => "Unable to load IO model '$ENV{PERL_ANYEVENT_IO_MODEL}' (from \$ENV{PERL_ANYEVENT_IO_MODEL}):\n$@";
       }
    }
 
    unless ($MODEL) {
       if (eval { require IO::AIO; require AnyEvent::AIO; require AnyEvent::IO::IOAIO }) {
          AE::log 7 => "Autoloaded IO model 'IOAIO', using it.";
       } else {
          require AnyEvent::IO::Perl;
          AE::log 7 => "Autoloaded IO model 'Perl', using it.";
       }
    }
 }
 
 =head1 GLOBAL VARIABLES AND FUNCTIONS
 
 =over 4
 
 =item $AnyEvent::IO::MODEL
 
 Contains the package name of the backend I/O model in use - at the moment,
 this is usually C<AnyEvent::IO::Perl> or C<AnyEvent::IO::IOAIO>.
 
 =item aio_load $path, $cb->($data)
 
 Tries to open C<$path> and read its contents into memory (obviously,
 should only be used on files that are "small enough"), then passes them to
 the callback as a string.
 
 Example: load F</etc/hosts>.
 
    aio_load "/etc/hosts", sub {
       my ($hosts) = @_
          or return AE::log error => "/etc/hosts: $!";
 
       AE::log info => "/etc/hosts contains ", ($hosts =~ y/\n/), " lines\n";
    };
 
 =item aio_open $path, $flags, $mode, $cb->($fh)
 
 Tries to open the file specified by C<$path> with the O_XXX-flags
 C<$flags> (from the Fcntl module, or see below) and the mode C<$mode> (a
 good value is 0666 for C<O_CREAT>, and C<0> otherwise).
 
 The (normal, standard, perl) file handle associated with the opened file
 is then passed to the callback.
 
 This works very much like Perl's C<sysopen> function.
 
 Changing the C<umask> while this request executes results in undefined
 behaviour - likewise changing anything else that would change the outcome,
 such as your effective user or group ID.
 
 To avoid having to load L<Fcntl>, this module provides constants
 for C<O_RDONLY>, C<O_WRONLY>, C<O_RDWR>, C<O_CREAT>, C<O_EXCL>,
 C<O_TRUNC> and C<O_APPEND> - you can either access them directly
 (C<AnyEvent::IO::O_RDONLY>) or import them by specifying the C<:flags>
 import tag (see SYNOPSIS).
 
 Example: securely open a file in F</var/tmp>, fail if it exists or is a symlink.
 
    use AnyEvent::IO qw(:flags);
 
    aio_open "/var/tmp/mytmp$$", O_CREAT | O_EXCL | O_RDWR, 0600, sub {
       my ($fh) = @_
          or return AE::log error => "$! - denial of service attack?";
 
       # now we have $fh
    };
 
 =item aio_close $fh, $cb->($success)
 
 Closes the file handle (yes, close can block your process indefinitely)
 and passes a true value to the callback on success.
 
 Due to idiosyncrasies in perl, instead of calling C<close>, the file
 handle might get closed by C<dup2>'ing another file descriptor over
 it, that is, the C<$fh> might still be open, but can be closed safely
 afterwards and must not be used for anything.
 
 Example: close a file handle, and dirty as we are, do not even bother
 to check for errors.
 
    aio_close $fh, sub { };
 
 =item aio_read $fh, $length, $cb->($data)
 
 Tries to read C<$length> octets from the current position from C<$fh> and
 passes these bytes to C<$cb>. Otherwise the semantics are very much like
 those of Perl's C<sysread>.
 
 If less than C<$length> octets have been read, C<$data> will contain
 only those bytes actually read. At EOF, C<$data> will be a zero-length
 string. If an error occurs, then nothing is passed to the callback.
 
 Obviously, multiple C<aio_read>'s or C<aio_write>'s at the same time on file
 handles sharing the underlying open file description results in undefined
 behaviour, due to sharing of the current file offset (and less obviously
 so, because OS X is not thread safe and corrupts data when you try).
 
 Example: read 128 octets from a file.
 
    aio_read $fh, 128, sub {
       my ($data) = @_
          or return AE::log error "read from fh: $!";
   
       if (length $data) {
          print "read ", length $data, " octets.\n";
       } else {
          print "EOF\n";
       }
    };
 
 =item aio_seek $fh, $offset, $whence, $callback->($offs)
 
 Seeks the filehandle to the new C<$offset>, similarly to Perl's
 C<sysseek>. The C<$whence> are the traditional values (C<0> to count from
 start, C<1> to count from the current position and C<2> to count from the
 end).
 
 The resulting absolute offset will be passed to the callback on success.
 
 Example: measure the size of the file in the old-fashioned way using seek.
 
    aio_seek $fh, 0, 2, sub {
       my ($size) = @_
          or return AE::log error => "seek to end failed: $!";
 
       # maybe we need to seek to the beginning again?
       aio_seek $fh, 0, 0, sub {
          # now we are hopefully at the beginning
       };
    };
 
 =item aio_write $fh, $data, $cb->($length)
 
 Tries to write the octets in C<$data> to the current position of C<$fh>
 and passes the actual number of bytes written to the C<$cb>. Otherwise the
 semantics are very much like those of Perl's C<syswrite>.
 
 If less than C<length $data> octets have been written, C<$length> will
 reflect that. If an error occurs, then nothing is passed to the callback.
 
 Obviously, multiple C<aio_read>'s or C<aio_write>'s at the same time on file
 handles sharing the underlying open file description results in undefined
 behaviour, due to sharing of the current file offset (and less obviously
 so, because OS X is not thread safe and corrupts data when you try).
 
 =item aio_truncate $fh_or_path, $new_length, $cb->($success)
 
 Calls C<truncate> on the path or perl file handle and passes a true value
 to the callback on success.
 
 Example: truncate F</etc/passwd> to zero length - this only works on
 systems that support C<truncate>, should not be tried out for obvious
 reasons and debian will probably open yte another security bug about this
 example.
 
    aio_truncate "/etc/passwd", sub {
       @_
          or return AE::log error => "/etc/passwd: $! - are you root enough?";
    };
 
 =item aio_utime $fh_or_path, $atime, $mtime, $cb->($success)
 
 Calls C<utime> on the path or perl file handle and passes a true value to
 the callback on success.
 
 The special case of both C<$atime> and C<$mtime> being C<undef> sets the
 times to the current time, on systems that support this.
 
 Example: try to touch F<file>.
 
    aio_utime "file", undef, undef, sub { };
 
 =item aio_chown $fh_or_path, $uid, $gid, $cb->($success)
 
 Calls C<chown> on the path or perl file handle and passes a true value to
 the callback on success.
 
 If C<$uid> or C<$gid> can be specified as C<undef>, in which case the
 uid or gid of the file is not changed. This differs from Perl's C<chown>
 built-in, which wants C<-1> for this.
 
 Example: update the group of F<file> to 0 (root), but leave the owner alone.
 
    aio_chown "file", undef, 0, sub {
       @_
          or return AE::log error => "chown 'file': $!";
    };
 
 =item aio_chmod $fh_or_path, $perms, $cb->($success)
 
 Calls C<chmod> on the path or perl file handle and passes a true value to
 the callback on success.
 
 Example: change F<file> to be user/group/world-readable, but leave the other flags
 alone.
 
    aio_stat "file", sub {
       @_
          or return AE::log error => "file: $!";
 
       aio_chmod "file", (stat _)[2] & 07777 | 00444, sub { };
    };
 
 =item aio_stat $fh_or_path, $cb->($success)
 
 =item aio_lstat $path, $cb->($success)
 
 Calls C<stat> or C<lstat> on the path or perl file handle and passes a
 true value to the callback on success.
 
 The stat data will be available by C<stat>'ing the C<_> file handle
 (e.g. C<-x _>, C<stat _> and so on).
 
 Example: see if we can find the number of subdirectories of F</etc>.
 
    aio_stat "/etc", sub {
       @_
          or return AE::log error => "/etc: $!";
 
       (stat _)[3] >= 2
          or return AE::log warn => "/etc has low link count - non-POSIX filesystem?";
 
       print "/etc has ", (stat _)[3] - 2, " subdirectories.\n";
    };
 
 =item aio_link $oldpath, $newpath, $cb->($success)
 
 Calls C<link> on the paths and passes a true value to the callback on
 success.
 
 Example: link "F<file> to F<file.bak>, then rename F<file.new> over F<file>,
 to atomically replace it.
 
    aio_link "file", "file.bak", sub {
       @_
          or return AE::log error => "file: $!";
 
       aio_rename "file.new", "file", sub {
          @_
             or return AE::log error => "file.new: $!";
 
          print "file atomically replaced by file.new, backup file.bak\n";
       };
    };
 
 =item aio_symlink $oldpath, $newpath, $cb->($success)
 
 Calls C<symlink> on the paths and passes a true value to the callback on
 success.
 
 Example: create a symlink "F<slink> containing "random data".
 
    aio_symlink "random data", "slink", sub {
       @_
          or return AE::log error => "slink: $!";
    };
 
 =item aio_readlink $path, $cb->($target)
 
 Calls C<readlink> on the paths and passes the link target string to the
 callback.
 
 Example: read the symlink called Fyslink> and verify that it contains "random data".
 
   aio_readlink "slink", sub {
      my ($target) = @_
         or return AE::log error => "slink: $!";
 
      $target eq "random data"
         or AE::log critical => "omg, the world will end!";
   };
 
 =item aio_rename $oldpath, $newpath, $cb->($success)
 
 Calls C<rename> on the paths and passes a true value to the callback on
 success.
 
 See C<aio_link> for an example.
 
 =item aio_unlink $path, $cb->($success)
 
 Tries to unlink the object at C<$path> and passes a true value to the
 callback on success.
 
 Example: try to delete the file F<tmpfile.dat~>.
 
    aio_unlink "tmpfile.dat~", sub { };
 
 =item aio_mkdir $path, $perms, $cb->($success)
 
 Calls C<mkdir> on the path with the given permissions C<$perms> (when in
 doubt, C<0777> is a good value) and passes a true value to the callback on
 success.
 
 Example: try to create the directory F<subdir> and leave it to whoeveer
 comes after us to check whether it worked.
 
    aio_mkdir "subdir", 0777, sub { };
 
 =item aio_rmdir $path, $cb->($success)
 
 Tries to remove the directory at C<$path> and passes a true value to the
 callback on success.
 
 Example: try to remove the directory F<subdir> and don't give a damn if
 that fails.
 
    aio_rmdir "subdir", sub { };
 
 =item aio_readdir $path, $cb->(\@names)
 
 Reads all filenames from the directory specified by C<$path> and passes
 them to the callback, as an array reference with the names (without a path
 prefix). The F<.> and F<..> names will be filtered out first.
 
 The ordering of the file names is undefined - backends that are capable
 of it (e.g. L<IO::AIO>) will return the ordering that most likely is
 fastest to C<stat> through, and furthermore put entries that likely are
 directories first in the array.
 
 If you need best performance in recursive directory traversal or when
 looking at really big directories, you are advised to use L<IO::AIO>
 directly, specifically the C<aio_readdirx> and C<aio_scandir> functions,
 which have more options to tune performance.
 
 Example: recursively scan a directory hierarchy, silently skip diretcories
 we couldn't read and print all others.
 
    sub scan($); # visibility-in-next statement is not so useful these days
    sub scan($) {
       my ($path) = @_;
 
       aio_readdir $path, sub {
          my ($names) = @_
             or return;
 
          print "$path\n";
 
          for my $name (@$names) {
             aio_lstat "$path/$name", sub {
                scan "$path/$name"
                   if -d _;
             };
          }
       };
    }
 
    scan "/etc";
 
 =back
 
 =head1 ENVIRONMENT VARIABLES
 
 See the description of C<PERL_ANYEVENT_IO_MODEL> in the L<AnyEvent>
 manpage.
 
 =head1 AUTHOR
 
  Marc Lehmann <schmorp@schmorp.de>
  http://anyevent.schmorp.de
 
 =cut
 
 1
 
### AnyEvent/IO/IOAIO.pm ###
 =head1 NAME
 
 AnyEvent::IO::IOAIO - AnyEvent::IO backend based on IO::AIO
 
 =head1 SYNOPSIS
 
    use AnyEvent::IO;
 
 =head1 DESCRIPTION
 
 This is the L<IO::AIO>-based backend of L<AnyEvent::IO> (via
 L<AnyEvent::AIO>). All I/O operations it implements are done
 asynchronously.
 
 =head1 FUNCTIONS
 
 =over 4
 
 =cut
 
 package AnyEvent::IO::IOAIO;
 
 use AnyEvent (); BEGIN { AnyEvent::common_sense }
 our $VERSION = $AnyEvent::VERSION;
 
 package AnyEvent::IO;
 
 use IO::AIO 4.13 ();
 use AnyEvent::AIO ();
 
 our $MODEL = "AnyEvent::IO::IOAIO";
 
 sub aio_load($$) {
    my ($cb, $data) = $_[1];
    IO::AIO::aio_load $_[0], $data,                  sub { $cb->($_[0] >= 0 ? $data : ()) };
 }
 
 sub aio_open($$$$) {
    my $cb = $_[3];
    IO::AIO::aio_open $_[0], $_[1], $_[2],           sub { $cb->($_[0] or ()) };
 }
 
 sub aio_close($$) {
    my $cb = $_[1];
    IO::AIO::aio_close $_[0],                        sub { $cb->($_[0] >= 0 ? 1 : ()) };
 }
 
 sub aio_seek($$$$) {
    my ($cb) = $_[3];
    IO::AIO::aio_seek $_[0], $_[1], $_[2],           sub { $cb->($_[0] >= 0 ? $_[0] : ()) };
 }
 
 sub aio_read($$$) {
    my ($cb, $data) = $_[2];
    IO::AIO::aio_read $_[0], undef, $_[1], $data, 0, sub { $cb->($_[0] >= 0 ? $data : ()) };
 }
 
 sub aio_write($$$) {
    my $cb = $_[2];
    IO::AIO::aio_write $_[0], undef, (length $_[1]), $_[1], 0,
                                                     sub { $cb->($_[0] >= 0 ? $_[0] : ()) };
 }
 
 sub aio_truncate($$$) {
    my $cb = $_[2];
    IO::AIO::aio_truncate $_[0], $_[1],              sub { $cb->($_[0] ? () : 1) };
 }
 
 sub aio_utime($$$$) {
    my $cb = $_[3];
    IO::AIO::aio_utime $_[0], $_[1], $_[2],          sub { $cb->($_[0] ? () : 1) };
 }
 
 sub aio_chown($$$$) {
    my $cb = $_[3];
    IO::AIO::aio_chown $_[0], $_[1], $_[2],          sub { $cb->($_[0] ? () : 1) };
 }
 
 sub aio_chmod($$$) {
    my $cb = $_[2];
    IO::AIO::aio_chmod $_[0], $_[1],                 sub { $cb->($_[0] ? () : 1) };
 }
 
 sub aio_stat($$) {
    my $cb = $_[1];
    IO::AIO::aio_stat $_[0],                         sub { $cb->($_[0] ? () : 1) };
 }
 
 sub aio_lstat($$) {
    my $cb = $_[1];
    IO::AIO::aio_lstat $_[0],                        sub { $cb->($_[0] ? () : 1) }
 }
 
 sub aio_link($$$) {
    my $cb = $_[2];
    IO::AIO::aio_link $_[0], $_[1],                  sub { $cb->($_[0] ? () : 1) };
 }
 
 sub aio_symlink($$$) {
    my $cb = $_[2];
    IO::AIO::aio_symlink $_[0], $_[1],               sub { $cb->($_[0] ? () : 1) };
 }
 
 sub aio_readlink($$) {
    my $cb = $_[1];
    IO::AIO::aio_readlink $_[0],                     sub { $cb->(defined $_[0] ? $_[0] : ()) };
 }
 
 sub aio_rename($$$) {
    my $cb = $_[2];
    IO::AIO::aio_rename $_[0], $_[1],                sub { $cb->($_[0] ? () : 1) };
 }
 
 sub aio_unlink($$) {
    my $cb = $_[1];
    IO::AIO::aio_unlink $_[0],                       sub { $cb->($_[0] ? () : 1) };
 }
 
 sub aio_mkdir($$$) {
    my $cb = $_[2];
    IO::AIO::aio_mkdir $_[0], $_[1],                 sub { $cb->($_[0] ? () : 1) };
 }
 
 sub aio_rmdir($$) {
    my $cb = $_[1];
    IO::AIO::aio_rmdir $_[0],                        sub { $cb->($_[0] ? () : 1) };
 }
 
 sub aio_readdir($$) {
    my $cb = $_[1];
 
    IO::AIO::aio_readdirx $_[0], IO::AIO::READDIR_DIRS_FIRST | IO::AIO::READDIR_STAT_ORDER,
                                                     sub { $cb->($_[0] or ()); };
 }
 
 =back
 
 =head1 SEE ALSO
 
 L<AnyEvent::IO>, L<AnyEvent>.
 
 =head1 AUTHOR
 
  Marc Lehmann <schmorp@schmorp.de>
  http://anyevent.schmorp.de
 
 =cut
 
 1
 
### AnyEvent/IO/Perl.pm ###
 =head1 NAME
 
 AnyEvent::IO::Perl - pure perl backend for AnyEvent::IO
 
 =head1 SYNOPSIS
 
    use AnyEvent::IO;
 
 =head1 DESCRIPTION
 
 This is the pure-perl backend of L<AnyEvent::IO> - it is always available,
 but does not actually implement any I/O operation asynchronously -
 everything is synchronous.
 
 For simple programs that can wait for I/O, this is likely the most
 efficient implementation.
 
 =cut
 
 package AnyEvent::IO::Perl;
 
 use AnyEvent (); BEGIN { AnyEvent::common_sense }
 our $VERSION = $AnyEvent::VERSION;
 
 package AnyEvent::IO;
 
 our $MODEL = "AnyEvent::IO::Perl";
 
 sub aio_load($$) {
    my ($path, $cb, $fh, $data) = @_;
 
    $cb->(
       (open $fh, "<:raw:perlio", $path
          and stat $fh
          and (-s _) == sysread $fh, $data, -s _)
       ? $data : ()
    );
 }
 
 sub aio_open($$$$) {
    sysopen my $fh, $_[0], $_[1], $_[2]
       or return $_[3]();
 
    $_[3]($fh)
 }
 
 sub aio_close($$) {
    $_[1](close $_[0]);
 }
 
 sub aio_seek($$$$) {
    my $data;
    $_[3](sysseek $_[0], $_[1], $_[2] or ());
 }
 
 sub aio_read($$$) {
    my $data;
    $_[2]( (defined sysread $_[0], $data, $_[1]) ? $data : () );
 }
 
 sub aio_write($$$) {
    my $res = syswrite $_[0], $_[1];
    $_[2](defined $res ? $res : ());
 }
 
 sub aio_truncate($$$) {
    #TODO: raises an exception on !truncate|ftruncate systems, maybe eval + set errno?
    $_[2](truncate $_[0], $_[1] or ());
 }
 
 sub aio_utime($$$$) {
    $_[3](utime $_[1], $_[2], $_[0] or ());
 }
 
 sub aio_chown($$$$) {
    $_[3](chown defined $_[1] ? $_[1] : -1, defined $_[2] ? $_[2] : -1, $_[0] or ());
 }
 
 sub aio_chmod($$$) {
    $_[2](chmod $_[1], $_[0] or ());
 }
 
 sub aio_stat($$) {
    $_[1](stat  $_[0]);
 }
 
 sub aio_lstat($$) {
    $_[1](lstat $_[0]);
 }
 
 sub aio_link($$$) {
    $_[2](link $_[0], $_[1] or ());
 }
 
 sub aio_symlink($$$) {
    #TODO: raises an exception on !symlink systems, maybe eval + set errno?
    $_[2](symlink $_[0], $_[1] or ());
 }
 
 sub aio_readlink($$) {
    #TODO: raises an exception on !symlink systems, maybe eval + set errno?
    my $res = readlink $_[0];
    $_[1](defined $res ? $res : ());
 }
 
 sub aio_rename($$$) {
    $_[2](rename $_[0], $_[1] or ());
 }
 
 sub aio_unlink($$) {
    $_[1](unlink $_[0] or ());
 }
 
 sub aio_mkdir($$$) {
    $_[2](mkdir $_[0], $_[1] or ());
 }
 
 sub aio_rmdir($$) {
    $_[1](rmdir $_[0] or ());
 }
 
 sub aio_readdir($$) {
    my ($fh, @res);
 
    opendir $fh, $_[0]
       or return $_[1]();
 
    @res = grep !/^\.\.?$/, readdir $fh;
 
    $_[1]((closedir $fh) ? \@res : ());
 }
 
 =head1 SEE ALSO
 
 L<AnyEvent::IO>, L<AnyEvent>.
 
 =head1 AUTHOR
 
  Marc Lehmann <schmorp@schmorp.de>
  http://anyevent.schmorp.de
 
 =cut
 
 1
 
### AnyEvent/Impl/Cocoa.pm ###
 =head1 NAME
 
 AnyEvent::Impl::Cocoa - AnyEvent adaptor for Cocoa::EventLoop
 
 =head1 SYNOPSIS
 
     use AnyEvent;
     use Cocoa::EventLoop;
     
     # do something
 
 =head1 DESCRIPTION
 
 This module provides NSRunLoop support to AnyEvent.
 
 NSRunLoop is an event loop for Cocoa applications, wrapped by
 L<Cocoa::EventLoop>. By using this module, you can use Cocoa based API in
 your AnyEvent application, or AnyEvent within Cocoa applications.
 
 It does not support blocking waits.
 
 =head1 BUGS
 
 Right now, L<Cocoa::EventLoop> (and this module) are in an early
 development phase and has some shortcomings and likely bugs.
 
 For example, there seems to be no way to just handle a single event
 with Cocoa (is there nothing they can implement properly?), so this
 module currently wakes up at least ten times a second when waiting for
 events. Also, events caused by timers might get delayed by up to 0.1
 seconds.
 
 =cut
 
 package AnyEvent::Impl::Cocoa;
 
 use AnyEvent (); BEGIN { AnyEvent::common_sense }
 
 use Cocoa::EventLoop;
 
 sub io {
    my ($class, %arg) = @_;
 
    Cocoa::EventLoop->io (%arg)
 }
 
 sub timer {
    my ($class, %arg) = @_;
 
    Cocoa::EventLoop->timer (%arg)
 }
 
 # does not support blocking waits
 
 #sub loop {
 #   Cocoa::EventLoop->run;
 #}
 
 =head1 AUTHORS
 
 Daisuke Murase <typester@cpan.org>, Marc Lehmann <schmorp@schmorp.de>.
 
 =head1 COPYRIGHTS
 
    Copyright (c) 2009 by KAYAC Inc.
    Copyright (c) 2010,2011 by Marc Lehmann <schmorp@schmorp.de>
 
 =cut
 
 1
 
### AnyEvent/Impl/EV.pm ###
 =head1 NAME
 
 AnyEvent::Impl::EV - AnyEvent adaptor for EV
 
 =head1 SYNOPSIS
 
    use AnyEvent;
    use EV;
   
    # this module gets loaded automatically as required
 
 =head1 DESCRIPTION
 
 This module provides transparent support for AnyEvent. You don't have to
 do anything to make EV work with AnyEvent except by loading EV before
 creating the first AnyEvent watcher.
 
 EV is the fastest event library for perl, and best supported by
 AnyEvent. Most functions from the L<AE> API are implemented as direct
 aliases to EV functions, so using EV via AE is as fast as using EV
 directly.
 
 =cut
 
 package AnyEvent::Impl::EV;
 
 use AnyEvent (); BEGIN { AnyEvent::common_sense }
 use EV 4.00;
 
 *AE::time       = \&EV::time;
 *AE::now        = \&EV::now;
 *AE::now_update = \&EV::now_update;
 *AE::timer      = \&EV::timer;
 *AE::signal     = \&EV::signal;
 *AE::idle       = \&EV::idle;
 
 # cannot override directly, as EV doesn't allow arguments
 sub time       { EV::time       }
 sub now        { EV::now        }
 sub now_update { EV::now_update }
 
 *AE::io = defined &EV::_ae_io # 3.8+, but keep just in case it is dropped
    ? \&EV::_ae_io
    : sub($$$) { EV::io $_[0], $_[1] ? EV::WRITE : EV::READ, $_[2] };
 
 sub timer {
    my ($class, %arg) = @_;
 
    EV::timer $arg{after}, $arg{interval}, $arg{cb}
 }
 
 sub io {
    my ($class, %arg) = @_;
 
    EV::io
       $arg{fh},
       $arg{poll} eq "r" ? EV::READ : EV::WRITE,
       $arg{cb}
 }
 
 sub signal {
    my ($class, %arg) = @_;
 
    EV::signal $arg{signal}, $arg{cb}
 }
 
 sub child {
    my ($class, %arg) = @_;
 
    my $cb = $arg{cb};
 
    EV::child $arg{pid}, 0, sub {
       $cb->($_[0]->rpid, $_[0]->rstatus);
    }
 }
 
 sub idle {
    my ($class, %arg) = @_;
 
    EV::idle $arg{cb}
 }
 
 sub _poll {
    EV::run EV::RUN_ONCE;
 }
 
 sub AnyEvent::CondVar::Base::_wait {
    EV::run EV::RUN_ONCE until exists $_[0]{_ae_sent};
 }
 
 #sub loop {
 #   EV::run;
 #}
 
 =head1 SEE ALSO
 
 L<AnyEvent>, L<EV>.
 
 =head1 AUTHOR
 
  Marc Lehmann <schmorp@schmorp.de>
  http://anyevent.schmorp.de
 
 =cut
 
 1
 
### AnyEvent/Impl/Event.pm ###
 =head1 NAME
 
 AnyEvent::Impl::Event - AnyEvent adaptor for Event
 
 =head1 SYNOPSIS
 
    use AnyEvent;
    use Event;
   
    # this module gets loaded automatically as required
 
 =head1 DESCRIPTION
 
 This module provides transparent support for AnyEvent. You don't have to
 do anything to make Event work with AnyEvent except by loading Event before
 creating the first AnyEvent watcher.
 
 The event module is reasonably efficient and generally works correctly
 even with many watchers, except that its signal handling is inherently
 racy and requires the wake-up-frequently workaround.
 
 =cut
 
 package AnyEvent::Impl::Event;
 
 use AnyEvent (); BEGIN { AnyEvent::common_sense }
 use Event qw(unloop); # we have to import something to make Event use Time::HiRes
 
 sub io {
    my (undef, %arg) = @_;
    $arg{fd} = delete $arg{fh};
    $arg{poll} .= "e" if AnyEvent::WIN32; # work around windows connect bug
    my $cb = $arg{cb}; $arg{cb} = sub { &$cb }; # event doesn't like callable objects
    bless \(Event->io (%arg)), __PACKAGE__
 }
 
 sub timer {
    my (undef, %arg) = @_;
    $arg{after} = 0 if $arg{after} < 0;
    my $cb = $arg{cb}; $arg{cb} = sub { &$cb }; # event doesn't like callable objects
    bless \Event->timer (%arg, repeat => $arg{interval}), __PACKAGE__
 }
 
 sub idle {
    my (undef, %arg) = @_;
    my $cb = $arg{cb}; $arg{cb} = sub { &$cb }; # event doesn't like callable objects
    bless \Event->idle (repeat => 1, min => 0, %arg), __PACKAGE__
 }
 
 sub DESTROY {
    ${$_[0]}->cancel;
 }
 
 sub signal {
    my (undef, %arg) = @_;
 
    my $cb = $arg{cb};
    my $w = Event->signal (
       signal => AnyEvent::Base::sig2name $arg{signal},
       cb     => sub { &$cb }, # event doesn't like callable objects
    );
 
    AnyEvent::Base::_sig_add;
    bless \$w, "AnyEvent::Impl::Event::signal"
 }
 
 sub AnyEvent::Impl::Event::signal::DESTROY {
    AnyEvent::Base::_sig_del;
    ${$_[0]}->cancel;
 }
 
 sub _poll {
    Event::one_event;
 }
 
 sub AnyEvent::CondVar::Base::_wait {
    Event::one_event until exists $_[0]{_ae_sent};
 }
 
 #sub loop {
 #   Event::loop;
 #}
 
 =head1 SEE ALSO
 
 L<AnyEvent>, L<Event>.
 
 =head1 AUTHOR
 
  Marc Lehmann <schmorp@schmorp.de>
  http://anyevent.schmorp.de
 
 =cut
 
 1
 
### AnyEvent/Impl/EventLib.pm ###
 =head1 NAME
 
 AnyEvent::Impl::EventLib - AnyEvent adaptor for Event::Lib
 
 =head1 SYNOPSIS
 
    use AnyEvent;
    use Event::Lib;
   
    # this module gets loaded automatically as required
 
 =head1 DESCRIPTION
 
 This module provides transparent support for AnyEvent. You don't have to
 do anything to make Event work with AnyEvent except by loading Event::Lib
 before creating the first AnyEvent watcher.
 
 Note: the AnyEvent author has not found recent releases of Event::Lib to
 be even remotely working (not even the examples from the manpage or the
 testsuite work), so this event backend should be avoided (or somebody
 should step up and maintain it, hint, hint).
 
 The L<Event::Lib> module suffers from the same limitations and bugs as
 libevent, most notably it kills already-installed watchers on a file
 descriptor and it is unable to support fork. These are not fatal issues,
 and are worked-around by this module, but the L<Event::Lib> perl module
 itself has many additional bugs such as taking references to file handles
 and callbacks instead of making a copy or freeing still-allocated scalars,
 causing memory corruption and random crashes. Only Tk rivals it in its
 brokenness.
 
 This adaptor module employs the same workaround around the watcher
 problems as Tk and should therefore be avoided. (This was done for
 simplicity, one could in theory work around the problems with lower
 overhead by managing our own watchers).
 
 Event::Lib also leaks file handles and memory and tends to just exit on
 problems.
 
 It also doesn't work around the Windows bug of not signalling TCP
 connection failures.
 
 It also doesn't work with many special devices on Linux (F</dev/random>
 works, F</dev/urandom> fails, F</dev/tty> works, F</dev/null> fails and so
 on).
 
 Event::Lib does not support idle watchers. They could be emulated using
 low-priority timers but as the priority range (and availability) is not
 queryable nor guaranteed, and the default priority is likely the lowest
 one, this module cannot use them.
 
 Avoid Event::Lib if you can.
 
 =cut
 
 package AnyEvent::Impl::EventLib;
 
 use AnyEvent (); BEGIN { AnyEvent::common_sense }
 
 use Event::Lib;
 
 # Event::Lib doesn't always take a reference to the callback, so closures
 # cause memory corruption and segfaults. it also has an issue actually
 # calling callbacks, so this exists as workaround.
 sub ccb {
    # Event:Lib accesses $_[0] after the callback, when it might be freed,
    # so we keep it referenced until after the callback. This still accesses
    # a freed scalar, but at least it'll not crash.
    my $keep_it = $_[0];
 
    $_[2]();
 }
 
 my $ccb = \&ccb;
 
 sub io {
    my (undef, %arg) = @_;
 
    # work around these bugs in Event::Lib:
    # - adding a callback might destroy other callbacks
    # - only one callback per fd/poll combination
    my ($fh, $mode) = AnyEvent::_dupfh $arg{poll}, $arg{fh}, EV_READ, EV_WRITE;
 
    # event_new errornously takes a reference to fh and cb instead of making a copy
    # fortunately, going through %arg/_dupfh already makes a copy, so it happpens to work
    my $w = event_new $fh, $mode | EV_PERSIST, $ccb, $arg{cb};
    event_add $w;
    bless \\$w, __PACKAGE__
 }
 
 sub timer {
    my (undef, %arg) = @_;
 
    my $ival = $arg{interval};
    my $cb   = $arg{cb};
 
    my $w; $w = timer_new $ccb,
                   $ival
                      ? sub { event_add $w, $ival; &$cb }
                      : sub { undef $w           ; &$cb };
 
    event_add $w, $arg{after} || 1e-10; # work around 0-bug in Event::Lib
 
    bless \\$w, __PACKAGE__
 }
 
 sub DESTROY {
    local $@;
    ${${$_[0]}}->remove;
 }
 
 sub signal {
    my (undef, %arg) = @_;
 
    my $w = signal_new AnyEvent::Base::sig2num $arg{signal}, $ccb, $arg{cb};
    event_add $w;
    AnyEvent::Base::_sig_add;
    bless \\$w, "AnyEvent::Impl::EventLib::signal"
 }
 
 sub AnyEvent::Impl::EventLib::signal::DESTROY {
    AnyEvent::Base::_sig_del;
    local $@;
    ${${$_[0]}}->remove;
 }
 
 #sub loop {
 #   event_mainloop;
 #}
 
 sub _poll {
    event_one_loop;
 }
 
 sub AnyEvent::CondVar::Base::_wait {
    event_one_loop until exists $_[0]{_ae_sent};
 }
 
 =head1 SEE ALSO
 
 L<AnyEvent>, L<Event::Lib>.
 
 =head1 AUTHOR
 
  Marc Lehmann <schmorp@schmorp.de>
  http://anyevent.schmorp.de
 
 =cut
 
 1
 
### AnyEvent/Impl/FLTK.pm ###
 =head1 NAME
 
 AnyEvent::Impl::FLTK - AnyEvent adaptor for FLTK (Fast Light Toolkit version two)
 
 =head1 SYNOPSIS
 
    use AnyEvent;
    use FLTK;
   
    # this module gets loaded automatically as required
 
 =head1 DESCRIPTION
 
 This module provides transparent support for AnyEvent. You don't have to
 do anything to make FLTK work with AnyEvent except by loading FLTK before
 creating the first AnyEvent watcher.
 
 This implementation is not to be confused with AnyEvent::Impl::FLTK by
 Sanko Robinson. That implementation is completely broken, and the author
 is apparently unreachable.
 
 In any case, FLTK suffers from typical GUI-ToolKit diseases, such as O(n)
 or worse for every operation (adding a timer, destroying a timer etc.),
 the typical Not-Well-Tested Perl Interface disases such as non-random
 memory corruption and the typical Event-Loop-as-an-Afterthrough issues,
 such as multiple watchers on the same fd silently overwriting the others.
 
 It doesn't have native idle, signal or child watchers, so all of these are
 emulated.
 
 =cut
 
 package AnyEvent::Impl::FLTK;
 
 use AnyEvent (); BEGIN { AnyEvent::common_sense }
 use FLTK 0.532 ();
 use Scalar::Util ();
 
 #*AE::timer      = \&EV::timer;
 #*AE::signal     = \&EV::signal;
 #*AE::idle       = \&EV::idle;
 
 # FLTK::get_time_secs returns a glob :/
 # on unix, fltk uses gettimeofday, so we are likely compatible
 # on windows, fltk uses GetTickCount, to which we are unlikely to be compatible with.
 #sub time { FLTK::get_time_secs }
 #*now = \&time;
 
 sub timer_interval_cb {
    my $id = shift; # add_timeout kills @_, so we have to make a copy :(
    $id->[0] = FLTK::add_timeout $id->[1], \&timer_interval_cb, $id;
    &{ $id->[2] }
 }
 
 sub timer {
    my ($class, %arg) = @_;
 
    my $cb = $arg{cb};
 
    if ($arg{interval}) {
       my $id = [undef, $arg{interval}, $cb];
 
       $id->[0] = FLTK::add_timeout $arg{after}, \&timer_interval_cb, $id;
 
       return bless $id, "AnyEvent::Impl::FLTK::timer"
    } else {
       # non-repeating timers can be done very efficiently
       # also, FLTK doesn't like callable objects
       return FLTK::add_timeout $arg{after}, sub { &$cb }
    }
 }
 
 sub AnyEvent::Impl::FLTK::timer::DESTROY {
    undef $_[0][0];
 }
 
 sub io {
    my ($class, %arg) = @_;
 
    # only one watcher/fd :(
 
    my $cb = $arg{cb};
    my ($fh, $ev) = AnyEvent::_dupfh $arg{poll}, $arg{fh},
       FLTK::READ,
       FLTK::WRITE | (AnyEvent::WIN32 ? FLTK::EXCEPT : 0);
 
    # fltk hardcodes poll constants and aliases EXCEPT with POLLERR,
    # which is grossly wrong, but likely it doesn't use poll on windows.
    FLTK::add_fd $fh, $ev, sub { &$cb }
 }
 
 # use signal and child emulation - fltk has no facilities for that
 
 # fltk idle watchers are like EV::check watchers, and fltk check watchers
 # are like EV::prepare watchers. both are called when the loop is busy,
 # so we have to use idle watcher emulation.
 
 sub _poll {
    FLTK::wait;
 }
 
 sub AnyEvent::CondVar::Base::_wait {
    FLTK::wait until exists $_[0]{_ae_sent};
 }
 
 #sub loop {
 #   FLTK::run;
 #}
 
 =head1 SEE ALSO
 
 L<AnyEvent>, L<FLTK>.
 
 =head1 AUTHOR
 
  Marc Lehmann <schmorp@schmorp.de>
  http://anyevent.schmorp.de
 
 =cut
 
 1
 
### AnyEvent/Impl/Glib.pm ###
 =head1 NAME
 
 AnyEvent::Impl::Glib - AnyEvent adaptor for Glib
 
 =head1 SYNOPSIS
 
    use AnyEvent;
    use Glib;
   
    # this module gets loaded automatically as required
 
 =head1 DESCRIPTION
 
 This module provides transparent support for AnyEvent. You don't have to
 do anything to make Glib work with AnyEvent except by loading Glib before
 creating the first AnyEvent watcher.
 
 Glib is probably the most inefficient event loop that has ever seen the
 light of the world: Glib not only scans all its watchers (really, ALL of
 them, whether I/O-related, timer-related or what not) during each loop
 iteration, it also does so multiple times and rebuilds the poll list for
 the kernel each time again, dynamically even. Newer versions of libglib
 fortunately do not call malloc/free on every single watcher invocation,
 though.
 
 Glib also enforces certain undocumented behaviours, for example, you
 cannot always remove active child watchers, and the conditions on when
 it is valid to do so are not documented. Of course, if you get it wrong,
 you get "GLib-CRITICAL" messages. This makes it extremely hard to write
 "correct" glib programs, as you have to study the source code to get it
 right, and hope future versions don't change any internals.
 
 AnyEvent implements the necessary workarounds, at a small performance
 cost.
 
 On the positive side, and most importantly, when it works, Glib generally
 works correctly, no quarrels there.
 
 If you create many watchers (as in: more than two), you might consider one
 of the L<Glib::EV>, L<EV::Glib> or L<Glib::Event> modules that map Glib to
 other, more efficient, event loops.
 
 This module uses the default Glib main context for all its watchers.
 
 =cut
 
 package AnyEvent::Impl::Glib;
 
 use AnyEvent (); BEGIN { AnyEvent::common_sense }
 use Glib 1.210 (); # (stable 1.220 2009, also Glib 2.4+ required, 2004)
 
 our $mainloop = Glib::MainContext->default;
 
 my %io_cond = (
    r => ["in" , "hup"],
    w => ["out", "hup"],
 );
 
 sub io {
    my ($class, %arg) = @_;
    
    my $cb = $arg{cb};
    my $fd = fileno $arg{fh};
    defined $fd or $fd = $arg{fh};
 
    my $source = add_watch Glib::IO
       $fd,
       $io_cond{$arg{poll}},
       sub { &$cb; 1 };
 
    bless \\$source, $class
 }
 
 sub timer {
    my ($class, %arg) = @_;
    
    my $cb   = $arg{cb};
    my $ival = $arg{interval} * 1000;
 
    my $source; $source = add Glib::Timeout $arg{after} < 0 ? 0 : $arg{after} * 1000,
       $ival ? sub {
                 remove Glib::Source $source;
                 $source = add Glib::Timeout $ival, sub { &$cb; 1 };
                 &$cb;
                 1 # already removed, should be a nop
               }
             : sub {
                # due to the braindamaged libglib API (it manages
                # removed-but-active watchers internally, but forces
                # users to # manage the same externally as well),
                # we have to go through these contortions.
                remove Glib::Source $source;
                undef $source;
                &$cb;
                1 # already removed, should be a nop
             };
 
    bless \\$source, $class
 }
 
 sub idle {
    my ($class, %arg) = @_;
    
    my $cb = $arg{cb};
    my $source = add Glib::Idle sub { &$cb; 1 };
 
    bless \\$source, $class
 }
 
 sub DESTROY {
    remove Glib::Source $${$_[0]}
       if defined $${$_[0]};
 }
 
 our %pid_w;
 our %pid_cb;
 
 sub child {
    my ($class, %arg) = @_;
 
    $arg{pid} > 0
       or Carp::croak "Glib does not support watching for all pids (pid == 0) as attempted";
 
    my $pid = $arg{pid};
    my $cb  = $arg{cb};
 
    $pid_cb{$pid}{$cb+0} = $cb;
 
    $pid_w{$pid} ||= Glib::Child->watch_add ($pid, sub {
       # the unbelievably braindamaged glib api ignores the return
       # value and always removes the watcher (this is of course
       # undocumented), so we need to go through these contortions to
       # work around this, here and in DESTROY.
       undef $pid_w{$pid};
 
       $_->($_[0], $_[1])
          for values %{ $pid_cb{$pid} };
 
       1 # gets ignored
    });
 
    bless [$pid, $cb+0], "AnyEvent::Impl::Glib::child"
 }
 
 sub AnyEvent::Impl::Glib::child::DESTROY {
    my ($pid, $icb) = @{ $_[0] };
 
    delete $pid_cb{$pid}{$icb};
    unless (%{ $pid_cb{$pid} }) {
       delete $pid_cb{$pid};
       my $source = delete $pid_w{$pid};
       remove Glib::Source if defined $source;
    }
 }
 
 #sub loop {
 #   # hackish, but we do not have a mainloop, just a maincontext
 #   $mainloop->iteration (1) while 1;
 #}
 
 sub _poll {
    $mainloop->iteration (1);
 }
 
 sub AnyEvent::CondVar::Base::_wait {
    $mainloop->iteration (1) until exists $_[0]{_ae_sent};
 }
 
 =head1 SEE ALSO
 
 L<AnyEvent>, L<Glib>.
 
 =head1 AUTHOR
 
  Marc Lehmann <schmorp@schmorp.de>
  http://anyevent.schmorp.de
 
 =cut
 
 1
 
### AnyEvent/Impl/IOAsync.pm ###
 =head1 NAME
 
 AnyEvent::Impl::IOAsync - AnyEvent adaptor for IO::Async
 
 =head1 SYNOPSIS
 
   use AnyEvent;
   use IO::Async::Loop;
 
   # optionally set another event loop
   use AnyEvent::Impl::IOAsync;
   my $loop = new IO::Async::Loop;
   AnyEvent::Impl::IOAsync::set_loop $loop;
 
 =head1 DESCRIPTION
 
 This module provides support for IO::Async as AnyEvent backend. It supports
 I/O, timers, signals and child process watchers. Idle watchers are emulated.
 I/O watchers need to dup their fh because IO::Async only supports IO handles,
 not plain file descriptors.
 
 =head1 FUNCTIONS AND VARIABLES
 
 The only user-servicible part in this module is the C<set_loop> function
 and C<$LOOP> variable:
 
 =over 4
 
 =item AnyEvent::Impl::IOAsync::set_loop $new_loop
 
 Unfortunately, IO::Async has no concept of a default loop. Modules using
 IO::Async must be told by their caller which loop to use, which makes it
 impossible to transparently use IO::Async from a module.
 
 This module is no exception. It creates a new IO::Async::Loop object when
 it is loaded. This might not be the right loop object, though, and thus
 you can replace it by a call to this function with the loop object of your
 choice.
 
 Note that switching loops while watchers are already initialised can have
 unexpected effects, and is not supported unless you can live witht he
 consequences.
 
 =item $AnyEvent::Impl::IOAsync::LOOP
 
 This variable always contains the IO::Async::Loop object used by this
 AnyEvent backend. See above for more info.
 
 Storing the "default" loop makes this module a possible arbiter for other
 modules that want to use IO::Async transparently. It's advised to directly
 refer to this variable each time you want to use it, without making a
 local copy.
 
 =back
 
 =head1 PROBLEMS WITH IO::Async
 
 This section had a long list of problems and shortcomings that made it
 almost impossible to support L<IO::Async>. With version 0.33 of IO::Async,
 however, most of these have been fixed, so L<IO::Async> can now be used as
 easily as many other loops.
 
 There are a few remaining problems that require emulation or workarounds:
 
 =over 4
 
 =item No support for multiple watchers per event
 
 In most (all? documentation?) cases you cannot have multiple watchers
 for the same event (what's the point of having all these fancy notifier
 classes when you cannot have multiple notifiers for the same event? That's
 like only allowing one timer per second or so...).
 
 For I/O watchers, AnyEvent has to dup() every file handle, as IO::Async
 fails to support the same or different file handles pointing to the same
 fd (the good thing is that it is documented, but why not fix it instead?).
 
 =back
 
 Apart from these fatal flaws, there are a number of unpleasent properties
 that just need some mentioning:
 
 =over 4
 
 =item Confusing and misleading names
 
 Another rather negative point about this module family is its name,
 which is deeply confusing: Despite the "async" in the name, L<IO::Async>
 only does I<synchronous> I/O, there is nothing "asynchronous" about it
 whatsoever (when I first heard about it, I thought, "wow, a second async
 I/O module, what does it do compared to L<IO::AIO>", and was somehow set
 back when I learned that the only "async" aspect of it is the name).
 
 =item Inconsistent, incomplete and convoluted API
 
 Implementing AnyEvent's rather simple timers on top of IO::Async's timers
 was a nightmare (try implementing a timer with configurable interval and
 delay value...).
 
 The method naming is chaotic: C<watch_child> creates a child watcher,
 but C<watch_io> is an internal method; C<detach_signal> removes a signal
 watcher, but C<detach_child> forks a subprocess and so on).
 
 =item Unpleasant surprises on GNU/Linux
 
 When you develop your program on FreeBSD and run it on GNU/Linux, you
 might have unpleasant surprises, as IO::Async::Loop will by default use
 L<IO::Async::Loop::Epoll>, which is incompatible with C<fork>, so your
 network server will run into spurious and very hard to debug problems
 under heavy load, as IO::Async forks a lot of processes, e.g. for DNS
 resolution. It would be better if IO::Async would only load "safe"
 backends by default (or fix the epoll backend to work in the presence of
 fork, which admittedly is hard - EV does it for you, and also does not use
 unsafe backends by default).
 
 =back
 
 On the positive side, performance with IO::Async is quite good even in my
 very demanding eyes.
 
 =cut
 
 package AnyEvent::Impl::IOAsync;
 
 use AnyEvent (); BEGIN { AnyEvent::common_sense }
 
 use Time::HiRes ();
 use Scalar::Util ();
 
 use IO::Async::Loop 0.33;
 
 our $LOOP = new IO::Async::Loop;
 
 sub set_loop($) {
    $LOOP = $_[0];
 }
 
 sub timer {
    my ($class, %arg) = @_;
    
    my $cb = $arg{cb};
 
    my $id;
 
    if (my $ival = $arg{interval}) {
       my $ival_cb; $ival_cb = sub {
          $id = $LOOP->enqueue_timer (delay => $ival, code => $ival_cb);
          &$cb;
       };
       $id = $LOOP->enqueue_timer (delay => $arg{after}, code => $ival_cb);
 
       # we have to weaken afterwards, but when enqueue dies, we have a memleak.
       # still, we do anything for speed...
       Scalar::Util::weaken $ival_cb;
 
    } else {
       # IO::Async has problems with overloaded objects
       $id = $LOOP->enqueue_timer (delay => $arg{after}, code => sub {
          undef $id; # IO::Async <= 0.43 bug workaround
          &$cb;
       });
    }
 
    bless \\$id, "AnyEvent::Impl::IOAsync::timer"
 }
 
 sub AnyEvent::Impl::IOAsync::timer::DESTROY {
    # Need to be well-behaved during global destruction
    $LOOP->cancel_timer (${${$_[0]}})
       if defined ${${$_[0]}}; # IO::Async <= 0.43 bug workaround
 }
 
 sub io {
    my ($class, %arg) = @_;
 
    # Ensure we have a real IO handle, and not just a UNIX fd integer
    my ($fh) = AnyEvent::_dupfh $arg{poll}, $arg{fh};
 
    my $event = $arg{poll} eq "r" ? "on_read_ready" : "on_write_ready";
 
    $LOOP->watch_io (
       handle => $fh,
       $event => $arg{cb},
    );
 
    bless [$fh, $event], "AnyEvent::Impl::IOAsync::io"
 }
 
 sub AnyEvent::Impl::IOAsync::io::DESTROY {
    $LOOP->unwatch_io (
       handle => $_[0][0],
       $_[0][1] => 1,
    );
 }
 
 sub signal {
    my ($class, %arg) = @_;
 
    my $signal = $arg{signal};
 
    my $id = $LOOP->attach_signal ($arg{signal}, $arg{cb});
    bless [$signal, $id], "AnyEvent::Impl::IOAsync::signal"
 }
 
 sub AnyEvent::Impl::IOAsync::signal::DESTROY {
    $LOOP->detach_signal (@{ $_[0] });
 }
 
 our %pid_cb;
 
 sub child {
    my ($class, %arg) = @_;
 
    my $pid = $arg{pid};
 
    $LOOP->watch_child ($pid, $arg{cb});
    bless [$pid], "AnyEvent::Impl::IOAsync::child"
 }
 
 sub child {
    my ($class, %arg) = @_;
 
    my $pid = $arg{pid};
    my $cb  = $arg{cb};
 
    unless (%{ $pid_cb{$pid} }) {
       $LOOP->watch_child ($pid, sub {
          $_->($_[0], $_[1])
             for values %{ $pid_cb{$pid} };
       });
    }
 
    $pid_cb{$pid}{$cb+0} = $cb;
 
    bless [$pid, $cb+0], "AnyEvent::Impl::IOAsync::child"
 }
 
 sub AnyEvent::Impl::IOAsync::child::DESTROY {
    my ($pid, $icb) = @{ $_[0] };
 
    delete $pid_cb{$pid}{$icb};
 
    unless (%{ $pid_cb{$pid} }) {
       delete $pid_cb{$pid};
       $LOOP->unwatch_child ($pid);
    }
 }
 
 #sub loop {
 #   $LOOP->loop_forever;
 #}
 
 sub _poll {
    $LOOP->loop_once;
 }
 
 sub AnyEvent::CondVar::Base::_wait {
    $LOOP->loop_once until exists $_[0]{_ae_sent};
 }
 
 =head1 SEE ALSO
 
 L<AnyEvent>, L<IO::Async>.
 
 =head1 AUTHOR
 
  Marc Lehmann <schmorp@schmorp.de>
  http://anyevent.schmorp.de
 
  Paul Evans <leonerd@leonerd.org.uk>
  Rewrote the backend for IO::Async version 0.33.
 
 =cut
 
 1
 
### AnyEvent/Impl/Irssi.pm ###
 =head1 NAME
 
 AnyEvent::Impl::Irssi - AnyEvent adaptor for Irssi
 
 =head1 SYNOPSIS
 
    use AnyEvent;
   
    # this module gets loaded automatically when running under irssi
 
 =head1 DESCRIPTION
 
 This module provides transparent support for AnyEvent. You don't have to
 do anything to make Irssi scripts work with AnyEvent.
 
 Limitations of this backend and implementation details:
 
 =over 4
 
 =item * This backend does not support blocking waits.
 
 That means you must set a callback on any condvars, or otherwise make sure
 to never call C<recv> on a condvar that hasn't been signalled yet.
 
 =item * Child exits will be handled by AnyEvent.
 
 AnyEvent will take over child handling, as Irssi only polls for children
 once/second and cannot handle unspecific child watchers.
 
 This I<should> have no negative effect, as AnyEvent will emit a pidwait
 signal just like irssi itself would.
 
 =item * Artificial timer delays.
 
 Irssi artificially enforces timers to have at least a 10ms delay (by
 croaking, even).
 
 This means that some applications will be limited to a rate of 100Hz (for
 example, L<Coro::AnyEvent> thread scheduling).
 
 =item * Irssi leaks memory like hell.
 
 Yeah.
 
 =back
 
 Apart from that, documentation is notoriously wrong (e.g. file handles
 are not supported by C<input_add>, contrary to documentation), hooking
 into irssi has to be done in... weird... ways, but otherwise, Irssi is
 surprisingly full-featured (for basically being a hack).
 
 =cut
 
 package AnyEvent::Impl::Irssi;
 
 use AnyEvent (); BEGIN { AnyEvent::common_sense }
 use Carp ();
 use Irssi ();
 
 our @ISA;
 
 # irssi works only from certain namespaces, so we
 # create one and use it.
 sub init {
    my $pkg = caller;
 
    push @ISA, $pkg;
 
    local $/;
    eval "package $pkg; " . <DATA>;
    print "AnyEvent::Impl::Irssi fatal compilation error: $@" if $@;
 
    close DATA;
 }
 
 Irssi::command "/script exec -permanent AnyEvent::Impl::Irssi::init 'AnyEvent adaptor'";
 
 1;
 
 __DATA__
 
 BEGIN { AnyEvent::common_sense }
 use base "AnyEvent::Base";
 
 sub io {
    my ($class, %arg) = @_;
    
    my $cb = $arg{cb};
    my $fd = fileno $arg{fh};
    defined $fd or $fd = $arg{fh};
 
    my $source = Irssi::input_add
       $fd,
       $arg{poll} eq "r" ? Irssi::INPUT_READ : Irssi::INPUT_WRITE,
       $cb,
       undef;
 
    bless \\$source, "AnyEvent::Impl::Irssi::io"
 }
 
 sub AnyEvent::Impl::Irssi::io::DESTROY {
    Irssi::input_remove $${$_[0]};
 }
 
 sub timer {
    my ($class, %arg) = @_;
    
    my $cb    = $arg{cb};
    my $ival  = $arg{interval} * 1000;
    my $after = $arg{after} * 1000;
 
    my $source; $source = Irssi::timeout_add_once $after > 10 ? $after : 10,
       ($ival ? sub {
                  $source = Irssi::timeout_add $ival > 10 ? $ival : 10, $cb, undef;
                  &$cb;
                  0
                }
              : $cb),
       undef;
 
    bless \\$source, "AnyEvent::Impl::Irssi::timer"
 }
 
 sub AnyEvent::Impl::Irssi::timer::DESTROY {
    Irssi::timeout_remove $${$_[0]};
 }
 
 my $_pidwait = sub {
    my ($rpid, $rstatus) = @_;
 
    AnyEvent::Base->_emit_childstatus ($rpid, $rstatus);
 };
 
 Irssi::signal_add pidwait => $_pidwait;
 
 sub _emit_childstatus {
    my ($self, $rpid, $rstatus) = @_;
    $self->SUPER::_emit_childstatus ($rpid, $rstatus);
 
    Irssi::signal_remove pidwait => $_pidwait;
    Irssi::signal_emit   pidwait => $rpid+0, $rstatus+0;
    Irssi::signal_add    pidwait => $_pidwait;
 }
 
 #sub loop {
 #   Carp::croak "Irssi does not support blocking waits";
 #}
 
 =head1 SEE ALSO
 
 L<AnyEvent>, L<Irssi>.
 
 =head1 AUTHOR
 
  Marc Lehmann <schmorp@schmorp.de>
  http://anyevent.schmorp.de
 
 =cut
 
 1
 
### AnyEvent/Impl/POE.pm ###
 =head1 NAME
 
 AnyEvent::Impl::POE - AnyEvent adaptor for POE
 
 =encoding utf-8
 
 =head1 SYNOPSIS
 
    use AnyEvent;
    use POE;
   
    # this module gets loaded automatically as required
 
 =head1 DESCRIPTION
 
 This module provides transparent support for AnyEvent. You don't have to
 do anything to make POE work with AnyEvent except by loading POE before
 creating the first AnyEvent watcher. There are some cases where POE will
 issue spurious (and non-suppressible) warnings. These can be avoided by
 loading AnyEvent::Impl::POE before loading any other modules using POE and
 AnyEvent, i.e. in your main program.
 
 AnyEvent::Impl::POE will output some spurious message how to work around
 POE's spurious messages when it detects these cases.
 
 Unfortunately, POE isn't generic enough to implement a fully working
 AnyEvent backend: POE is too badly designed, too badly documented and too
 badly implemented.
 
 Here are the details, and what it means to you if you want to be
 interoperable with POE:
 
 =over 4
 
 =item Weird messages
 
 If you only use C<run_one_timeslice> (as AnyEvent has to for its
 condition variables), POE will print an ugly, unsuppressible, message at
 program exit:
 
    Sessions were started, but POE::Kernel's run() method was never...
 
 The message is correct, the question is why POE prints it in the first
 place in a correct program (this is not a singular case though).
 
 AnyEvent consequently patches the POE kernel so it thinks it already
 ran. Other workarounds, even the one cited in the POE documentation
 itself, have serious side effects, such as throwing away events.
 
 The author of POE verified that this is indeed true, and has no plans to
 change this.
 
 POE has other weird messages, and sometimes weird behaviour, for example,
 it doesn't support overloaded code references as callbacks for no apparent
 reason.
 
 =item One POE session per Event
 
 AnyEvent has to create one POE::Session per event watcher, which is
 immensely slow and makes watchers very large. The reason for this is
 lacking lifetime management (mostly undocumented, too). Without one
 session/watcher it is not possible to easily keep the kernel from running
 endlessly.
 
 This is not just a problem with the way AnyEvent has to interact with
 POE, but is a principal issue with POEs lifetime management (namely
 that stopping the kernel stops sessions, but AnyEvent has no control
 over who and when the kernel starts or stops w.r.t. AnyEvent watcher
 creation/destruction).
 
 From benchmark data it is not clear that session creation is that costly,
 though - the real inefficiencies with POE seem to come from other sources,
 such as event handling.
 
 =item One watcher per fd/event combo
 
 POE, of course, suffers from the same bug as Tk and some other badly
 designed event models in that it doesn't support multiple watchers per
 fd/poll combo. The workaround is the same as with Tk: AnyEvent::Impl::POE
 creates a separate file descriptor to hand to POE, which isn't fast and
 certainly not nice to your resources.
 
 Of course, without the workaround, POE also prints ugly messages again
 that say the program *might* be buggy.
 
 While this is not good to performance, at least regarding speed, with a
 modern Linux kernel, the overhead is actually quite small.
 
 =item Timing deficiencies
 
 POE manages to not have a function that returns the current time. This is
 extremely problematic, as POE can use different time functions, which can
 differ by more than a second - and user code is left guessing which one is
 used.
 
 In addition, most timer functions in POE want an absolute timestamp, which
 is hard to create if all you have is a relative time and no function to
 return the "current time".
 
 And of course POE doesn't handle time jumps at all (not even when using
 an event loop that happens to do that, such as L<EV>, as it does its own
 unoptimised timer management).
 
 AnyEvent works around the unavailability of the current time using
 relative timers exclusively, in the hope that POE gets it right at least
 internally.
 
 =item Lack of defined event ordering
 
 POE cannot guarantee the order of callback invocation for timers, and
 usually gets it wrong. That is, if you have two timers, one timing out
 after another (all else being equal), the callbacks might be called in
 reverse order.
 
 How one manages to even implement stuff that way escapes me.
 
 =item Child watchers
 
 POE offers child watchers - which is a laudable thing, as few event loops
 do. Unfortunately, they cannot even implement AnyEvent's simple child
 watchers: they are not generic enough (the POE implementation isn't even
 generic enough to let properly designed back-end use their native child
 watcher instead - it insist on doing it itself the broken way).
 
 Unfortunately, POE's child handling is inherently racy: if the child exits
 before the handler is created (because e.g. it crashes or simply is quick
 about it), then current versions of POE (1.352) will I<never> invoke the
 child watcher, and there is nothing that can be done about it. Older
 versions of POE only delayed in this case. The reason is that POE first
 checks if the child has already exited, and I<then> installs the signal
 handler - aa classical race.
 
 Your only hope is for the fork'ed process to not exit too quickly, in
 which case everything happens to work.
 
 Of course, whenever POE reaps an unrelated child it will also output a
 message for it that you cannot suppress (which shouldn't be too surprising
 at this point). Very professional.
 
 As a workaround, AnyEvent::Impl::POE will take advantage of undocumented
 behaviour in POE::Kernel to catch the status of all child processes, but
 it cannot guarantee delivery.
 
 How one manages to have such a glaring bug in an event loop after ten
 years of development escapes me.
 
 (There are more annoying bugs, for example, POE runs C<waitpid>
 unconditionally at finaliser time, so your program will hang until all
 child processes have exited.)
 
 =item Documentation quality
 
 At the time of this writing, POE was in its tenth year. Still, its
 documentation is extremely lacking, making it impossible to implement
 stuff as trivial as AnyEvent watchers without having to resort to
 undocumented behaviour or features.
 
 For example, the POE::Kernel manpage has nine occurrences of the word TODO
 with an explanation of whats missing. In general, the POE man pages are
 littered with comments like "section not yet written".
 
 Some other gems:
 
    This allows many object methods to also be package methods.
 
 This is nice, but since it doesn't document I<which> methods these are,
 this is utterly useless information.
 
    Terminal signals will kill sessions if they are not handled by a
    "sig_handled"() call. The OS signals that usually kill or dump a
    process are considered terminal in POE, but they never trigger a
    coredump. These are: HUP, INT, QUIT and TERM.
 
 Although AnyEvent calls C<sig_handled>, removing it has no apparent
 effects on POE handling SIGINT.
 
    refcount_increment SESSION_ID, COUNTER_NAME
 
 Nowhere is explained which COUNTER_NAMEs are valid and which aren't - not
 all scalars (or even strings) are valid counter names. Take your guess,
 failure is of course completely silent. I found this out the hard way, as
 the first name I came up with was silently ignored.
 
    get_next_event_time() returns the time the next event is due, in a form
    compatible with the UNIX time() function.
 
 And surely, one would hope that POE supports sub-second accuracy as
 documented elsewhere, unlike the explanation above implies. Yet:
 
    POE::Kernel timers support subsecond accuracy, but don’t expect too
    much here. Perl is not the right language for realtime programming.
 
 ... of course, Perl is not the right language to expect sub-second
 accuracy - the manpage author must hate Perl to spread so much FUD in
 so little space. The Deliantra game server logs with 100µs-accuracy
 because Perl is fast enough to require this, and is still able to deliver
 map updates with little jitter at exactly the right time. It does not,
 however, use POE.
 
    Furthermore, since the Kernel keeps track of everything sessions do, it
    knows when a session has run out of tasks to perform.
 
 This is impossible - how does the kernel know that a session is no longer
 watching for some (external) event (e.g. by some other session)? It
 cannot, and therefore this is wrong - but you would be hard pressed to
 find out how to work around this and tell the kernel manually about such
 events.
 
 It gets worse, though - the notion of "task" or "resource", although used
 throughout the documentation, is not defined in a usable way. For example,
 waiting for a timeout is considered to be a task, waiting for a signal is
 not (a session that only waits for a signal is considered finished and
 gets removed). The user is left guessing when waiting for an event counts
 as task and when not (in fact, the issue with signals is mentioned in
 passing in a section about child watchers and directly contradicts earlier
 parts in that document).
 
 One could go on endlessly - ten years, no usable documentation.
 
 It is likely that differences between documentation, or the one or two
 things I had to guess, cause unanticipated problems with this adaptor.
 
 =item Fragile and inconsistent API
 
 The POE API is extremely inconsistent - sometimes you have to pass a
 session argument, sometimes it gets ignored, sometimes a session-specific
 method must not use a session argument.
 
 Error handling is sub-standard as well: even for programming mistakes,
 POE does not C<croak> but, in most cases, just sets C<$!> or simply does
 nothing at all, leading to fragile programs.
 
 Sometimes registering a handler uses the "eventname, parameter" ordering
 (timeouts), sometimes it is "parameter, eventname" (signals). There is
 little consistency overall.
 
 =item Lack of knowledge
 
    The IO::Poll event loop provides an alternative that theoretically
    scales better than select().
 
 The IO::Poll "event loop" (who in his right mind would call that an event
 loop) of course scales about identically (sometimes it is a bit faster,
 sometimes a bit slower) to select in theory, and also in practise, of
 course, as both are O(n) in the number of file descriptors, which is
 rather bad.
 
 This is just one place where it gets obvious how little the author of the
 POE manpage understands.
 
 =item No idle events
 
 The POE-recommended workaround to this is apparently to use
 C<fork>. Consequently, idle watchers will have to be emulated by AnyEvent.
 
 =item Questionable maintainer behaviour
 
 The author of POE is known to fabricate statements and post these to
 public mailinglists - apparently, spreading FUD about competing (in his
 eyes) projects or their maintainers is acceptable to him.
 
 This has (I believe) zero effects on the quality or usefulness of his
 code, but it does completely undermine his trustworthyness - so don't
 blindly believe anything he says, he might have just made it up to suit
 his needs (benchmark results, the names of my ten wifes, the length of my
 penis, etc. etc.). When in doubt, double-check - not just him, anybody
 actually.
 
 Example: L<http://www.nntp.perl.org/group/perl.perl5.porters/2012/01/msg182141.html>.
 I challenged him in that thread to provide evidence for his statement by giving at
 least two examples, but of course since he just made it up, he couldn't provide any evidence.
 
 =back
 
 On the good side, AnyEvent allows you to write your modules in a 100%
 POE-compatible way (bug-for-bug compatible even), without forcing your
 module to use POE - it is still open to better event models, of which
 there are plenty.
 
 Oh, and one other positive thing:
 
    RUNNING_IN_HELL
 
 POE knows about the nature of the beast!
 
 =cut
 
 package AnyEvent::Impl::POE;
 
 use AnyEvent (); BEGIN { AnyEvent::common_sense }
 use POE;
 
 # suppress an idiotic warning inside POE
 ${ POE::Kernel->new->[POE::Kernel::KR_RUN] } |= POE::Kernel::KR_RUN_CALLED;
 
 sub io {
    my ($class, %arg) = @_;
 
    # POE itself might do the right thing, but some POE backends don't,
    # so do the safe thing, it's not as if this will slow us down
    # any further *g*
    my ($fh, $pee) = AnyEvent::_dupfh $arg{poll}, $arg{fh}, "select_read", "select_write";
 
    my $cb = delete $arg{cb}; my $cb = sub { &$cb }; # POE doesn't like callable objects
 
    my $session = POE::Session->create (
       inline_states => {
          _start => sub { $_[KERNEL]->$pee ($fh => "ready") },
          ready  => sub { $cb->() },
          stop   => sub { $_[KERNEL]->$pee ($fh) },
       },
    );
    bless \\$session, "AnyEvent::Impl::POE"
 }
 
 sub timer {
    my ($class, %arg) = @_;
 
    my $after = delete $arg{after};
    my $ival  = delete $arg{interval};
    my $cb    = delete $arg{cb}; my $cb = sub { &$cb }; # POE doesn't like callable objects
 
    my $session = POE::Session->create (
       inline_states => {
          _start => sub {
             $_[KERNEL]->delay_set (timeout => $after);
          },
          timeout => $ival ? sub { $_[KERNEL]->delay_set (timeout => $ival); $cb->() } : $cb,
          stop => sub {
             $_[KERNEL]->alarm_remove_all;
          },
       },
    );
    bless \\$session, "AnyEvent::Impl::POE"
 }
 
 sub signal {
    my ($class, %arg) = @_;
    my $signal = AnyEvent::Base::sig2name delete $arg{signal};
    my $cb     = delete $arg{cb}; my $cb = sub { &$cb }; # POE doesn't like callable objects
    my $session = POE::Session->create (
       inline_states => {
          _start => sub {
             # I suck - POE
          },
          start => sub {
             $_[KERNEL]->sig ($signal => "catch");
             $_[KERNEL]->refcount_increment ($_[SESSION]->ID => "poe");
          },
          catch => sub {
             $cb->();
             $_[KERNEL]->sig_handled;
          },
          stop => sub {
             $_[KERNEL]->refcount_decrement ($_[SESSION]->ID => "poe");
             $_[KERNEL]->sig ($signal);
          },
       },
    );
    POE::Kernel->call ($session, "start");
    bless \\$session, "AnyEvent::Impl::POE"
 }
 
 sub child {
    my ($class, %arg) = @_;
    my $pid = delete $arg{pid};
    my $cb  = delete $arg{cb}; my $cb = sub { &$cb }; # POE doesn't like callable objects
    my $session = POE::Session->create (
       inline_states => {
          _start => sub {
             # I suck - POE
          },
          start => sub {
             $_[KERNEL]->sig (CHLD => "child");
             $_[KERNEL]->refcount_increment ($_[SESSION]->ID => "poe");
          },
          child => sub {
             my ($rpid, $status) = @_[ARG1, ARG2];
 
             $cb->($rpid, $status) if $rpid == $pid || $pid == 0;
          },
          stop => sub {
             $_[KERNEL]->refcount_decrement ($_[SESSION]->ID => "poe");
             $_[KERNEL]->sig ("CHLD");
          },
       },
    );
    # newer POE versions lose signals unless we call ->sig early.
    POE::Kernel->call ($session, "start");
    bless \\$session, "AnyEvent::Impl::POE"
 }
 
 sub DESTROY {
    POE::Kernel->call (${${$_[0]}}, "stop");
 }
 
 #sub loop {
 #   POE::Kernel->run;
 #}
 
 sub _poll {
    POE::Kernel->loop_do_timeslice;
 }
 
 sub AnyEvent::CondVar::Base::_wait {
    POE::Kernel->loop_do_timeslice until exists $_[0]{_ae_sent};
 }
 
 =head1 SEE ALSO
 
 L<AnyEvent>, L<POE>.
 
 =head1 AUTHOR
 
  Marc Lehmann <schmorp@schmorp.de>
  http://anyevent.schmorp.de
 
 =cut
 
 1
 
### AnyEvent/Impl/Perl.pm ###
 =head1 NAME
 
 AnyEvent::Impl::Perl - AnyEvent adaptor for AnyEvent's pure perl AnyEvent::Loop
 
 =head1 SYNOPSIS
 
    use AnyEvent;
    use AnyEvent::Loop;
    # this module gets loaded automatically as required
 
 =head1 DESCRIPTION
 
 This module provides transparent support for AnyEvent in case no other
 event loop could be found or loaded.
 
 If you want to use this module instead of autoloading another event loop
 you can simply load L<AnyEvent::Loop> before creating the first watcher.
 
 Naturally, it supports all features of AnyEvent.
 
 See L<AnyEvent::Loop> for more details on performance characteristics.
 
 =cut
 
 package AnyEvent::Impl::Perl;
 
 use AnyEvent (); BEGIN { AnyEvent::common_sense }
 use AnyEvent::Loop;
 
 our $VERSION = $AnyEvent::VERSION;
 
 # time() is provided via AnyEvent::Base
 
 *AE::now        = \&AnyEvent::Loop::now;
 *AE::now_update = \&AnyEvent::Loop::now_update;
 *AE::io         = \&AnyEvent::Loop::io;
 *AE::timer      = \&AnyEvent::Loop::timer;
 *AE::idle       = \&AnyEvent::Loop::idle;
 *_poll          = \&AnyEvent::Loop::one_event;
 *loop           = \&AnyEvent::Loop::run; # compatibility with AnyEvent < 6.0
 *now_update     = \&AnyEvent::Loop::now_update;
 
 sub now { $AnyEvent::Loop::NOW }
 
 sub AnyEvent::CondVar::Base::_wait {
    AnyEvent::Loop::one_event until exists $_[0]{_ae_sent};
 }
 
 sub io {
    my (undef, %arg) = @_;
 
    AnyEvent::Loop::io $arg{fh}, $arg{poll} eq "w", $arg{cb}
 }
 
 sub timer {
    my (undef, %arg) = @_;
 
    AnyEvent::Loop::timer $arg{after}, $arg{interval}, $arg{cb}
 }
 
 sub idle {
    my (undef, %arg) = @_;
 
    AnyEvent::Loop::idle $arg{cb}
 }
 
 =head1 SEE ALSO
 
 L<AnyEvent>.
 
 =head1 AUTHOR
 
    Marc Lehmann <schmorp@schmorp.de>
    http://anyevent.schmorp.de
 
 =cut
 
 1
 
### AnyEvent/Impl/Qt.pm ###
 =head1 NAME
 
 AnyEvent::Impl::Qt - AnyEvent adaptor for Qt
 
 =head1 SYNOPSIS
 
    use AnyEvent;
    use Qt;
   
    my $app = Qt::Application \@ARGV; # REQUIRED!
   
    # this module gets loaded automatically as required
 
 =head1 DESCRIPTION
 
 This module provides transparent support for AnyEvent. You don't have
 to do anything to make Qt work with AnyEvent except by loading Qt
 before creating the first AnyEvent watcher I<and instantiating the
 Qt::Application object>. Failure to do so will result in segfaults,
 which is why this model doesn't work as a default model and will not be
 autoprobed (but it will be autodetected when the main program uses Qt).
 
 Qt suffers from the same limitations as Event::Lib and Tk, the workaround
 is also the same (duplicating file descriptors).
 
 Qt doesn't support idle events, so they are being emulated.
 
 Avoid Qt if you can.
 
 =cut
 
 package AnyEvent::Impl::Qt::Io;
 
 use Qt;
 use Qt::isa qw(Qt::SocketNotifier); # Socket? what where they smoking
 use Qt::slots cb => [];
 
 sub NEW {
    my ($class, $fh, $mode, $cb) = @_;
    shift->SUPER::NEW (fileno $fh, $mode);
    this->{fh} = $fh;
    this->{cb} = $cb;
    this->connect (this, SIGNAL "activated(int)", SLOT "cb()");
 }
 
 sub cb {
    this->setEnabled (0); # required according to the docs. heavy smoking required.
    this->{cb}->();
    this->setEnabled (1);
 }
 
 package AnyEvent::Impl::Qt::Timer;
 
 use Qt;
 use Qt::isa qw(Qt::Timer);
 use Qt::slots cb => [];
 
 # having to go through these contortions just to get a timer event is
 # considered an advantage over other gui toolkits how?
 
 sub NEW {
    my ($class, $after, $interval, $cb) = @_;
    shift->SUPER::NEW ();
    this->{interval} = $interval;
    this->{cb}       = $cb;
    this->connect (this, SIGNAL "timeout()", SLOT "cb()");
    this->start ($after, 1);
 }
 
 sub cb {
    this->start (this->{interval}, 1) if defined this->{interval};
    this->{cb}->();
 }
 
 package AnyEvent::Impl::Qt;
 
 use AnyEvent (); BEGIN { AnyEvent::common_sense }
 use Qt;
 
 use AnyEvent::Impl::Qt::Timer;
 use AnyEvent::Impl::Qt::Io;
 
 our $app = Qt::Application \@ARGV; # REQUIRED!
 
 sub io {
    my ($class, %arg) = @_;
 
    # work around these bugs in Qt:
    # - adding a callback might destroy other callbacks
    # - only one callback per fd/poll combination
    my ($fh, $qt) = AnyEvent::_dupfh $arg{poll}, $arg{fh},
                       Qt::SocketNotifier::Read (), Qt::SocketNotifier::Write ();
 
    AnyEvent::Impl::Qt::Io $fh, $qt, $arg{cb}
 }
 
 sub timer {
    my ($class, %arg) = @_;
    
    # old Qt treats 0 timeout as "idle"
    AnyEvent::Impl::Qt::Timer
       $arg{after} * 1000 || 1,
       $arg{interval} ? $arg{interval} * 1000 || 1 : undef,
       $arg{cb}
 }
 
 # newer Qt have no idle mode for timers anymore...
 #sub idle {
 #   my ($class, %arg) = @_;
 #   
 #   AnyEvent::Impl::Qt::Timer 0, 0, $arg{cb}
 #}
 
 #sub loop {
 #   Qt::app->exec;
 #}
 
 sub _poll {
    Qt::app->processOneEvent;
 }
 
 sub AnyEvent::CondVar::Base::_wait {
    Qt::app->processOneEvent until exists $_[0]{_ae_sent};
 }
 
 =head1 SEE ALSO
 
 L<AnyEvent>, L<Qt>.
 
 =head1 AUTHOR
 
    Marc Lehmann <schmorp@schmorp.de>
    http://anyevent.schmorp.de
 
 =cut
 
 1
 
### AnyEvent/Impl/Tk.pm ###
 =head1 NAME
 
 AnyEvent::Impl::Tk - AnyEvent adaptor for Tk
 
 =head1 SYNOPSIS
 
    use AnyEvent;
    use Tk;
   
    # this module gets loaded automatically as required
 
 =head1 DESCRIPTION
 
 This module provides transparent support for AnyEvent. You don't have to
 do anything to make Tk work with AnyEvent except by loading Tk before
 creating the first AnyEvent watcher.
 
 Tk is buggy. Tk is extremely buggy. Tk is so unbelievably buggy that
 for each bug reported and fixed, you get one new bug followed by
 reintroduction of the old bug in a later revision. It is also basically
 unmaintained: the maintainers are not even interested in improving
 the situation - reporting bugs is considered rude, and fixing bugs is
 considered changing holy code, so it's apparently better to leave it
 broken.
 
 I regularly run out of words to describe how bad it really is.
 
 To work around some of the many, many bugs in Tk that don't get fixed,
 this adaptor dup()'s all filehandles that get passed into its I/O
 watchers, so if you register a read and a write watcher for one fh,
 AnyEvent will create two additional file descriptors (and handles).
 
 This creates a high overhead and is slow, but seems to work around most
 known bugs in L<Tk::fileevent> on 32 bit architectures (Tk seems to be
 terminally broken on 64 bit, do not expect more than 10 or so watchers to
 work on 64 bit machines).
 
 Do not expect these workarounds to avoid segfaults and crashes inside Tk.
 
 Note also that Tk event ids wrap around after 2**32 or so events, which on
 my machine can happen within less than 12 hours, after which Tk will stomp
 on random other events and kill them. So don't run Tk programs for more
 than an hour or so.
 
 To be able to access the Tk event loop, this module creates a main
 window and withdraws it immediately. This might cause flickering on some
 platforms, but Tk perversely requires a window to be able to wait for file
 handle readyness notifications. This window is always created (in this
 version of AnyEvent) and can be accessed as C<$AnyEvent::Impl::Tk::mw>.
 
 =cut
 
 package AnyEvent::Impl::Tk;
 
 use AnyEvent (); BEGIN { AnyEvent::common_sense }
 use Tk ();
 
 our $mw = new MainWindow -title => "AnyEvent Dummy Window";
 $mw->withdraw;
 
 END { undef $mw }
 
 sub io {
    my (undef, %arg) = @_;
 
    # work around these bugs in Tk:
    # - removing a callback will destroy other callbacks
    # - removing a callback might crash
    # - adding a callback might destroy other callbacks
    # - only one callback per fh
    # - only one callback per fh/poll combination
    my ($fh, $tk) = AnyEvent::_dupfh $arg{poll}, $arg{fh}, "readable", "writable";
 
    $mw->fileevent ($fh, $tk => $arg{cb});
 
    bless [$fh, $tk], "AnyEvent::Impl::Tk::io"
 }
 
 sub AnyEvent::Impl::Tk::io::DESTROY {
    my ($fh, $tk) = @{$_[0]};
 
    # work around another bug: watchers don't get removed when
    # the fh is closed, contrary to documentation. also, trying
    # to unregister a read callback will make it impossible
    # to remove the write callback.
    # if your program segfaults here then you need to destroy
    # your watchers before program exit. sorry, no way around
    # that.
    $mw->fileevent ($fh, $tk => "");
 }
 
 sub timer {
    my (undef, %arg) = @_;
    
    my $after = $arg{after} < 0 ? 0 : $arg{after} * 1000;
    my $cb = $arg{cb};
    my $id;
 
    if ($arg{interval}) {
       my $ival = $arg{interval} * 1000;
       my $rcb = sub {
          $id = Tk::after $mw, $ival, [$_[0], $_[0]];
          &$cb;
       };
       $id = Tk::after $mw, $after, [$rcb, $rcb];
    } else {
       # tk blesses $cb, thus the extra indirection
       $id = Tk::after $mw, $after, sub { &$cb };
    }
 
    bless \\$id, "AnyEvent::Impl::Tk::after"
 }
 
 sub idle {
    my (undef, %arg) = @_;
 
    my $cb = $arg{cb};
    my $id;
    my $rcb = sub {
       # in their endless stupidity, they decided to give repeating idle watchers
       # strictly higher priority than timers :/
       $id = Tk::after $mw, 0 => [sub {
          $id = Tk::after $mw, idle => [$_[0], $_[0]];
       }, $_[0]];
       &$cb;
    };
 
    $id = Tk::after $mw, idle => [$rcb, $rcb];
    bless \\$id, "AnyEvent::Impl::Tk::after"
 }
 
 sub AnyEvent::Impl::Tk::after::DESTROY {
    Tk::after $mw, cancel => $${$_[0]};
 }
 
 #sub loop {
 #   Tk::MainLoop;
 #}
 
 sub _poll {
    Tk::DoOneEvent (0);
 }
 
 sub AnyEvent::CondVar::Base::_wait {
    Tk::DoOneEvent (0) until exists $_[0]{_ae_sent};
 }
 
 =head1 SEE ALSO
 
 L<AnyEvent>, L<Tk>.
 
 =head1 AUTHOR
 
  Marc Lehmann <schmorp@schmorp.de>
  http://anyevent.schmorp.de
 
 =cut
 
 1
 
### AnyEvent/Impl/UV.pm ###
 =head1 NAME
 
 AnyEvent::Impl::UV - AnyEvent adaptor for UV
 
 =head1 SYNOPSIS
 
    use AnyEvent;
    use UV;
   
    # this module gets loaded automatically as required
 
 =head1 DESCRIPTION
 
 This module provides transparent support for AnyEvent. You don't have to
 do anything to make UV work with AnyEvent except by loading UV before
 creating the first AnyEvent watcher.
 
 =cut
 
 package AnyEvent::Impl::UV;
 
 use AnyEvent (); BEGIN { AnyEvent::common_sense }
 use UV 0.24;
 use Scalar::Util qw(weaken);
 
 sub warnlog {
    my $err = UV::last_error;
 
    AnyEvent::log warn => "returned $_[0]: "
                          . UV::err_name ($err) . "($err): "
                          . UV::strerror ($err);
 
    @_
 }
 
 # https://github.com/joyent/libuv/issues/680
 # https://github.com/joyent/libuv/blob/dc1ea27c736f0d21c7160c790bcd1b113d20abd9/include/uv.h#L1277
 my %io_watchers;
 
 sub io_watcher_cb {
    my $slaves = shift;
    my (undef, $events) = @_;
    return unless defined $slaves;
 
    foreach my $entry (keys %$slaves) {
       my $slave = $slaves->{$entry};
       $slave->{cb}(@_) if $slave->{mode} & $events;
    }
 }
 
 sub AnyEvent::Impl::UV::io_slave::new {
    bless { parent => $_[1] }, $_[0]
 }
 
 sub AnyEvent::Impl::UV::io_slave::DESTROY {
    my $self   = $_[0];
    my $master = $self->{parent};
 
    delete $master->{slaves}{$self};
    if (keys %{$master->{slaves}} == 0) {
       if (defined $master->{w}) {
          my $rc = UV::poll_stop $master->{w};
          warnlog $rc if $rc;
       }
       delete $io_watchers{$master->{fd}};
       return;
    }
 
    my $mode = 0;
    foreach my $entry (keys %{$master->{slaves}}) {
       $mode |= $master->{slaves}{$entry}{mode};
    }
 
    if ($master->{mode} != $mode) {
       $master->{mode} = $mode;
       my $rc = UV::poll_start $master->{w}, $master->{mode}, sub {
          io_watcher_cb $master->{slaves}, @_;
       };
       warnlog $rc if $rc;
    }
 }
 
 sub io {
    my ($class, %arg) = @_;
    my $fd = fileno $arg{fh};
    defined $fd or $fd = $arg{fh};
 
    my $master = $io_watchers{$fd} ||= { fd => $fd };
 
    unless (defined $master->{w}) {
       $master->{w} = UV::poll_init $fd;
       return warnlog $master->{w} unless defined $master->{w};
       $master->{slaves} = {};
    }
 
    my $slave = AnyEvent::Impl::UV::io_slave->new ($master);
    weaken ($master->{slaves}->{$slave} = $slave);
 
    $slave->{mode}  = $arg{poll} eq "r" ? UV::READABLE : UV::WRITABLE;
    $master->{mode} = 0 unless defined $master->{mode};
    $slave->{cb}    = $arg{cb};
 
    unless ($master->{mode} & $slave->{mode}) {
       $master->{mode} |= $slave->{mode};
       my $rc = UV::poll_start $master->{w}, $master->{mode}, sub {
          io_watcher_cb $master->{slaves}, @_;
       };
       warnlog $rc if $rc;
    }
 
    $slave
 }
 
 sub AnyEvent::Impl::UV::handle::new {
    my ($class, $w, $start, $stop, @args) = @_;
    return warnlog $w unless defined $w;
 
    my $rc = $start->($w, @args);
    warnlog $rc if $rc;
 
    bless { w => $w, stop => $stop }, $class
 }
 
 sub AnyEvent::Impl::UV::handle::DESTROY {
    my $h  = $_[0];
    return unless $h->{w};
    my $rc = $h->{stop}($h->{w});
    warnlog $rc if $rc;
    UV::close $h->{w};
 }
 
 sub idle {
    my ($class, %arg) = @_;
 
    AnyEvent::Impl::UV::handle->new (
       UV::timer_init,
       \&UV::idle_start,
       \&UV::idle_stop,
       $arg{cb}
    );
 }
 
 sub timer {
    my ($class, %arg) = @_;
 
    AnyEvent::Impl::UV::handle->new (
       UV::timer_init,
       \&UV::timer_start,
       \&UV::timer_stop,
       $arg{after} * 1000, $arg{interval} * 1000, $arg{cb}
    );
 }
 
 sub now { UV::now }
 
 sub _poll {
    UV::run UV::RUN_ONCE;
 }
 
 sub AnyEvent::CondVar::Base::_wait {
    UV::run UV::RUN_NOWAIT until exists $_[0]{_ae_sent};
 }
 
 =head1 SEE ALSO
 
 L<AnyEvent>, L<UV>.
 
 =head1 AUTHOR
 
  Mike Lowell <mikedotlowell@gmail.com>
 
 =cut
 
 1
 
### AnyEvent/Log.pm ###
 =head1 NAME
 
 AnyEvent::Log - simple logging "framework"
 
 =head1 SYNOPSIS
 
 Simple uses:
 
    use AnyEvent;
 
    AE::log fatal => "No config found, cannot continue!"; # never returns
    AE::log alert => "The battery died!";
    AE::log crit  => "The battery temperature is too hot!";
    AE::log error => "Division by zero attempted.";
    AE::log warn  => "Couldn't delete the file.";
    AE::log note  => "Wanted to create config, but config already exists.";
    AE::log info  => "File soandso successfully deleted.";
    AE::log debug => "the function returned 3";
    AE::log trace => "going to call function abc";
 
 Log level overview:
 
    LVL NAME      SYSLOG   PERL  NOTE
     1  fatal     emerg    exit  system unusable, aborts program!
     2  alert                    failure in primary system
     3  critical  crit           failure in backup system
     4  error     err      die   non-urgent program errors, a bug
     5  warn      warning        possible problem, not necessarily error
     6  note      notice         unusual conditions
     7  info                     normal messages, no action required
     8  debug                    debugging messages for development
     9  trace                    copious tracing output
 
 "Complex" uses (for speed sensitive code, e.g. trace/debug messages):
 
    use AnyEvent::Log;
 
    my $tracer = AnyEvent::Log::logger trace => \$my $trace;
 
    $tracer->("i am here") if $trace;
    $tracer->(sub { "lots of data: " . Dumper $self }) if $trace;
 
 Configuration (also look at the EXAMPLES section):
 
    # set logging for the current package to errors and higher only
    AnyEvent::Log::ctx->level ("error");
 
    # set logging level to suppress anything below "notice"
    $AnyEvent::Log::FILTER->level ("notice");
 
    # send all critical and higher priority messages to syslog,
    # regardless of (most) other settings
    $AnyEvent::Log::COLLECT->attach (new AnyEvent::Log::Ctx
       level         => "critical",
       log_to_syslog => "user",
    );
 
 =head1 DESCRIPTION
 
 This module implements a relatively simple "logging framework". It doesn't
 attempt to be "the" logging solution or even "a" logging solution for
 AnyEvent - AnyEvent simply creates logging messages internally, and this
 module more or less exposes the mechanism, with some extra spiff to allow
 using it from other modules as well.
 
 Remember that the default verbosity level is C<4> (C<error>), so only
 errors and more important messages will be logged, unless you set
 C<PERL_ANYEVENT_VERBOSE> to a higher number before starting your program
 (C<AE_VERBOSE=5> is recommended during development), or change the logging
 level at runtime with something like:
 
    use AnyEvent::Log;
    $AnyEvent::Log::FILTER->level ("info");
 
 The design goal behind this module was to keep it simple (and small),
 but make it powerful enough to be potentially useful for any module,
 and extensive enough for the most common tasks, such as logging to
 multiple targets, or being able to log into a database.
 
 The module is also usable before AnyEvent itself is initialised, in which
 case some of the functionality might be reduced.
 
 The amount of documentation might indicate otherwise, but the runtime part
 of the module is still just below 300 lines of code.
 
 =head1 LOGGING LEVELS
 
 Logging levels in this module range from C<1> (highest priority) to C<9>
 (lowest priority). Note that the lowest numerical value is the highest
 priority, so when this document says "higher priority" it means "lower
 numerical value".
 
 Instead of specifying levels by name you can also specify them by aliases:
 
    LVL NAME      SYSLOG   PERL  NOTE
     1  fatal     emerg    exit  system unusable, aborts program!
     2  alert                    failure in primary system
     3  critical  crit           failure in backup system
     4  error     err      die   non-urgent program errors, a bug
     5  warn      warning        possible problem, not necessarily error
     6  note      notice         unusual conditions
     7  info                     normal messages, no action required
     8  debug                    debugging messages for development
     9  trace                    copious tracing output
 
 As you can see, some logging levels have multiple aliases - the first one
 is the "official" name, the second one the "syslog" name (if it differs)
 and the third one the "perl" name, suggesting (only!) that you log C<die>
 messages at C<error> priority. The NOTE column tries to provide some
 rationale on how to chose a logging level.
 
 As a rough guideline, levels 1..3 are primarily meant for users of the
 program (admins, staff), and are the only ones logged to STDERR by
 default. Levels 4..6 are meant for users and developers alike, while
 levels 7..9 are usually meant for developers.
 
 You can normally only log a message once at highest priority level (C<1>,
 C<fatal>), because logging a fatal message will also quit the program - so
 use it sparingly :)
 
 For example, a program that finds an unknown switch on the commandline
 might well use a fatal logging level to tell users about it - the "system"
 in this case would be the program, or module.
 
 Some methods also offer some extra levels, such as C<0>, C<off>, C<none>
 or C<all> - these are only valid for the methods that documented them.
 
 =head1 LOGGING FUNCTIONS
 
 The following functions allow you to log messages. They always use the
 caller's package as a "logging context". Also, the main logging function,
 C<log>, is aliased to C<AnyEvent::log> and C<AE::log> when the C<AnyEvent>
 module is loaded.
 
 =over 4
 
 =cut
 
 package AnyEvent::Log;
 
 use Carp ();
 use POSIX ();
 
 # layout of a context
 #       0       1         2        3        4,    5
 # [$title, $level, %$slaves, &$logcb, &$fmtcb, $cap]
 
 use AnyEvent (); BEGIN { AnyEvent::common_sense }
 #use AnyEvent::Util (); need to load this in a delayed fashion, as it uses AE::log
 
 our $VERSION = $AnyEvent::VERSION;
 
 our ($COLLECT, $FILTER, $LOG);
 
 our ($now_int, $now_str1, $now_str2);
 
 # Format Time, not public - yet?
 sub format_time($) {
    my $i = int $_[0];
    my $f = sprintf "%06d", 1e6 * ($_[0] - $i);
 
    ($now_int, $now_str1, $now_str2) = ($i, split /\x01/, POSIX::strftime "%Y-%m-%d %H:%M:%S.\x01 %z", localtime $i)
       if $now_int != $i;
 
    "$now_str1$f$now_str2"
 }
 
 our %CTX; # all package contexts
 
 # creates a default package context object for the given package
 sub _pkg_ctx($) {
    my $ctx = bless [$_[0], (1 << 10) - 1 - 1, {}], "AnyEvent::Log::Ctx";
 
    # link "parent" package
    my $parent = $_[0] =~ /^(.+)::/
       ? $CTX{$1} ||= &_pkg_ctx ("$1")
       : $COLLECT;
 
    $ctx->[2]{$parent+0} = $parent;
 
    $ctx
 }
 
 =item AnyEvent::Log::log $level, $msg[, @args]
 
 Requests logging of the given C<$msg> with the given log level, and
 returns true if the message was logged I<somewhere>.
 
 For loglevel C<fatal>, the program will abort.
 
 If only a C<$msg> is given, it is logged as-is. With extra C<@args>, the
 C<$msg> is interpreted as an sprintf format string.
 
 The C<$msg> should not end with C<\n>, but may if that is convenient for
 you. Also, multiline messages are handled properly.
 
 Last not least, C<$msg> might be a code reference, in which case it is
 supposed to return the message. It will be called only then the message
 actually gets logged, which is useful if it is costly to create the
 message in the first place.
 
 This function takes care of saving and restoring C<$!> and C<$@>, so you
 don't have to.
 
 Whether the given message will be logged depends on the maximum log level
 and the caller's package. The return value can be used to ensure that
 messages or not "lost" - for example, when L<AnyEvent::Debug> detects a
 runtime error it tries to log it at C<die> level, but if that message is
 lost it simply uses warn.
 
 Note that you can (and should) call this function as C<AnyEvent::log> or
 C<AE::log>, without C<use>-ing this module if possible (i.e. you don't
 need any additional functionality), as those functions will load the
 logging module on demand only. They are also much shorter to write.
 
 Also, if you optionally generate a lot of debug messages (such as when
 tracing some code), you should look into using a logger callback and a
 boolean enabler (see C<logger>, below).
 
 Example: log something at error level.
 
    AE::log error => "something";
 
 Example: use printf-formatting.
 
    AE::log info => "%5d %-10.10s %s", $index, $category, $msg;
 
 Example: only generate a costly dump when the message is actually being logged.
 
    AE::log debug => sub { require Data::Dump; Data::Dump::dump \%cache };
 
 =cut
 
 # also allow syslog equivalent names
 our %STR2LEVEL = (
    fatal    => 1, emerg    => 1, exit => 1,
    alert    => 2,
    critical => 3, crit     => 3,
    error    => 4, err      => 4, die  => 4,
    warn     => 5, warning  => 5,
    note     => 6, notice   => 6,
    info     => 7,
    debug    => 8,
    trace    => 9,
 );
 
 our $TIME_EXACT;
 
 sub exact_time($) {
    $TIME_EXACT = shift;
    *_ts = $AnyEvent::MODEL
       ? $TIME_EXACT ? \&AE::now : \&AE::time
       : sub () { $TIME_EXACT ? do { require Time::HiRes; Time::HiRes::time () } : time };
 }
 
 BEGIN {
    exact_time 0;
 }
 
 AnyEvent::post_detect {
    exact_time $TIME_EXACT;
 };
 
 our @LEVEL2STR = qw(0 fatal alert crit error warn note info debug trace);
 
 # time, ctx, level, msg
 sub default_format($$$$) {
    my $ts = format_time $_[0];
    my $ct = " ";
 
    my @res;
 
    for (split /\n/, sprintf "%-5s %s: %s", $LEVEL2STR[$_[2]], $_[1][0], $_[3]) {
       push @res, "$ts$ct$_\n";
       $ct = " + ";
    }
 
    join "", @res
 }
 
 sub fatal_exit() {
    exit 1;
 }
 
 sub _log {
    my ($ctx, $level, $format, @args) = @_;
 
    $level = $level > 0 && $level <= 9
             ? $level+0
             : $STR2LEVEL{$level} || Carp::croak "$level: not a valid logging level, caught";
 
    my $mask = 1 << $level;
 
    my ($success, %seen, @ctx, $now, @fmt);
 
    do
       {
          # if !ref, then it's a level number
          if (!ref $ctx) {
             $level = $ctx;
          } elsif ($ctx->[1] & $mask and !$seen{$ctx+0}++) {
             # logging/recursing into this context
 
             # level cap
             if ($ctx->[5] > $level) {
                push @ctx, $level; # restore level when going up in tree
                $level = $ctx->[5];
             }
 
             # log if log cb
             if ($ctx->[3]) {
                # logging target found
 
                local ($!, $@);
 
                # now get raw message, unless we have it already
                unless ($now) {
                   $format = $format->() if ref $format;
                   $format = sprintf $format, @args if @args;
                   $format =~ s/\n$//;
                   $now = _ts;
                };
 
                # format msg
                my $str = $ctx->[4]
                   ? $ctx->[4]($now, $_[0], $level, $format)
                   : ($fmt[$level] ||= default_format $now, $_[0], $level, $format);
 
                $success = 1;
 
                $ctx->[3]($str)
                   or push @ctx, values %{ $ctx->[2] }; # not consumed - propagate
             } else {
                push @ctx, values %{ $ctx->[2] }; # not masked - propagate
             }
          }
       }
    while $ctx = pop @ctx;
 
    fatal_exit if $level <= 1;
 
    $success
 }
 
 sub log($$;@) {
    _log
       $CTX{ (caller)[0] } ||= _pkg_ctx +(caller)[0],
       @_;
 }
 
 =item $logger = AnyEvent::Log::logger $level[, \$enabled]
 
 Creates a code reference that, when called, acts as if the
 C<AnyEvent::Log::log> function was called at this point with the given
 level. C<$logger> is passed a C<$msg> and optional C<@args>, just as with
 the C<AnyEvent::Log::log> function:
 
    my $debug_log = AnyEvent::Log::logger "debug";
 
    $debug_log->("debug here");
    $debug_log->("%06d emails processed", 12345);
    $debug_log->(sub { $obj->as_string });
 
 The idea behind this function is to decide whether to log before actually
 logging - when the C<logger> function is called once, but the returned
 logger callback often, then this can be a tremendous speed win.
 
 Despite this speed advantage, changes in logging configuration will
 still be reflected by the logger callback, even if configuration changes
 I<after> it was created.
 
 To further speed up logging, you can bind a scalar variable to the logger,
 which contains true if the logger should be called or not - if it is
 false, calling the logger can be safely skipped. This variable will be
 updated as long as C<$logger> is alive.
 
 Full example:
 
    # near the init section
    use AnyEvent::Log;
 
    my $debug_log = AnyEvent:Log::logger debug => \my $debug;
 
    # and later in your program
    $debug_log->("yo, stuff here") if $debug;
 
    $debug and $debug_log->("123");
 
 =cut
 
 our %LOGGER;
 
 # re-assess logging status for all loggers
 sub _reassess {
    local $SIG{__DIE__};
    my $die = sub { die };
 
    for (@_ ? $LOGGER{$_[0]} : values %LOGGER) {
       my ($ctx, $level, $renabled) = @$_;
 
       # to detect whether a message would be logged, we actually
       # try to log one and die. this isn't fast, but we can be
       # sure that the logging decision is correct :)
 
       $$renabled = !eval {
          _log $ctx, $level, $die;
 
          1
       };
    }
 }
 
 sub _logger {
    my ($ctx, $level, $renabled) = @_;
 
    $$renabled = 1;
 
    my $logger = [$ctx, $level, $renabled];
 
    $LOGGER{$logger+0} = $logger;
 
    _reassess $logger+0;
 
    require AnyEvent::Util unless $AnyEvent::Util::VERSION;
    my $guard = AnyEvent::Util::guard (sub {
       # "clean up"
       delete $LOGGER{$logger+0};
    });
 
    sub {
       $guard if 0; # keep guard alive, but don't cause runtime overhead
 
       _log $ctx, $level, @_
          if $$renabled;
    }
 }
 
 sub logger($;$) {
    _logger
       $CTX{ (caller)[0] } ||= _pkg_ctx +(caller)[0],
       @_
 }
 
 =item AnyEvent::Log::exact_time $on
 
 By default, C<AnyEvent::Log> will use C<AE::now>, i.e. the cached
 eventloop time, for the log timestamps. After calling this function with a
 true value it will instead resort to C<AE::time>, i.e. fetch the current
 time on each log message. This only makes a difference for event loops
 that actually cache the time (such as L<EV> or L<AnyEvent::Loop>).
 
 This setting can be changed at any time by calling this function.
 
 Since C<AnyEvent::Log> has to work even before the L<AnyEvent> has been
 initialised, this switch will also decide whether to use C<CORE::time> or
 C<Time::HiRes::time> when logging a message before L<AnyEvent> becomes
 available.
 
 =item AnyEvent::Log::format_time $timestamp
 
 Formats a timestamp as returned by C<< AnyEvent->now >> or C<<
 AnyEvent->time >> or many other functions in the same way as
 C<AnyEvent::Log> does.
 
 In your main program (as opposed to in your module) you can override
 the default timestamp display format by loading this module and then
 redefining this function.
 
 Most commonly, this function can be used in formatting callbacks.
 
 =item AnyEvent::Log::default_format $time, $ctx, $level, $msg
 
 Format a log message using the given timestamp, logging context, log level
 and log message.
 
 This is the formatting function used to format messages when no custom
 function is provided.
 
 In your main program (as opposed to in your module) you can override the
 default message format by loading this module and then redefining this
 function.
 
 =item AnyEvent::Log::fatal_exit
 
 This is the function that is called after logging a C<fatal> log
 message. It must not return.
 
 The default implementation simply calls C<exit 1>.
 
 In your main program (as opposed to in your module) you can override
 the fatal exit function by loading this module and then redefining this
 function. Make sure you don't return.
 
 =back
 
 =head1 LOGGING CONTEXTS
 
 This module associates every log message with a so-called I<logging
 context>, based on the package of the caller. Every perl package has its
 own logging context.
 
 A logging context has three major responsibilities: filtering, logging and
 propagating the message.
 
 For the first purpose, filtering, each context has a set of logging
 levels, called the log level mask. Messages not in the set will be ignored
 by this context (masked).
 
 For logging, the context stores a formatting callback (which takes the
 timestamp, context, level and string message and formats it in the way
 it should be logged) and a logging callback (which is responsible for
 actually logging the formatted message and telling C<AnyEvent::Log>
 whether it has consumed the message, or whether it should be propagated).
 
 For propagation, a context can have any number of attached I<slave
 contexts>. Any message that is neither masked by the logging mask nor
 masked by the logging callback returning true will be passed to all slave
 contexts.
 
 Each call to a logging function will log the message at most once per
 context, so it does not matter (much) if there are cycles or if the
 message can arrive at the same context via multiple paths.
 
 =head2 DEFAULTS
 
 By default, all logging contexts have an full set of log levels ("all"), a
 disabled logging callback and the default formatting callback.
 
 Package contexts have the package name as logging title by default.
 
 They have exactly one slave - the context of the "parent" package. The
 parent package is simply defined to be the package name without the last
 component, i.e. C<AnyEvent::Debug::Wrapped> becomes C<AnyEvent::Debug>,
 and C<AnyEvent> becomes ... C<$AnyEvent::Log::COLLECT> which is the
 exception of the rule - just like the "parent" of any single-component
 package name in Perl is C<main>, the default slave of any top-level
 package context is C<$AnyEvent::Log::COLLECT>.
 
 Since perl packages form only an approximate hierarchy, this slave
 context can of course be removed.
 
 All other (anonymous) contexts have no slaves and an empty title by
 default.
 
 When the module is loaded it creates the C<$AnyEvent::Log::LOG> logging
 context that simply logs everything via C<warn>, without propagating
 anything anywhere by default.  The purpose of this context is to provide
 a convenient place to override the global logging target or to attach
 additional log targets. It's not meant for filtering.
 
 It then creates the C<$AnyEvent::Log::FILTER> context whose
 purpose is to suppress all messages with priority higher
 than C<$ENV{PERL_ANYEVENT_VERBOSE}>. It then attached the
 C<$AnyEvent::Log::LOG> context to it. The purpose of the filter context
 is to simply provide filtering according to some global log level.
 
 Finally it creates the top-level package context C<$AnyEvent::Log::COLLECT>
 and attaches the C<$AnyEvent::Log::FILTER> context to it, but otherwise
 leaves it at default config. Its purpose is simply to collect all log
 messages system-wide.
 
 The hierarchy is then:
 
    any package, eventually -> $COLLECT -> $FILTER -> $LOG
 
 The effect of all this is that log messages, by default, wander up to the
 C<$AnyEvent::Log::COLLECT> context where all messages normally end up,
 from there to C<$AnyEvent::Log::FILTER> where log messages with lower
 priority then C<$ENV{PERL_ANYEVENT_VERBOSE}> will be filtered out and then
 to the C<$AnyEvent::Log::LOG> context to be passed to C<warn>.
 
 This makes it easy to set a global logging level (by modifying $FILTER),
 but still allow other contexts to send, for example, their debug and trace
 messages to the $LOG target despite the global logging level, or to attach
 additional log targets that log messages, regardless of the global logging
 level.
 
 It also makes it easy to modify the default warn-logger ($LOG) to
 something that logs to a file, or to attach additional logging targets
 (such as loggign to a file) by attaching it to $FILTER.
 
 =head2 CREATING/FINDING/DESTROYING CONTEXTS
 
 =over 4
 
 =item $ctx = AnyEvent::Log::ctx [$pkg]
 
 This function creates or returns a logging context (which is an object).
 
 If a package name is given, then the context for that packlage is
 returned. If it is called without any arguments, then the context for the
 callers package is returned (i.e. the same context as a C<AE::log> call
 would use).
 
 If C<undef> is given, then it creates a new anonymous context that is not
 tied to any package and is destroyed when no longer referenced.
 
 =cut
 
 sub ctx(;$) {
    my $pkg = @_ ? shift : (caller)[0];
 
    ref $pkg
       ? $pkg
       : defined $pkg
          ? $CTX{$pkg} ||= AnyEvent::Log::_pkg_ctx $pkg
          : bless [undef, (1 << 10) - 1 - 1], "AnyEvent::Log::Ctx"
 }
 
 =item AnyEvent::Log::reset
 
 Resets all package contexts and recreates the default hierarchy if
 necessary, i.e. resets the logging subsystem to defaults, as much as
 possible. This process keeps references to contexts held by other parts of
 the program intact.
 
 This can be used to implement config-file (re-)loading: before loading a
 configuration, reset all contexts.
 
 =cut
 
 our $ORIG_VERBOSE = $AnyEvent::VERBOSE;
 $AnyEvent::VERBOSE = 9;
 
 sub reset {
    # hard to kill complex data structures
    # we "recreate" all package loggers and reset the hierarchy
    while (my ($k, $v) = each %CTX) {
       @$v = ($k, (1 << 10) - 1 - 1, { });
 
       $v->attach ($k =~ /^(.+)::/ ? $CTX{$1} : $AnyEvent::Log::COLLECT);
    }
 
    @$_ = ($_->[0], (1 << 10) - 1 - 1)
       for $LOG, $FILTER, $COLLECT;
 
    #$LOG->slaves;
    $LOG->title ('$AnyEvent::Log::LOG');
    $LOG->log_to_warn;
 
    $FILTER->slaves ($LOG);
    $FILTER->title ('$AnyEvent::Log::FILTER');
    $FILTER->level ($ORIG_VERBOSE);
 
    $COLLECT->slaves ($FILTER);
    $COLLECT->title ('$AnyEvent::Log::COLLECT');
 
    _reassess;
 }
 
 # override AE::log/logger
 *AnyEvent::log    = *AE::log    = \&log;
 *AnyEvent::logger = *AE::logger = \&logger;
 
 # convert AnyEvent loggers to AnyEvent::Log loggers
 $_->[0] = ctx $_->[0] # convert "pkg" to "ctx"
    for values %LOGGER;
 
 # create the default logger contexts
 $LOG     = ctx undef;
 $FILTER  = ctx undef;
 $COLLECT = ctx undef;
 
 AnyEvent::Log::reset;
 
 # hello, CPAN, please catch me
 package AnyEvent::Log::LOG;
 package AE::Log::LOG;
 package AnyEvent::Log::FILTER;
 package AE::Log::FILTER;
 package AnyEvent::Log::COLLECT;
 package AE::Log::COLLECT;
 
 package AnyEvent::Log::Ctx;
 
 =item $ctx = new AnyEvent::Log::Ctx methodname => param...
 
 This is a convenience constructor that makes it simpler to construct
 anonymous logging contexts.
 
 Each key-value pair results in an invocation of the method of the same
 name as the key with the value as parameter, unless the value is an
 arrayref, in which case it calls the method with the contents of the
 array. The methods are called in the same order as specified.
 
 Example: create a new logging context and set both the default logging
 level, some slave contexts and a logging callback.
 
    $ctx = new AnyEvent::Log::Ctx
       title   => "dubious messages",
       level   => "error",
       log_cb  => sub { print STDOUT shift; 0 },
       slaves  => [$ctx1, $ctx, $ctx2],
    ;
 
 =back
 
 =cut
 
 sub new {
    my $class = shift;
 
    my $ctx = AnyEvent::Log::ctx undef;
 
    while (@_) {
       my ($k, $v) = splice @_, 0, 2;
       $ctx->$k (ref $v eq "ARRAY" ? @$v : $v);
    }
 
    bless $ctx, $class # do we really support subclassing, hmm?
 }
 
 
 =head2 CONFIGURING A LOG CONTEXT
 
 The following methods can be used to configure the logging context.
 
 =over 4
 
 =item $ctx->title ([$new_title])
 
 Returns the title of the logging context - this is the package name, for
 package contexts, and a user defined string for all others.
 
 If C<$new_title> is given, then it replaces the package name or title.
 
 =cut
 
 sub title {
    $_[0][0] = $_[1] if @_ > 1;
    $_[0][0]
 }
 
 =back
 
 =head3 LOGGING LEVELS
 
 The following methods deal with the logging level set associated with the
 log context.
 
 The most common method to use is probably C<< $ctx->level ($level) >>,
 which configures the specified and any higher priority levels.
 
 All functions which accept a list of levels also accept the special string
 C<all> which expands to all logging levels.
 
 =over 4
 
 =item $ctx->levels ($level[, $level...)
 
 Enables logging for the given levels and disables it for all others.
 
 =item $ctx->level ($level)
 
 Enables logging for the given level and all lower level (higher priority)
 ones. In addition to normal logging levels, specifying a level of C<0> or
 C<off> disables all logging for this level.
 
 Example: log warnings, errors and higher priority messages.
 
    $ctx->level ("warn");
    $ctx->level (5); # same thing, just numeric
 
 =item $ctx->enable ($level[, $level...])
 
 Enables logging for the given levels, leaving all others unchanged.
 
 =item $ctx->disable ($level[, $level...])
 
 Disables logging for the given levels, leaving all others unchanged.
 
 =item $ctx->cap ($level)
 
 Caps the maximum priority to the given level, for all messages logged
 to, or passing through, this context. That is, while this doesn't affect
 whether a message is logged or passed on, the maximum priority of messages
 will be limited to the specified level - messages with a higher priority
 will be set to the specified priority.
 
 Another way to view this is that C<< ->level >> filters out messages with
 a too low priority, while C<< ->cap >> modifies messages with a too high
 priority.
 
 This is useful when different log targets have different interpretations
 of priority. For example, for a specific command line program, a wrong
 command line switch might well result in a C<fatal> log message, while the
 same message, logged to syslog, is likely I<not> fatal to the system or
 syslog facility as a whole, but more likely a mere C<error>.
 
 This can be modeled by having a stderr logger that logs messages "as-is"
 and a syslog logger that logs messages with a level cap of, say, C<error>,
 or, for truly system-critical components, actually C<critical>.
 
 =cut
 
 sub _lvl_lst {
    map {
       $_ > 0 && $_ <= 9 ? $_+0
       : $_ eq "all"     ? (1 .. 9)
       : $STR2LEVEL{$_} || Carp::croak "$_: not a valid logging level, caught"
    } @_
 }
 
 sub _lvl {
    $_[0] =~ /^(?:0|off|none)$/ ? 0 : (_lvl_lst $_[0])[-1]
 }
 
 our $NOP_CB = sub { 0 };
 
 sub levels {
    my $ctx = shift;
    $ctx->[1] = 0;
    $ctx->[1] |= 1 << $_
       for &_lvl_lst;
    AnyEvent::Log::_reassess;
 }
 
 sub level {
    my $ctx = shift;
    $ctx->[1] = ((1 << &_lvl) - 1) << 1;
    AnyEvent::Log::_reassess;
 }
 
 sub enable {
    my $ctx = shift;
    $ctx->[1] |= 1 << $_
       for &_lvl_lst;
    AnyEvent::Log::_reassess;
 }
 
 sub disable {
    my $ctx = shift;
    $ctx->[1] &= ~(1 << $_)
       for &_lvl_lst;
    AnyEvent::Log::_reassess;
 }
 
 sub cap {
    my $ctx = shift;
    $ctx->[5] = &_lvl;
 }
 
 =back
 
 =head3 SLAVE CONTEXTS
 
 The following methods attach and detach another logging context to a
 logging context.
 
 Log messages are propagated to all slave contexts, unless the logging
 callback consumes the message.
 
 =over 4
 
 =item $ctx->attach ($ctx2[, $ctx3...])
 
 Attaches the given contexts as slaves to this context. It is not an error
 to add a context twice (the second add will be ignored).
 
 A context can be specified either as package name or as a context object.
 
 =item $ctx->detach ($ctx2[, $ctx3...])
 
 Removes the given slaves from this context - it's not an error to attempt
 to remove a context that hasn't been added.
 
 A context can be specified either as package name or as a context object.
 
 =item $ctx->slaves ($ctx2[, $ctx3...])
 
 Replaces all slaves attached to this context by the ones given.
 
 =cut
 
 sub attach {
    my $ctx = shift;
 
    $ctx->[2]{$_+0} = $_
       for map { AnyEvent::Log::ctx $_ } @_;
 }
 
 sub detach {
    my $ctx = shift;
 
    delete $ctx->[2]{$_+0}
       for map { AnyEvent::Log::ctx $_ } @_;
 }
 
 sub slaves {
    undef $_[0][2];
    &attach;
 }
 
 =back
 
 =head3 LOG TARGETS
 
 The following methods configure how the logging context actually does
 the logging (which consists of formatting the message and printing it or
 whatever it wants to do with it).
 
 =over 4
 
 =item $ctx->log_cb ($cb->($str))
 
 Replaces the logging callback on the context (C<undef> disables the
 logging callback).
 
 The logging callback is responsible for handling formatted log messages
 (see C<fmt_cb> below) - normally simple text strings that end with a
 newline (and are possibly multiline themselves).
 
 It also has to return true iff it has consumed the log message, and false
 if it hasn't. Consuming a message means that it will not be sent to any
 slave context. When in doubt, return C<0> from your logging callback.
 
 Example: a very simple logging callback, simply dump the message to STDOUT
 and do not consume it.
 
    $ctx->log_cb (sub { print STDERR shift; 0 });
 
 You can filter messages by having a log callback that simply returns C<1>
 and does not do anything with the message, but this counts as "message
 being logged" and might not be very efficient.
 
 Example: propagate all messages except for log levels "debug" and
 "trace". The messages will still be generated, though, which can slow down
 your program.
 
    $ctx->levels ("debug", "trace");
    $ctx->log_cb (sub { 1 }); # do not log, but eat debug and trace messages
 
 =item $ctx->fmt_cb ($fmt_cb->($timestamp, $orig_ctx, $level, $message))
 
 Replaces the formatting callback on the context (C<undef> restores the
 default formatter).
 
 The callback is passed the (possibly fractional) timestamp, the original
 logging context (object, not title), the (numeric) logging level and
 the raw message string and needs to return a formatted log message. In
 most cases this will be a string, but it could just as well be an array
 reference that just stores the values.
 
 If, for some reason, you want to use C<caller> to find out more about the
 logger then you should walk up the call stack until you are no longer
 inside the C<AnyEvent::Log> package.
 
 To implement your own logging callback, you might find the
 C<AnyEvent::Log::format_time> and C<AnyEvent::Log::default_format>
 functions useful.
 
 Example: format the message just as AnyEvent::Log would, by letting
 AnyEvent::Log do the work. This is a good basis to design a formatting
 callback that only changes minor aspects of the formatting.
 
    $ctx->fmt_cb (sub {
       my ($time, $ctx, $lvl, $msg) = @_;
 
       AnyEvent::Log::default_format $time, $ctx, $lvl, $msg
    });
 
 Example: format just the raw message, with numeric log level in angle
 brackets.
 
    $ctx->fmt_cb (sub {
       my ($time, $ctx, $lvl, $msg) = @_;
 
       "<$lvl>$msg\n"
    });
 
 Example: return an array reference with just the log values, and use
 C<PApp::SQL::sql_exec> to store the message in a database.
 
    $ctx->fmt_cb (sub { \@_ });
    $ctx->log_cb (sub {
       my ($msg) = @_;
 
       sql_exec "insert into log (when, subsys, prio, msg) values (?, ?, ?, ?)",
                $msg->[0] + 0,
                "$msg->[1]",
                $msg->[2] + 0,
                "$msg->[3]";
 
       0
    });
 
 =item $ctx->log_to_warn
 
 Sets the C<log_cb> to simply use C<CORE::warn> to report any messages
 (usually this logs to STDERR).
 
 =item $ctx->log_to_file ($path)
 
 Sets the C<log_cb> to log to a file (by appending), unbuffered. The
 function might return before the log file has been opened or created.
 
 =item $ctx->log_to_path ($path)
 
 Same as C<< ->log_to_file >>, but opens the file for each message. This
 is much slower, but allows you to change/move/rename/delete the file at
 basically any time.
 
 Needless(?) to say, if you do not want to be bitten by some evil person
 calling C<chdir>, the path should be absolute. Doesn't help with
 C<chroot>, but hey...
 
 =item $ctx->log_to_syslog ([$facility])
 
 Logs all messages via L<Sys::Syslog>, mapping C<trace> to C<debug> and
 all the others in the obvious way. If specified, then the C<$facility> is
 used as the facility (C<user>, C<auth>, C<local0> and so on). The default
 facility is C<user>.
 
 Note that this function also sets a C<fmt_cb> - the logging part requires
 an array reference with [$level, $str] as input.
 
 =cut
 
 sub log_cb {
    my ($ctx, $cb) = @_;
 
    $ctx->[3] = $cb;
 }
 
 sub fmt_cb {
    my ($ctx, $cb) = @_;
 
    $ctx->[4] = $cb;
 }
 
 sub log_to_warn {
    my ($ctx, $path) = @_;
 
    $ctx->log_cb (sub {
       warn shift;
       0
    });
 }
 
 # this function is a good example of why threads are a must,
 # simply for priority inversion.
 sub _log_to_disk {
    # eval'uating this at runtime saves 220kb rss - perl has become
    # an insane memory waster.
    eval q{ # poor man's autoloading {}
       sub _log_to_disk {
          my ($ctx, $path, $keepopen) = @_;
 
          my $fh;
          my @queue;
          my $delay;
          my $disable;
 
          use AnyEvent::IO ();
 
          my $kick = sub {
             undef $delay;
             return unless @queue;
             $delay = 1;
 
             # we pass $kick to $kick, so $kick itself doesn't keep a reference to $kick.
             my $kick = shift;
 
             # write one or more messages
             my $write = sub {
                # we write as many messages as have been queued
                my $data = join "", @queue;
                @queue = ();
 
                AnyEvent::IO::aio_write $fh, $data, sub {
                   $disable = 1;
                   @_
                      ? ($_[0] == length $data or AE::log 4 => "unable to write to logfile '$path': short write")
                      :                           AE::log 4 => "unable to write to logfile '$path': $!";
                   undef $disable;
 
                   if ($keepopen) {
                      $kick->($kick);
                   } else {
                      AnyEvent::IO::aio_close ($fh, sub {
                         undef $fh;
                         $kick->($kick);
                      });
                   }
                };
             };
 
             if ($fh) {
                $write->();
             } else {
                AnyEvent::IO::aio_open
                   $path,
                   AnyEvent::IO::O_CREAT | AnyEvent::IO::O_WRONLY | AnyEvent::IO::O_APPEND,
                   0666,
                   sub {
                      $fh = shift
                         or do {
                            $disable = 1;
                            AE::log 4 => "unable to open logfile '$path': $!";
                            undef $disable;
                            return;
                         };
 
                      $write->();
                   }
                ;
             }
          };
 
          $ctx->log_cb (sub {
             return if $disable;
             push @queue, shift;
             $kick->($kick) unless $delay;
             0
          });
 
          $kick->($kick) if $keepopen; # initial open
       };
    };
    die if $@;
    &_log_to_disk
 }
 
 sub log_to_file {
    my ($ctx, $path) = @_;
 
    _log_to_disk $ctx, $path, 1;
 }
 
 sub log_to_path {
    my ($ctx, $path) = @_;
 
    _log_to_disk $ctx, $path, 0;
 }
 
 sub log_to_syslog {
    my ($ctx, $facility) = @_;
 
    require Sys::Syslog;
 
    $ctx->fmt_cb (sub {
       my $str = $_[3];
       $str =~ s/\n(?=.)/\n+ /g;
 
       [$_[2], "($_[1][0]) $str"]
    });
 
    $facility ||= "user";
 
    $ctx->log_cb (sub {
       my $lvl = $_[0][0] < 9 ? $_[0][0] : 8;
 
       Sys::Syslog::syslog ("$facility|" . ($lvl - 1), $_)
          for split /\n/, $_[0][1];
 
       0
    });
 }
 
 =back
 
 =head3 MESSAGE LOGGING
 
 These methods allow you to log messages directly to a context, without
 going via your package context.
 
 =over 4
 
 =item $ctx->log ($level, $msg[, @params])
 
 Same as C<AnyEvent::Log::log>, but uses the given context as log context.
 
 Example: log a message in the context of another package.
 
    (AnyEvent::Log::ctx "Other::Package")->log (warn => "heely bo");
 
 =item $logger = $ctx->logger ($level[, \$enabled])
 
 Same as C<AnyEvent::Log::logger>, but uses the given context as log
 context.
 
 =cut
 
 *log    = \&AnyEvent::Log::_log;
 *logger = \&AnyEvent::Log::_logger;
 
 =back
 
 =cut
 
 package AnyEvent::Log;
 
 =head1 CONFIGURATION VIA $ENV{PERL_ANYEVENT_LOG}
 
 Logging can also be configured by setting the environment variable
 C<PERL_ANYEVENT_LOG> (or C<AE_LOG>).
 
 The value consists of one or more logging context specifications separated
 by C<:> or whitespace. Each logging specification in turn starts with a
 context name, followed by C<=>, followed by zero or more comma-separated
 configuration directives, here are some examples:
 
    # set default logging level
    filter=warn
 
    # log to file instead of to stderr
    log=file=/tmp/mylog
 
    # log to file in addition to stderr
    log=+%file:%file=file=/tmp/mylog
 
    # enable debug log messages, log warnings and above to syslog
    filter=debug:log=+%warnings:%warnings=warn,syslog=LOG_LOCAL0
 
    # log trace messages (only) from AnyEvent::Debug to file
    AnyEvent::Debug=+%trace:%trace=only,trace,file=/tmp/tracelog
 
 A context name in the log specification can be any of the following:
 
 =over 4
 
 =item C<collect>, C<filter>, C<log>
 
 Correspond to the three predefined C<$AnyEvent::Log::COLLECT>,
 C<AnyEvent::Log::FILTER> and C<$AnyEvent::Log::LOG> contexts.
 
 =item C<%name>
 
 Context names starting with a C<%> are anonymous contexts created when the
 name is first mentioned. The difference to package contexts is that by
 default they have no attached slaves.
 
 =item a perl package name
 
 Any other string references the logging context associated with the given
 Perl C<package>. In the unlikely case where you want to specify a package
 context that matches on of the other context name forms, you can add a
 C<::> to the package name to force interpretation as a package.
 
 =back
 
 The configuration specifications can be any number of the following:
 
 =over 4
 
 =item C<stderr>
 
 Configures the context to use Perl's C<warn> function (which typically
 logs to C<STDERR>). Works like C<log_to_warn>.
 
 =item C<file=>I<path>
 
 Configures the context to log to a file with the given path. Works like
 C<log_to_file>.
 
 =item C<path=>I<path>
 
 Configures the context to log to a file with the given path. Works like
 C<log_to_path>.
 
 =item C<syslog> or C<syslog=>I<expr>
 
 Configures the context to log to syslog. If I<expr> is given, then it is
 evaluated in the L<Sys::Syslog> package, so you could use:
 
    log=syslog=LOG_LOCAL0
 
 =item C<nolog>
 
 Configures the context to not log anything by itself, which is the
 default. Same as C<< $ctx->log_cb (undef) >>.
 
 =item C<cap=>I<level>
 
 Caps logging messages entering this context at the given level, i.e.
 reduces the priority of messages with higher priority than this level. The
 default is C<0> (or C<off>), meaning the priority will not be touched.
 
 =item C<0> or C<off>
 
 Sets the logging level of the context to C<0>, i.e. all messages will be
 filtered out.
 
 =item C<all>
 
 Enables all logging levels, i.e. filtering will effectively be switched
 off (the default).
 
 =item C<only>
 
 Disables all logging levels, and changes the interpretation of following
 level specifications to enable the specified level only.
 
 Example: only enable debug messages for a context.
 
    context=only,debug
 
 =item C<except>
 
 Enables all logging levels, and changes the interpretation of following
 level specifications to disable that level. Rarely used.
 
 Example: enable all logging levels except fatal and trace (this is rather
 nonsensical).
 
    filter=exept,fatal,trace
 
 =item C<level>
 
 Enables all logging levels, and changes the interpretation of following
 level specifications to be "that level or any higher priority
 message". This is the default.
 
 Example: log anything at or above warn level.
 
    filter=warn
 
    # or, more verbose
    filter=only,level,warn
 
 =item C<1>..C<9> or a logging level name (C<error>, C<debug> etc.)
 
 A numeric loglevel or the name of a loglevel will be interpreted according
 to the most recent C<only>, C<except> or C<level> directive. By default,
 specifying a logging level enables that and any higher priority messages.
 
 =item C<+>I<context>
 
 Attaches the named context as slave to the context.
 
 =item C<+>
 
 A lone C<+> detaches all contexts, i.e. clears the slave list from the
 context. Anonymous (C<%name>) contexts have no attached slaves by default,
 but package contexts have the parent context as slave by default.
 
 Example: log messages from My::Module to a file, do not send them to the
 default log collector.
 
    My::Module=+,file=/tmp/mymodulelog
 
 =back
 
 Any character can be escaped by prefixing it with a C<\> (backslash), as
 usual, so to log to a file containing a comma, colon, backslash and some
 spaces in the filename, you would do this:
 
    PERL_ANYEVENT_LOG='log=file=/some\ \:file\ with\,\ \\-escapes'
 
 Since whitespace (which includes newlines) is allowed, it is fine to
 specify multiple lines in C<PERL_ANYEVENT_LOG>, e.g.:
 
    PERL_ANYEVENT_LOG="
       filter=warn
       AnyEvent::Debug=+%trace
       %trace=only,trace,+log
    " myprog
 
 Also, in the unlikely case when you want to concatenate specifications,
 use whitespace as separator, as C<::> will be interpreted as part of a
 module name, an empty spec with two separators:
 
    PERL_ANYEVENT_LOG="$PERL_ANYEVENT_LOG MyMod=debug"
 
 =cut
 
 for (my $spec = $ENV{PERL_ANYEVENT_LOG}) {
    my %anon;
 
    my $pkg = sub {
       $_[0] eq "log"              ? $LOG
       : $_[0] eq "filter"         ? $FILTER
       : $_[0] eq "collect"        ? $COLLECT
       : $_[0] =~ /^%(.+)$/        ? ($anon{$1} ||= do { my $ctx = ctx undef; $ctx->[0] = $_[0]; $ctx })
       : $_[0] =~ /^(.*?)(?:::)?$/ ? ctx "$1" # egad :/
       : die # never reached?
    };
 
    /\G[[:space:]]+/gc; # skip initial whitespace
 
    while (/\G((?:[^:=[:space:]]+|::|\\.)+)=/gc) {
       my $ctx = $pkg->($1);
       my $level = "level";
 
       while (/\G((?:[^,:[:space:]]+|::|\\.)+)/gc) {
          for ("$1") {
             if ($_ eq "stderr"               ) { $ctx->log_to_warn;
             } elsif (/^file=(.+)/            ) { $ctx->log_to_file ("$1");
             } elsif (/^path=(.+)/            ) { $ctx->log_to_path ("$1");
             } elsif (/^syslog(?:=(.*))?/     ) { require Sys::Syslog; $ctx->log_to_syslog ("$1");
             } elsif ($_ eq "nolog"           ) { $ctx->log_cb (undef);
             } elsif (/^cap=(.+)/             ) { $ctx->cap ("$1");
             } elsif (/^\+(.+)$/              ) { $ctx->attach ($pkg->("$1"));
             } elsif ($_ eq "+"               ) { $ctx->slaves;
             } elsif ($_ eq "off" or $_ eq "0") { $ctx->level (0);
             } elsif ($_ eq "all"             ) { $ctx->level ("all");
             } elsif ($_ eq "level"           ) { $ctx->level ("all"); $level = "level";
             } elsif ($_ eq "only"            ) { $ctx->level ("off"); $level = "enable";
             } elsif ($_ eq "except"          ) { $ctx->level ("all"); $level = "disable";
             } elsif (/^\d$/                  ) { $ctx->$level ($_);
             } elsif (exists $STR2LEVEL{$_}   ) { $ctx->$level ($_);
             } else                             { die "PERL_ANYEVENT_LOG ($spec): parse error at '$_'\n";
             }
          }
 
          /\G,/gc or last;
       }
 
       /\G[:[:space:]]+/gc or last;
    }
 
    /\G[[:space:]]+/gc; # skip trailing whitespace
 
    if (/\G(.+)/g) {
       die "PERL_ANYEVENT_LOG ($spec): parse error at '$1'\n";
    }
 }
 
 =head1 EXAMPLES
 
 This section shows some common configurations, both as code, and as
 C<PERL_ANYEVENT_LOG> string.
 
 =over 4
 
 =item Setting the global logging level.
 
 Either put C<PERL_ANYEVENT_VERBOSE=><number> into your environment before
 running your program, use C<PERL_ANYEVENT_LOG> or modify the log level of
 the root context at runtime:
 
    PERL_ANYEVENT_VERBOSE=5 ./myprog
 
    PERL_ANYEVENT_LOG=log=warn
 
    $AnyEvent::Log::FILTER->level ("warn");
 
 =item Append all messages to a file instead of sending them to STDERR.
 
 This is affected by the global logging level.
 
    $AnyEvent::Log::LOG->log_to_file ($path);
 
    PERL_ANYEVENT_LOG=log=file=/some/path
 
 =item Write all messages with priority C<error> and higher to a file.
 
 This writes them only when the global logging level allows it, because
 it is attached to the default context which is invoked I<after> global
 filtering.
 
    $AnyEvent::Log::FILTER->attach (
       new AnyEvent::Log::Ctx log_to_file => $path);
 
    PERL_ANYEVENT_LOG=filter=+%filelogger:%filelogger=file=/some/path
 
 This writes them regardless of the global logging level, because it is
 attached to the toplevel context, which receives all messages I<before>
 the global filtering.
 
    $AnyEvent::Log::COLLECT->attach (
       new AnyEvent::Log::Ctx log_to_file => $path);
 
    PERL_ANYEVENT_LOG=%filelogger=file=/some/path:collect=+%filelogger
 
 In both cases, messages are still written to STDERR.
 
 =item Additionally log all messages with C<warn> and higher priority to
 C<syslog>, but cap at C<error>.
 
 This logs all messages to the default log target, but also logs messages
 with priority C<warn> or higher (and not filtered otherwise) to syslog
 facility C<user>. Messages with priority higher than C<error> will be
 logged with level C<error>.
 
    $AnyEvent::Log::LOG->attach (
       new AnyEvent::Log::Ctx
          level  => "warn",
          cap    => "error",
          syslog => "user",
    );
 
    PERL_ANYEVENT_LOG=log=+%syslog:%syslog=warn,cap=error,syslog
 
 =item Write trace messages (only) from L<AnyEvent::Debug> to the default logging target(s).
 
 Attach the C<$AnyEvent::Log::LOG> context to the C<AnyEvent::Debug>
 context - this simply circumvents the global filtering for trace messages.
 
    my $debug = AnyEvent::Debug->AnyEvent::Log::ctx;
    $debug->attach ($AnyEvent::Log::LOG);
 
    PERL_ANYEVENT_LOG=AnyEvent::Debug=+log
 
 This of course works for any package, not just L<AnyEvent::Debug>, but
 assumes the log level for AnyEvent::Debug hasn't been changed from the
 default.
 
 =back
 
 =head1 ASYNCHRONOUS DISK I/O
 
 This module uses L<AnyEvent::IO> to actually write log messages (in
 C<log_to_file> and C<log_to_path>), so it doesn't block your program when
 the disk is busy and a non-blocking L<AnyEvent::IO> backend is available.
 
 =head1 AUTHOR
 
  Marc Lehmann <schmorp@schmorp.de>
  http://anyevent.schmorp.de
 
 =cut
 
 1
 
### AnyEvent/Loop.pm ###
 =head1 NAME
 
 AnyEvent::Loop - AnyEvent's Pure-Perl event loop
 
 =head1 SYNOPSIS
 
    use AnyEvent;
    # use AnyEvent::Loop;
   
    # this module gets loaded automatically when no other loop can be found
 
    # Explicit use:
    use AnyEvent::Loop;
    use AnyEvent;
 
    ...
 
    AnyEvent::Loop::run; # run the event loop
 
 =head1 DESCRIPTION
 
 This module provides an event loop for AnyEvent in case no other event
 loop could be found or loaded. You don't have to do anything to make it
 work with AnyEvent except by possibly loading it before creating the first
 AnyEvent watcher.
 
 This module is I<not> some loop abstracion used by AnyEvent, but just
 another event loop like EV or Glib, just written in pure perl and
 delivered with AnyEvent, so AnyEvent always works, even in the absence of
 any other backend.
 
 If you want to use this module instead of autoloading a potentially better
 event loop you can simply load it (and no other event loops) before
 creating the first watcher.
 
 As for performance, this module is on par with (and usually faster than)
 most select/poll-based C event modules such as Event or Glib (it does not
 even come close to EV, though), with respect to I/O watchers. Timers are
 handled less optimally, but for many common tasks, it is still on par with
 event loops written in C.
 
 This event loop has been optimised for the following use cases:
 
 =over 4
 
 =item monotonic clock is available
 
 This module will use the POSIX monotonic clock option (if it can be
 detected at runtime) or the POSIX C<times> function (if the resolution
 is at least 100Hz), in which case it will not suffer adversely from time
 jumps.
 
 If no monotonic clock is available, this module will not attempt to
 correct for time jumps in any way.
 
 The clock chosen will be reported if the environment variable
 C<$PERL_ANYEVENT_VERBOSE> is set to 8 or higher.
 
 =item any number of watchers on one fd
 
 Supporting a large number of watchers per fd is purely a dirty benchmark
 optimisation not relevant in practise. The more common case of having one
 watcher per fd/poll combo is special-cased, however, and therefore fast,
 too.
 
 =item relatively few active fds per C<select> call
 
 This module expects that only a tiny amount of fds is active at any one
 time. This is relatively typical of larger servers (but not the case where
 C<select> traditionally is fast), at the expense of the "dense activity
 case" where most of the fds are active (which suits C<select>).
 
 The optimal implementation of the "dense" case is not much faster, though,
 so the module should behave very well in most cases, subject to the bad
 scalability of C<select> in the presence of a large number of inactive
 file descriptors.
 
 =item lots of timer changes/iteration, or none at all
 
 This module sorts the timer list using perl's C<sort>, even though a total
 ordering is not required for timers internally.
 
 This sorting is expensive, but means sorting can be avoided unless the
 timer list has changed in a way that requires a new sort.
 
 This means that adding lots of timers is very efficient, as well as not
 changing the timers. Advancing timers (e.g. recreating a timeout watcher
 on activity) is also relatively efficient, for example, if you have a
 large number of timeout watchers that time out after 10 seconds, then the
 timer list will be sorted only once every 10 seconds.
 
 This should not have much of an impact unless you have hundreds or
 thousands of timers, though, or your timers have very small timeouts.
 
 =back
 
 =head1 FUNCTIONS
 
 The only user-visible functions provided by this module loop related -
 watchers are created via the normal AnyEvent mechanisms.
 
 =over 4
 
 =item AnyEvent::Loop::run
 
 Run the event loop, usually the last thing done in the main program when
 you want to use the pure-perl backend.
 
 =item AnyEvent::Loop::one_event
 
 Blocks until at least one new event has been received by the operating
 system, whether or not it was AnyEvent-related.
 
 =back
 
 =cut
 
 package AnyEvent::Loop;
 
 use Scalar::Util qw(weaken);
 use List::Util ();
 
 use AnyEvent (); BEGIN { AnyEvent::common_sense }
 use AnyEvent::Util ();
 
 our $VERSION = $AnyEvent::VERSION;
 
 our ($NOW, $MNOW);
 
 sub MAXWAIT() { 3600 } # never sleep for longer than this many seconds
 
 BEGIN {
    local $SIG{__DIE__}; # protect us against the many broken __DIE__ handlers out there
    my $time_hires = eval "use Time::HiRes (); 1";
    my $clk_tck    = eval "use POSIX (); POSIX::sysconf (POSIX::_SC_CLK_TCK ())";
    my $round; # actual granularity
 
    if ($time_hires && eval "&Time::HiRes::clock_gettime (Time::HiRes::CLOCK_MONOTONIC ())") {
       AE::log 8 => "Using CLOCK_MONOTONIC as timebase.";
       *_update_clock = sub {
          $NOW  = &Time::HiRes::time;
          $MNOW = Time::HiRes::clock_gettime (&Time::HiRes::CLOCK_MONOTONIC);
       };
 
    } elsif (100 <= $clk_tck && $clk_tck <= 1000000 && eval { (POSIX::times ())[0] != -1 }) { # -1 is also a valid return value :/
       AE::log 8 => "Using POSIX::times (monotonic) as timebase.";
       my $HZ1 = 1 / $clk_tck;
 
       my $last = (POSIX::times ())[0];
       my $next;
       *_update_clock = sub {
          $NOW  = time; # d'oh
 
          $next = (POSIX::times ())[0];
          # we assume 32 bit signed on wrap but 64 bit will never wrap
          $last -= 4294967296 if $last > $next; # 0x100000000, but perl has problems with big hex constants
          $MNOW += ($next - $last) * $HZ1;
          $last = $next;
       };
 
       $round = $HZ1;
 
    } elsif (eval "use Time::HiRes (); 1") {
       AE::log 8 => "Using Time::HiRes::time (non-monotonic) clock as timebase.";
       *_update_clock = sub {
          $NOW = $MNOW = &Time::HiRes::time;
       };
 
    } else {
       AE::log fatal => "Unable to find sub-second time source (is this really perl 5.8.0 or later?)";
    }
 
    $round = 0.001 if $round < 0.001; # 1ms is enough for us
    $round -= $round * 1e-2; # 0.1 => 0.099
    eval "sub ROUNDUP() { $round }";
 }
 
 _update_clock;
 
 # rely on AnyEvent:Base::time to provide time
 sub now       () { $NOW          }
 sub now_update() { _update_clock }
 
 # fds[0] is for read, fds[1] is for write watchers
 # fds[poll][V] is the bitmask for select
 # fds[poll][W][fd] contains a list of i/o watchers
 # an I/O watcher is a blessed arrayref containing [fh, poll(0/1), callback, queue-index]
 # the queue-index is simply the index in the [W] array, which is only used to improve
 # benchmark results in the synthetic "many watchers on one fd" benchmark.
 my @fds = ([], []);
 sub V() { 0 }
 sub W() { 1 }
 
 my $need_sort = 1e300; # when to re-sort timer list
 my @timer; # list of [ abs-timeout, Timer::[callback] ]
 my @idle;  # list of idle callbacks
 
 # the pure perl mainloop
 sub one_event {
    _update_clock;
 
    # first sort timers if required (slow)
    if ($MNOW >= $need_sort) {
       $need_sort = 1e300;
       @timer = sort { $a->[0] <=> $b->[0] } @timer;
    }
 
    # handle all pending timers
    if (@timer && $timer[0][0] <= $MNOW) {
       do {
          my $timer = shift @timer;
          $timer->[1] && $timer->[1]($timer);
       } while @timer && $timer[0][0] <= $MNOW;
 
    } else {
       # poll for I/O events, we do not do this when there
       # were any pending timers to ensure that one_event returns
       # quickly when some timers have been handled
       my ($wait, @vec, $fds)
          = (@timer && $timer[0][0] < $need_sort ? $timer[0][0] : $need_sort) - $MNOW;
 
       $wait = $wait < MAXWAIT ? $wait + ROUNDUP : MAXWAIT;
       $wait = 0 if @idle;
 
       $fds = CORE::select
         $vec[0] = $fds[0][V],
         $vec[1] = $fds[1][V],
         AnyEvent::WIN32 ? $vec[2] = $fds[1][V] : undef,
         $wait;
 
       _update_clock;
 
       if ($fds > 0) {
          # buggy microshit windows errornously sets exceptfds instead of writefds
          $vec[1] |= $vec[2] if AnyEvent::WIN32;
 
          # prefer write watchers, because they might reduce memory pressure.
          for (1, 0) {
             my $fds = $fds[$_];
 
             # we parse the bitmask by first expanding it into
             # a string of bits
             for (unpack "b*", $vec[$_]) {
                # and then repeatedly matching a regex against it
                while (/1/g) {
                   # and use the resulting string position as fd
                   $_ && $_->[2]()
                      for @{ $fds->[W][(pos) - 1] || [] };
                }
             }
          }
       } elsif (AnyEvent::WIN32 && $fds && $! == AnyEvent::Util::WSAEINVAL) {
          # buggy microshit windoze asks us to route around it
          CORE::select undef, undef, undef, $wait if $wait;
       } elsif (!@timer || $timer[0][0] > $MNOW && !$fds) {
          $$$_ && $$$_->() for @idle = grep $$$_, @idle;
       }
    }
 }
 
 sub run {
    one_event while 1;
 }
 
 sub io($$$) {
    my ($fd, $write, $cb) = @_;
 
    defined ($fd = fileno $fd)
       or $fd = $_[0];
 
    my $self = bless [
       $fd,
       $write,
       $cb,
       # q-idx
    ], "AnyEvent::Loop::io";
 
    my $fds = $fds[$self->[1]];
 
    # add watcher to fds structure
    my $q = $fds->[W][$fd] ||= [];
 
    (vec $fds->[V], $fd, 1) = 1;
 
    $self->[3] = @$q;
    push @$q, $self;
    weaken $q->[-1];
 
    $self
 }
 
 sub AnyEvent::Loop::io::DESTROY {
    my ($self) = @_;
 
    my $fds = $fds[$self->[1]];
 
    # remove watcher from fds structure
    my $fd = $self->[0];
 
    if (@{ $fds->[W][$fd] } == 1) {
       delete $fds->[W][$fd];
       (vec $fds->[V], $fd, 1) = 0;
    } else {
       my $q = $fds->[W][$fd];
       my $last = pop @$q;
 
       if ($last != $self) {
          weaken ($q->[$self->[3]] = $last);
          $last->[3] = $self->[3];
       }
    }
 }
 
 sub timer($$$) {
    my ($after, $interval, $cb) = @_;
    
    my $self;
 
    if ($interval) {
       $self = [$MNOW + $after , sub {
          $_[0][0] = List::Util::max $_[0][0] + $interval, $MNOW;
          push @timer, $_[0];
          weaken $timer[-1];
          $need_sort = $_[0][0] if $_[0][0] < $need_sort;
          &$cb;
       }];
    } else {
       $self = [$MNOW + $after, $cb];
    }
 
    push @timer, $self;
    weaken $timer[-1];
    $need_sort = $self->[0] if $self->[0] < $need_sort;
 
    $self
 }
 
 sub idle($) {
    my $cb = shift;
 
    push @idle, \\$cb;
    weaken ${$idle[-1]};
 
    ${$idle[-1]}
 }
 
 =head1 SEE ALSO
 
 L<AnyEvent>.
 
 =head1 AUTHOR
 
    Marc Lehmann <schmorp@schmorp.de>
    http://anyevent.schmorp.de
 
 =cut
 
 1
 
### AnyEvent/Socket.pm ###
 =head1 NAME
 
 AnyEvent::Socket - useful IPv4 and IPv6 stuff. also unix domain sockets. and stuff.
 
 =head1 SYNOPSIS
 
    use AnyEvent::Socket;
    
    tcp_connect "gameserver.deliantra.net", 13327, sub {
       my ($fh) = @_
          or die "gameserver.deliantra.net connect failed: $!";
    
       # enjoy your filehandle
    };
    
    # a simple tcp server
    tcp_server undef, 8888, sub {
       my ($fh, $host, $port) = @_;
    
       syswrite $fh, "The internet is full, $host:$port. Go away!\015\012";
    };
 
 =head1 DESCRIPTION
 
 This module implements various utility functions for handling internet
 protocol addresses and sockets, in an as transparent and simple way as
 possible.
 
 All functions documented without C<AnyEvent::Socket::> prefix are exported
 by default.
 
 =over 4
 
 =cut
 
 package AnyEvent::Socket;
 
 use Carp ();
 use Errno ();
 use Socket qw(AF_INET AF_UNIX SOCK_STREAM SOCK_DGRAM SOL_SOCKET SO_REUSEADDR);
 
 use AnyEvent (); BEGIN { AnyEvent::common_sense }
 use AnyEvent::Util qw(guard AF_INET6);
 use AnyEvent::DNS ();
 
 use base 'Exporter';
 
 our @EXPORT = qw(
    getprotobyname
    parse_hostport format_hostport
    parse_ipv4 parse_ipv6
    parse_ip parse_address
    format_ipv4 format_ipv6
    format_ip format_address
    address_family
    inet_aton
    tcp_server
    tcp_connect
 );
 
 our $VERSION = $AnyEvent::VERSION;
 
 =item $ipn = parse_ipv4 $dotted_quad
 
 Tries to parse the given dotted quad IPv4 address and return it in
 octet form (or undef when it isn't in a parsable format). Supports all
 forms specified by POSIX (e.g. C<10.0.0.1>, C<10.1>, C<10.0x020304>,
 C<0x12345678> or C<0377.0377.0377.0377>).
 
 =cut
 
 sub parse_ipv4($) {
    $_[0] =~ /^      (?: 0x[0-9a-fA-F]+ | 0[0-7]* | [1-9][0-9]* )
               (?:\. (?: 0x[0-9a-fA-F]+ | 0[0-7]* | [1-9][0-9]* ) ){0,3}$/x
       or return undef;
 
    @_ = map /^0/ ? oct : $_, split /\./, $_[0];
 
    # check leading parts against range
    return undef if grep $_ >= 256, @_[0 .. @_ - 2];
 
    # check trailing part against range
    return undef if $_[-1] >= 2 ** (8 * (4 - $#_));
 
    pack "N", (pop)
              + ($_[0] << 24)
              + ($_[1] << 16)
              + ($_[2] <<  8);
 }
 
 =item $ipn = parse_ipv6 $textual_ipv6_address
 
 Tries to parse the given IPv6 address and return it in
 octet form (or undef when it isn't in a parsable format).
 
 Should support all forms specified by RFC 2373 (and additionally all IPv4
 forms supported by parse_ipv4). Note that scope-id's are not supported
 (and will not parse).
 
 This function works similarly to C<inet_pton AF_INET6, ...>.
 
 Example:
 
    print unpack "H*", parse_ipv6 "2002:5345::10.0.0.1";
    # => 2002534500000000000000000a000001
 
 =cut
 
 sub parse_ipv6($) {
    # quick test to avoid longer processing
    my $n = $_[0] =~ y/://;
    return undef if $n < 2 || $n > 8;
 
    my ($h, $t) = split /::/, $_[0], 2;
 
    unless (defined $t) {
       ($h, $t) = (undef, $h);
    }
 
    my @h = split /:/, $h, -1;
    my @t = split /:/, $t, -1;
 
    # check for ipv4 tail
    if (@t && $t[-1]=~ /\./) {
       return undef if $n > 6;
 
       my $ipn = parse_ipv4 pop @t
          or return undef;
 
       push @t, map +(sprintf "%x", $_), unpack "nn", $ipn;
    }
 
    # no :: then we need to have exactly 8 components
    return undef unless @h + @t == 8 || $_[0] =~ /::/;
 
    # now check all parts for validity
    return undef if grep !/^[0-9a-fA-F]{1,4}$/, @h, @t;
 
    # now pad...
    push @h, 0 while @h + @t < 8;
 
    # and done
    pack "n*", map hex, @h, @t
 }
 
 =item $token = parse_unix $hostname
 
 This fucntion exists mainly for symmetry to the other C<parse_protocol>
 functions - it takes a hostname and, if it is C<unix/>, it returns a
 special address token, otherwise C<undef>.
 
 The only use for this function is probably to detect whether a hostname
 matches whatever AnyEvent uses for unix domain sockets.
 
 =cut
 
 sub parse_unix($) {
    $_[0] eq "unix/"
       ? pack "S", AF_UNIX
       : undef
 
 }
 
 =item $ipn = parse_address $ip
 
 Combines C<parse_ipv4> and C<parse_ipv6> in one function. The address
 here refers to the host address (not socket address) in network form
 (binary).
 
 If the C<$text> is C<unix/>, then this function returns a special token
 recognised by the other functions in this module to mean "UNIX domain
 socket".
 
 If the C<$text> to parse is a mapped IPv4 in IPv6 address (:ffff::<ipv4>),
 then it will be treated as an IPv4 address. If you don't want that, you
 have to call C<parse_ipv4> and/or C<parse_ipv6> manually.
 
 Example:
 
    print unpack "H*", parse_address "10.1.2.3";
    # => 0a010203
 
 =item $ipn = AnyEvent::Socket::aton $ip
 
 Same as C<parse_address>, but not exported (think C<Socket::inet_aton> but
 I<without> name resolution).
 
 =cut
 
 sub parse_address($) {
    for (&parse_ipv6) {
       if ($_) {
          s/^\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff//;
          return $_;
       } else {
          return &parse_ipv4 || &parse_unix
       }
    }
 }
 
 *aton = \&parse_address;
 
 =item ($name, $aliases, $proto) = getprotobyname $name
 
 Works like the builtin function of the same name, except it tries hard to
 work even on broken platforms (well, that's windows), where getprotobyname
 is traditionally very unreliable.
 
 Example: get the protocol number for TCP (usually 6)
 
    my $proto = getprotobyname "tcp";
 
 =cut
 
 # microsoft can't even get getprotobyname working (the etc/protocols file
 # gets lost fairly often on windows), so we have to hardcode some common
 # protocol numbers ourselves.
 our %PROTO_BYNAME;
 
 $PROTO_BYNAME{tcp}  = Socket::IPPROTO_TCP () if defined &Socket::IPPROTO_TCP;
 $PROTO_BYNAME{udp}  = Socket::IPPROTO_UDP () if defined &Socket::IPPROTO_UDP;
 $PROTO_BYNAME{icmp} = Socket::IPPROTO_ICMP() if defined &Socket::IPPROTO_ICMP;
 
 sub getprotobyname($) {
    my $name = lc shift;
 
    defined (my $proton = $PROTO_BYNAME{$name} || (getprotobyname $name)[2])
       or return;
 
    ($name, uc $name, $proton)
 }
 
 =item ($host, $service) = parse_hostport $string[, $default_service]
 
 Splitting a string of the form C<hostname:port> is a common
 problem. Unfortunately, just splitting on the colon makes it hard to
 specify IPv6 addresses and doesn't support the less common but well
 standardised C<[ip literal]> syntax.
 
 This function tries to do this job in a better way, it supports (at
 least) the following formats, where C<port> can be a numerical port
 number of a service name, or a C<name=port> string, and the C< port> and
 C<:port> parts are optional. Also, everywhere where an IP address is
 supported a hostname or unix domain socket address is also supported (see
 C<parse_unix>), and strings starting with C</> will also be interpreted as
 unix domain sockets.
 
    hostname:port    e.g. "www.linux.org", "www.x.de:443", "www.x.de:https=443",
    ipv4:port        e.g. "198.182.196.56", "127.1:22"
    ipv6             e.g. "::1", "affe::1"
    [ipv4or6]:port   e.g. "[::1]", "[10.0.1]:80"
    [ipv4or6] port   e.g. "[127.0.0.1]", "[www.x.org] 17"
    ipv4or6 port     e.g. "::1 443", "10.0.0.1 smtp"
    unix/:path       e.g. "unix/:/path/to/socket"
    /path            e.g. "/path/to/socket"
 
 It also supports defaulting the service name in a simple way by using
 C<$default_service> if no service was detected. If neither a service was
 detected nor a default was specified, then this function returns the
 empty list. The same happens when a parse error was detected, such as a
 hostname with a colon in it (the function is rather conservative, though).
 
 Example:
 
   print join ",", parse_hostport "localhost:443";
   # => "localhost,443"
 
   print join ",", parse_hostport "localhost", "https";
   # => "localhost,https"
 
   print join ",", parse_hostport "[::1]";
   # => "," (empty list)
 
   print join ",", parse_hostport "/tmp/debug.sock";
   # => "unix/", "/tmp/debug.sock"
 
 =cut
 
 sub parse_hostport($;$) {
    my ($host, $port);
 
    for ("$_[0]") { # work on a copy, just in case, and also reset pos
 
       # shortcut for /path
       return ("unix/", $_)
          if m%^/%;
 
       # parse host, special cases: "ipv6" or "ipv6[#p ]port"
       unless (
          ($host) = /^\s* ([0-9a-fA-F:]*:[0-9a-fA-F:]*:[0-9a-fA-F\.:]*)/xgc
          and parse_ipv6 $host
       ) {
          /^\s*/xgc;
 
          if (/^ \[ ([^\[\]]+) \]/xgc) {
             $host = $1;
          } elsif (/^ ([^\[\]:\ ]+) /xgc) {
             $host = $1;
          } else {
             return;
          }
       }
 
       # parse port
       if (/\G (?:\s+|:|\#) ([^:[:space:]]+) \s*$/xgc) {
          $port = $1;
       } elsif (/\G\s*$/gc && length $_[1]) {
          $port = $_[1];
       } else {
          return;
       }
 
    }
 
    # hostnames must not contain :'s
    return if $host =~ /:/ && !parse_ipv6 $host;
 
    ($host, $port)
 }
 
 =item $string = format_hostport $host, $port
 
 Takes a host (in textual form) and a port and formats in unambigiously in
 a way that C<parse_hostport> can parse it again. C<$port> can be C<undef>.
 
 =cut
 
 sub format_hostport($;$) {
    my ($host, $port) = @_;
 
    $port = ":$port"  if length $port;
    $host = "[$host]" if $host =~ /:/;
 
    "$host$port"
 }
 
 =item $sa_family = address_family $ipn
 
 Returns the address family/protocol-family (AF_xxx/PF_xxx, in one value :)
 of the given host address in network format.
 
 =cut
 
 sub address_family($) {
    4 == length $_[0]
       ? AF_INET
       : 16 == length $_[0]
          ? AF_INET6
          : unpack "S", $_[0]
 }
 
 =item $text = format_ipv4 $ipn
 
 Expects a four octet string representing a binary IPv4 address and returns
 its textual format. Rarely used, see C<format_address> for a nicer
 interface.
 
 =item $text = format_ipv6 $ipn
 
 Expects a sixteen octet string representing a binary IPv6 address and
 returns its textual format. Rarely used, see C<format_address> for a
 nicer interface.
 
 =item $text = format_address $ipn
 
 Covnvert a host address in network format (e.g. 4 octets for IPv4 or 16
 octets for IPv6) and convert it into textual form.
 
 Returns C<unix/> for UNIX domain sockets.
 
 This function works similarly to C<inet_ntop AF_INET || AF_INET6, ...>,
 except it automatically detects the address type.
 
 Returns C<undef> if it cannot detect the type.
 
 If the C<$ipn> is a mapped IPv4 in IPv6 address (:ffff::<ipv4>), then just
 the contained IPv4 address will be returned. If you do not want that, you
 have to call C<format_ipv6> manually.
 
 Example:
 
    print format_address "\x01\x02\x03\x05";
    => 1.2.3.5
 
 =item $text = AnyEvent::Socket::ntoa $ipn
 
 Same as format_address, but not exported (think C<inet_ntoa>).
 
 =cut
 
 sub format_ipv4($) {
    join ".", unpack "C4", $_[0]
 }
 
 sub format_ipv6($) {
    if ($_[0] =~ /^\x00\x00\x00\x00\x00\x00\x00\x00/) {
       if (v0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0 eq $_[0]) {
          return "::";
       } elsif (v0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.1 eq $_[0]) {
          return "::1";
       } elsif (v0.0.0.0.0.0.0.0.0.0.0.0 eq substr $_[0], 0, 12) {
          # v4compatible
          return "::" . format_ipv4 substr $_[0], 12;
       } elsif (v0.0.0.0.0.0.0.0.0.0.255.255 eq substr $_[0], 0, 12) {
          # v4mapped
          return "::ffff:" . format_ipv4 substr $_[0], 12;
       } elsif (v0.0.0.0.0.0.0.0.255.255.0.0 eq substr $_[0], 0, 12) {
          # v4translated
          return "::ffff:0:" . format_ipv4 substr $_[0], 12;
       }
    }
 
    my $ip = sprintf "%x:%x:%x:%x:%x:%x:%x:%x", unpack "n8", $_[0];
 
    # this is admittedly rather sucky
       $ip =~ s/(?:^|:) 0:0:0:0:0:0:0 (?:$|:)/::/x
    or $ip =~ s/(?:^|:)   0:0:0:0:0:0 (?:$|:)/::/x
    or $ip =~ s/(?:^|:)     0:0:0:0:0 (?:$|:)/::/x
    or $ip =~ s/(?:^|:)       0:0:0:0 (?:$|:)/::/x
    or $ip =~ s/(?:^|:)         0:0:0 (?:$|:)/::/x
    or $ip =~ s/(?:^|:)           0:0 (?:$|:)/::/x;
 
    $ip
 }
 
 sub format_address($) {
    if (4 == length $_[0]) {
       return &format_ipv4;
    } elsif (16 == length $_[0]) {
       return $_[0] =~ /^\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff(....)$/s
          ? format_ipv4 $1
          : &format_ipv6;
    } elsif (AF_UNIX == address_family $_[0]) {
       return "unix/"
    } else {
       return undef
    }
 }
 
 *ntoa = \&format_address;
 
 =item inet_aton $name_or_address, $cb->(@addresses)
 
 Works similarly to its Socket counterpart, except that it uses a
 callback. Use the length to distinguish between ipv4 and ipv6 (4 octets
 for IPv4, 16 for IPv6), or use C<format_address> to convert it to a more
 readable format.
 
 Note that C<resolve_sockaddr>, while initially a more complex interface,
 resolves host addresses, IDNs, service names and SRV records and gives you
 an ordered list of socket addresses to try and should be preferred over
 C<inet_aton>.
 
 Example.
 
    inet_aton "www.google.com", my $cv = AE::cv;
    say unpack "H*", $_
       for $cv->recv;
    # => d155e363
    # => d155e367 etc.
 
    inet_aton "ipv6.google.com", my $cv = AE::cv;
    say unpack "H*", $_
       for $cv->recv;
    # => 20014860a00300000000000000000068
 
 =cut
 
 sub inet_aton {
    my ($name, $cb) = @_;
 
    if (my $ipn = &parse_ipv4) {
       $cb->($ipn);
    } elsif (my $ipn = &parse_ipv6) {
       $cb->($ipn);
    } elsif ($name eq "localhost") { # rfc2606 et al.
       $cb->(v127.0.0.1, v0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.1);
    } else {
       require AnyEvent::DNS unless $AnyEvent::DNS::VERSION;
 
       my $ipv4 = $AnyEvent::PROTOCOL{ipv4};
       my $ipv6 = $AnyEvent::PROTOCOL{ipv6};
 
       my @res;
 
       my $cv = AE::cv {
          $cb->(map @$_, reverse @res);
       };
 
       $cv->begin;
 
       if ($ipv4) {
          $cv->begin;
          AnyEvent::DNS::a ($name, sub {
             $res[$ipv4] = [map { parse_ipv4 $_ } @_];
             $cv->end;
          });
       };
 
       if ($ipv6) {
          $cv->begin;
          AnyEvent::DNS::aaaa ($name, sub {
             $res[$ipv6] = [map { parse_ipv6 $_ } @_];
             $cv->end;
          });
       };
 
       $cv->end;
    }
 }
 
 BEGIN {
    *sockaddr_family = $Socket::VERSION >= 1.75
       ? \&Socket::sockaddr_family
       : # for 5.6.x, we need to do something much more horrible
         (Socket::pack_sockaddr_in 0x5555, "\x55\x55\x55\x55"
            | eval { Socket::pack_sockaddr_un "U" }) =~ /^\x00/
            ? sub { unpack "xC", $_[0] }
            : sub { unpack "S" , $_[0] };
 }
 
 # check for broken platforms with an extra field in sockaddr structure
 # kind of a rfc vs. bsd issue, as usual (ok, normally it's a
 # unix vs. bsd issue, a iso C vs. bsd issue or simply a
 # correctness vs. bsd issue.)
 my $pack_family = 0x55 == sockaddr_family ("\x55\x55")
                   ? "xC" : "S";
 
 =item $sa = AnyEvent::Socket::pack_sockaddr $service, $host
 
 Pack the given port/host combination into a binary sockaddr
 structure. Handles both IPv4 and IPv6 host addresses, as well as UNIX
 domain sockets (C<$host> == C<unix/> and C<$service> == absolute
 pathname).
 
 Example:
 
    my $bind = AnyEvent::Socket::pack_sockaddr 43, v195.234.53.120;
    bind $socket, $bind
       or die "bind: $!";
 
 =cut
 
 sub pack_sockaddr($$) {
    my $af = address_family $_[1];
 
    if ($af == AF_INET) {
       Socket::pack_sockaddr_in $_[0], $_[1]
    } elsif ($af == AF_INET6) {
       pack "$pack_family nL a16 L",
          AF_INET6,
          $_[0], # port
          0,     # flowinfo
          $_[1], # addr
          0      # scope id
    } elsif ($af == AF_UNIX) {
       Socket::pack_sockaddr_un $_[0]
    } else {
       Carp::croak "pack_sockaddr: invalid host";
    }
 }
 
 =item ($service, $host) = AnyEvent::Socket::unpack_sockaddr $sa
 
 Unpack the given binary sockaddr structure (as used by bind, getpeername
 etc.) into a C<$service, $host> combination.
 
 For IPv4 and IPv6, C<$service> is the port number and C<$host> the host
 address in network format (binary).
 
 For UNIX domain sockets, C<$service> is the absolute pathname and C<$host>
 is a special token that is understood by the other functions in this
 module (C<format_address> converts it to C<unix/>).
 
 =cut
 
 # perl contains a bug (imho) where it requires that the kernel always returns
 # sockaddr_un structures of maximum length (which is not, AFAICS, required
 # by any standard). try to 0-pad structures for the benefit of those platforms.
 # unfortunately, the IO::Async author chose to break Socket again in version
 # 2.011 - it now contains a bogus length check, so we disable the workaround.
 
 my $sa_un_zero = $Socket::VERSION >= 2.011
    ? ""
    : eval { Socket::pack_sockaddr_un "" };
 
 $sa_un_zero ^= $sa_un_zero;
 
 sub unpack_sockaddr($) {
    my $af = sockaddr_family $_[0];
 
    if ($af == AF_INET) {
       Socket::unpack_sockaddr_in $_[0]
    } elsif ($af == AF_INET6) {
       unpack "x2 n x4 a16", $_[0]
    } elsif ($af == AF_UNIX) {
       ((Socket::unpack_sockaddr_un $_[0] ^ $sa_un_zero), pack "S", AF_UNIX)
    } else {
       Carp::croak "unpack_sockaddr: unsupported protocol family $af";
    }
 }
 
 =item AnyEvent::Socket::resolve_sockaddr $node, $service, $proto, $family, $type, $cb->([$family, $type, $proto, $sockaddr], ...)
 
 Tries to resolve the given nodename and service name into protocol families
 and sockaddr structures usable to connect to this node and service in a
 protocol-independent way. It works remotely similar to the getaddrinfo
 posix function.
 
 For internet addresses, C<$node> is either an IPv4 or IPv6 address, an
 internet hostname (DNS domain name or IDN), and C<$service> is either
 a service name (port name from F</etc/services>) or a numerical port
 number. If both C<$node> and C<$service> are names, then SRV records
 will be consulted to find the real service, otherwise they will be
 used as-is. If you know that the service name is not in your services
 database, then you can specify the service in the format C<name=port>
 (e.g. C<http=80>).
 
 If a host cannot be found via DNS, then it will be looked up in
 F</etc/hosts> (or the file specified via C<< $ENV{PERL_ANYEVENT_HOSTS}
 >>). If they are found, the addresses there will be used. The effect is as
 if entries from F</etc/hosts> would yield C<A> and C<AAAA> records for the
 host name unless DNS already had records for them.
 
 For UNIX domain sockets, C<$node> must be the string C<unix/> and
 C<$service> must be the absolute pathname of the socket. In this case,
 C<$proto> will be ignored.
 
 C<$proto> must be a protocol name, currently C<tcp>, C<udp> or
 C<sctp>. The default is currently C<tcp>, but in the future, this function
 might try to use other protocols such as C<sctp>, depending on the socket
 type and any SRV records it might find.
 
 C<$family> must be either C<0> (meaning any protocol is OK), C<4> (use
 only IPv4) or C<6> (use only IPv6). The default is influenced by
 C<$ENV{PERL_ANYEVENT_PROTOCOLS}>.
 
 C<$type> must be C<SOCK_STREAM>, C<SOCK_DGRAM> or C<SOCK_SEQPACKET> (or
 C<undef> in which case it gets automatically chosen to be C<SOCK_STREAM>
 unless C<$proto> is C<udp>).
 
 The callback will receive zero or more array references that contain
 C<$family, $type, $proto> for use in C<socket> and a binary
 C<$sockaddr> for use in C<connect> (or C<bind>).
 
 The application should try these in the order given.
 
 Example:
 
    resolve_sockaddr "google.com", "http", 0, undef, undef, sub { ... };
 
 =cut
 
 our %HOSTS;          # $HOSTS{$nodename}[$ipv6] = [@aliases...]
 our @HOSTS_CHECKING; # callbacks to call when hosts have been loaded
 our $HOSTS_MTIME;
 
 sub _parse_hosts($) {
    %HOSTS = ();
 
    for (split /\n/, $_[0]) {
       s/#.*$//;
       s/^[ \t]+//;
       y/A-Z/a-z/;
 
       my ($addr, @aliases) = split /[ \t]+/;
       next unless @aliases;
 
       if (my $ip = parse_ipv4 $addr) {
          ($ip) = $ip =~ /^(.*)$/s if AnyEvent::TAINT;
          push @{ $HOSTS{$_}[0] }, $ip
             for @aliases;
       } elsif (my $ip = parse_ipv6 $addr) {
          ($ip) = $ip =~ /^(.*)$/s if AnyEvent::TAINT;
          push @{ $HOSTS{$_}[1] }, $ip
             for @aliases;
       }
    }
 }
 
 # helper function - unless dns delivered results, check and parse hosts, then call continuation code
 sub _load_hosts_unless(&$@) {
    my ($cont, $cv, @dns) = @_;
 
    if (@dns) {
       $cv->end;
    } else {
       my $etc_hosts = length $ENV{PERL_ANYEVENT_HOSTS} ? $ENV{PERL_ANYEVENT_HOSTS}
                       : AnyEvent::WIN32                ? "$ENV{SystemRoot}/system32/drivers/etc/hosts"
                       :                                  "/etc/hosts";
 
       push @HOSTS_CHECKING, sub {
          $cont->();
          $cv->end;
       };
 
       unless ($#HOSTS_CHECKING) {
          # we are not the first, so we actually have to do the work
          require AnyEvent::IO;
 
          AnyEvent::IO::aio_stat ($etc_hosts, sub {
             if ((stat _)[9] ne $HOSTS_MTIME) {
                AE::log 8 => "(re)loading $etc_hosts.";
                $HOSTS_MTIME = (stat _)[9];
                # we might load a newer version of hosts,but that's a harmless race,
                # as the next call will just load it again.
                AnyEvent::IO::aio_load ($etc_hosts, sub {
                   _parse_hosts $_[0];
                   (shift @HOSTS_CHECKING)->() while @HOSTS_CHECKING;
                });
             } else {
                (shift @HOSTS_CHECKING)->() while @HOSTS_CHECKING;
             }
          });
       }
    }
 }
 
 sub resolve_sockaddr($$$$$$) {
    my ($node, $service, $proto, $family, $type, $cb) = @_;
 
    if ($node eq "unix/") {
       return $cb->() if $family || $service !~ /^\//; # no can do
 
       return $cb->([AF_UNIX, defined $type ? $type : SOCK_STREAM, 0, Socket::pack_sockaddr_un $service]);
    }
 
    unless (AF_INET6) {
       $family != 6
          or return $cb->();
 
       $family = 4;
    }
 
    $cb->() if $family == 4 && !$AnyEvent::PROTOCOL{ipv4};
    $cb->() if $family == 6 && !$AnyEvent::PROTOCOL{ipv6};
 
    $family ||= 4 unless $AnyEvent::PROTOCOL{ipv6};
    $family ||= 6 unless $AnyEvent::PROTOCOL{ipv4};
 
    $proto ||= "tcp";
    $type  ||= $proto eq "udp" ? SOCK_DGRAM : SOCK_STREAM;
 
    my $proton = AnyEvent::Socket::getprotobyname $proto
       or Carp::croak "$proto: protocol unknown";
 
    my $port;
 
    if ($service =~ /^(\S+)=(\d+)$/) {
       ($service, $port) = ($1, $2);
    } elsif ($service =~ /^\d+$/) {
       ($service, $port) = (undef, $service);
    } else {
       $port = (getservbyname $service, $proto)[2]
               or Carp::croak "$service/$proto: service unknown";
    }
 
    # resolve a records / provide sockaddr structures
    my $resolve = sub {
       my @target = @_;
 
       my @res;
       my $cv = AE::cv {
          $cb->(
             map $_->[2],
             sort {
                $AnyEvent::PROTOCOL{$b->[1]} <=> $AnyEvent::PROTOCOL{$a->[1]}
                   or $a->[0] <=> $b->[0]
             }
             @res
          )
       };
 
       $cv->begin;
       for my $idx (0 .. $#target) {
          my ($node, $port) = @{ $target[$idx] };
 
          if (my $noden = parse_address $node) {
             my $af = address_family $noden;
 
             if ($af == AF_INET && $family != 6) {
                push @res, [$idx, "ipv4", [AF_INET, $type, $proton,
                            pack_sockaddr $port, $noden]]
             }
 
             if ($af == AF_INET6 && $family != 4) {
                push @res, [$idx, "ipv6", [AF_INET6, $type, $proton,
                            pack_sockaddr $port, $noden]]
             }
          } else {
             $node =~ y/A-Z/a-z/;
 
             # a records
             if ($family != 6) {
                $cv->begin;
                AnyEvent::DNS::a $node, sub {
                   push @res, [$idx, "ipv4", [AF_INET, $type, $proton, pack_sockaddr $port, parse_ipv4 $_]]
                      for @_;
 
                   # dns takes precedence over hosts
                   _load_hosts_unless {
                      push @res,
                         map [$idx, "ipv4", [AF_INET, $type, $proton, pack_sockaddr $port, $_]],
                            @{ ($HOSTS{$node} || [])->[0] };
                   } $cv, @_;
                };
             }
 
             # aaaa records
             if ($family != 4) {
                $cv->begin;
                AnyEvent::DNS::aaaa $node, sub {
                   push @res, [$idx, "ipv6", [AF_INET6, $type, $proton, pack_sockaddr $port, parse_ipv6 $_]]
                      for @_;
 
                   _load_hosts_unless {
                      push @res,
                         map [$idx + 0.5, "ipv6", [AF_INET6, $type, $proton, pack_sockaddr $port, $_]],
                            @{ ($HOSTS{$node} || [])->[1] }
                   } $cv, @_;
                };
             }
          }
       }
       $cv->end;
    };
 
    $node = AnyEvent::Util::idn_to_ascii $node
       if $node =~ /[^\x00-\x7f]/;
 
    # try srv records, if applicable
    if ($node eq "localhost") {
       $resolve->(["127.0.0.1", $port], ["::1", $port]);
    } elsif (defined $service && !parse_address $node) {
       AnyEvent::DNS::srv $service, $proto, $node, sub {
          my (@srv) = @_;
 
          if (@srv) {
             # the only srv record has "." ("" here) => abort
             $srv[0][2] ne "" || $#srv
                or return $cb->();
 
             # use srv records then
             $resolve->(
                map ["$_->[3].", $_->[2]],
                   grep $_->[3] ne ".",
                      @srv
             );
          } else {
             # no srv records, continue traditionally
             $resolve->([$node, $port]);
          }
       };
    } else {
       # most common case
       $resolve->([$node, $port]);
    }
 }
 
 =item $guard = tcp_connect $host, $service, $connect_cb[, $prepare_cb]
 
 This is a convenience function that creates a TCP socket and makes a
 100% non-blocking connect to the given C<$host> (which can be a DNS/IDN
 hostname or a textual IP address, or the string C<unix/> for UNIX domain
 sockets) and C<$service> (which can be a numeric port number or a service
 name, or a C<servicename=portnumber> string, or the pathname to a UNIX
 domain socket).
 
 If both C<$host> and C<$port> are names, then this function will use SRV
 records to locate the real target(s).
 
 In either case, it will create a list of target hosts (e.g. for multihomed
 hosts or hosts with both IPv4 and IPv6 addresses) and try to connect to
 each in turn.
 
 After the connection is established, then the C<$connect_cb> will be
 invoked with the socket file handle (in non-blocking mode) as first, and
 the peer host (as a textual IP address) and peer port as second and third
 arguments, respectively. The fourth argument is a code reference that you
 can call if, for some reason, you don't like this connection, which will
 cause C<tcp_connect> to try the next one (or call your callback without
 any arguments if there are no more connections). In most cases, you can
 simply ignore this argument.
 
    $cb->($filehandle, $host, $port, $retry)
 
 If the connect is unsuccessful, then the C<$connect_cb> will be invoked
 without any arguments and C<$!> will be set appropriately (with C<ENXIO>
 indicating a DNS resolution failure).
 
 The callback will I<never> be invoked before C<tcp_connect> returns, even
 if C<tcp_connect> was able to connect immediately (e.g. on unix domain
 sockets).
 
 The file handle is perfect for being plugged into L<AnyEvent::Handle>, but
 can be used as a normal perl file handle as well.
 
 Unless called in void context, C<tcp_connect> returns a guard object that
 will automatically cancel the connection attempt when it gets destroyed
 - in which case the callback will not be invoked. Destroying it does not
 do anything to the socket after the connect was successful - you cannot
 "uncall" a callback that has been invoked already.
 
 Sometimes you need to "prepare" the socket before connecting, for example,
 to C<bind> it to some port, or you want a specific connect timeout that
 is lower than your kernel's default timeout. In this case you can specify
 a second callback, C<$prepare_cb>. It will be called with the file handle
 in not-yet-connected state as only argument and must return the connection
 timeout value (or C<0>, C<undef> or the empty list to indicate the default
 timeout is to be used).
 
 Note to the poor Microsoft Windows users: Windows (of course) doesn't
 correctly signal connection errors, so unless your event library works
 around this, failed connections will simply hang. The only event libraries
 that handle this condition correctly are L<EV> and L<Glib>. Additionally,
 AnyEvent works around this bug with L<Event> and in its pure-perl
 backend. All other libraries cannot correctly handle this condition. To
 lessen the impact of this windows bug, a default timeout of 30 seconds
 will be imposed on windows. Cygwin is not affected.
 
 Simple Example: connect to localhost on port 22.
 
    tcp_connect localhost => 22, sub {
       my $fh = shift
          or die "unable to connect: $!";
       # do something
    };
 
 Complex Example: connect to www.google.com on port 80 and make a simple
 GET request without much error handling. Also limit the connection timeout
 to 15 seconds.
 
    tcp_connect "www.google.com", "http",
       sub {
          my ($fh) = @_
             or die "unable to connect: $!";
 
          my $handle; # avoid direct assignment so on_eof has it in scope.
          $handle = new AnyEvent::Handle
             fh     => $fh,
             on_error => sub {
                AE::log error => $_[2];
                $_[0]->destroy;
             },
             on_eof => sub {
                $handle->destroy; # destroy handle
                AE::log info => "Done.";
             };
 
          $handle->push_write ("GET / HTTP/1.0\015\012\015\012");
 
          $handle->push_read (line => "\015\012\015\012", sub {
             my ($handle, $line) = @_;
 
             # print response header
             print "HEADER\n$line\n\nBODY\n";
 
             $handle->on_read (sub {
                # print response body
                print $_[0]->rbuf;
                $_[0]->rbuf = "";
             });
          });
       }, sub {
          my ($fh) = @_;
          # could call $fh->bind etc. here
 
          15
       };
 
 Example: connect to a UNIX domain socket.
 
    tcp_connect "unix/", "/tmp/.X11-unix/X0", sub {
       ...
    }
 
 =cut
 
 sub tcp_connect($$$;$) {
    my ($host, $port, $connect, $prepare) = @_;
 
    # see http://cr.yp.to/docs/connect.html for some tricky aspects
    # also http://advogato.org/article/672.html
 
    my %state = ( fh => undef );
 
    # name/service to type/sockaddr resolution
    resolve_sockaddr $host, $port, 0, 0, undef, sub {
       my @target = @_;
 
       $state{next} = sub {
          return unless exists $state{fh};
 
          my $errno = $!;
          my $target = shift @target
             or return AE::postpone {
                return unless exists $state{fh};
                %state = ();
                $! = $errno;
                $connect->();
             };
 
          my ($domain, $type, $proto, $sockaddr) = @$target;
 
          # socket creation
          socket $state{fh}, $domain, $type, $proto
             or return $state{next}();
 
          AnyEvent::fh_unblock $state{fh};
          
          my $timeout = $prepare && $prepare->($state{fh});
 
          $timeout ||= 30 if AnyEvent::WIN32;
 
          $state{to} = AE::timer $timeout, 0, sub {
             $! = Errno::ETIMEDOUT;
             $state{next}();
          } if $timeout;
 
          # now connect
          if (
             (connect $state{fh}, $sockaddr)
             || ($! == Errno::EINPROGRESS # POSIX
                 || $! == Errno::EWOULDBLOCK
                 # WSAEINPROGRESS intentionally not checked - it means something else entirely
                 || $! == AnyEvent::Util::WSAEINVAL # not convinced, but doesn't hurt
                 || $! == AnyEvent::Util::WSAEWOULDBLOCK)
          ) {
             $state{ww} = AE::io $state{fh}, 1, sub {
                # we are connected, or maybe there was an error
                if (my $sin = getpeername $state{fh}) {
                   my ($port, $host) = unpack_sockaddr $sin;
 
                   delete $state{ww}; delete $state{to};
 
                   my $guard = guard { %state = () };
 
                   $connect->(delete $state{fh}, format_address $host, $port, sub {
                      $guard->cancel;
                      $state{next}();
                   });
                } else {
                   if ($! == Errno::ENOTCONN) {
                      # dummy read to fetch real error code if !cygwin
                      sysread $state{fh}, my $buf, 1;
 
                      # cygwin 1.5 continously reports "ready' but never delivers
                      # an error with getpeername or sysread.
                      # cygwin 1.7 only reports readyness *once*, but is otherwise
                      # the same, which is actually more broken.
                      # Work around both by using unportable SO_ERROR for cygwin.
                      $! = (unpack "l", getsockopt $state{fh}, Socket::SOL_SOCKET(), Socket::SO_ERROR()) || Errno::EAGAIN
                         if AnyEvent::CYGWIN && $! == Errno::EAGAIN;
                   }
 
                   return if $! == Errno::EAGAIN; # skip spurious wake-ups
 
                   delete $state{ww}; delete $state{to};
 
                   $state{next}();
                }
             };
          } else {
             $state{next}();
          }
       };
 
       $! = Errno::ENXIO;
       $state{next}();
    };
 
    defined wantarray && guard { %state = () }
 }
 
 =item $guard = tcp_server $host, $service, $accept_cb[, $prepare_cb]
 
 Create and bind a stream socket to the given host address and port, set
 the SO_REUSEADDR flag (if applicable) and call C<listen>. Unlike the name
 implies, this function can also bind on UNIX domain sockets.
 
 For internet sockets, C<$host> must be an IPv4 or IPv6 address (or
 C<undef>, in which case it binds either to C<0> or to C<::>, depending
 on whether IPv4 or IPv6 is the preferred protocol, and maybe to both in
 future versions, as applicable).
 
 To bind to the IPv4 wildcard address, use C<0>, to bind to the IPv6
 wildcard address, use C<::>.
 
 The port is specified by C<$service>, which must be either a service name
 or a numeric port number (or C<0> or C<undef>, in which case an ephemeral
 port will be used).
 
 For UNIX domain sockets, C<$host> must be C<unix/> and C<$service> must be
 the absolute pathname of the socket. This function will try to C<unlink>
 the socket before it tries to bind to it, and will try to unlink it after
 it stops using it. See SECURITY CONSIDERATIONS, below.
 
 For each new connection that could be C<accept>ed, call the C<<
 $accept_cb->($fh, $host, $port) >> with the file handle (in non-blocking
 mode) as first, and the peer host and port as second and third arguments
 (see C<tcp_connect> for details).
 
 Croaks on any errors it can detect before the listen.
 
 If called in non-void context, then this function returns a guard object
 whose lifetime it tied to the TCP server: If the object gets destroyed,
 the server will be stopped (but existing accepted connections will
 not be affected).
 
 Regardless, when the function returns to the caller, the socket is bound
 and in listening state.
 
 If you need more control over the listening socket, you can provide a
 C<< $prepare_cb->($fh, $host, $port) >>, which is called just before the
 C<listen ()> call, with the listen file handle as first argument, and IP
 address and port number of the local socket endpoint as second and third
 arguments.
 
 It should return the length of the listen queue (or C<0> for the default).
 
 Note to IPv6 users: RFC-compliant behaviour for IPv6 sockets listening on
 C<::> is to bind to both IPv6 and IPv4 addresses by default on dual-stack
 hosts. Unfortunately, only GNU/Linux seems to implement this properly, so
 if you want both IPv4 and IPv6 listening sockets you should create the
 IPv6 socket first and then attempt to bind on the IPv4 socket, but ignore
 any C<EADDRINUSE> errors.
 
 Example: bind on some TCP port on the local machine and tell each client
 to go away.
 
    tcp_server undef, undef, sub {
       my ($fh, $host, $port) = @_;
 
       syswrite $fh, "The internet is full, $host:$port. Go away!\015\012";
    }, sub {
       my ($fh, $thishost, $thisport) = @_;
       AE::log info => "Bound to $thishost, port $thisport.";
    };
 
 Example: bind a server on a unix domain socket.
 
    tcp_server "unix/", "/tmp/mydir/mysocket", sub {
       my ($fh) = @_;
    };
 
 =item $guard = AnyEvent::Socket::tcp_bind $host, $service, $done_cb[, $prepare_cb]
 
 Same as C<tcp_server>, except it doesn't call C<accept> in a loop for you
 but simply passes the listen socket to the C<$done_cb>. This is useful
 when you want to have a convenient set up for your listen socket, but want
 to do the C<accept>'ing yourself, for example, in another process.
 
 In case of an error, C<tcp_bind> either croaks, or passes C<undef> to the
 C<$done_cb>.
 
 The guard only protects the set-up phase, it isn't used after C<$done_cb>
 has been invoked.
 
 =cut
 
 sub _tcp_bind($$$;$) {
    my ($host, $service, $done, $prepare) = @_;
 
    $host = $AnyEvent::PROTOCOL{ipv4} < $AnyEvent::PROTOCOL{ipv6} && AF_INET6
            ? "::" : "0"
       unless defined $host;
 
    my $ipn = parse_address $host
       or Carp::croak "AnyEvent::Socket::tcp_server: cannot parse '$host' as host address";
 
    my $af = address_family $ipn;
 
    my %state;
 
    # win32 perl is too stupid to get this right :/
    Carp::croak "tcp_server/socket: address family not supported"
       if AnyEvent::WIN32 && $af == AF_UNIX;
 
    socket $state{fh}, $af, SOCK_STREAM, 0
       or Carp::croak "tcp_server/socket: $!";
 
    if ($af == AF_INET || $af == AF_INET6) {
       setsockopt $state{fh}, SOL_SOCKET, SO_REUSEADDR, 1
          or Carp::croak "tcp_server/so_reuseaddr: $!"
             unless AnyEvent::WIN32; # work around windows bug
 
       unless ($service =~ /^\d*$/) {
          $service = (getservbyname $service, "tcp")[2]
                     or Carp::croak "$service: service unknown"
       }
    } elsif ($af == AF_UNIX) {
       unlink $service;
    }
 
    bind $state{fh}, pack_sockaddr $service, $ipn
       or Carp::croak "bind: $!";
 
    if ($af == AF_UNIX) {
       my $fh  = $state{fh};
       my $ino = (stat $fh)[1];
       $state{unlink} = guard {
          # this is racy, but is not designed to be foolproof, just best-effort
          unlink $service
             if $ino == (stat $fh)[1];
       };
    }
 
    AnyEvent::fh_unblock $state{fh};
 
    my $len;
 
    if ($prepare) {
       my ($service, $host) = unpack_sockaddr getsockname $state{fh};
       $len = $prepare && $prepare->($state{fh}, format_address $host, $service);
    }
    
    $len ||= 128;
 
    listen $state{fh}, $len
       or Carp::croak "listen: $!";
 
    $done->(\%state);
 
    defined wantarray
       ? guard { %state = () } # clear fh and watcher, which breaks the circular dependency
       : ()
 }
 
 sub tcp_bind($$$;$) {
    my ($host, $service, $done, $prepare) = @_;
 
    _tcp_bind $host, $service, sub {
       $done->(delete shift->{fh});
    }, $prepare
 }
 
 sub tcp_server($$$;$) {
    my ($host, $service, $accept, $prepare) = @_;
 
    _tcp_bind $host, $service, sub {
       my $rstate = shift;
 
       $rstate->{aw} = AE::io $rstate->{fh}, 0, sub {
          # this closure keeps $state alive
          while ($rstate->{fh} && (my $peer = accept my $fh, $rstate->{fh})) {
             AnyEvent::fh_unblock $fh; # POSIX requires inheritance, the outside world does not
 
             my ($service, $host) = unpack_sockaddr $peer;
             $accept->($fh, format_address $host, $service);
          }
       };
    }, $prepare
 }
 
 =item tcp_nodelay $fh, $enable
 
 Enables (or disables) the C<TCP_NODELAY> socket option (also known as
 Nagle's algorithm). Returns false on error, true otherwise.
 
 =cut
 
 sub tcp_nodelay($$) {
    my $onoff = int ! ! $_[1];
 
    setsockopt $_[0], Socket::IPPROTO_TCP (), Socket::TCP_NODELAY (), $onoff
 }
 
 =item tcp_congestion $fh, $algorithm
 
 Sets the tcp congestion avoidance algorithm (via the C<TCP_CONGESTION>
 socket option). The default is OS-specific, but is usually
 C<reno>. Typical other available choices include C<cubic>, C<lp>, C<bic>,
 C<highspeed>, C<htcp>, C<hybla>, C<illinois>, C<scalable>, C<vegas>,
 C<veno>, C<westwood> and C<yeah>.
 
 =cut
 
 sub tcp_congestion($$) {
    defined TCP_CONGESTION
       ? setsockopt $_[0], Socket::IPPROTO_TCP (), TCP_CONGESTION, "$_[1]"
       : undef
 }
 
 =back
 
 =head1 SECURITY CONSIDERATIONS
 
 This module is quite powerful, with with power comes the ability to abuse
 as well: If you accept "hostnames" and ports from untrusted sources,
 then note that this can be abused to delete files (host=C<unix/>). This
 is not really a problem with this module, however, as blindly accepting
 any address and protocol and trying to bind a server or connect to it is
 harmful in general.
 
 =head1 AUTHOR
 
  Marc Lehmann <schmorp@schmorp.de>
  http://anyevent.schmorp.de
 
 =cut
 
 1
 
### AnyEvent/Strict.pm ###
 =head1 NAME
 
 AnyEvent::Strict - force strict mode on for the whole process
 
 =head1 SYNOPSIS
 
    use AnyEvent::Strict;
    # strict mode now switched on
 
 =head1 DESCRIPTION
 
 This module implements AnyEvent's strict mode.
 
 Loading it makes AnyEvent check all arguments to AnyEvent-methods, at the
 expense of being slower (often the argument checking takes longer than the
 actual function). It also wraps all callbacks to check for modifications
 of C<$_>, which indicates a programming bug inside the watcher callback.
 
 Normally, you don't load this module yourself but instead use it
 indirectly via the C<PERL_ANYEVENT_STRICT> environment variable (see
 L<AnyEvent>). However, this module can be loaded manually at any time.
 
 =cut
 
 package AnyEvent::Strict;
 
 use Carp qw(confess);
 use Errno ();
 use POSIX ();
 
 $Carp::Internal{AE}               = 1;
 $Carp::Internal{AnyEvent::Strict} = 1;
 
 use AnyEvent (); BEGIN { AnyEvent::common_sense }
 
 AnyEvent::_isa_hook 1 => "AnyEvent::Strict", 1;
 
 BEGIN {
    if (defined &Internals::SvREADONLY) {
       # readonly available (at least 5.8.9+, working better in 5.10.1+)
       *wrap = sub {
          my $cb = shift;
 
          sub {
             local $_;
             Internals::SvREADONLY $_, 1;
             &$cb;
          }
       };
    } else {
       # or not :/
       my $magic = []; # a unique magic value
 
       *wrap = sub {
          my $cb = shift;
 
          sub {
             local $_ = $magic;
 
             &$cb;
 
             if (!ref $_ || $_ != $magic) {
                require AnyEvent::Debug;
                die "callback $cb (" . AnyEvent::Debug::cb2str ($cb) . ") modified \$_ without restoring it.\n";
             }
          }
       };
    }
 }
 
 our (@FD_INUSE, $FD_I);
 our $FD_CHECK_W = AE::timer 4, 4, sub {
    my $cnt = (@FD_INUSE < 100 * 10 ? int @FD_INUSE * 0.1 : 100) || 10;
 
    if ($FD_I <= 0) {
       #pop @FD_INUSE while @FD_INUSE && !$FD_INUSE[-1];
       $FD_I = @FD_INUSE
          or return; # empty
    }
 
    $cnt = $FD_I if $cnt > $FD_I;
 
    eval {
       do {
          !$FD_INUSE[--$FD_I]
             or (POSIX::lseek $FD_I, 0, 1) != -1
             or $! != Errno::EBADF
             or die;
       } while --$cnt;
       1
    } or AE::log crit => "File descriptor $FD_I registered with AnyEvent but prematurely closed, event loop might malfunction.";
 };
 
 sub io {
    my $class = shift;
    my (%arg, $fh, $cb, $fd) = @_;
 
    ref $arg{cb}
       or confess "AnyEvent->io called with illegal cb argument '$arg{cb}'";
    $cb = wrap delete $arg{cb};
  
    $arg{poll} =~ /^[rw]$/
       or confess "AnyEvent->io called with illegal poll argument '$arg{poll}'";
 
    $fh = delete $arg{fh};
 
    if ($fh =~ /^\s*\d+\s*$/) {
       $fd = $fh;
       $fh = AnyEvent::_dupfh $arg{poll}, $fh;
    } else {
       defined eval { $fd = fileno $fh }
          or confess "AnyEvent->io called with illegal fh argument '$fh'";
    }
 
    -f $fh
       and confess "AnyEvent->io called with fh argument pointing to a file";
 
    delete $arg{poll};
  
    confess "AnyEvent->io called with unsupported parameter(s) " . join ", ", keys %arg
       if keys %arg;
 
    ++$FD_INUSE[$fd];
 
    bless [
       $fd,
       $class->SUPER::io (@_, cb => $cb)
    ], "AnyEvent::Strict::io";
 }
 
 sub AnyEvent::Strict::io::DESTROY {
    --$FD_INUSE[$_[0][0]];
 }
 
 sub timer {
    my $class = shift;
    my %arg = @_;
 
    ref $arg{cb}
       or confess "AnyEvent->timer called with illegal cb argument '$arg{cb}'";
    my $cb = wrap delete $arg{cb};
  
    exists $arg{after}
       or confess "AnyEvent->timer called without mandatory 'after' parameter";
    delete $arg{after};
  
    !$arg{interval} or $arg{interval} > 0
       or confess "AnyEvent->timer called with illegal interval argument '$arg{interval}'";
    delete $arg{interval};
  
    confess "AnyEvent->timer called with unsupported parameter(s) " . join ", ", keys %arg
       if keys %arg;
 
    $class->SUPER::timer (@_, cb => $cb)
 }
 
 sub signal {
    my $class = shift;
    my %arg = @_;
 
    ref $arg{cb}
       or confess "AnyEvent->signal called with illegal cb argument '$arg{cb}'";
    my $cb = wrap delete $arg{cb};
  
    defined AnyEvent::Base::sig2num $arg{signal} and $arg{signal} == 0
       or confess "AnyEvent->signal called with illegal signal name '$arg{signal}'";
    delete $arg{signal};
  
    confess "AnyEvent->signal called with unsupported parameter(s) " . join ", ", keys %arg
       if keys %arg;
 
    $class->SUPER::signal (@_, cb => $cb)
 }
 
 sub child {
    my $class = shift;
    my %arg = @_;
 
    ref $arg{cb}
       or confess "AnyEvent->child called with illegal cb argument '$arg{cb}'";
    my $cb = wrap delete $arg{cb};
  
    $arg{pid} =~ /^-?\d+$/
       or confess "AnyEvent->child called with malformed pid value '$arg{pid}'";
    delete $arg{pid};
  
    confess "AnyEvent->child called with unsupported parameter(s) " . join ", ", keys %arg
       if keys %arg;
 
    $class->SUPER::child (@_, cb => $cb)
 }
 
 sub idle {
    my $class = shift;
    my %arg = @_;
 
    ref $arg{cb}
       or confess "AnyEvent->idle called with illegal cb argument '$arg{cb}'";
    my $cb = wrap delete $arg{cb};
  
    confess "AnyEvent->idle called with unsupported parameter(s) " . join ", ", keys %arg
       if keys %arg;
 
    $class->SUPER::idle (@_, cb => $cb)
 }
 
 sub condvar {
    my $class = shift;
    my %arg = @_;
 
    !exists $arg{cb} or ref $arg{cb}
       or confess "AnyEvent->condvar called with illegal cb argument '$arg{cb}'";
    my @cb = exists $arg{cb} ? (cb => wrap delete $arg{cb}) : ();
  
    confess "AnyEvent->condvar called with unsupported parameter(s) " . join ", ", keys %arg
       if keys %arg;
 
    $class->SUPER::condvar (@cb);
 }
 
 sub time {
    my $class = shift;
 
    @_
       and confess "AnyEvent->time wrongly called with paramaters";
 
    $class->SUPER::time (@_)
 }
 
 sub now {
    my $class = shift;
 
    @_
       and confess "AnyEvent->now wrongly called with paramaters";
 
    $class->SUPER::now (@_)
 }
 
 =head1 AUTHOR
 
  Marc Lehmann <schmorp@schmorp.de>
  http://anyevent.schmorp.de
 
 =cut
 
 1
 
### AnyEvent/TLS.pm ###
 package AnyEvent::TLS;
 
 use Carp qw(croak);
 use Scalar::Util ();
 
 use AnyEvent (); BEGIN { AnyEvent::common_sense }
 use AnyEvent::Util ();
 
 use Net::SSLeay;
 
 =head1 NAME
 
 AnyEvent::TLS - SSLv2/SSLv3/TLSv1 contexts for use in AnyEvent::Handle
 
 =cut
 
 our $VERSION = $AnyEvent::VERSION;
 
 =head1 SYNOPSIS
 
    # via AnyEvent::Handle
 
    use AnyEvent;
    use AnyEvent::Handle;
    use AnyEvent::Socket;
 
    # simple https-client
    my $handle = new AnyEvent::Handle
       connect  => [$host, $port],
       tls      => "connect",
       tls_ctx  => { verify => 1, verify_peername => "https" },
       ...
 
    # simple ssl-server
    tcp_server undef, $port, sub {
       my ($fh) = @_;
 
       my $handle = new AnyEvent::Handle
          fh       => $fh,
          tls      => "accept",
          tls_ctx  => { cert_file => "my-server-keycert.pem" },
          ...
 
    # directly
 
    my $tls = new AnyEvent::TLS
       verify => 1,
       verify_peername => "ldaps",
       ca_file => "/etc/cacertificates.pem";
 
 =head1 DESCRIPTION
 
 This module is a helper module that implements TLS/SSL (Transport Layer
 Security/Secure Sockets Layer) contexts. A TLS context is a common set of
 configuration values for use in establishing TLS connections.
 
 For some quick facts about SSL/TLS, see the section of the same name near
 the end of the document.
 
 A single TLS context can be used for any number of TLS connections that
 wish to use the same certificates, policies etc.
 
 Note that this module is inherently tied to L<Net::SSLeay>, as this
 library is used to implement it. Since that perl module is rather ugly,
 and OpenSSL has a rather ugly license, AnyEvent might switch TLS providers
 at some future point, at which this API will change dramatically, at least
 in the Net::SSLeay-specific parts (most constructor arguments should still
 work, though).
 
 Although this module does not require a specific version of Net::SSLeay,
 many features will gradually stop working, or bugs will be introduced with
 old versions (verification might succeed when it shouldn't - this is a
 real security issue). Version 1.35 is recommended, 1.33 should work, 1.32
 might, and older versions are yours to keep.
 
 =head1 USAGE EXAMPLES
 
 See the L<AnyEvent::Handle> manpage, NONFREQUENTLY ASKED QUESTIONS, for
 some actual usage examples.
 
 =head1 PUBLIC METHODS AND FUNCTIONS
 
 =over 4
 
 =cut
 
 our $REF_IDX; # our session ex_data id
 
 # create temp file, populate it, and return a guard and filename
 sub _tmpfile($) {
    require File::Temp unless $File::Temp::VERSION;
 
    # File::Temp opens the file with mode 0600
    my ($fh, $path) = File::Temp::tempfile ("aetlsXXXXXXXXX", TMPDIR => 1, EXLOCK => 0);
    my $guard = AnyEvent::Util::guard { unlink $path };
 
    syswrite $fh, $_[0];
    close $fh;
 
    ($path, $guard)
 }
 
 our %DH_PARAMS = (
    # These are the DH parameters from "Assigned Number for SKIP Protocols"
    # (http://www.skip-vpn.org/spec/numbers.html).
    # (or http://web.archive.org/web/20011212141438/http://www.skip-vpn.org/spec/numbers.html#params)
    # See there for how they were generated.
    # Note that g might not be a generator,
    # but this is not a problem since p is a safe prime.
    skip512 => "MEYCQQD1Kv884bEpQBgRjXyEpwpy1obEAxnIByl6ypUM2Zafq9AKUJsCRtMIPWak|XUGfnHy9iUsiGSa6q6Jew1XpKgVfAgEC",
    skip1024 => "MIGHAoGBAPSI/VhOSdvNILSd5JEHNmszbDgNRR0PfIizHHxbLY7288kjwEPwpVsY|jY67VYy4XTjTNP18F1dDox0YbN4zISy1Kv884bEpQBgRjXyEpwpy1obEAxnIByl6|ypUM2Zafq9AKUJsCRtMIPWakXUGfnHy9iUsiGSa6q6Jew1XpL3jHAgEC",
    skip2048 => "MIIBCAKCAQEA9kJXtwh/CBdyorrWqULzBej5UxE5T7bxbrlLOCDaAadWoxTpj0BV|89AHxstDqZSt90xkhkn4DIO9ZekX1KHTUPj1WV/cdlJPPT2N286Z4VeSWc39uK50|T8X8dryDxUcwYc58yWb/Ffm7/ZFexwGq01uejaClcjrUGvC/RgBYK+X0iP1YTknb|zSC0neSRBzZrM2w4DUUdD3yIsxx8Wy2O9vPJI8BD8KVbGI2Ou1WMuF040zT9fBdX|Q6MdGGzeMyEstSr/POGxKUAYEY18hKcKctaGxAMZyAcpesqVDNmWn6vQClCbAkbT|CD1mpF1Bn5x8vYlLIhkmuquiXsNV6TILOwIBAg==",
    skip4096 => "MIICCAKCAgEA+hRyUsFN4VpJ1O8JLcCo/VWr19k3BCgJ4uk+d+KhehjdRqNDNyOQ|l/MOyQNQfWXPeGKmOmIig6Ev/nm6Nf9Z2B1h3R4hExf+zTiHnvVPeRBhjdQi81rt|Xeoh6TNrSBIKIHfUJWBh3va0TxxjQIs6IZOLeVNRLMqzeylWqMf49HsIXqbcokUS|Vt1BkvLdW48j8PPv5DsKRN3tloTxqDJGo9tKvj1Fuk74A+Xda1kNhB7KFlqMyN98|VETEJ6c7KpfOo30mnK30wqw3S8OtaIR/maYX72tGOno2ehFDkq3pnPtEbD2CScxc|alJC+EL7RPk5c/tgeTvCngvc1KZn92Y//EI7G9tPZtylj2b56sHtMftIoYJ9+ODM|sccD5Piz/rejE3Ome8EOOceUSCYAhXn8b3qvxVI1ddd1pED6FHRhFvLrZxFvBEM9|ERRMp5QqOaHJkM+Dxv8Cj6MqrCbfC4u+ZErxodzuusgDgvZiLF22uxMZbobFWyte|OvOzKGtwcTqO/1wV5gKkzu1ZVswVUQd5Gg8lJicwqRWyyNRczDDoG9jVDxmogKTH|AaqLulO7R8Ifa1SwF2DteSGVtgWEN8gDpN3RBmmPTDngyF2DHb5qmpnznwtFKdTL|KWbuHn491xNO25CQWMtem80uKw+pTnisBRF/454n1Jnhub144YRBoN8CAQI=",
 
    # generated on a linux desktop with openssl using /dev/urandom - entropy_avail was >= 3600 each time
    # the 8192 bit key took 25 hours to generate :/
    schmorp1024 => "MIGHAoGBAN+GjqAhNxLesSuGfDzYe6HdexXtHuxe85umshfPHfnmLSkGWl/FE27+|v+50mwY5XaNnCmo1VvGju4iTKxWoZTGgslUSc8KX197XWAXIpab8ESyg442if9Kr|vSOuu0fopwvvTOgHK8mkEWI4joU5G4/MQy+pnC5NIEVBP4HtGiTrAgEC",
    schmorp1539 => "MIHHAoHBByJzpVGUsXysX8w/+uuXRUCL9exhAixoHkaJU5lf4noJUtp9F0yr/5rb|hF8M9mSZJ+RlPyB+Zt37GPp1WQDO1+/2yZJX9kHE3+h5JCRoR8PKc2G+ts9jhM7r|CnTQ0z0b6s12Pusf+UhQPwLust4JAYE/LPuTK8yFiVx5L2a+aZhGMVlYN/12SEtY|jRl3lGXdZj9g8E2PzTQbA9CGy5dGIvz/ENTzTVleKuQ+80bzpVEPjZL9tv43Zc+l|MFLzxuE5uwIBAg==",
    schmorp2048 => "MIIBCAKCAQEAhR5Fn9h3Tgnc+q4o3CMkZtre3lLUyDT+1bf3aiVOt22JdDQndZLc|FeKz8AqliB3UIgNExc6oDtuG4znKPgklfOnHv/a9tl1AYQbV+QFM/E0jYl6oG8tF|Epgxezt1GCivvtu64ql0s213wr64QffNMt3hva8lNqK1PXfqp13PzzLzAVsfghrv|fMAX7/bYm1T5fAJdcah6FeZkKof+mqbs8HtRjfvrUF2npEM2WdupFu190vcwABnN|TTJheXCWv2BF2f9EEr61q3OUhSNWIThtZP+NKe2bACm1PebT0drAcaxKoMz9LjKr|y5onGs0TOuQ7JmhtZL45Zr4LwBcyTucLUwIBAg==",
    schmorp4096 => "MIICCAKCAgEA5WwA5lQg09YRYqc/JILCd2AfBmYBkF19wmCEJB8G3JhTxv8EGvYk|xyP2ecKVUvHTG8Xw/qpW8nRqzPIyV8QRf6YFYSf33Qnx2xYhcnqOumU3nfC0SNOL|/w2q1BA9BbHtW4574P+6hOQx9ftRtbtZ2HPKBMRcAKGjpYZiKopv0+UAM4NpEC2p|bfajp7pyVLeb/Aqm/oWP3L63wPlY1SDp+XRzrOAKB+/uLGqEwV0bBaxxGL29BpOp|O2z1ALGXiDCcLs9WTn9WqUhWDzUN6fahm53rd7zxwpFCb6K2YhaK0peG95jzSUJ8|aoL0KgWuC6v5+gPJHRu0HrQIdfAdN4VchqYOKE46uNNkQl8VJGu4RjYB7lFBpRwO|g2HCsGMo2X7BRmA1st66fh+JOd1smXMZG/2ozTOooL+ixcx4spNneg4aQerWl5cb|nWXKtPCp8yPzt/zoNzL3Fon2Ses3sNgMos0M/ZbnigScDxz84Ms6V/X8Z0L4m/qX|mL42dP40tgvmgqi6BdsBzcIWeHlEcIhmGcsEBxxKEg7gjb0OjjvatpUCJhmRrGjJ|LtMkBR68qr42OBMN/PBB4KPOWNUqTauXZajfCwYdbpvV24ZhtkcRdw1zisyARBSh|aTKW/GV8iLsUzlYN27LgVEwMwnWQaoecW6eOTNKGUURC3In6XZSvVzsCAQI=",
    schmorp8192 => "MIIECAKCBAEA/SAEbRSSLenVxoInHiltm/ztSwehGOhOiUKfzDcKlRBZHlCC9jBl|S/aeklM6Ucg8E6J2bnfoh6CAdnE/glQOn6CifhZr8X/rnlL9/eP+r9m+aiAw4l0D|MBd8BondbEqwTZthMmLtx0SslnevsFAZ1Cj8WgmUNaSPOukvJ1N7aQ98U+E99Pw3|VG8ANBydXqLqW2sogS8FtZoMbVywcQuaGmC7M6i3Akxe3CCSIpR/JkEZIytREBSC|CH+x3oW/w+wHzq3w8DGB9hqz1iMXqDMiPIMSdXC0DaIPokLnd7X8u6N14yCAco2h|P0gspD3J8pS2FpUY8ZTVjzbVCjhNNmTryBZAxHSWBuX4xYcCHUtfGlUe/IGLSVE1|xIdFpZUfvlvAJjVq0/TtDMg3r2JSXrhQVlr8MPJwSApDVr5kOBHT/uABio4z+5yR|PAvundznfyo9GGAWhIA36GQqsxSQfoRTjWssFoR/cu+9aomRwwOLkvObu8nCVVLH|nLdKDk5cIR0TvNs9HZ6ZmkzL7ah7cPzEKl7U6eE6yZLVYMNecnPLS6PSAIG4gxcq|CVQrrZjQLfTDrJn0OGgpShX85RaDsuiRtp2bpDZ23YDqdwr4wRjvIargjqc2zcF+|jIb7dUS6ci7bVG/CGOQUuiMWAiXZ3a1f343SMf9A05/sf1xwnMeco6STBLZ3X+PA|4urU+grtpWaFtS/fPD2ILn8nrJ3WuSKKUeSnVM46mmJQsOkyn7z8l3jNLB17GYKo|qc+0UuU/2PM9qtZdZElSM/ACLV2vdCuaibop4B9UIP9z3F8kfZ72+zKxpGiE+Bo1|x8SfG8FQw90mYIx+qZzJ8MCvc2wh+l4wDX5KxrhwvcouE2tHQlwfDgv/DiIXp173|hAmUCV0+bPRW8IIJvBODdAWtJe9hNwxj1FFYmPA7l4wa3gXV4I6tb+iO1MbwVjZ/|116tD5MdCo3JuSisgPYCHfkQccwEO0FHEuBbmfN+fQimQ8H0dePP8XctwbkplsB+|aLT5hYKmva/j9smEswgyHglPwc3WvZ+2DgKk7A7DHi7a2gDwCRQlHaXtNWx3992R|dfNgkSeB1CvGSQoo95WpC9ZoqGmcSlVqdetDU8iglPmfYTKO8aIPA6TuTQ/lQ0IW|90LQmqP23FwnNFiyqX8+rztLq4KVkTyeHIQwig6vFxgD8N+SbZCW2PPiB72TVF2U|WePU8MRTv1OIGBUBajF49k28HnZPSGlILHtFEkYkbPvomcE5ENnoejwzjktOTS5d|/R3SIOvCauOzadtzwTYOXT78ORaR1KI1cm8DzkkwJTd/Rrk07Q5vnvnSJQMwFUeH|PwJIgWBQf/GZ/OsDHmkbYR2ZWDClbKw2mwIBAg==",
 );
 
 =item $tls = new AnyEvent::TLS key => value...
 
 The constructor supports these arguments (all as key => value pairs).
 
 =over 4
 
 =item method => "SSLv2" | "SSLv3" | "TLSv1" | "TLSv1_1" | "TLSv1_2" | "any"
 
 The protocol parser to use. C<SSLv2>, C<SSLv3>, C<TLSv1>, C<TLSv1_1>
 and C<TLSv1_2> will use a parser for those protocols only (so will
 I<not> accept or create connections with/to other protocol versions),
 while C<any> (the default) uses a parser capable of all three
 protocols.
 
 The default is to use C<"any"> but disable SSLv2. This has the effect of
 sending a SSLv2 hello, indicating the support for SSLv3 and TLSv1, but not
 actually negotiating an (insecure) SSLv2 connection.
 
 Specifying a specific version is almost always wrong to use for a server
 speaking to a wide variety of clients (e.g. web browsers), and often wrong
 for a client. If you only want to allow a specific protocol version, use
 the C<sslv2>, C<sslv3>, C<tlsv1>, C<tlsv1_1> or C<tlsv1_2> arguments instead.
 
 For new services it is usually a good idea to enforce a C<TLSv1> method
 from the beginning.
 
 C<TLSv1_1> and C<TLSv1_2> require L<Net::SSLeay> >= 1.55 and OpenSSL
 >= 1.0.1. Check the L<Net::SSLeay> and OpenSSL documentations for more
 details.
 
 =item sslv2 => $enabled
 
 Enable or disable SSLv2 (normally I<disabled>).
 
 =item sslv3 => $enabled
 
 Enable or disable SSLv3 (normally I<enabled>).
 
 =item tlsv1 => $enabled
 
 Enable or disable TLSv1 (normally I<enabled>).
 
 =item tlsv1_1 => $enabled
 
 Enable or disable TLSv1_1 (normally I<enabled>).
 
 This requires L<Net::SSLeay> >= 1.55 and OpenSSL >= 1.0.1. Check the
 L<Net::SSLeay> and OpenSSL documentations for more details.
 
 =item tlsv1_2 => $enabled
 
 Enable or disable TLSv1_2 (normally I<enabled>).
 
 This requires L<Net::SSLeay> >= 1.55 and OpenSSL >= 1.0.1. Check the
 L<Net::SSLeay> and OpenSSL documentations for more details.
 
 =item verify => $enable
 
 Enable or disable peer certificate checking (default is I<disabled>, which
 is I<not recommended>).
 
 This is the "master switch" for all verify-related parameters and
 functions.
 
 If it is disabled, then no peer certificate verification will be done
 - the connection will be encrypted, but the peer certificate won't be
 verified against any known CAs, or whether it is still valid or not. No
 peername verification or custom verification will be done either.
 
 If enabled, then the peer certificate (required in client mode, optional
 in server mode, see C<verify_require_client_cert>) will be checked against
 its CA certificate chain - that means there must be a signing chain from
 the peer certificate to any of the CA certificates you trust locally, as
 specified by the C<ca_file> and/or C<ca_path> and/or C<ca_cert> parameters
 (or the system default CA repository, if all of those parameters are
 missing - see also the L<AnyEvent> manpage for the description of
 PERL_ANYEVENT_CA_FILE).
 
 Other basic checks, such as checking the validity period, will also be
 done, as well as optional peername/hostname/common name verification
 C<verify_peername>.
 
 An optional C<verify_cb> callback can also be set, which will be invoked
 with the verification results, and which can override the decision.
 
 =item verify_require_client_cert => $enable
 
 Enable or disable mandatory client certificates (default is
 I<disabled>). When this mode is enabled, then a client certificate will be
 required in server mode (a server certificate is mandatory, so in client
 mode, this switch has no effect).
 
 =item verify_peername => $scheme | $callback->($tls, $cert, $peername)
 
 TLS only protects the data that is sent - it cannot automatically verify
 that you are really talking to the right peer. The reason is that
 certificates contain a "common name" (and a set of possible alternative
 "names") that need to be checked against the peername (usually, but not
 always, the DNS name of the server) in a protocol-dependent way.
 
 This can be implemented by specifying a callback that has to verify that
 the actual C<$peername> matches the given certificate in C<$cert>.
 
 Since this can be rather hard to implement, AnyEvent::TLS offers a variety
 of predefined "schemes" (lifted from L<IO::Socket::SSL>) that are named
 like the protocols that use them:
 
 =over 4
 
 =item ldap (rfc4513), pop3,imap,acap (rfc2995), nntp (rfc4642)
 
 Simple wildcards in subjectAltNames are possible, e.g. *.example.org
 matches www.example.org but not lala.www.example.org. If nothing from
 subjectAltNames matches, it checks against the common name, but there are
 no wildcards allowed.
 
 =item http (rfc2818)
 
 Extended wildcards in subjectAltNames are possible, e.g. *.example.org or
 even www*.example.org. Wildcards in the common name are not allowed. The
 common name will be only checked if no host names are given in
 subjectAltNames.
 
 =item smtp (rfc3207)
 
 This RFC isn't very useful in determining how to do verification so it
 just assumes that subjectAltNames are possible, but no wildcards are
 possible anywhere.
 
 =item [$wildcards_in_alt, $wildcards_in_cn, $check_cn]
 
 You can also specify a scheme yourself by using an array reference with
 three integers.
 
 C<$wildcards_in_alt> and C<$wildcards_in_cn> specify whether and where
 wildcards (C<*>) are allowed in subjectAltNames and the common name,
 respectively. C<0> means no wildcards are allowed, C<1> means they
 are allowed only as the first component (C<*.example.org>), and C<2>
 means they can be used anywhere (C<www*.example.org>), except that very
 dangerous matches will not be allowed (C<*.org> or C<*>).
 
 C<$check_cn> specifies if and how the common name field is checked: C<0>
 means it will be completely ignored, C<1> means it will only be used if
 no host names have been found in the subjectAltNames, and C<2> means the
 common name will always be checked against the peername.
 
 =back
 
 You can specify either the name of the parent protocol (recommended,
 e.g. C<http>, C<ldap>), the protocol name as usually used in URIs
 (e.g. C<https>, C<ldaps>) or the RFC (not recommended, e.g. C<rfc2995>,
 C<rfc3920>).
 
 This verification will only be done when verification is enabled (C<<
 verify => 1 >>).
 
 =item verify_cb => $callback->($tls, $ref, $cn, $depth, $preverify_ok, $x509_store_ctx, $cert)
 
 Provide a custom peer verification callback used by TLS sessions,
 which is called with the result of any other verification (C<verify>,
 C<verify_peername>).
 
 This callback will only be called when verification is enabled (C<< verify
 => 1 >>).
 
 C<$tls> is the C<AnyEvent::TLS> object associated with the session,
 while C<$ref> is whatever the user associated with the session (usually
 an L<AnyEvent::Handle> object when used by AnyEvent::Handle).
 
 C<$depth> is the current verification depth - C<$depth = 0> means the
 certificate to verify is the peer certificate, higher levels are its CA
 certificate and so on. In most cases, you can just return C<$preverify_ok>
 if the C<$depth> is non-zero:
 
    verify_cb => sub {
       my ($tls, $ref, $cn, $depth, $preverify_ok, $x509_store_ctx, $cert) = @_;
 
       return $preverify_ok
          if $depth;
 
       # more verification
    },
 
 C<$preverify_ok> is true iff the basic verification of the certificates
 was successful (a valid CA chain must exist, the certificate has passed
 basic validity checks, peername verification succeeded).
 
 C<$x509_store_ctx> is the Net::SSLeay::X509_CTX> object.
 
 C<$cert> is the C<Net::SSLeay::X509> object representing the
 peer certificate, or zero if there was an error. You can call
 C<AnyEvent::TLS::certname $cert> to get a nice user-readable string to
 identify the certificate.
 
 The callback must return either C<0> to indicate failure, or C<1> to
 indicate success.
 
 =item verify_client_once => $enable
 
 Enable or disable skipping the client certificate verification on
 renegotiations (default is I<disabled>, the certificate will always be
 checked). Only makes sense in server mode.
 
 =item ca_file => $path
 
 If this parameter is specified and non-empty, it will be the path to a
 file with (server) CA certificates in PEM format that will be loaded. Each
 certificate will look like:
 
    -----BEGIN CERTIFICATE-----
    ... (CA certificate in base64 encoding) ...
    -----END CERTIFICATE-----
 
 You have to enable verify mode (C<< verify => 1 >>) for this parameter to
 have any effect.
 
 =item ca_path => $path
 
 If this parameter is specified and non-empty, it will be
 the path to a directory with hashed CA certificate files in
 PEM format. When the ca certificate is being verified, the
 certificate will be hashed and looked up in that directory (see
 L<http://www.openssl.org/docs/ssl/SSL_CTX_load_verify_locations.html> for
 details)
 
 The certificates specified via C<ca_file> take precedence over the ones
 found in C<ca_path>.
 
 You have to enable verify mode (C<< verify => 1 >>) for this parameter to
 have any effect.
 
 =item ca_cert => $string
 
 In addition or instead of using C<ca_file> and/or C<ca_path>, you can
 also use C<ca_cert> to directly specify the CA certificates (there can be
 multiple) in PEM format, in a string.
 
 =item check_crl => $enable
 
 Enable or disable certificate revocation list checking. If enabled, then
 peer certificates will be checked against a list of revoked certificates
 issued by the CA. The revocation lists will be expected in the C<ca_path>
 directory.
 
 certificate verification will fail if this is enabled but no revocation
 list was found.
 
 This requires OpenSSL >= 0.9.7b. Check the OpenSSL documentation for more
 details.
 
 =item key_file => $path
 
 Path to the local private key file in PEM format (might be a combined
 certificate/private key file).
 
 The local certificate is used to authenticate against the peer - servers
 mandatorily need a certificate and key, clients can use a certificate and
 key optionally to authenticate, e.g. for log-in purposes.
 
 The key in the file should look similar this:
 
    -----BEGIN RSA PRIVATE KEY-----
    ...header data
    ... (key data in base64 encoding) ...
    -----END RSA PRIVATE KEY-----
 
 =item key => $string
 
 The private key string in PEM format (see C<key_file>, only one of
 C<key_file> or C<key> can be specified).
 
 The idea behind being able to specify a string is to avoid blocking in
 I/O. Unfortunately, Net::SSLeay fails to implement any interface to the
 needed OpenSSL functionality, this is currently implemented by writing to
 a temporary file.
 
 =item cert_file => $path
 
 The path to the local certificate file in PEM format (might be a combined
 certificate/private key file, including chained certificates).
 
 The local certificate (and key) are used to authenticate against the
 peer - servers mandatorily need a certificate and key, clients can use
 certificate and key optionally to authenticate, e.g. for log-in purposes.
 
 The certificate in the file should look like this:
 
    -----BEGIN CERTIFICATE-----
    ... (certificate in base64 encoding) ...
    -----END CERTIFICATE-----
 
 If the certificate file or string contain both the certificate and
 private key, then there is no need to specify a separate C<key_file> or
 C<key>.
 
 Additional signing certifiates to send to the peer (in SSLv3 and newer)
 can be specified by appending them to the certificate proper: the order
 must be from issuer certificate over any intermediate CA certificates to
 the root CA.
 
 So the recommended ordering for a combined key/cert/chain file, specified
 via C<cert_file> or C<cert> looks like this:
 
   certificate private key
   client/server certificate
   ca 1, signing client/server certficate
   ca 2, signing ca 1
   ...
 
 =item cert => $string
 
 The local certificate in PEM format (might be a combined
 certificate/private key file). See C<cert_file>.
 
 The idea behind being able to specify a string is to avoid blocking in
 I/O. Unfortunately, Net::SSLeay fails to implement any interface to the
 needed OpenSSL functionality, this is currently implemented by writing to
 a temporary file.
 
 =item cert_password => $string | $callback->($tls)
 
 The certificate password - if the certificate is password-protected, then
 you can specify its password here.
 
 Instead of providing a password directly (which is not so recommended),
 you can also provide a password-query callback. The callback will be
 called whenever a password is required to decode a local certificate, and
 is supposed to return the password.
 
 =item dh_file => $path
 
 Path to a file containing Diffie-Hellman parameters in PEM format, for
 use in servers. See also C<dh> on how to specify them directly, or use a
 pre-generated set.
 
 Diffie-Hellman key exchange generates temporary encryption keys that
 are not transferred over the connection, which means that even if the
 certificate key(s) are made public at a later time and a full dump of the
 connection exists, the key still cannot be deduced.
 
 These ciphers are only available with SSLv3 and later (which is the
 default with AnyEvent::TLS), and are only used in server/accept
 mode. Anonymous DH protocols are usually disabled by default, and usually
 not even compiled into the underlying library, as they provide no direct
 protection against man-in-the-middle attacks. The same is true for the
 common practise of self-signed certificates that you have to accept first,
 of course.
 
 =item dh => $string
 
 Specify the Diffie-Hellman parameters in PEM format directly as a string
 (see C<dh_file>), the default is C<schmorp1539> unless C<dh_file> was
 specified.
 
 AnyEvent::TLS supports supports a number of precomputed DH parameters,
 since computing them is expensive. They are:
 
    # from "Assigned Number for SKIP Protocols"
    skip512, skip1024, skip2048, skip4096
 
    # from schmorp
    schmorp1024, schmorp1539, schmorp2048, schmorp4096, schmorp8192
 
 The default was chosen as a trade-off between security and speed, and
 should be secure for a few years. It is said that 2048 bit DH parameters
 are safe till 2030, and DH parameters shorter than 900 bits are totally
 insecure.
 
 To disable DH protocols completely, specify C<undef> as C<dh> parameter.
 
 =item dh_single_use => $enable
 
 Enables or disables "use only once" mode when using Diffie-Hellman key
 exchange. When enabled (default), each time a new key is exchanged a new
 Diffie-Hellman key is generated, which improves security as each key is
 only used once. When disabled, the key will be created as soon as the
 AnyEvent::TLS object is created and will be reused.
 
 All the DH parameters supplied with AnyEvent::TLS should be safe with
 C<dh_single_use> switched off, but YMMV.
 
 =item cipher_list => $string
 
 The list of ciphers to use, as a string (example:
 C<AES:ALL:!aNULL:!eNULL:+RC4:@STRENGTH>). The format
 of this string and its default value is documented at
 L<http://www.openssl.org/docs/apps/ciphers.html#CIPHER_STRINGS>.
 
 =item session_ticket => $enable
 
 Enables or disables RC5077 support (Session Resumption without Server-Side
 State). The default is disabled for clients, as many (buggy) TLS/SSL
 servers choke on it, but enabled for servers.
 
 When enabled and supported by the server, a session ticket will be
 provided to the client, which allows fast resuming of connections.
 
 =item prepare => $coderef->($tls)
 
 If this argument is present, then it will be called with the new
 AnyEvent::TLS object after any other initialisation has bee done, in case
 you wish to fine-tune something...
 
 =cut
 
 #=item trust => $trust
 #
 #Sets the expected (root) certificate use on this context, i.e. what 
 #certificates to trust. The default is C<compat>, and the following strings
 #are supported:
 #
 #   compat          any certifictae will do
 #   ssl_client      only trust client certificates
 #   ssl_server      only trust server certificates
 #   email           only trust e-mail certificates
 #   object_sign     only trust signing (CA) certificates
 #   ocsp_sign       only trust ocsp signing certs
 #   ocsp_request    only trust ocsp request certs
 
 # purpose?
 
 #TODO
 # verify_depth?
 # reuse_ctx
 # session_cache_size
 # session_cache
 
 #=item debug => $level
 #
 #Enable or disable sending debugging output to STDERR. This is, as
 #the name says, mostly for debugging. The default is taken from the
 #C<PERL_ANYEVENT_TLS_DEBUG> environment variable.
 #
 #=cut
 
 =back
 
 =cut
 
 sub init ();
 
 #our %X509_TRUST = (
 #   compat       => 1,
 #   ssl_client   => 2,
 #   ssl_server   => 3,
 #   email        => 4,
 #   object_sign  => 5,
 #   ocsp_sign    => 6,
 #   ocsp_request => 7,
 #);
 
 BEGIN {
    eval 'sub _check_tls_gt_1 (){'
       . (($Net::SSLeay::VERSION >= 1.55 && Net::SSLeay::OPENSSL_VERSION_NUMBER() >= 0x1000100f) * 1)
       . '}';
 }
 
 our %SSL_METHODS = (
    any     => \&Net::SSLeay::CTX_new,
    sslv23  => \&Net::SSLeay::CTX_new, # deliberately undocumented
    sslv2   => \&Net::SSLeay::CTX_v2_new,
    sslv3   => \&Net::SSLeay::CTX_v3_new,
    tlsv1   => \&Net::SSLeay::CTX_tlsv1_new,
 );
 
 # Add TLSv1_1 and TLSv1_2 if Net::SSLEay and openssl allow them
 if (_check_tls_gt_1) {
    $SSL_METHODS{tlsv1_1} = \&Net::SSLeay::CTX_tlsv1_1_new;
    $SSL_METHODS{tlsv1_2} = \&Net::SSLeay::CTX_tlsv1_2_new;
 } else {
    for my $method (qw(tlsv1_1 tlsv1_2)) {
       $SSL_METHODS{$method} = sub { croak "AnyEvent::TLS method '$method' requires openssl v1.0.1 and Net::SSLeay 1.55 or higher" };
    }
 }
 
 sub new {
    my ($class, %arg) = @_;
 
    init unless $REF_IDX;
 
    my $method = lc $arg{method} || "any";
 
    my $ctx = ($SSL_METHODS{$method}
               || croak "'$method' is not a valid AnyEvent::TLS method (must be one of @{[ sort keys %SSL_METHODS ]})")->();
 
    my $self = bless { ctx => $ctx }, $class; # to make sure it's destroyed if we croak
 
    my $op = Net::SSLeay::OP_ALL ();
 
    $op |= Net::SSLeay::OP_NO_SSLv2      () unless $arg{sslv2};
    $op |= Net::SSLeay::OP_NO_SSLv3      () if exists $arg{sslv3} && !$arg{sslv3};
    $op |= Net::SSLeay::OP_NO_TLSv1      () if exists $arg{tlsv1} && !$arg{tlsv1};
    $op |= Net::SSLeay::OP_NO_TLSv1_1    () if exists $arg{tlsv1_1} && !$arg{tlsv1_1} && _check_tls_gt_1;
    $op |= Net::SSLeay::OP_NO_TLSv1_2    () if exists $arg{tlsv1_2} && !$arg{tlsv1_2} && _check_tls_gt_1;
    $op |= Net::SSLeay::OP_SINGLE_DH_USE () if !exists $arg{dh_single_use} || $arg{dh_single_use};
 
    Net::SSLeay::CTX_set_options ($ctx, $op);
 
    Net::SSLeay::CTX_set_cipher_list ($ctx, $arg{cipher_list})
       or croak "'$arg{cipher_list}' was not accepted as a valid cipher list by AnyEvent::TLS"
          if exists $arg{cipher_list};
 
    my ($dh_bio, $dh_file);
 
    if (exists $arg{dh_file}) {
       $dh_file = $arg{dh_file};
 
       $dh_bio = Net::SSLeay::BIO_new_file ($dh_file, "r")
          or croak "$dh_file: failed to open DH parameter file: $!";
    } else {
       $arg{dh} = "schmorp1539" unless exists $arg{dh};
 
       if (defined $arg{dh}) {
          $dh_file = "dh string";
 
          if ($arg{dh} =~ /^\w+$/) {
             $dh_file = "dh params $arg{dh}";
             $arg{dh} = "-----BEGIN DH PARAMETERS-----\n"
                      . $DH_PARAMS{$arg{dh}} . "\n"
                      . "-----END DH PARAMETERS-----";
             $arg{dh} =~ s/\|/\n/g;
          }
 
          $dh_bio = Net::SSLeay::BIO_new (Net::SSLeay::BIO_s_mem ());
          Net::SSLeay::BIO_write ($dh_bio, $arg{dh});
       }
    }
 
    if ($dh_bio) {
       my $dh = Net::SSLeay::PEM_read_bio_DHparams ($dh_bio);
       Net::SSLeay::BIO_free ($dh_bio);
       $dh or croak "$dh_file: failed to parse DH parameters - not PEM format?";
       my $rv = Net::SSLeay::CTX_set_tmp_dh ($ctx, $dh);
       Net::SSLeay::DH_free ($dh);
       $rv or croak "$dh_file: failed to set DH parameters";
    }
 
    if ($arg{verify}) {
       $self->{verify_mode} = Net::SSLeay::VERIFY_PEER ();
 
       $self->{verify_mode} |= Net::SSLeay::VERIFY_FAIL_IF_NO_PEER_CERT ()
          if $arg{verify_require_client_cert};
 
       $self->{verify_mode} |= Net::SSLeay::VERIFY_CLIENT_ONCE ()
          if $arg{verify_client_once};
 
    } else {
       $self->{verify_mode} = Net::SSLeay::VERIFY_NONE ();
    }
 
    $self->{verify_peername} = $arg{verify_peername}
       if exists $arg{verify_peername};
 
    $self->{verify_cb} = $arg{verify_cb}
       if exists $arg{verify_cb};
 
    $self->{session_ticket} = $arg{session_ticket}
       if exists $arg{session_ticket};
 
    $self->{debug} = $ENV{PERL_ANYEVENT_TLS_DEBUG}
       if length $ENV{PERL_ANYEVENT_TLS_DEBUG};
 
    $self->{debug} = $arg{debug}
       if exists $arg{debug};
 
    my $pw = $arg{cert_password};
    Net::SSLeay::CTX_set_default_passwd_cb ($ctx, ref $pw ? $pw : sub { $pw });
 
    if ($self->{verify_mode}) {
       if (exists $arg{ca_file} or exists $arg{ca_path} or exists $arg{ca_cert}) {
          # either specified: use them
          if (exists $arg{ca_cert}) {
             my ($ca_file, $g1) = _tmpfile delete $arg{ca_cert};
             Net::SSLeay::CTX_load_verify_locations ($ctx, $ca_file, undef);
          }
          if (exists $arg{ca_file} or exists $arg{ca_path}) {
             Net::SSLeay::CTX_load_verify_locations ($ctx, $arg{ca_file}, $arg{ca_path});
          }
       } elsif (length $ENV{PERL_ANYEVENT_CA_FILE} or length $ENV{PERL_ANYEVENT_CA_PATH}) {
          Net::SSLeay::CTX_load_verify_locations (
             $ctx,
             $ENV{PERL_ANYEVENT_CA_FILE},
             $ENV{PERL_ANYEVENT_CA_PATH},
          );
       } else {
          # else fall back to defaults
          Net::SSLeay::CTX_set_default_verify_paths ($ctx);
       }
    }
 
    if (exists $arg{cert} or exists $arg{cert_file}) {
       my ($g1, $g2);
 
       if (exists $arg{cert}) {
          croak "specifying both cert_file and cert is not allowed"
             if exists $arg{cert_file};
 
         ($arg{cert_file}, $g1) = _tmpfile delete $arg{cert};
       }
 
       if (exists $arg{key} or exists $arg{key_file}) {
          if (exists $arg{key}) {
             croak "specifying both key_file and key is not allowed"
                if exists $arg{key_file};
            ($arg{key_file}, $g2) = _tmpfile delete $arg{key};
          }
       } else {
          $arg{key_file} = $arg{cert_file};
       }
 
       Net::SSLeay::CTX_use_PrivateKey_file
             ($ctx, $arg{key_file}, Net::SSLeay::FILETYPE_PEM ())
          or croak "$arg{key_file}: failed to load local private key (key_file or key)";
 
       Net::SSLeay::CTX_use_certificate_chain_file ($ctx, $arg{cert_file})
          or croak "$arg{cert_file}: failed to use local certificate chain (cert_file or cert)";
    }
 
    if ($arg{check_crl}) {
       Net::SSLeay::OPENSSL_VERSION_NUMBER () >= 0x00090702f
          or croak "check_crl requires openssl v0.9.7b or higher";
 
       Net::SSLeay::X509_STORE_set_flags (
          Net::SSLeay::CTX_get_cert_store ($ctx),
          Net::SSLeay::X509_V_FLAG_CRL_CHECK ());
    }
 
    Net::SSLeay::CTX_set_read_ahead ($ctx, 1);
 
    $arg{prepare}->($self)
       if $arg{prepare};
 
    $self
 }
 
 =item $tls = new_from_ssleay AnyEvent::TLS $ctx
 
 This constructor takes an existing L<Net::SSLeay> SSL_CTX object
 (which is just an integer) and converts it into an C<AnyEvent::TLS>
 object. This only works because AnyEvent::TLS is currently implemented
 using Net::SSLeay. As this is such a horrible perl module and OpenSSL has
 such an annoying license, this might change in the future, in which case
 this method might vanish.
 
 =cut
 
 sub new_from_ssleay {
    my ($class, $ctx) = @_;
 
    bless { ctx => $ctx }, $class
 }
 
 =item $ctx = $tls->ctx
 
 Returns the actual L<Net::SSLeay::CTX> object (just an integer).
 
 =cut
 
 sub ctx {
    $_[0]{ctx}
 }
 
 sub verify_hostname($$$);
 
 sub _verify_hostname {
    my ($self, $cn, $cert) = @_;
    
    return 1
       unless defined $cn;
 
    return 1
       unless exists $self->{verify_peername} && "none" ne lc $self->{verify_peername};
 
    return $self->{verify_peername}->($self, $cn, $cert)
       if ref $self->{verify_peername} && "ARRAY" ne ref $self->{verify_peername};
 
    verify_hostname $cn, $cert, $self->{verify_peername}
 }
 
 sub verify {
    my ($self, $session, $ref, $cn, $preverify_ok, $x509_store_ctx) = @_;
 
    my $cert = $x509_store_ctx
       ? Net::SSLeay::X509_STORE_CTX_get_current_cert ($x509_store_ctx)
       : undef;
    my $depth = Net::SSLeay::X509_STORE_CTX_get_error_depth ($x509_store_ctx);
 
    $preverify_ok &&= $self->_verify_hostname ($cn, $cert)
       unless $depth;
 
    $preverify_ok = $self->{verify_cb}->($self, $ref, $cn, $depth, $preverify_ok, $x509_store_ctx, $cert)
       if $self->{verify_cb};
 
    $preverify_ok
 }
 
 #=item $ssl = $tls->_get_session ($mode[, $ref])
 #
 #Creates a new Net::SSLeay::SSL session object, puts it into C<$mode>
 #(C<accept> or C<connect>) and optionally associates it with the given
 #C<$ref>. If C<$mode> is already a C<Net::SSLeay::SSL> object, then just
 #associate data with it.
 #
 #=cut
 
 #our %REF_MAP;
 
 sub _get_session($$;$$) {
    my ($self, $mode, $ref, $cn) = @_;
 
    my $session;
 
    if ($mode eq "accept") {
       $session = Net::SSLeay::new ($self->{ctx});
       Net::SSLeay::set_accept_state ($session);
 
       Net::SSLeay::set_options ($session, eval { Net::SSLeay::OP_NO_TICKET () })
          unless $self->{session_ticket} || !exists $self->{session_ticket};
 
    } elsif ($mode eq "connect") {
       $session = Net::SSLeay::new ($self->{ctx});
       Net::SSLeay::set_connect_state ($session);
 
       Net::SSLeay::set_options ($session, eval { Net::SSLeay::OP_NO_TICKET () })
          unless $self->{session_ticket};
    } else {
       croak "'$mode': unsupported TLS mode (must be either 'connect' or 'accept')"
    }
 
 #   # associate data
 #   Net::SSLeay::set_ex_data ($session, $REF_IDX, $ref+0);
 #   Scalar::Util::weaken ($REF_MAP{$ref+0} = $ref)
 #      if ref $ref;
    
    if ($self->{debug}) {
       #d# Net::SSLeay::set_info_callback ($session, 50000);
    }
 
    if ($self->{verify_mode}) {
       Scalar::Util::weaken $self;
       Scalar::Util::weaken $ref;
 
       # we have to provide a dummy callbacks as at least Net::SSLeay <= 1.35
       # try to call it even if specified as 0 or undef.
       Net::SSLeay::set_verify
          $session,
          $self->{verify_mode},
          sub { $self->verify ($session, $ref, $cn, @_) };
    }
 
    $session
 }
 
 sub _put_session($$) {
    my ($self, $session) = @_;
 
    # clear callback, if any
    # this leaks memoryin Net::SSLeay up to at least 1.35, but there
    # apparently is no other way.
    Net::SSLeay::set_verify $session, 0, undef;
 
 #   # disassociate data
 #   delete $REF_MAP{Net::SSLeay::get_ex_data ($session, $REF_IDX)};
 
    Net::SSLeay::free ($session);
 }
 
 #sub _ref($) {
 #   $REF_MAP{Net::SSLeay::get_ex_data ($_[0], $REF_IDX)}
 #}
 
 sub DESTROY {
    my ($self) = @_;
 
    # better be safe than sorry with net-ssleay
    Net::SSLeay::CTX_set_default_passwd_cb ($self->{ctx});
 
    Net::SSLeay::CTX_free ($self->{ctx});
 }
 
 =item AnyEvent::TLS::init
 
 AnyEvent::TLS does on-demand initialisation, and normally there is no need to call an initialise
 function.
 
 As initialisation might take some time (to read e.g. C</dev/urandom>), this
 could be annoying in some highly interactive programs. In that case, you can
 call C<AnyEvent::TLS::init> to make sure there will be no costly initialisation
 later. It is harmless to call C<AnyEvent::TLS::init> multiple times.
 
 =cut
 
 sub init() {
    return if $REF_IDX;
 
    AE::log 5 => "Net::SSLeay versions older than 1.33 might malfunction."
       if $Net::SSLeay::VERSION < 1.33;
 
    Net::SSLeay::load_error_strings ();
    Net::SSLeay::SSLeay_add_ssl_algorithms ();
    Net::SSLeay::randomize ();
 
    $REF_IDX = Net::SSLeay::get_ex_new_index (0, 0, 0, 0, 0)
       until $REF_IDX; # Net::SSLeay uses id #0 for its own stuff without allocating it
 }
 
 =item $certname = AnyEvent::TLS::certname $x509
 
 Utility function that returns a user-readable string identifying the X509
 certificate object.
 
 =cut
 
 sub certname {
    $_[0]
       ? Net::SSLeay::X509_NAME_oneline (Net::SSLeay::X509_get_issuer_name ($_[0]))
         . Net::SSLeay::X509_NAME_oneline (Net::SSLeay::X509_get_subject_name ($_[0]))
       : undef
 }
 
 our %CN_SCHEME = (
    # each tuple is [$cn_wildcards, $alt_wildcards, $check_cn]
    # where *_wildcards is 0 for none allowed, 1 for allowed at beginning and 2 for allowed everywhere
    # and check_cn is 0 for do not check, 1 for check when no alternate dns names and 2 always
    # all of this is from IO::Socket::SSL
 
    rfc4513 => [0, 1, 2],
    rfc2818 => [0, 2, 1],
    rfc3207 => [0, 0, 2], # see IO::Socket::SSL, rfc seems unclear
    none    => [],        # do not check
 
    ldap    => "rfc4513",                    ldaps => "ldap",
    http    => "rfc2818",                    https => "http",
    smtp    => "rfc3207",                    smtps => "smtp",
 
    xmpp    => "rfc3920", rfc3920 => "http",
    pop3    => "rfc2595", rfc2595 => "ldap", pop3s => "pop3",
    imap    => "rfc2595", rfc2595 => "ldap", imaps => "imap",
    acap    => "rfc2595", rfc2595 => "ldap",
    nntp    => "rfc4642", rfc4642 => "ldap", nntps => "nntp",
    ftp     => "rfc4217", rfc4217 => "http", ftps  => "ftp" ,
 );
 
 sub match_cn($$$) {
    my ($name, $cn, $type) = @_;
 
    # remove leading and trailing garbage
    for ($name, $cn) {
       s/[\x00-\x1f]+$//;
       s/^[\x00-\x1f]+//;
    }
 
    my $pattern;
 
    ### IMPORTANT!
    # we accept only a single wildcard and only for a single part of the FQDN
    # e.g *.example.org does match www.example.org but not bla.www.example.org
    # The RFCs are in this regard unspecific but we don't want to have to
    # deal with certificates like *.com, *.co.uk or even *
    # see also http://nils.toedtmann.net/pub/subjectAltName.txt
    if ($type == 2 and $name =~m{^([^.]*)\*(.+)} ) {
       $pattern = qr{^\Q$1\E[^.]*\Q$2\E$}i;
    } elsif ($type == 1 and $name =~m{^\*(\..+)$} ) {
       $pattern = qr{^[^.]*\Q$1\E$}i;
    } else {
       $pattern = qr{^\Q$name\E$}i;
    }
 
    $cn =~ $pattern
 }
 
 # taken verbatim from IO::Socket::SSL, then changed to take advantage of
 # AnyEvent utilities.
 sub verify_hostname($$$) {
    my ($cn, $cert, $scheme) = @_;
 
    while (!ref $scheme) {
       $scheme = $CN_SCHEME{$scheme}
          or return 1;
    }
 
    my $cert_cn =
       Net::SSLeay::X509_NAME_get_text_by_NID (
          Net::SSLeay::X509_get_subject_name ($cert), Net::SSLeay::NID_commonName ());
 
    my @cert_alt = Net::SSLeay::X509_get_subjectAltNames ($cert);
 
    # rfc2460 - convert to network byte order
    require AnyEvent::Socket;
    my $ip = AnyEvent::Socket::parse_address ($cn);
 
    my $alt_dns_count;
 
    while (my ($type, $name) = splice @cert_alt, 0, 2) {
       if ($type == Net::SSLeay::GEN_IPADD ()) {
          # $name is already packed format (inet_xton)
          return 1 if $ip eq $name;
       } elsif ($type == Net::SSLeay::GEN_DNS ()) {
          $alt_dns_count++;
 
          return 1 if match_cn $name, $cn, $scheme->[1];
       }
    }
 
    if ($scheme->[2] == 2
        || ($scheme->[2] == 1 && !$alt_dns_count)) {
       return 1 if match_cn $cert_cn, $cn, $scheme->[0];
    }
 
    0
 }
 
 =back
 
 =head1 SSL/TLS QUICK FACTS
 
 Here are some quick facts about TLS/SSL that might help you:
 
 =over 4
 
 =item * A certificate is the public key part, a key is the private key part.
 
 While not strictly true, certificates are the things you can hand around
 publicly as a kind of identity, while keys should really be kept private,
 as proving that you have the private key is usually interpreted as being
 the entity behind the certificate.
 
 =item * A certificate is signed by a CA (Certificate Authority).
 
 By signing, the CA basically claims that the certificate it signs
 really belongs to the identity named in it, verified according to the
 CA policies. For e.g. HTTPS, the CA usually makes some checks that the
 hostname mentioned in the certificate really belongs to the company/person
 that requested the signing and owns the domain.
 
 =item * CAs can be certified by other CAs.
 
 Or by themselves - a certificate that is signed by a CA that is itself
 is called a self-signed certificate, a trust chain of length zero. When
 you find a certificate signed by another CA, which is in turn signed by
 another CA you trust, you have a trust chain of depth two.
 
 =item * "Trusting" a CA means trusting all certificates it has signed.
 
 If you "trust" a CA certificate, then all certificates signed by it are
 automatically considered trusted as well.
 
 =item * A successfully verified certificate means that you can be
 reasonably sure that whoever you are talking with really is who he claims
 he is.
 
 By verifying certificates against a number of CAs that you trust (meaning
 it is signed directly or indirectly by such a CA), you can find out that
 the other side really is whoever he claims, according to the CA policies,
 and your belief in the integrity of the CA.
 
 =item * Verifying the certificate signature is not everything.
 
 Even when the certificate is correct, it might belong to somebody else: if
 www.attacker.com can make your computer believe that it is really called
 www.mybank.com (by making your DNS server believe this for example),
 then it could send you the certificate for www.attacker.com that your
 software trusts because it is signed by a CA you trust, and intercept
 all your traffic that you think goes to www.mybank.com. This works
 because your software sees that the certificate is correctly signed (for
 www.attacker.com) and you think you are talking to your bank.
 
 To thwart this attack vector, peername verification should be used, which
 basically checks that the certificate (for www.attacker.com) really
 belongs to the host you are trying to talk to (www.mybank.com), which in
 this example is not the case, as www.attacker.com (from the certificate)
 doesn't match www.mybank.com (the hostname used to create the connection).
 
 So peername verification is almost as important as checking the CA
 signing. Unfortunately, every protocol implements this differently, if at
 all...
 
 =item * Switching off verification is sometimes reasonable.
 
 You can switch off verification. You still get an encrypted connection
 that is protected against eavesdropping and injection - you just lose
 protection against man in the middle attacks, i.e. somebody else with
 enough abilities to intercept all traffic can masquerade herself as the
 other side.
 
 For many applications, switching off verification is entirely
 reasonable. Downloading random stuff from websites using HTTPS for no
 reason is such an application. Talking to your bank and entering TANs is
 not such an application.
 
 =item * A SSL/TLS server always needs a certificate/key pair to operate,
 for clients this is optional.
 
 Apart from (usually disabled) anonymous cipher suites, a server always
 needs a certificate/key pair to operate.
 
 Clients almost never use certificates, but if they do, they can be used
 to authenticate the client, just as server certificates can be used to
 authenticate the server.
 
 =item * SSL version 2 is very insecure.
 
 SSL version 2 is old and not only has it some security issues, SSLv2-only
 implementations are usually buggy, too, due to their age.
 
 =item * Sometimes, even losing your "private" key might not expose all your
 data.
 
 With Diffie-Hellman ephemeral key exchange, you can lose the DH parameters
 (the "keys"), but all your connections are still protected. Diffie-Hellman
 needs special set-up (done by default by AnyEvent::TLS).
 
 =back
 
 =head1 SECURITY CONSIDERATIONS
 
 When you use any of the options that pass in keys or certificates
 as strings (e.g. C<ca_cert>), then, due to serious shortcomings in
 L<Net::SSLeay>, this module creates a temporary file to store the string -
 see L<File::Temp> and possibly its C<safe_level> setting for more details
 on what to watch out for.
 
 =head1 BUGS
 
 Due to the abysmal code quality of Net::SSLeay, this module will leak small
 amounts of memory per TLS connection (currently at least one perl scalar).
 
 =head1 AUTHORS
 
 Marc Lehmann <schmorp@schmorp.de>.
 
 Some of the API, documentation and implementation (verify_hostname),
 and a lot of ideas/workarounds/knowledge have been taken from the
 L<IO::Socket::SSL> module. Care has been taken to keep the API similar to
 that and other modules, to the extent possible while providing a sensible
 API for AnyEvent.
 
 =cut
 
 1
 
### AnyEvent/Util.pm ###
 =encoding utf-8
 
 =head1 NAME
 
 AnyEvent::Util - various utility functions.
 
 =head1 SYNOPSIS
 
    use AnyEvent::Util;
 
 =head1 DESCRIPTION
 
 This module implements various utility functions, mostly replacing
 well-known functions by event-ised counterparts.
 
 All functions documented without C<AnyEvent::Util::> prefix are exported
 by default.
 
 =over 4
 
 =cut
 
 package AnyEvent::Util;
 
 use Carp ();
 use Errno ();
 use Socket ();
 
 use AnyEvent (); BEGIN { AnyEvent::common_sense }
 
 use base 'Exporter';
 
 our @EXPORT = qw(fh_nonblocking guard fork_call portable_pipe portable_socketpair run_cmd);
 our @EXPORT_OK = qw(
    AF_INET6 WSAEWOULDBLOCK WSAEINPROGRESS WSAEINVAL
    close_all_fds_except
    punycode_encode punycode_decode idn_nameprep idn_to_ascii idn_to_unicode
 );
 
 our $VERSION = $AnyEvent::VERSION;
 
 BEGIN {
    # provide us with AF_INET6, but only if allowed
    if (
       $AnyEvent::PROTOCOL{ipv6}
       && _AF_INET6
       && socket my $ipv6_socket, _AF_INET6, Socket::SOCK_DGRAM(), 0 # check if they can be created
    ) {
       *AF_INET6 = \&_AF_INET6;
    } else {
       # disable ipv6
       *AF_INET6 = sub () { 0 };
       delete $AnyEvent::PROTOCOL{ipv6};
    }
 
    # fix buggy Errno on some non-POSIX platforms
    # such as openbsd and windows.
    my %ERR = (
       EBADMSG => Errno::EDOM   (),
       EPROTO  => Errno::ESPIPE (),
    );
 
    while (my ($k, $v) = each %ERR) {
       next if eval "Errno::$k ()";
       AE::log 8 => "Broken Errno module, adding Errno::$k.";
 
       eval "sub Errno::$k () { $v }";
       push @Errno::EXPORT_OK, $k;
       push @{ $Errno::EXPORT_TAGS{POSIX} }, $k;
    }
 }
 
 =item ($r, $w) = portable_pipe
 
 Calling C<pipe> in Perl is portable - except it doesn't really work on
 sucky windows platforms (at least not with most perls - cygwin's perl
 notably works fine): On windows, you actually get two file handles you
 cannot use select on.
 
 This function gives you a pipe that actually works even on the broken
 windows platform (by creating a pair of TCP sockets on windows, so do not
 expect any speed from that) and using C<pipe> everywhere else.
 
 See C<portable_socketpair>, below, for a bidirectional "pipe".
 
 Returns the empty list on any errors.
 
 =item ($fh1, $fh2) = portable_socketpair
 
 Just like C<portable_pipe>, above, but returns a bidirectional pipe
 (usually by calling C<socketpair> to create a local loopback socket pair,
 except on windows, where it again returns two interconnected TCP sockets).
 
 Returns the empty list on any errors.
 
 =cut
 
 BEGIN {
    if (AnyEvent::WIN32) {
       *_win32_socketpair = sub () {
          # perl's socketpair emulation fails on many vista machines, because
          # vista returns fantasy port numbers.
 
          for (1..10) {
             socket my $l, Socket::AF_INET(), Socket::SOCK_STREAM(), 0
                or next;
 
             bind $l, Socket::pack_sockaddr_in 0, "\x7f\x00\x00\x01"
                or next;
 
             my $sa = getsockname $l
                or next;
 
             listen $l, 1
                or next;
 
             socket my $r, Socket::AF_INET(), Socket::SOCK_STREAM(), 0
                or next;
 
             bind $r, Socket::pack_sockaddr_in 0, "\x7f\x00\x00\x01"
                or next;
 
             connect $r, $sa
                or next;
 
             accept my $w, $l
                or next;
 
             # vista has completely broken peername/sockname that return
             # fantasy ports. this combo seems to work, though.
             (Socket::unpack_sockaddr_in getpeername $r)[0]
             == (Socket::unpack_sockaddr_in getsockname $w)[0]
                or (($! = WSAEINVAL), next);
 
             # vista example (you can't make this shit up...):
             #(Socket::unpack_sockaddr_in getsockname $r)[0] == 53364
             #(Socket::unpack_sockaddr_in getpeername $r)[0] == 53363
             #(Socket::unpack_sockaddr_in getsockname $w)[0] == 53363
             #(Socket::unpack_sockaddr_in getpeername $w)[0] == 53365
 
             return ($r, $w);
          }
 
          ()
       };
 
       *portable_socketpair = \&_win32_socketpair;
       *portable_pipe       = \&_win32_socketpair;
    } else {
       *portable_pipe = sub () {
          my ($r, $w);
 
          pipe $r, $w
             or return;
 
          ($r, $w);
       };
 
       *portable_socketpair = sub () {
          socketpair my $fh1, my $fh2, Socket::AF_UNIX(), Socket::SOCK_STREAM(), 0
             or return;
 
          ($fh1, $fh2)
       };
    }
 }
 
 =item fork_call { CODE } @args, $cb->(@res)
 
 Executes the given code block asynchronously, by forking. Everything the
 block returns will be transferred to the calling process (by serialising and
 deserialising via L<Storable>).
 
 If there are any errors, then the C<$cb> will be called without any
 arguments. In that case, either C<$@> contains the exception (and C<$!> is
 irrelevant), or C<$!> contains an error number. In all other cases, C<$@>
 will be C<undef>ined.
 
 The code block must not ever call an event-polling function or use
 event-based programming that might cause any callbacks registered in the
 parent to run.
 
 Win32 spoilers: Due to the endlessly sucky and broken native windows
 perls (there is no way to cleanly exit a child process on that platform
 that doesn't also kill the parent), you have to make sure that your main
 program doesn't exit as long as any C<fork_calls> are still in progress,
 otherwise the program won't exit. Also, on most windows platforms some
 memory will leak for every invocation. We are open for improvements that
 don't require XS hackery.
 
 Note that forking can be expensive in large programs (RSS 200MB+). On
 windows, it is abysmally slow, do not expect more than 5..20 forks/s on
 that sucky platform (note this uses perl's pseudo-threads, so avoid those
 like the plague).
 
 Example: poor man's async disk I/O (better use L<AnyEvent::IO> together
 with L<IO::AIO>).
 
    fork_call {
       open my $fh, "</etc/passwd"
          or die "passwd: $!";
       local $/;
       <$fh>
    } sub {
       my ($passwd) = @_;
       ...
    };
 
 =item $AnyEvent::Util::MAX_FORKS [default: 10]
 
 The maximum number of child processes that C<fork_call> will fork in
 parallel. Any additional requests will be queued until a slot becomes free
 again.
 
 The environment variable C<PERL_ANYEVENT_MAX_FORKS> is used to initialise
 this value.
 
 =cut
 
 our $MAX_FORKS = int 1 * $ENV{PERL_ANYEVENT_MAX_FORKS};
 $MAX_FORKS = 10 if $MAX_FORKS <= 0;
 
 my $forks;
 my @fork_queue;
 
 sub _fork_schedule;
 sub _fork_schedule {
    require Storable unless $Storable::VERSION;
    require POSIX    unless $POSIX::VERSION;
 
    while ($forks < $MAX_FORKS) {
       my $job = shift @fork_queue
          or last;
 
       ++$forks;
 
       my $coderef = shift @$job;
       my $cb = pop @$job;
       
       # gimme a break...
       my ($r, $w) = portable_pipe
          or ($forks and last) # allow failures when we have at least one job
          or die "fork_call: $!";
 
       my $pid = fork;
 
       if ($pid != 0) {
          # parent
          close $w;
 
          my $buf;
 
          my $ww; $ww = AE::io $r, 0, sub {
             my $len = sysread $r, $buf, 65536, length $buf;
 
             return unless defined $len or $! != Errno::EINTR;
 
             if (!$len) {
                undef $ww;
                close $r;
                --$forks;
                _fork_schedule;
                
                my $result = eval { Storable::thaw ($buf) };
                $result = [$@] unless $result;
                $@ = shift @$result;
 
                $cb->(@$result);
 
                # work around the endlessly broken windows perls
                kill 9, $pid if AnyEvent::WIN32;
 
                # clean up the pid
                waitpid $pid, 0;
             }
          };
 
       } elsif (defined $pid) {
          # child
          close $r;
 
          my $result = eval {
             local $SIG{__DIE__};
 
             Storable::freeze ([undef, $coderef->(@$job)])
          };
 
          $result = Storable::freeze (["$@"])
             if $@;
 
          # windows forces us to these contortions
          my $ofs;
 
          while () {
             my $len = (length $result) - $ofs
                or last;
 
             $len = syswrite $w, $result, $len < 65536 ? $len : 65536, $ofs;
 
             last unless $len || (!defined $len && $! == Errno::EINTR);
 
             $ofs += $len;
          }
 
          # on native windows, _exit KILLS YOUR FORKED CHILDREN!
          if (AnyEvent::WIN32) {
             shutdown $w, 1; # signal parent to please kill us
             sleep 10; # give parent a chance to clean up
             sysread $w, (my $buf), 1; # this *might* detect the parent exiting in some cases.
          }
          POSIX::_exit (0);
          exit 1;
          
       } elsif (($! != &Errno::EAGAIN && $! != &Errno::EWOULDBLOCK && $! != &Errno::ENOMEM) || !$forks) {
          # we ignore some errors as long as we can run at least one job
          # maybe we should wait a few seconds and retry instead
          die "fork_call: $!";
       }
    }
 }
 
 sub fork_call(&@) {
    push @fork_queue, [@_];
    _fork_schedule;
 }
 
 END {
    if (AnyEvent::WIN32) {
       while ($forks) {
          @fork_queue = ();
          AnyEvent->one_event;
       }
    }
 }
 
 # to be removed
 sub dotted_quad($) {
    $_[0] =~ /^(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[0-9][0-9]?)
             \.(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[0-9][0-9]?)
             \.(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[0-9][0-9]?)
             \.(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[0-9][0-9]?)$/x
 }
 
 # just a forwarder
 sub inet_aton {
    require AnyEvent::Socket;
    *inet_aton = \&AnyEvent::Socket::inet_aton;
    goto &inet_aton
 }
 
 =item fh_nonblocking $fh, $nonblocking
 
 Sets the blocking state of the given filehandle (true == nonblocking,
 false == blocking). Uses fcntl on anything sensible and ioctl FIONBIO on
 broken (i.e. windows) platforms.
 
 Instead of using this function, you could use C<AnyEvent::fh_block> or
 C<AnyEvent::fh_unblock>.
 
 =cut
 
 BEGIN {
    *fh_nonblocking = \&AnyEvent::_fh_nonblocking;
 }
 
 =item $guard = guard { CODE }
 
 This function creates a special object that, when called, will execute
 the code block.
 
 This is often handy in continuation-passing style code to clean up some
 resource regardless of where you break out of a process.
 
 The L<Guard> module will be used to implement this function, if it is
 available. Otherwise a pure-perl implementation is used.
 
 While the code is allowed to throw exceptions in unusual conditions, it is
 not defined whether this exception will be reported (at the moment, the
 Guard module and AnyEvent's pure-perl implementation both try to report
 the error and continue).
 
 You can call one method on the returned object:
 
 =item $guard->cancel
 
 This simply causes the code block not to be invoked: it "cancels" the
 guard.
 
 =cut
 
 BEGIN {
    if (!$ENV{PERL_ANYEVENT_AVOID_GUARD} && eval { require Guard; $Guard::VERSION >= 0.5 }) {
       *guard = \&Guard::guard;
       AE::log 8 => "Using Guard module to implement guards.";
    } else {
       *AnyEvent::Util::guard::DESTROY = sub {
          local $@;
 
          eval {
             local $SIG{__DIE__};
             ${$_[0]}->();
          };
 
          AE::log 4 => "Runtime error in AnyEvent::guard callback: $@" if $@;
       };
 
       *AnyEvent::Util::guard::cancel = sub ($) {
          ${$_[0]} = sub { };
       };
 
       *guard = sub (&) {
          bless \(my $cb = shift), "AnyEvent::Util::guard"
       };
 
       AE::log 8 => "Using pure-perl guard implementation.";
    }
 }
 
 =item AnyEvent::Util::close_all_fds_except @fds
 
 This rarely-used function simply closes all file descriptors (or tries to)
 of the current process except the ones given as arguments.
 
 When you want to start a long-running background server, then it is often
 beneficial to do this, as too many C-libraries are too stupid to mark
 their internal fd's as close-on-exec.
 
 The function expects to be called shortly before an C<exec> call.
 
 Example: close all fds except 0, 1, 2.
 
    close_all_fds_except 0, 2, 1;
 
 =cut
 
 sub close_all_fds_except {
    my %except; @except{@_} = ();
 
    require POSIX unless $POSIX::VERSION;
 
    # some OSes have a usable /dev/fd, sadly, very few
    if ($^O =~ /(freebsd|cygwin|linux)/) {
       # netbsd, openbsd, solaris have a broken /dev/fd
       my $dir;
       if (opendir $dir, "/dev/fd" or opendir $dir, "/proc/self/fd") {
          my @fds = sort { $a <=> $b } grep /^\d+$/, readdir $dir;
          # broken OS's have device nodes for 0..63 usually, solaris 0..255
          if (@fds < 20 or "@fds" ne join " ", 0..$#fds) {
             # assume the fds array is valid now
             exists $except{$_} or POSIX::close ($_)
                for @fds;
             return;
          }
       }
    }
 
    my $fd_max = eval { POSIX::sysconf (POSIX::_SC_OPEN_MAX ()) - 1 } || 1023;
 
    exists $except{$_} or POSIX::close ($_)
       for 0..$fd_max;
 }
 
 =item $cv = run_cmd $cmd, key => value...
 
 Run a given external command, potentially redirecting file descriptors and
 return a condition variable that gets sent the exit status (like C<$?>)
 when the program exits I<and> all redirected file descriptors have been
 exhausted.
 
 The C<$cmd> is either a single string, which is then passed to a shell, or
 an arrayref, which is passed to the C<execvp> function (the first array
 element is used both for the executable name and argv[0]).
 
 The key-value pairs can be:
 
 =over 4
 
 =item ">" => $filename
 
 Redirects program standard output into the specified filename, similar to C<<
 >filename >> in the shell.
 
 =item ">" => \$data
 
 Appends program standard output to the referenced scalar. The condvar will
 not be signalled before EOF or an error is signalled.
 
 =item ">" => $filehandle
 
 Redirects program standard output to the given filehandle (or actually its
 underlying file descriptor).
 
 =item ">" => $callback->($data)
 
 Calls the given callback each time standard output receives some data,
 passing it the data received. On EOF or error, the callback will be
 invoked once without any arguments.
 
 The condvar will not be signalled before EOF or an error is signalled.
 
 =item "fd>" => $see_above
 
 Like ">", but redirects the specified fd number instead.
 
 =item "<" => $see_above
 
 The same, but redirects the program's standard input instead. The same
 forms as for ">" are allowed.
 
 In the callback form, the callback is supposed to return data to be
 written, or the empty list or C<undef> or a zero-length scalar to signal
 EOF.
 
 Similarly, either the write data must be exhausted or an error is to be
 signalled before the condvar is signalled, for both string-reference and
 callback forms.
 
 =item "fd<" => $see_above
 
 Like "<", but redirects the specified file descriptor instead.
 
 =item on_prepare => $cb
 
 Specify a callback that is executed just before the command is C<exec>'ed,
 in the child process. Be careful not to use any event handling or other
 services not available in the child.
 
 This can be useful to set up the environment in special ways, such as
 changing the priority of the command or manipulating signal handlers (e.g.
 setting C<SIGINT> to C<IGNORE>).
 
 =item close_all => $boolean
 
 When C<close_all> is enabled (default is disabled), then all extra file
 descriptors will be closed, except the ones that were redirected and C<0>,
 C<1> and C<2>.
 
 See C<close_all_fds_except> for more details.
 
 =item '$$' => \$pid
 
 A reference to a scalar which will receive the PID of the newly-created
 subprocess after C<run_cmd> returns.
 
 Note the the PID might already have been recycled and used by an unrelated
 process at the time C<run_cmd> returns, so it's not useful to send
 signals, use a unique key in data structures and so on.
 
 =back
 
 Example: run C<rm -rf />, redirecting standard input, output and error to
 F</dev/null>.
 
    my $cv = run_cmd [qw(rm -rf /)],
       "<", "/dev/null",
       ">", "/dev/null",
       "2>", "/dev/null";
    $cv->recv and die "d'oh! something survived!"
 
 Example: run F<openssl> and create a self-signed certificate and key,
 storing them in C<$cert> and C<$key>. When finished, check the exit status
 in the callback and print key and certificate.
 
    my $cv = run_cmd [qw(openssl req
                      -new -nodes -x509 -days 3650
                      -newkey rsa:2048 -keyout /dev/fd/3
                      -batch -subj /CN=AnyEvent
                     )],
       "<", "/dev/null",
       ">" , \my $cert,
       "3>", \my $key,
       "2>", "/dev/null";
 
    $cv->cb (sub {
       shift->recv and die "openssl failed";
 
       print "$key\n$cert\n";
    });
 
 =cut
 
 sub run_cmd {
    my $cmd = shift;
 
    require POSIX unless $POSIX::VERSION;
 
    my $cv = AE::cv;
 
    my %arg;
    my %redir;
    my @exe;
 
    while (@_) {
       my ($type, $ob) = splice @_, 0, 2;
 
       my $fd = $type =~ s/^(\d+)// ? $1 : undef;
 
       if ($type eq ">") {
          $fd = 1 unless defined $fd;
 
          if (defined eval { fileno $ob }) {
             $redir{$fd} = $ob;
          } elsif (ref $ob) {
             my ($pr, $pw) = AnyEvent::Util::portable_pipe;
             $cv->begin;
 
             fcntl $pr, AnyEvent::F_SETFD, AnyEvent::FD_CLOEXEC;
             fh_nonblocking $pr, 1;
             my $w; $w = AE::io $pr, 0,
                "SCALAR" eq ref $ob
                   ? sub {
                        defined (sysread $pr, $$ob, 16384, length $$ob
                                 and return)
                           or ($! == Errno::EINTR and return);
                        undef $w; $cv->end;
                     }
                   : sub {
                        my $buf;
                        defined (sysread $pr, $buf, 16384
                                 and return $ob->($buf))
                           or ($! == Errno::EINTR and return);
                        undef $w; $cv->end;
                        $ob->();
                     }
             ;
             $redir{$fd} = $pw;
          } else {
             push @exe, sub {
                open my $fh, ">", $ob
                   or POSIX::_exit (125);
                $redir{$fd} = $fh;
             };
          }
 
       } elsif ($type eq "<") {
          $fd = 0 unless defined $fd;
 
          if (defined eval { fileno $ob }) {
             $redir{$fd} = $ob;
          } elsif (ref $ob) {
             my ($pr, $pw) = AnyEvent::Util::portable_pipe;
             $cv->begin;
 
             my $data;
             if ("SCALAR" eq ref $ob) {
                $data = $$ob;
                $ob = sub { };
             } else {
                $data = $ob->();
             }
 
             fcntl $pw, AnyEvent::F_SETFD, AnyEvent::FD_CLOEXEC;
             fh_nonblocking $pw, 1;
             my $w; $w = AE::io $pw, 1, sub {
                my $len = syswrite $pw, $data;
 
                return unless defined $len or $! != Errno::EINTR;
 
                if (!$len) {
                   undef $w; $cv->end;
                } else {
                   substr $data, 0, $len, "";
                   unless (length $data) {
                      $data = $ob->();
                      unless (length $data) {
                         undef $w; $cv->end
                      }
                   }
                }
             };
 
             $redir{$fd} = $pr;
          } else {
             push @exe, sub {
                open my $fh, "<", $ob
                   or POSIX::_exit (125);
                $redir{$fd} = $fh;
             };
          }
 
       } else {
          $arg{$type} = $ob;
       }
    }
 
    my $pid = fork;
 
    defined $pid
       or Carp::croak "fork: $!";
 
    unless ($pid) {
       # step 1, execute
       $_->() for @exe;
 
       # step 2, move any existing fd's out of the way
       # this also ensures that dup2 is never called with fd1==fd2
       # so the cloexec flag is always cleared
       my (@oldfh, @close);
       for my $fh (values %redir) {
          push @oldfh, $fh; # make sure we keep it open
          $fh = fileno $fh; # we only want the fd
 
          # dup if we are in the way
          # if we "leak" fds here, they will be dup2'ed over later
          defined ($fh = POSIX::dup ($fh)) or POSIX::_exit (124)
             while exists $redir{$fh};
       }
 
       # step 3, execute redirects
       while (my ($k, $v) = each %redir) {
          defined POSIX::dup2 ($v, $k)
             or POSIX::_exit (123);
       }
 
       # step 4, close everything else, except 0, 1, 2
       if ($arg{close_all}) {
          close_all_fds_except 0, 1, 2, keys %redir
       } else {
          POSIX::close ($_)
             for values %redir;
       }
 
       eval { $arg{on_prepare}(); 1 } or POSIX::_exit (123)
          if exists $arg{on_prepare};
 
       ref $cmd
          ? exec {$cmd->[0]} @$cmd
          : exec $cmd;
 
       POSIX::_exit (126);
    }
 
    ${$arg{'$$'}} = $pid
       if $arg{'$$'};
 
    %redir = (); # close child side of the fds
 
    my $status;
    $cv->begin (sub { shift->send ($status) });
    my $cw; $cw = AE::child $pid, sub {
       $status = $_[1];
       undef $cw; $cv->end;
    };
 
    $cv
 }
 
 =item AnyEvent::Util::punycode_encode $string
 
 Punycode-encodes the given C<$string> and returns its punycode form. Note
 that uppercase letters are I<not> casefolded - you have to do that
 yourself.
 
 Croaks when it cannot encode the string.
 
 =item AnyEvent::Util::punycode_decode $string
 
 Tries to punycode-decode the given C<$string> and return its unicode
 form. Again, uppercase letters are not casefoled, you have to do that
 yourself.
 
 Croaks when it cannot decode the string.
 
 =cut
 
 sub punycode_encode($) {
    require "AnyEvent/Util/idna.pl";
    goto &punycode_encode;
 }
 
 sub punycode_decode($) {
    require "AnyEvent/Util/idna.pl";
    goto &punycode_decode;
 }
 
 =item AnyEvent::Util::idn_nameprep $idn[, $display]
 
 Implements the IDNA nameprep normalisation algorithm. Or actually the
 UTS#46 algorithm. Or maybe something similar - reality is complicated
 between IDNA2003, UTS#46 and IDNA2008. If C<$display> is true then the name
 is prepared for display, otherwise it is prepared for lookup (default).
 
 If you have no clue what this means, look at C<idn_to_ascii> instead.
 
 This function is designed to avoid using a lot of resources - it uses
 about 1MB of RAM (most of this due to Unicode::Normalize). Also, names
 that are already "simple" will only be checked for basic validity, without
 the overhead of full nameprep processing.
 
 =cut
 
 our ($uts46_valid, $uts46_imap);
 
 sub idn_nameprep($;$) {
    local $_ = $_[0];
 
    # lowercasing these should always be valid, and is required for xn-- detection
    y/A-Z/a-z/;
 
    if (/[^0-9a-z\-.]/) {
       # load the mapping data
       unless (defined $uts46_imap) {
          require Unicode::Normalize;
          require "AnyEvent/Util/uts46data.pl";
       }
 
       # uts46 nameprep
 
       # I naively tried to use a regex/transliterate approach first,
       # with one regex and one y///, but the compiled code was 4.5MB.
       # this version has a bit-table for the valid class, and
       # a char-replacement search string
 
       # for speed (cough) reasons, we skip-case 0-9a-z, -, ., which
       # really ought to be trivially valid. A-Z is valid, but already lowercased.
       s{
          ([^0-9a-z\-.])
       }{
          my $chr = $1;
          unless (vec $uts46_valid, ord $chr, 1) {
             # not in valid class, search for mapping
             utf8::encode $chr; # the imap table is in utf-8
             (my $rep = index $uts46_imap, "\x00$chr") >= 0
                or Carp::croak "$_[0]: disallowed characters ($chr) during idn_nameprep" . unpack "H*", $chr;
 
             (substr $uts46_imap, $rep, 128) =~ /\x00 .[\x80-\xbf]* ([^\x00]*) \x00/x
                or die "FATAL: idn_nameprep imap table has unexpected contents";
 
             $rep = $1;
             $chr = $rep unless $rep =~ s/^\x01// && $_[1]; # replace unless deviation and display
             utf8::decode $chr;
          }
          $chr
       }gex;
 
       # KC
       $_ = Unicode::Normalize::NFKC ($_);
    }
 
    # decode punycode components, check for invalid xx-- prefixes
    s{
       (^|\.)(..)--([^\.]*)
    }{
       my ($pfx, $ace, $pc) = ($1, $2, $3);
 
       if ($ace eq "xn") {
          $pc = punycode_decode $pc; # will croak on error (we hope :)
 
          require Unicode::Normalize;
          $pc eq Unicode::Normalize::NFC ($pc)
             or Carp::croak "$_[0]: punycode label not in NFC detected during idn_nameprep";
 
          "$pfx$pc"
       } elsif ($ace !~ /^[a-z0-9]{2}$/) {
          "$pfx$ace--$pc"
       } else {
          Carp::croak "$_[0]: hyphens in 3rd/4th position of a label are not allowed";
       }
    }gex;
 
    # uts46 verification
    /\.-|-\./
       and Carp::croak "$_[0]: invalid hyphens detected during idn_nameprep";
 
    # missing: label begin with combining mark, idna2008 bidi
 
    # now check validity of each codepoint
    if (/[^0-9a-z\-.]/) {
       # load the mapping data
       unless (defined $uts46_imap) {
          require "AnyEvent/Util/uts46data.pl";
       }
 
       vec $uts46_valid, ord, 1
          or $_[1] && 0 <= index $uts46_imap, pack "C0U*", 0, ord, 1 # deviation == \x00$chr\x01
          or Carp::croak "$_[0]: disallowed characters during idn_nameprep"
          for split //;
    }
 
    $_
 }
 
 =item $domainname = AnyEvent::Util::idn_to_ascii $idn
 
 Converts the given unicode string (C<$idn>, international domain name,
 e.g. 日本語。ＪＰ) to a pure-ASCII domain name (this is usually
 called the "IDN ToAscii" transform). This transformation is idempotent,
 which means you can call it just in case and it will do the right thing.
 
 Unlike some other "ToAscii" implementations, this one works on full domain
 names and should never fail - if it cannot convert the name, then it will
 return it unchanged.
 
 This function is an amalgam of IDNA2003, UTS#46 and IDNA2008 - it tries to
 be reasonably compatible to other implementations, reasonably secure, as
 much as IDNs can be secure, and reasonably efficient when confronted with
 IDNs that are already valid DNS names.
 
 =cut
 
 sub idn_to_ascii($) {
    return $_[0]
       unless $_[0] =~ /[^\x00-\x7f]/;
 
    my @output;
 
    eval {
       # punycode by label
       for (split /\./, (idn_nameprep $_[0]), -1) {
          if (/[^\x00-\x7f]/) {
             eval {
                push @output, "xn--" . punycode_encode $_;
                1;
             } or do {
                push @output, $_;
             };
          } else {
             push @output, $_;
          }
       }
 
       1
    } or return $_[0];
 
    shift @output
       while !length $output[0] && @output > 1;
 
    join ".", @output
 }
 
 =item $idn = AnyEvent::Util::idn_to_unicode $idn
 
 Converts the given unicode string (C<$idn>, international domain name,
 e.g. 日本語。ＪＰ, www.deliantra.net, www.xn--l-0ga.de) to
 unicode form (this is usually called the "IDN ToUnicode" transform). This
 transformation is idempotent, which means you can call it just in case and
 it will do the right thing.
 
 Unlike some other "ToUnicode" implementations, this one works on full
 domain names and should never fail - if it cannot convert the name, then
 it will return it unchanged.
 
 This function is an amalgam of IDNA2003, UTS#46 and IDNA2008 - it tries to
 be reasonably compatible to other implementations, reasonably secure, as
 much as IDNs can be secure, and reasonably efficient when confronted with
 IDNs that are already valid DNS names.
 
 At the moment, this function simply calls C<idn_nameprep $idn, 1>,
 returning its argument when that function fails.
 
 =cut
 
 sub idn_to_unicode($) {
    my $res = eval { idn_nameprep $_[0], 1 };
    defined $res ? $res : $_[0]
 }
 
 =back
 
 =head1 AUTHOR
 
  Marc Lehmann <schmorp@schmorp.de>
  http://anyevent.schmorp.de
 
 =cut
 
 1
 
### B/Hooks/EndOfScope.pm ###
 package B::Hooks::EndOfScope; # git description: 0.14-19-g9296689
 # ABSTRACT: Execute code after a scope finished compilation
 # KEYWORDS: code hooks execution scope
 
 use strict;
 use warnings;
 
 our $VERSION = '0.15';
 
 # note - a %^H tie() fallback will probably work on 5.6 as well,
 # if you need to go that low - sane patches passing *all* tests
 # will be gladly accepted
 use 5.008001;
 
 BEGIN {
   use Module::Implementation 0.05;
   Module::Implementation::build_loader_sub(
     implementations => [ 'XS', 'PP' ],
     symbols => [ 'on_scope_end' ],
   )->();
 }
 
 use Sub::Exporter::Progressive 0.001006 -setup => {
   exports => [ 'on_scope_end' ],
   groups  => { default => ['on_scope_end'] },
 };
 
 #pod =head1 SYNOPSIS
 #pod
 #pod     on_scope_end { ... };
 #pod
 #pod =head1 DESCRIPTION
 #pod
 #pod This module allows you to execute code when perl finished compiling the
 #pod surrounding scope.
 #pod
 #pod =func on_scope_end
 #pod
 #pod     on_scope_end { ... };
 #pod
 #pod     on_scope_end $code;
 #pod
 #pod Registers C<$code> to be executed after the surrounding scope has been
 #pod compiled.
 #pod
 #pod This is exported by default. See L<Sub::Exporter> on how to customize it.
 #pod
 #pod =head1 PURE-PERL MODE CAVEAT
 #pod
 #pod While L<Variable::Magic> has access to some very dark sorcery to make it
 #pod possible to throw an exception from within a callback, the pure-perl
 #pod implementation does not have access to these hacks. Therefore, what
 #pod would have been a compile-time exception is instead converted to a
 #pod warning, and your execution will continue as if the exception never
 #pod happened.
 #pod
 #pod To explicitly request an XS (or PP) implementation one has two choices. Either
 #pod to import from the desired implementation explicitly:
 #pod
 #pod  use B::Hooks::EndOfScope::XS
 #pod    or
 #pod  use B::Hooks::EndOfScope::PP
 #pod
 #pod or by setting C<$ENV{B_HOOKS_ENDOFSCOPE_IMPLEMENTATION}> to either C<XS> or
 #pod C<PP>.
 #pod
 #pod =head1 SEE ALSO
 #pod
 #pod L<Sub::Exporter>
 #pod
 #pod L<Variable::Magic>
 #pod
 #pod =cut
 
 1;
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 B::Hooks::EndOfScope - Execute code after a scope finished compilation
 
 =head1 VERSION
 
 version 0.15
 
 =head1 SYNOPSIS
 
     on_scope_end { ... };
 
 =head1 DESCRIPTION
 
 This module allows you to execute code when perl finished compiling the
 surrounding scope.
 
 =head1 FUNCTIONS
 
 =head2 on_scope_end
 
     on_scope_end { ... };
 
     on_scope_end $code;
 
 Registers C<$code> to be executed after the surrounding scope has been
 compiled.
 
 This is exported by default. See L<Sub::Exporter> on how to customize it.
 
 =head1 PURE-PERL MODE CAVEAT
 
 While L<Variable::Magic> has access to some very dark sorcery to make it
 possible to throw an exception from within a callback, the pure-perl
 implementation does not have access to these hacks. Therefore, what
 would have been a compile-time exception is instead converted to a
 warning, and your execution will continue as if the exception never
 happened.
 
 To explicitly request an XS (or PP) implementation one has two choices. Either
 to import from the desired implementation explicitly:
 
  use B::Hooks::EndOfScope::XS
    or
  use B::Hooks::EndOfScope::PP
 
 or by setting C<$ENV{B_HOOKS_ENDOFSCOPE_IMPLEMENTATION}> to either C<XS> or
 C<PP>.
 
 =head1 SEE ALSO
 
 L<Sub::Exporter>
 
 L<Variable::Magic>
 
 =head1 AUTHORS
 
 =over 4
 
 =item *
 
 Florian Ragwitz <rafl@debian.org>
 
 =item *
 
 Peter Rabbitson <ribasushi@cpan.org>
 
 =back
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2008 by Florian Ragwitz.
 
 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 Karen Etheridge Simon Wilper Tatsuhiko Miyagawa Tomas Doran
 
 =over 4
 
 =item *
 
 Karen Etheridge <ether@cpan.org>
 
 =item *
 
 Simon Wilper <sxw@chronowerks.de>
 
 =item *
 
 Tatsuhiko Miyagawa <miyagawa@bulknews.net>
 
 =item *
 
 Tomas Doran <bobtfish@bobtfish.net>
 
 =back
 
 =cut
### B/Hooks/EndOfScope/PP.pm ###
 package B::Hooks::EndOfScope::PP;
 # ABSTRACT: Execute code after a scope finished compilation - PP implementation
 
 use warnings;
 use strict;
 
 our $VERSION = '0.15';
 
 use constant _PERL_VERSION => "$]";
 
 BEGIN {
   if (_PERL_VERSION =~ /^5\.009/) {
     # CBA to figure out where %^H got broken and which H::U::HH is sane enough
     die "By design B::Hooks::EndOfScope does not operate in pure-perl mode on perl 5.9.X\n"
   }
   elsif (_PERL_VERSION < '5.010') {
     require B::Hooks::EndOfScope::PP::HintHash;
     *on_scope_end = \&B::Hooks::EndOfScope::PP::HintHash::on_scope_end;
   }
   else {
     require B::Hooks::EndOfScope::PP::FieldHash;
     *on_scope_end = \&B::Hooks::EndOfScope::PP::FieldHash::on_scope_end;
   }
 }
 
 use Sub::Exporter::Progressive 0.001006 -setup => {
   exports => ['on_scope_end'],
   groups  => { default => ['on_scope_end'] },
 };
 
 sub __invoke_callback {
   local $@;
   eval { $_[0]->(); 1 } or do {
     my $err = $@;
     require Carp;
     Carp::cluck( (join ' ',
       'A scope-end callback raised an exception, which can not be propagated when',
       'B::Hooks::EndOfScope operates in pure-perl mode. Your program will CONTINUE',
       'EXECUTION AS IF NOTHING HAPPENED AFTER THIS WARNING. Below is the complete',
       'exception text, followed by a stack-trace of the callback execution:',
     ) . "\n\n$err\n\r" );
 
     sleep 1 if -t *STDERR;  # maybe a bad idea...?
   };
 }
 
 #pod =head1 DESCRIPTION
 #pod
 #pod This is the pure-perl implementation of L<B::Hooks::EndOfScope> based only on
 #pod modules available as part of the perl core. Its leaner sibling
 #pod L<B::Hooks::EndOfScope::XS> will be automatically preferred if all
 #pod dependencies are available and C<$ENV{B_HOOKS_ENDOFSCOPE_IMPLEMENTATION}> is
 #pod not set to C<'PP'>.
 #pod
 #pod =func on_scope_end
 #pod
 #pod     on_scope_end { ... };
 #pod
 #pod     on_scope_end $code;
 #pod
 #pod Registers C<$code> to be executed after the surrounding scope has been
 #pod compiled.
 #pod
 #pod This is exported by default. See L<Sub::Exporter> on how to customize it.
 #pod
 #pod =cut
 
 1;
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 B::Hooks::EndOfScope::PP - Execute code after a scope finished compilation - PP implementation
 
 =head1 VERSION
 
 version 0.15
 
 =head1 DESCRIPTION
 
 This is the pure-perl implementation of L<B::Hooks::EndOfScope> based only on
 modules available as part of the perl core. Its leaner sibling
 L<B::Hooks::EndOfScope::XS> will be automatically preferred if all
 dependencies are available and C<$ENV{B_HOOKS_ENDOFSCOPE_IMPLEMENTATION}> is
 not set to C<'PP'>.
 
 =head1 FUNCTIONS
 
 =head2 on_scope_end
 
     on_scope_end { ... };
 
     on_scope_end $code;
 
 Registers C<$code> to be executed after the surrounding scope has been
 compiled.
 
 This is exported by default. See L<Sub::Exporter> on how to customize it.
 
 =head1 AUTHORS
 
 =over 4
 
 =item *
 
 Florian Ragwitz <rafl@debian.org>
 
 =item *
 
 Peter Rabbitson <ribasushi@cpan.org>
 
 =back
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2008 by Florian Ragwitz.
 
 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
### B/Hooks/EndOfScope/XS.pm ###
 package B::Hooks::EndOfScope::XS;
 # ABSTRACT: Execute code after a scope finished compilation - XS implementation
 
 use strict;
 use warnings;
 
 our $VERSION = '0.15';
 
 use Variable::Magic 0.48 ();
 use Sub::Exporter::Progressive 0.001006 -setup => {
   exports => ['on_scope_end'],
   groups  => { default => ['on_scope_end'] },
 };
 
 my $wiz = Variable::Magic::wizard
   data => sub { [$_[1]] },
   free => sub { $_->() for @{ $_[1] }; () },
   # When someone localise %^H, our magic doesn't want to be copied
   # down. We want it to be around only for the scope we've initially
   # attached ourselfs to. Merely having MGf_LOCAL and a noop svt_local
   # callback achieves this. If anything wants to attach more magic of our
   # kind to a localised %^H, things will continue to just work as we'll be
   # attached with a new and empty callback list.
   local => \undef
 ;
 
 sub on_scope_end (&) {
   my $cb = shift;
 
   $^H |= 0x020000;
 
   if (my $stack = Variable::Magic::getdata %^H, $wiz) {
     push @{ $stack }, $cb;
   }
   else {
     Variable::Magic::cast %^H, $wiz, $cb;
   }
 }
 
 
 #pod =head1 DESCRIPTION
 #pod
 #pod This is the implementation of L<B::Hooks::EndOfScope> based on
 #pod L<Variable::Magic>, which is an XS module dependent on a compiler. It will
 #pod always be automatically preferred if L<Variable::Magic> is available.
 #pod
 #pod =func on_scope_end
 #pod
 #pod     on_scope_end { ... };
 #pod
 #pod     on_scope_end $code;
 #pod
 #pod Registers C<$code> to be executed after the surrounding scope has been
 #pod compiled.
 #pod
 #pod This is exported by default. See L<Sub::Exporter> on how to customize it.
 #pod
 #pod =cut
 
 1;
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 B::Hooks::EndOfScope::XS - Execute code after a scope finished compilation - XS implementation
 
 =head1 VERSION
 
 version 0.15
 
 =head1 DESCRIPTION
 
 This is the implementation of L<B::Hooks::EndOfScope> based on
 L<Variable::Magic>, which is an XS module dependent on a compiler. It will
 always be automatically preferred if L<Variable::Magic> is available.
 
 =head1 FUNCTIONS
 
 =head2 on_scope_end
 
     on_scope_end { ... };
 
     on_scope_end $code;
 
 Registers C<$code> to be executed after the surrounding scope has been
 compiled.
 
 This is exported by default. See L<Sub::Exporter> on how to customize it.
 
 =head1 AUTHORS
 
 =over 4
 
 =item *
 
 Florian Ragwitz <rafl@debian.org>
 
 =item *
 
 Peter Rabbitson <ribasushi@cpan.org>
 
 =back
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2008 by Florian Ragwitz.
 
 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
### Border/Style.pm ###
 package Border::Style;
 
 our $DATE = '2014-12-10'; # DATE
 our $VERSION = '0.01'; # VERSION
 
 1;
 # ABSTRACT: Border style structure
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Border::Style - Border style structure
 
 =head1 VERSION
 
 This document describes version 0.01 of Border::Style (from Perl distribution Border-Style), released on 2014-12-10.
 
 =head1 DESCRIPTION
 
 This module specifies a structure for border styles. The distribution also comes
 with utility routines and roles for managing border styles in applications.
 
 =head1 SPECIFICATION
 
 Border style is a L<DefHash> containing these keys: C<v>, C<name>, C<summary>,
 C<utf8> (bool, set to true to indicate that characters are Unicode characters in
 UTF8), C<chars> (array). Format for the characters in C<chars>:
 
  [
    [A, b, C, D],  # 0
    [E, F, G],     # 1
    [H, i, J, K],  # 2
    [L, M, N],     # 3
    [O, p, Q, R],  # 4
    [S, t, U, V],  # 5
  ]
 
  AbbbCbbbD        #0 Top border characters
  E   F   G        #1 Vertical separators for header row
  HiiiJiiiK        #2 Separator between header row and first data row
  L   M   N        #3 Vertical separators for data row
  OpppQpppR        #4 Separator between data rows
  L   M   N        #3
  StttUtttV        #5 Bottom border characters
 
 A character can also be a coderef that will be called with C<< ($self, %args)
 >>. Arguments in C<%args> contains information such as C<name>, C<y>, C<x>, C<n>
 (how many times should character be repeated), etc.
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Border-Style>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Border-Style>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Border-Style>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2014 by perlancar@cpan.org.
 
 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
### Border/Style/Role.pm ###
 package Border::Style::Role;
 
 our $DATE = '2014-12-10'; # DATE
 our $VERSION = '0.01'; # VERSION
 
 # currently this is still very Text::ANSITable-ish.
 
 use 5.010001;
 use Moo::Role;
 
 with 'Term::App::Role::Attrs';
 
 has border_style_args  => (is => 'rw', default => sub { {} });
 has _all_border_styles => (is => 'rw');
 
 sub get_border_char {
     my ($self, $y, $x, $n, $args) = @_;
     my $bch = $self->{border_style}{chars};
     $n //= 1;
     if (ref($bch) eq 'CODE') {
         $bch->($self, y=>$y, x=>$x, n=>$n, %{$args // {}});
     } else {
         $bch->[$y][$x] x $n;
     }
 }
 
 sub border_style {
     my $self = shift;
 
     if (!@_) { return $self->{border_style} }
     my $bs = shift;
 
     my $p2 = "";
     if (!ref($bs)) {
         $p2 = " named $bs";
         $bs = $self->get_border_style($bs);
     }
 
     my $err;
     if ($bs->{box_chars} && !$self->use_box_chars) {
         $err = "use_box_chars is set to false";
     } elsif ($bs->{utf8} && !$self->use_utf8) {
         $err = "use_utf8 is set to false";
     }
     die "Can't select border style$p2: $err" if $err;
 
     $self->{border_style} = $bs;
 }
 
 sub get_border_style {
     my ($self, $bs) = @_;
 
     my $prefix = (ref($self) ? ref($self) : $self ) .
         '::BorderStyle'; # XXX allow override
 
     my $bss;
     my $pkg;
     if ($bs =~ s/(.+):://) {
         $pkg = "$prefix\::$1";
         my $pkgp = $pkg; $pkgp =~ s!::!/!g;
         require "$pkgp.pm";
         no strict 'refs';
         $bss = \%{"$pkg\::border_styles"};
     } else {
         #$bss = $self->list_border_styles(1);
         die "Please use SubPackage::name to choose border style, ".
             "use list_border_styles() to list available styles";
     }
     $bss->{$bs} or die "Unknown border style name '$bs'".
         ($pkg ? " in package $prefix\::$pkg" : "");
     $bss->{$bs};
 }
 
 sub list_border_styles {
     require Module::List;
     require Module::Load;
 
     my ($self, $detail) = @_;
 
     my $prefix = (ref($self) ? ref($self) : $self ) .
         '::BorderStyle'; # XXX allow override
     my $all_bs = $self->_all_border_styles;
 
     if (!$all_bs) {
         my $mods = Module::List::list_modules("$prefix\::",
                                               {list_modules=>1, recurse=>1});
         no strict 'refs';
         $all_bs = {};
         for my $mod (sort keys %$mods) {
             #$log->tracef("Loading border style module '%s' ...", $mod);
             Module::Load::load($mod);
             my $bs = \%{"$mod\::border_styles"};
             for (keys %$bs) {
                 my $cutmod = $mod;
                 $cutmod =~ s/^\Q$prefix\E:://;
                 my $name = "$cutmod\::$_";
                 $bs->{$_}{name} = $name;
                 $all_bs->{$name} = $bs->{$_};
             }
         }
         $self->_all_border_styles($all_bs);
     }
 
     if ($detail) {
         return $all_bs;
     } else {
         return sort keys %$all_bs;
     }
 }
 
 1;
 # ABSTRACT: Role for class wanting to support border styles
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Border::Style::Role - Role for class wanting to support border styles
 
 =head1 VERSION
 
 This document describes version 0.01 of Border::Style::Role (from Perl distribution Border-Style), released on 2014-12-10.
 
 =head1 DESCRIPTION
 
 =head1 ATTRIBUTES
 
 =head2 border_style => HASH
 
 =head2 border_style_args => HASH
 
 =head1 METHODS
 
 =head2 $cl->list_border_styles($detail) => ARRAY
 
 =head2 $cl->get_border_style($name) => HASH
 
 =head2 $cl->get_border_char($y, $x, $repeat, \%args) => STR
 
 Pick border character from border style (and optionally repeat it C<$repeat>
 times). C<\%args> is a hashref to be supplied to the coderef if the 'chars'
 value from the style is a coderef.
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Border-Style>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Border-Style>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Border-Style>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2014 by perlancar@cpan.org.
 
 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
### Class/Inspector.pm ###
 package Class::Inspector;
 
 =pod
 
 =head1 NAME
 
 Class::Inspector - Get information about a class and its structure
 
 =head1 SYNOPSIS
 
   use Class::Inspector;
   
   # Is a class installed and/or loaded
   Class::Inspector->installed( 'Foo::Class' );
   Class::Inspector->loaded( 'Foo::Class' );
   
   # Filename related information
   Class::Inspector->filename( 'Foo::Class' );
   Class::Inspector->resolved_filename( 'Foo::Class' );
   
   # Get subroutine related information
   Class::Inspector->functions( 'Foo::Class' );
   Class::Inspector->function_refs( 'Foo::Class' );
   Class::Inspector->function_exists( 'Foo::Class', 'bar' );
   Class::Inspector->methods( 'Foo::Class', 'full', 'public' );
   
   # Find all loaded subclasses or something
   Class::Inspector->subclasses( 'Foo::Class' );
 
 =head1 DESCRIPTION
 
 Class::Inspector allows you to get information about a loaded class. Most or
 all of this information can be found in other ways, but they aren't always
 very friendly, and usually involve a relatively high level of Perl wizardry,
 or strange and unusual looking code. Class::Inspector attempts to provide 
 an easier, more friendly interface to this information.
 
 =head1 METHODS
 
 =cut
 
 use 5.006;
 # We don't want to use strict refs anywhere in this module, since we do a
 # lot of things in here that aren't strict refs friendly.
 use strict qw{vars subs};
 use warnings;
 use File::Spec ();
 
 # Globals
 use vars qw{$VERSION $RE_IDENTIFIER $RE_CLASS $UNIX};
 BEGIN {
 	$VERSION = '1.28';
 
 	# If Unicode is available, enable it so that the
 	# pattern matches below match unicode method names.
 	# We can safely ignore any failure here.
 	SCOPE: {
 		local $@;
 		eval "require utf8; utf8->import";
 	}
 
 	# Predefine some regexs
 	$RE_IDENTIFIER = qr/\A[^\W\d]\w*\z/s;
 	$RE_CLASS      = qr/\A[^\W\d]\w*(?:(?:\'|::)\w+)*\z/s;
 
 	# Are we on something Unix-like?
 	$UNIX  = !! ( $File::Spec::ISA[0] eq 'File::Spec::Unix'  );
 }
 
 
 
 
 
 #####################################################################
 # Basic Methods
 
 =pod
 
 =head2 installed $class
 
 The C<installed> static method tries to determine if a class is installed
 on the machine, or at least available to Perl. It does this by wrapping
 around C<resolved_filename>.
 
 Returns true if installed/available, false if the class is not installed,
 or C<undef> if the class name is invalid.
 
 =cut
 
 sub installed {
 	my $class = shift;
 	!! ($class->loaded_filename($_[0]) or $class->resolved_filename($_[0]));
 }
 
 =pod
 
 =head2 loaded $class
 
 The C<loaded> static method tries to determine if a class is loaded by
 looking for symbol table entries.
 
 This method it uses to determine this will work even if the class does not
 have its own file, but is contained inside a single file with multiple
 classes in it. Even in the case of some sort of run-time loading class
 being used, these typically leave some trace in the symbol table, so an
 L<Autoload> or L<Class::Autouse>-based class should correctly appear
 loaded.
 
 Returns true if the class is loaded, false if not, or C<undef> if the
 class name is invalid.
 
 =cut
 
 sub loaded {
 	my $class = shift;
 	my $name  = $class->_class(shift) or return undef;
 	$class->_loaded($name);
 }
 
 sub _loaded {
 	my $class = shift;
 	my $name  = shift;
 
 	# Handle by far the two most common cases
 	# This is very fast and handles 99% of cases.
 	return 1 if defined ${"${name}::VERSION"};
 	return 1 if @{"${name}::ISA"};
 
 	# Are there any symbol table entries other than other namespaces
 	foreach ( keys %{"${name}::"} ) {
 		next if substr($_, -2, 2) eq '::';
 		return 1 if defined &{"${name}::$_"};
 	}
 
 	# No functions, and it doesn't have a version, and isn't anything.
 	# As an absolute last resort, check for an entry in %INC
 	my $filename = $class->_inc_filename($name);
 	return 1 if defined $INC{$filename};
 
 	'';
 }
 
 =pod
 
 =head2 filename $class
 
 For a given class, returns the base filename for the class. This will NOT
 be a fully resolved filename, just the part of the filename BELOW the
 C<@INC> entry.
 
   print Class->filename( 'Foo::Bar' );
   > Foo/Bar.pm
 
 This filename will be returned with the right seperator for the local
 platform, and should work on all platforms.
 
 Returns the filename on success or C<undef> if the class name is invalid.
 
 =cut
 
 sub filename {
 	my $class = shift;
 	my $name  = $class->_class(shift) or return undef;
 	File::Spec->catfile( split /(?:\'|::)/, $name ) . '.pm';
 }
 
 =pod
 
 =head2 resolved_filename $class, @try_first
 
 For a given class, the C<resolved_filename> static method returns the fully
 resolved filename for a class. That is, the file that the class would be
 loaded from.
 
 This is not nescesarily the file that the class WAS loaded from, as the
 value returned is determined each time it runs, and the C<@INC> include
 path may change.
 
 To get the actual file for a loaded class, see the C<loaded_filename>
 method.
 
 Returns the filename for the class, or C<undef> if the class name is
 invalid.
 
 =cut
 
 sub resolved_filename {
 	my $class     = shift;
 	my $filename  = $class->_inc_filename(shift) or return undef;
 	my @try_first = @_;
 
 	# Look through the @INC path to find the file
 	foreach ( @try_first, @INC ) {
 		my $full = "$_/$filename";
 		next unless -e $full;
 		return $UNIX ? $full : $class->_inc_to_local($full);
 	}
 
 	# File not found
 	'';
 }
 
 =pod
 
 =head2 loaded_filename $class
 
 For a given loaded class, the C<loaded_filename> static method determines
 (via the C<%INC> hash) the name of the file that it was originally loaded
 from.
 
 Returns a resolved file path, or false if the class did not have it's own
 file.
 
 =cut
 
 sub loaded_filename {
 	my $class    = shift;
 	my $filename = $class->_inc_filename(shift);
 	$UNIX ? $INC{$filename} : $class->_inc_to_local($INC{$filename});
 }
 
 
 
 
 
 #####################################################################
 # Sub Related Methods
 
 =pod
 
 =head2 functions $class
 
 For a loaded class, the C<functions> static method returns a list of the
 names of all the functions in the classes immediate namespace.
 
 Note that this is not the METHODS of the class, just the functions.
 
 Returns a reference to an array of the function names on success, or C<undef>
 if the class name is invalid or the class is not loaded.
 
 =cut
 
 sub functions {
 	my $class = shift;
 	my $name  = $class->_class(shift) or return undef;
 	return undef unless $class->loaded( $name );
 
 	# Get all the CODE symbol table entries
 	my @functions = sort grep { /$RE_IDENTIFIER/o }
 		grep { defined &{"${name}::$_"} }
 		keys %{"${name}::"};
 	\@functions;
 }
 
 =pod
 
 =head2 function_refs $class
 
 For a loaded class, the C<function_refs> static method returns references to
 all the functions in the classes immediate namespace.
 
 Note that this is not the METHODS of the class, just the functions.
 
 Returns a reference to an array of C<CODE> refs of the functions on
 success, or C<undef> if the class is not loaded.
 
 =cut
 
 sub function_refs {
 	my $class = shift;
 	my $name  = $class->_class(shift) or return undef;
 	return undef unless $class->loaded( $name );
 
 	# Get all the CODE symbol table entries, but return
 	# the actual CODE refs this time.
 	my @functions = map { \&{"${name}::$_"} }
 		sort grep { /$RE_IDENTIFIER/o }
 		grep { defined &{"${name}::$_"} }
 		keys %{"${name}::"};
 	\@functions;
 }
 
 =pod
 
 =head2 function_exists $class, $function
 
 Given a class and function name the C<function_exists> static method will
 check to see if the function exists in the class.
 
 Note that this is as a function, not as a method. To see if a method
 exists for a class, use the C<can> method for any class or object.
 
 Returns true if the function exists, false if not, or C<undef> if the
 class or function name are invalid, or the class is not loaded.
 
 =cut
 
 sub function_exists {
 	my $class    = shift;
 	my $name     = $class->_class( shift ) or return undef;
 	my $function = shift or return undef;
 
 	# Only works if the class is loaded
 	return undef unless $class->loaded( $name );
 
 	# Does the GLOB exist and its CODE part exist
 	defined &{"${name}::$function"};
 }
 
 =pod
 
 =head2 methods $class, @options
 
 For a given class name, the C<methods> static method will returns ALL
 the methods available to that class. This includes all methods available
 from every class up the class' C<@ISA> tree.
 
 Returns a reference to an array of the names of all the available methods
 on success, or C<undef> if the class name is invalid or the class is not
 loaded.
 
 A number of options are available to the C<methods> method that will alter
 the results returned. These should be listed after the class name, in any
 order.
 
   # Only get public methods
   my $method = Class::Inspector->methods( 'My::Class', 'public' );
 
 =over 4
 
 =item public
 
 The C<public> option will return only 'public' methods, as defined by the Perl
 convention of prepending an underscore to any 'private' methods. The C<public> 
 option will effectively remove any methods that start with an underscore.
 
 =item private
 
 The C<private> options will return only 'private' methods, as defined by the
 Perl convention of prepending an underscore to an private methods. The
 C<private> option will effectively remove an method that do not start with an
 underscore.
 
 B<Note: The C<public> and C<private> options are mutually exclusive>
 
 =item full
 
 C<methods> normally returns just the method name. Supplying the C<full> option
 will cause the methods to be returned as the full names. That is, instead of
 returning C<[ 'method1', 'method2', 'method3' ]>, you would instead get
 C<[ 'Class::method1', 'AnotherClass::method2', 'Class::method3' ]>.
 
 =item expanded
 
 The C<expanded> option will cause a lot more information about method to be 
 returned. Instead of just the method name, you will instead get an array
 reference containing the method name as a single combined name, ala C<full>,
 the seperate class and method, and a CODE ref to the actual function ( if
 available ). Please note that the function reference is not guarenteed to 
 be available. C<Class::Inspector> is intended at some later time, work 
 with modules that have some some of common run-time loader in place ( e.g
 C<Autoloader> or C<Class::Autouse> for example.
 
 The response from C<methods( 'Class', 'expanded' )> would look something like
 the following.
 
   [
     [ 'Class::method1',   'Class',   'method1', \&Class::method1   ],
     [ 'Another::method2', 'Another', 'method2', \&Another::method2 ],
     [ 'Foo::bar',         'Foo',     'bar',     \&Foo::bar         ],
   ]
 
 =back
 
 =cut
 
 sub methods {
 	my $class     = shift;
 	my $name      = $class->_class( shift ) or return undef;
 	my @arguments = map { lc $_ } @_;
 
 	# Process the arguments to determine the options
 	my %options = ();
 	foreach ( @arguments ) {
 		if ( $_ eq 'public' ) {
 			# Only get public methods
 			return undef if $options{private};
 			$options{public} = 1;
 
 		} elsif ( $_ eq 'private' ) {
 			# Only get private methods
 			return undef if $options{public};
 			$options{private} = 1;
 
 		} elsif ( $_ eq 'full' ) {
 			# Return the full method name
 			return undef if $options{expanded};
 			$options{full} = 1;
 
 		} elsif ( $_ eq 'expanded' ) {
 			# Returns class, method and function ref
 			return undef if $options{full};
 			$options{expanded} = 1;
 
 		} else {
 			# Unknown or unsupported options
 			return undef;
 		}
 	}
 
 	# Only works if the class is loaded
 	return undef unless $class->loaded( $name );
 
 	# Get the super path ( not including UNIVERSAL )
 	# Rather than using Class::ISA, we'll use an inlined version
 	# that implements the same basic algorithm.
 	my @path  = ();
 	my @queue = ( $name );
 	my %seen  = ( $name => 1 );
 	while ( my $cl = shift @queue ) {
 		push @path, $cl;
 		unshift @queue, grep { ! $seen{$_}++ }
 			map { s/^::/main::/; s/\'/::/g; $_ }
 			( @{"${cl}::ISA"} );
 	}
 
 	# Find and merge the function names across the entire super path.
 	# Sort alphabetically and return.
 	my %methods = ();
 	foreach my $namespace ( @path ) {
 		my @functions = grep { ! $methods{$_} }
 			grep { /$RE_IDENTIFIER/o }
 			grep { defined &{"${namespace}::$_"} } 
 			keys %{"${namespace}::"};
 		foreach ( @functions ) {
 			$methods{$_} = $namespace;
 		}
 	}
 
 	# Filter to public or private methods if needed
 	my @methodlist = sort keys %methods;
 	@methodlist = grep { ! /^\_/ } @methodlist if $options{public};
 	@methodlist = grep {   /^\_/ } @methodlist if $options{private};
 
 	# Return in the correct format
 	@methodlist = map { "$methods{$_}::$_" } @methodlist if $options{full};
 	@methodlist = map { 
 		[ "$methods{$_}::$_", $methods{$_}, $_, \&{"$methods{$_}::$_"} ] 
 		} @methodlist if $options{expanded};
 
 	\@methodlist;
 }
 
 
 
 
 
 #####################################################################
 # Search Methods
 
 =pod
 
 =head2 subclasses $class
 
 The C<subclasses> static method will search then entire namespace (and thus
 B<all> currently loaded classes) to find all classes that are subclasses
 of the class provided as a the parameter.
 
 The actual test will be done by calling C<isa> on the class as a static
 method. (i.e. C<My::Class-E<gt>isa($class)>.
 
 Returns a reference to a list of the loaded classes that match the class
 provided, or false is none match, or C<undef> if the class name provided
 is invalid.
 
 =cut
 
 sub subclasses {
 	my $class = shift;
 	my $name  = $class->_class( shift ) or return undef;
 
 	# Prepare the search queue
 	my @found = ();
 	my @queue = grep { $_ ne 'main' } $class->_subnames('');
 	while ( @queue ) {
 		my $c = shift(@queue); # c for class
 		if ( $class->_loaded($c) ) {
 			# At least one person has managed to misengineer
 			# a situation in which ->isa could die, even if the
 			# class is real. Trap these cases and just skip
 			# over that (bizarre) class. That would at limit
 			# problems with finding subclasses to only the
 			# modules that have broken ->isa implementation.
 			local $@;
 			eval {
 				if ( $c->isa($name) ) {
 					# Add to the found list, but don't add the class itself
 					push @found, $c unless $c eq $name;
 				}
 			};
 		}
 
 		# Add any child namespaces to the head of the queue.
 		# This keeps the queue length shorted, and allows us
 		# not to have to do another sort at the end.
 		unshift @queue, map { "${c}::$_" } $class->_subnames($c);
 	}
 
 	@found ? \@found : '';
 }
 
 sub _subnames {
 	my ($class, $name) = @_;
 	return sort
 		grep {
 			substr($_, -2, 2, '') eq '::'
 			and
 			/$RE_IDENTIFIER/o
 		}
 		keys %{"${name}::"};
 }
 
 
 
 
 
 #####################################################################
 # Children Related Methods
 
 # These can go undocumented for now, until I decide if its best to
 # just search the children in namespace only, or if I should do it via
 # the file system.
 
 # Find all the loaded classes below us
 sub children {
 	my $class = shift;
 	my $name  = $class->_class(shift) or return ();
 
 	# Find all the Foo:: elements in our symbol table
 	no strict 'refs';
 	map { "${name}::$_" } sort grep { s/::$// } keys %{"${name}::"};
 }
 
 # As above, but recursively
 sub recursive_children {
 	my $class    = shift;
 	my $name     = $class->_class(shift) or return ();
 	my @children = ( $name );
 
 	# Do the search using a nicer, more memory efficient 
 	# variant of actual recursion.
 	my $i = 0;
 	no strict 'refs';
 	while ( my $namespace = $children[$i++] ) {
 		push @children, map { "${namespace}::$_" }
 			grep { ! /^::/ } # Ignore things like ::ISA::CACHE::
 			grep { s/::$// }
 			keys %{"${namespace}::"};
 	}
 
 	sort @children;
 }
 
 
 
 
 
 #####################################################################
 # Private Methods
 
 # Checks and expands ( if needed ) a class name
 sub _class {
 	my $class = shift;
 	my $name  = shift or return '';
 
 	# Handle main shorthand
 	return 'main' if $name eq '::';
 	$name =~ s/\A::/main::/;
 
 	# Check the class name is valid
 	$name =~ /$RE_CLASS/o ? $name : '';
 }
 
 # Create a INC-specific filename, which always uses '/'
 # regardless of platform.
 sub _inc_filename {
 	my $class = shift;
 	my $name  = $class->_class(shift) or return undef;
 	join( '/', split /(?:\'|::)/, $name ) . '.pm';
 }
 
 # Convert INC-specific file name to local file name
 sub _inc_to_local {
 	# Shortcut in the Unix case
 	return $_[1] if $UNIX;
 
 	# On other places, we have to deal with an unusual path that might look
 	# like C:/foo/bar.pm which doesn't fit ANY normal pattern.
 	# Putting it through splitpath/dir and back again seems to normalise
 	# it to a reasonable amount.
 	my $class              = shift;
 	my $inc_name           = shift or return undef;
 	my ($vol, $dir, $file) = File::Spec->splitpath( $inc_name );
 	$dir = File::Spec->catdir( File::Spec->splitdir( $dir || "" ) );
 	File::Spec->catpath( $vol, $dir, $file || "" );
 }
 
 1;
 
 =pod
 
 =head1 SUPPORT
 
 Bugs should be reported via the CPAN bug tracker
 
 L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Class-Inspector>
 
 For other issues, or commercial enhancement or support, contact the author.
 
 =head1 AUTHOR
 
 Adam Kennedy E<lt>adamk@cpan.orgE<gt>
 
 =head1 SEE ALSO
 
 L<http://ali.as/>, L<Class::Handle>
 
 =head1 COPYRIGHT
 
 Copyright 2002 - 2012 Adam Kennedy.
 
 This program is free software; you can redistribute
 it and/or modify it under the same terms as Perl itself.
 
 The full text of the license can be found in the
 LICENSE file included with this module.
 
 =cut
### Class/Inspector/Functions.pm ###
 package Class::Inspector::Functions;
 
 use 5.006;
 use strict;
 use warnings;
 use Exporter         ();
 use Class::Inspector ();
 
 use vars qw(@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS $VERSION);
 BEGIN {
 	$VERSION = '1.28';
 	@ISA     = 'Exporter';
 
 
 	@EXPORT = qw(
 		installed
 		loaded
 
 		filename
 		functions
 		methods
 
 		subclasses
 	);
 
 	@EXPORT_OK = qw(
 		resolved_filename
 		loaded_filename
 
 		function_refs
 		function_exists
 	);
 		#children
 		#recursive_children
 
 	%EXPORT_TAGS = ( ALL => [ @EXPORT_OK, @EXPORT ] );
 
 	foreach my $meth (@EXPORT, @EXPORT_OK) {
 	    my $sub = Class::Inspector->can($meth);
 	    no strict 'refs';
 	    *{$meth} = sub {&$sub('Class::Inspector', @_)};
 	}
 
 }
 
 1;
 
 __END__
 
 =pod
 
 =head1 NAME
 
 Class::Inspector::Functions - Get information about a class and its structure
 
 =head1 SYNOPSIS
 
   use Class::Inspector::Functions;
   # Class::Inspector provides a non-polluting,
   # method based interface!
   
   # Is a class installed and/or loaded
   installed( 'Foo::Class' );
   loaded( 'Foo::Class' );
   
   # Filename related information
   filename( 'Foo::Class' );
   resolved_filename( 'Foo::Class' );
   
   # Get subroutine related information
   functions( 'Foo::Class' );
   function_refs( 'Foo::Class' );
   function_exists( 'Foo::Class', 'bar' );
   methods( 'Foo::Class', 'full', 'public' );
   
   # Find all loaded subclasses or something
   subclasses( 'Foo::Class' );
 
 =head1 DESCRIPTION
 
 Class::Inspector::Functions is a function based interface of
 L<Class::Inspector>. For a thorough documentation of the available
 functions, please check the manual for the main module.
 
 =head2 Exports
 
 The following functions are exported by default.
 
   installed
   loaded
   filename
   functions
   methods
   subclasses
 
 The following functions are exported only by request.
 
   resolved_filename
   loaded_filename
   function_refs
   function_exists
 
 All the functions may be imported using the C<:ALL> tag.
 
 =head1 SUPPORT
 
 Bugs should be reported via the CPAN bug tracker
 
 L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Class-Inspector>
 
 For other issues, or commercial enhancement or support, contact the author.
 
 =head1 AUTHOR
 
 Adam Kennedy E<lt>adamk@cpan.orgE<gt>
 
 Steffen Mueller E<lt>smueller@cpan.orgE<gt>
 
 =head1 SEE ALSO
 
 L<http://ali.as/>, L<Class::Handle>
 
 =head1 COPYRIGHT
 
 Copyright 2002 - 2012 Adam Kennedy.
 
 Class::Inspector::Functions copyright 2008 - 2009 Steffen Mueller.
 
 This program is free software; you can redistribute
 it and/or modify it under the same terms as Perl itself.
 
 The full text of the license can be found in the
 LICENSE file included with this module.
 
 =cut
### Class/Method/Modifiers.pm ###
 use strict;
 use warnings;
 package Class::Method::Modifiers;
 BEGIN {
   $Class::Method::Modifiers::AUTHORITY = 'cpan:SARTAK';
 }
 # git description: v2.10-10-gcae27a4
 $Class::Method::Modifiers::VERSION = '2.11';
 # ABSTRACT: Provides Moose-like method modifiers
 # KEYWORDS: method wrap modification patch
 # vim: set ts=8 sw=4 tw=78 et :
 
 # work around https://rt.cpan.org/Ticket/Display.html?id=89173
 use base 'Exporter';
 
 our @EXPORT = qw(before after around);
 our @EXPORT_OK = (@EXPORT, qw(fresh install_modifier));
 our %EXPORT_TAGS = (
     moose => [qw(before after around)],
     all   => \@EXPORT_OK,
 );
 
 BEGIN {
   *_HAS_READONLY = $] >= 5.008 ? sub(){1} : sub(){0};
 }
 
 our %MODIFIER_CACHE;
 
 # for backward compatibility
 sub _install_modifier; # -w
 *_install_modifier = \&install_modifier;
 
 sub install_modifier {
     my $into  = shift;
     my $type  = shift;
     my $code  = pop;
     my @names = @_;
 
     @names = @{ $names[0] } if ref($names[0]) eq 'ARRAY';
 
     return _fresh($into, $code, @names) if $type eq 'fresh';
 
     for my $name (@names) {
         my $hit = $into->can($name) or do {
             require Carp;
             Carp::confess("The method '$name' is not found in the inheritance hierarchy for class $into");
         };
 
         my $qualified = $into.'::'.$name;
         my $cache = $MODIFIER_CACHE{$into}{$name} ||= {
             before => [],
             after  => [],
             around => [],
         };
 
         # this must be the first modifier we're installing
         if (!exists($cache->{"orig"})) {
             no strict 'refs';
 
             # grab the original method (or undef if the method is inherited)
             $cache->{"orig"} = *{$qualified}{CODE};
 
             # the "innermost" method, the one that "around" will ultimately wrap
             $cache->{"wrapped"} = $cache->{"orig"} || $hit; #sub {
             #    # we can't cache this, because new methods or modifiers may be
             #    # added between now and when this method is called
             #    for my $package (@{ mro::get_linear_isa($into) }) {
             #        next if $package eq $into;
             #        my $code = *{$package.'::'.$name}{CODE};
             #        goto $code if $code;
             #    }
             #    require Carp;
             #    Carp::confess("$qualified\::$name disappeared?");
             #};
         }
 
         # keep these lists in the order the modifiers are called
         if ($type eq 'after') {
             push @{ $cache->{$type} }, $code;
         }
         else {
             unshift @{ $cache->{$type} }, $code;
         }
 
         # wrap the method with another layer of around. much simpler than
         # the Moose equivalent. :)
         if ($type eq 'around') {
             my $method = $cache->{wrapped};
             my $attrs = _sub_attrs($code);
             # a bare "sub :lvalue {...}" will be parsed as a label and an
             # indirect method call. force it to be treated as an expression
             # using +
             $cache->{wrapped} = eval "package $into; +sub $attrs { \$code->(\$method, \@_); };";
         }
 
         # install our new method which dispatches the modifiers, but only
         # if a new type was added
         if (@{ $cache->{$type} } == 1) {
 
             # avoid these hash lookups every method invocation
             my $before  = $cache->{"before"};
             my $after   = $cache->{"after"};
 
             # this is a coderef that changes every new "around". so we need
             # to take a reference to it. better a deref than a hash lookup
             my $wrapped = \$cache->{"wrapped"};
 
             my $attrs = _sub_attrs($cache->{wrapped});
 
             my $generated = "package $into;\n";
             $generated .= "sub $name $attrs {";
 
             # before is easy, it doesn't affect the return value(s)
             if (@$before) {
                 $generated .= '
                     for my $method (@$before) {
                         $method->(@_);
                     }
                 ';
             }
 
             if (@$after) {
                 $generated .= '
                     my $ret;
                     if (wantarray) {
                         $ret = [$$wrapped->(@_)];
                         '.(_HAS_READONLY ? 'Internals::SvREADONLY(@$ret, 1);' : '').'
                     }
                     elsif (defined wantarray) {
                         $ret = \($$wrapped->(@_));
                     }
                     else {
                         $$wrapped->(@_);
                     }
 
                     for my $method (@$after) {
                         $method->(@_);
                     }
 
                     wantarray ? @$ret : $ret ? $$ret : ();
                 '
             }
             else {
                 $generated .= '$$wrapped->(@_);';
             }
 
             $generated .= '}';
 
             no strict 'refs';
             no warnings 'redefine';
             no warnings 'closure';
             eval $generated;
         };
     }
 }
 
 sub before {
     _install_modifier(scalar(caller), 'before', @_);
 }
 
 sub after {
     _install_modifier(scalar(caller), 'after', @_);
 }
 
 sub around {
     _install_modifier(scalar(caller), 'around', @_);
 }
 
 sub fresh {
     my $code = pop;
     my @names = @_;
 
     @names = @{ $names[0] } if ref($names[0]) eq 'ARRAY';
 
     _fresh(scalar(caller), $code, @names);
 }
 
 sub _fresh {
     my ($into, $code, @names) = @_;
 
     for my $name (@names) {
         if ($name !~ /\A [a-zA-Z_] [a-zA-Z0-9_]* \z/xms) {
             require Carp;
             Carp::confess("Invalid method name '$name'");
         }
         if ($into->can($name)) {
             require Carp;
             Carp::confess("Class $into already has a method named '$name'");
         }
 
         # We need to make sure that the installed method has its CvNAME in
         # the appropriate package; otherwise, it would be subject to
         # deletion if callers use namespace::autoclean.  If $code was
         # compiled in the target package, we can just install it directly;
         # otherwise, we'll need a different approach.  Using Sub::Name would
         # be fine in all cases, at the cost of introducing a dependency on
         # an XS-using, non-core module.  So instead we'll use string-eval to
         # create a new subroutine that wraps $code.
         if (_is_in_package($code, $into)) {
             no strict 'refs';
             *{"$into\::$name"} = $code;
         }
         else {
             no warnings 'closure'; # for 5.8.x
             my $attrs = _sub_attrs($code);
             eval "package $into; sub $name $attrs { \$code->(\@_) }";
         }
     }
 }
 
 sub _sub_attrs {
     my ($coderef) = @_;
     local *_sub = $coderef;
     local $@;
     (eval 'sub { _sub = 1 }') ? ':lvalue' : '';
 }
 
 sub _is_in_package {
     my ($coderef, $package) = @_;
     require B;
     my $cv = B::svref_2object($coderef);
     return $cv->GV->STASH->NAME eq $package;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Class::Method::Modifiers - provides Moose-like method modifiers
 
 =head1 VERSION
 
 version 2.11
 
 =head1 SYNOPSIS
 
     package Child;
     use parent 'Parent';
     use Class::Method::Modifiers;
 
     sub new_method { }
 
     before 'old_method' => sub {
         carp "old_method is deprecated, use new_method";
     };
 
     around 'other_method' => sub {
         my $orig = shift;
         my $ret = $orig->(@_);
         return $ret =~ /\d/ ? $ret : lc $ret;
     };
 
     after 'private', 'protected' => sub {
         debug "finished calling a dangerous method";
     };
 
     use Class::Method::Modifiers qw(fresh);
 
     fresh 'not_in_hierarchy' => sub {
         warn "freshly added method\n";
     };
 
 
 =head1 DESCRIPTION
 
 =for stopwords CLOS
 
 Method modifiers are a convenient feature from the CLOS (Common Lisp Object
 System) world.
 
 In its most basic form, a method modifier is just a method that calls
 C<< $self->SUPER::foo(@_) >>. I for one have trouble remembering that exact
 invocation, so my classes seldom re-dispatch to their base classes. Very bad!
 
 C<Class::Method::Modifiers> provides three modifiers: C<before>, C<around>, and
 C<after>. C<before> and C<after> are run just before and after the method they
 modify, but can not really affect that original method. C<around> is run in
 place of the original method, with a hook to easily call that original method.
 See the C<MODIFIERS> section for more details on how the particular modifiers
 work.
 
 One clear benefit of using C<Class::Method::Modifiers> is that you can define
 multiple modifiers in a single namespace. These separate modifiers don't need
 to know about each other. This makes top-down design easy. Have a base class
 that provides the skeleton methods of each operation, and have plugins modify
 those methods to flesh out the specifics.
 
 Parent classes need not know about C<Class::Method::Modifiers>. This means you
 should be able to modify methods in I<any> subclass. See
 L<Term::VT102::ZeroBased> for an example of subclassing with
 C<ClasS::Method::Modifiers>.
 
 In short, C<Class::Method::Modifiers> solves the problem of making sure you
 call C<< $self->SUPER::foo(@_) >>, and provides a cleaner interface for it.
 
 As of version 1.00, C<Class::Method::Modifiers> is faster in some cases than
 L<Moose>. See C<benchmark/method_modifiers.pl> in the L<Moose> distribution.
 
 C<Class::Method::Modifiers> also provides an additional "modifier" type,
 C<fresh>; see below.
 
 =head1 MODIFIERS
 
 All modifiers let you modify one or multiple methods at a time. The names of
 multiple methods can be provided as a list or as an array-reference. Examples:
 
  before 'method' => sub { ... };
  before 'method1', 'method2' => sub { ... };
  before [ 'method1', 'method2' ] => sub { ... };
 
 =head2 before method(s) => sub { ... };
 
 C<before> is called before the method it is modifying. Its return value is
 totally ignored. It receives the same C<@_> as the method it is modifying
 would have received. You can modify the C<@_> the original method will receive
 by changing C<$_[0]> and friends (or by changing anything inside a reference).
 This is a feature!
 
 =head2 after method(s) => sub { ... };
 
 C<after> is called after the method it is modifying. Its return value is
 totally ignored. It receives the same C<@_> as the method it is modifying
 received, mostly. The original method can modify C<@_> (such as by changing
 C<$_[0]> or references) and C<after> will see the modified version. If you
 don't like this behavior, specify both a C<before> and C<after>, and copy the
 C<@_> during C<before> for C<after> to use.
 
 =head2 around method(s) => sub { ... };
 
 C<around> is called instead of the method it is modifying. The method you're
 overriding is passed in as the first argument (called C<$orig> by convention).
 Watch out for contextual return values of C<$orig>.
 
 You can use C<around> to:
 
 =over 4
 
 =item Pass C<$orig> a different C<@_>
 
     around 'method' => sub {
         my $orig = shift;
         my $self = shift;
         $orig->($self, reverse @_);
     };
 
 =item Munge the return value of C<$orig>
 
     around 'method' => sub {
         my $orig = shift;
         ucfirst $orig->(@_);
     };
 
 =item Avoid calling C<$orig> -- conditionally
 
     around 'method' => sub {
         my $orig = shift;
         return $orig->(@_) if time() % 2;
         return "no dice, captain";
     };
 
 =back
 
 =head2 fresh method(s) => sub { ... };
 
 (Available since version 2.00)
 
 Unlike the other modifiers, this does not modify an existing method.
 Ordinarily, C<fresh> merely installs the coderef as a method in the
 appropriate class; but if the class hierarchy already contains a method of
 the same name, an exception is thrown.  The idea of this "modifier" is to
 increase safety when subclassing.  Suppose you're writing a subclass of a
 class Some::Base, and adding a new method:
 
     package My::SubclassOf::C;
     use base 'Some::Base';
 
     sub foo { ... }
 
 If a later version of Some::Base also adds a new method named C<foo>, your
 method will shadow that method.  Alternatively, you can use C<fresh>
 to install the additional method into your subclass:
 
     package My::SubclassOf::C;
     use base 'Some::Base';
 
     use Class::Method::Modifiers 'fresh';
 
     fresh 'foo' => sub { ... };
 
 Now upgrading Some::Base to a version with a conflicting C<foo> method will
 cause an exception to be thrown; seeing that error will give you the
 opportunity to fix the problem (perhaps by picking a different method name
 in your subclass, or similar).
 
 Creating fresh methods with C<install_modifier> (see below) provides a way
 to get similar safety benefits when adding local monkeypatches to existing
 classes; see L<http://aaroncrane.co.uk/talks/monkey_patching_subclassing/>.
 
 For API compatibility reasons, this function is exported only when you ask
 for it specifically, or for C<:all>.
 
 =head2 install_modifier $package, $type, @names, sub { ... }
 
 C<install_modifier> is like C<before>, C<after>, C<around>, and C<fresh> but
 it also lets you dynamically select the modifier type ('before', 'after',
 'around', 'fresh')
 and package that the method modifiers are installed into. This expert-level
 function is exported only when you ask for it specifically, or for C<:all>.
 
 =head1 NOTES
 
 All three normal modifiers; C<before>, C<after>, and C<around>; are exported
 into your namespace by default. You may C<use Class::Method::Modifiers ()> to
 avoid thrashing your namespace. I may steal more features from L<Moose>, namely
 C<super>, C<override>, C<inner>, C<augment>, and whatever the L<Moose> folks
 come up with next.
 
 Note that the syntax and semantics for these modifiers is directly borrowed
 from L<Moose> (the implementations, however, are not).
 
 L<Class::Trigger> shares a few similarities with C<Class::Method::Modifiers>,
 and they even have some overlap in purpose -- both can be used to implement
 highly pluggable applications. The difference is that L<Class::Trigger>
 provides a mechanism for easily letting parent classes to invoke hooks defined
 by other code. C<Class::Method::Modifiers> provides a way of
 overriding/augmenting methods safely, and the parent class need not know about
 it.
 
 =head2 :lvalue METHODS
 
 When adding C<before> or C<after> modifiers, the wrapper method will be
 an lvalue method if the wrapped sub is, and assigning to the method
 will propagate to the wrapped method as expected.  For C<around>
 modifiers, it is the modifier sub that determines if the wrapper
 method is an lvalue method.
 
 =head1 CAVEATS
 
 It is erroneous to modify a method that doesn't exist in your class's
 inheritance hierarchy. If this occurs, an exception will be thrown when
 the modifier is defined.
 
 It doesn't yet play well with C<caller>. There are some C<TODO> tests for this.
 Don't get your hopes up though!
 
 Applying modifiers to array lvalue methods is not fully supported. Attempting
 to assign to an array lvalue method that has an C<after> modifier applied will
 result in an error.  Array lvalue methods are not well supported by perl in
 general, and should be avoided.
 
 =head1 MAJOR VERSION CHANGES
 
 =for stopwords reimplementation
 
 This module was bumped to 1.00 following a complete reimplementation, to
 indicate breaking backwards compatibility. The "guard" modifier was removed,
 and the internals are completely different.
 
 The new version is a few times faster with half the code. It's now even faster
 than Moose.
 
 Any code that just used modifiers should not change in behavior, except to
 become more correct. And, of course, faster. :)
 
 =head1 SEE ALSO
 
 L<Class::Method::Modifiers::Fast>
 L<Moose>, L<Class::Trigger>, L<Class::MOP::Method::Wrapped>, L<MRO::Compat>,
 CLOS
 
 =head1 AUTHOR
 
 Shawn M Moore, C<sartak@gmail.com>
 
 =head1 ACKNOWLEDGEMENTS
 
 =for stopwords Stevan
 
 Thanks to Stevan Little for L<Moose>, I would never have known about
 method modifiers otherwise.
 
 Thanks to Matt Trout and Stevan Little for their advice.
 
 =head1 COPYRIGHT AND LICENSE
 
 Copyright 2007-2009 Shawn M Moore.
 
 This program is free software; you can redistribute it and/or modify it
 under the same terms as Perl itself.
 
 =cut
### Clone/PP.pm ###
 package Clone::PP;
 
 use 5.006;
 use strict;
 use warnings;
 use vars qw($VERSION @EXPORT_OK);
 use Exporter;
 
 $VERSION = 1.06;
 
 @EXPORT_OK = qw( clone );
 sub import { goto &Exporter::import } # lazy Exporter
 
 # These methods can be temporarily overridden to work with a given class.
 use vars qw( $CloneSelfMethod $CloneInitMethod );
 $CloneSelfMethod ||= 'clone_self';
 $CloneInitMethod ||= 'clone_init';
 
 # Used to detect looped networks and avoid infinite recursion. 
 use vars qw( %CloneCache );
 
 # Generic cloning function
 sub clone {
   my $source = shift;
 
   return undef if not defined($source);
   
   # Optional depth limit: after a given number of levels, do shallow copy.
   my $depth = shift;
   return $source if ( defined $depth and $depth -- < 1 );
   
   # Maintain a shared cache during recursive calls, then clear it at the end.
   local %CloneCache = ( undef => undef ) unless ( exists $CloneCache{undef} );
   
   return $CloneCache{ $source } if ( defined $CloneCache{ $source } );
   
   # Non-reference values are copied shallowly
   my $ref_type = ref $source or return $source;
   
   # Extract both the structure type and the class name of referent
   my $class_name;
   if ( "$source" =~ /^\Q$ref_type\E\=([A-Z]+)\(0x[0-9a-f]+\)$/ ) {
     $class_name = $ref_type;
     $ref_type = $1;
     # Some objects would prefer to clone themselves; check for clone_self().
     return $CloneCache{ $source } = $source->$CloneSelfMethod() 
 				  if $source->can($CloneSelfMethod);
   }
   
   # To make a copy:
   # - Prepare a reference to the same type of structure;
   # - Store it in the cache, to avoid looping if it refers to itself;
   # - Tie in to the same class as the original, if it was tied;
   # - Assign a value to the reference by cloning each item in the original;
   
   my $copy;
   if ($ref_type eq 'HASH') {
     $CloneCache{ $source } = $copy = {};
     if ( my $tied = tied( %$source ) ) { tie %$copy, ref $tied }
     %$copy = map { ! ref($_) ? $_ : clone($_, $depth) } %$source;
   } elsif ($ref_type eq 'ARRAY') {
     $CloneCache{ $source } = $copy = [];
     if ( my $tied = tied( @$source ) ) { tie @$copy, ref $tied }
     @$copy = map { ! ref($_) ? $_ : clone($_, $depth) } @$source;
   } elsif ($ref_type eq 'REF' or $ref_type eq 'SCALAR') {
     $CloneCache{ $source } = $copy = \( my $var = "" );
     if ( my $tied = tied( $$source ) ) { tie $$copy, ref $tied }
     $$copy = clone($$source, $depth);
   } else {
     # Shallow copy anything else; this handles a reference to code, glob, regex
     $CloneCache{ $source } = $copy = $source;
   }
   
   # - Bless it into the same class as the original, if it was blessed;
   # - If it has a post-cloning initialization method, call it.
   if ( $class_name ) {
     bless $copy, $class_name;
     $copy->$CloneInitMethod() if $copy->can($CloneInitMethod);
   }
   
   return $copy;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Clone::PP - Recursively copy Perl datatypes
 
 =head1 SYNOPSIS
 
   use Clone::PP qw(clone);
   
   $item = { 'foo' => 'bar', 'move' => [ 'zig', 'zag' ]  };
   $copy = clone( $item );
 
   $item = [ 'alpha', 'beta', { 'gamma' => 'vlissides' } ];
   $copy = clone( $item );
 
   $item = Foo->new();
   $copy = clone( $item );
 
 Or as an object method:
 
   require Clone::PP;
   push @Foo::ISA, 'Clone::PP';
   
   $item = Foo->new();
   $copy = $item->clone();
 
 =head1 DESCRIPTION
 
 This module provides a general-purpose clone function to make deep
 copies of Perl data structures. It calls itself recursively to copy
 nested hash, array, scalar and reference types, including tied
 variables and objects.
 
 The clone() function takes a scalar argument to copy. To duplicate
 arrays or hashes, pass them in by reference:
 
   my $copy = clone(\@array);    my @copy = @{ clone(\@array) };
   my $copy = clone(\%hash);     my %copy = %{ clone(\%hash) };
 
 The clone() function also accepts an optional second parameter that
 can be used to limit the depth of the copy. If you pass a limit of
 0, clone will return the same value you supplied; for a limit of
 1, a shallow copy is constructed; for a limit of 2, two layers of
 copying are done, and so on.
 
   my $shallow_copy = clone( $item, 1 );
 
 To allow objects to intervene in the way they are copied, the
 clone() function checks for a couple of optional methods. If an
 object provides a method named C<clone_self>, it is called and the
 result returned without further processing. Alternately, if an
 object provides a method named C<clone_init>, it is called on the
 copied object before it is returned.
 
 =head1 BUGS
 
 Some data types, such as globs, regexes, and code refs, are always copied shallowly.
 
 References to hash elements are not properly duplicated. (This is why two tests in t/dclone.t that are marked "todo".) For example, the following test should succeed but does not:
 
   my $hash = { foo => 1 }; 
   $hash->{bar} = \{ $hash->{foo} }; 
   my $copy = clone( \%hash ); 
   $hash->{foo} = 2; 
   $copy->{foo} = 2; 
   ok( $hash->{bar} == $copy->{bar} );
 
 To report bugs via the CPAN web tracking system, go to 
 C<http://rt.cpan.org/NoAuth/Bugs.html?Dist=Clone-PP> or send mail 
 to C<Dist=Clone-PP#rt.cpan.org>, replacing C<#> with C<@>.
 
 =head1 SEE ALSO
 
 L<Clone> - a baseclass which provides a C<clone()> method.
 
 L<MooseX::Clone> - find-grained cloning for Moose objects.
 
 The C<dclone()> function in L<Storable>.
 
 L<Data::Clone> -
 polymorphic data cloning (see its documentation for what that means).
 
 L<Clone::Any> - use whichever of the cloning methods is available.
 
 =head1 REPOSITORY
 
 L<https://github.com/neilbowers/Clone-PP>
 
 =head1 AUTHOR AND CREDITS
 
 Developed by Matthew Simon Cavalletto at Evolution Softworks. 
 More free Perl software is available at C<www.evoscript.org>.
 
 
 =head1 COPYRIGHT AND LICENSE
 
 Copyright 2003 Matthew Simon Cavalletto. You may contact the author
 directly at C<evo@cpan.org> or C<simonm@cavalletto.org>.
 
 Code initially derived from Ref.pm. Portions Copyright 1994 David Muir Sharnoff.
 
 Interface based by Clone by Ray Finch with contributions from chocolateboy.
 Portions Copyright 2001 Ray Finch. Portions Copyright 2001 chocolateboy. 
 
 You may use, modify, and distribute this software under the same terms as Perl.
 
 =cut
### Color/ANSI/Util.pm ###
 package Color::ANSI::Util;
 
 our $DATE = '2015-01-03'; # DATE
 our $VERSION = '0.14'; # VERSION
 
 use 5.010001;
 use strict;
 use warnings;
 
 require Exporter;
 our @ISA       = qw(Exporter);
 our @EXPORT_OK = qw(
                        ansi16_to_rgb
                        rgb_to_ansi16
                        rgb_to_ansi16_fg_code
                        ansi16fg
                        rgb_to_ansi16_bg_code
                        ansi16bg
 
                        ansi256_to_rgb
                        rgb_to_ansi256
                        rgb_to_ansi256_fg_code
                        ansi256fg
                        rgb_to_ansi256_bg_code
                        ansi256bg
 
                        rgb_to_ansi24b_fg_code
                        ansi24bfg
                        rgb_to_ansi24b_bg_code
                        ansi24bbg
 
                        rgb_to_ansi_fg_code
                        ansifg
                        rgb_to_ansi_bg_code
                        ansibg
                );
 
 my %ansi16 = (
     0  => '000000',
     1  => '800000',
     2  => '008000',
     3  => '808000',
     4  => '000080',
     5  => '800080',
     6  => '008080',
     7  => 'c0c0c0',
     8  => '808080',
     9  => 'ff0000',
     10 => '00ff00',
     11 => 'ffff00',
     12 => '0000ff',
     13 => 'ff00ff',
     14 => '00ffff',
     15 => 'ffffff',
 );
 my @revansi16;
 for (sort {$a<=>$b} keys %ansi16) {
     $ansi16{$_} =~ /(..)(..)(..)/;
     push @revansi16, [hex($1), hex($2), hex($3), $_];
 }
 
 my %ansi256 = (
     %ansi16,
 
     16 => '000000',  17 => '00005f',  18 => '000087',  19 => '0000af',  20 => '0000d7',  21 => '0000ff',
     22 => '005f00',  23 => '005f5f',  24 => '005f87',  25 => '005faf',  26 => '005fd7',  27 => '005fff',
     28 => '008700',  29 => '00875f',  30 => '008787',  31 => '0087af',  32 => '0087d7',  33 => '0087ff',
     34 => '00af00',  35 => '00af5f',  36 => '00af87',  37 => '00afaf',  38 => '00afd7',  39 => '00afff',
     40 => '00d700',  41 => '00d75f',  42 => '00d787',  43 => '00d7af',  44 => '00d7d7',  45 => '00d7ff',
     46 => '00ff00',  47 => '00ff5f',  48 => '00ff87',  49 => '00ffaf',  50 => '00ffd7',  51 => '00ffff',
     52 => '5f0000',  53 => '5f005f',  54 => '5f0087',  55 => '5f00af',  56 => '5f00d7',  57 => '5f00ff',
     58 => '5f5f00',  59 => '5f5f5f',  60 => '5f5f87',  61 => '5f5faf',  62 => '5f5fd7',  63 => '5f5fff',
     64 => '5f8700',  65 => '5f875f',  66 => '5f8787',  67 => '5f87af',  68 => '5f87d7',  69 => '5f87ff',
     70 => '5faf00',  71 => '5faf5f',  72 => '5faf87',  73 => '5fafaf',  74 => '5fafd7',  75 => '5fafff',
     76 => '5fd700',  77 => '5fd75f',  78 => '5fd787',  79 => '5fd7af',  80 => '5fd7d7',  81 => '5fd7ff',
     82 => '5fff00',  83 => '5fff5f',  84 => '5fff87',  85 => '5fffaf',  86 => '5fffd7',  87 => '5fffff',
     88 => '870000',  89 => '87005f',  90 => '870087',  91 => '8700af',  92 => '8700d7',  93 => '8700ff',
     94 => '875f00',  95 => '875f5f',  96 => '875f87',  97 => '875faf',  98 => '875fd7',  99 => '875fff',
     100 => '878700', 101 => '87875f', 102 => '878787', 103 => '8787af', 104 => '8787d7', 105 => '8787ff',
     106 => '87af00', 107 => '87af5f', 108 => '87af87', 109 => '87afaf', 110 => '87afd7', 111 => '87afff',
     112 => '87d700', 113 => '87d75f', 114 => '87d787', 115 => '87d7af', 116 => '87d7d7', 117 => '87d7ff',
     118 => '87ff00', 119 => '87ff5f', 120 => '87ff87', 121 => '87ffaf', 122 => '87ffd7', 123 => '87ffff',
     124 => 'af0000', 125 => 'af005f', 126 => 'af0087', 127 => 'af00af', 128 => 'af00d7', 129 => 'af00ff',
     130 => 'af5f00', 131 => 'af5f5f', 132 => 'af5f87', 133 => 'af5faf', 134 => 'af5fd7', 135 => 'af5fff',
     136 => 'af8700', 137 => 'af875f', 138 => 'af8787', 139 => 'af87af', 140 => 'af87d7', 141 => 'af87ff',
     142 => 'afaf00', 143 => 'afaf5f', 144 => 'afaf87', 145 => 'afafaf', 146 => 'afafd7', 147 => 'afafff',
     148 => 'afd700', 149 => 'afd75f', 150 => 'afd787', 151 => 'afd7af', 152 => 'afd7d7', 153 => 'afd7ff',
     154 => 'afff00', 155 => 'afff5f', 156 => 'afff87', 157 => 'afffaf', 158 => 'afffd7', 159 => 'afffff',
     160 => 'd70000', 161 => 'd7005f', 162 => 'd70087', 163 => 'd700af', 164 => 'd700d7', 165 => 'd700ff',
     166 => 'd75f00', 167 => 'd75f5f', 168 => 'd75f87', 169 => 'd75faf', 170 => 'd75fd7', 171 => 'd75fff',
     172 => 'd78700', 173 => 'd7875f', 174 => 'd78787', 175 => 'd787af', 176 => 'd787d7', 177 => 'd787ff',
     178 => 'd7af00', 179 => 'd7af5f', 180 => 'd7af87', 181 => 'd7afaf', 182 => 'd7afd7', 183 => 'd7afff',
     184 => 'd7d700', 185 => 'd7d75f', 186 => 'd7d787', 187 => 'd7d7af', 188 => 'd7d7d7', 189 => 'd7d7ff',
     190 => 'd7ff00', 191 => 'd7ff5f', 192 => 'd7ff87', 193 => 'd7ffaf', 194 => 'd7ffd7', 195 => 'd7ffff',
     196 => 'ff0000', 197 => 'ff005f', 198 => 'ff0087', 199 => 'ff00af', 200 => 'ff00d7', 201 => 'ff00ff',
     202 => 'ff5f00', 203 => 'ff5f5f', 204 => 'ff5f87', 205 => 'ff5faf', 206 => 'ff5fd7', 207 => 'ff5fff',
     208 => 'ff8700', 209 => 'ff875f', 210 => 'ff8787', 211 => 'ff87af', 212 => 'ff87d7', 213 => 'ff87ff',
     214 => 'ffaf00', 215 => 'ffaf5f', 216 => 'ffaf87', 217 => 'ffafaf', 218 => 'ffafd7', 219 => 'ffafff',
     220 => 'ffd700', 221 => 'ffd75f', 222 => 'ffd787', 223 => 'ffd7af', 224 => 'ffd7d7', 225 => 'ffd7ff',
     226 => 'ffff00', 227 => 'ffff5f', 228 => 'ffff87', 229 => 'ffffaf', 230 => 'ffffd7', 231 => 'ffffff',
 
     232 => '080808', 233 => '121212', 234 => '1c1c1c', 235 => '262626', 236 => '303030', 237 => '3a3a3a',
     238 => '444444', 239 => '4e4e4e', 240 => '585858', 241 => '606060', 242 => '666666', 243 => '767676',
     244 => '808080', 245 => '8a8a8a', 246 => '949494', 247 => '9e9e9e', 248 => 'a8a8a8', 249 => 'b2b2b2',
     250 => 'bcbcbc', 251 => 'c6c6c6', 252 => 'd0d0d0', 253 => 'dadada', 254 => 'e4e4e4', 255 => 'eeeeee',
 );
 my @revansi256;
 for (sort {$a<=>$b} keys %ansi256) {
     $ansi256{$_} =~ /(..)(..)(..)/;
     push @revansi256, [hex($1), hex($2), hex($3), $_];
 }
 
 sub ansi16_to_rgb {
     my ($input) = @_;
 
     if ($input =~ /^\d+$/) {
         if ($input >= 0 && $input <= 15) {
             return $ansi16{$input + 0}; # to remove prefix zero e.g. "06"
         } else {
             die "Invalid ANSI 16-color number '$input'";
         }
     } elsif ($input =~ /^(?:(bold|bright) \s )?
                         (black|red|green|yellow|blue|magenta|cyan|white)$/ix) {
         my ($bold, $col) = (lc($1 // ""), lc($2));
         my $i;
         if ($col eq 'black') {
             $i = 0;
         } elsif ($col eq 'red') {
             $i = 1;
         } elsif ($col eq 'green') {
             $i = 2;
         } elsif ($col eq 'yellow') {
             $i = 3;
         } elsif ($col eq 'blue') {
             $i = 4;
         } elsif ($col eq 'magenta') {
             $i = 5;
         } elsif ($col eq 'cyan') {
             $i = 6;
         } elsif ($col eq 'white') {
             $i = 7;
         }
         $i += 8 if $bold;
         return $ansi16{$i};
     } else {
         die "Invalid ANSI 16-color name '$input'";
     }
 }
 
 sub _rgb_to_indexed {
     my ($rgb, $table) = @_;
 
     $rgb =~ /^#?([0-9A-Fa-f]{2})([0-9A-Fa-f]{2})([0-9A-Fa-f]{2})$/
         or die "Invalid RGB input '$rgb'";
     my $r = hex($1);
     my $g = hex($2);
     my $b = hex($3);
 
     my ($minsqdist, $res);
     for my $e (@$table) {
         my $sqdist =
             abs($e->[0]-$r)**2 + abs($e->[1]-$g)**2 + abs($e->[2]-$b)**2;
         # exact match, return immediately
         return $e->[3] if $sqdist == 0;
         if (!defined($minsqdist) || $minsqdist > $sqdist) {
             #say "D:sqdist=$sqdist";
             $minsqdist = $sqdist;
             $res = $e->[3];
         }
     }
     return $res;
 }
 
 sub ansi256_to_rgb {
     my ($input) = @_;
 
     $input += 0;
     exists($ansi256{$input}) or die "Invalid ANSI 256-color index '$input'";
     $ansi256{$input};
 }
 
 sub rgb_to_ansi16 {
     my ($input) = @_;
     _rgb_to_indexed($input, \@revansi16);
 }
 
 sub rgb_to_ansi256 {
     my ($input) = @_;
     _rgb_to_indexed($input, \@revansi256);
 }
 
 sub rgb_to_ansi16_fg_code {
     my ($input) = @_;
 
     my $res = _rgb_to_indexed($input, \@revansi16);
     return "\e[" . ($res >= 8 ? ($res+30-8) . ";1" : ($res+30)) . "m";
 }
 
 sub ansi16fg  { goto &rgb_to_ansi16_fg_code  }
 
 sub rgb_to_ansi16_bg_code {
     my ($input) = @_;
 
     my $res = _rgb_to_indexed($input, \@revansi16);
     return "\e[" . ($res >= 8 ? ($res+40-8) : ($res+40)) . "m";
 }
 
 sub ansi16bg  { goto &rgb_to_ansi16_bg_code  }
 
 sub rgb_to_ansi256_fg_code {
     my ($input) = @_;
 
     my $res = _rgb_to_indexed($input, \@revansi16);
     return "\e[38;5;${res}m";
 }
 
 sub ansi256fg { goto &rgb_to_ansi256_fg_code }
 
 sub rgb_to_ansi256_bg_code {
     my ($input) = @_;
 
     my $res = _rgb_to_indexed($input, \@revansi16);
     return "\e[48;5;${res}m";
 }
 
 sub ansi256bg { goto &rgb_to_ansi256_bg_code }
 
 sub rgb_to_ansi24b_fg_code {
     my ($rgb) = @_;
 
     return sprintf("\e[38;2;%d;%d;%dm",
                    hex(substr($rgb, 0, 2)),
                    hex(substr($rgb, 2, 2)),
                    hex(substr($rgb, 4, 2)));
 }
 
 sub ansi24bfg { goto &rgb_to_ansi24b_fg_code }
 
 sub rgb_to_ansi24b_bg_code {
     my ($rgb) = @_;
 
     return sprintf("\e[48;2;%d;%d;%dm",
                    hex(substr($rgb, 0, 2)),
                    hex(substr($rgb, 2, 2)),
                    hex(substr($rgb, 4, 2)));
 }
 
 sub ansi24bbg { goto &rgb_to_ansi24b_bg_code }
 
 our $_use_termdetsw = 1;
 our $_color_depth; # cache, can be set during testing
 sub _color_depth {
     unless (defined $_color_depth) {
         {
             if (defined $ENV{COLOR_DEPTH}) {
                 $_color_depth = $ENV{COLOR_DEPTH};
                 last;
             }
             if ($_use_termdetsw) {
                 eval { require Term::Detect::Software };
                 if (!$@) {
                     $_color_depth = Term::Detect::Software::detect_terminal_cached()->{color_depth};
                     last;
                 }
             }
             # simple heuristic
             if ($ENV{KONSOLE_DBUS_SERVICE}) {
                 $_color_depth = 2**24;
                 last;
             }
             # safe value
             $_color_depth = 16;
         }
     };
     $_color_depth;
 }
 
 sub rgb_to_ansi_fg_code {
     my ($rgb) = @_;
     my $cd = _color_depth();
     if ($cd >= 2**24) {
         rgb_to_ansi24b_fg_code($rgb);
     } elsif ($cd >= 256) {
         rgb_to_ansi256_fg_code($rgb);
     } else {
         rgb_to_ansi16_fg_code($rgb);
     }
 }
 
 sub ansifg { goto &rgb_to_ansi_fg_code }
 
 sub rgb_to_ansi_bg_code {
     my ($rgb) = @_;
     my $cd = _color_depth();
     if ($cd >= 2**24) {
         rgb_to_ansi24b_bg_code($rgb);
     } elsif ($cd >= 256) {
         rgb_to_ansi256_bg_code($rgb);
     } else {
         rgb_to_ansi16_bg_code($rgb);
     }
 }
 
 sub ansibg { goto &rgb_to_ansi_bg_code }
 
 1;
 # ABSTRACT: Routines for dealing with ANSI colors
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Color::ANSI::Util - Routines for dealing with ANSI colors
 
 =head1 VERSION
 
 This document describes version 0.14 of Color::ANSI::Util (from Perl distribution Color-ANSI-Util), released on 2015-01-03.
 
 =head1 SYNOPSIS
 
  use Color::ANSI::Util qw(
      ansifg
      ansibg
  );
 
  say ansifg("f0c010"); # => "\e[33;1m" (on 16-color terminal)
                        # => "\e[38;5;11m" (on 256-color terminal)
                        # => "\e[38;2;240;192;16m" (on 24-bit-color terminal)
 
  say ansibg("ff5f87"); # => "\e[47m" (on 16-color terminal)
                        # => "\e[48;5;7m" (on 256-color terminal)
                        # => "\e[48;2;255;95;135m" (on 24-bit-color terminal)
 
 There are a bunch of other exportable functions too, mostly for converting
 between RGB and ANSI color (16/256/24bit color depth).
 
 =head1 DESCRIPTION
 
 This module provides routines for dealing with ANSI colors. The two main
 functions are C<ansifg> and C<ansibg>. With those functions, you can specify
 colors in RGB and let it output the correct ANSI color escape code according to
 the color depth support of the terminal (whether 16-color, 256-color, or 24bit).
 There are other functions to convert RGB to ANSI in specific color depths, or
 reverse functions to convert from ANSI to RGB codes.
 
 Keywords: xterm, xterm-256color, terminal
 
 =head1 FUNCTIONS
 
 =head2 ansi16_to_rgb($color) => STR
 
 Convert ANSI-16 color to RGB. C<$color> is number from 0-15, or color names
 "black", "red", "green", "yellow", "blue", "magenta", "cyan", "white" with
 "bold" to indicate bold/bright. Return 6-hexdigit, e.g. "ff00cc".
 
 Die on invalid input.
 
 =head2 rgb_to_ansi16($color) => INT
 
 Convert RGB to ANSI-16 color. C<$color> is 6-hexdigit RGB color like "ff00cc".
 Will pick the closest color. Return number from 0-15.
 
 Die on invalid input.
 
 =head2 ansi256_to_rgb($color) => STR
 
 Convert ANSI-256 color to RGB. C<$color> is a number from 0-255. Return
 6-hexdigit, e.g. "ff00cc".
 
 Die on invalid input.
 
 =head2 rgb_to_ansi256($color) => INT
 
 Convert RGB to ANSI-256 color. C<$color> is 6-hexdigit RGB color like "ff00cc".
 Will pick the closest color. Return number between 0-255.
 
 Die on invalid input.
 
 =head2 rgb_to_ansi16_fg_code($rgb) => STR
 
 =head2 ansi16fg($rgb) => STR
 
 Alias for rgb_to_ansi16_fg_code().
 
 =head2 rgb_to_ansi16_bg_code($rgb) => STR
 
 =head2 ansi16bg($rgb) => STR
 
 Alias for rgb_to_ansi16_bg_code().
 
 =head2 rgb_to_ansi256_fg_code($rgb) => STR
 
 =head2 ansi256fg($rgb) => STR
 
 Alias for rgb_to_ansi256_fg_code().
 
 =head2 rgb_to_ansi256_bg_code($rgb) => STR
 
 =head2 ansi256bg($rgb) => STR
 
 Alias for rgb_to_ansi256_bg_code().
 
 =head2 rgb_to_ansi24b_fg_code($rgb) => STR
 
 Return ANSI escape code to set 24bit foreground color. Supported by Konsole and
 Yakuake.
 
 =head2 ansi24bfg($rgb) => STR
 
 Alias for rgb_to_ansi24b_fg_code().
 
 =head2 rgb_to_ansi24b_bg_code($rgb) => STR
 
 Return ANSI escape code to set 24bit background color. Supported by Konsole and
 Yakuake.
 
 =head2 ansi24bbg($rgb) => STR
 
 Alias for rgb_to_ansi24b_bg_code().
 
 =head2 rgb_to_ansi_fg_code($rgb) => STR
 
 Return ANSI escape code to set 24bit/256/16 foreground color (which color depth
 used is determined by C<COLOR_DEPTH> environment setting or from
 L<Term::Detect::Software> if that module is available). In other words, this
 function automatically chooses rgb_to_ansi{24b,256,16}_fg_code().
 
 =head2 ansifg($rgb) => STR
 
 Alias for rgb_to_ansi_fg_code().
 
 =head2 rgb_to_ansi_bg_code($rgb) => STR
 
 Return ANSI escape code to set 24bit/256/16 background color (which color depth
 used is determined by C<COLOR_DEPTH> environment setting or from
 Term::Detect::Software if that module is available). In other words, this
 function automatically chooses rgb_to_ansi{24b,256,16}_bg_code().
 
 =head2 ansibg($rgb) => STR
 
 Alias for rgb_to_ansi_bg_code().
 
 =head1 ENVIRONMENT
 
 =head2 COLOR_DEPTH => INT
 
 Observed by: ansi{fg,bg}.
 
 =head1 BUGS/NOTES
 
 Algorithm for finding closest indexed color from RGB color currently not very
 efficient. Probably can add some threshold square distance, below which we can
 shortcut to the final answer.
 
 =head1 SEE ALSO
 
 L<Term::ANSIColor>
 
 L<http://en.wikipedia.org/wiki/ANSI_escape_code>
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Color-ANSI-Util>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Color-ANSI-Util>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Color-ANSI-Util>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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
### Color/RGB/Util.pm ###
 package Color::RGB::Util;
 
 our $DATE = '2015-01-03'; # DATE
 our $VERSION = '0.58'; # VERSION
 
 use 5.010001;
 use strict;
 use warnings;
 
 #use List::Util qw(min);
 
 require Exporter;
 our @ISA = qw(Exporter);
 our @EXPORT_OK = qw(
                        mix_2_rgb_colors
                        rand_rgb_color
                        reverse_rgb_color
                        rgb2grayscale
                        rgb2sepia
                        rgb_luminance
                        tint_rgb_color
                );
 
 sub mix_2_rgb_colors {
     my ($rgb1, $rgb2, $pct) = @_;
 
     $pct //= 0.5;
 
     $rgb1 =~ /^#?([0-9A-Fa-f]{2})([0-9A-Fa-f]{2})([0-9A-Fa-f]{2})$/o
         or die "Invalid rgb1 color, must be in 'ffffff' form";
     my $r1 = hex($1);
     my $g1 = hex($2);
     my $b1 = hex($3);
     $rgb2 =~ /^#?([0-9A-Fa-f]{2})([0-9A-Fa-f]{2})([0-9A-Fa-f]{2})$/o
         or die "Invalid rgb2 color, must be in 'ffffff' form";
     my $r2 = hex($1);
     my $g2 = hex($2);
     my $b2 = hex($3);
 
     return sprintf("%02x%02x%02x",
                    $r1 + $pct*($r2-$r1),
                    $g1 + $pct*($g2-$g1),
                    $b1 + $pct*($b2-$b1),
                );
 }
 
 sub rand_rgb_color {
     my ($rgb1, $rgb2) = @_;
 
     $rgb1 //= '000000';
     $rgb1 =~ /^#?([0-9A-Fa-f]{2})([0-9A-Fa-f]{2})([0-9A-Fa-f]{2})$/o
         or die "Invalid rgb1 color, must be in 'ffffff' form";
     my $r1 = hex($1);
     my $g1 = hex($2);
     my $b1 = hex($3);
     $rgb2 //= 'ffffff';
     $rgb2 =~ /^#?([0-9A-Fa-f]{2})([0-9A-Fa-f]{2})([0-9A-Fa-f]{2})$/o
         or die "Invalid rgb2 color, must be in 'ffffff' form";
     my $r2 = hex($1);
     my $g2 = hex($2);
     my $b2 = hex($3);
 
     return sprintf("%02x%02x%02x",
                    $r1 + rand()*($r2-$r1+1),
                    $g1 + rand()*($g2-$g1+1),
                    $b1 + rand()*($b2-$b1+1),
                );
 }
 
 sub rgb2grayscale {
     my ($rgb) = @_;
 
     $rgb =~ /^#?([0-9A-Fa-f]{2})([0-9A-Fa-f]{2})([0-9A-Fa-f]{2})$/o
         or die "Invalid rgb color, must be in 'ffffff' form";
     my $r = hex($1);
     my $g = hex($2);
     my $b = hex($3);
 
     # basically we just average the R, G, B
     my $avg = int(($r + $g + $b)/3);
     return sprintf("%02x%02x%02x", $avg, $avg, $avg);
 }
 
 sub rgb2sepia {
     my ($rgb) = @_;
 
     $rgb =~ /^#?([0-9A-Fa-f]{2})([0-9A-Fa-f]{2})([0-9A-Fa-f]{2})$/o
         or die "Invalid rgb color, must be in 'ffffff' form";
     my $r = hex($1);
     my $g = hex($2);
     my $b = hex($3);
 
     # reference: http://www.techrepublic.com/blog/howdoi/how-do-i-convert-images-to-grayscale-and-sepia-tone-using-c/120
     my $or = ($r*0.393) + ($g*0.769) + ($b*0.189);
     my $og = ($r*0.349) + ($g*0.686) + ($b*0.168);
     my $ob = ($r*0.272) + ($g*0.534) + ($b*0.131);
     for ($or, $og, $ob) { $_ = 255 if $_ > 255 }
     return sprintf("%02x%02x%02x", $or, $og, $ob);
 }
 
 sub reverse_rgb_color {
     my ($rgb) = @_;
 
     $rgb =~ /^#?([0-9A-Fa-f]{2})([0-9A-Fa-f]{2})([0-9A-Fa-f]{2})$/o
         or die "Invalid rgb color, must be in 'ffffff' form";
     my $r = hex($1);
     my $g = hex($2);
     my $b = hex($3);
 
     return sprintf("%02x%02x%02x", 255-$r, 255-$g, 255-$b);
 }
 
 sub _rgb_luminance {
     my ($r, $g, $b) = @_;
     0.2126*$r/255 + 0.7152*$g/255 + 0.0722*$b/255;
 }
 
 sub rgb_luminance {
     my ($rgb) = @_;
 
     $rgb =~ /^#?([0-9A-Fa-f]{2})([0-9A-Fa-f]{2})([0-9A-Fa-f]{2})$/o
         or die "Invalid rgb color, must be in 'ffffff' form";
     my $r = hex($1);
     my $g = hex($2);
     my $b = hex($3);
 
     return _rgb_luminance($r, $g, $b);
 }
 
 sub tint_rgb_color {
     my ($rgb1, $rgb2, $pct) = @_;
 
     $pct //= 0.5;
 
     $rgb1 =~ /^#?([0-9A-Fa-f]{2})([0-9A-Fa-f]{2})([0-9A-Fa-f]{2})$/o
         or die "Invalid rgb color, must be in 'ffffff' form";
     my $r1 = hex($1);
     my $g1 = hex($2);
     my $b1 = hex($3);
     $rgb2 =~ /^#?([0-9A-Fa-f]{2})([0-9A-Fa-f]{2})([0-9A-Fa-f]{2})$/o
         or die "Invalid tint color, must be in 'ffffff' form";
     my $r2 = hex($1);
     my $g2 = hex($2);
     my $b2 = hex($3);
 
     my $lum = _rgb_luminance($r1, $g1, $b1);
 
     return sprintf("%02x%02x%02x",
                    $r1 + $pct*($r2-$r1)*$lum,
                    $g1 + $pct*($g2-$g1)*$lum,
                    $b1 + $pct*($b2-$b1)*$lum,
                );
 }
 
 1;
 # ABSTRACT: Utilities related to RGB colors
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Color::RGB::Util - Utilities related to RGB colors
 
 =head1 VERSION
 
 This document describes version 0.58 of Color::RGB::Util (from Perl distribution Color-RGB-Util), released on 2015-01-03.
 
 =head1 SYNOPSIS
 
  use Color::RGB::Util qw(
      mix_2_rgb_colors
      rand_rgb_color
      rgb2grayscale
      rgb2sepia
      reverse_rgb_color
      rgb_luminance
  );
 
  say mix_2_rgb_colors('#ff0000', '#ffffff');     # pink (red + white)
  say mix_2_rgb_colors('ff0000', 'ffffff', 0.75); # pink with a whiter shade
 
  say rand_rgb_color();
  say rand_rgb_color('000000', '333333');         # limit range
 
  say rgb2grayscale('0033CC');                    # => 555555
 
  say rgb2sepia('0033CC');                        # => 4d4535
 
  say reverse_rgb_color('0033CC');                # => ffcc33
 
  say rgb_luminance('d090aa');                    # => ffcc33
 
 =head1 DESCRIPTION
 
 =head1 FUNCTIONS
 
 None are exported by default, but they are exportable.
 
 =head2 mix_2_rgb_colors($rgb1, $rgb2, $pct) => STR
 
 Mix 2 RGB colors. C<$pct> is a number between 0 and 1, by default 0.5 (halfway),
 the closer to 1 the closer the resulting color to C<$rgb2>.
 
 =head2 rand_rgb_color([$low_limit[, $high_limit]]) => STR
 
 Generate a random RGB color. You can specify the limit. Otherwise, they default
 to the full range (000000 to ffffff).
 
 =head2 rgb2grayscale($rgb) => RGB
 
 Convert C<$rgb> to grayscale RGB value.
 
 =head2 rgb2sepia($rgb) => RGB
 
 Convert C<$rgb> to sepia tone RGB value.
 
 =head2 reverse_rgb_color($rgb) => RGB
 
 Reverse C<$rgb>.
 
 =head2 rgb_luminance($rgb) => NUM
 
 Calculate standard/objective luminance from RGB value using this formula:
 
  (0.2126*R) + (0.7152*G) + (0.0722*B)
 
 where R, G, and B range from 0 to 1. Return a number from 0 to 1.
 
 =head2 tint_rgb_color($rgb, $tint_rgb, $pct) => RGB
 
 Tint C<$rgb> with C<$tint_rgb>. $pct is by default 0.5. It is similar to mixing,
 but the less luminance the color is the less it is tinted with the tint color.
 This has the effect of black color still being black instead of becoming tinted.
 
 =head1 SEE ALSO
 
 L<Color::ANSI::Util>
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Color-RGB-Util>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-SHARYANTO-Color-Util>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Color-RGB-Util>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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
### Color/Theme.pm ###
 package Color::Theme;
 
 our $DATE = '2014-12-11'; # DATE
 our $VERSION = '0.01'; # VERSION
 
 1;
 # ABSTRACT: Color theme structure
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Color::Theme - Color theme structure
 
 =head1 VERSION
 
 This document describes version 0.01 of Color::Theme (from Perl distribution Color-Theme), released on 2014-12-11.
 
 =head1 DESCRIPTION
 
 This module specifies a structure for color themes. The distribution also comes
 with utility routines and roles for managing color themes in applications.
 
 =head1 SPECIFICATION
 
 Color theme is a L<DefHash> containing these keys: C<v> (float, should be 1.1),
 C<name> (str), C<summary> (str), C<no_color> (bool, should be set to 1 if this
 is a color theme without any colors), and C<colors> (hash, the colors for items;
 hash keys are item names and hash values are color values).
 
 A color value should be a scalar containing a single color code which is
 6-hexdigit RGB color (e.g. C<ffc0c0>), or a hashref containing multiple color
 codes, or a coderef which should produce a color code (or a hash of color
 codes).
 
 Multiple color codes are used to support foreground/background values or ANSI
 color codes that are not representable by RGB, among other things. The keys are:
 C<fg> (RGB value for foreground), C<bg> (RGB value for background), C<ansi_fg>
 (ANSI color escape code for foreground), C<ansi_bg> (ANSI color escape code for
 background). Future keys like C<css> can be defined.
 
 Allowing coderef as color allows for flexibility, e.g. for doing gradation
 border color, random color, etc. See, for example,
 L<Text::ANSITable::ColorTheme::Demo>. Code will be called with C<< ($self,
 %args) >> where C<%args> contains various information, like C<name> (the item
 name being requested), etc. In Text::ANSITable, you can get the row position
 from C<< $self->{_draw}{y} >>.
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Color-Theme>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Color-Theme>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Color-Theme>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2014 by perlancar@cpan.org.
 
 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
### Color/Theme/Role.pm ###
 package Color::Theme::Role;
 
 our $DATE = '2014-12-11'; # DATE
 our $VERSION = '0.01'; # VERSION
 
 use 5.010001;
 use Moo::Role;
 
 has color_theme_args  => (is => 'rw', default => sub { {} });
 has _all_color_themes => (is => 'rw');
 
 sub color_theme_module_prefix {
     my $self = shift;
 
     (ref($self) ? ref($self) : $self ) . '::ColorTheme';
 }
 
 sub color_theme {
     my $self = shift;
 
     if (!@_) { return $self->{color_theme} }
     my $ct = shift;
 
     my $p2 = "";
     if (!ref($ct)) {
         $p2 = " named $ct";
         $ct = $self->get_color_theme($ct);
     }
 
     my $err;
     if (!$ct->{no_color} && !$self->use_color) {
         $err = "color theme uses color but use_color is set to false";
     }
     die "Can't select color theme$p2: $err" if $err;
 
     $self->{color_theme} = $ct;
 }
 
 sub get_color_theme {
     my ($self, $ct) = @_;
 
     my $prefix = $self->color_theme_module_prefix;
     my $cts;
     my $pkg;
     if ($ct =~ s/(.+):://) {
         $pkg = "$prefix\::$1";
         my $pkgp = $pkg; $pkgp =~ s!::!/!g;
         require "$pkgp.pm";
         no strict 'refs';
         $cts = \%{"$pkg\::color_themes"};
     } else {
         #$cts = $self->list_color_themes(1);
         die "Please use SubPackage::name to choose color theme, ".
             "use list_color_themes() to list available themes";
     }
     $cts->{$ct} or die "Unknown color theme name '$ct'".
         ($pkg ? " in package $pkg" : "");
     ($cts->{$ct}{v} // 1.0) == 1.1 or die "Color theme '$ct' is too old ".
         "(v < 1.1)". ($pkg ? ", please upgrade $pkg" : "");
     $cts->{$ct};
 }
 
 sub get_theme_color {
     my ($self, $item_name) = @_;
 
     return undef if $self->{color_theme}{no_color};
     $self->{color_theme}{colors}{$item_name};
 }
 
 sub get_theme_color_as_rgb {
     my ($self, $item_name, $args) = @_;
     my $c = $self->get_theme_color($item_name);
     return undef unless defined($c);
 
     # resolve coderef color
     if (ref($c) eq 'CODE') {
         $args //= {};
         $c = $c->($self, %$args);
     }
 
     $c;
 }
 
 sub list_color_themes {
     require Module::List;
     require Module::Load;
 
     my ($self, $detail) = @_;
 
     my $prefix = $self->color_theme_module_prefix;
     my $all_ct = $self->_all_color_themes;
 
     if (!$all_ct) {
         my $mods = Module::List::list_modules("$prefix\::",
                                               {list_modules=>1, recurse=>1});
         no strict 'refs';
         $all_ct = {};
         for my $mod (sort keys %$mods) {
             #$log->tracef("Loading color theme module '%s' ...", $mod);
             Module::Load::load($mod);
             my $ct = \%{"$mod\::color_themes"};
             for (keys %$ct) {
                 my $cutmod = $mod;
                 $cutmod =~ s/^\Q$prefix\E:://;
                 my $name = "$cutmod\::$_";
                 $ct->{$_}{name} = $name;
                 $all_ct->{$name} = $ct->{$_};
             }
         }
         $self->_all_color_themes($all_ct);
     }
 
     if ($detail) {
         return $all_ct;
     } else {
         return sort keys %$all_ct;
     }
 }
 
 1;
 # ABSTRACT: Role for class wanting to support color themes
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Color::Theme::Role - Role for class wanting to support color themes
 
 =head1 VERSION
 
 This document describes version 0.01 of Color::Theme::Role (from Perl distribution Color-Theme), released on 2014-12-11.
 
 =head1 DESCRIPTION
 
 This role is for class that wants to support color themes. Color theme is
 represented as a structure according to the specification described in
 L<Color::Theme>.
 
 B<Color theme module.> Color themes are put in modules under
 C<Color::Theme::Themes::> (configurable using C<color_theme_module_prefix>
 attribute). Each color theme modules can contain one or more color themes. The
 module must define a package global variable named C<%color_themes> that contain
 color themes keyed by their names. Example:
 
  package MyProject::ColorThemes::Default;
 
  our %color_themes = (
      no_color => {
          v => 1.1,
          summary => 'Special theme that means no color',
          colors => {
          },
          no_color => 1,
      },
 
      default => {
          v => 1.1,
          summary => 'Default color theme',
          colors => {
          },
      },
  );
 
 =head1 ATTRIBUTES
 
 =head2 color_theme => HASH
 
 Get/set color theme.
 
 =head2 color_theme_args => HASH
 
 Get/set arguments for color theme. This can be
 
 =head2 color_theme_module_prefix => STR (default: CLASS + C<::ColorTheme::>)
 
 Each project should have its own class prefix. For example, L<Text::ANSITable>
 has its color themes in C<Text::ANSITable::ColorTheme::> namespace,
 L<Data::Dump::Color> has them in C<Data::Dump::Color::ColorTheme::> and so on.
 
 =head1 METHODS
 
 =head2 $cl->list_color_themes($detail) => array
 
 Will search packages under C<color_theme_module_prefix> for color theme modules,
 then list all color themes for each module. If, for example, the color theme
 modules found are C<MyProject::ColorTheme::Default> and
 C<MyProject::ColorTheme::Extras>, will return something like:
 
  ['Default::theme1', 'Default::theme2', 'Extras::extra3', 'Extras::extra4']
 
 =head2 $cl->get_color_theme($name) => hash
 
 Get color theme hash data structure by name. Note that name must be prefixed by
 color theme module name (minus the C<color_theme_module_prefix>).
 
 =head2 $cl->get_theme_color($item_name) => str
 
 Get an item's color value from the current color theme (will get from the color
 theme's C<colors> hash, then the C<$item_name> key from that hash). If color
 value is a coderef, it will be
 
 =head2 $cl->get_theme_color_as_rgb($item_name, \%args) => str|hash
 
 Like C<get_theme_color>, but if the resulting color value is a coderef, will
 call that coderef, passing C<%args> to it and returning the value.
 
 =head1 SEE ALSO
 
 L<Color::Theme>
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Color-Theme>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Color-Theme>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Color-Theme>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2014 by perlancar@cpan.org.
 
 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
### Color/Theme/Role/ANSI.pm ###
 package Color::Theme::Role::ANSI;
 
 our $DATE = '2014-12-11'; # DATE
 our $VERSION = '0.01'; # VERSION
 
 use 5.010001;
 use Moo::Role;
 
 use Color::ANSI::Util ();
 with 'Color::Theme::Role';
 with 'Term::App::Role::Attrs';
 
 sub theme_color_to_ansi {
     my ($self, $c, $args, $is_bg) = @_;
 
     # empty? skip
     return '' if !defined($c) || !length($c);
 
     # resolve coderef color
     if (ref($c) eq 'CODE') {
         $args //= {};
         $c = $c->($self, %$args);
     }
 
     my $coldepth = $self->color_depth;
 
     if ($coldepth >= 2**24) {
         if (ref $c) {
             my $ansifg = $c->{ansi_fg};
             $ansifg //= Color::ANSI::Util::ansi24bfg($c->{fg})
                 if defined $c->{fg};
             $ansifg //= "";
             my $ansibg = $c->{ansi_bg};
             $ansibg //= Color::ANSI::Util::ansi24bbg($c->{bg})
                 if defined $c->{bg};
             $ansibg //= "";
             $c = $ansifg . $ansibg;
         } else {
             $c = $is_bg ? Color::ANSI::Util::ansi24bbg($c) :
                 Color::ANSI::Util::ansi24bfg($c);
         }
     } elsif ($coldepth >= 256) {
         if (ref $c) {
             my $ansifg = $c->{ansi_fg};
             $ansifg //= Color::ANSI::Util::ansi256fg($c->{fg})
                 if defined $c->{fg};
             $ansifg //= "";
             my $ansibg = $c->{ansi_bg};
             $ansibg //= Color::ANSI::Util::ansi256bg($c->{bg})
                 if defined $c->{bg};
             $ansibg //= "";
             $c = $ansifg . $ansibg;
         } else {
             $c = $is_bg ? Color::ANSI::Util::ansi256bg($c) :
                 Color::ANSI::Util::ansi256fg($c);
         }
     } else {
         if (ref $c) {
             my $ansifg = $c->{ansi_fg};
             $ansifg //= Color::ANSI::Util::ansi16fg($c->{fg})
                 if defined $c->{fg};
             $ansifg //= "";
             my $ansibg = $c->{ansi_bg};
             $ansibg //= Color::ANSI::Util::ansi16bg($c->{bg})
                 if defined $c->{bg};
             $ansibg //= "";
             $c = $ansifg . $ansibg;
         } else {
             $c = $is_bg ? Color::ANSI::Util::ansi16bg($c) :
                 Color::ANSI::Util::ansi16fg($c);
         }
     }
     $c;
 }
 
 sub get_theme_color_as_ansi {
     my ($self, $item_name, $args) = @_;
     $self->theme_color_to_ansi(
         $self->get_theme_color($item_name),
         {name=>$item_name, %{ $args // {} }},
         $item_name =~ /_bg$/,
     );
 }
 
 1;
 # ABSTRACT: Role for class wanting to support color themes (ANSI support)
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Color::Theme::Role::ANSI - Role for class wanting to support color themes (ANSI support)
 
 =head1 VERSION
 
 This document describes version 0.01 of Color::Theme::Role::ANSI (from Perl distribution Color-Theme), released on 2014-12-11.
 
 =head1 DESCRIPTION
 
 This role consumes L<Color::Theme::Role> and L<Term::App::Role::Attrs>.
 
 =head1 METHODS
 
 =head2 $cl->theme_color_to_ansi($color) => str
 
 =head2 $cl->get_theme_color_as_ansi($item_name, \%args) => str
 
 Like C<get_theme_color>, but if the resulting color value is a coderef, will
 call that coderef, passing C<%args> to it and returning the value. Also, will
 convert color theme to ANSI color escape codes.
 
 When converting to ANSI code, will consult C<color_depth> from
 L<Term::App::Role::Attr>.
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Color-Theme>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Color-Theme>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Color-Theme>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2014 by perlancar@cpan.org.
 
 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
### Color/Theme/Util.pm ###
 package Color::Theme::Util;
 
 our $DATE = '2014-12-11'; # DATE
 our $VERSION = '0.01'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 
 require Exporter;
 our @ISA       = qw(Exporter);
 our @EXPORT_OK = qw(create_color_theme_transform);
 
 sub create_color_theme_transform {
     my ($basect, $func) = @_;
 
     my $derivedct = {};
 
     for my $cn (keys %{ $basect->{colors} }) {
         my $cv = $basect->{colors}{$cn};
 
         if ($cv) {
             $derivedct->{colors}{$cn} = sub {
                 my ($self, %args) = @_;
                 my $basec = $basect->{colors}{$cn};
                 if (ref($basec) eq 'CODE') {
                     $basec = $basec->($self, name=>$cn, %args);
                 }
                 if ($basec) {
                     if (ref($basec) eq 'ARRAY') {
                         $basec = [map {defined($_) && /^#?[0-9A-Fa-f]{6}$/ ?
                                            $func->($_) : $_} @$basec];
                     } else {
                         for ($basec) {
                             $_ = defined($_) && /^#?[0-9A-Fa-f]{6}$/ ?
                                 $func->($_) : $_;
                         }
                     }
                 }
                 return $basec;
             };
         } else {
             #$derivedct->{colors}{$cn} = $cv;
         }
     }
     $derivedct;
 }
 
 1;
 # ABSTRACT: Utility routines related to color themes
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Color::Theme::Util - Utility routines related to color themes
 
 =head1 VERSION
 
 This document describes version 0.01 of Color::Theme::Util (from Perl distribution Color-Theme), released on 2014-12-11.
 
 =head1 FUNCTIONS
 
 =head2 create_color_theme_transform($basect, $func) => HASH
 
 Create a new color theme by applying transform function C<$func> (code) to base
 theme C<$basetheme> (hash). For example if you want to create a reddish
 L<Text::ANSITable> color theme from the default theme:
 
  use Color::RGB::Util qw(mix_2_rgb_colors);
  use Color::Theme::Util qw(create_color_theme_transform);
  use Text::ANSITable;
 
  my $basetheme = Text::ANSITable->get_color_theme("Default::default_gradation");
  my $redtheme  = create_color_theme_transform(
      $basetheme, sub { mix_2_rgb_colors(shift, 'ff0000') });
 
  # use the color theme
  my $t = Text::ANSITable->new;
  $t->color_theme($redtheme);
 
 =head1 SEE ALSO
 
 L<Color::Theme>
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Color-Theme>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Color-Theme>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Color-Theme>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2014 by perlancar@cpan.org.
 
 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
### Complete.pm ###
 package Complete;
 
 our $DATE = '2015-09-16'; # DATE
 our $VERSION = '0.16'; # VERSION
 
 1;
 # ABSTRACT: Convention for Complete::* modules family
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Complete - Convention for Complete::* modules family
 
 =head1 VERSION
 
 This document describes version 0.16 of Complete (from Perl distribution Complete), released on 2015-09-16.
 
 =head1 DESCRIPTION
 
 The namespace C<Complete::> is used for the family of modules that deal with
 completion (including, but not limited to, shell tab completion, tab completion
 feature in other CLI-based application, web autocomplete, completion in GUI,
 etc). This (family of) modules try to have a clear separation between general
 completion routine and shell-/environment specific ones, for more reusability.
 
 This POD page gives an overview of the modules in C<Complete::*> namespace,
 establishes convention, and declares common settings.
 
 =head2 Modules
 
 =head3 Common/shared settings
 
 L<Complete::Setting>
 
 =head3 Generic (non-environment-specific) modules
 
 Modules usually are named after the type of completion answer they provide. For
 example: L<Complete::Unix> completes username/group name,
 L<Complete::Getopt::Long> completes from L<Getopt::Long> specification,
 L<Complete::Module> completes Perl module names, and so on. A current exception
 is L<Complete::Util> which contains several routines to complete from
 common/generic sources (array, hash, file, environment).
 
 =head3 Environment-specific modules
 
 C<Complete::Bash::*> modules are specific to bash shell. See L<Complete::Bash>
 on some of the ways to do bash tab completion with Perl. Other shells are also
 supported. For shell-specific information, please refer to L<Complete::Zsh>,
 L<Complete::Tcsh>, L<Complete::Fish>, as well as their submodules.
 
 C<Complete::*> modules for non-shell environment (like browser or GUI) have not
 been developed. Please check again from time to time in the future.
 
 =head2 C<complete_*()> functions
 
 The main functions that do the actual completion are the C<complete_*()>
 functions. These functions are generic completion routines: they accept the word
 to be completed, zero or more other arguments, and return a completion answer
 structure (see L</"Completion answer structure">).
 
  use Complete::Util qw(complete_array_elem);
  my $ary = complete_array_elem(array=>[qw/apple apricot banana/], word=>'ap');
  # -> ['apple', 'apricot']
 
 Convention for C<complete_*> function:
 
 =over
 
 =item * Accept a hash argument
 
 Example:
 
  complete_array_elem(%args)
 
 Required arguments: C<word> (the word to be completed). Sometimes, for
 lower-level functions, you can accept C<words> and C<cword> instead of C<word>,
 For example, in function C<Complete::Getopt::Long::complete_cli_arg>.
 
 Optional common arguments: C<ci> (bool, whether the matching should be
 case-insensitive, if unspecified should default to
 C<$Complete::Setting::OPT_CI>).
 
 Other arguments: you can define more arguments as you fit. Often there is at
 least one argument to specify or customize the source of completion, for example
 for the function C<Complete::Util::complete_array_elem> there is an C<array>
 argument to specify the source array.
 
 =item * Return completion answer structure
 
 See L</"Completion answer structure">.
 
 =item * Use defaults from global Complete::Setting, when applicable
 
 =back
 
 =head2 Completion answer structure
 
 C<complete_*()> functions return completion answer structure. Completion answer
 contains the completion entries as well as extra metadata to give hints to
 formatters/tools. It is a hashref which can contain the following keys:
 
 =over
 
 =item * words => array
 
 This key is required. Its value is an array of completion entries. A completion
 entry can be a string or a hashref. Example:
 
  ['apple', 'apricot'] # array of strings
 
  [{word=>'apple', summary=>'A delicious fruit with thousands of varieties'},
   {word=>'apricot', summary=>'Another delicious fruit'},] # array of hashes
 
 As you can see from the above, each entry can contain description (can be
 displayed in shells that support them, like fish and zsh).
 
 =item * type => str
 
 See L<Complete::Bash>.
 
 =item * path_sep => str
 
 See L<Complete::Bash>.
 
 =item * esc_mode => str
 
 See L<Complete::Bash>.
 
 =item * static => bool
 
 Specify that completion is "static", meaning that it does not depend on external
 state (like filesystem) or a custom code which can return different answer
 everytime completion is requested.
 
 This can be useful for code that wants to generate completion code, like bash
 completion or fish completion. Knowing that completion for an option value is
 static means that completion for that option can be answered from an array
 instead of having to call code/program (faster).
 
 =back
 
 As a shortcut, completion answer can also be an arrayref (just the C<words>)
 without any metadata.
 
 Examples:
 
  # hash form
  {words=>[qw/apple apricot/]}
 
  # another hash form. type=env instructs formatter not to escape '$'
  {words=>[qw/$HOME $ENV/], type=>'env'}
 
  # array form
  ['apple', 'apricot']
 
  # another array form, each entry is a hashref to include description
  [{word=>'apple', summary=>'A delicious fruit with thousands of varieties'},
   {word=>'apricot', summary=>'Another delicious fruit'},] # array of hashes
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Complete>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Complete>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Complete>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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
### Complete/Bash.pm ###
 package Complete::Bash;
 
 our $DATE = '2015-09-09'; # DATE
 our $VERSION = '0.21'; # VERSION
 
 use 5.010001;
 use strict;
 use warnings;
 
 #use Complete;
 
 require Exporter;
 our @ISA = qw(Exporter);
 our @EXPORT_OK = qw(
                        parse_cmdline
                        parse_options
                        format_completion
                );
 
 our %SPEC;
 
 $SPEC{':package'} = {
     v => 1.1,
     summary => 'Completion module for bash shell',
     links => [
         {url => 'pm:Complete'},
     ],
 };
 
 sub _expand_tilde {
     my ($user, $slash) = @_;
     my @ent;
     if (length $user) {
         @ent = getpwnam($user);
     } else {
         @ent = getpwuid($>);
         $user = $ent[0];
     }
     return $ent[7] . $slash if @ent;
     "~$user$slash"; # return as-is when failed
 }
 
 sub _add_unquoted {
     no warnings 'uninitialized';
 
     my ($word, $is_cur_word, $after_ws) = @_;
 
     #say "D:add_unquoted word=$word is_cur_word=$is_cur_word after_ws=$after_ws";
 
     $word =~ s!^(~)(\w*)(/|\z) |  # 1) tilde  2) username  3) optional slash
                \\(.)           |  # 4) escaped char
                \$(\w+)            # 5) variable name
               !
                   $1 ? (not($after_ws) || $is_cur_word ? "$1$2$3" : _expand_tilde($2, $3)) :
                       $4 ? $4 :
                           ($is_cur_word ? "\$$5" : $ENV{$5})
                               !egx;
     $word;
 }
 
 sub _add_double_quoted {
     no warnings 'uninitialized';
 
     my ($word, $is_cur_word) = @_;
 
     $word =~ s!\\(.)           |  # 1) escaped char
                \$(\w+)            # 2) variable name
               !
                   $1 ? $1 :
                       ($is_cur_word ? "\$$2" : $ENV{$2})
                           !egx;
     $word;
 }
 
 sub _add_single_quoted {
     my $word = shift;
     $word =~ s/\\(.)/$1/g;
     $word;
 }
 
 $SPEC{parse_cmdline} = {
     v => 1.1,
     summary => 'Parse shell command-line for processing by completion routines',
     description => <<'_',
 
 This function basically converts COMP_LINE (str) and COMP_POINT (int) into
 something like (but not exactly the same as) COMP_WORDS (array) and COMP_CWORD
 (int) that bash supplies to shell functions.
 
 The differences with bash are (these differences are mostly for parsing
 convenience for programs that use this routine):
 
 1) quotes and backslashes are stripped (bash's COMP_WORDS contains all the
 quotes and backslashes);
 
 2) variables are substituted with their values from environment variables except
 for the current word (COMP_WORDS[COMP_CWORD]) (bash does not perform variable
 substitution for COMP_WORDS). However, note that special shell variables that
 are not environment variables like `$0`, `$_`, `$IFS` will not be replaced
 correctly because bash does not export those variables for us.
 
 3) tildes (~) are expanded with user's home directory except for the current
 word (bash does not perform tilde expansion for COMP_WORDS);
 
 4) no word-breaking characters aside from whitespaces and `=` are currently used
 (bash uses COMP_WORDBREAKS which by default also include `:`, `;`, and so on).
 This is done for convenience of parsing of Getopt::Long-based applications. More
 word-breaking characters might be used in the future, e.g. when we want to
 handle complex bash statements like pipes, redirection, etc.
 
 Caveats:
 
 * Due to the way bash parses the command line, the two below are equivalent:
 
     % cmd --foo=bar
     % cmd --foo = bar
 
 Because they both expand to `['--foo', '=', 'bar']`. But obviously
 `Getopt::Long` does not regard the two as equivalent.
 
 _
     args_as => 'array',
     args => {
         cmdline => {
             summary => 'Command-line, defaults to COMP_LINE environment',
             schema => 'str*',
             pos => 0,
         },
         point => {
             summary => 'Point/position to complete in command-line, '.
                 'defaults to COMP_POINT',
             schema => 'int*',
             pos => 1,
         },
     },
     result => {
         schema => ['array*', len=>2],
         description => <<'_',
 
 Return a 2-element array: `[$words, $cword]`. `$words` is array of str,
 equivalent to `COMP_WORDS` provided by bash to shell functions. `$cword` is an
 integer, equivalent to `COMP_CWORD` provided by bash to shell functions. The
 word to be completed is at `$words->[$cword]`.
 
 Note that COMP_LINE includes the command name. If you want the command-line
 arguments only (like in `@ARGV`), you need to strip the first element from
 `$words` and reduce `$cword` by 1.
 
 
 _
     },
     result_naked => 1,
     links => [
     ],
 };
 sub parse_cmdline {
     no warnings 'uninitialized';
     my ($line, $point) = @_;
 
     $line  //= $ENV{COMP_LINE};
     $point //= $ENV{COMP_POINT} // 0;
 
     die "$0: COMP_LINE not set, make sure this script is run under ".
         "bash completion (e.g. through complete -C)\n" unless defined $line;
 
     my @words;
     my $cword;
     my $pos = 0;
     my $pos_min_ws = 0;
     my $after_ws = 1;
     my $chunk;
     my $add_blank;
     my $is_cur_word;
     $line =~ s!(                                                 # 1) everything
                   (")((?: \\\\|\\"|[^"])*)(?:"|\z)(\s*)       |  # 2) open "  3) content  4) space after
                   (')((?: \\\\|\\'|[^'])*)(?:'|\z)(\s*)       |  # 5) open '  6) content  7) space after
                   ((?: \\\\|\\"|\\'|\\=|\\\s|[^"'=\s])+)(\s*) |  # 8) unquoted word  9) space after
                   = |
                   \s+
               )!
                   $pos += length($1);
                   #say "D:<$1> pos=$pos, point=$point, cword=$cword, after_ws=$after_ws";
 
                   if ($2 || $5 || defined($8)) {
                       # double-quoted/single-quoted/unquoted chunk
 
                       if (not(defined $cword)) {
                           $pos_min_ws = $pos - length($2 ? $4 : $5 ? $7 : $9);
                           #say "D:pos_min_ws=$pos_min_ws";
                           if ($point <= $pos_min_ws) {
                               $cword = @words - ($after_ws ? 0 : 1);
                           } elsif ($point < $pos) {
                               $cword = @words + 1 - ($after_ws ? 0 : 1);
                               $add_blank = 1;
                           }
                       }
 
                       if ($after_ws) {
                           $is_cur_word = defined($cword) && $cword==@words;
                       } else {
                           $is_cur_word = defined($cword) && $cword==@words-1;
                       }
                       $chunk =
                           $2 ? _add_double_quoted($3, $is_cur_word) :
                               $5 ? _add_single_quoted($6) :
                                   _add_unquoted($8, $is_cur_word, $after_ws);
                       if ($after_ws) {
                           push @words, $chunk;
                       } else {
                           $words[-1] .= $chunk;
                       }
                       if ($add_blank) {
                           push @words, '';
                           $add_blank = 0;
                       }
                       $after_ws = ($2 ? $4 : $5 ? $7 : $9) ? 1:0;
 
                   } elsif ($1 eq '=') {
                       # equal sign as word-breaking character
                       push @words, '=';
                       $after_ws = 1;
                   } else {
                       # whitespace
                       $after_ws = 1;
                   }
     !egx;
 
     $cword //= @words;
     $words[$cword] //= '';
 
     [\@words, $cword];
 }
 
 $SPEC{parse_options} = {
     v => 1.1,
     summary => 'Parse command-line for options and arguments, '.
         'more or less like Getopt::Long',
     description => <<'_',
 
 Parse command-line into words using `parse_cmdline()` then separate options and
 arguments. Since this routine does not accept `Getopt::Long` (this routine is
 meant to be a generic option parsing of command-lines), it uses a few simple
 rules to server the common cases:
 
 * After `--`, the rest of the words are arguments (just like Getopt::Long).
 
 * If we get something like `-abc` (a single dash followed by several letters) it
   is assumed to be a bundle of short options.
 
 * If we get something like `-MData::Dump` (a single dash, followed by a letter,
   followed by some letters *and* non-letters/numbers) it is assumed to be an
   option (`-M`) followed by a value.
 
 * If we get something like `--foo` it is a long option. If the next word is an
   option (starts with a `-`) then it is assumed that this option does not have
   argument. Otherwise, the next word is assumed to be this option's value.
 
 * Otherwise, it is an argument (that is, permute is assumed).
 
 _
 
     args => {
         cmdline => {
             summary => 'Command-line, defaults to COMP_LINE environment',
             schema => 'str*',
         },
         point => {
             summary => 'Point/position to complete in command-line, '.
                 'defaults to COMP_POINT',
             schema => 'int*',
         },
         words => {
             summary => 'Alternative to passing `cmdline` and `point`',
             schema => ['array*', of=>'str*'],
             description => <<'_',
 
 If you already did a `parse_cmdline()`, you can pass the words result (the first
 element) here to avoid calling `parse_cmdline()` twice.
 
 _
         },
         cword => {
             summary => 'Alternative to passing `cmdline` and `point`',
             schema => ['array*', of=>'str*'],
             description => <<'_',
 
 If you already did a `parse_cmdline()`, you can pass the cword result (the
 second element) here to avoid calling `parse_cmdline()` twice.
 
 _
         },
     },
     result => {
         schema => 'hash*',
     },
 };
 sub parse_options {
     my %args = @_;
 
     my ($words, $cword) = @_;
     if ($args{words}) {
         ($words, $cword) = ($args{words}, $args{cword});
     } else {
         ($words, $cword) = @{parse_cmdline($args{cmdline}, $args{point}, '=')};
     }
 
     my @types;
     my %opts;
     my @argv;
     my $type;
     $types[0] = 'command';
     my $i = 1;
     while ($i < @$words) {
         my $word = $words->[$i];
         if ($word eq '--') {
             if ($i == $cword) {
                 $types[$i] = 'opt_name';
                 $i++; next;
             }
             $types[$i] = 'separator';
             for ($i+1 .. @$words-1) {
                 $types[$_] = 'arg,' . @argv;
                 push @argv, $words->[$_];
             }
             last;
         } elsif ($word =~ /\A-(\w*)\z/) {
             $types[$i] = 'opt_name';
             for (split '', $1) {
                 push @{ $opts{$_} }, undef;
             }
             $i++; next;
         } elsif ($word =~ /\A-([\w?])(.*)/) {
             $types[$i] = 'opt_name';
             # XXX currently not completing option value
             push @{ $opts{$1} }, $2;
             $i++; next;
         } elsif ($word =~ /\A--(\w[\w-]*)\z/) {
             $types[$i] = 'opt_name';
             my $opt = $1;
             $i++;
             if ($i < @$words) {
                 if ($words->[$i] eq '=') {
                     $types[$i] = 'separator';
                     $i++;
                 }
                 if ($words->[$i] =~ /\A-/) {
                     push @{ $opts{$opt} }, undef;
                     next;
                 }
                 $types[$i] = 'opt_val';
                 push @{ $opts{$opt} }, $words->[$i];
                 $i++; next;
             }
         } else {
             $types[$i] = 'arg,' . @argv;
             push @argv, $word;
             $i++; next;
         }
     }
 
     return {
         opts      => \%opts,
         argv      => \@argv,
         cword     => $cword,
         words     => $words,
         word_type => $types[$cword],
         #_types    => \@types,
     };
 }
 
 $SPEC{format_completion} = {
     v => 1.1,
     summary => 'Format completion for output (for shell)',
     description => <<'_',
 
 Bash accepts completion reply in the form of one entry per line to STDOUT. Some
 characters will need to be escaped. This function helps you do the formatting,
 with some options.
 
 This function accepts completion answer structure as described in the `Complete`
 POD. Aside from `words`, this function also recognizes these keys:
 
 * `as` (str): Either `string` (the default) or `array` (to return array of lines
   instead of the lines joined together). Returning array is useful if you are
   doing completion inside `Term::ReadLine`, for example, where the library
   expects an array.
 
 * `esc_mode` (str): Escaping mode for entries. Either `default` (most
   nonalphanumeric characters will be escaped), `shellvar` (like `default`, but
   dollar sign `$` will not be escaped, convenient when completing environment
   variables for example), `filename` (currently equals to `default`), `option`
   (currently equals to `default`), or `none` (no escaping will be done).
 
 * `path_sep` (str): If set, will enable "path mode", useful for
   completing/drilling-down path. Below is the description of "path mode".
 
   In shell, when completing filename (e.g. `foo`) and there is only a single
   possible completion (e.g. `foo` or `foo.txt`), the shell will display the
   completion in the buffer and automatically add a space so the user can move to
   the next argument. This is also true when completing other values like
   variables or program names.
 
   However, when completing directory (e.g. `/et` or `Downloads`) and there is
   solely a single completion possible and it is a directory (e.g. `/etc` or
   `Downloads`), the shell automatically adds the path separator character
   instead (`/etc/` or `Downloads/`). The user can press Tab again to complete
   for files/directories inside that directory, and so on. This is obviously more
   convenient compared to when shell adds a space instead.
 
   The `path_sep` option, when set, will employ a trick to mimic this behaviour.
   The trick is, if you have a completion array of `['foo/']`, it will be changed
   to `['foo/', 'foo/ ']` (the second element is the first element with added
   space at the end) to prevent bash from adding a space automatically.
 
   Path mode is not restricted to completing filesystem paths. Anything path-like
   can use it. For example when you are completing Java or Perl module name (e.g.
   `com.company.product.whatever` or `File::Spec::Unix`) you can use this mode
   (with `path_sep` appropriately set to, e.g. `.` or `::`).
 
 _
     args_as => 'array',
     args => {
         completion => {
             summary => 'Completion answer structure',
             description => <<'_',
 
 Either an array or hash. See function description for more details.
 
 _
             schema=>['any*' => of => ['hash*', 'array*']],
             req=>1,
             pos=>0,
         },
         opts => {
             schema=>'hash*',
             pos=>1,
         },
     },
     result => {
         summary => 'Formatted string (or array, if `as` is set to `array`)',
         schema => ['any*' => of => ['str*', 'array*']],
     },
     result_naked => 1,
 };
 sub format_completion {
     my ($hcomp, $opts) = @_;
 
     $opts //= {};
 
     $hcomp = {words=>$hcomp} unless ref($hcomp) eq 'HASH';
     my $comp     = $hcomp->{words};
     my $as       = $hcomp->{as} // 'string';
     # 'escmode' key is deprecated (Complete 0.11-) and will be removed later
     my $esc_mode = $hcomp->{esc_mode} // $hcomp->{escmode} // 'default';
     my $path_sep = $hcomp->{path_sep};
 
     if (defined($path_sep) && @$comp == 1) {
         my $re = qr/\Q$path_sep\E\z/;
         my $word;
         if (ref($comp->[0]) eq 'HASH') {
             $comp = [$comp->[0], {word=>"$comp->[0] "}] if
                 $comp->[0]{word} =~ $re;
         } else {
             $comp = [$comp->[0], "$comp->[0] "]
                 if $comp->[0] =~ $re;
         }
     }
 
     # XXX this is currently an ad-hoc solution, need to formulate a
     # name/interface for the more generic solution. since bash breaks words
     # differently than us (we only break using '" and whitespace, while bash
     # breaks using characters in $COMP_WORDBREAKS, by default is "'><=;|&(:),
     # this presents a problem we often encounter: if we want to provide with a
     # list of strings containing ':', most often Perl modules/packages, if user
     # types e.g. "Text::AN" and we provide completion ["Text::ANSI"] then bash
     # will change the word at cursor to become "Text::Text::ANSI" since it sees
     # the current word as "AN" and not "Text::AN". the workaround is to chop
     # /^Text::/ from completion answers. btw, we actually chop /^text::/i to
     # handle case-insensitive matching, although this does not have the ability
     # to replace the current word (e.g. if we type 'text::an' then bash can only
     # replace the current word 'an' with 'ANSI). also, we currently only
     # consider ':' since that occurs often.
     if (defined($opts->{word})) {
         if ($opts->{word} =~ s/(.+:)//) {
             my $prefix = $1;
             for (@$comp) {
                 if (ref($_) eq 'HASH') {
                     $_->{word} =~ s/\A\Q$prefix\E//i;
                 } else {
                     s/\A\Q$prefix\E//i;
                 }
             }
         }
     }
 
     my @res;
     for my $entry (@$comp) {
         my $word = ref($entry) eq 'HASH' ? $entry->{word} : $entry;
         if ($esc_mode eq 'shellvar') {
             # don't escape $
             $word =~ s!([^A-Za-z0-9,+._/\$~-])!\\$1!g;
         } elsif ($esc_mode eq 'none') {
             # no escaping
         } else {
             # default
             $word =~ s!([^A-Za-z0-9,+._/:~-])!\\$1!g;
         }
         push @res, $word;
     }
 
     if ($as eq 'array') {
         return \@res;
     } else {
         return join("", map {($_, "\n")} @res);
     }
 }
 
 1;
 # ABSTRACT: Completion module for bash shell
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Complete::Bash - Completion module for bash shell
 
 =head1 VERSION
 
 This document describes version 0.21 of Complete::Bash (from Perl distribution Complete-Bash), released on 2015-09-09.
 
 =head1 DESCRIPTION
 
 Bash allows completion to come from various sources. The simplest is from a list
 of words (C<-W>):
 
  % complete -W "one two three four" somecmd
  % somecmd t<Tab>
  two  three
 
 Another source is from a bash function (C<-F>). The function will receive input
 in two variables: C<COMP_WORDS> (array, command-line chopped into words) and
 C<COMP_CWORD> (integer, index to the array of words indicating the cursor
 position). It must set an array variable C<COMPREPLY> that contains the list of
 possible completion:
 
  % _foo()
  {
    local cur
    COMPREPLY=()
    cur=${COMP_WORDS[COMP_CWORD]}
    COMPREPLY=($( compgen -W '--help --verbose --version' -- $cur ) )
  }
  % complete -F _foo foo
  % foo <Tab>
  --help  --verbose  --version
 
 And yet another source is an external command (including, a Perl script). The
 command receives two environment variables: C<COMP_LINE> (string, raw
 command-line) and C<COMP_POINT> (integer, cursor location). Program must split
 C<COMP_LINE> into words, find the word to be completed, complete that, and
 return the list of words one per-line to STDOUT. An example:
 
  % cat foo-complete
  #!/usr/bin/perl
  use Complete::Bash qw(parse_cmdline format_completion);
  use Complete::Util qw(complete_array_elem);
  my ($words, $cword) = @{ parse_cmdline() };
  my $res = complete_array_elem(array=>[qw/--help --verbose --version/], word=>$words->[$cword]);
  print format_completion($res);
 
  % complete -C foo-complete foo
  % foo --v<Tab>
  --verbose --version
 
 This module provides routines for you to be doing the above.
 
 =head1 FUNCTIONS
 
 
 =head2 format_completion($completion, $opts) -> str|array
 
 Format completion for output (for shell).
 
 Bash accepts completion reply in the form of one entry per line to STDOUT. Some
 characters will need to be escaped. This function helps you do the formatting,
 with some options.
 
 This function accepts completion answer structure as described in the C<Complete>
 POD. Aside from C<words>, this function also recognizes these keys:
 
 =over
 
 =item * C<as> (str): Either C<string> (the default) or C<array> (to return array of lines
 instead of the lines joined together). Returning array is useful if you are
 doing completion inside C<Term::ReadLine>, for example, where the library
 expects an array.
 
 =item * C<esc_mode> (str): Escaping mode for entries. Either C<default> (most
 nonalphanumeric characters will be escaped), C<shellvar> (like C<default>, but
 dollar sign C<$> will not be escaped, convenient when completing environment
 variables for example), C<filename> (currently equals to C<default>), C<option>
 (currently equals to C<default>), or C<none> (no escaping will be done).
 
 =item * C<path_sep> (str): If set, will enable "path mode", useful for
 completing/drilling-down path. Below is the description of "path mode".
 
 In shell, when completing filename (e.g. C<foo>) and there is only a single
 possible completion (e.g. C<foo> or C<foo.txt>), the shell will display the
 completion in the buffer and automatically add a space so the user can move to
 the next argument. This is also true when completing other values like
 variables or program names.
 
 However, when completing directory (e.g. C</et> or C<Downloads>) and there is
 solely a single completion possible and it is a directory (e.g. C</etc> or
 C<Downloads>), the shell automatically adds the path separator character
 instead (C</etc/> or C<Downloads/>). The user can press Tab again to complete
 for files/directories inside that directory, and so on. This is obviously more
 convenient compared to when shell adds a space instead.
 
 The C<path_sep> option, when set, will employ a trick to mimic this behaviour.
 The trick is, if you have a completion array of C<['foo/']>, it will be changed
 to C<['foo/', 'foo/ ']> (the second element is the first element with added
 space at the end) to prevent bash from adding a space automatically.
 
 Path mode is not restricted to completing filesystem paths. Anything path-like
 can use it. For example when you are completing Java or Perl module name (e.g.
 C<com.company.product.whatever> or C<File::Spec::Unix>) you can use this mode
 (with C<path_sep> appropriately set to, e.g. C<.> or C<::>).
 
 =back
 
 Arguments ('*' denotes required arguments):
 
 =over 4
 
 =item * B<completion>* => I<hash|array>
 
 Completion answer structure.
 
 Either an array or hash. See function description for more details.
 
 =item * B<opts> => I<hash>
 
 =back
 
 Return value: Formatted string (or array, if `as` is set to `array`) (str|array)
 
 
 =head2 parse_cmdline($cmdline, $point) -> array
 
 Parse shell command-line for processing by completion routines.
 
 This function basically converts COMP_LINE (str) and COMP_POINT (int) into
 something like (but not exactly the same as) COMP_WORDS (array) and COMP_CWORD
 (int) that bash supplies to shell functions.
 
 The differences with bash are (these differences are mostly for parsing
 convenience for programs that use this routine):
 
 1) quotes and backslashes are stripped (bash's COMP_WORDS contains all the
 quotes and backslashes);
 
 2) variables are substituted with their values from environment variables except
 for the current word (COMP_WORDS[COMP_CWORD]) (bash does not perform variable
 substitution for COMP_WORDS). However, note that special shell variables that
 are not environment variables like C<$0>, C<$_>, C<$IFS> will not be replaced
 correctly because bash does not export those variables for us.
 
 3) tildes (~) are expanded with user's home directory except for the current
 word (bash does not perform tilde expansion for COMP_WORDS);
 
 4) no word-breaking characters aside from whitespaces and C<=> are currently used
 (bash uses COMP_WORDBREAKS which by default also include C<:>, C<;>, and so on).
 This is done for convenience of parsing of Getopt::Long-based applications. More
 word-breaking characters might be used in the future, e.g. when we want to
 handle complex bash statements like pipes, redirection, etc.
 
 Caveats:
 
 =over
 
 =item * Due to the way bash parses the command line, the two below are equivalent:
 
 % cmd --foo=bar
 % cmd --foo = bar
 
 =back
 
 Because they both expand to C<['--foo', '=', 'bar']>. But obviously
 C<Getopt::Long> does not regard the two as equivalent.
 
 Arguments ('*' denotes required arguments):
 
 =over 4
 
 =item * B<cmdline> => I<str>
 
 Command-line, defaults to COMP_LINE environment.
 
 =item * B<point> => I<int>
 
 Point/position to complete in command-line, defaults to COMP_POINT.
 
 =back
 
 Return value:  (array)
 
 
 Return a 2-element array: C<[$words, $cword]>. C<$words> is array of str,
 equivalent to C<COMP_WORDS> provided by bash to shell functions. C<$cword> is an
 integer, equivalent to C<COMP_CWORD> provided by bash to shell functions. The
 word to be completed is at C<< $words-E<gt>[$cword] >>.
 
 Note that COMP_LINE includes the command name. If you want the command-line
 arguments only (like in C<@ARGV>), you need to strip the first element from
 C<$words> and reduce C<$cword> by 1.
 
 
 =head2 parse_options(%args) -> [status, msg, result, meta]
 
 Parse command-line for options and arguments, more or less like Getopt::Long.
 
 Parse command-line into words using C<parse_cmdline()> then separate options and
 arguments. Since this routine does not accept C<Getopt::Long> (this routine is
 meant to be a generic option parsing of command-lines), it uses a few simple
 rules to server the common cases:
 
 =over
 
 =item * After C<-->, the rest of the words are arguments (just like Getopt::Long).
 
 =item * If we get something like C<-abc> (a single dash followed by several letters) it
 is assumed to be a bundle of short options.
 
 =item * If we get something like C<-MData::Dump> (a single dash, followed by a letter,
 followed by some letters I<and> non-letters/numbers) it is assumed to be an
 option (C<-M>) followed by a value.
 
 =item * If we get something like C<--foo> it is a long option. If the next word is an
 option (starts with a C<->) then it is assumed that this option does not have
 argument. Otherwise, the next word is assumed to be this option's value.
 
 =item * Otherwise, it is an argument (that is, permute is assumed).
 
 =back
 
 Arguments ('*' denotes required arguments):
 
 =over 4
 
 =item * B<cmdline> => I<str>
 
 Command-line, defaults to COMP_LINE environment.
 
 =item * B<cword> => I<array[str]>
 
 Alternative to passing `cmdline` and `point`.
 
 If you already did a C<parse_cmdline()>, you can pass the cword result (the
 second element) here to avoid calling C<parse_cmdline()> twice.
 
 =item * B<point> => I<int>
 
 Point/position to complete in command-line, defaults to COMP_POINT.
 
 =item * B<words> => I<array[str]>
 
 Alternative to passing `cmdline` and `point`.
 
 If you already did a C<parse_cmdline()>, you can pass the words result (the first
 element) here to avoid calling C<parse_cmdline()> twice.
 
 =back
 
 Returns an enveloped result (an array).
 
 First element (status) is an integer containing HTTP status code
 (200 means OK, 4xx caller error, 5xx function error). Second element
 (msg) is a string containing error message, or 'OK' if status is
 200. Third element (result) is optional, the actual result. Fourth
 element (meta) is called result metadata and is optional, a hash
 that contains extra information.
 
 Return value:  (hash)
 
 =head1 SEE ALSO (2)
 
 Other modules related to bash shell tab completion: L<Bash::Completion>,
 L<Getopt::Complete>. L<Term::Bash::Completion::Generator>
 
 Programmable Completion section in Bash manual:
 L<https://www.gnu.org/software/bash/manual/html_node/Programmable-Completion.html>
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Complete-Bash>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Complete-Bash>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Complete-Bash>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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 SEE ALSO
 
 
 L<Complete>
 
 =cut
### Complete/Env.pm ###
 package Complete::Env;
 
 our $DATE = '2015-09-17'; # DATE
 our $VERSION = '0.37'; # VERSION
 
 use 5.010001;
 use strict;
 use warnings;
 
 use Complete::Setting;
 
 require Exporter;
 our @ISA = qw(Exporter);
 our @EXPORT_OK = qw(
                        complete_env
                );
 
 our %SPEC;
 
 $SPEC{':package'} = {
     v => 1.1,
     summary => 'Completion routines related to environment variables',
 };
 
 $SPEC{complete_env} = {
     v => 1.1,
     summary => 'Complete from environment variables',
     description => <<'_',
 
 On Windows, environment variable names are all converted to uppercase. You can
 use case-insensitive option (`ci`) to match against original casing.
 
 _
     args => {
         word     => { schema=>[str=>{default=>''}], pos=>0, req=>1 },
         ci       => { schema=>['bool'] },
         fuzzy    => { schema=>['int*', min=>0] },
         map_case => { schema=>['bool'] },
     },
     result_naked => 1,
     result => {
         schema => 'array',
     },
 };
 sub complete_env {
     require Complete::Util;
 
     my %args  = @_;
     my $word     = $args{word} // "";
     my $ci       = $args{ci} // $Complete::Setting::OPT_CI;
     my $fuzzy    = $args{fuzzy} // $Complete::Setting::OPT_FUZZY;
     my $map_case = $args{map_case} // $Complete::Setting::OPT_MAP_CASE;
     if ($word =~ /^\$/) {
         Complete::Util::complete_array_elem(
             word=>$word, array=>[map {"\$$_"} keys %ENV],
             ci=>$ci, fuzzy=>$fuzzy, map_case=>$map_case);
     } else {
         Complete::Util::complete_array_elem(
             word=>$word, array=>[keys %ENV],
             ci=>$ci, fuzzy=>$fuzzy, map_case=>$map_case);
     }
 }
 1;
 # ABSTRACT: Completion routines related to environment variables
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Complete::Env - Completion routines related to environment variables
 
 =head1 VERSION
 
 This document describes version 0.37 of Complete::Env (from Perl distribution Complete-Env), released on 2015-09-17.
 
 =head1 DESCRIPTION
 
 =head1 FUNCTIONS
 
 
 =head2 complete_env(%args) -> array
 
 Complete from environment variables.
 
 On Windows, environment variable names are all converted to uppercase. You can
 use case-insensitive option (C<ci>) to match against original casing.
 
 Arguments ('*' denotes required arguments):
 
 =over 4
 
 =item * B<ci> => I<bool>
 
 =item * B<fuzzy> => I<int>
 
 =item * B<map_case> => I<bool>
 
 =item * B<word>* => I<str> (default: "")
 
 =back
 
 Return value:  (array)
 
 =head1 SEE ALSO
 
 L<Complete>
 
 Other C<Complete::*> modules.
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Complete-Env>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Complete-Env>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Complete-Env>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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
### Complete/File.pm ###
 package Complete::File;
 
 our $DATE = '2015-09-20'; # DATE
 our $VERSION = '0.37'; # VERSION
 
 use 5.010001;
 use strict;
 use warnings;
 
 use Complete::Setting;
 
 require Exporter;
 our @ISA = qw(Exporter);
 our @EXPORT_OK = qw(
                        complete_file
                );
 
 our %SPEC;
 
 $SPEC{':package'} = {
     v => 1.1,
     summary => 'Completion routines related to files',
 };
 
 $SPEC{complete_file} = {
     v => 1.1,
     summary => 'Complete file and directory from local filesystem',
     args_rels => {
         choose_one => [qw/filter file_regex_filter/],
     },
     args => {
         word => {
             schema  => [str=>{default=>''}],
             req     => 1,
             pos     => 0,
         },
         ci => {
             summary => 'Case-insensitive matching',
             schema  => 'bool',
         },
         fuzzy => {
             summary => 'Fuzzy matching',
             schema  => ['int*', min=>0],
         },
         map_case => {
             schema  => 'bool',
         },
         exp_im_path => {
             schema  => 'bool',
         },
         dig_leaf => {
             schema  => 'bool',
         },
         filter => {
             summary => 'Only return items matching this filter',
             description => <<'_',
 
 Filter can either be a string or a code.
 
 For string filter, you can specify a pipe-separated groups of sequences of these
 characters: f, d, r, w, x. Dash can appear anywhere in the sequence to mean
 not/negate. An example: `f` means to only show regular files, `-f` means only
 show non-regular files, `drwx` means to show only directories which are
 readable, writable, and executable (cd-able). `wf|wd` means writable regular
 files or writable directories.
 
 For code filter, you supply a coderef. The coderef will be called for each item
 with these arguments: `$name`. It should return true if it wants the item to be
 included.
 
 _
             schema  => ['any*' => {of => ['str*', 'code*']}],
         },
         file_regex_filter => {
             summary => 'Filter shortcut for file regex',
             description => <<'_',
 
 This is a shortcut for constructing a filter. So instead of using `filter`, you
 use this option. This will construct a filter of including only directories or
 regular files, and the file must match a regex pattern. This use-case is common.
 
 _
             schema => 're*',
         },
         starting_path => {
             schema  => 'str*',
             default => '.',
         },
         handle_tilde => {
             schema  => 'bool',
             default => 1,
         },
         allow_dot => {
             summary => 'If turned off, will not allow "." or ".." in path',
             description => <<'_',
 
 This is most useful when combined with `starting_path` option to prevent user
 going up/outside the starting path.
 
 _
             schema  => 'bool',
             default => 1,
         },
     },
     result_naked => 1,
     result => {
         schema => 'array',
     },
 };
 sub complete_file {
     require Complete::Path;
     require File::Glob;
 
     my %args   = @_;
     my $word   = $args{word} // "";
     my $ci          = $args{ci} // $Complete::Setting::OPT_CI;
     my $fuzzy       = $args{fuzzy} // $Complete::Setting::OPT_FUZZY;
     my $map_case    = $args{map_case} // $Complete::Setting::OPT_MAP_CASE;
     my $exp_im_path = $args{exp_im_path} // $Complete::Setting::OPT_EXP_IM_PATH;
     my $dig_leaf    = $args{dig_leaf} // $Complete::Setting::OPT_DIG_LEAF;
     my $handle_tilde = $args{handle_tilde} // 1;
     my $allow_dot   = $args{allow_dot} // 1;
     my $filter = $args{filter};
 
     # if word is starts with "~/" or "~foo/" replace it temporarily with user's
     # name (so we can restore it back at the end). this is to mimic bash
     # support. note that bash does not support case-insensitivity for "foo".
     my $result_prefix;
     my $starting_path = $args{starting_path} // '.';
     if ($handle_tilde && $word =~ s!\A(~[^/]*)/!!) {
         $result_prefix = "$1/";
         my @dir = File::Glob::glob($1); # glob will expand ~foo to /home/foo
         return [] unless @dir;
         $starting_path = $dir[0];
     } elsif ($allow_dot && $word =~ s!\A((?:\.\.?/+)+|/+)!!) {
         # just an optimization to skip sequences of '../'
         $starting_path = $1;
         $result_prefix = $1;
         $starting_path =~ s#/+\z## unless $starting_path =~ m!\A/!;
     }
 
     # bail if we don't allow dot and the path contains dot
     return [] if !$allow_dot &&
         $word =~ m!(?:\A|/)\.\.?(?:\z|/)!;
 
     # prepare list_func
     my $list = sub {
         my ($path, $intdir, $isint) = @_;
         opendir my($dh), $path or return undef;
         my @res;
         for (sort readdir $dh) {
             # skip . and .. if leaf is empty, like in bash
             next if ($_ eq '.' || $_ eq '..') && $intdir eq '';
             next if $isint && !(-d "$path/$_");
             push @res, $_;
         }
         \@res;
     };
 
     # prepare filter_func
     if ($filter && !ref($filter)) {
         my @seqs = split /\s*\|\s*/, $filter;
         $filter = sub {
             my $name = shift;
             my @st = stat($name) or return 0;
             my $mode = $st[2];
             my $pass;
           SEQ:
             for my $seq (@seqs) {
                 my $neg = sub { $_[0] };
                 for my $c (split //, $seq) {
                     if    ($c eq '-') { $neg = sub { $_[0] ? 0 : 1 } }
                     elsif ($c eq 'r') { next SEQ unless $neg->($mode & 0400) }
                     elsif ($c eq 'w') { next SEQ unless $neg->($mode & 0200) }
                     elsif ($c eq 'x') { next SEQ unless $neg->($mode & 0100) }
                     elsif ($c eq 'f') { next SEQ unless $neg->($mode & 0100000)}
                     elsif ($c eq 'd') { next SEQ unless $neg->($mode & 0040000)}
                     else {
                         die "Unknown character in filter: $c (in $seq)";
                     }
                 }
                 $pass = 1; last SEQ;
             }
             $pass;
         };
     } elsif (!$filter && $args{file_regex_filter}) {
         $filter = sub {
             my $name = shift;
             return 1 if -d $name;
             return 0 unless -f _;
             return 1 if $name =~ $args{file_regex_filter};
             0;
         };
     }
 
     Complete::Path::complete_path(
         word => $word,
 
         ci => $ci,
         fuzzy => $fuzzy,
         map_case => $map_case,
         exp_im_path => $exp_im_path,
         dig_leaf => $dig_leaf,
 
         list_func => $list,
         is_dir_func => sub { -d $_[0] },
         filter_func => $filter,
         starting_path => $starting_path,
         result_prefix => $result_prefix,
     );
 }
 
 1;
 # ABSTRACT: Completion routines related to files
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Complete::File - Completion routines related to files
 
 =head1 VERSION
 
 This document describes version 0.37 of Complete::File (from Perl distribution Complete-File), released on 2015-09-20.
 
 =head1 DESCRIPTION
 
 =head1 FUNCTIONS
 
 
 =head2 complete_file(%args) -> array
 
 Complete file and directory from local filesystem.
 
 Arguments ('*' denotes required arguments):
 
 =over 4
 
 =item * B<allow_dot> => I<bool> (default: 1)
 
 If turned off, will not allow "." or ".." in path.
 
 This is most useful when combined with C<starting_path> option to prevent user
 going up/outside the starting path.
 
 =item * B<ci> => I<bool>
 
 Case-insensitive matching.
 
 =item * B<dig_leaf> => I<bool>
 
 =item * B<exp_im_path> => I<bool>
 
 =item * B<file_regex_filter> => I<re>
 
 Filter shortcut for file regex.
 
 This is a shortcut for constructing a filter. So instead of using C<filter>, you
 use this option. This will construct a filter of including only directories or
 regular files, and the file must match a regex pattern. This use-case is common.
 
 =item * B<filter> => I<str|code>
 
 Only return items matching this filter.
 
 Filter can either be a string or a code.
 
 For string filter, you can specify a pipe-separated groups of sequences of these
 characters: f, d, r, w, x. Dash can appear anywhere in the sequence to mean
 not/negate. An example: C<f> means to only show regular files, C<-f> means only
 show non-regular files, C<drwx> means to show only directories which are
 readable, writable, and executable (cd-able). C<wf|wd> means writable regular
 files or writable directories.
 
 For code filter, you supply a coderef. The coderef will be called for each item
 with these arguments: C<$name>. It should return true if it wants the item to be
 included.
 
 =item * B<fuzzy> => I<int>
 
 Fuzzy matching.
 
 =item * B<handle_tilde> => I<bool> (default: 1)
 
 =item * B<map_case> => I<bool>
 
 =item * B<starting_path> => I<str> (default: ".")
 
 =item * B<word>* => I<str> (default: "")
 
 =back
 
 Return value:  (array)
 
 =head1 SEE ALSO
 
 L<Complete>
 
 Other C<Complete::*> modules.
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Complete-File>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Complete-File>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Complete-File>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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
### Complete/Fish.pm ###
 package Complete::Fish;
 
 our $DATE = '2015-09-09'; # DATE
 our $VERSION = '0.04'; # VERSION
 
 use 5.010001;
 use strict;
 use warnings;
 
 require Exporter;
 our @ISA = qw(Exporter);
 our @EXPORT_OK = qw(
                        format_completion
                );
 
 require Complete::Bash;
 
 our %SPEC;
 
 $SPEC{':package'} = {
     v => 1.1,
     summary => 'Completion module for fish shell',
 };
 
 $SPEC{parse_cmdline} = {
     v => 1.1,
     summary => 'Parse shell command-line for processing by completion routines',
     description => <<'_',
 
 This function converts COMMAND_LINE (str) given by tcsh to become something like
 COMP_WORDS (array) and COMP_CWORD (int), like what bash supplies to shell
 functions. Currently implemented using `Complete::Bash`'s `parse_cmdline`.
 
 _
     args_as => 'array',
     args => {
         cmdline => {
             summary => 'Command-line, defaults to COMMAND_LINE environment',
             schema => 'str*',
             pos => 0,
         },
     },
     result => {
         schema => ['array*', len=>2],
         description => <<'_',
 
 Return a 2-element array: `[$words, $cword]`. `$words` is array of str,
 equivalent to `COMP_WORDS` provided by bash to shell functions. `$cword` is an
 integer, equivalent to `COMP_CWORD` provided by bash to shell functions. The
 word to be completed is at `$words->[$cword]`.
 
 Note that COMP_LINE includes the command name. If you want the command-line
 arguments only (like in `@ARGV`), you need to strip the first element from
 `$words` and reduce `$cword` by 1.
 
 _
     },
     result_naked => 1,
 };
 sub parse_cmdline {
     my ($line) = @_;
 
     $line //= $ENV{COMMAND_LINE};
     Complete::Bash::parse_cmdline($line, length($line));
 }
 
 $SPEC{format_completion} = {
     v => 1.1,
     summary => 'Format completion for output (for shell)',
     description => <<'_',
 
 fish accepts completion reply in the form of one entry per line to STDOUT.
 Description can be added to each entry, prefixed by tab character.
 
 _
     args_as => 'array',
     args => {
         completion => {
             summary => 'Completion answer structure',
             description => <<'_',
 
 Either an array or hash, as described in `Complete`.
 
 _
             schema=>['any*' => of => ['hash*', 'array*']],
             req=>1,
             pos=>0,
         },
     },
     result => {
         summary => 'Formatted string (or array, if `as` key is set to `array`)',
         schema => ['any*' => of => ['str*', 'array*']],
     },
     result_naked => 1,
 };
 sub format_completion {
     my $comp = shift;
 
     my $as;
     my $entries;
 
     # we currently use Complete::Bash's rule because i haven't done a read up on
     # how exactly fish escaping rules are.
     if (ref($comp) eq 'HASH') {
         $as = $comp->{as} // 'string';
         $entries = Complete::Bash::format_completion({%$comp, as=>'array'});
     } else {
         $as = 'string';
         $entries = Complete::Bash::format_completion({
             words=>$comp, as=>'array',
         });
     }
 
     # insert description
     {
         my $compary = ref($comp) eq 'HASH' ? $comp->{words} : $comp;
         for (my $i=0; $i<@$compary; $i++) {
 
             my $desc = (ref($compary->[$i]) eq 'HASH' ?
                             $compary->[$i]{description} : '' ) // '';
             $desc =~ s/\R/ /g;
             $entries->[$i] .= "\t$desc";
         }
     }
 
     # turn back to string if that's what the user wants
     if ($as eq 'string') {
         $entries = join("", map{"$_\n"} @$entries);
     }
     $entries;
 }
 
 1;
 # ABSTRACT: Completion module for fish shell
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Complete::Fish - Completion module for fish shell
 
 =head1 VERSION
 
 This document describes version 0.04 of Complete::Fish (from Perl distribution Complete-Fish), released on 2015-09-09.
 
 =head1 DESCRIPTION
 
 fish allows completion of option arguments to come from an external command,
 e.g.:
 
  % complete -c deluser -l user -d Username -a "(cat /etc/passwd|cut -d : -f 1)"
 
 The command is supposed to return completion entries one in a separate line.
 Description for each entry can be added, prefixed with a tab character. The
 provided function C<format_completion()> accept a completion answer structure
 and format it for fish. Example:
 
  format_completion(["a", "b", {word=>"c", description=>"Another letter"}])
 
 will result in:
 
  a
  b
  c       Another letter
 
 =head1 FUNCTIONS
 
 
 =head2 format_completion($completion) -> str|array
 
 Format completion for output (for shell).
 
 fish accepts completion reply in the form of one entry per line to STDOUT.
 Description can be added to each entry, prefixed by tab character.
 
 Arguments ('*' denotes required arguments):
 
 =over 4
 
 =item * B<completion>* => I<hash|array>
 
 Completion answer structure.
 
 Either an array or hash, as described in C<Complete>.
 
 =back
 
 Return value: Formatted string (or array, if `as` key is set to `array`) (str|array)
 
 
 =head2 parse_cmdline($cmdline) -> array
 
 Parse shell command-line for processing by completion routines.
 
 This function converts COMMAND_LINE (str) given by tcsh to become something like
 COMP_WORDS (array) and COMP_CWORD (int), like what bash supplies to shell
 functions. Currently implemented using C<Complete::Bash>'s C<parse_cmdline>.
 
 Arguments ('*' denotes required arguments):
 
 =over 4
 
 =item * B<cmdline> => I<str>
 
 Command-line, defaults to COMMAND_LINE environment.
 
 =back
 
 Return value:  (array)
 
 
 Return a 2-element array: C<[$words, $cword]>. C<$words> is array of str,
 equivalent to C<COMP_WORDS> provided by bash to shell functions. C<$cword> is an
 integer, equivalent to C<COMP_CWORD> provided by bash to shell functions. The
 word to be completed is at C<< $words-E<gt>[$cword] >>.
 
 Note that COMP_LINE includes the command name. If you want the command-line
 arguments only (like in C<@ARGV>), you need to strip the first element from
 C<$words> and reduce C<$cword> by 1.
 
 =head1 SEE ALSO
 
 L<Complete>
 
 L<Complete::Bash>
 
 Fish manual.
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Complete-Fish>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Complete-Fish>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Complete-Fish>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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
### Complete/Getopt/Long.pm ###
 package Complete::Getopt::Long;
 
 our $DATE = '2015-09-22'; # DATE
 our $VERSION = '0.37'; # VERSION
 
 use 5.010001;
 use strict;
 use warnings;
 use Log::Any::IfLOG '$log';
 
 require Exporter;
 our @ISA = qw(Exporter);
 our @EXPORT_OK = qw(
                        complete_cli_arg
                );
 
 our %SPEC;
 
 sub _default_completion {
     require Complete::Env;
     require Complete::File;
     require Complete::Util;
 
     my %args = @_;
     my $word = $args{word} // '';
 
     my $fres;
     $log->tracef('[comp][compgl] entering default completion routine');
 
     # try completing '$...' with shell variables
     if ($word =~ /\A\$/) {
         $log->tracef('[comp][compgl] completing shell variable');
         {
             my $compres = Complete::Env::complete_env(
                 word=>$word);
             last unless @$compres;
             $fres = {words=>$compres, esc_mode=>'shellvar'};
             goto RETURN_RES;
         }
         # if empty, fallback to searching file
     }
 
     # try completing '~foo' with user dir (appending / if user's home exists)
     if ($word =~ m!\A~([^/]*)\z!) {
         $log->tracef("[comp][compgl] completing userdir, user=%s", $1);
         {
             eval { require Unix::Passwd::File };
             last if $@;
             my $res = Unix::Passwd::File::list_users(detail=>1);
             last unless $res->[0] == 200;
             my $compres = Complete::Util::complete_array_elem(
                 array=>[map {"~" . $_->{user} . ((-d $_->{home}) ? "/":"")}
                             @{ $res->[2] }],
                 word=>$word,
             );
             last unless @$compres;
             $fres = {words=>$compres, path_sep=>'/'};
             goto RETURN_RES;
         }
         # if empty, fallback to searching file
     }
 
     # try completing '~/blah' or '~foo/blah' as if completing file, but do not
     # expand ~foo (this is supported by complete_file(), so we just give it off
     # to the routine)
     if ($word =~ m!\A(~[^/]*)/!) {
         $log->tracef("[comp][compgl] completing file, path=<%s>", $word);
         $fres = {words=>Complete::File::complete_file(word=>$word),
                  path_sep=>'/'};
         goto RETURN_RES;
     }
 
     # try completing something that contains wildcard with glob. for
     # convenience, we add '*' at the end so that when user type [AB] it is
     # treated like [AB]*.
     require String::Wildcard::Bash;
     if (String::Wildcard::Bash::contains_wildcard($word)) {
         $log->tracef("[comp][compgl] completing with wildcard glob, glob=<%s>", "$word*");
         {
             my $compres = [glob("$word*")];
             last unless @$compres;
             for (@$compres) {
                 $_ .= "/" if (-d $_);
             }
             $fres = {words=>$compres, path_sep=>'/'};
             goto RETURN_RES;
         }
         # if empty, fallback to searching file
     }
     $log->tracef("[comp][compgl] completing with file, file=<%s>", $word);
     $fres = {words=>Complete::File::complete_file(word=>$word),
              path_sep=>'/'};
   RETURN_RES:
     $log->tracef("[comp][compgl] leaving default completion routine, result=%s", $fres);
     $fres;
 }
 
 # return the key/element if $opt matches exactly a key/element in $opts (which
 # can be an array/hash) OR expands unambiguously to exactly one key/element in
 # $opts, otherwise return undef. e.g. _expand1('--fo', [qw/--foo --bar --baz
 # --fee --feet/]) and _expand('--fee', ...) will respectively return '--foo' and
 # '--fee' because it expands/is unambiguous in the list, but _expand1('--ba',
 # ...) or _expand1('--qux', ...) will both return undef because '--ba' expands
 # ambiguously (--bar/--baz) while '--qux' cannot be expanded.
 sub _expand1 {
     my ($opt, $opts) = @_;
     my @candidates;
     my $is_hash = ref($opts) eq 'HASH';
     for ($is_hash ? (sort {length($a)<=>length($b)} keys %$opts) : @$opts) {
         next unless index($_, $opt) == 0;
         push @candidates, $is_hash ? $opts->{$_} : $_;
         last if $opt eq $_;
     }
     return @candidates == 1 ? $candidates[0] : undef;
 }
 
 # mark an option (and all its aliases) as seen
 sub _mark_seen {
     my ($seen_opts, $opt, $opts) = @_;
     my $opthash = $opts->{$opt};
     return unless $opthash;
     my $ospec = $opthash->{ospec};
     for (keys %$opts) {
         my $v = $opts->{$_};
         $seen_opts->{$_}++ if $v->{ospec} eq $ospec;
     }
 }
 
 $SPEC{complete_cli_arg} = {
     v => 1.1,
     summary => 'Complete command-line argument using '.
         'Getopt::Long specification',
     description => <<'_',
 
 This routine can complete option names, where the option names are retrieved
 from `Getopt::Long` specification. If you provide completion routine in
 `completion`, you can also complete _option values_ and _arguments_.
 
 Note that this routine does not use `Getopt::Long` (it does its own parsing) and
 currently is not affected by Getopt::Long's configuration. Its behavior mimics
 Getopt::Long under these configuration: `no_ignore_case`, `bundling` (or
 `no_bundling` if the `bundling` option is turned off). Which I think is the
 sensible default. This routine also does not currently support `auto_help` and
 `auto_version`, so you'll need to add those options specifically if you want to
 recognize `--help/-?` and `--version`, respectively.
 
 _
     args => {
         getopt_spec => {
             summary => 'Getopt::Long specification',
             schema  => 'hash*',
             req     => 1,
         },
         completion => {
             summary     =>
                 'Completion routine to complete option value/argument',
             schema      => 'code*',
             description => <<'_',
 
 Completion code will receive a hash of arguments (`%args`) containing these
 keys:
 
 * `type` (str, what is being completed, either `optval`, or `arg`)
 * `word` (str, word to be completed)
 * `cword` (int, position of words in the words array, starts from 0)
 * `opt` (str, option name, e.g. `--str`; undef if we're completing argument)
 * `ospec` (str, Getopt::Long option spec, e.g. `str|S=s`; undef when completing
   argument)
 * `argpos` (int, argument position, zero-based; undef if type='optval')
 * `nth` (int, the number of times this option has seen before, starts from 0
   that means this is the first time this option has been seen; undef when
   type='arg')
 * `seen_opts` (hash, all the options seen in `words`)
 * `parsed_opts` (hash, options parsed the standard/raw way)
 
 as well as all keys from `extras` (but these won't override the above keys).
 
 and is expected to return a completion answer structure as described in
 `Complete` which is either a hash or an array. The simplest form of answer is
 just to return an array of strings. The various `complete_*` function like those
 in `Complete::Util` or the other `Complete::*` modules are suitable to use here.
 
 Completion routine can also return undef to express declination, in which case
 the default completion routine will then be consulted. The default routine
 completes from shell environment variables (`$FOO`), Unix usernames (`~foo`),
 and files/directories.
 
 Example:
 
     use Complete::Unix qw(complete_user);
     use Complete::Util qw(complete_array_elem);
     complete_cli_arg(
         getopt_spec => {
             'help|h'   => sub{...},
             'format=s' => \$format,
             'user=s'   => \$user,
         },
         completion  => sub {
             my %args  = @_;
             my $word  = $args{word};
             my $ospec = $args{ospec};
             if ($ospec && $ospec eq 'format=s') {
                 complete_array_elem(array=>[qw/json text xml yaml/], word=>$word);
             } else {
                 complete_user(word=>$word);
             }
         },
     );
 
 _
         },
         words => {
             summary     => 'Command line arguments, like @ARGV',
             description => <<'_',
 
 See function `parse_cmdline` in `Complete::Bash` on how to produce this (if
 you're using bash).
 
 _
             schema      => 'array*',
             req         => 1,
         },
         cword => {
             summary     =>
                 "Index in words of the word we're trying to complete",
             description => <<'_',
 
 See function `parse_cmdline` in `Complete::Bash` on how to produce this (if
 you're using bash).
 
 _
             schema      => 'int*',
             req         => 1,
         },
         extras => {
             summary => 'Add extra arguments to completion routine',
             schema  => 'hash',
             description => <<'_',
 
 The keys from this `extras` hash will be merged into the final `%args` passed to
 completion routines. Note that standard keys like `type`, `word`, and so on as
 described in the function description will not be overwritten by this.
 
 _
         },
         bundling => {
             schema  => 'bool*',
             default => 1,
             'summary.alt.bool.not' => 'Turn off bundling',
             description => <<'_',
 
 If you turn off bundling, completion of short-letter options won't support
 bundling (e.g. `-b<tab>` won't add more single-letter options), but single-dash
 multiletter options can be recognized. Currently only those specified with a
 single dash will be completed. For example if you have `-foo=s` in your option
 specification, `-f<tab>` can complete it.
 
 This can be used to complete old-style programs, e.g. emacs which has options
 like `-nw`, `-nbc` etc (but also have double-dash options like
 `--no-window-system` or `--no-blinking-cursor`).
 
 _
         },
     },
     result_naked => 1,
     result => {
         schema => ['any*' => of => ['hash*', 'array*']],
         description => <<'_',
 
 You can use `format_completion` function in `Complete::Bash` module to format
 the result of this function for bash.
 
 _
     },
 };
 sub complete_cli_arg {
     require Complete::Util;
     require Getopt::Long::Util;
 
     my %args = @_;
 
     my $fname = __PACKAGE__ . "::complete_cli_arg"; # XXX use __SUB__
     my $fres;
 
     $args{words} or die "Please specify words";
     my @words = @{ $args{words} };
     defined(my $cword = $args{cword}) or die "Please specify cword";
     my $gospec = $args{getopt_spec} or die "Please specify getopt_spec";
     my $comp = $args{completion};
     my $extras = $args{extras} // {};
     my $bundling = $args{bundling} // 1;
     my %parsed_opts;
 
     $log->tracef('[comp][compgl] entering %s(), words=%s, cword=%d, word=<%s>',
                  $fname, \@words, $cword, $words[$cword]);
 
     # parse all options first & supply default completion routine
     my %opts;
     for my $ospec (keys %$gospec) {
         my $res = Getopt::Long::Util::parse_getopt_long_opt_spec($ospec)
             or die "Can't parse option spec '$ospec'";
         $res->{min_vals} //= $res->{type} ? 1 : 0;
         $res->{max_vals} //= $res->{type} || $res->{opttype} ? 1:0;
         for my $o0 (@{ $res->{opts} }) {
             my @o = $res->{is_neg} && length($o0) > 1 ?
                 ($o0, "no$o0", "no-$o0") : ($o0);
             for my $o (@o) {
                 my $k = length($o)==1 ||
                     (!$bundling && $res->{dash_prefix} eq '-') ?
                         "-$o" : "--$o";
                 $opts{$k} = {
                     name => $k,
                     ospec => $ospec, # key to getopt specification
                     parsed => $res,
                 };
             }
         }
     }
     my @optnames = sort keys %opts;
 
     my %seen_opts;
 
     # for each word, we try to find out whether it's supposed to complete option
     # name, or option value, or argument, or separator (or more than one of
     # them). plus some other information.
     my @expects;
 
     my $i = -1;
     my $argpos = 0;
 
   WORD:
     while (1) {
         last WORD if ++$i >= @words;
         my $word = $words[$i];
         #say "D:i=$i, word=$word, ~~@words=",~~@words;
 
         if ($word eq '--' && $i != $cword) {
             $expects[$i] = {separator=>1};
             while (1) {
                 $i++;
                 last WORD if $i >= @words;
                 $expects[$i] = {arg=>1, argpos=>$argpos++};
             }
         }
 
         if ($word =~ /\A-/) {
 
             # split bundled short options
           SPLIT_BUNDLED:
             {
                 last unless $bundling;
                 my $shorts = $word;
                 if ($shorts =~ s/\A-([^-])(.*)/$2/) {
                     my $opt = "-$1";
                     my $opthash = $opts{$opt};
                     if (!$opthash || $opthash->{parsed}{max_vals}) {
                         last SPLIT_BUNDLED;
                     }
                     $words[$i] = $word = "-$1";
                     $expects[$i]{prefix} = $word;
                     $expects[$i]{word} = '';
                     $expects[$i]{short_only} = 1;
                     my $len_before_split = @words;
                     my $j = $i+1;
                   SHORTOPT:
                     while ($shorts =~ s/(.)//) {
                         $opt = "-$1";
                         $opthash = $opts{$opt};
                         if (!$opthash || $opthash->{parsed}{max_vals}) {
                             # end after unknown short option or short option
                             # expects value, and don't complete this optname
                             # later
                             $expects[$i]{do_complete_optname} = 0;
                             if (length $shorts) {
                                 splice @words, $j, 0, $opt, '=', $shorts;
                                 $j += 3;
                             } else {
                                 splice @words, $j, 0, $opt;
                                 $j++;
                             }
                             last SHORTOPT;
                         } else {
                             splice @words, $j, 0, $opt;
                             $j++;
                             # continue splitting
                         }
                     }
                     $cword += @words-$len_before_split if $cword > $i;
                     #say "D:words increases ", @words-$len_before_split;
                 }
             }
 
             # split --foo=val -> --foo, =, val
           SPLIT_EQUAL:
             {
                 if ($word =~ /\A(--?[^=]+)(=)(.*)/) {
                     splice @words, $i, 1, $1, $2, $3;
                     $word = $1;
                     $cword += 2 if $cword >= $i;
                 }
             }
 
             my $opt = $word;
             my $opthash = _expand1($opt, \%opts);
 
             if ($opthash) {
                 $opt = $opthash->{name};
                 $expects[$i]{optname} = $opt;
                 my $nth = $seen_opts{$opt} // 0;
                 $expects[$i]{nth} = $nth;
                 _mark_seen(\%seen_opts, $opt, \%opts);
 
                 my $min_vals = $opthash->{parsed}{min_vals};
                 my $max_vals = $opthash->{parsed}{max_vals};
                 #say "D:min_vals=$min_vals, max_vals=$max_vals";
 
                 # detect = after --opt
                 if ($i+1 < @words && $words[$i+1] eq '=') {
                     $i++;
                     $expects[$i] = {separator=>1, optval=>$opt, word=>'', nth=>$nth};
                     # force a value due to =
                     if (!$max_vals) { $min_vals = $max_vals = 1 }
                 }
 
                 push @{ $parsed_opts{$opt} }, $words[$i+1];
                 for (1 .. $min_vals) {
                     $i++;
                     last WORD if $i >= @words;
                     $expects[$i]{optval} = $opt;
                     $expects[$i]{nth} = $nth;
                 }
                 for (1 .. $max_vals-$min_vals) {
                     last if $i+$_ >= @words;
                     last if $words[$i+$_] =~ /\A-/; # a new option
                     $expects[$i+$_]{optval} = $opt; # but can also be optname
                     $expects[$i]{nth} = $nth;
                 }
             } else {
                 # an unknown option, assume it doesn't require argument, unless
                 # it's --opt= or --opt=foo
                 $opt = undef;
                 $expects[$i]{optname} = $opt;
 
                 # detect = after --opt
                 if ($i+1 < @words && $words[$i+1] eq '=') {
                     $i++;
                     $expects[$i] = {separator=>1, optval=>undef, word=>''};
                     if ($i+1 < @words) {
                         $i++;
                         $expects[$i]{optval} = $opt;
                     }
                 }
             }
         } else {
             $expects[$i]{optname} = '';
             $expects[$i]{arg} = 1;
             $expects[$i]{argpos} = $argpos++;
         }
     }
 
     #use DD; print "D:words: "; dd \@words;
     #say "D:cword: $cword";
     #use DD; print "D:expects: "; dd \@expects;
     #use DD; print "D:seen_opts: "; dd \%seen_opts;
     #use DD; print "D:parsed_opts: "; dd \%parsed_opts;
 
     my $exp = $expects[$cword];
     my $word = $exp->{word} // $words[$cword];
 
     my @answers;
 
     # complete option names
     {
         last unless exists $exp->{optname};
         last if defined($exp->{do_complete_optname}) &&
             !$exp->{do_complete_optname};
         my $opt = $exp->{optname};
         my @o;
         for (@optnames) {
             #say "D:$_";
             my $repeatable = 0;
             next if $exp->{short_only} && /\A--/;
             if ($seen_opts{$_}) {
                 my $opthash = $opts{$_};
                 my $ospecval = $gospec->{$opthash->{ospec}};
                 my $parsed = $opthash->{parsed};
                 if (ref($ospecval) eq 'ARRAY') {
                     $repeatable = 1;
                 } elsif ($parsed->{desttype} || $parsed->{is_inc}) {
                     $repeatable = 1;
                 }
             }
             # skip options that have been specified and not repeatable
             #use DD; dd {'$_'=>$_, seen=>$seen_opts{$_}, repeatable=>$repeatable, opt=>$opt};
             next if $seen_opts{$_} && !$repeatable && (
                 # long option has been specified
                 (!$opt || $opt ne $_) ||
                      # short option (in a bundle) has been specified
                     (defined($exp->{prefix}) &&
                          index($exp->{prefix}, substr($opt, 1, 1)) >= 0));
             if (defined $exp->{prefix}) {
                 my $o = $_; $o =~ s/\A-//;
                 push @o, "$exp->{prefix}$o";
             } else {
                 push @o, $_;
             }
         }
         #use DD; dd \@o;
         my $compres = Complete::Util::complete_array_elem(
             array => \@o, word => $word);
         $log->tracef('[comp][compgl] adding result from option names, '.
                          'matching options=%s', $compres);
         push @answers, $compres;
         if (!exists($exp->{optval}) && !exists($exp->{arg})) {
             $fres = {words=>$compres, esc_mode=>'option'};
             goto RETURN_RES;
         }
     }
 
     # complete option value
     {
         last unless exists($exp->{optval});
         my $opt = $exp->{optval};
         my $opthash = $opts{$opt} if $opt;
         my %compargs = (
             %$extras,
             type=>'optval', words=>\@words, cword=>$args{cword},
             word=>$word, opt=>$opt, ospec=>$opthash->{ospec},
             argpos=>undef, nth=>$exp->{nth}, seen_opts=>\%seen_opts,
             parsed_opts=>\%parsed_opts,
         );
         my $compres;
         if ($comp) {
             $log->tracef("[comp][compgl] invoking routine supplied from 'completion' argument to complete option value, option=<%s>", $opt);
             $compres = $comp->(%compargs);
             $log->tracef('[comp][compgl] adding result from routine: %s', $compres);
         }
         if (!$compres || !$comp) {
             $compres = _default_completion(%compargs);
             $log->tracef('[comp][compgl] adding result from default '.
                              'completion routine');
         }
         push @answers, $compres;
     }
 
     # complete argument
     {
         last unless exists($exp->{arg});
         my %compargs = (
             %$extras,
             type=>'arg', words=>\@words, cword=>$args{cword},
             word=>$word, opt=>undef, ospec=>undef,
             argpos=>$exp->{argpos}, seen_opts=>\%seen_opts,
             parsed_opts=>\%parsed_opts,
         );
         $log->tracef('[comp][compgl] invoking \'completion\' routine '.
                          'to complete argument');
         my $compres = $comp->(%compargs);
         if (!defined $compres) {
             $compres = _default_completion(%compargs);
             $log->tracef('[comp][compgl] adding result from default '.
                              'completion routine: %s', $compres);
         }
         push @answers, $compres;
     }
 
     $log->tracef("[comp][compgl] combining result from %d source(s)", ~~@answers);
     $fres = Complete::Util::combine_answers(@answers) // [];
 
   RETURN_RES:
     $log->tracef("[comp][compgl] leaving %s(), result=%s", $fname, $fres);
     $fres;
 }
 
 1;
 # ABSTRACT: Complete command-line argument using Getopt::Long specification
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Complete::Getopt::Long - Complete command-line argument using Getopt::Long specification
 
 =head1 VERSION
 
 This document describes version 0.37 of Complete::Getopt::Long (from Perl distribution Complete-Getopt-Long), released on 2015-09-22.
 
 =head1 SYNOPSIS
 
 See L<Getopt::Long::Complete> for an easy way to use this module.
 
 =head1 DESCRIPTION
 
 Note that I deliberately do not support C<ci> (case-insensitive) option here.
 Options that differ only in case often are often and they mean different things.
 
 =head1 FUNCTIONS
 
 
 =head2 complete_cli_arg(%args) -> hash|array
 
 Complete command-line argument using Getopt::Long specification.
 
 This routine can complete option names, where the option names are retrieved
 from C<Getopt::Long> specification. If you provide completion routine in
 C<completion>, you can also complete I<option values> and I<arguments>.
 
 Note that this routine does not use C<Getopt::Long> (it does its own parsing) and
 currently is not affected by Getopt::Long's configuration. Its behavior mimics
 Getopt::Long under these configuration: C<no_ignore_case>, C<bundling> (or
 C<no_bundling> if the C<bundling> option is turned off). Which I think is the
 sensible default. This routine also does not currently support C<auto_help> and
 C<auto_version>, so you'll need to add those options specifically if you want to
 recognize C<--help/-?> and C<--version>, respectively.
 
 Arguments ('*' denotes required arguments):
 
 =over 4
 
 =item * B<bundling> => I<bool> (default: 1)
 
 If you turn off bundling, completion of short-letter options won't support
 bundling (e.g. C<< -bE<lt>tabE<gt> >> won't add more single-letter options), but single-dash
 multiletter options can be recognized. Currently only those specified with a
 single dash will be completed. For example if you have C<-foo=s> in your option
 specification, C<< -fE<lt>tabE<gt> >> can complete it.
 
 This can be used to complete old-style programs, e.g. emacs which has options
 like C<-nw>, C<-nbc> etc (but also have double-dash options like
 C<--no-window-system> or C<--no-blinking-cursor>).
 
 =item * B<completion> => I<code>
 
 Completion routine to complete option value/argument.
 
 Completion code will receive a hash of arguments (C<%args>) containing these
 keys:
 
 =over
 
 =item * C<type> (str, what is being completed, either C<optval>, or C<arg>)
 
 =item * C<word> (str, word to be completed)
 
 =item * C<cword> (int, position of words in the words array, starts from 0)
 
 =item * C<opt> (str, option name, e.g. C<--str>; undef if we're completing argument)
 
 =item * C<ospec> (str, Getopt::Long option spec, e.g. C<str|S=s>; undef when completing
 argument)
 
 =item * C<argpos> (int, argument position, zero-based; undef if type='optval')
 
 =item * C<nth> (int, the number of times this option has seen before, starts from 0
 that means this is the first time this option has been seen; undef when
 type='arg')
 
 =item * C<seen_opts> (hash, all the options seen in C<words>)
 
 =item * C<parsed_opts> (hash, options parsed the standard/raw way)
 
 =back
 
 as well as all keys from C<extras> (but these won't override the above keys).
 
 and is expected to return a completion answer structure as described in
 C<Complete> which is either a hash or an array. The simplest form of answer is
 just to return an array of strings. The various C<complete_*> function like those
 in C<Complete::Util> or the other C<Complete::*> modules are suitable to use here.
 
 Completion routine can also return undef to express declination, in which case
 the default completion routine will then be consulted. The default routine
 completes from shell environment variables (C<$FOO>), Unix usernames (C<~foo>),
 and files/directories.
 
 Example:
 
  use Complete::Unix qw(complete_user);
  use Complete::Util qw(complete_array_elem);
  complete_cli_arg(
      getopt_spec => {
          'help|h'   => sub{...},
          'format=s' => \$format,
          'user=s'   => \$user,
      },
      completion  => sub {
          my %args  = @_;
          my $word  = $args{word};
          my $ospec = $args{ospec};
          if ($ospec && $ospec eq 'format=s') {
              complete_array_elem(array=>[qw/json text xml yaml/], word=>$word);
          } else {
              complete_user(word=>$word);
          }
      },
  );
 
 =item * B<cword>* => I<int>
 
 Index in words of the word we're trying to complete.
 
 See function C<parse_cmdline> in C<Complete::Bash> on how to produce this (if
 you're using bash).
 
 =item * B<extras> => I<hash>
 
 Add extra arguments to completion routine.
 
 The keys from this C<extras> hash will be merged into the final C<%args> passed to
 completion routines. Note that standard keys like C<type>, C<word>, and so on as
 described in the function description will not be overwritten by this.
 
 =item * B<getopt_spec>* => I<hash>
 
 Getopt::Long specification.
 
 =item * B<words>* => I<array>
 
 Command line arguments, like @ARGV.
 
 See function C<parse_cmdline> in C<Complete::Bash> on how to produce this (if
 you're using bash).
 
 =back
 
 Return value:  (hash|array)
 
 
 You can use C<format_completion> function in C<Complete::Bash> module to format
 the result of this function for bash.
 
 =head1 SEE ALSO
 
 L<Getopt::Long::Complete>
 
 L<Complete>
 
 L<Complete::Bash>
 
 Other modules related to bash shell tab completion: L<Bash::Completion>,
 L<Getopt::Complete>.
 
 L<Perinci::CmdLine> - an alternative way to easily create command-line
 applications with completion feature.
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Complete-Getopt-Long>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Complete-Getopt-Long>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Complete-Getopt-Long>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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
### Complete/Path.pm ###
 package Complete::Path;
 
 our $DATE = '2015-09-22'; # DATE
 our $VERSION = '0.19'; # VERSION
 
 use 5.010001;
 use strict;
 use warnings;
 
 use Complete::Setting;
 
 require Exporter;
 our @ISA = qw(Exporter);
 our @EXPORT_OK = qw(
                        complete_path
                );
 
 sub _dig_leaf {
     my ($p, $list_func, $is_dir_func, $path_sep) = @_;
     my $num_dirs;
     my $listres = $list_func->($p, '', 0);
     return $p unless ref($listres) eq 'ARRAY' && @$listres == 1;
     my $e = $listres->[0];
     my $p2 = $p =~ m!\Q$path_sep\E\z! ? "$p$e" : "$p$path_sep$e";
     my $is_dir;
     if ($e =~ m!\Q$path_sep\E\z!) {
         $is_dir++;
     } else {
         $is_dir = $is_dir_func && $is_dir_func->($p2);
     }
     return _dig_leaf($p2, $list_func, $is_dir_func, $path_sep) if $is_dir;
     $p2;
 }
 
 our %SPEC;
 
 $SPEC{complete_path} = {
     v => 1.1,
     summary => 'Complete path',
     description => <<'_',
 
 Complete path, for anything path-like. Meant to be used as backend for other
 functions like `Complete::File::complete_file` or
 `Complete::Module::complete_module`. Provides features like case-insensitive
 matching, expanding intermediate paths, and case mapping.
 
 Algorithm is to split path into path elements, then list items (using the
 supplied `list_func`) and perform filtering (using the supplied `filter_func`)
 at every level.
 
 _
     args => {
         word => {
             schema  => [str=>{default=>''}],
             pos     => 0,
         },
         list_func => {
             summary => 'Function to list the content of intermediate "dirs"',
             schema => 'code*',
             req => 1,
             description => <<'_',
 
 Code will be called with arguments: ($path, $cur_path_elem, $is_intermediate).
 Code should return an arrayref containing list of elements. "Directories" can be
 marked by ending the name with the path separator (see `path_sep`). Or, you can
 also provide an `is_dir_func` function that will be consulted after filtering.
 If an item is a "directory" then its name will be suffixed with a path
 separator by `complete_path()`.
 
 _
         },
         is_dir_func => {
             summary => 'Function to check whether a path is a "dir"',
             schema  => 'code*',
             description => <<'_',
 
 Optional. You can provide this function to determine if an item is a "directory"
 (so its name can be suffixed with path separator). You do not need to do this if
 you already suffix names of "directories" with path separator in `list_func`.
 
 One reason you might want to provide this and not mark "directories" in
 `list_func` is when you want to do extra filtering with `filter_func`. Sometimes
 you do not want to suffix the names first (example: see `complete_file` in
 `Complete::File`).
 
 _
         },
         starting_path => {
             schema => 'str*',
             req => 1,
             default => '',
         },
         filter_func => {
             schema  => 'code*',
             description => <<'_',
 
 Provide extra filtering. Code will be given path and should return 1 if the item
 should be included in the final result or 0 if the item should be excluded.
 
 _
         },
 
         path_sep => {
             schema  => 'str*',
             default => '/',
         },
         ci => {
             summary => 'Case-insensitive matching',
             schema  => 'bool',
         },
         fuzzy => {
             summary => 'Fuzzy matching',
             schema  => ['int*', min=>0],
         },
         map_case => {
             summary => 'Treat _ (underscore) and - (dash) as the same',
             schema  => 'bool',
             description => <<'_',
 
 This is another convenience option like `ci`, where you can type `-` (without
 pressing Shift, at least in US keyboard) and can still complete `_` (underscore,
 which is typed by pressing Shift, at least in US keyboard).
 
 This option mimics similar option in bash/readline: `completion-map-case`.
 
 _
         },
         exp_im_path => {
             summary => 'Expand intermediate paths',
             schema  => 'bool',
             description => <<'_',
 
 This option mimics feature in zsh where when you type something like `cd
 /h/u/b/myscript` and get `cd /home/ujang/bin/myscript` as a completion answer.
 
 _
         },
         dig_leaf => {
             summary => 'Dig leafs',
             schema => 'bool',
             description => <<'_',
 
 This feature mimics what's seen on GitHub. If a directory entry only contains a
 single entry, it will directly show the subentry (and subsubentry and so on) to
 save a number of tab presses.
 
 _
         },
         #result_prefix => {
         #    summary => 'Prefix each result with this string',
         #    schema  => 'str*',
         #},
     },
     result_naked => 1,
     result => {
         schema => 'array',
     },
 };
 sub complete_path {
     require Complete::Util;
 
     my %args   = @_;
     my $word   = $args{word} // "";
     my $path_sep = $args{path_sep} // '/';
     my $list_func   = $args{list_func};
     my $is_dir_func = $args{is_dir_func};
     my $filter_func = $args{filter_func};
     my $ci          = $args{ci} // $Complete::Setting::OPT_CI;
     my $fuzzy       = $args{fuzzy} // $Complete::Setting::OPT_FUZZY;
     my $map_case    = $args{map_case} // $Complete::Setting::OPT_MAP_CASE;
     my $exp_im_path = $args{exp_im_path} // $Complete::Setting::OPT_EXP_IM_PATH;
     my $dig_leaf    = $args{dig_leaf} // $Complete::Setting::OPT_DIG_LEAF;
     my $result_prefix = $args{result_prefix};
     my $starting_path = $args{starting_path} // '';
 
     my $re_ends_with_path_sep = qr!\A\z|\Q$path_sep\E\z!;
 
     # split word by into path elements, as we want to dig level by level (needed
     # when doing case-insensitive search on a case-sensitive tree).
     my @intermediate_dirs;
     {
         @intermediate_dirs = split qr/\Q$path_sep/, $word;
         @intermediate_dirs = ('') if !@intermediate_dirs;
         push @intermediate_dirs, '' if $word =~ $re_ends_with_path_sep;
     }
 
     # extract leaf path, because this one is treated differently
     my $leaf = pop @intermediate_dirs;
     @intermediate_dirs = ('') if !@intermediate_dirs;
 
     #say "D:starting_path=<$starting_path>";
     #say "D:intermediate_dirs=[",join(", ", map{"<$_>"} @intermediate_dirs),"]";
     #say "D:leaf=<$leaf>";
 
     # candidate for intermediate paths. when doing case-insensitive search,
     # there maybe multiple candidate paths for each dir, for example if
     # word='../foo/s' and there is '../foo/Surya', '../Foo/sri', '../FOO/SUPER'
     # then candidate paths would be ['../foo', '../Foo', '../FOO'] and the
     # filename should be searched inside all those dirs. everytime we drill down
     # to deeper subdirectories, we adjust this list by removing
     # no-longer-eligible candidates.
     my @candidate_paths;
 
     for my $i (0..$#intermediate_dirs) {
         my $intdir = $intermediate_dirs[$i];
         my $intdir_with_path_sep = "$intdir$path_sep";
         my @dirs;
         if ($i == 0) {
             # first path elem, we search starting_path first since
             # candidate_paths is still empty.
             @dirs = ($starting_path);
         } else {
             # subsequent path elem, we search all candidate_paths
             @dirs = @candidate_paths;
         }
 
         if ($i == $#intermediate_dirs && $intdir eq '') {
             @candidate_paths = @dirs;
             last;
         }
 
         my @new_candidate_paths;
         for my $dir (@dirs) {
             #say "D:  intdir list($dir)";
             my $listres = $list_func->($dir, $intdir, 1);
             next unless $listres && @$listres;
             #use DD; dd $listres;
             my $matches = Complete::Util::complete_array_elem(
                 word => $intdir, array => $listres,
                 ci=>$ci, fuzzy=>$fuzzy, map_case=>$map_case,
             );
             my $exact_matches = [grep {
                 length($intdir)+length($path_sep) eq length($_)
             } @$matches];
             #print "D: word=<$intdir>, matches="; use DD; dd $matches; print ", exact_matches="; dd $exact_matches;
 
             # when doing exp_im_path, check if we have a single exact match. in
             # that case, don't use all the candidates because that can be
             # annoying, e.g. you have 'a/foo' and 'and/food', you won't be able
             # to complete 'a/f' because bash (e.g.) will always cut the answer
             # to 'a' because the candidates are 'a/foo' and 'and/foo' (it will
             # use the shortest common string which is 'a').
             #say "D:  num_exact_matches: $num_exact_matches";
             if ($exp_im_path && @$exact_matches == 1) {
                 $matches = $exact_matches;
             }
 
             for (@$matches) {
                 my $p = $dir =~ $re_ends_with_path_sep ?
                     "$dir$_" : "$dir$path_sep$_";
                 push @new_candidate_paths, $p;
             }
 
         }
         #say "D:  candidate_paths=[",join(", ", map{"<$_>"} @new_candidate_paths),"]";
         return [] unless @new_candidate_paths;
         @candidate_paths = @new_candidate_paths;
     }
 
     my $cut_chars = 0;
     if (length($starting_path)) {
         $cut_chars += length($starting_path);
         unless ($starting_path =~ /\Q$path_sep\E\z/) {
             $cut_chars += length($path_sep);
         }
     }
 
     my @res;
     for my $dir (@candidate_paths) {
         #say "D:opendir($dir)";
         my $listres = $list_func->($dir, $leaf, 0);
         next unless $listres && @$listres;
         my $matches = Complete::Util::complete_array_elem(
             word => $leaf, array => $listres,
             ci=>$ci, fuzzy=>$fuzzy, map_case=>$map_case,
         );
         #use DD; dd $matches;
 
       L1:
         for my $e (@$matches) {
             my $p = $dir =~ $re_ends_with_path_sep ?
                 "$dir$e" : "$dir$path_sep$e";
             {
                 local $_ = $p; # convenience for filter func
                 next L1 if $filter_func && !$filter_func->($p);
             }
 
             my $is_dir;
             if ($e =~ $re_ends_with_path_sep) {
                 $is_dir = 1;
             } else {
                 local $_ = $p; # convenience for is_dir_func
                 $is_dir = $is_dir_func->($p);
             }
 
             if ($is_dir && $dig_leaf) {
                 $p = _dig_leaf($p, $list_func, $is_dir_func, $path_sep);
                 # check again
                 if ($p =~ $re_ends_with_path_sep) {
                     $is_dir = 1;
                 } else {
                     local $_ = $p; # convenience for is_dir_func
                     $is_dir = $is_dir_func->($p);
                 }
             }
 
             # process into final result
             my $p0 = $p;
             substr($p, 0, $cut_chars) = '' if $cut_chars;
             $p = "$result_prefix$p" if length($result_prefix);
             unless ($p =~ /\Q$path_sep\E\z/) {
                 $p .= $path_sep if $is_dir;
             }
             push @res, $p;
         }
     }
 
     \@res;
 }
 1;
 # ABSTRACT: Complete path
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Complete::Path - Complete path
 
 =head1 VERSION
 
 This document describes version 0.19 of Complete::Path (from Perl distribution Complete-Path), released on 2015-09-22.
 
 =head1 DESCRIPTION
 
 =head1 FUNCTIONS
 
 
 =head2 complete_path(%args) -> array
 
 Complete path.
 
 Complete path, for anything path-like. Meant to be used as backend for other
 functions like C<Complete::File::complete_file> or
 C<Complete::Module::complete_module>. Provides features like case-insensitive
 matching, expanding intermediate paths, and case mapping.
 
 Algorithm is to split path into path elements, then list items (using the
 supplied C<list_func>) and perform filtering (using the supplied C<filter_func>)
 at every level.
 
 Arguments ('*' denotes required arguments):
 
 =over 4
 
 =item * B<ci> => I<bool>
 
 Case-insensitive matching.
 
 =item * B<dig_leaf> => I<bool>
 
 Dig leafs.
 
 This feature mimics what's seen on GitHub. If a directory entry only contains a
 single entry, it will directly show the subentry (and subsubentry and so on) to
 save a number of tab presses.
 
 =item * B<exp_im_path> => I<bool>
 
 Expand intermediate paths.
 
 This option mimics feature in zsh where when you type something like C<cd
 /h/u/b/myscript> and get C<cd /home/ujang/bin/myscript> as a completion answer.
 
 =item * B<filter_func> => I<code>
 
 Provide extra filtering. Code will be given path and should return 1 if the item
 should be included in the final result or 0 if the item should be excluded.
 
 =item * B<fuzzy> => I<int>
 
 Fuzzy matching.
 
 =item * B<is_dir_func> => I<code>
 
 Function to check whether a path is a "dir".
 
 Optional. You can provide this function to determine if an item is a "directory"
 (so its name can be suffixed with path separator). You do not need to do this if
 you already suffix names of "directories" with path separator in C<list_func>.
 
 One reason you might want to provide this and not mark "directories" in
 C<list_func> is when you want to do extra filtering with C<filter_func>. Sometimes
 you do not want to suffix the names first (example: see C<complete_file> in
 C<Complete::File>).
 
 =item * B<list_func>* => I<code>
 
 Function to list the content of intermediate "dirs".
 
 Code will be called with arguments: ($path, $cur_path_elem, $is_intermediate).
 Code should return an arrayref containing list of elements. "Directories" can be
 marked by ending the name with the path separator (see C<path_sep>). Or, you can
 also provide an C<is_dir_func> function that will be consulted after filtering.
 If an item is a "directory" then its name will be suffixed with a path
 separator by C<complete_path()>.
 
 =item * B<map_case> => I<bool>
 
 Treat _ (underscore) and - (dash) as the same.
 
 This is another convenience option like C<ci>, where you can type C<-> (without
 pressing Shift, at least in US keyboard) and can still complete C<_> (underscore,
 which is typed by pressing Shift, at least in US keyboard).
 
 This option mimics similar option in bash/readline: C<completion-map-case>.
 
 =item * B<path_sep> => I<str> (default: "/")
 
 =item * B<starting_path>* => I<str> (default: "")
 
 =item * B<word> => I<str> (default: "")
 
 =back
 
 Return value:  (array)
 
 =head1 SEE ALSO
 
 L<Complete>
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Complete-Path>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Complete-Path>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Complete-Path>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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
### Complete/Setting.pm ###
 package Complete::Setting;
 
 our $DATE = '2015-09-16'; # DATE
 our $VERSION = '0.16'; # VERSION
 
 use 5.010001;
 use strict;
 use warnings;
 
 our $OPT_CI          = ($ENV{COMPLETE_OPT_CI}          // 1) ? 1:0;
 our $OPT_FUZZY       = ($ENV{COMPLETE_OPT_FUZZY}       // 1)+0;
 our $OPT_MAP_CASE    = ($ENV{COMPLETE_OPT_MAP_CASE}    // 1) ? 1:0;
 our $OPT_EXP_IM_PATH = ($ENV{COMPLETE_OPT_EXP_IM_PATH} // 1) ? 1:0;
 our $OPT_DIG_LEAF    = ($ENV{COMPLETE_OPT_DIG_LEAF}    // 1) ? 1:0;
 
 1;
 # ABSTRACT: Common settings for completion routines
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Complete::Setting - Common settings for completion routines
 
 =head1 VERSION
 
 This document describes version 0.16 of Complete::Setting (from Perl distribution Complete), released on 2015-09-16.
 
 =head1 DESCRIPTION
 
 This module defines some configuration variables. C<Complete::*> modules should
 use the default from these settings, to make it convenient for users to change
 some behaviors globally.
 
 The defaults are optimized for convenience and laziness for user typing and
 might change from release to release.
 
 =head2 C<$Complete::Setting::OPT_CI> => bool (default: from COMPLETE_OPT_CI or 1)
 
 If set to 1, matching is done case-insensitively. This setting should be
 consulted as the default for all C<ci> argument in the C<complete_*> functions.
 But users can override this setting by providing value to C<ci> argument.
 
 In bash/readline, this is akin to setting C<completion-ignore-case>.
 
 =head2 C<$Complete::Setting::OPT_FUZZY> => int (default: from COMPLETE_OPT_FUZZY or 1)
 
 Enable fuzzy matching. The greater the number, the greater the tolerance. To
 disable fuzzy matching, set to 0. This setting should be consulted for every
 C<fuzzy> argument in the C<complete_*> functions. But users can override this
 setting by providing value to C<fuzzy> argumnt.
 
 =head2 C<$Complete::Setting::OPT_MAP_CASE> => bool (default: from COMPLETE_OPT_MAP_CASE or 1)
 
 This is exactly like C<completion-map-case> in readline/bash to treat C<_> and
 C<-> as the same when matching.
 
 All L<Complete::Path>-based modules (like L<Complete::Util>'s
 C<complete_file()>), L<Complete::Module>, or L<Complete::Riap> respect this
 setting.
 
 =head2 C<$Complete::Setting::OPT_EXP_IM_PATH> => bool (default: from COMPLETE_OPT_EXP_IM_PATH or 1)
 
 Whether to "expand intermediate paths". What is meant by this is something like
 zsh: when you type something like C<cd /h/u/b/myscript> it can be completed to
 C<cd /home/ujang/bin/myscript>.
 
 All L<Complete::Path>-based modules (like L<Complete::Util>'s
 C<complete_file()>, L<Complete::Module>, or L<Complete::Riap>) respect this
 setting.
 
 =head2 C<$Complete::Setting::OPT_DIG_LEAF> => bool (default: from COMPLETE_OPT_DIG_LEAF or 1)
 
 (Experimental) When enabled, this option mimics what's seen on GitHub. If a
 directory entry only contains a single subentry, it will directly show the
 subentry (and subsubentry and so on) to save a number of tab presses.
 
 Suppose you have files like this:
 
  a
  b/c/d/e
  c
 
 If you complete for C<b> you will directly get C<b/c/d/e> (the leaf).
 
 This is currently experimental because if you want to complete only directories,
 you won't get b or b/c or b/c/d. Need to think how to solve this.
 
 =head1 ENVIRONMENT
 
 =head2 COMPLETE_OPT_CI => bool
 
 Set default for C<$Complete::Setting::OPT_CI>.
 
 =head2 COMPLETE_OPT_FUZZY => int
 
 Set default for C<$Complete::Setting::OPT_FUZZY>.
 
 =head2 COMPLETE_OPT_MAP_CASE => bool
 
 Set default for C<$Complete::Setting::OPT_MAP_CASE>.
 
 =head2 COMPLETE_OPT_EXP_IM_PATH => bool
 
 Set default for C<$Complete::Setting::OPT_EXP_IM_PATH>.
 
 =head2 COMPLETE_OPT_DIG_LEAF => bool
 
 Set default for C<$Complete::Setting::OPT_DIG_LEAF>.
 
 =head1 SEE ALSO
 
 L<Complete>
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Complete>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Complete>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Complete>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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
### Complete/Tcsh.pm ###
 package Complete::Tcsh;
 
 our $DATE = '2015-09-09'; # DATE
 our $VERSION = '0.02'; # VERSION
 
 use 5.010001;
 use strict;
 use warnings;
 
 require Exporter;
 our @ISA = qw(Exporter);
 our @EXPORT_OK = qw(
                        parse_cmdline
                        format_completion
                );
 
 require Complete::Bash;
 
 our %SPEC;
 
 $SPEC{':package'} = {
     v => 1.1,
     summary => 'Completion module for tcsh shell',
 };
 
 $SPEC{parse_cmdline} = {
     v => 1.1,
     summary => 'Parse shell command-line for processing by completion routines',
     description => <<'_',
 
 This function converts COMMAND_LINE (str) given by tcsh to become something like
 COMP_WORDS (array) and COMP_CWORD (int), like what bash supplies to shell
 functions. Currently implemented using `Complete::Bash`'s `parse_cmdline`.
 
 _
     args_as => 'array',
     args => {
         cmdline => {
             summary => 'Command-line, defaults to COMMAND_LINE environment',
             schema => 'str*',
             pos => 0,
         },
     },
     result => {
         schema => ['array*', len=>2],
         description => <<'_',
 
 Return a 2-element array: `[$words, $cword]`. `$words` is array of str,
 equivalent to `COMP_WORDS` provided by bash to shell functions. `$cword` is an
 integer, equivalent to `COMP_CWORD` provided by bash to shell functions. The
 word to be completed is at `$words->[$cword]`.
 
 Note that COMP_LINE includes the command name. If you want the command-line
 arguments only (like in `@ARGV`), you need to strip the first element from
 `$words` and reduce `$cword` by 1.
 
 _
     },
     result_naked => 1,
 };
 sub parse_cmdline {
     my ($line) = @_;
 
     $line //= $ENV{COMMAND_LINE};
     Complete::Bash::parse_cmdline($line, length($line));
 }
 
 $SPEC{format_completion} = {
     v => 1.1,
     summary => 'Format completion for output (for shell)',
     description => <<'_',
 
 tcsh accepts completion reply in the form of one entry per line to STDOUT.
 Currently the formatting is done using `Complete::Bash`'s `format_completion`
 because escaping rule and so on are not yet well defined in tcsh.
 
 _
     args_as => 'array',
     args => {
         completion => {
             summary => 'Completion answer structure',
             description => <<'_',
 
 Either an array or hash, as described in `Complete`.
 
 _
             schema=>['any*' => of => ['hash*', 'array*']],
             req=>1,
             pos=>0,
         },
     },
     result => {
         summary => 'Formatted string (or array, if `as` is set to `array`)',
         schema => ['any*' => of => ['str*', 'array*']],
     },
     result_naked => 1,
 };
 sub format_completion {
     Complete::Bash::format_completion(@_);
 }
 
 1;
 # ABSTRACT: Completion module for tcsh shell
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Complete::Tcsh - Completion module for tcsh shell
 
 =head1 VERSION
 
 This document describes version 0.02 of Complete::Tcsh (from Perl distribution Complete-Tcsh), released on 2015-09-09.
 
 =head1 DESCRIPTION
 
 tcsh allows completion to come from various sources. One of the simplest is from
 a list of words:
 
  % complete CMDNAME 'p/*/(one two three)/'
 
 Another source is from an external command:
 
  % complete CMDNAME 'p/*/`mycompleter --somearg`/'
 
 The command receives one environment variables C<COMMAND_LINE> (string, raw
 command-line). Unlike bash, tcsh does not (yet) provide something akin to
 C<COMP_POINT> in bash. Command is expected to print completion entries, one line
 at a time.
 
  % cat mycompleter
  #!/usr/bin/perl
  use Complete::Tcsh qw(parse_cmdline format_completion);
  use Complete::Util qw(complete_array_elem);
  my ($words, $cword) = parse_cmdline();
  my $res = complete_array_elem(array=>[qw/--help --verbose --version/], word=>$words->[$cword]);
  print format_completion($res);
 
  % complete -C foo-complete foo
  % foo --v<Tab>
  --verbose --version
 
 This module provides routines for you to be doing the above.
 
 Also, unlike bash, currently tcsh does not allow delegating completion to a
 shell function.
 
 =head1 FUNCTIONS
 
 
 =head2 format_completion($completion) -> str|array
 
 Format completion for output (for shell).
 
 tcsh accepts completion reply in the form of one entry per line to STDOUT.
 Currently the formatting is done using C<Complete::Bash>'s C<format_completion>
 because escaping rule and so on are not yet well defined in tcsh.
 
 Arguments ('*' denotes required arguments):
 
 =over 4
 
 =item * B<completion>* => I<hash|array>
 
 Completion answer structure.
 
 Either an array or hash, as described in C<Complete>.
 
 =back
 
 Return value: Formatted string (or array, if `as` is set to `array`) (str|array)
 
 
 =head2 parse_cmdline($cmdline) -> array
 
 Parse shell command-line for processing by completion routines.
 
 This function converts COMMAND_LINE (str) given by tcsh to become something like
 COMP_WORDS (array) and COMP_CWORD (int), like what bash supplies to shell
 functions. Currently implemented using C<Complete::Bash>'s C<parse_cmdline>.
 
 Arguments ('*' denotes required arguments):
 
 =over 4
 
 =item * B<cmdline> => I<str>
 
 Command-line, defaults to COMMAND_LINE environment.
 
 =back
 
 Return value:  (array)
 
 
 Return a 2-element array: C<[$words, $cword]>. C<$words> is array of str,
 equivalent to C<COMP_WORDS> provided by bash to shell functions. C<$cword> is an
 integer, equivalent to C<COMP_CWORD> provided by bash to shell functions. The
 word to be completed is at C<< $words-E<gt>[$cword] >>.
 
 Note that COMP_LINE includes the command name. If you want the command-line
 arguments only (like in C<@ARGV>), you need to strip the first element from
 C<$words> and reduce C<$cword> by 1.
 
 =head1 SEE ALSO
 
 L<Complete>
 
 L<Complete::Bash>
 
 tcsh manual.
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Complete-Tcsh>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Complete-Tcsh>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Complete-Tcsh>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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
### Complete/Util.pm ###
 package Complete::Util;
 
 our $DATE = '2015-09-18'; # DATE
 our $VERSION = '0.38'; # VERSION
 
 use 5.010001;
 use strict;
 use warnings;
 
 use Complete::Setting;
 
 require Exporter;
 our @ISA = qw(Exporter);
 our @EXPORT_OK = qw(
                        hashify_answer
                        arrayify_answer
                        combine_answers
                        complete_array_elem
                        complete_hash_key
                );
 
 our %SPEC;
 
 $SPEC{':package'} = {
     v => 1.1,
     summary => 'General completion routine',
 };
 
 $SPEC{hashify_answer} = {
     v => 1.1,
     summary => 'Make sure we return completion answer in hash form',
     description => <<'_',
 
 This function accepts a hash or an array. If it receives an array, will convert
 the array into `{words=>$ary}' first to make sure the completion answer is in
 hash form.
 
 Then will add keys from `meta` to the hash.
 
 _
     args => {
         arg => {
             summary => '',
             schema  => ['any*' => of => ['array*','hash*']],
             req => 1,
             pos => 0,
         },
         meta => {
             summary => 'Metadata (extra keys) for the hash',
             schema  => 'hash*',
             pos => 1,
         },
     },
     result_naked => 1,
     result => {
         schema => 'hash*',
     },
 };
 sub hashify_answer {
     my $ans = shift;
     if (ref($ans) ne 'HASH') {
         $ans = {words=>$ans};
     }
     if (@_) {
         my $meta = shift;
         for (keys %$meta) {
             $ans->{$_} = $meta->{$_};
         }
     }
     $ans;
 }
 
 $SPEC{arrayify_answer} = {
     v => 1.1,
     summary => 'Make sure we return completion answer in array form',
     description => <<'_',
 
 This is the reverse of `hashify_answer`. It accepts a hash or an array. If it
 receives a hash, will return its `words` key.
 
 _
     args => {
         arg => {
             summary => '',
             schema  => ['any*' => of => ['array*','hash*']],
             req => 1,
             pos => 0,
         },
     },
     result_naked => 1,
     result => {
         schema => 'array*',
     },
 };
 sub arrayify_answer {
     my $ans = shift;
     if (ref($ans) eq 'HASH') {
         $ans = $ans->{words};
     }
     $ans;
 }
 
 sub __min(@) {
     my $m = $_[0];
     for (@_) {
         $m = $_ if $_ < $m;
     }
     $m;
 }
 
 # straight copy of Wikipedia's "Levenshtein Distance"
 sub __editdist {
     my @a = split //, shift;
     my @b = split //, shift;
 
     # There is an extra row and column in the matrix. This is the distance from
     # the empty string to a substring of the target.
     my @d;
     $d[$_][0] = $_ for 0 .. @a;
     $d[0][$_] = $_ for 0 .. @b;
 
     for my $i (1 .. @a) {
         for my $j (1 .. @b) {
             $d[$i][$j] = (
                 $a[$i-1] eq $b[$j-1]
                     ? $d[$i-1][$j-1]
                     : 1 + __min(
                         $d[$i-1][$j],
                         $d[$i][$j-1],
                         $d[$i-1][$j-1]
                     )
                 );
         }
     }
 
     $d[@a][@b];
 }
 
 $SPEC{complete_array_elem} = {
     v => 1.1,
     summary => 'Complete from array',
     description => <<'_',
 
 Will sort the resulting completion list, so you don't have to presort the array.
 
 _
     args => {
         word     => { schema=>[str=>{default=>''}], pos=>0, req=>1 },
         array    => { schema=>['array*'=>{of=>'str*'}], req=>1 },
         ci       => { schema=>['bool'] },
         exclude  => { schema=>['array*'] },
         fuzzy    => { schema=>['int*', min=>0] },
         map_case => {
             summary => 'Treat _ (underscore) and - (dash) as the same',
             schema  => ['bool'],
         },
     },
     result_naked => 1,
     result => {
         schema => 'array',
     },
 };
 sub complete_array_elem {
     state $code_editdist = do {
         if (eval { require Text::Levenshtein::XS; 1 }) {
             \&Text::Levenshtein::XS::distance;
         } else {
             \&__editdist;
         }
     };
 
     my %args  = @_;
 
     my $array    = $args{array} or die "Please specify array";
     my $word     = $args{word} // "";
     my $ci       = $args{ci} // $Complete::Setting::OPT_CI;
     my $fuzzy    = $args{fuzzy} // $Complete::Setting::OPT_FUZZY;
     my $map_case = $args{map_case} // $Complete::Setting::OPT_MAP_CASE;
 
     return [] unless @$array;
 
     # normalize
     my $wordn = $ci ? uc($word) : $word; $wordn =~ s/_/-/g if $map_case;
 
     my @words;
     for my $el (@$array) {
         my $eln = $ci ? uc($el) : $el; $eln =~ s/_/-/g if $map_case;
         next unless 0==index($eln, $wordn);
         push @words, $el;
     }
 
     if ($fuzzy && !@words) {
         my $factor = 1.3;
         my $x = -1;
         my $y = 1;
 
         my %editdists;
       ELEM:
         for my $el (@$array) {
             my $eln = $ci ? uc($el) : $el; $eln =~ s/_/-/g if $map_case;
             for my $l (length($wordn)-$y .. length($wordn)+$y) {
                 next if $l <= 0;
                 my $chopped = substr($eln, 0, $l);
                 my $d;
                 unless (defined $editdists{$chopped}) {
                     $d = $code_editdist->($wordn, $chopped);
                     $editdists{$chopped} = $d;
                 } else {
                     $d = $editdists{$chopped};
                 }
                 my $maxd = __min(
                     __min(length($chopped), length($word))/$factor,
                     $fuzzy,
                 );
                 #say "D: d(".($ci ? $wordu:$word).",$chopped)=$d (maxd=$maxd)";
                 next unless $d <= $maxd;
                 push @words, $el;
                 next ELEM;
             }
         }
     }
 
     if ($args{exclude}) {
         my $exclude = $ci ? [map {uc} @{ $args{exclude} }] : $args{exclude};
         @words = grep {
             my $w = $_;
             !(grep {($ci ? uc($w) : $w) eq $_} @$exclude);
         } @words;
     }
 
     return $ci ? [sort {lc($a) cmp lc($b)} @words] : [sort @words];
 }
 
 $SPEC{complete_hash_key} = {
     v => 1.1,
     summary => 'Complete from hash keys',
     args => {
         word     => { schema=>[str=>{default=>''}], pos=>0, req=>1 },
         hash     => { schema=>['hash*'=>{}], req=>1 },
         ci       => { schema=>['bool'] },
         fuzzy    => { schema=>['int*', min=>0] },
         map_case => { schema=>['bool'] },
     },
     result_naked => 1,
     result => {
         schema => 'array',
     },
 };
 sub complete_hash_key {
     my %args  = @_;
     my $hash     = $args{hash} or die "Please specify hash";
     my $word     = $args{word} // "";
     my $ci       = $args{ci} // $Complete::Setting::OPT_CI;
     my $fuzzy    = $args{fuzzy} // $Complete::Setting::OPT_FUZZY;
     my $map_case = $args{map_case} // $Complete::Setting::OPT_MAP_CASE;
 
     my @array = $ci ?
         (sort {uc($a) cmp uc($b)} keys %$hash) : (sort keys %$hash);
     complete_array_elem(
         word=>$word, array=>\@array,
         ci=>$ci, fuzzy=>$fuzzy, map_case=>$map_case,
     );
 }
 
 $SPEC{combine_answers} = {
     v => 1.1,
     summary => 'Given two or more answers, combine them into one',
     description => <<'_',
 
 This function is useful if you want to provide a completion answer that is
 gathered from multiple sources. For example, say you are providing completion
 for the Perl tool `cpanm`, which accepts a filename (a tarball like `*.tar.gz`),
 a directory, or a module name. You can do something like this:
 
     combine_answers(
         complete_file(word=>$word, ci=>1),
         complete_module(word=>$word, ci=>1),
     );
 
 If a completion answer has a metadata `final` set to true, then that answer is
 used as the final answer without any combining with the other answers.
 
 _
     args => {
         answers => {
             schema => [
                 'array*' => {
                     of => ['any*', of=>['hash*','array*']], # XXX answer_t
                     min_len => 1,
                 },
             ],
             req => 1,
             pos => 0,
             greedy => 1,
         },
     },
     args_as => 'array',
     result_naked => 1,
     result => {
         schema => 'hash*',
         description => <<'_',
 
 Return a combined completion answer. Words from each input answer will be
 combined, order preserved and duplicates removed. The other keys from each
 answer will be merged.
 
 _
     },
 };
 sub combine_answers {
     require List::Util;
 
     return undef unless @_;
     return $_[0] if @_ < 2;
 
     my $final = {words=>[]};
     my $encounter_hash;
     my $add_words = sub {
         my $words = shift;
         for my $entry (@$words) {
             push @{ $final->{words} }, $entry
                 unless List::Util::first(
                     sub {
                         (ref($entry) ? $entry->{word} : $entry)
                             eq
                                 (ref($_) ? $_->{word} : $_)
                             }, @{ $final->{words} }
                         );
         }
     };
 
   ANSWER:
     for my $ans (@_) {
         if (ref($ans) eq 'ARRAY') {
             $add_words->($ans);
         } elsif (ref($ans) eq 'HASH') {
             $encounter_hash++;
 
             if ($ans->{final}) {
                 $final = $ans;
                 last ANSWER;
             }
 
             $add_words->($ans->{words} // []);
             for (keys %$ans) {
                 if ($_ eq 'words') {
                     next;
                 } elsif ($_ eq 'static') {
                     if (exists $final->{$_}) {
                         $final->{$_} &&= $ans->{$_};
                     } else {
                         $final->{$_} = $ans->{$_};
                     }
                 } else {
                     $final->{$_} = $ans->{$_};
                 }
             }
         }
     }
 
     # re-sort final words
     if ($final->{words}) {
         $final->{words} = [
             sort {
                 (ref($a) ? $a->{word} : $a) cmp
                     (ref($b) ? $b->{word} : $b);
             }
                 @{ $final->{words} }];
     }
 
     $encounter_hash ? $final : $final->{words};
 }
 
 1;
 # ABSTRACT: General completion routine
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Complete::Util - General completion routine
 
 =head1 VERSION
 
 This document describes version 0.38 of Complete::Util (from Perl distribution Complete-Util), released on 2015-09-18.
 
 =head1 DESCRIPTION
 
 =head1 FUNCTIONS
 
 
 =head2 arrayify_answer(%args) -> array
 
 Make sure we return completion answer in array form.
 
 This is the reverse of C<hashify_answer>. It accepts a hash or an array. If it
 receives a hash, will return its C<words> key.
 
 Arguments ('*' denotes required arguments):
 
 =over 4
 
 =item * B<arg>* => I<array|hash>
 
 =back
 
 Return value:  (array)
 
 
 =head2 combine_answers($answers, ...) -> hash
 
 Given two or more answers, combine them into one.
 
 This function is useful if you want to provide a completion answer that is
 gathered from multiple sources. For example, say you are providing completion
 for the Perl tool C<cpanm>, which accepts a filename (a tarball like C<*.tar.gz>),
 a directory, or a module name. You can do something like this:
 
  combine_answers(
      complete_file(word=>$word, ci=>1),
      complete_module(word=>$word, ci=>1),
  );
 
 If a completion answer has a metadata C<final> set to true, then that answer is
 used as the final answer without any combining with the other answers.
 
 Arguments ('*' denotes required arguments):
 
 =over 4
 
 =item * B<answers>* => I<array[hash|array]>
 
 =back
 
 Return value:  (hash)
 
 
 Return a combined completion answer. Words from each input answer will be
 combined, order preserved and duplicates removed. The other keys from each
 answer will be merged.
 
 
 =head2 complete_array_elem(%args) -> array
 
 Complete from array.
 
 Will sort the resulting completion list, so you don't have to presort the array.
 
 Arguments ('*' denotes required arguments):
 
 =over 4
 
 =item * B<array>* => I<array[str]>
 
 =item * B<ci> => I<bool>
 
 =item * B<exclude> => I<array>
 
 =item * B<fuzzy> => I<int>
 
 =item * B<map_case> => I<bool>
 
 Treat _ (underscore) and - (dash) as the same.
 
 =item * B<word>* => I<str> (default: "")
 
 =back
 
 Return value:  (array)
 
 
 =head2 complete_hash_key(%args) -> array
 
 Complete from hash keys.
 
 Arguments ('*' denotes required arguments):
 
 =over 4
 
 =item * B<ci> => I<bool>
 
 =item * B<fuzzy> => I<int>
 
 =item * B<hash>* => I<hash>
 
 =item * B<map_case> => I<bool>
 
 =item * B<word>* => I<str> (default: "")
 
 =back
 
 Return value:  (array)
 
 
 =head2 hashify_answer(%args) -> hash
 
 Make sure we return completion answer in hash form.
 
 This function accepts a hash or an array. If it receives an array, will convert
 the array into `{words=>$ary}' first to make sure the completion answer is in
 hash form.
 
 Then will add keys from C<meta> to the hash.
 
 Arguments ('*' denotes required arguments):
 
 =over 4
 
 =item * B<arg>* => I<array|hash>
 
 =item * B<meta> => I<hash>
 
 Metadata (extra keys) for the hash.
 
 =back
 
 Return value:  (hash)
 
 =head1 SEE ALSO
 
 L<Complete>
 
 If you want to do bash tab completion with Perl, take a look at
 L<Complete::Bash> or L<Getopt::Long::Complete> or L<Perinci::CmdLine>.
 
 Other C<Complete::*> modules.
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Complete-Util>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Complete-Util>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Complete-Util>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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
### Complete/Zsh.pm ###
 package Complete::Zsh;
 
 our $DATE = '2015-09-09'; # DATE
 our $VERSION = '0.02'; # VERSION
 
 use 5.010001;
 use strict;
 use warnings;
 
 require Exporter;
 our @ISA = qw(Exporter);
 our @EXPORT_OK = qw(
                        parse_cmdline
                        format_completion
                );
 
 require Complete::Bash;
 
 our %SPEC;
 
 $SPEC{':package'} = {
     v => 1.1,
     summary => 'Completion module for zsh shell',
 };
 
 $SPEC{parse_cmdline} = {
     v => 1.1,
     summary => 'Parse shell command-line for processing by completion routines',
     description => <<'_',
 
 This function converts COMP_LINE (str) (which can be supplied by zsh from `read
 -l`) and COMP_POINT (int) (which can be supplied by zsh from `read -ln`) into
 COMP_WORDS (array) and COMP_CWORD (int), like what bash supplies to shell
 functions. Currently implemented using `Complete::Bash`'s `parse_cmdline`.
 
 _
     args_as => 'array',
     args => {
         cmdline => {
             summary => 'Command-line, defaults to COMP_LINE environment',
             schema => 'str*',
             pos => 0,
         },
     },
     result => {
         schema => ['array*', len=>2],
         description => <<'_',
 
 Return a 2-element array: `[$words, $cword]`. `$words` is array of str,
 equivalent to `COMP_WORDS` provided by bash to shell functions. `$cword` is an
 integer, equivalent to `COMP_CWORD` provided by bash to shell functions. The
 word to be completed is at `$words->[$cword]`.
 
 Note that COMP_LINE includes the command name. If you want the command-line
 arguments only (like in `@ARGV`), you need to strip the first element from
 `$words` and reduce `$cword` by 1.
 
 _
     },
     result_naked => 1,
 };
 sub parse_cmdline {
     my ($line) = @_;
 
     $line //= $ENV{COMP_LINE};
     Complete::Bash::parse_cmdline($line, length($line));
 }
 
 $SPEC{format_completion} = {
     v => 1.1,
     summary => 'Format completion for output (for shell)',
     description => <<'_',
 
 zsh accepts completion reply in the form of one entry per line to STDOUT.
 Currently the formatting is done using `Complete::Bash`'s `format_completion`.
 
 _
     args_as => 'array',
     args => {
         completion => {
             summary => 'Completion answer structure',
             description => <<'_',
 
 Either an array or hash, as described in `Complete`.
 
 _
             schema=>['any*' => of => ['hash*', 'array*']],
             req=>1,
             pos=>0,
         },
     },
     result => {
         summary => 'Formatted string (or array, if `as` key is set to `array`)',
         schema => ['any*' => of => ['str*', 'array*']],
     },
     result_naked => 1,
 };
 sub format_completion {
     Complete::Bash::format_completion(@_);
 }
 
 1;
 # ABSTRACT: Completion module for zsh shell
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Complete::Zsh - Completion module for zsh shell
 
 =head1 VERSION
 
 This document describes version 0.02 of Complete::Zsh (from Perl distribution Complete-Zsh), released on 2015-09-09.
 
 =head1 DESCRIPTION
 
 This module provides routines related to doing completion in zsh.
 
 =head1 FUNCTIONS
 
 
 =head2 format_completion($completion) -> str|array
 
 Format completion for output (for shell).
 
 zsh accepts completion reply in the form of one entry per line to STDOUT.
 Currently the formatting is done using C<Complete::Bash>'s C<format_completion>.
 
 Arguments ('*' denotes required arguments):
 
 =over 4
 
 =item * B<completion>* => I<hash|array>
 
 Completion answer structure.
 
 Either an array or hash, as described in C<Complete>.
 
 =back
 
 Return value: Formatted string (or array, if `as` key is set to `array`) (str|array)
 
 
 =head2 parse_cmdline($cmdline) -> array
 
 Parse shell command-line for processing by completion routines.
 
 This function converts COMP_LINE (str) (which can be supplied by zsh from C<read
 -l>) and COMP_POINT (int) (which can be supplied by zsh from C<read -ln>) into
 COMP_WORDS (array) and COMP_CWORD (int), like what bash supplies to shell
 functions. Currently implemented using C<Complete::Bash>'s C<parse_cmdline>.
 
 Arguments ('*' denotes required arguments):
 
 =over 4
 
 =item * B<cmdline> => I<str>
 
 Command-line, defaults to COMP_LINE environment.
 
 =back
 
 Return value:  (array)
 
 
 Return a 2-element array: C<[$words, $cword]>. C<$words> is array of str,
 equivalent to C<COMP_WORDS> provided by bash to shell functions. C<$cword> is an
 integer, equivalent to C<COMP_CWORD> provided by bash to shell functions. The
 word to be completed is at C<< $words-E<gt>[$cword] >>.
 
 Note that COMP_LINE includes the command name. If you want the command-line
 arguments only (like in C<@ARGV>), you need to strip the first element from
 C<$words> and reduce C<$cword> by 1.
 
 =head1 SEE ALSO
 
 L<Complete>
 
 L<Complete::Bash>, L<Complete::Fish>, L<Complete::Tcsh>.
 
 zshcompctl manual page.
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Complete-Zsh>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Complete-Zsh>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Complete-Zsh>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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
### Config/IOD/Base.pm ###
 package Config::IOD::Base;
 
 our $DATE = '2015-09-08'; # DATE
 our $VERSION = '0.19'; # VERSION
 
 use 5.010001;
 use strict;
 use warnings;
 #use Carp; # avoided to shave a bit of startup time
 
 use constant +{
     COL_V_ENCODING => 0, # either "!j" or '"', '[', '{'
     COL_V_WS1 => 1,
     COL_V_VALUE => 2,
     COL_V_WS2 => 3,
     COL_V_COMMENT_CHAR => 4,
     COL_V_COMMENT => 5,
 };
 
 sub new {
     my ($class, %attrs) = @_;
     $attrs{default_section} //= 'GLOBAL';
     $attrs{allow_bang_only} //= 1;
     $attrs{allow_duplicate_key} //= 1;
     $attrs{enable_encoding} //= 1;
     $attrs{enable_quoting}  //= 1;
     $attrs{enable_bracket}  //= 1;
     $attrs{enable_brace}    //= 1;
     $attrs{enable_expr}     //= 0;
     $attrs{ignore_unknown_directive} //= 0;
     # allow_encodings
     # disallow_encodings
     # allow_directives
     # disallow_directives
     bless \%attrs, $class;
 }
 
 # borrowed from Parse::CommandLine. differences: returns arrayref. return undef
 # on error (instead of dying).
 sub _parse_command_line {
     my ($self, $str) = @_;
 
     $str =~ s/\A\s+//ms;
     $str =~ s/\s+\z//ms;
 
     my @argv;
     my $buf;
     my $escaped;
     my $double_quoted;
     my $single_quoted;
 
     for my $char (split //, $str) {
         if ($escaped) {
             $buf .= $char;
             $escaped = undef;
             next;
         }
 
         if ($char eq '\\') {
             if ($single_quoted) {
                 $buf .= $char;
             }
             else {
                 $escaped = 1;
             }
             next;
         }
 
         if ($char =~ /\s/) {
             if ($single_quoted || $double_quoted) {
                 $buf .= $char;
             }
             else {
                 push @argv, $buf if defined $buf;
                 undef $buf;
             }
             next;
         }
 
         if ($char eq '"') {
             if ($single_quoted) {
                 $buf .= $char;
                 next;
             }
             $double_quoted = !$double_quoted;
             next;
         }
 
         if ($char eq "'") {
             if ($double_quoted) {
                 $buf .= $char;
                 next;
             }
             $single_quoted = !$single_quoted;
             next;
         }
 
         $buf .= $char;
     }
     push @argv, $buf if defined $buf;
 
     if ($escaped || $single_quoted || $double_quoted) {
         return undef;
     }
 
     \@argv;
 }
 
 # return ($err, $res, $decoded_val)
 sub _parse_raw_value {
     no warnings; # XXX no warnings 'experimental::smartmatch', but this is unrecognized in 5.10
 
     my ($self, $val, $needs_res) = @_;
 
     if ($val =~ /\A!/ && $self->{enable_encoding}) {
 
         $val =~ s/!(\w+)(\s+)// or return ("Invalid syntax in encoded value");
         my ($enc, $ws1) = ($1, $2);
 
         # canonicalize shorthands
         $enc = "json" if $enc eq 'j';
         $enc = "hex"  if $enc eq 'h';
         $enc = "expr" if $enc eq 'e';
 
         if ($self->{allow_encodings}) {
             return ("Encoding '$enc' is not in ".
                         "allow_encodings list")
                 unless $enc ~~ @{$self->{allow_encodings}};
         }
         if ($self->{disallow_encodings}) {
             return ("Encoding '$enc' is in ".
                         "disallow_encodings list")
                 if $enc ~~ @{$self->{disallow_encodings}};
         }
 
         if ($enc eq 'json') {
             # XXX imperfect regex for simplicity, comment should not contain
             # "]", '"', or '}' or it will be gobbled up as value by greedy regex
             # quantifier
             $val =~ /\A
                      (".*"|\[.*\]|\{.*\}|\S+)
                      (\s*)
                      (?: ([;#])(.*) )?
                      \z/x or return ("Invalid syntax in JSON-encoded value");
             my $res = [
                 "!$enc", # COL_V_ENCODING
                 $ws1, # COL_V_WS1
                 $1, # COL_V_VALUE
                 $2, # COL_V_WS2
                 $3, # COL_V_COMMENT_CHAR
                 $4, # COL_V_COMMENT
             ] if $needs_res;
             my $decode_res = $self->_decode_json($val);
             return ($decode_res->[1]) unless $decode_res->[0] == 200;
             return (undef, $res, $decode_res->[2]);
         } elsif ($enc eq 'hex') {
             $val =~ /\A
                      ([0-9A-Fa-f]*)
                      (\s*)
                      (?: ([;#])(.*) )?
                      \z/x or return ("Invalid syntax in hex-encoded value");
             my $res = [
                 "!$enc", # COL_V_ENCODING
                 $ws1, # COL_V_WS1
                 $1, # COL_V_VALUE
                 $2, # COL_V_WS2
                 $3, # COL_V_COMMENT_CHAR
                 $4, # COL_V_COMMENT
             ] if $needs_res;
             my $decode_res = $self->_decode_hex($1);
             return ($decode_res->[1]) unless $decode_res->[0] == 200;
             return (undef, $res, $decode_res->[2]);
         } elsif ($enc eq 'base64') {
             $val =~ m!\A
                       ([A-Za-z0-9+/]*=*)
                       (\s*)
                       (?: ([;#])(.*) )?
                       \z!x or return ("Invalid syntax in base64-encoded value");
             my $res = [
                 "!$enc", # COL_V_ENCODING
                 $ws1, # COL_V_WS1
                 $1, # COL_V_VALUE
                 $2, # COL_V_WS2
                 $3, # COL_V_COMMENT_CHAR
                 $4, # COL_V_COMMENT
             ] if $needs_res;
             my $decode_res = $self->_decode_base64($1);
             return ($decode_res->[1]) unless $decode_res->[0] == 200;
             return (undef, $res, $decode_res->[2]);
         } elsif ($enc eq 'expr') {
             return ("expr is not allowed (enable_expr=0)")
                 unless $self->{enable_expr};
             # XXX imperfect regex, expression can't contain # and ; because it
             # will be assumed as comment
             $val =~ m!\A
                       ((?:[^#;])+?)
                       (\s*)
                       (?: ([;#])(.*) )?
                       \z!x or return ("Invalid syntax in expr-encoded value");
             my $res = [
                 "!$enc", # COL_V_ENCODING
                 $ws1, # COL_V_WS1
                 $1, # COL_V_VALUE
                 $2, # COL_V_WS2
                 $3, # COL_V_COMMENT_CHAR
                 $4, # COL_V_COMMENT
             ] if $needs_res;
             my $decode_res = $self->_decode_expr($1);
             return ($decode_res->[1]) unless $decode_res->[0] == 200;
             return (undef, $res, $decode_res->[2]);
         } else {
             return ("unknown encoding '$enc'");
         }
 
     } elsif ($val =~ /\A"/ && $self->{enable_quoting}) {
 
         $val =~ /\A
                  "( (?:
                          \\\\ | # backslash
                          \\.  | # escaped something
                          [^"\\]+ # non-doublequote or non-backslash
                      )* )"
                  (\s*)
                  (?: ([;#])(.*) )?
                  \z/x or return ("Invalid syntax in quoted string value");
         my $res = [
             '"', # COL_V_ENCODING
             '', # COL_V_WS1
             $1, # VOL_V_VALUE
             $2, # COL_V_WS2
             $3, # COL_V_COMMENT_CHAR
             $4, # COL_V_COMMENT
         ] if $needs_res;
         my $decode_res = $self->_decode_json(qq("$1"));
         return ($decode_res->[1]) unless $decode_res->[0] == 200;
         return (undef, $res, $decode_res->[2]);
 
     } elsif ($val =~ /\A\[/ && $self->{enable_bracket}) {
 
         # XXX imperfect regex for simplicity, comment should not contain "]" or
         # it will be gobbled up as value by greedy regex quantifier
         $val =~ /\A
                  \[(.*)\]
                  (?:
                      (\s*)
                      ([#;])(.*)
                  )?
                  \z/x or return ("Invalid syntax in bracketed array value");
         my $res = [
             '[', # COL_V_ENCODING
             '', # COL_V_WS1
             $1, # VOL_V_VALUE
             $2, # COL_V_WS2
             $3, # COL_V_COMMENT_CHAR
             $4, # COL_V_COMMENT
         ] if $needs_res;
         my $decode_res = $self->_decode_json("[$1]");
         return ($decode_res->[1]) unless $decode_res->[0] == 200;
         return (undef, $res, $decode_res->[2]);
 
     } elsif ($val =~ /\A\{/ && $self->{enable_brace}) {
 
         # XXX imperfect regex for simplicity, comment should not contain "}" or
         # it will be gobbled up as value by greedy regex quantifier
         $val =~ /\A
                  \{(.*)\}
                  (?:
                      (\s*)
                      ([#;])(.*)
                  )?
                  \z/x or return ("Invalid syntax in braced hash value");
         my $res = [
             '{', # COL_V_ENCODING
             '', # COL_V_WS1
             $1, # VOL_V_VALUE
             $2, # COL_V_WS2
             $3, # COL_V_COMMENT_CHAR
             $4, # COL_V_COMMENT
         ] if $needs_res;
         my $decode_res = $self->_decode_json("{$1}");
         return ($decode_res->[1]) unless $decode_res->[0] == 200;
         return (undef, $res, $decode_res->[2]);
 
     } else {
 
         $val =~ /\A
                  (.*?)
                  (\s*)
                  (?: ([#;])(.*) )?
                  \z/x or return ("Invalid syntax in value"); # shouldn't happen, regex should match any string
         my $res = [
             '', # COL_V_ENCODING
             '', # COL_V_WS1
             $1, # VOL_V_VALUE
             $2, # COL_V_WS2
             $3, # COL_V_COMMENT_CHAR
             $4, # COL_V_COMMENT
         ] if $needs_res;
         return (undef, $res, $1);
 
     }
     # should not be reached
 }
 
 sub _decode_json {
     my ($self, $val) = @_;
     state $json = do {
         require JSON;
         JSON->new->allow_nonref;
     };
     my $res;
     eval { $res = $json->decode($val) };
     if ($@) {
         return [500, "Invalid JSON: $@"];
     } else {
         return [200, "OK", $res];
     }
 }
 
 sub _decode_hex {
     my ($self, $val) = @_;
     [200, "OK", pack("H*", $val)];
 }
 
 sub _decode_base64 {
     my ($self, $val) = @_;
     require MIME::Base64;
     [200, "OK", MIME::Base64::decode_base64($val)];
 }
 
 sub _decode_expr {
     require Config::IOD::Expr;
 
     my ($self, $val) = @_;
     no strict 'refs';
     local *{"Config::IOD::Expr::val"} = sub {
         my $arg = shift;
         if ($arg =~ /(.+)\.(.+)/) {
             return $self->{_res}{$1}{$2};
         } else {
             return $self->{_res}{ $self->{_cur_section} }{$arg};
         }
     };
     Config::IOD::Expr::_parse_expr($val);
 }
 
 sub _err {
     my ($self, $msg) = @_;
     die join(
         "",
         @{ $self->{_include_stack} } ? "$self->{_include_stack}[0] " : "",
         "line $self->{_linum}: ",
         $msg
     );
 }
 
 sub _push_include_stack {
     require Cwd;
 
     my ($self, $path) = @_;
 
     # included file's path is based on the main (topmost) file
     if (@{ $self->{_include_stack} }) {
         require File::Spec;
         my ($vol, $dir, $file) =
             File::Spec->splitpath($self->{_include_stack}[-1]);
         $path = File::Spec->rel2abs($path, File::Spec->catpath($vol, $dir));
     }
 
     my $abs_path = Cwd::abs_path($path) or return [400, "Invalid path name"];
     return [409, "Recursive", $abs_path]
         if grep { $_ eq $abs_path } @{ $self->{_include_stack} };
     push @{ $self->{_include_stack} }, $abs_path;
     return [200, "OK", $abs_path];
 }
 
 sub _pop_include_stack {
     my $self = shift;
 
     die "BUG: Overpopped _pop_include_stack"
         unless @{$self->{_include_stack}};
     pop @{ $self->{_include_stack} };
 }
 
 sub _init_read {
     my $self = shift;
 
     $self->{_include_stack} = [];
 }
 
 sub _read_file {
     my ($self, $filename) = @_;
     open my $fh, "<", $filename
         or die "Can't open file '$filename': $!";
     binmode($fh, ":utf8");
     local $/;
     return ~~<$fh>;
 }
 
 sub read_file {
     my ($self, $filename) = @_;
     $self->_init_read;
     my $res = $self->_push_include_stack($filename);
     die "Can't read '$filename': $res->[1]" unless $res->[0] == 200;
     $res =
         $self->_read_string($self->_read_file($filename));
     $self->_pop_include_stack;
     $res;
 }
 
 sub read_string {
     my ($self, $str) = @_;
     $self->_init_read;
     $self->_read_string($str);
 }
 
 1;
 # ABSTRACT: Base class for Config::IOD and Config::IOD::Reader
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Config::IOD::Base - Base class for Config::IOD and Config::IOD::Reader
 
 =head1 VERSION
 
 This document describes version 0.19 of Config::IOD::Base (from Perl distribution Config-IOD-Reader), released on 2015-09-08.
 
 =head1 ATTRIBUTES
 
 =for BEGIN_BLOCK: attributes
 
 =head2 default_section => str (default: C<GLOBAL>)
 
 If a key line is specified before any section line, this is the section that the
 key will be put in.
 
 =head2 enable_encoding => bool (default: 1)
 
 If set to false, then encoding notation will be ignored and key value will be
 parsed as verbatim. Example:
 
  name = !json null
 
 With C<enable_encoding> turned off, value will not be undef but will be string
 with the value of (as Perl literal) C<"!json null">.
 
 =head2 enable_quoting => bool (default: 1)
 
 If set to false, then quotes on key value will be ignored and key value will be
 parsed as verbatim. Example:
 
  name = "line 1\nline2"
 
 With C<enable_quoting> turned off, value will not be a two-line string, but will
 be a one line string with the value of (as Perl literal) C<"line 1\\nline2">.
 
 =head2 enable_bracket => bool (default: 1)
 
 If set to false, then JSON literal array will be parsed as verbatim. Example:
 
  name = [1,2,3]
 
 With C<enable_bracket> turned off, value will not be a three-element array, but
 will be a string with the value of (as Perl literal) C<"[1,2,3]">.
 
 =head2 enable_brace => bool (default: 1)
 
 If set to false, then JSON literal object (hash) will be parsed as verbatim.
 Example:
 
  name = {"a":1,"b":2}
 
 With C<enable_brace> turned off, value will not be a hash with two pairs, but
 will be a string with the value of (as Perl literal) C<'{"a":1,"b":2}'>.
 
 =head2 allow_encodings => array
 
 If defined, set list of allowed encodings. Note that if C<disallow_encodings> is
 also set, an encoding must also not be in that list.
 
 Also note that, for safety reason, if you want to enable C<expr> encoding,
 you'll also need to set C<enable_expr> to 1.
 
 =head2 disallow_encodings => array
 
 If defined, set list of disallowed encodings. Note that if C<allow_encodings> is
 also set, an encoding must also be in that list.
 
 Also note that, for safety reason, if you want to enable C<expr> encoding,
 you'll also need to set C<enable_expr> to 1.
 
 =head2 enable_expr => bool (default: 0)
 
 Whether to enable C<expr> encoding. By default this is turned on, for safety.
 Please see L</"EXPRESSION"> for more details.
 
 =head2 allow_directives => array
 
 If defined, only directives listed here are allowed. Note that if
 C<disallow_directives> is also set, a directive must also not be in that list.
 
 =head2 disallow_directives => array
 
 If defined, directives listed here are not allowed. Note that if
 C<allow_directives> is also set, a directive must also be in that list.
 
 =head2 allow_bang_only => bool (default: 1)
 
 Since the mistake of specifying a directive like this:
 
  !foo
 
 instead of the correct:
 
  ;!foo
 
 is very common, the spec allows it. This reader, however, can be configured to
 be more strict.
 
 =head2 allow_duplicate_key => bool (default: 1)
 
 If set to 0, you can forbid duplicate key, e.g.:
 
  [section]
  a=1
  a=2
 
 or:
 
  [section]
  a=1
  b=2
  c=3
  a=10
 
 In traditional INI file, to specify an array you specify multiple keys. But when
 there is only a single key, it is unclear if the value is a single-element array
 or a scalar. You can use this setting to avoid this array/scalar ambiguity in
 config file and force user to use JSON encoding or bracket to specify array:
 
  [section]
  a=[1,2]
 
 =head2 ignore_unknown_directive => bool (default: 0)
 
 If set to true, will not die if an unknown directive is encountered. It will
 simply be ignored as a regular comment.
 
 =for END_BLOCK: attributes
 
 =head1 EXPRESSION
 
 =for BEGIN_BLOCK: expression
 
 Expression allows you to do things like:
 
  [section1]
  foo=1
  bar="monkey"
 
  [section2]
  baz =!e 1+1
  qux =!e "grease" . val("section1.bar")
  quux=!e val("qux") . " " . val('baz')
 
 And the result will be:
 
  {
      section1 => {foo=>1, bar=>"monkey"},
      section2 => {baz=>2, qux=>"greasemonkey", quux=>"greasemonkey 2"},
  }
 
 For safety, you'll need to set C<enable_expr> attribute to 1 first to enable
 this feature.
 
 The syntax of the expression (the C<expr> encoding) is not officially specified
 yet in the L<IOD> specification. It will probably be Expr (see
 L<Language::Expr::Manual::Syntax>). At the moment, this module implements a very
 limited subset that is compatible (lowest common denominator) with Perl syntax
 and uses C<eval()> to evaluate the expression. However, only the limited subset
 is allowed (checked by Perl 5.10 regular expression).
 
 The supported terms:
 
  number
  string (double-quoted and single-quoted)
  undef literal
  function call (only the 'val' function is supported)
  grouping (parenthesis)
 
 The supported operators are:
 
  + - .
  * / % x
  **
  unary -, unary +, !, ~
 
 The C<val()> function refers to the configuration key. If the argument contains
 ".", it will be assumed as C<SECTIONNAME.KEYNAME>, otherwise it will access the
 current section's key. Since parsing is done in a single pass, you can only
 refer to the already mentioned key.
 
 =for END_BLOCK: expression
 
 =head1 METHODS
 
 =for BEGIN_BLOCK: methods
 
 =head2 new(%attrs) => obj
 
 =head2 $reader->read_file($filename)
 
 Read IOD configuration from a file. Die on errors.
 
 =head2 $reader->read_string($str)
 
 Read IOD configuration from a string. Die on errors.
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Config-IOD-Reader>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Config-IOD-Reader>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Config-IOD-Reader>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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
### Config/IOD/Expr.pm ###
 package Config::IOD::Expr;
 
 our $DATE = '2015-09-08'; # DATE
 our $VERSION = '0.19'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 
 my $EXPR_RE = qr{
 
 (?&ANSWER)
 
 (?(DEFINE)
 
 (?<ANSWER>    (?&ADD))
 (?<ADD>       (?&MULT)   | (?&MULT)  (?: \s* ([+.-]) \s* (?&MULT)  )+)
 (?<MULT>      (?&UNARY)  | (?&UNARY) (?: \s* ([*/x%]) \s* (?&UNARY))+)
 (?<UNARY>     (?&POWER)  | [!~+-] (?&POWER))
 (?<POWER>     (?&TERM)   | (?&TERM) (?: \s* \*\* \s* (?&TERM))+)
 
 (?<TERM>
     (?&NUM)
   | (?&STR_SINGLE)
   | (?&STR_DOUBLE)
   | undef
   | (?&FUNC)
   | \( \s* ((?&ANSWER)) \s* \)
 )
 
 (?<FUNC> val \s* \( (?&TERM) \))
 
 (?<NUM>
     (
      -?
      (?: 0 | [1-9]\d* )
      (?: \. \d+ )?
      (?: [eE] [-+]? \d+ )?
     )
 )
 
 (?<STR_SINGLE>
     (
      '
      (?:
          [^\\']+
        |
          \\ ['\\]
        |
          \\
      )*
      '
     )
 )
 
 (?<STR_DOUBLE>
     (
      "
      (?:
          [^\\"]+
        |
          \\ ["'\\\$tnrfbae]
 # octal, hex, wide hex
      )*
      "
     )
 )
 
 ) # DEFINE
 
 }msx;
 
 sub _parse_expr {
     my $str = shift;
 
     return [400, 'Not a valid expr'] unless $str =~ m{\A$EXPR_RE\z}o;
     my $res = eval $str;
     return [500, "Died when evaluating expr: $@"] if $@;
     [200, "OK", $res];
 }
 
 1;
 # ABSTRACT: Parse expression
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Config::IOD::Expr - Parse expression
 
 =head1 VERSION
 
 This document describes version 0.19 of Config::IOD::Expr (from Perl distribution Config-IOD-Reader), released on 2015-09-08.
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Config-IOD-Reader>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Config-IOD-Reader>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Config-IOD-Reader>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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
### Config/IOD/Reader.pm ###
 package Config::IOD::Reader;
 
 our $DATE = '2015-09-08'; # DATE
 our $VERSION = '0.19'; # VERSION
 
 use 5.010001;
 use strict;
 use warnings;
 
 use parent qw(Config::IOD::Base);
 
 sub _merge {
     my ($self, $section) = @_;
 
     my $res = $self->{_res};
     for my $msect (@{ $self->{_merge} }) {
         if ($msect eq $section) {
             # ignore merging self
             next;
             #local $self->{_linum} = $self->{_linum}-1;
             #$self->_err("Can't merge section '$msect' to '$section': ".
             #                "Same section");
         }
         if (!exists($res->{$msect})) {
             local $self->{_linum} = $self->{_linum}-1;
             $self->_err("Can't merge section '$msect' to '$section': ".
                             "Section '$msect' not seen yet");
         }
         for my $k (keys %{ $res->{$msect} }) {
             $res->{$section}{$k} //= $res->{$msect}{$k};
         }
     }
 }
 
 sub _init_read {
     my $self = shift;
 
     $self->SUPER::_init_read;
     $self->{_res} = {};
     $self->{_merge} = undef;
     $self->{_num_seen_section_lines} = 0;
     $self->{_cur_section} = $self->{default_section};
     $self->{_arrayified} = {};
 }
 
 sub _read_string {
     my ($self, $str) = @_;
 
     my $res = $self->{_res};
     my $cur_section = $self->{_cur_section};
 
     my $directive_re = $self->{allow_bang_only} ?
         qr/^;?\s*!\s*(\w+)\s*/ :
         qr/^;\s*!\s*(\w+)\s*/;
 
     my @lines = split /^/, $str;
     local $self->{_linum} = 0;
   LINE:
     for my $line (@lines) {
         $self->{_linum}++;
 
         # blank line
         if ($line !~ /\S/) {
             next LINE;
         }
 
         # directive line
         if ($line =~ s/$directive_re//) {
             my $directive = $1;
             if ($self->{allow_directives}) {
                 $self->_err("Directive '$directive' is not in ".
                                 "allow_directives list")
                     unless grep { $_ eq $directive }
                         @{$self->{allow_directives}};
             }
             if ($self->{disallow_directives}) {
                 $self->_err("Directive '$directive' is in ".
                                 "disallow_directives list")
                     if grep { $_ eq $directive }
                         @{$self->{disallow_directives}};
             }
             my $args = $self->_parse_command_line($line);
             if (!defined($args)) {
                 $self->_err("Invalid arguments syntax '$line'");
             }
             if ($directive eq 'include') {
                 my $path;
                 if (! @$args) {
                     $self->_err("Missing filename to include");
                 } elsif (@$args > 1) {
                     $self->_err("Extraneous arguments");
                 } else {
                     $path = $args->[0];
                 }
                 my $res = $self->_push_include_stack($path);
                 if ($res->[0] != 200) {
                     $self->_err("Can't include '$path': $res->[1]");
                 }
                 $path = $res->[2];
                 $self->_read_string($self->_read_file($path));
                 $self->_pop_include_stack;
             } elsif ($directive eq 'merge') {
                 $self->{_merge} = @$args ? $args : undef;
             } elsif ($directive eq 'noop') {
             } else {
                 if ($self->{ignore_unknown_directive}) {
                     # assume a regular comment
                     next LINE;
                 } else {
                     $self->_err("Unknown directive '$directive'");
                 }
             }
             next LINE;
         }
 
         # comment line
         if ($line =~ /^\s*[;#]/) {
             next LINE;
         }
 
         # section line
         if ($line =~ /^\s*\[\s*(.+?)\s*\](?: \s*[;#].*)?/) {
             my $prev_section = $self->{_cur_section};
             $self->{_cur_section} = $cur_section = $1;
             $res->{$cur_section} //= {};
             $self->{_num_seen_section_lines}++;
 
             # previous section exists? do merging for previous section
             if ($self->{_merge} && $self->{_num_seen_section_lines} > 1) {
                 $self->_merge($prev_section);
             }
 
             next LINE;
         }
 
         # key line
         if ($line =~ /^\s*([^=]+?)\s*=\s*(.*)/) {
             my $key = $1;
             my $val = $2;
 
             # the common case is that value are not decoded or
             # quoted/bracketed/braced, so we avoid calling _parse_raw_value here
             # to avoid overhead
             if ($val =~ /\A["!\\[\{]/) {
                 my ($err, $parse_res, $decoded_val) = $self->_parse_raw_value($val);
                 $self->_err("Invalid value: " . $err) if $err;
                 $val = $decoded_val;
             } else {
                 $val =~ s/\s*[#;].*//; # strip comment
             }
 
             if (exists $res->{$cur_section}{$key}) {
                 if (!$self->{allow_duplicate_key}) {
                     $self->_err("Duplicate key: $key (section $cur_section)");
                 } elsif ($self->{_arrayified}{$cur_section}{$key}++) {
                     push @{ $res->{$cur_section}{$key} }, $val;
                 } else {
                     $res->{$cur_section}{$key} = [
                         $res->{$cur_section}{$key}, $val];
                 }
             } else {
                 $res->{$cur_section}{$key} = $val;
             }
 
             next LINE;
         }
 
         $self->_err("Invalid syntax");
     }
 
     if ($self->{_merge} && $self->{_num_seen_section_lines} > 1) {
         $self->_merge($cur_section);
     }
 
     $res;
 }
 
 1;
 # ABSTRACT: Read IOD/INI configuration files
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Config::IOD::Reader - Read IOD/INI configuration files
 
 =head1 VERSION
 
 This document describes version 0.19 of Config::IOD::Reader (from Perl distribution Config-IOD-Reader), released on 2015-09-08.
 
 =head1 SYNOPSIS
 
  use Config::IOD::Reader;
  my $reader = Config::IOD::Reader->new(
      # list of known attributes, with their default values
      # default_section     => 'GLOBAL',
      # enable_encoding     => 1,
      # enable_quoting      => 1,
      # enable_backet       => 1,
      # enable_brace        => 1,
      # allow_encodings     => undef, # or ['base64','json',...]
      # disallow_encodings  => undef, # or ['base64','json',...]
      # allow_directives    => undef, # or ['include','merge',...]
      # disallow_directives => undef, # or ['include','merge',...]
      # allow_bang_only     => 1,
      # enable_expr         => 0,
  );
  my $config_hash = $reader->read_file('config.iod');
 
 =head1 DESCRIPTION
 
 This module reads L<IOD> configuration files (IOD is an INI-like format with
 more precise specification, some extra features, and 99% compatible with typical
 INI format). It is a minimalist alternative to the more fully-featured
 L<Config::IOD>. It cannot write IOD files and is optimized for low startup
 overhead.
 
 =head1 EXPRESSION
 
 Expression allows you to do things like:
 
  [section1]
  foo=1
  bar="monkey"
 
  [section2]
  baz =!e 1+1
  qux =!e "grease" . val("section1.bar")
  quux=!e val("qux") . " " . val('baz')
 
 And the result will be:
 
  {
      section1 => {foo=>1, bar=>"monkey"},
      section2 => {baz=>2, qux=>"greasemonkey", quux=>"greasemonkey 2"},
  }
 
 For safety, you'll need to set C<enable_expr> attribute to 1 first to enable
 this feature.
 
 The syntax of the expression (the C<expr> encoding) is not officially specified
 yet in the L<IOD> specification. It will probably be Expr (see
 L<Language::Expr::Manual::Syntax>). At the moment, this module implements a very
 limited subset that is compatible (lowest common denominator) with Perl syntax
 and uses C<eval()> to evaluate the expression. However, only the limited subset
 is allowed (checked by Perl 5.10 regular expression).
 
 The supported terms:
 
  number
  string (double-quoted and single-quoted)
  undef literal
  function call (only the 'val' function is supported)
  grouping (parenthesis)
 
 The supported operators are:
 
  + - .
  * / % x
  **
  unary -, unary +, !, ~
 
 The C<val()> function refers to the configuration key. If the argument contains
 ".", it will be assumed as C<SECTIONNAME.KEYNAME>, otherwise it will access the
 current section's key. Since parsing is done in a single pass, you can only
 refer to the already mentioned key.
 
 =head1 ATTRIBUTES
 
 =head2 default_section => str (default: C<GLOBAL>)
 
 If a key line is specified before any section line, this is the section that the
 key will be put in.
 
 =head2 enable_encoding => bool (default: 1)
 
 If set to false, then encoding notation will be ignored and key value will be
 parsed as verbatim. Example:
 
  name = !json null
 
 With C<enable_encoding> turned off, value will not be undef but will be string
 with the value of (as Perl literal) C<"!json null">.
 
 =head2 enable_quoting => bool (default: 1)
 
 If set to false, then quotes on key value will be ignored and key value will be
 parsed as verbatim. Example:
 
  name = "line 1\nline2"
 
 With C<enable_quoting> turned off, value will not be a two-line string, but will
 be a one line string with the value of (as Perl literal) C<"line 1\\nline2">.
 
 =head2 enable_bracket => bool (default: 1)
 
 If set to false, then JSON literal array will be parsed as verbatim. Example:
 
  name = [1,2,3]
 
 With C<enable_bracket> turned off, value will not be a three-element array, but
 will be a string with the value of (as Perl literal) C<"[1,2,3]">.
 
 =head2 enable_brace => bool (default: 1)
 
 If set to false, then JSON literal object (hash) will be parsed as verbatim.
 Example:
 
  name = {"a":1,"b":2}
 
 With C<enable_brace> turned off, value will not be a hash with two pairs, but
 will be a string with the value of (as Perl literal) C<'{"a":1,"b":2}'>.
 
 =head2 allow_encodings => array
 
 If defined, set list of allowed encodings. Note that if C<disallow_encodings> is
 also set, an encoding must also not be in that list.
 
 Also note that, for safety reason, if you want to enable C<expr> encoding,
 you'll also need to set C<enable_expr> to 1.
 
 =head2 disallow_encodings => array
 
 If defined, set list of disallowed encodings. Note that if C<allow_encodings> is
 also set, an encoding must also be in that list.
 
 Also note that, for safety reason, if you want to enable C<expr> encoding,
 you'll also need to set C<enable_expr> to 1.
 
 =head2 enable_expr => bool (default: 0)
 
 Whether to enable C<expr> encoding. By default this is turned on, for safety.
 Please see L</"EXPRESSION"> for more details.
 
 =head2 allow_directives => array
 
 If defined, only directives listed here are allowed. Note that if
 C<disallow_directives> is also set, a directive must also not be in that list.
 
 =head2 disallow_directives => array
 
 If defined, directives listed here are not allowed. Note that if
 C<allow_directives> is also set, a directive must also be in that list.
 
 =head2 allow_bang_only => bool (default: 1)
 
 Since the mistake of specifying a directive like this:
 
  !foo
 
 instead of the correct:
 
  ;!foo
 
 is very common, the spec allows it. This reader, however, can be configured to
 be more strict.
 
 =head2 allow_duplicate_key => bool (default: 1)
 
 If set to 0, you can forbid duplicate key, e.g.:
 
  [section]
  a=1
  a=2
 
 or:
 
  [section]
  a=1
  b=2
  c=3
  a=10
 
 In traditional INI file, to specify an array you specify multiple keys. But when
 there is only a single key, it is unclear if the value is a single-element array
 or a scalar. You can use this setting to avoid this array/scalar ambiguity in
 config file and force user to use JSON encoding or bracket to specify array:
 
  [section]
  a=[1,2]
 
 =head2 ignore_unknown_directive => bool (default: 0)
 
 If set to true, will not die if an unknown directive is encountered. It will
 simply be ignored as a regular comment.
 
 =head1 METHODS
 
 =head2 new(%attrs) => obj
 
 =head2 $reader->read_file($filename) => hash
 
 Read IOD configuration from a file. Die on errors.
 
 =head2 $reader->read_string($str) => hash
 
 Read IOD configuration from a string. Die on errors.
 
 =head1 SEE ALSO
 
 L<IOD> - specification
 
 L<Config::IOD> - round-trip parser for reading as well as writing IOD documents
 
 L<IOD::Examples> - sample documents
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Config-IOD-Reader>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Config-IOD-Reader>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Config-IOD-Reader>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Check/Structure.pm ###
 package Data::Check::Structure;
 
 our $DATE = '2014-07-14'; # DATE
 our $VERSION = '0.03'; # VERSION
 
 use 5.010001;
 use strict;
 use warnings;
 
 require Exporter;
 our @ISA = qw(Exporter);
 our @EXPORT_OK = qw(
                        is_aoa
                        is_aoaos
                        is_aoh
                        is_aohos
                        is_aos
                        is_hoa
                        is_hoaos
                        is_hoh
                        is_hohos
                        is_hos
                );
 
 sub is_aos {
     my ($data, $opts) = @_;
     $opts //= {};
     my $max = $opts->{max};
 
     return 0 unless ref($data) eq 'ARRAY';
     for my $i (0..@$data-1) {
         last if defined($max) && $i >= $max;
         return 0 if ref($data->[$i]);
     }
     1;
 }
 
 sub is_aoa {
     my ($data, $opts) = @_;
     $opts //= {};
     my $max = $opts->{max};
 
     return 0 unless ref($data) eq 'ARRAY';
     for my $i (0..@$data-1) {
         last if defined($max) && $i >= $max;
         return 0 unless ref($data->[$i]) eq 'ARRAY';
     }
     1;
 }
 
 sub is_aoaos {
     my ($data, $opts) = @_;
     $opts //= {};
     my $max = $opts->{max};
 
     return 0 unless ref($data) eq 'ARRAY';
     my $aos_opts = {max=>$max};
     for my $i (0..@$data-1) {
         last if defined($max) && $i >= $max;
         return 0 unless is_aos($data->[$i], $aos_opts);
     }
     1;
 }
 
 sub is_aoh {
     my ($data, $opts) = @_;
     $opts //= {};
     my $max = $opts->{max};
 
     return 0 unless ref($data) eq 'ARRAY';
     for my $i (0..@$data-1) {
         last if defined($max) && $i >= $max;
         return 0 unless ref($data->[$i]) eq 'HASH';
     }
     1;
 }
 
 sub is_aohos {
     my ($data, $opts) = @_;
     $opts //= {};
     my $max = $opts->{max};
 
     return 0 unless ref($data) eq 'ARRAY';
     my $hos_opts = {max=>$max};
     for my $i (0..@$data-1) {
         last if defined($max) && $i >= $max;
         return 0 unless is_hos($data->[$i], $hos_opts);
     }
     1;
 }
 
 sub is_hos {
     my ($data, $opts) = @_;
     $opts //= {};
     my $max = $opts->{max};
 
     return 0 unless ref($data) eq 'HASH';
     my $i = 0;
     for my $k (keys %$data) {
         last if defined($max) && ++$i >= $max;
         return 0 if ref($data->{$k});
     }
     1;
 }
 
 sub is_hoa {
     my ($data, $opts) = @_;
     $opts //= {};
     my $max = $opts->{max};
 
     return 0 unless ref($data) eq 'HASH';
     my $i = 0;
     for my $k (keys %$data) {
         last if defined($max) && ++$i >= $max;
         return 0 unless ref($data->{$k}) eq 'ARRAY';
     }
     1;
 }
 
 sub is_hoaos {
     my ($data, $opts) = @_;
     $opts //= {};
     my $max = $opts->{max};
 
     return 0 unless ref($data) eq 'HASH';
     my $i = 0;
     for my $k (keys %$data) {
         last if defined($max) && ++$i >= $max;
         return 0 unless is_aos($data->{$k});
     }
     1;
 }
 
 sub is_hoh {
     my ($data, $opts) = @_;
     $opts //= {};
     my $max = $opts->{max};
 
     return 0 unless ref($data) eq 'HASH';
     my $i = 0;
     for my $k (keys %$data) {
         last if defined($max) && ++$i >= $max;
         return 0 unless ref($data->{$k}) eq 'HASH';
     }
     1;
 }
 
 sub is_hohos {
     my ($data, $opts) = @_;
     $opts //= {};
     my $max = $opts->{max};
 
     return 0 unless ref($data) eq 'HASH';
     my $i = 0;
     for my $k (keys %$data) {
         last if defined($max) && ++$i >= $max;
         return 0 unless is_hos($data->{$k});
     }
     1;
 }
 
 1;
 # ABSTRACT: Check structure of data
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Check::Structure - Check structure of data
 
 =head1 VERSION
 
 This document describes version 0.03 of Data::Check::Structure (from Perl distribution Data-Check-Structure), released on 2014-07-14.
 
 =head1 SYNOPSIS
 
 =head1 DESCRIPTION
 
 This small module provides several simple routines to check the structure of
 data, e.g. whether data is an array of arrays ("aoa"), array of scalars ("aos"),
 and so on.
 
 =head1 FUNCTIONS
 
 =head2 is_aos($data, \%opts) => bool
 
 Check that data is an array of scalars. Examples:
 
  is_aos([]);                     # true
  is_aos(['a', 'b']);             # true
  is_aos(['a', []]);              # false
  is_aos([1,2,3, []], {max=>3});  # true
 
 Known options: C<max> (maximum number of items to check, undef means check all
 items).
 
 =head2 is_aoa($data, \%opts) => bool
 
 Check that data is an array of arrays. Examples:
 
  is_aoa([]);                          # true
  is_aoa([[1], [2]]);                  # true
  is_aoa([[1], 'a']);                  # false
  is_aoa([[1],[],[], 'a'], {max=>3});  # true
 
 Known options: C<max> (maximum number of items to check, undef means check all
 items).
 
 =head2 is_aoaos($data, \%opts) => bool
 
 Check that data is an array of arrays of scalars. Examples:
 
  is_aoaos([]);                           # true
  is_aoaos([[1], [2]]);                   # true
  is_aoaos([[1], [{}]]);                  # false
  is_aoaos([[1],[],[], [{}]], {max=>3});  # true
 
 Known options: C<max> (maximum number of items to check, undef means check all
 items).
 
 =head2 is_aoh($data, \%opts) => bool
 
 Check that data is an array of hashes. Examples:
 
  is_aoh([]);                             # true
  is_aoh([{}, {a=>1}]);                   # true
  is_aoh([{}, 'a']);                      # false
  is_aoh([{},{},{a=>1}, 'a'], {max=>3});  # true
 
 Known options: C<max> (maximum number of items to check, undef means check all
 items).
 
 =head2 is_aohos($data, \%opts) => bool
 
 Check that data is an array of hashes of scalars. Examples:
 
  is_aohos([]);                                 # true
  is_aohos([{a=>1}, {}]);                       # true
  is_aohos([{a=>1}, {b=>[]}]);                  # false
  is_aohos([{a=>1},{},{}, {b=>[]}], {max=>3});  # true
 
 Known options: C<max> (maximum number of items to check, undef means check all
 items).
 
 =head2 is_hos($data, \%opts) => bool
 
 Check that data is a hash of scalars. Examples:
 
  is_hos({});                                   # true
  is_hos({a=>1, b=>2});                         # true
  is_hos({a=>1, b=>[]});                        # false
  is_hos({a=>1, b=>2, c=>3, d=>[]}, {max=>3});  # true (or false, depending on random hash key ordering)
 
 Known options: C<max> (maximum number of items to check, undef means check all
 items).
 
 =head2 is_hoa($data, \%opts) => bool
 
 Check that data is a hash of arrays. Examples:
 
  is_hoa({}) );       # true
  is_hoa({a=>[]}) );  # true
  is_hoa({a=>1}) );   # false
 
 Known options: C<max> (maximum number of items to check, undef means check all
 items).
 
 =head2 is_hoaos($data, \%opts) => bool
 
 Check that data is a hash of arrays of scalars. Examples:
 
  is_hoaos({}) );         # true
  is_hoaos({a=>[]}) );    # true
  is_hoaos({a=>[1]}) );   # true
  is_hoaos({a=>1}) );     # false
  is_hoaos({a=>[{}]}) );  # false
 
 Known options: C<max> (maximum number of items to check, undef means check all
 items).
 
 =head2 is_hoh($data, \%opts) => bool
 
 Check that data is a hash of hashes. Examples:
 
  is_hoh({}) );       # true
  is_hoh({a=>{}}) );  # true
  is_hoh({a=>1}) );   # false
 
 Known options: C<max> (maximum number of items to check, undef means check all
 items).
 
 =head2 is_hohos($data, \%opts) => bool
 
 Check that data is a hash of hashes of scalrs. Examples:
 
  is_hohos({}) );            # true
  is_hohos({a=>{}}) );       # true
  is_hohos({a=>{b=>1}}) );   # true
  is_hohos({a=>1}) );        # false
  is_hohos({a=>{b=>[]}}) );  # false
 
 Known options: C<max> (maximum number of items to check, undef means check all
 items).
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Check-Structure>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Check-Structure>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Check-Structure>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 Steven Haryanto <stevenharyanto@gmail.com>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2014 by Steven Haryanto.
 
 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/Clean/Base.pm ###
 package Data::Clean::Base;
 
 our $DATE = '2015-06-10'; # DATE
 our $VERSION = '0.28'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 use Log::Any::IfLOG '$log';
 
 use Function::Fallback::CoreOrPP qw(clone);
 use Scalar::Util qw();
 
 sub new {
     my ($class, %opts) = @_;
     my $self = bless {opts=>\%opts}, $class;
     $log->tracef("Cleanser options: %s", \%opts);
     $self->_generate_cleanser_code;
     $self;
 }
 
 sub command_call_method {
     my ($self, $args) = @_;
     my $mn = $args->[0];
     die "Invalid method name syntax" unless $mn =~ /\A\w+\z/;
     return "{{var}} = {{var}}->$mn; \$ref = ref({{var}})";
 }
 
 sub command_call_func {
     my ($self, $args) = @_;
     my $fn = $args->[0];
     die "Invalid func name syntax" unless $fn =~ /\A\w+(::\w+)*\z/;
     return "{{var}} = $fn({{var}}); \$ref = ref({{var}})";
 }
 
 sub command_one_or_zero {
     my ($self, $args) = @_;
     return "{{var}} = {{var}} ? 1:0; \$ref = ''";
 }
 
 sub command_deref_scalar {
     my ($self, $args) = @_;
     return '{{var}} = ${ {{var}} }; $ref = ref({{var}})';
 }
 
 sub command_stringify {
     my ($self, $args) = @_;
     return '{{var}} = "{{var}}"';
 }
 
 sub command_replace_with_ref {
     my ($self, $args) = @_;
     return '{{var}} = $ref; $ref = ""';
 }
 
 sub command_replace_with_str {
     require String::PerlQuote;
 
     my ($self, $args) = @_;
     return "{{var}} = ".String::PerlQuote::double_quote($args->[0]).'; $ref=""';
 }
 
 sub command_unbless {
     my ($self, $args) = @_;
 
     # Data::Clone by default does not clone objects, so Acme::Damn can modify
     # the original object despite the use of clone(), so we need to know whether
     # user runs clone_and_clean() or clean_in_place() and avoid the use of
     # Acme::Damn for the former case. this workaround will be unnecessary when
     # Data::Clone clones objects.
 
     my $acme_damn_available = eval { require Acme::Damn; 1 } ? 1:0;
     return join(
         "",
         "if (!\$Data::Clean::Base::_clone && $acme_damn_available) { ",
         "{{var}} = Acme::Damn::damn({{var}}) ",
         "} else { ",
         "{{var}} = Function::Fallback::CoreOrPP::_unbless_fallback({{var}}) } ",
         "\$ref = ref({{var}})",
     );
 }
 
 sub command_clone {
     my $clone_func;
     eval { require Data::Clone };
     if ($@) {
         require Clone::PP;
         $clone_func = "Clone::PP::clone";
     } else {
         $clone_func = "Data::Clone::clone";
     }
 
     my ($self, $args) = @_;
     my $limit = $args->[0] // 1;
     return join(
         "",
         "if (++\$ctr_circ <= $limit) { ",
         "{{var}} = $clone_func({{var}}); redo ",
         "} else { ",
         "{{var}} = 'CIRCULAR' } ",
         "\$ref = ref({{var}})",
     );
 }
 
 # test
 sub command_die {
     my ($self, $args) = @_;
     return "die";
 }
 
 sub _generate_cleanser_code {
     my $self = shift;
     my $opts = $self->{opts};
 
     my (@code, @stmts_ary, @stmts_hash, @stmts_main);
 
     my $n = 0;
     my $add_stmt = sub {
         my $which = shift;
         if ($which eq 'if' || $which eq 'new_if') {
             my ($cond0, $act0) = @_;
             for ([\@stmts_ary, '$e', 'ary'],
                  [\@stmts_hash, '$h->{$k}', 'hash'],
                  [\@stmts_main, '$_', 'main']) {
                 my $act  = $act0 ; $act  =~ s/\Q{{var}}\E/$_->[1]/g;
                 my $cond = $cond0; $cond =~ s/\Q{{var}}\E/$_->[1]/g;
                 #unless (@{ $_->[0] }) { push @{ $_->[0] }, '    say "D:'.$_->[2].' val=", '.$_->[1].', ", ref=$ref"; # DEBUG'."\n" }
                 push @{ $_->[0] }, "    ".($n && $which ne 'new_if' ? "els":"")."if ($cond) { $act }\n";
             }
             $n++;
         } else {
             my ($stmt0) = @_;
             for ([\@stmts_ary, '$e', 'ary'],
                  [\@stmts_hash, '$h->{$k}', 'hash'],
                  [\@stmts_main, '$_', 'main']) {
                 my $stmt = $stmt0; $stmt =~ s/\Q{{var}}\E/$_->[1]/g;
                 push @{ $_->[0] }, "    $stmt;\n";
             }
         }
     };
     my $add_if = sub {
         $add_stmt->('if', @_);
     };
     my $add_new_if = sub {
         $add_stmt->('new_if', @_);
     };
     my $add_if_ref = sub {
         my ($ref, $act0) = @_;
         $add_if->("\$ref eq '$ref'", $act0);
     };
     my $add_new_if_ref = sub {
         my ($ref, $act0) = @_;
         $add_new_if->("\$ref eq '$ref'", $act0);
     };
 
     # catch object of specified classes (e.g. DateTime, etc)
     for my $on (grep {/\A\w*(::\w+)*\z/} sort keys %$opts) {
         my $o = $opts->{$on};
         next unless $o;
         my $meth = "command_$o->[0]";
         die "Can't handle command $o->[0] for option '$on'" unless $self->can($meth);
         my @args = @$o; shift @args;
         my $act = $self->$meth(\@args);
         $add_if_ref->($on, $act);
     }
 
     # catch general object not caught by previous
     for my $p ([-obj => 'Scalar::Util::blessed({{var}})']) {
         my $o = $opts->{$p->[0]};
         next unless $o;
         my $meth = "command_$o->[0]";
         die "Can't handle command $o->[0] for option '$p->[0]'" unless $self->can($meth);
         my @args = @$o; shift @args;
         $add_if->($p->[1], $self->$meth(\@args));
     }
 
     # catch circular references
     my $circ = $opts->{-circular};
     if ($circ) {
         my $meth = "command_$circ->[0]";
         die "Can't handle command $circ->[0] for option '-circular'" unless $self->can($meth);
         my @args = @$circ; shift @args;
         my $act = $self->$meth(\@args);
         #$add_stmt->('stmt', 'say "ref=$ref, " . {{var}}'); # DEBUG
         $add_new_if->('$ref && $refs{ {{var}} }++', $act);
     }
 
     # recurse array and hash
     $add_new_if_ref->("ARRAY", '$process_array->({{var}})');
     $add_if_ref->("HASH" , '$process_hash->({{var}})');
 
     # lastly, catch any reference left
     for my $p ([-ref => '$ref']) {
         my $o = $opts->{$p->[0]};
         next unless $o;
         my $meth = "command_$o->[0]";
         die "Can't handle command $o->[0] for option '$p->[0]'" unless $self->can($meth);
         my @args = @$o; shift @args;
         $add_if->($p->[1], $self->$meth(\@args));
     }
 
     push @code, 'sub {'."\n";
     push @code, 'my $data = shift;'."\n";
     push @code, 'state %refs;'."\n" if $circ;
     push @code, 'state $ctr_circ;'."\n" if $circ;
     push @code, 'state $process_array;'."\n";
     push @code, 'state $process_hash;'."\n";
     push @code, 'if (!$process_array) { $process_array = sub { my $a = shift; for my $e (@$a) { my $ref=ref($e);'."\n".join("", @stmts_ary).'} } }'."\n";
     push @code, 'if (!$process_hash) { $process_hash = sub { my $h = shift; for my $k (keys %$h) { my $ref=ref($h->{$k});'."\n".join("", @stmts_hash).'} } }'."\n";
     push @code, '%refs = (); $ctr_circ=0;'."\n" if $circ;
     push @code, 'for ($data) { my $ref=ref($_);'."\n".join("", @stmts_main).'}'."\n";
     push @code, '$data'."\n";
     push @code, '}'."\n";
 
     my $code = join("", @code).";";
 
     if ($ENV{LOG_CLEANSER_CODE} && $log->is_trace) {
         require String::LineNumber;
         $log->tracef("Cleanser code:\n%s",
                      $ENV{LINENUM} // 1 ?
                          String::LineNumber::linenum($code) : $code);
     }
     eval "\$self->{code} = $code";
     die "Can't generate code: $@" if $@;
     $self->{src} = $code;
 }
 
 sub clean_in_place {
     my ($self, $data) = @_;
 
     $self->{code}->($data);
 }
 
 sub clone_and_clean {
     my ($self, $data) = @_;
     my $clone = clone($data);
     local $Data::Clean::Base::_clone = 1;
     $self->clean_in_place($clone);
 }
 
 1;
 # ABSTRACT: Base class for Data::Clean::*
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Clean::Base - Base class for Data::Clean::*
 
 =head1 VERSION
 
 This document describes version 0.28 of Data::Clean::Base (from Perl distribution Data-Clean-JSON), released on 2015-06-10.
 
 =for Pod::Coverage ^(command_.+)$
 
 =head1 METHODS
 
 =head2 new(%opts) => $obj
 
 Create a new instance.
 
 Options specify what to do with problematic data. Option keys are either
 reference types or class names, or C<-obj> (to refer to objects, a.k.a. blessed
 references), C<-circular> (to refer to circular references), C<-ref> (to refer
 to references, used to process references not handled by other options). Option
 values are arrayrefs, the first element of the array is command name, to specify
 what to do with the reference/class. The rest are command arguments.
 
 Note that arrayrefs and hashrefs are always walked into, so it's not trapped by
 C<-ref>.
 
 Default for C<%opts>: C<< -ref => 'stringify' >>.
 
 Available commands:
 
 =over 4
 
 =item * ['stringify']
 
 This will stringify a reference like C<{}> to something like C<HASH(0x135f998)>.
 
 =item * ['replace_with_ref']
 
 This will replace a reference like C<{}> with C<HASH>.
 
 =item * ['replace_with_str', STR]
 
 This will replace a reference like C<{}> with I<STR>.
 
 =item * ['call_method']
 
 This will call a method and use its return as the replacement. For example:
 DateTime->from_epoch(epoch=>1000) when processed with [call_method => 'epoch']
 will become 1000.
 
 =item * ['call_func', STR]
 
 This will call a function named STR with value as argument and use its return as
 the replacement.
 
 =item * ['one_or_zero', STR]
 
 This will perform C<< $val ? 1:0 >>.
 
 =item * ['deref_scalar']
 
 This will replace a scalar reference like \1 with 1.
 
 =item * ['unbless']
 
 This will perform unblessing using L<Function::Fallback::CoreOrPP::unbless()>.
 Should be done only for objects (C<-obj>).
 
 =item * ['code', STR]
 
 This will replace with STR treated as Perl code.
 
 =item * ['clone', INT]
 
 This command is useful if you have circular references and want to expand/copy
 them. For example:
 
  my $def_opts = { opt1 => 'default', opt2 => 0 };
  my $users    = { alice => $def_opts, bob => $def_opts, charlie => $def_opts };
 
 C<$users> contains three references to the same data structure. With the default
 behaviour of C<< -circular => [replace_with_str => 'CIRCULAR'] >> the cleaned
 data structure will be:
 
  { alice   => { opt1 => 'default', opt2 => 0 },
    bob     => 'CIRCULAR',
    charlie => 'CIRCULAR' }
 
 But with C<< -circular => ['clone'] >> option, the data structure will be
 cleaned to become (the C<$def_opts> is cloned):
 
  { alice   => { opt1 => 'default', opt2 => 0 },
    bob     => { opt1 => 'default', opt2 => 0 },
    charlie => { opt1 => 'default', opt2 => 0 }, }
 
 The command argument specifies the number of references to clone as a limit (the
 default is 50), since a cyclical structure can lead to infinite cloning. Above
 this limit, the circular references will be replaced with a string
 C<"CIRCULAR">. For example:
 
  my $a = [1]; push @$a, $a;
 
 With C<< -circular => ['clone', 2] >> the data will be cleaned as:
 
  [1, [1, [1, "CIRCULAR"]]]
 
 With C<< -circular => ['clone', 3] >> the data will be cleaned as:
 
  [1, [1, [1, [1, "CIRCULAR"]]]]
 
 =back
 
 =head2 $obj->clean_in_place($data) => $cleaned
 
 Clean $data. Modify data in-place.
 
 =head2 $obj->clone_and_clean($data) => $cleaned
 
 Clean $data. Clone $data first.
 
 =head1 ENVIRONMENT
 
 =over
 
 =item * LOG_CLEANSER_CODE => BOOL (default: 0)
 
 Can be enabled if you want to see the generated cleanser code. It is logged at
 level C<trace>.
 
 =item * LINENUM => BOOL (default: 1)
 
 When logging cleanser code, whether to give line numbers.
 
 =back
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Clean-JSON>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Data-Clean-JSON>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Clean-JSON>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Clean/FromJSON.pm ###
 package Data::Clean::FromJSON;
 
 our $DATE = '2015-06-10'; # DATE
 our $VERSION = '0.28'; # VERSION
 
 use 5.010001;
 use strict;
 use warnings;
 
 use parent qw(Data::Clean::Base);
 
 sub new {
     my ($class, %opts) = @_;
     $opts{"JSON::XS::Boolean"} //= ['one_or_zero'];
     $opts{"JSON::PP::Boolean"} //= ['one_or_zero'];
     $class->SUPER::new(%opts);
 }
 
 sub get_cleanser {
     my $class = shift;
     state $singleton = $class->new;
     $singleton;
 }
 
 1;
 # ABSTRACT: Clean data from JSON decoder
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Clean::FromJSON - Clean data from JSON decoder
 
 =head1 VERSION
 
 This document describes version 0.28 of Data::Clean::FromJSON (from Perl distribution Data-Clean-JSON), released on 2015-06-10.
 
 =head1 SYNOPSIS
 
  use Data::Clean::FromJSON;
  use JSON;
  my $cleanser = Data::Clean::FromJSON->get_cleanser;
  my $data    = JSON->new->decode('[true]'); # -> [bless(do{\(my $o=1)},"JSON::XS::Boolean")]
  my $cleaned = $cleanser->clean_in_place($data); # -> [1]
 
 =head1 DESCRIPTION
 
 This class can convert L<JSON::PP::Boolean> (or C<JSON::XS::Boolean>) objects to
 1/0 values.
 
 =head1 METHODS
 
 =head2 CLASS->get_cleanser => $obj
 
 Return a singleton instance, with default options. Use C<new()> if you want to
 customize options.
 
 =head2 CLASS->new(%opts) => $obj
 
 Create a new instance. For list of known options, see L<Data::Clean::Base>.
 Data::Clean::FromJSON sets some defaults.
 
     "JSON::PP::Boolean" => ['one_or_zero']
     "JSON::XS::Boolean" => ['one_or_zero']
 
 =head2 $obj->clean_in_place($data) => $cleaned
 
 Clean $data. Modify data in-place.
 
 =head2 $obj->clone_and_clean($data) => $cleaned
 
 Clean $data. Clone $data first.
 
 =head1 ENVIRONMENT
 
 LOG_CLEANSER_CODE
 
 =head1 FAQ
 
 =head2 Why am I getting 'Modification of a read-only value attempted at lib/Data/Clean/Base.pm line xxx'?
 
 [2013-10-15 ] This is also from Data::Clone::clone() when it encounters
 JSON::{PP,XS}::Boolean objects. You can use clean_in_place() instead of
 clone_and_clean(), or clone your data using other cloner like L<Sereal>.
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Clean-JSON>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Data-Clean-JSON>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Clean-JSON>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Clean/JSON.pm ###
 package Data::Clean::JSON;
 
 our $DATE = '2015-06-10'; # DATE
 our $VERSION = '0.28'; # VERSION
 
 use 5.010001;
 use strict;
 use warnings;
 
 use parent qw(Data::Clean::Base);
 
 sub new {
     my ($class, %opts) = @_;
     $opts{DateTime}  //= [call_method => 'epoch'];
     $opts{'Time::Moment'} //= [call_method => 'epoch'];
     $opts{Regexp}    //= ['stringify'];
     $opts{SCALAR}    //= ['deref_scalar'];
     $opts{-ref}      //= ['replace_with_ref'];
     $opts{-circular} //= ['clone'];
     $opts{-obj}      //= ['unbless'];
     $class->SUPER::new(%opts);
 }
 
 sub get_cleanser {
     my $class = shift;
     state $singleton = $class->new;
     $singleton;
 }
 
 1;
 # ABSTRACT: Clean data so it is safe to output to JSON
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Clean::JSON - Clean data so it is safe to output to JSON
 
 =head1 VERSION
 
 This document describes version 0.28 of Data::Clean::JSON (from Perl distribution Data-Clean-JSON), released on 2015-06-10.
 
 =head1 SYNOPSIS
 
  use Data::Clean::JSON;
  my $cleanser = Data::Clean::JSON->get_cleanser;
  my $data     = { code=>sub {}, re=>qr/abc/i };
 
  my $cleaned;
 
  # modifies data in-place
  $cleaned = $cleanser->clean_in_place($data);
 
  # ditto, but deep clone first, return
  $cleaned = $cleanser->clone_and_clean($data);
 
  # now output it
  use JSON;
  print encode_json($cleaned); # prints '{"code":"CODE","re":"(?^i:abc)"}'
 
 =head1 DESCRIPTION
 
 This class cleans data from anything that might be problematic when encoding to
 JSON. This includes coderefs, globs, and so on.
 
 Data that has been cleaned will probably not be convertible back to the
 original, due to information loss (for example, coderefs converted to string
 C<"CODE">).
 
 The design goals are good performance, good defaults, and just enough
 flexibility. The original use-case is for returning JSON response in HTTP API
 service.
 
 This module is significantly faster than modules like L<Data::Rmap> or
 L<Data::Visitor::Callback> because with something like Data::Rmap you repeatedly
 invoke callback for each data item. This module, on the other hand, generates a
 cleanser code using eval(), using native Perl for() loops.
 
 If C<LOG_CLEANSER_CODE> environment is set to true, the generated cleanser code
 will be logged using L<Log::Any> at trace level. You can see it, e.g. using
 L<Log::Any::App>:
 
  % LOG=1 LOG_CLEANSER_CODE=1 TRACE=1 perl -MLog::Any::App -MData::Clean::JSON \
    -e'$c=Data::Clean::JSON->new; ...'
 
 =head1 METHODS
 
 =head2 CLASS->get_cleanser => $obj
 
 Return a singleton instance, with default options. Use C<new()> if you want to
 customize options.
 
 =head2 CLASS->new(%opts) => $obj
 
 Create a new instance. For list of known options, see L<Data::Clean::Base>.
 Data::Clean::JSON sets some defaults.
 
     DateTime  => [call_method => 'epoch']
     Regexp    => ['stringify']
     SCALAR    => ['deref_scalar']
     -ref      => ['replace_with_ref']
     -circular => ['clone']
     -obj      => ['unbless']
 
 =head2 $obj->clean_in_place($data) => $cleaned
 
 Clean $data. Modify data in-place.
 
 =head2 $obj->clone_and_clean($data) => $cleaned
 
 Clean $data. Clone $data first.
 
 =head1 ENVIRONMENT
 
 LOG_CLEANSER_CODE
 
 =head1 FAQ
 
 =head2 Why clone/modify? Why not directly output JSON?
 
 So that the data can be used for other stuffs, like outputting to YAML, etc.
 
 =head2 Why is it slow?
 
 If you use C<new()> instead of C<get_cleanser()>, make sure that you do not
 construct the Data::Clean::JSON object repeatedly, as the constructor generates
 the cleanser code first using eval(). A short benchmark (run on my slow Atom
 netbook):
 
  % bench -MData::Clean::JSON -b'$c=Data::Clean::JSON->new' \
      'Data::Clean::JSON->new->clone_and_clean([1..100])' \
      '$c->clone_and_clean([1..100])'
  Benchmarking sub { Data::Clean::JSON->new->clean_in_place([1..100]) }, sub { $c->clean_in_place([1..100]) } ...
  a: 302 calls (291.3/s), 1.037s (3.433ms/call)
  b: 7043 calls (4996/s), 1.410s (0.200ms/call)
  Fastest is b (17.15x a)
 
 Second, you can turn off some checks if you are sure you will not be getting bad
 data. For example, if you know that your input will not contain circular
 references, you can turn off circular detection:
 
  $cleanser = Data::Clean::JSON->new(-circular => 0);
 
 Benchmark:
 
  $ perl -MData::Clean::JSON -MBench -E '
    $data = [[1],[2],[3],[4],[5]];
    bench {
        circ   => sub { state $c = Data::Clean::JSON->new;               $c->clone_and_clean($data) },
        nocirc => sub { state $c = Data::Clean::JSON->new(-circular=>0); $c->clone_and_clean($data) }
    }, -1'
  circ: 9456 calls (9425/s), 1.003s (0.106ms/call)
  nocirc: 13161 calls (12885/s), 1.021s (0.0776ms/call)
  Fastest is nocirc (1.367x circ)
 
 The less number of checks you do, the faster the cleansing process will be.
 
 =head2 Why am I getting 'Not a CODE reference at lib/Data/Clean/Base.pm line xxx'?
 
 [2013-08-07 ] This error message is from Data::Clone::clone() when it is cloning
 an object. If you are cleaning objects, instead of using clone_and_clean(), try
 using clean_in_place(). Or, clone your data first using something else like
 L<Sereal>.
 
 =head1 SEE ALSO
 
 L<Data::Rmap>
 
 L<Data::Visitor::Callback>
 
 L<Data::Abridge> is similar in goal, which is to let Perl data structures (which
 might contain stuffs unsupported in JSON) be encodeable to JSON. But unlike
 Data::Clean::JSON, it has some (currently) non-configurable rules, like changing
 a coderef with a hash C<< {CODE=>'\&main::__ANON__'} >> or a scalar ref with C<<
 {SCALAR=>'value'} >> and so on. Note that the abridging process is similarly
 unidirectional (you cannot convert back the original Perl data structure).
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Clean-JSON>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Data-Clean-JSON>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Clean-JSON>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Dmp.pm ###
 package Data::Dmp;
 
 our $DATE = '2015-09-27'; # DATE
 our $VERSION = '0.13'; # VERSION
 
 use 5.010001;
 use strict;
 use warnings;
 
 use Scalar::Util qw(looks_like_number blessed reftype refaddr);
 
 require Exporter;
 our @ISA = qw(Exporter);
 our @EXPORT = qw(dd dmp);
 
 # for when dealing with circular refs
 our %_seen_refaddrs;
 our %_subscripts;
 our @_fixups;
 
 our $OPT_PERL_VERSION = "5.010";
 
 # BEGIN COPY PASTE FROM Data::Dump
 my %esc = (
     "\a" => "\\a",
     "\b" => "\\b",
     "\t" => "\\t",
     "\n" => "\\n",
     "\f" => "\\f",
     "\r" => "\\r",
     "\e" => "\\e",
 );
 
 # put a string value in double quotes
 sub _double_quote {
     local($_) = $_[0];
 
     # If there are many '"' we might want to use qq() instead
     s/([\\\"\@\$])/\\$1/g;
     return qq("$_") unless /[^\040-\176]/;  # fast exit
 
     s/([\a\b\t\n\f\r\e])/$esc{$1}/g;
 
     # no need for 3 digits in escape for these
     s/([\0-\037])(?!\d)/sprintf('\\%o',ord($1))/eg;
 
     s/([\0-\037\177-\377])/sprintf('\\x%02X',ord($1))/eg;
     s/([^\040-\176])/sprintf('\\x{%X}',ord($1))/eg;
 
     return qq("$_");
 }
 # END COPY PASTE FROM Data::Dump
 
 sub _dump {
     my ($val, $subscript) = @_;
 
     my $ref = ref($val);
     if ($ref eq '') {
         if (!defined($val)) {
             return "undef";
         } elsif (looks_like_number($val)) {
             return $val;
         } else {
             return _double_quote($val);
         }
     }
     my $refaddr = refaddr($val);
     $_subscripts{$refaddr} //= $subscript;
     if ($_seen_refaddrs{$refaddr}++) {
         push @_fixups, "\$a->$subscript=\$a",
             ($_subscripts{$refaddr} ? "->$_subscripts{$refaddr}" : ""), ";";
         return "'fix'";
     }
 
     my $class;
 
     if ($ref eq 'Regexp' || $ref eq 'REGEXP') {
         require Regexp::Stringify;
         return Regexp::Stringify::stringify_regexp(
             regexp=>$val, with_qr=>1, plver=>$OPT_PERL_VERSION);
     }
 
     if (blessed $val) {
         $class = $ref;
         $ref = reftype($val);
     }
 
     my $res;
     if ($ref eq 'ARRAY') {
         $res = "[";
         my $i = 0;
         for (@$val) {
             $res .= "," if $i;
             $res .= _dump($_, "$subscript\[$i]");
             $i++;
         }
         $res .= "]";
     } elsif ($ref eq 'HASH') {
         $res = "{";
         my $i = 0;
         for (sort keys %$val) {
             $res .= "," if $i++;
             my $k = /\W/ ? _double_quote($_) : $_;
             my $v = _dump($val->{$_}, "$subscript\{$k}");
             $res .= "$k=>$v";
         }
         $res .= "}";
     } elsif ($ref eq 'SCALAR') {
         $res = "\\"._dump($$val, $subscript);
     } elsif ($ref eq 'REF') {
         $res = "\\"._dump($$val, $subscript);
     } elsif ($ref eq 'CODE') {
         require Data::Dumper;
         local $Data::Dumper::Terse = 1;
         local $Data::Dumper::Indent = 0;
         local $Data::Dumper::Deparse = 1;
         $res = Data::Dumper::Dumper($val);
         if ($OPT_PERL_VERSION < 5.016) {
             # older perls' feature.pm doesn't yet support q{no feature ':all';}
             # so we replace it with q{no feature}.
             $res =~ s/no feature ':all';/no feature;/m;
         }
     } else {
         die "Sorry, I can't dump $val (ref=$ref) yet";
     }
 
     $res = "bless($res,"._double_quote($class).")" if defined($class);
     $res;
 }
 
 our $_is_dd;
 sub _dd_or_dmp {
     local %_seen_refaddrs;
     local %_subscripts;
     local @_fixups;
 
     my $res;
     if (@_ > 1) {
         $res = "(" . join(",", map {_dump($_, '')} @_) . ")";
     } else {
         $res = _dump($_[0], '');
     }
     if (@_fixups) {
         $res = "do{my\$a=$res;" . join("", @_fixups) . "\$a}";
     }
 
     if ($_is_dd) {
         say $res;
         return @_;
     } else {
         return $res;
     }
 }
 
 sub dd { local $_is_dd=1; _dd_or_dmp(@_) } # goto &sub doesn't work here
 sub dmp { goto &_dd_or_dmp }
 
 1;
 # ABSTRACT: Dump Perl data structures as Perl code
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Dmp - Dump Perl data structures as Perl code
 
 =head1 VERSION
 
 This document describes version 0.13 of Data::Dmp (from Perl distribution Data-Dmp), released on 2015-09-27.
 
 =head1 SYNOPSIS
 
  use Data::Dmp; # exports dd() and dmp()
  dd [1, 2, 3]; # prints "[1,2,3]"
  $a = dmp({a => 1}); # -> "{a=>1}"
 
 =head1 DESCRIPTION
 
 Data::Dmp is a Perl dumper like L<Data::Dumper>. It's compact (only about 150
 lines of code long), starts fast and does not use other module except
 L<Regexp::Stringify> when dumping regexes. It produces compact output (similar
 to L<Data::Dumper::Concise>). It roughly has the same speed as Data::Dumper
 (usually a bit faster for smaller structures), but does not offer the various
 formatting options. It supports dumping objects, regexes, circular structures,
 coderefs. Its code is based on L<Data::Dump>.
 
 =head1 FUNCTIONS
 
 =head2 dd($data, ...) => $data ...
 
 Exported by default. Like C<Data::Dump>'s C<dd> (a.k.a. C<dump>), print one or
 more data to STDOUT. Unlike C<Data::Dump>'s C<dd>, it I<always> prints and
 return I<the original data> (like L<XXX>), making it convenient to insert into
 expressions. This also removes ambiguity and saves one C<wantarray()> call.
 
 =head2 dmp($data, ...) => $str
 
 Exported by default. Return dump result as string. Unlike C<Data::Dump>'s C<dd>
 (a.k.a. C<dump>), it I<never> prints and only return the data.
 
 =head1 SETTINGS
 
 =head2 $Data::Dmp::OPT_PERL_VERSION => str (default: 5.010)
 
 Set target Perl version. If you set this to, say C<5.010>, then the dumped code
 will keep compatibility with Perl 5.10.0. This is used in the following ways:
 
 =over
 
 =item * passed to L<Regexp::Stringify>
 
 =item * when dumping code references
 
 For example, in perls earlier than 5.016, feature.pm does not understand:
 
  no feature ':all';
 
 so we replace it with:
 
  no feature;
 
 =back
 
 =head1 BENCHMARKS
 
  [1..10]:
                        Rate    Data::Dump Data::Dumper Data::Dmp
  Data::Dump     28529+-40/s            --       -68.6%    -77.6%
  Data::Dumper  90760+-110/s 218.13+-0.59%           --    -28.6%
  Data::Dmp    127150+-220/s 345.69+-0.98%  40.1+-0.29%        --
  
  [1..100]:
                        Rate  Data::Dump Data::Dumper Data::Dmp
  Data::Dump   3294.3+-6.9/s          --       -77.6%    -78.6%
  Data::Dumper   14717+-75/s 346.8+-2.5%           --     -4.6%
  Data::Dmp      15423+-25/s 368.2+-1.3%   4.8+-0.56%        --
  
  Some mixed structure:
                      Rate Data::Dump    Data::Dmp Data::Dumper
  Data::Dump    8119+-18/s         --       -73.7%       -81.5%
  Data::Dmp    30925+-46/s 280.91+-1%           --       -29.6%
  Data::Dumper 43921+-13/s  441+-1.2% 42.02+-0.21%           --
 
 =head1 FAQ
 
 =head2 When to use Data::Dmp? How does it compare to other dumper modules?
 
 Data::Dmp might be suitable for you if you want a relatively fast pure-Perl data
 structure dumper to eval-able Perl code. It produces compact, single-line Perl
 code but offers little/no formatting options. Data::Dmp and Data::Dump module
 family usually produce Perl code that is "more eval-able", e.g. it can recreate
 circular structure.
 
 L<Data::Dump> produces nicer output (some alignment, use of range operator to
 shorten lists, use of base64 for binary data, etc) but no built-in option to
 produce compact/single-line output. It's also relatively slow. I usually use its
 variant, L<Data::Dump::Color>, for console debugging.
 
 L<Data::Dumper> is core module, offers a lot of formatting options (like
 disabling hash key sorting, setting verboseness/indent level, and so on) but you
 usually have to configure it quite a bit before it does exactly like you want
 (that's why there are modules on CPAN that are just wrapping Data::Dumper with
 some configuration, like L<Data::Dumper::Concise> et al). It does not support
 dumping Perl code that can recreate circular structures.
 
 Of course, dumping to eval-able Perl code is slow (not to mention the cost of
 re-loading the code back to in-memory data, via eval-ing) compared to dumping to
 JSON, YAML, Sereal, or other format. So you need to decide first whether this is
 the appropriate route you want to take. (But note that there is also
 L<Data::Dumper::Limited> and L<Data::Undump> which uses a format similar to
 Data::Dumper but lets you load the serialized data without eval-ing them, thus
 achieving the speed comparable to JSON::XS).
 
 =head1 SEE ALSO
 
 L<Data::Dump> and other variations/derivate works in Data::Dump::*.
 
 L<Data::Dumper> and its variants.
 
 L<Data::Printer>.
 
 L<YAML>, L<JSON>, L<Storable>, L<Sereal>, and other serialization formats.
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Dmp>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Data-Dmp>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Dmp>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Dump.pm ###
 package Data::Dump;
 
 use strict;
 use vars qw(@EXPORT @EXPORT_OK $VERSION $DEBUG);
 use subs qq(dump);
 
 require Exporter;
 *import = \&Exporter::import;
 @EXPORT = qw(dd ddx);
 @EXPORT_OK = qw(dump pp dumpf quote);
 
 $VERSION = "1.23";
 $DEBUG = 0;
 
 use overload ();
 use vars qw(%seen %refcnt @dump @fixup %require $TRY_BASE64 @FILTERS $INDENT);
 
 $TRY_BASE64 = 50 unless defined $TRY_BASE64;
 $INDENT = "  " unless defined $INDENT;
 
 sub dump
 {
     local %seen;
     local %refcnt;
     local %require;
     local @fixup;
 
     require Data::Dump::FilterContext if @FILTERS;
 
     my $name = "a";
     my @dump;
 
     for my $v (@_) {
 	my $val = _dump($v, $name, [], tied($v));
 	push(@dump, [$name, $val]);
     } continue {
 	$name++;
     }
 
     my $out = "";
     if (%require) {
 	for (sort keys %require) {
 	    $out .= "require $_;\n";
 	}
     }
     if (%refcnt) {
 	# output all those with refcounts first
 	for (@dump) {
 	    my $name = $_->[0];
 	    if ($refcnt{$name}) {
 		$out .= "my \$$name = $_->[1];\n";
 		undef $_->[1];
 	    }
 	}
 	for (@fixup) {
 	    $out .= "$_;\n";
 	}
     }
 
     my $paren = (@dump != 1);
     $out .= "(" if $paren;
     $out .= format_list($paren, undef,
 			map {defined($_->[1]) ? $_->[1] : "\$".$_->[0]}
 			    @dump
 		       );
     $out .= ")" if $paren;
 
     if (%refcnt || %require) {
 	$out .= ";\n";
 	$out =~ s/^/$INDENT/gm;
 	$out = "do {\n$out}";
     }
 
     print STDERR "$out\n" unless defined wantarray;
     $out;
 }
 
 *pp = \&dump;
 
 sub dd {
     print dump(@_), "\n";
 }
 
 sub ddx {
     my(undef, $file, $line) = caller;
     $file =~ s,.*[\\/],,;
     my $out = "$file:$line: " . dump(@_) . "\n";
     $out =~ s/^/# /gm;
     print $out;
 }
 
 sub dumpf {
     require Data::Dump::Filtered;
     goto &Data::Dump::Filtered::dump_filtered;
 }
 
 sub _dump
 {
     my $ref  = ref $_[0];
     my $rval = $ref ? $_[0] : \$_[0];
     shift;
 
     my($name, $idx, $dont_remember, $pclass, $pidx) = @_;
 
     my($class, $type, $id);
     my $strval = overload::StrVal($rval);
     # Parse $strval without using regexps, in order not to clobber $1, $2,...
     if ((my $i = rindex($strval, "=")) >= 0) {
 	$class = substr($strval, 0, $i);
 	$strval = substr($strval, $i+1);
     }
     if ((my $i = index($strval, "(0x")) >= 0) {
 	$type = substr($strval, 0, $i);
 	$id = substr($strval, $i + 2, -1);
     }
     else {
 	die "Can't parse " . overload::StrVal($rval);
     }
     if ($] < 5.008 && $type eq "SCALAR") {
 	$type = "REF" if $ref eq "REF";
     }
     warn "\$$name(@$idx) $class $type $id ($ref)" if $DEBUG;
 
     my $out;
     my $comment;
     my $hide_keys;
     if (@FILTERS) {
 	my $pself = "";
 	$pself = fullname("self", [@$idx[$pidx..(@$idx - 1)]]) if $pclass;
 	my $ctx = Data::Dump::FilterContext->new($rval, $class, $type, $ref, $pclass, $pidx, $idx);
 	my @bless;
 	for my $filter (@FILTERS) {
 	    if (my $f = $filter->($ctx, $rval)) {
 		if (my $v = $f->{object}) {
 		    local @FILTERS;
 		    $out = _dump($v, $name, $idx, 1);
 		    $dont_remember++;
 		}
 		if (defined(my $c = $f->{bless})) {
 		    push(@bless, $c);
 		}
 		if (my $c = $f->{comment}) {
 		    $comment = $c;
 		}
 		if (defined(my $c = $f->{dump})) {
 		    $out = $c;
 		    $dont_remember++;
 		}
 		if (my $h = $f->{hide_keys}) {
 		    if (ref($h) eq "ARRAY") {
 			$hide_keys = sub {
 			    for my $k (@$h) {
 				return 1 if $k eq $_[0];
 			    }
 			    return 0;
 			};
 		    }
 		}
 	    }
 	}
 	push(@bless, "") if defined($out) && !@bless;
 	if (@bless) {
 	    $class = shift(@bless);
 	    warn "More than one filter callback tried to bless object" if @bless;
 	}
     }
 
     unless ($dont_remember) {
 	if (my $s = $seen{$id}) {
 	    my($sname, $sidx) = @$s;
 	    $refcnt{$sname}++;
 	    my $sref = fullname($sname, $sidx,
 				($ref && $type eq "SCALAR"));
 	    warn "SEEN: [\$$name(@$idx)] => [\$$sname(@$sidx)] ($ref,$sref)" if $DEBUG;
 	    return $sref unless $sname eq $name;
 	    $refcnt{$name}++;
 	    push(@fixup, fullname($name,$idx)." = $sref");
 	    return "do{my \$fix}" if @$idx && $idx->[-1] eq '$';
 	    return "'fix'";
 	}
 	$seen{$id} = [$name, $idx];
     }
 
     if ($class) {
 	$pclass = $class;
 	$pidx = @$idx;
     }
 
     if (defined $out) {
 	# keep it
     }
     elsif ($type eq "SCALAR" || $type eq "REF" || $type eq "REGEXP") {
 	if ($ref) {
 	    if ($class && $class eq "Regexp") {
 		my $v = "$rval";
 
 		my $mod = "";
 		if ($v =~ /^\(\?\^?([msix-]*):([\x00-\xFF]*)\)\z/) {
 		    $mod = $1;
 		    $v = $2;
 		    $mod =~ s/-.*//;
 		}
 
 		my $sep = '/';
 		my $sep_count = ($v =~ tr/\///);
 		if ($sep_count) {
 		    # see if we can find a better one
 		    for ('|', ',', ':', '#') {
 			my $c = eval "\$v =~ tr/\Q$_\E//";
 			#print "SEP $_ $c $sep_count\n";
 			if ($c < $sep_count) {
 			    $sep = $_;
 			    $sep_count = $c;
 			    last if $sep_count == 0;
 			}
 		    }
 		}
 		$v =~ s/\Q$sep\E/\\$sep/g;
 
 		$out = "qr$sep$v$sep$mod";
 		undef($class);
 	    }
 	    else {
 		delete $seen{$id} if $type eq "SCALAR";  # will be seen again shortly
 		my $val = _dump($$rval, $name, [@$idx, "\$"], 0, $pclass, $pidx);
 		$out = $class ? "do{\\(my \$o = $val)}" : "\\$val";
 	    }
 	} else {
 	    if (!defined $$rval) {
 		$out = "undef";
 	    }
 	    elsif (do {no warnings 'numeric'; $$rval + 0 eq $$rval}) {
 		$out = $$rval;
 	    }
 	    else {
 		$out = str($$rval);
 	    }
 	    if ($class && !@$idx) {
 		# Top is an object, not a reference to one as perl needs
 		$refcnt{$name}++;
 		my $obj = fullname($name, $idx);
 		my $cl  = quote($class);
 		push(@fixup, "bless \\$obj, $cl");
 	    }
 	}
     }
     elsif ($type eq "GLOB") {
 	if ($ref) {
 	    delete $seen{$id};
 	    my $val = _dump($$rval, $name, [@$idx, "*"], 0, $pclass, $pidx);
 	    $out = "\\$val";
 	    if ($out =~ /^\\\*Symbol::/) {
 		$require{Symbol}++;
 		$out = "Symbol::gensym()";
 	    }
 	} else {
 	    my $val = "$$rval";
 	    $out = "$$rval";
 
 	    for my $k (qw(SCALAR ARRAY HASH)) {
 		my $gval = *$$rval{$k};
 		next unless defined $gval;
 		next if $k eq "SCALAR" && ! defined $$gval;  # always there
 		my $f = scalar @fixup;
 		push(@fixup, "RESERVED");  # overwritten after _dump() below
 		$gval = _dump($gval, $name, [@$idx, "*{$k}"], 0, $pclass, $pidx);
 		$refcnt{$name}++;
 		my $gname = fullname($name, $idx);
 		$fixup[$f] = "$gname = $gval";  #XXX indent $gval
 	    }
 	}
     }
     elsif ($type eq "ARRAY") {
 	my @vals;
 	my $tied = tied_str(tied(@$rval));
 	my $i = 0;
 	for my $v (@$rval) {
 	    push(@vals, _dump($v, $name, [@$idx, "[$i]"], $tied, $pclass, $pidx));
 	    $i++;
 	}
 	$out = "[" . format_list(1, $tied, @vals) . "]";
     }
     elsif ($type eq "HASH") {
 	my(@keys, @vals);
 	my $tied = tied_str(tied(%$rval));
 
 	# statistics to determine variation in key lengths
 	my $kstat_max = 0;
 	my $kstat_sum = 0;
 	my $kstat_sum2 = 0;
 
 	my @orig_keys = keys %$rval;
 	if ($hide_keys) {
 	    @orig_keys = grep !$hide_keys->($_), @orig_keys;
 	}
 	my $text_keys = 0;
 	for (@orig_keys) {
 	    $text_keys++, last unless /^[-+]?(?:0|[1-9]\d*)(?:\.\d+)?\z/;
 	}
 
 	if ($text_keys) {
 	    @orig_keys = sort { lc($a) cmp lc($b) } @orig_keys;
 	}
 	else {
 	    @orig_keys = sort { $a <=> $b } @orig_keys;
 	}
 
 	my $quote;
 	for my $key (@orig_keys) {
 	    next if $key =~ /^-?[a-zA-Z_]\w*\z/;
 	    next if $key =~ /^-?[1-9]\d{0,8}\z/;
 	    $quote++;
 	    last;
 	}
 
 	for my $key (@orig_keys) {
 	    my $val = \$rval->{$key};  # capture value before we modify $key
 	    $key = quote($key) if $quote;
 	    $kstat_max = length($key) if length($key) > $kstat_max;
 	    $kstat_sum += length($key);
 	    $kstat_sum2 += length($key)*length($key);
 
 	    push(@keys, $key);
 	    push(@vals, _dump($$val, $name, [@$idx, "{$key}"], $tied, $pclass, $pidx));
 	}
 	my $nl = "";
 	my $klen_pad = 0;
 	my $tmp = "@keys @vals";
 	if (length($tmp) > 60 || $tmp =~ /\n/ || $tied) {
 	    $nl = "\n";
 
 	    # Determine what padding to add
 	    if ($kstat_max < 4) {
 		$klen_pad = $kstat_max;
 	    }
 	    elsif (@keys >= 2) {
 		my $n = @keys;
 		my $avg = $kstat_sum/$n;
 		my $stddev = sqrt(($kstat_sum2 - $n * $avg * $avg) / ($n - 1));
 
 		# I am not actually very happy with this heuristics
 		if ($stddev / $kstat_max < 0.25) {
 		    $klen_pad = $kstat_max;
 		}
 		if ($DEBUG) {
 		    push(@keys, "__S");
 		    push(@vals, sprintf("%.2f (%d/%.1f/%.1f)",
 					$stddev / $kstat_max,
 					$kstat_max, $avg, $stddev));
 		}
 	    }
 	}
 	$out = "{$nl";
 	$out .= "$INDENT# $tied$nl" if $tied;
 	while (@keys) {
 	    my $key = shift @keys;
 	    my $val = shift @vals;
 	    my $vpad = $INDENT . (" " x ($klen_pad ? $klen_pad + 4 : 0));
 	    $val =~ s/\n/\n$vpad/gm;
 	    my $kpad = $nl ? $INDENT : " ";
 	    $key .= " " x ($klen_pad - length($key)) if $nl && $klen_pad > length($key);
 	    $out .= "$kpad$key => $val,$nl";
 	}
 	$out =~ s/,$/ / unless $nl;
 	$out .= "}";
     }
     elsif ($type eq "CODE") {
 	$out = 'sub { ... }';
     }
     elsif ($type eq "VSTRING") {
         $out = sprintf +($ref ? '\v%vd' : 'v%vd'), $$rval;
     }
     else {
 	warn "Can't handle $type data";
 	$out = "'#$type#'";
     }
 
     if ($class && $ref) {
 	$out = "bless($out, " . quote($class) . ")";
     }
     if ($comment) {
 	$comment =~ s/^/# /gm;
 	$comment .= "\n" unless $comment =~ /\n\z/;
 	$comment =~ s/^#[ \t]+\n/\n/;
 	$out = "$comment$out";
     }
     return $out;
 }
 
 sub tied_str {
     my $tied = shift;
     if ($tied) {
 	if (my $tied_ref = ref($tied)) {
 	    $tied = "tied $tied_ref";
 	}
 	else {
 	    $tied = "tied";
 	}
     }
     return $tied;
 }
 
 sub fullname
 {
     my($name, $idx, $ref) = @_;
     substr($name, 0, 0) = "\$";
 
     my @i = @$idx;  # need copy in order to not modify @$idx
     if ($ref && @i && $i[0] eq "\$") {
 	shift(@i);  # remove one deref
 	$ref = 0;
     }
     while (@i && $i[0] eq "\$") {
 	shift @i;
 	$name = "\$$name";
     }
 
     my $last_was_index;
     for my $i (@i) {
 	if ($i eq "*" || $i eq "\$") {
 	    $last_was_index = 0;
 	    $name = "$i\{$name}";
 	} elsif ($i =~ s/^\*//) {
 	    $name .= $i;
 	    $last_was_index++;
 	} else {
 	    $name .= "->" unless $last_was_index++;
 	    $name .= $i;
 	}
     }
     $name = "\\$name" if $ref;
     $name;
 }
 
 sub format_list
 {
     my $paren = shift;
     my $comment = shift;
     my $indent_lim = $paren ? 0 : 1;
     if (@_ > 3) {
 	# can we use range operator to shorten the list?
 	my $i = 0;
 	while ($i < @_) {
 	    my $j = $i + 1;
 	    my $v = $_[$i];
 	    while ($j < @_) {
 		# XXX allow string increment too?
 		if ($v eq "0" || $v =~ /^-?[1-9]\d{0,9}\z/) {
 		    $v++;
 		}
 		elsif ($v =~ /^"([A-Za-z]{1,3}\d*)"\z/) {
 		    $v = $1;
 		    $v++;
 		    $v = qq("$v");
 		}
 		else {
 		    last;
 		}
 		last if $_[$j] ne $v;
 		$j++;
 	    }
 	    if ($j - $i > 3) {
 		splice(@_, $i, $j - $i, "$_[$i] .. $_[$j-1]");
 	    }
 	    $i++;
 	}
     }
     my $tmp = "@_";
     if ($comment || (@_ > $indent_lim && (length($tmp) > 60 || $tmp =~ /\n/))) {
 	my @elem = @_;
 	for (@elem) { s/^/$INDENT/gm; }
 	return "\n" . ($comment ? "$INDENT# $comment\n" : "") .
                join(",\n", @elem, "");
     } else {
 	return join(", ", @_);
     }
 }
 
 sub str {
   if (length($_[0]) > 20) {
       for ($_[0]) {
       # Check for repeated string
       if (/^(.)\1\1\1/s) {
           # seems to be a repeating sequence, let's check if it really is
           # without backtracking
           unless (/[^\Q$1\E]/) {
               my $base = quote($1);
               my $repeat = length;
               return "($base x $repeat)"
           }
       }
       # Length protection because the RE engine will blow the stack [RT#33520]
       if (length($_) < 16 * 1024 && /^(.{2,5}?)\1*\z/s) {
 	  my $base   = quote($1);
 	  my $repeat = length($_)/length($1);
 	  return "($base x $repeat)";
       }
       }
   }
 
   local $_ = &quote;
 
   if (length($_) > 40  && !/\\x\{/ && length($_) > (length($_[0]) * 2)) {
       # too much binary data, better to represent as a hex/base64 string
 
       # Base64 is more compact than hex when string is longer than
       # 17 bytes (not counting any require statement needed).
       # But on the other hand, hex is much more readable.
       if ($TRY_BASE64 && length($_[0]) > $TRY_BASE64 &&
 	  (defined &utf8::is_utf8 && !utf8::is_utf8($_[0])) &&
 	  eval { require MIME::Base64 })
       {
 	  $require{"MIME::Base64"}++;
 	  return "MIME::Base64::decode(\"" .
 	             MIME::Base64::encode($_[0],"") .
 		 "\")";
       }
       return "pack(\"H*\",\"" . unpack("H*", $_[0]) . "\")";
   }
 
   return $_;
 }
 
 my %esc = (
     "\a" => "\\a",
     "\b" => "\\b",
     "\t" => "\\t",
     "\n" => "\\n",
     "\f" => "\\f",
     "\r" => "\\r",
     "\e" => "\\e",
 );
 
 # put a string value in double quotes
 sub quote {
   local($_) = $_[0];
   # If there are many '"' we might want to use qq() instead
   s/([\\\"\@\$])/\\$1/g;
   return qq("$_") unless /[^\040-\176]/;  # fast exit
 
   s/([\a\b\t\n\f\r\e])/$esc{$1}/g;
 
   # no need for 3 digits in escape for these
   s/([\0-\037])(?!\d)/sprintf('\\%o',ord($1))/eg;
 
   s/([\0-\037\177-\377])/sprintf('\\x%02X',ord($1))/eg;
   s/([^\040-\176])/sprintf('\\x{%X}',ord($1))/eg;
 
   return qq("$_");
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Data::Dump - Pretty printing of data structures
 
 =head1 SYNOPSIS
 
  use Data::Dump qw(dump);
 
  $str = dump(@list);
  @copy_of_list = eval $str;
 
  # or use it for easy debug printout
  use Data::Dump; dd localtime;
 
 =head1 DESCRIPTION
 
 This module provide a few functions that traverse their
 argument and produces a string as its result.  The string contains
 Perl code that, when C<eval>ed, produces a deep copy of the original
 arguments.
 
 The main feature of the module is that it strives to produce output
 that is easy to read.  Example:
 
     @a = (1, [2, 3], {4 => 5});
     dump(@a);
 
 Produces:
 
     "(1, [2, 3], { 4 => 5 })"
 
 If you dump just a little data, it is output on a single line. If
 you dump data that is more complex or there is a lot of it, line breaks
 are automatically added to keep it easy to read.
 
 The following functions are provided (only the dd* functions are exported by default):
 
 =over
 
 =item dump( ... )
 
 =item pp( ... )
 
 Returns a string containing a Perl expression.  If you pass this
 string to Perl's built-in eval() function it should return a copy of
 the arguments you passed to dump().
 
 If you call the function with multiple arguments then the output will
 be wrapped in parenthesis "( ..., ... )".  If you call the function with a
 single argument the output will not have the wrapping.  If you call the function with
 a single scalar (non-reference) argument it will just return the
 scalar quoted if needed, but never break it into multiple lines.  If you
 pass multiple arguments or references to arrays of hashes then the
 return value might contain line breaks to format it for easier
 reading.  The returned string will never be "\n" terminated, even if
 contains multiple lines.  This allows code like this to place the
 semicolon in the expected place:
 
    print '$obj = ', dump($obj), ";\n";
 
 If dump() is called in void context, then the dump is printed on
 STDERR and then "\n" terminated.  You might find this useful for quick
 debug printouts, but the dd*() functions might be better alternatives
 for this.
 
 There is no difference between dump() and pp(), except that dump()
 shares its name with a not-so-useful perl builtin.  Because of this
 some might want to avoid using that name.
 
 =item quote( $string )
 
 Returns a quoted version of the provided string.
 
 It differs from C<dump($string)> in that it will quote even numbers and
 not try to come up with clever expressions that might shorten the
 output.  If a non-scalar argument is provided then it's just stringified
 instead of traversed.
 
 =item dd( ... )
 
 =item ddx( ... )
 
 These functions will call dump() on their argument and print the
 result to STDOUT (actually, it's the currently selected output handle, but
 STDOUT is the default for that).
 
 The difference between them is only that ddx() will prefix the lines
 it prints with "# " and mark the first line with the file and line
 number where it was called.  This is meant to be useful for debug
 printouts of state within programs.
 
 =item dumpf( ..., \&filter )
 
 Short hand for calling the dump_filtered() function of L<Data::Dump::Filtered>.
 This works like dump(), but the last argument should be a filter callback
 function.  As objects are visited the filter callback is invoked and it
 can modify how the objects are dumped.
 
 =back
 
 =head1 CONFIGURATION
 
 There are a few global variables that can be set to modify the output
 generated by the dump functions.  It's wise to localize the setting of
 these.
 
 =over
 
 =item $Data::Dump::INDENT
 
 This holds the string that's used for indenting multiline data structures.
 It's default value is "  " (two spaces).  Set it to "" to suppress indentation.
 Setting it to "| " makes for nice visuals even if the dump output then fails to
 be valid Perl.
 
 =item $Data::Dump::TRY_BASE64
 
 How long must a binary string be before we try to use the base64 encoding
 for the dump output.  The default is 50.  Set it to 0 to disable base64 dumps.
 
 =back
 
 
 =head1 LIMITATIONS
 
 Code references will be dumped as C<< sub { ... } >>. Thus, C<eval>ing them will
 not reproduce the original routine.  The C<...>-operator used will also require
 perl-5.12 or better to be evaled.
 
 If you forget to explicitly import the C<dump> function, your code will
 core dump. That's because you just called the builtin C<dump> function
 by accident, which intentionally dumps core.  Because of this you can
 also import the same function as C<pp>, mnemonic for "pretty-print".
 
 =head1 HISTORY
 
 The C<Data::Dump> module grew out of frustration with Sarathy's
 in-most-cases-excellent C<Data::Dumper>.  Basic ideas and some code
 are shared with Sarathy's module.
 
 The C<Data::Dump> module provides a much simpler interface than
 C<Data::Dumper>.  No OO interface is available and there are fewer
 configuration options to worry about.  The other benefit is
 that the dump produced does not try to set any variables.  It only
 returns what is needed to produce a copy of the arguments.  This means
 that C<dump("foo")> simply returns C<'"foo"'>, and C<dump(1..3)> simply
 returns C<'(1, 2, 3)'>.
 
 =head1 SEE ALSO
 
 L<Data::Dump::Filtered>, L<Data::Dump::Trace>, L<Data::Dumper>, L<JSON>,
 L<Storable>
 
 =head1 AUTHORS
 
 The C<Data::Dump> module is written by Gisle Aas <gisle@aas.no>, based
 on C<Data::Dumper> by Gurusamy Sarathy <gsar@umich.edu>.
 
  Copyright 1998-2010 Gisle Aas.
  Copyright 1996-1998 Gurusamy Sarathy.
 
 This library is free software; you can redistribute it and/or
 modify it under the same terms as Perl itself.
 
 =cut
### Data/Dump/FilterContext.pm ###
 package Data::Dump::FilterContext;
 
 sub new {
     my($class, $obj, $oclass, $type, $ref, $pclass, $pidx, $idx) = @_;
     return bless {
 	object => $obj,
 	class => $ref && $oclass,
 	reftype => $type,
 	is_ref => $ref,
 	pclass => $pclass,
 	pidx => $pidx,
 	idx => $idx,
     }, $class;
 }
 
 sub object_ref {
     my $self = shift;
     return $self->{object};
 }
 
 sub class {
     my $self = shift;
     return $self->{class} || "";
 }
 
 *is_blessed = \&class;
 
 sub reftype {
     my $self = shift;
     return $self->{reftype};
 }
 
 sub is_scalar {
     my $self = shift;
     return $self->{reftype} eq "SCALAR";
 }
 
 sub is_array {
     my $self = shift;
     return $self->{reftype} eq "ARRAY";
 }
 
 sub is_hash {
     my $self = shift;
     return $self->{reftype} eq "HASH";
 }
 
 sub is_code {
     my $self = shift;
     return $self->{reftype} eq "CODE";
 }
 
 sub is_ref {
     my $self = shift;
     return $self->{is_ref};
 }
 
 sub container_class {
     my $self = shift;
     return $self->{pclass} || "";
 }
 
 sub container_self {
     my $self = shift;
     return "" unless $self->{pclass};
     my $idx = $self->{idx};
     my $pidx = $self->{pidx};
     return Data::Dump::fullname("self", [@$idx[$pidx..(@$idx - 1)]]);
 }
 
 sub expr {
     my $self = shift;
     my $top = shift || "var";
     $top =~ s/^\$//; # it's always added by fullname()
     my $idx = $self->{idx};
     return Data::Dump::fullname($top, $idx);
 }
 
 sub object_isa {
     my($self, $class) = @_;
     return $self->{class} && $self->{class}->isa($class);
 }
 
 sub container_isa {
     my($self, $class) = @_;
     return $self->{pclass} && $self->{pclass}->isa($class);
 }
 
 sub depth {
     my $self = shift;
     return scalar @{$self->{idx}};
 }
 
 1;
### Data/Dump/Filtered.pm ###
 package Data::Dump::Filtered;
 
 use Data::Dump ();
 use Carp ();
 
 use base 'Exporter';
 our @EXPORT_OK = qw(add_dump_filter remove_dump_filter dump_filtered);
 
 sub add_dump_filter {
     my $filter = shift;
     unless (ref($filter) eq "CODE") {
 	Carp::croak("add_dump_filter argument must be a code reference");
     }
     push(@Data::Dump::FILTERS, $filter);
     return $filter;
 }
 
 sub remove_dump_filter {
     my $filter = shift;
     @Data::Dump::FILTERS = grep $_ ne $filter, @Data::Dump::FILTERS;
 }
 
 sub dump_filtered {
     my $filter = pop;
     if (defined($filter) && ref($filter) ne "CODE") {
 	Carp::croak("Last argument to dump_filtered must be undef or a code reference");
     }
     local @Data::Dump::FILTERS = ($filter ? $filter : ());
     return &Data::Dump::dump;
 }
 
 1;
 
 =head1 NAME
 
 Data::Dump::Filtered - Pretty printing with filtering
 
 =head1 DESCRIPTION
 
 The following functions are provided:
 
 =over
 
 =item add_dump_filter( \&filter )
 
 This registers a filter function to be used by the regular Data::Dump::dump()
 function.  By default no filters are active.
 
 Since registering filters has a global effect is might be more appropriate
 to use the dump_filtered() function instead.
 
 =item remove_dump_filter( \&filter )
 
 Unregister the given callback function as filter callback.
 This undoes the effect of L<add_filter>.
 
 =item dump_filtered(..., \&filter )
 
 Works like Data::Dump::dump(), but the last argument should
 be a filter callback function.  As objects are visited the
 filter callback is invoked at it might influence how objects are dumped.
 
 Any filters registered with L<add_filter()> are ignored when
 this interface is invoked.  Actually, passing C<undef> as \&filter
 is allowed and C<< dump_filtered(..., undef) >> is the official way to
 force unfiltered dumps.
 
 =back
 
 =head2 Filter callback
 
 A filter callback is a function that will be invoked with 2 arguments;
 a context object and reference to the object currently visited.  The return
 value should either be a hash reference or C<undef>.
 
     sub filter_callback {
         my($ctx, $object_ref) = @_;
 	...
 	return { ... }
     }
 
 If the filter callback returns C<undef> (or nothing) then normal
 processing and formatting of the visited object happens.
 If the filter callback returns a hash it might replace
 or annotate the representation of the current object.
 
 =head2 Filter context
 
 The context object provide methods that can be used to determine what kind of
 object is currently visited and where it's located.  The context object has the
 following interface:
 
 =over
 
 =item $ctx->object_ref
 
 Alternative way to obtain a reference to the current object
 
 =item $ctx->class
 
 If the object is blessed this return the class.  Returns ""
 for objects not blessed.
 
 =item $ctx->reftype
 
 Returns what kind of object this is.  It's a string like "SCALAR",
 "ARRAY", "HASH", "CODE",...
 
 =item $ctx->is_ref
 
 Returns true if a reference was provided.
 
 =item $ctx->is_blessed
 
 Returns true if the object is blessed.  Actually, this is just an alias
 for C<< $ctx->class >>.
 
 =item $ctx->is_array
 
 Returns true if the object is an array
 
 =item $ctx->is_hash
 
 Returns true if the object is a hash
 
 =item $ctx->is_scalar
 
 Returns true if the object is a scalar (a string or a number)
 
 =item $ctx->is_code
 
 Returns true if the object is a function (aka subroutine)
 
 =item $ctx->container_class
 
 Returns the class of the innermost container that contains this object.
 Returns "" if there is no blessed container.
 
 =item $ctx->container_self
 
 Returns an textual expression relative to the container object that names this
 object.  The variable C<$self> in this expression is the container itself.
 
 =item $ctx->object_isa( $class )
 
 Returns TRUE if the current object is of the given class or is of a subclass.
 
 =item $ctx->container_isa( $class )
 
 Returns TRUE if the innermost container is of the given class or is of a
 subclass.
 
 =item $ctx->depth
 
 Returns how many levels deep have we recursed into the structure (from the
 original dump_filtered() arguments).
 
 =item $ctx->expr
 
 =item $ctx->expr( $top_level_name )
 
 Returns an textual expression that denotes the current object.  In the
 expression C<$var> is used as the name of the top level object dumped.  This
 can be overridden by providing a different name as argument.
 
 =back
 
 =head2 Filter return hash
 
 The following elements has significance in the returned hash:
 
 =over
 
 =item dump => $string
 
 incorporate the given string as the representation for the
 current value
 
 =item object => $value
 
 dump the given value instead of the one visited and passed in as $object.
 Basically the same as specifying C<< dump => Data::Dump::dump($value) >>.
 
 =item comment => $comment
 
 prefix the value with the given comment string
 
 =item bless => $class
 
 make it look as if the current object is of the given $class
 instead of the class it really has (if any).  The internals of the object
 is dumped in the regular way.  The $class can be the empty string
 to make Data::Dump pretend the object wasn't blessed at all.
 
 =item hide_keys => ['key1', 'key2',...]
 
 =item hide_keys => \&code
 
 If the $object is a hash dump is as normal but pretend that the
 listed keys did not exist.  If the argument is a function then
 the function is called to determine if the given key should be
 hidden.
 
 =back
 
 =head1 SEE ALSO
 
 L<Data::Dump>
### Data/Dump/OneLine.pm ###
 package Data::Dump::OneLine;
 
 our $DATE = '2015-03-25'; # DATE
 our $VERSION = '0.07'; # VERSION
 
 use 5.010001;
 use strict;
 use warnings;
 
 use Data::Dmp;
 
 our @ISA = qw(Data::Dmp);
 our @EXPORT = (@Data::Dmp::EXPORT, 'dump1', 'dump_one_line');
 
 *dump1 = \&Data::Dmp::dmp;
 *dump_one_line = \&Data::Dmp::dmp;
 
 1;
 # ABSTRACT: Dump data structures as single-line strings
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Dump::OneLine - Dump data structures as single-line strings
 
 =head1 VERSION
 
 This document describes version 0.07 of Data::Dump::OneLine (from Perl distribution Data-Dump-OneLine), released on 2015-03-25.
 
 =head1 SYNOPSIS
 
  use Data::Dump::OneLine; # exports dd and dmp
  $str = dd(@list);
 
 =head1 DESCRIPTION
 
 It now uses L<Data::Dmp>. You should use Data::Dmp directly.
 
 =for Pod::Coverage ^(.+)$
 
 =head1 SEE ALSO
 
 L<JSON> should also encode to a single-line string, but some data structures
 (cyclical, contains globs or other special Perl data) cannot be encoded out of
 the box to JSON.
 
 L<Data::Dumper::OneLine> strives to do the same for L<Data::Dumper>, but last
 time I tried it (at v0.05) it's still buggy.
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Dump-OneLine>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Data-Dump-OneLine>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Dump-OneLine>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Dump/Partial.pm ###
 package Data::Dump::Partial;
 
 use 5.010001;
 use strict;
 use warnings;
 use experimental 'smartmatch';
 use Data::Dump::Filtered;
 
 require Exporter;
 our @ISA = qw(Exporter);
 our @EXPORT_OK = qw(dump_partial dumpp);
 
 our $VERSION = '0.05'; # VERSION
 
 sub _dmp { Data::Dump::Filtered::dump_filtered(@_, undef) }
 
 sub dump_partial {
     my @data = @_;
     die 'Usage: dump_partial(@data, \%opts)'
         if @data > 1 && ref($data[-1]) ne 'HASH';
     my $opts = (@data > 1) ? {%{pop(@data)}} : {};
 
     $opts->{max_keys}      //=  5;
     $opts->{max_elems}     //=  5;
     $opts->{max_len}       //= 32;
     $opts->{max_total_len} //= 80;
 
     $opts->{max_keys} = @{$opts->{precious_keys}} if $opts->{precious_keys} &&
         @{ $opts->{precious_keys} } > $opts->{max_keys};
 
     my $out;
 
     if ($opts->{_inner}) {
         #print "DEBUG: inner dump, data="._dmp(@data)."\n";
         $out = Data::Dump::dump(@data);
     } else {
         #print "DEBUG: outer dump, data="._dmp(@data)."\n";
         my $filter = sub {
             my ($ctx, $oref) = @_;
 
             # to avoid deep recursion (dump_partial keeps modifying the hash due
             # to pair_filter or mask_keys_regex)
             my $skip_modify_outermost_hash;
             if ($opts->{_skip_modify_outermost_hash}) {
                 #print "DEBUG: Will skip modify outermost hash\n";
                 $skip_modify_outermost_hash++;
                 $opts->{_skip_modify_outermost_hash}--;
             }
 
             if ($opts->{max_len} && $ctx->is_scalar && defined($$oref) &&
                     length($$oref) > $opts->{max_len}) {
 
                 #print "DEBUG: truncating scalar\n";
                 return { object => substr($$oref, 0, $opts->{max_len}-3)."..." };
 
             } elsif ($opts->{max_elems} && $ctx->is_array &&
                          @$oref > $opts->{max_elems}) {
 
                 #print "DEBUG: truncating array\n";
                 my @ary = @{$oref}[0..($opts->{max_elems}-1)];
                 local $opts->{_inner} = 1;
                 local $opts->{max_total_len} = 0;
                 my $out = dump_partial(\@ary, $opts);
                 $out =~ s/(?:, )?]$/, ...]/;
                 return { dump => $out };
 
             } elsif ($ctx->is_hash) {
 
                 my %hash;
                 my $modified;
 
                 if ($opts->{pair_filter} && !$skip_modify_outermost_hash) {
                     for (sort keys %$oref) {
                         my @res = $opts->{pair_filter}->($_, $oref->{$_});
                         $modified = "pair_filter" unless @res == 2 &&
                             $res[0] eq $_ && "$res[1]" eq "$oref->{$_}";
                         while (my ($k, $v) = splice @res, 0, 2) {
                             $hash{$k} = $v;
                         }
                     }
                 } else {
                     %hash = %$oref;
                 }
 
                 if ($opts->{mask_keys_regex} && !$skip_modify_outermost_hash) {
                     for (sort keys %hash) {
                         if (/$opts->{mask_keys_regex}/) {
                             $modified = "mask_keys_regex";
                             $hash{$_} = '***';
                         }
                     }
                 }
 
                 my $truncated;
                 if ($opts->{max_keys} && keys(%$oref) > $opts->{max_keys}) {
                     my $mk = $opts->{max_keys};
                     {
                         if ($opts->{hide_keys}) {
                             for (sort keys %hash) {
                                 delete $hash{$_} if $_ ~~ @{$opts->{hide_keys}};
                             }
                         }
                         last if keys(%hash) <= $mk;
                         if ($opts->{worthless_keys}) {
                             for (sort keys %hash) {
                                 last if keys(%hash) <= $mk;
                                 delete $hash{$_} if $_ ~~ @{$opts->{worthless_keys}};
                             }
                         }
                         last if keys(%hash) <= $mk;
                         for (reverse sort keys %hash) {
                             delete $hash{$_} if !$opts->{precious_keys} ||
                                 !($_ ~~ @{$opts->{precious_keys}});
                             last if keys(%hash) <= $mk;
                         }
                     }
                     $modified = "truncate";
                     $truncated++;
                 }
 
                 if ($modified) {
                     #print "DEBUG: modified hash ($modified)\n";
                     local $opts->{_inner} = 1;
                     local $opts->{_skip_modify_outermost_hash} = 1;
                     local $opts->{max_total_len} = 0;
                     my $out = dump_partial(\%hash, $opts);
                     $out =~ s/(?:, )? }$/, ... }/ if $truncated;
                     return { dump => $out };
                 }
             }
 
             if ($opts->{dd_filter}) {
                 return $opts->{dd_filter}->($ctx, $oref);
             } else {
                 return;
             }
         };
         $out = Data::Dump::Filtered::dump_filtered(@data, $filter);
     }
 
     for ($out) {
         s/^\s*#.*//mg; # comments
         s/^\s+//mg; # indents
         s/\n+/ /g; # newlines
     }
 
     if ($opts->{max_total_len} && length($out) > $opts->{max_total_len}) {
         $out = substr($out, 0, $opts->{max_total_len}-3) . "...";
     }
 
     print STDERR "$out\n" unless defined wantarray;
     $out;
 }
 
 sub dumpp { dump_partial(@_) }
 
 1;
 # ABSTRACT: Dump data structure compactly and potentially partially
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Dump::Partial - Dump data structure compactly and potentially partially
 
 =head1 VERSION
 
 version 0.05
 
 =head1 SYNOPSIS
 
  use Data::Dump::Partial qw(dump_partial dumpp);
 
  dump_partial([1, "some long string", 3, 4, 5, 6, 7]);
  # prints something like: [1, "some long st...", 3, 4, 5, ...]
 
  # specify options
  dumpp($data, $more_data, {max_total_len => 50, max_keys => 4});
 
  # mask passwords specified in hash key values
  dumpp({auth_info=>{user=>"steven", password=>"secret"}, foo=>1, bar=>2},
        {mask_keys_regex=>qr/\Apass\z|passw(or)?d/i});
  # prints something like:
  # {auth_info=>{user=>"steven", password=>"***"}, foo=>1, bar=>2}
 
 =head1 DESCRIPTION
 
 =head1 FUNCTIONS
 
 =head2 dump_partial(..., $opts)
 
 Dump one more data structures compactly and potentially partially. Uses
 L<Data::Dump::Filtered> as the backend.
 
 By compactly, it means all indents and comments and newlines are removed, so the
 output all fits in one line.
 
 By partially, it means only up to a certain amount of data are dumped/shown:
 string longer than a certain length will be truncated (with "..." appended in
 the end), array more than a certain number of elements will be truncated, and
 hash containing more than a certain number of pairs will be truncated. The total
 length of dump is also limited. When truncating hash you can specify which keys
 to discard/preserve first. You can also mask certain hash key values (for
 example, to avoid exposing passwords in dumps).
 
 $opts is a hashref, optional only when there is one data to dump, with the
 following known keys:
 
 =over 4
 
 =item * max_total_len => NUM
 
 Total length of output before it gets truncated with an ellipsis. Default is 80.
 
 =item * max_len => NUM
 
 Maximum length of a scalar (string, etc) to show before the rest get truncated
 with an ellipsis. Default is 32.
 
 =item * max_keys => NUM
 
 Number of key pairs of a hash to show before the rest get truncated with an
 ellipsis. Default is 5.
 
 =item * max_elems => NUM
 
 Number of elements of an array to show before the rest get truncated with an
 ellipsis. Default is 5.
 
 =item * precious_keys => [KEY, ...]
 
 Never truncate these keys (even if it results in max_keys limit being exceeded).
 
 =item * worthless_keys => [KEY, ...]
 
 When needing to truncate hash keys, search for these first.
 
 =item * hide_keys => [KEY, ...]
 
 Always truncate these hash keys, no matter what. This is actually also
 implemented by Data::Dump::Filtered.
 
 =item * mask_keys_regex => REGEX
 
 When encountering keys that match certain regex, mask the values with '***'.
 This can be useful if you want to mask passwords, e.g.: mask_keys_regex =>
 qr/\Apass\z|passw(or)?d/i. If you want more general masking, you can use
 pair_filter.
 
 =item * pair_filter => CODE
 
 CODE will be called for each hash key/value pair encountered in the data. It
 will be given ($key, $value) as argument and is expected to return a list of
 zero or more of keys and values. The example below implements something similar
 to what mask_keys_regex accomplishes:
 
  # mask each password character with '*'
  hash_pair_filter => sub {
      my ($k, $v) = @_;
      if ($k =~ /\Apass\z|passw(or)?d/i) {
          $v =~ s/./*/g;
      }
      ($k, $v);
  }
 
 =item * dd_filter => \&sub
 
 If you have other Data::Dump::Filtered filter you want to execute, you can pass
 it here.
 
 =back
 
 =head2 dumpp
 
 An alias for dump_filtered().
 
 =head1 FAQ
 
 =head2 What is the point/purpose of this module?
 
 Sometimes you want to dump a data structure, but need it to be short, more than
 need it to be complete, for example when logging to log files or database.
 
 =head2 Is the dump result eval()-able? Will the dump result eval() to produce the original data?
 
 Sometimes it is/will, sometimes it does/will not if it gets truncated.
 
 =head1 SEE ALSO
 
 L<Data::Dump::Filtered>
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Dump-Partial>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Dump-Partial>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Dump-Partial>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 Steven Haryanto <stevenharyanto@gmail.com>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2014 by Steven Haryanto.
 
 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/Dump/Trace.pm ###
 package Data::Dump::Trace;
 
 $VERSION = "0.02";
 
 # Todo:
 #   - prototypes
 #     in/out parameters key/value style
 #   - exception
 #   - wrap class
 #   - configurable colors
 #   - show call depth using indentation
 #   - show nested calls sensibly
 #   - time calls
 
 use strict;
 
 use base 'Exporter';
 our @EXPORT_OK = qw(call mcall wrap autowrap trace);
 
 use Carp qw(croak);
 use overload ();
 
 my %obj_name;
 my %autowrap_class;
 my %name_count;
 
 sub autowrap {
     while (@_) {
         my $class = shift;
         my $info = shift;
         $info = { prefix => $info } unless ref($info);
         for ($info->{prefix}) {
             unless ($_) {
                 $_ = lc($class);
                 s/.*:://;
             }
             $_ = '$' . $_ unless /^\$/;
         }
         $autowrap_class{$class} = $info;
     }
 }
 
 sub wrap {
     my %arg = @_;
     my $name = $arg{name} || "func";
     my $func = $arg{func};
     my $proto = $arg{proto};
 
     return sub {
         call($name, $func, $proto, @_);
     } if $func;
 
     if (my $obj = $arg{obj}) {
         $name = '$' . $name unless $name =~ /^\$/;
         $obj_name{overload::StrVal($obj)} = $name;
         return bless {
             name => $name,
             obj => $obj,
             proto => $arg{proto},
         }, "Data::Dump::Trace::Wrapper";
     }
 
     croak("Either the 'func' or 'obj' option must be given");
 }
 
 sub trace {
     my($symbol, $prototype) = @_;
     no strict 'refs';
     no warnings 'redefine';
     *{$symbol} = wrap(name => $symbol, func => \&{$symbol}, proto => $prototype);
 }
 
 sub call {
     my $name = shift;
     my $func = shift;
     my $proto = shift;
     my $fmt = Data::Dump::Trace::Call->new($name, $proto, \@_);
     if (!defined wantarray) {
         $func->(@_);
         return $fmt->return_void(\@_);
     }
     elsif (wantarray) {
         return $fmt->return_list(\@_, $func->(@_));
     }
     else {
         return $fmt->return_scalar(\@_, scalar $func->(@_));
     }
 }
 
 sub mcall {
     my $o = shift;
     my $method = shift;
     my $proto = shift;
     return if $method eq "DESTROY" && !$o->can("DESTROY");
     my $oname = ref($o) ? $obj_name{overload::StrVal($o)} || "\$o" : $o;
     my $fmt = Data::Dump::Trace::Call->new("$oname->$method", $proto, \@_);
     if (!defined wantarray) {
         $o->$method(@_);
         return $fmt->return_void(\@_);
     }
     elsif (wantarray) {
         return $fmt->return_list(\@_, $o->$method(@_));
     }
     else {
         return $fmt->return_scalar(\@_, scalar $o->$method(@_));
     }
 }
 
 package Data::Dump::Trace::Wrapper;
 
 sub AUTOLOAD {
     my $self = shift;
     our $AUTOLOAD;
     my $method = substr($AUTOLOAD, rindex($AUTOLOAD, '::')+2);
     Data::Dump::Trace::mcall($self->{obj}, $method, $self->{proto}{$method}, @_);
 }
 
 package Data::Dump::Trace::Call;
 
 use Term::ANSIColor ();
 use Data::Dump ();
 
 *_dump = \&Data::Dump::dump;
 
 our %COLOR = (
     name => "yellow",
     output => "cyan",
     error => "red",
     debug => "red",
 );
 
 %COLOR = () unless -t STDOUT;
 
 sub _dumpav {
     return "(" . _dump(@_) . ")" if @_ == 1;
     return _dump(@_);
 }
 
 sub _dumpkv {
     return _dumpav(@_) if @_ % 2;
     my %h = @_;
     my $str = _dump(\%h);
     $str =~ s/^\{/(/ && $str =~ s/\}\z/)/;
     return $str;
 }
 
 sub new {
     my($class, $name, $proto, $input_args) = @_;
     my $self = bless {
         name => $name,
         proto => $proto,
     }, $class;
     my $proto_arg = $self->proto_arg;
     if ($proto_arg =~ /o/) {
         for (@$input_args) {
             push(@{$self->{input_av}}, _dump($_));
         }
     }
     else {
         $self->{input} = $proto_arg eq "%" ? _dumpkv(@$input_args) : _dumpav(@$input_args);
     }
     return $self;
 }
 
 sub proto_arg {
     my $self = shift;
     my($arg, $ret) = split(/\s*=\s*/, $self->{proto} || "");
     $arg ||= '@';
     return $arg;
 }
 
 sub proto_ret {
     my $self = shift;
     my($arg, $ret) = split(/\s*=\s*/, $self->{proto} || "");
     $ret ||= '@';
     return $ret;
 }
 
 sub color {
     my($self, $category, $text) = @_;
     return $text unless $COLOR{$category};
     return Term::ANSIColor::colored($text, $COLOR{$category});
 }
 
 sub print_call {
     my $self = shift;
     my $outarg = shift;
     print $self->color("name", "$self->{name}");
     if (my $input = $self->{input}) {
         $input = "" if $input eq "()" && $self->{name} =~ /->/;
         print $self->color("input", $input);
     }
     else {
         my $proto_arg = $self->proto_arg;
         print "(";
         my $i = 0;
         for (@{$self->{input_av}}) {
             print ", " if $i;
             my $proto = substr($proto_arg, 0, 1, "");
             if ($proto ne "o") {
                 print $self->color("input", $_);
             }
             if ($proto eq "o" || $proto eq "O") {
                 print " = " if $proto eq "O";
                 print $self->color("output", _dump($outarg->[$i]));
             }
         }
         continue {
             $i++;
         }
         print ")";
     }
 }
 
 sub return_void {
     my $self = shift;
     my $arg = shift;
     $self->print_call($arg);
     print "\n";
     return;
 }
 
 sub return_scalar {
     my $self = shift;
     my $arg = shift;
     $self->print_call($arg);
     my $s = shift;
     my $name;
     my $proto_ret = $self->proto_ret;
     my $wrap = $autowrap_class{ref($s)};
     if ($proto_ret =~ /^\$\w+\z/ && ref($s) && ref($s) !~ /^(?:ARRAY|HASH|CODE|GLOB)\z/) {
         $name = $proto_ret;
     }
     else {
         $name = $wrap->{prefix} if $wrap;
     }
     if ($name) {
         $name .= $name_count{$name} if $name_count{$name}++;
         print " = ", $self->color("output", $name), "\n";
         $s = Data::Dump::Trace::wrap(name => $name, obj => $s, proto => $wrap->{proto});
     }
     else {
         print " = ", $self->color("output", _dump($s));
         if (!$s && $proto_ret =~ /!/ && $!) {
             print " ", $self->color("error", errno($!));
         }
         print "\n";
     }
     return $s;
 }
 
 sub return_list {
     my $self = shift;
     my $arg = shift;
     $self->print_call($arg);
     print " = ", $self->color("output", $self->proto_ret eq "%" ? _dumpkv(@_) : _dumpav(@_)), "\n";
     return @_;
 }
 
 sub errno {
     my $t = "";
     for (keys %!) {
         if ($!{$_}) {
             $t = $_;
             last;
         }
     }
     my $n = int($!);
     return "$t($n) $!";
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Data::Dump::Trace - Helpers to trace function and method calls
 
 =head1 SYNOPSIS
 
   use Data::Dump::Trace qw(autowrap mcall);
 
   autowrap("LWP::UserAgent" => "ua", "HTTP::Response" => "res");
 
   use LWP::UserAgent;
   $ua = mcall(LWP::UserAgent => "new");      # instead of LWP::UserAgent->new;
   $ua->get("http://www.example.com")->dump;
 
 =head1 DESCRIPTION
 
 The following functions are provided:
 
 =over
 
 =item autowrap( $class )
 
 =item autowrap( $class => $prefix )
 
 =item autowrap( $class1 => $prefix1,  $class2 => $prefix2, ... )
 
 =item autowrap( $class1 => \%info1, $class2 => \%info2, ... )
 
 Register classes whose objects are automatically wrapped when
 returned by one of the call functions below.  If $prefix is provided
 it will be used as to name the objects.
 
 Alternative is to pass an %info hash for each class.  The recognized keys are:
 
 =over
 
 =item prefix => $string
 
 The prefix string used to name objects of this type.
 
 =item proto => \%hash
 
 A hash of prototypes to use for the methods when an object is wrapped.
 
 =back
 
 =item wrap( name => $str, func => \&func, proto => $proto )
 
 =item wrap( name => $str, obj => $obj, proto => \%hash )
 
 Returns a wrapped function or object.  When a wrapped function is
 invoked then a trace is printed after the underlying function has returned.
 When a method on a wrapped object is invoked then a trace is printed
 after the methods on the underlying objects has returned.
 
 See L</"Prototypes"> for description of the C<proto> argument.
 
 =item call( $name, \&func, $proto, @ARGS )
 
 Calls the given function with the given arguments.  The trace will use
 $name as the name of the function.
 
 See L</"Prototypes"> for description of the $proto argument.
 
 =item mcall( $class, $method, $proto, @ARGS )
 
 =item mcall( $object, $method, $proto, @ARGS )
 
 Calls the given method with the given arguments.
 
 See L</"Prototypes"> for description of the $proto argument.
 
 =item trace( $symbol, $prototype )
 
 Replaces the function given by $symbol with a wrapped function.
 
 =back
 
 =head2 Prototypes
 
 B<Note: The prototype string syntax described here is experimental and
 likely to change in revisions of this interface>.
 
 The $proto argument to call() and mcall() can optionally provide a
 prototype for the function call.  This give the tracer hints about how
 to best format the argument lists and if there are I<in/out> or I<out>
 arguments.  The general form for the prototype string is:
 
    <arguments> = <return_value>
 
 The default prototype is "@ = @"; list of values as input and list of
 values as output.
 
 The value '%' can be used for both arguments and return value to say
 that key/value pair style lists are used.
 
 Alternatively, individual positional arguments can be listed each
 represented by a letter:
 
 =over
 
 =item C<i>
 
 input argument
 
 =item C<o>
 
 output argument
 
 =item C<O>
 
 both input and output argument
 
 =back
 
 If the return value prototype has C<!> appended, then it signals that
 this function sets errno ($!) when it returns a false value.  The
 trace will display the current value of errno in that case.
 
 If the return value prototype looks like a variable name (with C<$>
 prefix), and the function returns a blessed object, then the variable
 name will be used as prefix and the returned object automatically
 traced.
 
 =head1 SEE ALSO
 
 L<Data::Dump>
 
 =head1 AUTHOR
 
 Copyright 2009 Gisle Aas.
 
 This library is free software; you can redistribute it and/or
 modify it under the same terms as Perl itself.
 
 =cut
### Data/Format/Pretty.pm ###
 package Data::Format::Pretty;
 
 use 5.010001;
 use strict;
 use warnings;
 
 use Module::Load;
 use Module::Loaded;
 
 require Exporter;
 our @ISA       = qw(Exporter);
 our @EXPORT    = qw(ppr);
 our @EXPORT_OK = qw(format_pretty print_pretty ppr);
 
 our $VERSION = '0.04'; # VERSION
 
 sub format_pretty {
     my ($data, $opts0) = @_;
 
     my %opts = $opts0 ? %$opts0 : ();
     my $module = $opts{module};
     if (!$module) {
         if ($ENV{GATEWAY_INTERFACE} || $ENV{PLACK_ENV}) {
             $module = 'HTML';
         } else {
             $module = 'Console';
         }
     }
     delete $opts{module};
 
     my $module_full = "Data::Format::Pretty::" . $module;
     load $module_full unless is_loaded $module_full;
     my $sub = \&{$module_full . "::format_pretty"};
 
     $sub->($data, \%opts);
 }
 
 sub print_pretty {
     print format_pretty(@_);
 }
 
 *ppr = \&print_pretty;
 
 1;
 # ABSTRACT: Pretty-print data structure
 
 
 =pod
 
 =head1 NAME
 
 Data::Format::Pretty - Pretty-print data structure
 
 =head1 VERSION
 
 version 0.04
 
 =head1 SYNOPSIS
 
 In your program:
 
  use Data::Format::Pretty qw(format_pretty print_pretty);
 
  # automatically choose an appropriate formatter
  print format_pretty($data);
 
  # explicitly select a formatter
  print format_pretty($data, {module=>'JSON'});
 
  # specify formatter option(s)
  print format_pretty($data, {module=>'Console', interactive=>1});
 
  # shortcut for printing to output
  print_pretty($data);
 
 
  # ppr() is alias for print_pretty(), exported automatically. suitable for when
  # debugging.
  use Data::Format::Pretty;
  ppr [1, 2, 3];
 
 =head1 DESCRIPTION
 
 Data::Format::Pretty is an extremely simple framework for pretty-printing data
 structure. Its focus is on "prettiness" and automatic detection of appropriate
 format to use.
 
 To develop a formatter, look at one of the formatter modules (like
 L<Data::Format::Pretty::JSON>) for example. You only need to specify one
 function, C<format_pretty>.
 
 =head1 FUNCTIONS
 
 =head2 format_pretty($data, \%opts) => STR
 
 Send $data to formatter module (one of Data::Format::Pretty::* modules) and
 return the result. Options:
 
 =over 4
 
 =item * module => STR
 
 Select the formatter module. It will be prefixed with "Data::Format::Pretty::".
 
 Currently if unspecified the default is 'Console', or 'HTML' if CGI/PSGI/plackup
 environment is detected. In the future, more sophisticated detection logic will
 be used.
 
 =back
 
 The rest of the options will be passed to the formatter module.
 
 =head2 print_pretty($data, \%opts)
 
 Just call format_pretty() and print() it.
 
 =head2 ppr($data, \%opts) [EXPORTED BY DEFAULT]
 
 Alias for print_pretty().
 
 =head1 SEE ALSO
 
 One of Data::Format::Pretty::* formatter, like L<Data::Format::Pretty::Console>,
 L<Data::Format::Pretty::HTML>, L<Data::Format::Pretty::JSON>,
 L<Data::Format::Pretty::YAML>.
 
 Alternative data formatting framework/module family: L<Any::Renderer>.
 
 =head1 AUTHOR
 
 Steven Haryanto <stevenharyanto@gmail.com>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2013 by Steven Haryanto.
 
 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__
 
### Data/Format/Pretty/CompactJSON.pm ###
 package Data::Format::Pretty::CompactJSON;
 
 use 5.010;
 use strict;
 use warnings;
 
 require Exporter;
 our @ISA = qw(Exporter);
 our @EXPORT_OK = qw(format_pretty);
 
 our $VERSION = '0.11'; # VERSION
 
 sub content_type { "application/json" }
 
 sub format_pretty {
     my ($data, $opts) = @_;
     state $json;
 
     $opts //= {};
 
     if ($opts->{color} // $ENV{COLOR} // (-t STDOUT)) {
         require JSON::Color;
         JSON::Color::encode_json($data, {pretty=>0, linum=>0});
     } else {
         if (!$json) {
             require JSON;
             $json = JSON->new->utf8->allow_nonref;
         }
         $json->encode($data);
     }
 }
 
 1;
 # ABSTRACT: Pretty-print data structure as compact JSON
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Format::Pretty::CompactJSON - Pretty-print data structure as compact JSON
 
 =head1 VERSION
 
 This document describes version 0.11 of Data::Format::Pretty::CompactJSON (from Perl distribution Data-Format-Pretty-JSON), released on 2014-12-10.
 
 =head1 SYNOPSIS
 
  use Data::Format::Pretty::CompactJSON qw(format_pretty);
  print format_pretty($data);
 
 Some example output:
 
 =over 4
 
 =item * format_pretty({a=>1, b=>2});
 
  {"a":1,"b":2}
 
 =back
 
 =head1 DESCRIPTION
 
 Like L<Data::Format::Pretty::JSON>, but will always print with JSON option C<<
 pretty => 0 >> (minimal indentation).
 
 =head1 FUNCTIONS
 
 =head2 format_pretty($data, \%opts)
 
 Return formatted data structure as JSON. Options:
 
 =over 4
 
 =item * color => BOOL
 
 Whether to enable coloring. The default is the enable only when running
 interactively.
 
 =back
 
 =head2 content_type() => STR
 
 Return C<application/json>.
 
 =head1 ENVIRONMENT
 
 =head2 COLOR => BOOL
 
 Set C<color> option (if unset).
 
 =head1 SEE ALSO
 
 L<Data::Format::Pretty::JSON>
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Format-Pretty-JSON>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Data-Format-Pretty-JSON>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Format-Pretty-JSON>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2014 by perlancar@cpan.org.
 
 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/Format/Pretty/Console.pm ###
 package Data::Format::Pretty::Console;
 
 our $DATE = '2015-10-20'; # DATE
 our $VERSION = '0.35'; # VERSION
 
 use 5.010001;
 use strict;
 use warnings;
 use experimental 'smartmatch';
 use Log::Any::IfLOG '$log';
 
 use Scalar::Util qw(blessed);
 use Text::ANSITable;
 use YAML::Any;
 use JSON;
 
 my $json = JSON->new->allow_nonref;
 
 require Exporter;
 our @ISA = qw(Exporter);
 our @EXPORT_OK = qw(format_pretty);
 
 sub content_type { "text/plain" }
 
 sub format_pretty {
     my ($data, $opts) = @_;
     $opts //= {};
     __PACKAGE__->new($opts)->_format($data);
 }
 
 # OO interface is nto documented, we use it just to subclass
 # Data::Format::Pretty::HTML
 sub new {
     my ($class, $opts) = @_;
     $opts //= {};
     $opts->{interactive} //= $ENV{INTERACTIVE} // (-t STDOUT);
     $opts->{table_column_orders} //= $json->decode(
         $ENV{FORMAT_PRETTY_TABLE_COLUMN_ORDERS})
         if defined($ENV{FORMAT_PRETTY_TABLE_COLUMN_ORDERS});
     $opts->{table_column_formats} //= $json->decode(
         $ENV{FORMAT_PRETTY_TABLE_COLUMN_FORMATS})
         if defined($ENV{FORMAT_PRETTY_TABLE_COLUMN_FORMATS});
     $opts->{table_column_types} //= $json->decode(
         $ENV{FORMAT_PRETTY_TABLE_COLUMN_TYPES})
         if defined($ENV{FORMAT_PRETTY_TABLE_COLUMN_TYPES});
     $opts->{list_max_columns} //= $ENV{FORMAT_PRETTY_LIST_MAX_COLUMNS};
     bless {opts=>$opts}, $class;
 }
 
 sub _is_cell_or_format_cell {
     my ($self, $data, $is_format) = @_;
 
     # XXX currently hardcoded limits
     my $maxlen = 1000;
 
     if (!ref($data) || blessed($data)) {
         if (!defined($data)) {
             return "" if $is_format;
             return 1;
         }
         if (length($data) > $maxlen) {
             return;
         }
         return "$data" if $is_format;
         return 1;
     } elsif (ref($data) eq 'ARRAY') {
         if (grep {ref($_) && !blessed($_)} @$data) {
             return;
         }
         my $s = join(", ", map {defined($_) ? "$_":""} @$data);
         if (length($s) > $maxlen) {
             return;
         }
         return $s if $is_format;
         return 1;
     } else {
         return;
     }
 }
 
 # return a string when data can be represented as a cell, otherwise undef. what
 # can be put in a table cell? a string (or stringified object) or array of
 # strings (stringified objects) that is quite "short".
 sub _format_cell { _is_cell_or_format_cell(@_, 1) }
 
 sub _is_cell     { _is_cell_or_format_cell(@_, 0) }
 
 sub _detect_struct {
     my ($self, $data) = @_;
     my $struct;
     my $struct_meta = {};
 
     # XXX perhaps, use Data::Schema later?
   CHECK_FORMAT:
     {
       CHECK_SCALAR:
         {
             if (!ref($data) || blessed($data)) {
                 $struct = "scalar";
                 last CHECK_FORMAT;
             }
         }
 
       CHECK_AOA:
         {
             if (ref($data) eq 'ARRAY') {
                 my $numcols;
                 for my $row (@$data) {
                     last CHECK_AOA unless ref($row) eq 'ARRAY';
                     last CHECK_AOA if defined($numcols) && $numcols != @$row;
                     last CHECK_AOA if grep { !$self->_is_cell($_) } @$row;
                     $numcols = @$row;
                 }
                 $struct = "aoa";
                 last CHECK_FORMAT;
             }
         }
 
       CHECK_AOH:
         {
             if (ref($data) eq 'ARRAY') {
                 $struct_meta->{columns} = {};
                 for my $row (@$data) {
                     last CHECK_AOH unless ref($row) eq 'HASH';
                     for my $k (keys %$row) {
                         last CHECK_AOH if !$self->_is_cell($row->{$k});
                         $struct_meta->{columns}{$k} = 1;
                     }
                 }
                 $struct = "aoh";
                 last CHECK_FORMAT;
             }
         }
 
         # list of scalars/cells
       CHECK_LIST:
         {
             if (ref($data) eq 'ARRAY') {
                 for (@$data) {
                     last CHECK_LIST unless $self->_is_cell($_);
                 }
                 $struct = "list";
                 last CHECK_FORMAT;
             }
         }
 
         # hash which contains at least one "table" (list/aoa/aoh)
       CHECK_HOT:
         {
             last CHECK_HOT if $self->{opts}{skip_hot};
             last CHECK_HOT unless ref($data) eq 'HASH';
             my $has_t;
             while (my ($k, $v) = each %$data) {
                 my ($s2, $sm2) = $self->_detect_struct($v, {skip_hot=>1});
                 last CHECK_HOT unless $s2;
                 $has_t = 1 if $s2 =~ /^(?:list|aoa|aoh|hash)$/;
             }
             last CHECK_HOT unless $has_t;
             $struct = "hot";
             last CHECK_FORMAT;
         }
 
         # hash of scalars/cells
       CHECK_HASH:
         {
             if (ref($data) eq 'HASH') {
                 for (values %$data) {
                     last CHECK_HASH unless $self->_is_cell($_);
                 }
                 $struct = "hash";
                 last CHECK_FORMAT;
             }
         }
 
     }
 
     ($struct, $struct_meta);
 }
 
 # t (table) is a structure like this: {cols=>["colName1", "colName2", ...]},
 # rows=>[ [row1.1, row1.2, ...], [row2.1, row2.2, ...], ... ], at_opts=>{...},
 # col_widths=>{colName1=>5, ...}}. the job of this routine is to render it
 # (currently uses Text::ANSITable).
 sub _render_table {
     my ($self, $t) = @_;
 
     my $colfmts;
     my $tcff = $self->{opts}{table_column_formats};
     if ($tcff) {
         for my $tcf (@$tcff) {
             my $match = 1;
             my @tcols = @{ $t->{cols} };
             for my $scol (keys %$tcf) {
                 do { $match = 0; last } unless $scol ~~ @tcols;
             }
             if ($match) {
                 $colfmts = $tcf;
                 last;
             }
         }
     }
 
     my $coltypes;
     my $tctt = $self->{opts}{table_column_types};
     if ($tctt) {
         for my $tct (@$tctt) {
             my $match = 1;
             my @tcols = @{ $t->{cols} };
             for my $scol (keys %$tct) {
                 do { $match = 0; last } unless $scol ~~ @tcols;
             }
             if ($match) {
                 $coltypes = $tct;
                 last;
             }
         }
     }
 
     # render using Text::ANSITable
     my $at = Text::ANSITable->new;
     $at->columns($t->{cols});
     $at->rows($t->{rows});
     if ($t->{at_opts}) {
         $at->{$_} = $t->{at_opts}{$_} for keys %{ $t->{at_opts} };
     }
     if ($colfmts) {
         $at->set_column_style($_ => formats => $colfmts->{$_})
             for keys %$colfmts;
     }
     if ($coltypes) {
         $at->set_column_style($_ => type => $coltypes->{$_})
             for keys %$coltypes;
     }
     if ($t->{col_widths}) {
         $at->set_column_style($_ => width => $t->{col_widths}{$_})
             for keys %{ $t->{col_widths} };
     }
     $at->draw;
 }
 
 # format unknown structure, the default is to dump YAML structure
 sub _format_unknown {
     my ($self, $data) = @_;
     Dump($data);
 }
 
 sub _format_scalar {
     my ($self, $data) = @_;
 
     my $sdata = defined($data) ? "$data" : "";
     return "" if !length($sdata);
     return $sdata =~ /\n\z/s ? $sdata : "$sdata\n";
 }
 
 sub _format_list {
     my ($self, $data) = @_;
     if ($self->{opts}{interactive}) {
 
         require List::Util;
         require POSIX;
 
         # format list as as columns (a la 'ls' output)
 
         my @rows = map { $self->_format_cell($_) } @$data;
 
         my $maxwidth = List::Util::max(map { length } @rows) // 0;
         my ($termcols, $termrows);
         if ($ENV{COLUMNS}) {
             $termcols = $ENV{COLUMNS};
         } elsif (eval { require Term::Size; 1 }) {
             ($termcols, $termrows) = Term::Size::chars();
         } else {
             # sane default, on windows we need to offset by 1 because printing
             # at the rightmost column will cause cursor to move down one line.
             $termcols = $^O =~ /Win/ ? 79 : 80;
         }
         my $numcols = 1;
         if ($maxwidth) {
             # | some-text-some | some-text-some... |
             # 2/\__maxwidth__/\3/\__maxwidth__/...\2
             #
             # table width = (2+maxwidth) + (3+maxwidth)*(numcols-1) + 2
             #
             # so with a bit of algrebra, solve for numcols:
             $numcols = int( (($termcols-1)-$maxwidth-6)/(3+$maxwidth) + 1 );
             $numcols = @rows if $numcols > @rows;
             $numcols = 1 if $numcols < 1;
         }
         $numcols = $self->{opts}{list_max_columns}
             if defined($self->{opts}{list_max_columns}) &&
                 $numcols > $self->{opts}{list_max_columns};
         my $numrows = POSIX::ceil(@rows/$numcols);
         if ($numrows) {
             # reduce number of columns to avoid empty columns
             $numcols = POSIX::ceil(@rows/$numrows);
         }
         #say "D: $numcols x $numrows";
 
         my $t = {rows=>[], at_opts=>{show_header=>0}};
         $t->{cols} = [map { "c$_" } 1..$numcols];
         if ($numcols > 1) {
             $t->{col_widths}{"c$_"} = $maxwidth for 1..$numcols;
         }
         for my $r (1..$numrows) {
             my @trow;
             for my $c (1..$numcols) {
                 my $idx = ($c-1)*$numrows + ($r-1);
                 push @trow, $idx < @rows ? $rows[$idx] : '';
             }
             push @{$t->{rows}}, \@trow;
         }
 
         return $self->_render_table($t);
 
     } else {
         my @rows;
         for my $row (@$data) {
             push @rows, ($row // "") . "\n";
         }
         return join("", @rows);
     }
 }
 
 sub _format_hash {
     my ($self, $data) = @_;
     # format hash as two-column table
     if ($self->{opts}{interactive}) {
         my $t = {cols=>[qw/key value/], rows=>[],
                  at_opts=>{}};
         for my $k (sort keys %$data) {
             push @{ $t->{rows} }, [$k, $self->_format_cell($data->{$k})];
         }
         return $self->_render_table($t);
     } else {
         my @t;
         for my $k (sort keys %$data) {
             push @t, $k, "\t", ($data->{$k} // ""), "\n";
         }
         return join("", @t);
     }
 }
 
 sub _format_aoa {
     my ($self, $data) = @_;
     # show aoa as table
     if ($self->{opts}{interactive}) {
         if (@$data) {
             my $t = {rows=>[], at_opts=>{}};
             $t->{cols} = [map { "column$_" } 0..@{ $data->[0] }-1];
             for my $i (0..@$data-1) {
                 push @{ $t->{rows} },
                     [map {$self->_format_cell($_)} @{ $data->[$i] }];
             }
             return $self->_render_table($t);
         } else {
             return "";
         }
     } else {
         # tab-separated
         my @t;
         for my $row (@$data) {
             push @t, join("\t", map { $self->_format_cell($_) } @$row) .
                 "\n";
         }
         return join("", @t);
     }
 }
 
 sub _format_aoh {
     my ($self, $data, $struct_meta) = @_;
     # show aoh as table
     my @cols = @{ $self->_order_table_columns(
         [keys %{$struct_meta->{columns}}]) };
     if ($self->{opts}{interactive}) {
         my $t = {cols=>\@cols, rows=>[]};
         for my $i (0..@$data-1) {
             my $row = $data->[$i];
             push @{ $t->{rows} }, [map {$self->_format_cell($row->{$_})} @cols];
         }
         return $self->_render_table($t);
     } else {
         # tab-separated
         my @t;
         for my $row (@$data) {
             my @row = map {$self->_format_cell($row->{$_})} @cols;
             push @t, join("\t", @row) . "\n";
         }
         return join("", @t);
     }
 }
 
 sub _format_hot {
     my ($self, $data) = @_;
     # show hot as paragraphs:
     #
     # key:
     # value (table)
     #
     # key2:
     # value ...
     my @t;
     for my $k (sort keys %$data) {
         push @t, "$k:\n", $self->_format($data->{$k}), "\n";
     }
     return join("", @t);
 }
 
 sub _format {
     my ($self, $data) = @_;
 
     my ($struct, $struct_meta) = $self->_detect_struct($data);
 
     if (!$struct) {
         return $self->_format_unknown($data, $struct_meta);
     } elsif ($struct eq 'scalar') {
         return $self->_format_scalar($data, $struct_meta);
     } elsif ($struct eq 'list') {
         return $self->_format_list($data, $struct_meta);
     } elsif ($struct eq 'hash') {
         return $self->_format_hash($data, $struct_meta);
     } elsif ($struct eq 'aoa') {
         return $self->_format_aoa($data, $struct_meta);
     } elsif ($struct eq 'aoh') {
         return $self->_format_aoh($data, $struct_meta);
     } elsif ($struct eq 'hot') {
         return $self->_format_hot($data, $struct_meta);
     } else {
         die "BUG: Unknown format `$struct`";
     }
 }
 
 sub _order_table_columns {
     #$log->tracef('=> _order_table_columns(%s)', \@_);
     my ($self, $cols) = @_;
 
     my $found; # whether we found an ordering in table_column_orders
     my $tco = $self->{opts}{table_column_orders};
     my %orders; # colname => idx
     if ($tco) {
         die "table_column_orders should be an arrayref"
             unless ref($tco) eq 'ARRAY';
       CO:
         for my $co (@$tco) {
             die "table_column_orders elements must all be arrayrefs"
                 unless ref($co) eq 'ARRAY';
             for (@$co) {
                 next CO unless $_ ~~ @$cols;
             }
 
             $found++;
             for (my $i=0; $i<@$co; $i++) {
                 $orders{$co->[$i]} = $i;
             }
             $found++;
             last CO;
         }
     }
 
     my @ocols;
     if ($found) {
         @ocols = sort {
             (defined($orders{$a}) && defined($orders{$b}) ?
                  $orders{$a} <=> $orders{$b} : 0)
                 || $a cmp $b
         } (sort @$cols);
     } else {
         @ocols = sort @$cols;
     }
 
     \@ocols;
 }
 
 1;
 # ABSTRACT: Pretty-print data structure for console output
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Format::Pretty::Console - Pretty-print data structure for console output
 
 =head1 VERSION
 
 This document describes version 0.35 of Data::Format::Pretty::Console (from Perl distribution Data-Format-Pretty-Console), released on 2015-10-20.
 
 =head1 SYNOPSIS
 
 In your program:
 
  use Data::Format::Pretty::Console qw(format_pretty);
  ...
  print format_pretty($result);
 
 Some example output:
 
 Scalar, format_pretty("foo"):
 
  foo
 
 List, format_pretty([1..21]):
 
  .------------------------------------------------------.
  |  1 |  3 |  5 |  7 |  9 | 11 | 13 | 15 | 17 | 19 | 21 |
  |  2 |  4 |  6 |  8 | 10 | 12 | 14 | 16 | 18 | 20 |    |
  '----+----+----+----+----+----+----+----+----+----+----'
 
 The same list, when program output is being piped (that is, (-t STDOUT) is
 false):
 
  1
  2
  3
  4
  5
  6
  7
  8
  9
  10
  11
  12
  14
  15
  16
  17
  18
  19
  20
  21
 
 Hash, format_pretty({foo=>"data",bar=>"format",baz=>"pretty",qux=>"console"}):
 
  +-----+---------+
  | bar | format  |
  | baz | pretty  |
  | foo | data    |
  | qux | console |
  '-----+---------'
 
 2-dimensional array, format_pretty([ [1, 2, ""], [28, "bar", 3], ["foo", 3,
 undef] ]):
 
  +---------+---------+---------+
  |       1 |       2 |         |
  |      28 | bar     |       3 |
  | foo     |       3 |         |
  '---------+---------+---------'
 
 An array of hashrefs, such as commonly found if you use DBI's fetchrow_hashref()
 and friends, format_pretty([ {a=>1, b=>2}, {b=>2, c=>3}, {c=>4} ]):
 
  .-----------.
  | a | b | c |
  +---+---+---+
  | 1 | 2 |   |
  |   | 2 | 3 |
  |   |   | 4 |
  '---+---+---'
 
 Some more complex data, format_pretty({summary => "Blah...", users =>
 [{name=>"budi", domains=>["foo.com", "bar.com"], quota=>"1000"}, {name=>"arif",
 domains=>["baz.com"], quota=>"2000"}], verified => 0}):
 
  summary:
  Blah...
 
  users:
  .---------------------------------.
  | domains          | name | quota |
  +------------------+------+-------+
  | foo.com, bar.com | budi |  1000 |
  | baz.com          | arif |  2000 |
  '------------------+------+-------'
 
  verified:
  0
 
 Structures which can't be handled yet will simply be output as YAML,
 format_pretty({a {b=>1}}):
 
  ---
  a:
    b: 1
 
 =head1 DESCRIPTION
 
 This module is meant to output data structure in a "pretty" or "nice" format,
 suitable for console programs. The idea of this module is that for you to just
 merrily dump data structure to the console, and this module will figure out how
 to best display your data to the end-user.
 
 Currently this module tries to display the data mostly as a nice text table (or
 a series of text tables), and failing that, display it as YAML.
 
 This module takes piping into consideration, and will output a simpler, more
 suitable format when your user pipes your program's output into some other
 program.
 
 Most of the time, you don't have to configure anything, but some options are
 provided to tweak the output.
 
 =for Pod::Coverage ^(content_type)$
 
 =head1 FUNCTIONS
 
 =for Pod::Coverage new
 
 =head2 format_pretty($data, \%opts)
 
 Return formatted data structure. Options:
 
 =over
 
 =item * interactive => BOOL (optional, default undef)
 
 If set, will override interactive terminal detection (-t STDOUT). Simpler
 formatting will be done if terminal is non-interactive (e.g. when output is
 piped). Using this option will force simpler/full formatting.
 
 =item * list_max_columns => INT
 
 When displaying list as columns, specify maximum number of columns. This can be
 used to force fewer columns (for example, single column) instead of using the
 whole available terminal width.
 
 =item * table_column_orders => [[COLNAME1, COLNAME2], ...]
 
 Specify column orders when drawing a table. If a table has all the columns, then
 the column names will be ordered according to the specification. For example,
 when table_column_orders is [[qw/foo bar baz/]], this table's columns will not
 be reordered because it doesn't have all the mentioned columns:
 
  |foo|quux|
 
 But this table will:
 
  |apple|bar|baz|foo|quux|
 
 into:
 
  |apple|foo|bar|baz|quux|
 
 =item * table_column_formats => [{COLNAME=>FMT, ...}, ...]
 
 Specify formats for columns. Each table format specification is a hashref
 {COLNAME=>FMT, COLNAME2=>FMT2, ...}. It will be applied to a table if the table
 has all the columns. FMT is a format specification according to
 L<Data::Unixish::Apply>, it's basically either a name of a dux function (e.g.
 C<"date">) or an array of function name + arguments (e.g. C<< [['date', [align
 => {align=>'middle'}]] >>). This will be fed to L<Text::ANSITable>'s C<formats>
 column style.
 
 =item * table_column_types => [{COLNAME=>TYPE, ...}, ...]
 
 Specify types for columns. Each table format specification is a hashref
 {COLNAME=>TYPE, COLNAME2=>TYPE2, ...}. It will be applied to a table if the
 table has all the columns. TYPE is type name according to L<Sah> schema. This
 will be fed to L<Text::ANSITable>'s C<type> column style to give hints on how to
 format the column. Sometimes this is the simpler alternative to
 C<table_column_formats>.
 
 =back
 
 =head1 ENVIRONMENT
 
 =over
 
 =item * INTERACTIVE => BOOL
 
 To set default for C<interactive> option (overrides automatic detection).
 
 =item * FORMAT_PRETTY_LIST_MAX_COLUMNS => INT
 
 To set C<list_max_columns> option.
 
 =item * FORMAT_PRETTY_TABLE_COLUMN_FORMATS => ARRAY (JSON)
 
 To set C<table_column_formats> option, interpreted as JSON.
 
 =item * FORMAT_PRETTY_TABLE_COLUMN_TYPES => ARRAY (JSON)
 
 To set C<table_column_types> option, interpreted as JSON.
 
 =item * FORMAT_PRETTY_TABLE_COLUMN_ORDERS => ARRAY (JSON)
 
 To set C<table_column_orders> option, interpreted as JSON.
 
 =item * COLUMNS => INT
 
 To override terminal width detection.
 
 =back
 
 =head1 SEE ALSO
 
 Modules used for formatting: L<Text::ANSITable>, L<YAML>.
 
 L<Data::Format::Pretty>
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Format-Pretty-Console>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Data-Format-Pretty-Console>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Format-Pretty-Console>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Format/Pretty/HTML.pm ###
 package Data::Format::Pretty::HTML;
 
 use 5.010001;
 use strict;
 use warnings;
 use Log::Any::IfLOG '$log';
 
 use Data::Format::Pretty::Console 0.24;
 use HTML::Entities;
 use Scalar::Util qw(looks_like_number);
 use URI::Find::Schemeless;
 use YAML::Any;
 
 require Exporter;
 our @ISA = qw(Exporter Data::Format::Pretty::Console);
 our @EXPORT_OK = qw(format_pretty);
 
 our $VERSION = '0.10'; # VERSION
 
 sub content_type { "text/html" }
 
 sub format_pretty {
     my ($data, $opts) = @_;
     $opts //= {};
     __PACKAGE__->new($opts)->_format($data);
 }
 
 # OO interface is hidden
 sub new {
     my ($class, $opts) = @_;
     my $obj = $class->SUPER::new($opts);
     #my $obj = Data::Format::Pretty::Console->new($opts);
     $obj->{opts}{linkify_urls_in_text} //= 1;
     $obj->{opts}{interactive} = 1;
     $obj->{opts}{list_max_columns} = 1;
     #bless $class, $obj;
     $obj;
 }
 
 sub _htmlify {
     my ($self, $text) = @_;
 
     $text = encode_entities($text);
     if ($self->{opts}{linkify_urls_in_text}) {
         URI::Find::Schemeless->new(
             sub {
                 #my $uri = encode_entities $_[0];
                 #my $uri = $_[0];
                 my $uri = decode_entities $_[0];
                 return qq|<a href="$uri">$uri</a>|;
             })->find(\$text);
     }
     if ($text =~ /\R/) {
         return "<pre>$text</pre>";
     } else {
         return $text;
     }
 }
 
 sub _render_table {
     my ($self, $t) = @_;
     my @t = ("<table>\n");
 
     my $sh = $t->{at_opts}{show_header};
     unless (defined($sh) && !$sh) {
         push @t, "  <thead>\n";
         push @t, "    <tr>";
         for my $c (@{$t->{cols}}) {
             push @t, (
                 "<th", (looks_like_number($c) ? ' class="number"':''), ">",
                 $self->_htmlify($c),
                 "</th>",
             );
         }
         push @t, "</tr>\n";
         push @t, "  </thead>\n";
     }
 
     push @t, "  <tbody>\n";
     for my $r (@{$t->{rows}}) {
         push @t, "    <tr>";
         my $cidx = 0;
         for my $c (@$r) {
             if ($t->{html_cols} && $t->{html_cols}[$cidx]) {
                 push @t, "<td>", $c, "</td>";
             } else {
                 push @t, (
                     "<td", (looks_like_number($c) ? ' class="number"':''), ">",
                     $self->_htmlify($c),
                     "</td>",
                 );
             }
             $cidx++;
         }
         push @t, "</tr>\n";
     }
     push @t, "  </tbody>\n";
     push @t, "</table>\n";
     join "", @t;
 }
 
 # format unknown structure, the default is to dump YAML structure
 sub _format_unknown {
     my ($self, $data) = @_;
     $self->_htmlify(Dump $data);
 }
 
 sub _format_scalar {
     my ($self, $data) = @_;
 
     my $sdata = defined($data) ? "$data" : "";
     $self->_htmlify($sdata);
 }
 
 sub _format_hot {
     my ($self, $data) = @_;
     my @t;
     # format as 2-column table of key/value
     my $t = {cols=>[qw/key value/], html_cols=>[0, 1], rows=>[]};
     for my $k (sort keys %$data) {
         push @{ $t->{rows} }, [$k, $self->_format($data->{$k})];
     }
     $self->_render_table($t);
 }
 
 1;
 # ABSTRACT: Pretty-print data structure for HTML output
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Format::Pretty::HTML - Pretty-print data structure for HTML output
 
 =head1 VERSION
 
 This document describes version 0.10 of Data::Format::Pretty::HTML (from Perl distribution Data-Format-Pretty-HTML), released on 2015-08-17.
 
 =head1 SYNOPSIS
 
 In your program:
 
  use Data::Format::Pretty::HTML qw(format_pretty);
  ...
  print format_pretty($result);
 
 Some example output:
 
 Scalar, format_pretty("foo & bar"):
 
  foo &amp; bar
 
 Scalar multiline, format_pretty("foo\nbar\nbaz"):
 
  <pre>foo
  bar
  baz</pre>
 
 List, format_pretty([qw/foo bar baz qux/]):
 
  <table>
    <tr><td>foo</td></tr>
    <tr><td>bar</td></tr>
    <tr><td>baz</td></tr>
    <tr><td>qux</td></tr>
  </table>
 
 Hash, format_pretty({foo=>"data",bar=>"format",baz=>"pretty",qux=>"html"}):
 
  <table>
    <tr><th>key</th><th>value</th></tr>
    <tr><td>bar</td><td>format</td></tr>
    <tr><td>baz</td><td>pretty</td></tr>
    <tr><td>foo</td><td>data</td></tr>
    <tr><td>qux</td><td>html</td></tr>
  </table>
 
 2-dimensional array, format_pretty([ [1, 2, ""], [28, "bar", 3], ["foo", 3,
 undef] ]):
 
  <table>
    <tr><th>column0</th><th>column1</th><th>column2</th></tr>
    <tr><td class="number">1</td><td class="number">2</td><td></td></tr>
    <tr><td class="number">28</td><td>bar</td><td class="number">3</td></tr>
    <tr><td>foo</td><td class="number">3</td><td></td></tr>
  </table>
 
 An array of hashrefs, such as commonly found if you use DBI's fetchrow_hashref()
 and friends, format_pretty([ {a=>1, b=>2}, {b=>2, c=>3}, {c=>4} ]):
 
  <table>
    <tr><th>a</th><th>b</th><th>c</th></tr>
    <tr><td class="number">1</td><td class="number">2</td><td></td></tr>
    <tr><td></td><td class="number">2</td><td class="number">3</td></tr>
    <tr><td></td><td></td><td class="number">4</td></tr>
  </table>
 
 Some more complex data, format_pretty({summary => "Blah...", users =>
 [{name=>"budi", domains=>["f.com", "b.com"], quota=>"1000"}, {name=>"arif",
 domains=>["baz.com"], quota=>"2000"}], verified => 0}):
 
  <table>
 
    <tr>
      <td>summary</td>
      <td>Blah...</td>
    </tr>
 
    <tr>
      <td>users</td>
      <td>
        <table>
          <tr><th>domains</th><th>name</th><th>quota</th></tr>
          <tr><td>f.com, b.com</td><td>budi</td><td class="number">1000</td></tr>
          <tr><td>baz.com</td><td>arif</td><td class="number">2000</td></tr>
      </td>
    </tr>
 
    <tr>
      <td>verified</td>
      <td class="number">0</td>
    </tr>
 
  </table>
 
 Structures which can't be handled yet will simply be output as YAML,
 format_pretty({a => {b=>1}}):
 
  <pre>a:
    b: 1
  </pre>
 
 =head1 DESCRIPTION
 
 This module has the same spirit as L<Data::Format::Pretty::Console> (and
 currently implemented as its subclass). The idea is to throw it some data
 structure and let it figure out how to best display the data in a pretty HTML
 format.
 
 Differences with Data::Format::Pretty::Console:
 
 =over 4
 
 =item * hot (hash of table) structure is rendered as table of inner tables
 
 =back
 
 =for Pod::Coverage new
 
 =head1 FUNCTIONS
 
 =head2 format_pretty($data, \%opts)
 
 Return formatted data structure as HTML. Options:
 
 =over 4
 
 =item * table_column_orders => [[colname, colname], ...]
 
 See Data::Format::Pretty::Console for more details.
 
 =item * linkify_urls_in_text => BOOL
 
 Whether to convert 'http://foo' in text into '<a
 href="http://foo">http://foo</a>'. Default is true.
 
 =back
 
 =head1 SEE ALSO
 
 L<Data::Format::Pretty>
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Format-Pretty-HTML>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Format-Pretty-HTML>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Format-Pretty-HTML>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Format/Pretty/JSON.pm ###
 package Data::Format::Pretty::JSON;
 
 use 5.010001;
 use strict;
 use warnings;
 
 require Exporter;
 our @ISA = qw(Exporter);
 our @EXPORT_OK = qw(format_pretty);
 
 our $VERSION = '0.11'; # VERSION
 
 sub content_type { "application/json" }
 
 sub format_pretty {
     my ($data, $opts) = @_;
     $opts //= {};
 
     state $json;
     my $interactive = (-t STDOUT);
     my $pretty = $opts->{pretty} // 1;
     my $color  = $opts->{color} // $ENV{COLOR} // $interactive //
         $opts->{pretty};
     my $linum  = $opts->{linum} // $ENV{LINUM} // 0;
     if ($color) {
         require JSON::Color;
         JSON::Color::encode_json($data, {pretty=>$pretty, linum=>$linum})."\n";
     } else {
         if (!$json) {
             require JSON;
             $json = JSON->new->utf8->allow_nonref;
         }
         $json->pretty($pretty);
         if ($linum) {
             require String::LineNumber;
             String::LineNumber::linenum($json->encode($data));
         } else {
             $json->encode($data);
         }
     }
 }
 
 1;
 # ABSTRACT: Pretty-print data structure as JSON
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Format::Pretty::JSON - Pretty-print data structure as JSON
 
 =head1 VERSION
 
 This document describes version 0.11 of Data::Format::Pretty::JSON (from Perl distribution Data-Format-Pretty-JSON), released on 2014-12-10.
 
 =head1 SYNOPSIS
 
  use Data::Format::Pretty::JSON qw(format_pretty);
  print format_pretty($data);
 
 =head1 DESCRIPTION
 
 This module uses L<JSON> or L<JSON::Color> to encode data as JSON.
 
 =for Pod::Coverage ^(new)$
 
 =head1 FUNCTIONS
 
 =head2 format_pretty($data, \%opts)
 
 Return formatted data structure as JSON. Options:
 
 =over 4
 
 =item * color => BOOL (default: from env or 1 on interactive)
 
 Whether to enable coloring. The default is the enable only when running
 interactively.
 
 =item * pretty => BOOL (default: 1)
 
 Whether to pretty-print JSON.
 
 =item * linum => BOOL (default: from env or 0)
 
 Whether to add line numbers.
 
 =back
 
 =head2 content_type() => STR
 
 Return C<application/json>.
 
 =head1 ENVIRONMENT
 
 =head2 COLOR => BOOL
 
 Set C<color> option (if unset).
 
 =head2 LINUM => BOOL
 
 Set C<linum> option (if unset).
 
 =head1 FAQ
 
 =head1 SEE ALSO
 
 L<Data::Format::Pretty>
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Format-Pretty-JSON>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Data-Format-Pretty-JSON>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Format-Pretty-JSON>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2014 by perlancar@cpan.org.
 
 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/Format/Pretty/SimpleText.pm ###
 package Data::Format::Pretty::SimpleText;
 
 use 5.010;
 use strict;
 use warnings;
 
 use Data::Format::Pretty::Console ();
 
 require Exporter;
 our @ISA = qw(Exporter);
 our @EXPORT_OK = qw(format_pretty);
 
 our $VERSION = '0.35'; # VERSION
 
 sub content_type { "text/plain" }
 
 sub format_pretty {
     my ($data, $opts) = @_;
     my %opts = $opts ? %$opts : ();
     $opts{interactive} = 0;
     Data::Format::Pretty::Console::format_pretty($data, \%opts);
 }
 
 1;
 # ABSTRACT: Pretty-print data structure as simple text
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Format::Pretty::SimpleText - Pretty-print data structure as simple text
 
 =head1 VERSION
 
 This document describes version 0.35 of Data::Format::Pretty::SimpleText (from Perl distribution Data-Format-Pretty-Console), released on 2015-10-20.
 
 =head1 SYNOPSIS
 
 In your program:
 
  use Data::Format::Pretty::SimpleText qw(format_pretty);
  print format_pretty($data);
 
 Some example output:
 
 =over 4
 
 =item * format_pretty([qw/foo bar baz qux/])
 
  foo
  bar
  baz
  qux
 
 =back
 
 =head1 DESCRIPTION
 
 This module just calls L<Data::Format::Pretty::Console::format_pretty> with
 C<interactive>=0 option.
 
 =for Pod::Coverage ^(content_type)$
 
 =head1 FUNCTIONS
 
 =head2 format_pretty($data, \%opts)
 
 Return formatted data structure. See L<Data::Format::Pretty::Console> for
 details.
 
 =head1 SEE ALSO
 
 L<Data::Format::Pretty::Console>
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Format-Pretty-Console>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Data-Format-Pretty-Console>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Format-Pretty-Console>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Format/Pretty/Text.pm ###
 package Data::Format::Pretty::Text;
 
 use 5.010;
 use strict;
 use warnings;
 
 use Data::Format::Pretty::Console ();
 
 require Exporter;
 our @ISA = qw(Exporter);
 our @EXPORT_OK = qw(format_pretty);
 
 our $VERSION = '0.35'; # VERSION
 
 sub content_type { "text/plain" }
 
 sub format_pretty {
     my ($data, $opts) = @_;
     my %opts = $opts ? %$opts : ();
     $opts{interactive} = 1;
     Data::Format::Pretty::Console::format_pretty($data, \%opts);
 }
 
 1;
 # ABSTRACT: Pretty-print data structure as text
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Format::Pretty::Text - Pretty-print data structure as text
 
 =head1 VERSION
 
 This document describes version 0.35 of Data::Format::Pretty::Text (from Perl distribution Data-Format-Pretty-Console), released on 2015-10-20.
 
 =head1 SYNOPSIS
 
 In your program:
 
  use Data::Format::Pretty::Text qw(format_pretty);
  print format_pretty($data);
 
 Some example output:
 
 =over 4
 
 =item * format_pretty([qw/foo bar baz qux/])
 
  +------+
  | foo  |
  | bar  |
  | baz  |
  | qux  |
  '------'
 
 =back
 
 =head1 DESCRIPTION
 
 This module just calls L<Data::Format::Pretty::Console::format_pretty> with
 C<interactive>=1 option.
 
 =for Pod::Coverage ^(content_type)$
 
 =head1 FUNCTIONS
 
 =head2 format_pretty($data, \%opts)
 
 Return formatted data structure. See L<Data::Format::Pretty::Console> for
 details.
 
 =head1 SEE ALSO
 
 L<Data::Format::Pretty::Console>
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Format-Pretty-Console>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Data-Format-Pretty-Console>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Format-Pretty-Console>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/ModeMerge.pm ###
 package Data::ModeMerge;
 
 our $DATE = '2015-02-21'; # DATE
 our $VERSION = '0.32'; # VERSION
 
 use 5.010001;
 use strict;
 use warnings;
 
 use Mo qw(build default);
 
 require Exporter;
 our @ISA = qw(Exporter);
 our @EXPORT = qw(mode_merge);
 
 sub mode_merge {
     my ($l, $r, $config_vars) = @_;
     my $mm = __PACKAGE__->new(config => $config_vars);
     $mm->merge($l, $r);
 }
 
 has config => (is => "rw");
 
 # hash of modename => handler
 has modes => (is => 'rw', default => sub { {} });
 
 has combine_rules => (is => 'rw');
 
 # merging process state
 has path => (is => "rw", default => sub { [] });
 has errors => (is => "rw", default => sub { [] });
 has mem => (is => "rw", default => sub { {} }); # for handling circular refs. {key=>{res=>[...], todo=>[sub1, ...]}, ...}
 has cur_mem_key => (is => "rw"); # for handling circular refs. instead of passing around this as argument, we put it here.
 
 sub _dump {
     require Data::Dumper;
 
     my ($self, $var) = @_;
     Data::Dumper->new([$var])->Indent(0)->Terse(1)->Sortkeys(1)->Dump;
 }
 
 sub _in($$) {
     my ($self, $needle, $haystack) = @_;
     return 0 unless defined($needle);
     my $r1 = ref($needle);
     my $f1 = $r1 ? $self->_dump($needle) : undef;
     for (@$haystack) {
         my $r2 = ref($_);
         next if $r1 xor $r2;
         return 1 if  $r2 && $f1 eq $self->_dump($_);
         return 1 if !$r2 && $needle eq $_;
     }
     0;
 }
 
 sub BUILD {
     require Data::ModeMerge::Config;
 
     my ($self, $args) = @_;
 
     if ($self->config) {
         # some sanity checks
         my $is_hashref = ref($self->config) eq 'HASH';
         die "config must be a hashref or a Data::ModeMerge::Config" unless
             $is_hashref || UNIVERSAL::isa($self->config, "Data::ModeMerge::Config");
         $self->config(Data::ModeMerge::Config->new(%{ $self->config })) if $is_hashref;
     } else {
         $self->config(Data::ModeMerge::Config->new);
     }
 
     for (qw(NORMAL KEEP ADD CONCAT SUBTRACT DELETE)) {
 	$self->register_mode($_);
     }
 
     if (!$self->combine_rules) {
         $self->combine_rules({
             # "left + right" => [which mode to use, which mode after merge]
             'ADD+ADD'            => ['ADD'     , 'ADD'   ],
             #'ADD+CONCAT'         => undef,
             'ADD+DELETE'         => ['DELETE'  , 'DELETE'],
             #'ADD+KEEP'           => undef,
             'ADD+NORMAL'         => ['NORMAL'  , 'NORMAL'],
             'ADD+SUBTRACT'       => ['SUBTRACT', 'ADD'   ],
 
             #'CONCAT+ADD'         => undef,
             'CONCAT+CONCAT'      => ['CONCAT'  , 'CONCAT'],
             'CONCAT+DELETE'      => ['DELETE'  , 'DELETE'],
             #'CONCAT+KEEP'        => undef,
             'CONCAT+NORMAL'      => ['NORMAL'  , 'NORMAL'],
             #'CONCAT+SUBTRACT'    => undef,
 
             'DELETE+ADD'         => ['NORMAL'  , 'ADD'     ],
             'DELETE+CONCAT'      => ['NORMAL'  , 'CONCAT'  ],
             'DELETE+DELETE'      => ['DELETE'  , 'DELETE'  ],
             'DELETE+KEEP'        => ['NORMAL'  , 'KEEP'    ],
             'DELETE+NORMAL'      => ['NORMAL'  , 'NORMAL'  ],
             'DELETE+SUBTRACT'    => ['NORMAL'  , 'SUBTRACT'],
 
             'KEEP+ADD'          => ['KEEP', 'KEEP'],
             'KEEP+CONCAT'       => ['KEEP', 'KEEP'],
             'KEEP+DELETE'       => ['KEEP', 'KEEP'],
             'KEEP+KEEP'         => ['KEEP', 'KEEP'],
             'KEEP+NORMAL'       => ['KEEP', 'KEEP'],
             'KEEP+SUBTRACT'     => ['KEEP', 'KEEP'],
 
             'NORMAL+ADD'        => ['ADD'     , 'NORMAL'],
             'NORMAL+CONCAT'     => ['CONCAT'  , 'NORMAL'],
             'NORMAL+DELETE'     => ['DELETE'  , 'NORMAL'],
             'NORMAL+KEEP'       => ['NORMAL'  , 'KEEP'  ],
             'NORMAL+NORMAL'     => ['NORMAL'  , 'NORMAL'],
             'NORMAL+SUBTRACT'   => ['SUBTRACT', 'NORMAL'],
 
             'SUBTRACT+ADD'      => ['SUBTRACT', 'SUBTRACT'],
             #'SUBTRACT+CONCAT'   => undef,
             'SUBTRACT+DELETE'   => ['DELETE'  , 'DELETE'  ],
             #'SUBTRACT+KEEP'     => undef,
             'SUBTRACT+NORMAL'   => ['NORMAL'  , 'NORMAL'  ],
             'SUBTRACT+SUBTRACT' => ['ADD'     , 'SUBTRACT'],
         });
     }
 }
 
 sub push_error {
     my ($self, $errmsg) = @_;
     push @{ $self->errors }, [[@{ $self->path }], $errmsg];
     return;
 }
 
 sub register_mode {
     my ($self, $name0) = @_;
     my $obj;
     if (ref($name0)) {
         my $obj = $name0;
     } elsif ($name0 =~ /^\w+(::\w+)+$/) {
         eval "require $name0; \$obj = $name0->new";
         die "Can't load module $name0: $@" if $@;
     } elsif ($name0 =~ /^\w+$/) {
         my $modname = "Data::ModeMerge::Mode::$name0";
         eval "require $modname; \$obj = $modname->new";
         die "Can't load module $modname: $@" if $@;
     } else {
         die "Invalid mode name $name0";
     }
     my $name = $obj->name;
     die "Mode $name already registered" if $self->modes->{$name};
     $obj->merger($self);
     $self->modes->{$name} = $obj;
 }
 
 sub check_prefix {
     my ($self, $hash_key) = @_;
     die "Hash key not a string" if ref($hash_key);
     my $dis = $self->config->disable_modes;
     if (defined($dis) && ref($dis) ne 'ARRAY') {
         $self->push_error("Invalid config value `disable_modes`: must be an array");
         return;
     }
     for my $mh (sort { $b->precedence_level <=> $a->precedence_level }
                 grep { !$dis || !$self->_in($_->name, $dis) }
                 values %{ $self->modes }) {
         if ($mh->check_prefix($hash_key)) {
             return $mh->name;
         }
     }
     return;
 }
 
 sub check_prefix_on_hash {
     my ($self, $hash) = @_;
     die "Not a hash" unless ref($hash) eq 'HASH';
     my $res = 0;
     for (keys %$hash) {
 	do { $res++; last } if $self->check_prefix($_);
     }
     $res;
 }
 
 sub add_prefix {
     my ($self, $hash_key, $mode) = @_;
     die "Hash key not a string" if ref($hash_key);
     my $dis = $self->config->disable_modes;
     if (defined($dis) && ref($dis) ne 'ARRAY') {
         die "Invalid config value `disable_modes`: must be an array";
     }
     if ($dis && $self->_in($mode, $dis)) {
         $self->push_error("Can't add prefix for currently disabled mode `$mode`");
         return $hash_key;
     }
     my $mh = $self->modes->{$mode} or die "Unknown mode: $mode";
     $mh->add_prefix($hash_key);
 }
 
 sub remove_prefix {
     my ($self, $hash_key) = @_;
     die "Hash key not a string" if ref($hash_key);
     my $dis = $self->config->disable_modes;
     if (defined($dis) && ref($dis) ne 'ARRAY') {
         die "Invalid config value `disable_modes`: must be an array";
     }
     for my $mh (sort { $b->precedence_level <=> $a->precedence_level }
                 grep { !$dis || !$self->_in($_->name, $dis) }
                 values %{ $self->modes }) {
         if ($mh->check_prefix($hash_key)) {
             my $r = $mh->remove_prefix($hash_key);
             if (wantarray) { return ($r, $mh->name) }
             else           { return $r }
         }
     }
     if (wantarray) { return ($hash_key, $self->config->default_mode) }
     else           { return $hash_key }
 }
 
 sub remove_prefix_on_hash {
     my ($self, $hash) = @_;
     die "Not a hash" unless ref($hash) eq 'HASH';
     for (keys %$hash) {
 	my $old = $_;
 	$_ = $self->remove_prefix($_);
 	next unless $old ne $_;
 	die "Conflict when removing prefix on hash: $old -> $_ but $_ already exists"
 	    if exists $hash->{$_};
 	$hash->{$_} = $hash->{$old};
 	delete $hash->{$old};
     }
     $hash;
 }
 
 sub merge {
     my ($self, $l, $r) = @_;
     $self->path([]);
     $self->errors([]);
     $self->mem({});
     $self->cur_mem_key(undef);
     my ($key, $res, $backup) = $self->_merge(undef, $l, $r);
     {
         success => !@{ $self->errors },
         error   => (@{ $self->errors } ?
                     join(", ",
                          map { sprintf("/%s: %s", join("/", @{ $_->[0] }), $_->[1]) }
                              @{ $self->errors }) : ''),
         result  => $res,
         backup  => $backup,
     };
 }
 
 # handle circular refs: process todo's
 sub _process_todo {
     my ($self) = @_;
     if ($self->cur_mem_key) {
         for my $mk (keys %{ $self->mem }) {
             my $res = $self->mem->{$mk}{res};
             if (defined($res) && @{ $self->mem->{$mk}{todo} }) {
                 #print "DEBUG: processing todo for mem<$mk>\n";
                 for (@{  $self->mem->{$mk}{todo} }) {
                     $_->(@$res);
                     return if @{ $self->errors };
                 }
                 $self->mem->{$mk}{todo} = [];
             }
         }
     }
 }
 
 sub _merge {
     my ($self, $key, $l, $r, $mode) = @_;
     my $c = $self->config;
     $mode //= $c->default_mode;
 
     my $mh = $self->modes->{$mode};
     die "Can't find handler for mode $mode" unless $mh;
 
     # determine which merge method we will call
     my $rl = ref($l);
     my $rr = ref($r);
     my $tl = $rl eq 'HASH' ? 'HASH' : $rl eq 'ARRAY' ? 'ARRAY' : $rl eq 'CODE' ? 'CODE' : !$rl ? 'SCALAR' : '';
     my $tr = $rr eq 'HASH' ? 'HASH' : $rr eq 'ARRAY' ? 'ARRAY' : $rr eq 'CODE' ? 'CODE' : !$rr ? 'SCALAR' : '';
     if (!$tl) { $self->push_error("Unknown type in left side: $rl"); return }
     if (!$tr) { $self->push_error("Unknown type in right side: $rr"); return }
     if (!$c->allow_create_array && $tl ne 'ARRAY' && $tr eq 'ARRAY') {
         $self->push_error("Not allowed to create array"); return;
     }
     if (!$c->allow_create_hash && $tl ne 'HASH' && $tr eq 'HASH') {
         $self->push_error("Not allowed to create hash"); return;
     }
     if (!$c->allow_destroy_array && $tl eq 'ARRAY' && $tr ne 'ARRAY') {
         $self->push_error("Not allowed to destroy array"); return;
     }
     if (!$c->allow_destroy_hash && $tl eq 'HASH' && $tr ne 'HASH') {
         $self->push_error("Not allowed to destroy hash"); return;
     }
     my $meth = "merge_${tl}_${tr}";
     if (!$mh->can($meth)) { $self->push_error("No merge method found for $tl + $tr (mode $mode)"); return }
 
     #$self->_process_todo;
     # handle circular refs: add to todo if necessary
     my $memkey;
     if ($rl || $rr) {
         $memkey = sprintf "%s%s %s%s %s %s",
             (defined($l) ? ($rl ? 2 : 1) : 0),
             (defined($l) ? "$l" : ''),
             (defined($r) ? ($rr ? 2 : 1) : 0),
             (defined($r) ? "$r" : ''),
             $mode,
             $self->config;
         #print "DEBUG: number of keys in mem = ".scalar(keys %{ $self->mem })."\n";
         #print "DEBUG: mem keys = \n".join("", map { "  $_\n" } keys %{ $self->mem }) if keys %{ $self->mem };
         #print "DEBUG: calculating memkey = <$memkey>\n";
     }
     if ($memkey) {
         if (exists $self->mem->{$memkey}) {
             $self->_process_todo;
             if (defined $self->mem->{$memkey}{res}) {
                 #print "DEBUG: already calculated, using cached result\n";
                 return @{ $self->mem->{$memkey}{res} };
             } else {
                 #print "DEBUG: detecting circular\n";
                 return ($key, undef, undef, 1);
             }
         } else {
             $self->mem->{$memkey} = {res=>undef, todo=>[]};
             $self->cur_mem_key($memkey);
             #print "DEBUG: invoking ".$mh->name."'s $meth(".$self->_dump($key).", ".$self->_dump($l).", ".$self->_dump($r).")\n";
             my ($newkey, $res, $backup) = $mh->$meth($key, $l, $r);
             #print "DEBUG: setting res for mem<$memkey>\n";
             $self->mem->{$memkey}{res} = [$newkey, $res, $backup];
             $self->_process_todo;
             return ($newkey, $res, $backup);
         }
     } else {
         $self->_process_todo;
         #print "DEBUG: invoking ".$mh->name."'s $meth(".$self->_dump($key).", ".$self->_dump($l).", ".$self->_dump($r).")\n";
         return $mh->$meth($key, $l, $r);
     }
 }
 
 # returns 1 if a is included in b (e.g. [user => "jajang"] in included in [user
 # => jajang => "quota"], but [user => "paijo"] is not)
 sub _path_is_included {
     my ($self, $p1, $p2) = @_;
     my $res = 1;
     for my $i (0..@$p1-1) {
         do { $res = 0; last } if !defined($p2->[$i]) || $p1->[$i] ne $p2->[$i];
     }
     #print "_path_is_included([".join(", ", @$p1)."], [".join(", ", @$p2)."])? $res\n";
     $res;
 }
 
 1;
 # ABSTRACT: Merge two nested data structures, with merging modes and options
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::ModeMerge - Merge two nested data structures, with merging modes and options
 
 =head1 VERSION
 
 This document describes version 0.32 of Data::ModeMerge (from Perl distribution Data-ModeMerge), released on 2015-02-21.
 
 =head1 SYNOPSIS
 
     use Data::ModeMerge;
 
     my $hash1 = { a=>1,    c=>1, d=>{  da =>[1]} };
     my $hash2 = { a=>2, "-c"=>2, d=>{"+da"=>[2]} };
 
 
     # if you want Data::ModeMerge to behave like many other merging
     # modules (e.g. Hash::Merge or Data::Merger), turn off modes
     # (prefix) parsing and options key parsing.
 
     my $mm = Data::ModeMerge->new(config => {parse_prefix=>0, options_key=>undef});
     my $res = $mm->merge($hash1, $hash2);
     die $res->{error} if $res->{error};
     # $res->{result} -> { a=>2, c=>1, "-c"=>2, d=>{da=>[1], "+da"=>[2]} }
 
 
     # otherwise Data::ModeMerge will parse prefix as well as options
     # key
 
     my $res = $mm->merge($hash1, $hash2);
     die $res->{error} if $res->{error};
     # $res->{result} -> { a=>2, c=>-1, d=>{da=>[1,2]} }
 
     $res = $merge({  a =>1, {  a2 =>1, ""=>{parse_prefix=>0}},
                   {".a"=>2, {".a2"=>2                       }});
     # $res->{result} -> { a=>12, {a2=>1, ".a2"=>2} }, parse_prefix is turned off in just the subhash
 
 
     # procedural interface
 
     my $res = mode_merge($hash1, $hash2, {allow_destroy_hash=>0});
 
 =head1 DESCRIPTION
 
 There are already several modules on CPAN to do recursive data
 structure merging, like L<Data::Merger> and
 L<Hash::Merge>. C<Data::ModeMerge> differs in that it offers merging
 "modes" and "options". It provides greater flexibility on what the
 result of a merge between two data should/can be. This module may or
 may not be what you need.
 
 One application of this module is in handling configuration. Often
 there are multiple levels of configuration, e.g. in your typical Unix
 command-line program there are system-wide config file in /etc,
 per-user config file under ~/, and command-line options. It's
 convenient programatically to load each of those in a hash and then
 merge system-wide hash with the per-user hash, and then merge the
 result with the command-line hash to get the a single hash as the
 final configuration. Your program can from there on deal with this
 just one hash instead of three.
 
 In a typical merging process between two hashes (left-side and
 right-side), when there is a conflicting key, then the right-side key
 will override the left-side. This is usually the desired behaviour in
 our said program as the system-wide config is there to provide
 defaults, and the per-user config (and the command-line arguments)
 allow a user to override those defaults.
 
 But suppose that the user wants to I<unset> a certain configuration
 setting that is defined by the system-wide config? She can't do that
 unless she edits the system-wide config (in which she might need admin
 rights), or the program allows the user to disregard the system-wide
 config. The latter is usually what's implemented by many Unix
 programs, e.g. the C<-noconfig> command-line option in C<mplayer>. But
 this has two drawbacks: a slightly added complexity in the program
 (need to provide a special, extra comand-line option) and the user
 loses all the default settings in the system-wide config. What she
 needed in the first place was to just unset I<a single setting> (a
 single key-value pair of the hash).
 
 L<Data::ModeMerge> comes to the rescue. It provides a so-called
 C<DELETE mode>.
 
  mode_merge({foo=>1, bar=>2}, {"!foo"=>undef, bar=>3, baz=>1});
 
 will result ini:
 
  {bar=>3, baz=>1}
 
 The C<!> prefix tells Data::ModeMerge to do a DELETE mode merging. So
 the final result will lack the C<foo> key.
 
 On the other hand, what if the system admin wants to I<protect> a
 certain configuration setting from being overriden by the user or the
 command-line? This is useful in a hosting or other retrictive
 environment where we want to limit users' freedom to some levels. This
 is possible via the KEEP mode merging.
 
  mode_merge({"^bar"=>2, "^baz"=>1}, {bar=>3, "!baz"=>0, qux=>7});
 
 will result in:
 
  {"^bar"=>2, "^baz"=>1, qux=>7}
 
 effectively protecting C<bar> and C<baz> from being
 overriden/deleted/etc.
 
 Aside from the two mentioned modes, there are also a few others
 available by default: ADD (prefix C<+>), CONCAT (prefix C<.>),
 SUBTRACT (prefix C<->), as well as the plain ol' NORMAL/override
 (optional prefix C<*>).
 
 You can add other modes by writing a mode handler module.
 
 You can change the default prefixes for each mode if you want. You can
 disable each mode individually.
 
 You can default to always using a certain mode, like the NORMAL mode,
 and ignore all the prefixes, in which case Data::ModeMerge will behave
 like most other merge modules.
 
 There are a few other options like whether or not the right side is
 allowed a "change the structure" of the left side (e.g. replacing a
 scalar with an array/hash, destroying an existing array/hash with
 scalar), maximum length of scalar/array/hash, etc.
 
 You can change default mode, prefixes, disable/enable modes, etc on a
 per-hash basis using the so-called B<options key>. See the B<OPTIONS
 KEY> section for more details.
 
 This module can handle (though not all possible cases)
 circular/recursive references.
 
 =for Pod::Coverage ^(BUILD)$
 
 =head1 MERGING PREFIXES AND YOUR DATA
 
 Merging with this module means you need to be careful when your hash
 keys might contain one of the mode prefixes characters by accident,
 because it will trigger the wrong merge mode and moreover the prefix
 characters will be B<stripped> from the final result (unless you
 configure the module not to do so).
 
 A rather common case is when you have regexes in your hash
 keys. Regexes often begins with C<^>, which coincidentally is a prefix
 for the KEEP mode. Or perhaps you have dot filenames as hash keys,
 where it clashes with the CONCAT mode. Or perhaps shell wildcards,
 where C<*> is also used as the prefix for NORMAL mode.
 
 To avoid clashes, you can either:
 
 =over 4
 
 =item * exclude the keys using
 C<exclude_merge>/C<include_merge>/C<exclude_parse>/C<include_parse>
 config settings
 
 =item * turn off some modes which you don't want via the
 C<disable_modes> config
 
 =item * change the prefix for that mode so that it doesn't clash with
 your data via the C<set_prefix> config
 
 =item * disable prefix parsing altogether via setting C<parse_prefix>
 config to 0
 
 =back
 
 You can do this via the configuration, or on a per-hash basis, using
 the options key.
 
 See L<Data::ModeMerge::Config> for more details on configuration.
 
 =head1 OPTIONS KEY
 
 Aside from merging mode prefixes, you also need to watch out if your
 hash contains a "" (empty string) key, because by default this is the
 key used for options key.
 
 Options key are used to specify configuration on a per-hash basis.
 
 If your hash keys might contain "" keys which are not meant to be an
 options key, you can either:
 
 =over 4
 
 =item * change the name of the key for options key, via setting
 C<options_key> config to another string.
 
 =item * turn off options key mechanism,
 by setting C<options_key> config to undef.
 
 =back
 
 See L<Data::ModeMerge::Config> for more details about options key.
 
 =head1 MERGING MODES
 
 =head2 NORMAL (optional '*' prefix on left/right side)
 
  mode_merge({  a =>11, b=>12}, {  b =>22, c=>23}); # {a=>11, b=>22, c=>23}
  mode_merge({"*a"=>11, b=>12}, {"*b"=>22, c=>23}); # {a=>11, b=>22, c=>23}
 
 =head2 ADD ('+' prefix on the right side)
 
  mode_merge({i=>3}, {"+i"=>4, "+j"=>1}); # {i=>7, j=>1}
  mode_merge({a=>[1]}, {"+a"=>[2, 3]}); # {a=>[1, 2, 3]}
 
 Additive merge on hashes will be treated like a normal merge.
 
 =head2 CONCAT ('.' prefix on the right side)
 
  mode_merge({i=>3}, {".i"=>4, ".j"=>1}); # {i=>34, j=>1}
 
 Concative merge on arrays will be treated like additive merge.
 
 =head2 SUBTRACT ('-' prefix on the right side)
 
  mode_merge({i=>3}, {"-i"=>4}); # {i=>-1}
  mode_merge({a=>["a","b","c"]}, {"-a"=>["b"]}); # {a=>["a","c"]}
 
 Subtractive merge on hashes behaves like a normal merge, except that
 each key on the right-side hash without any prefix will be assumed to
 have a DELETE prefix, i.e.:
 
  mode_merge({h=>{a=>1, b=>1}}, {-h=>{a=>2, "+b"=>2, c=>2}})
 
 is equivalent to:
 
  mode_merge({h=>{a=>1, b=>1}}, {h=>{"!a"=>2, "+b"=>2, "!c"=>2}})
 
 and will merge to become:
 
  {h=>{b=>3}}
 
 =head2 DELETE ('!' prefix on the right side)
 
  mode_merge({x=>WHATEVER}, {"!x"=>WHATEVER}); # {}
 
 =head2 KEEP ('^' prefix on the left/right side)
 
 If you add '^' prefix on the left side, it will be protected from
 being replaced/deleted/etc.
 
  mode_merge({'^x'=>WHATEVER1}, {"x"=>WHATEVER2}); # {x=>WHATEVER1}
 
 For hashes, KEEP mode means that all keys on the left side will not be
 replaced/modified/deleted, *but* you can still add more keys from the
 right side hash.
 
  mode_merge({a=>1, b=>2, c=>3},
             {a=>4, '^c'=>1, d=>5},
             {default_mode=>'KEEP'});
             # {a=>1, b=>2, c=>3, d=>5}
 
 Multiple prefixes on the right side is allowed, where the merging will
 be done by precedence level (highest first):
 
  mode_merge({a=>[1,2]}, {'-a'=>[1], '+a'=>[10]}); # {a=>[2,10]}
 
 but not on the left side:
 
  mode_merge({a=>1, '^a'=>2}, {a=>3}); # error!
 
 Precedence levels (from highest to lowest):
 
  KEEP
  NORMAL
  SUBTRACT
  CONCAT ADD
  DELETE
 
 =head1 FUNCTIONS
 
 =head2 mode_merge($l, $r[, $config_vars])
 
 A non-OO wrapper for merge() method. Exported by default. See C<merge>
 method for more details.
 
 =head1 ATTRIBUTES
 
 =head2 config
 
 A hashref for config. See L<Data::ModeMerge::Config>.
 
 =head2 modes
 
 =head2 combine_rules
 
 =head2 path
 
 =head2 errors
 
 =head2 mem
 
 =head2 cur_mem_key
 
 =head1 METHODS
 
 For typical usage, you only need merge().
 
 =head2 push_error($errmsg)
 
 Used by mode handlers to push error when doing merge. End users
 normally should not need this.
 
 =head2 register_mode($name_or_package_or_obj)
 
 Register a mode. Will die if mode with the same name already exists.
 
 =head2 check_prefix($hash_key)
 
 Check whether hash key has prefix for certain mode. Return the name of
 the mode, or undef if no prefix is detected.
 
 =head2 check_prefix_on_hash($hash)
 
 This is like C<check_prefix> but performed on every key of the
 specified hash. Return true if any of the key contain a merge prefix.
 
 =head2 add_prefix($hash_key, $mode)
 
 Return hash key with added prefix with specified mode. Log merge error
 if mode is unknown or is disabled.
 
 =head2 remove_prefix($hash_key)
 
 Return hash key will any prefix removed.
 
 =head2 remove_prefix_on_hash($hash)
 
 This is like C<remove_prefix> but performed on every key of the
 specified hash. Return the same hash but with prefixes removed.
 
 =head2 merge($l, $r)
 
 Merge two nested data structures. Returns the result hash: {
 success=>0|1, error=>'...', result=>..., backup=>... }. The 'error'
 key is set to contain an error message if there is an error. The merge
 result is in the 'result' key. The 'backup' key contains replaced
 elements from the original hash/array.
 
 =head1 CREATING AND USING YOUR OWN MODE
 
 Let's say you want to add a mode named C<FOO>. It will have the prefix
 '?'.
 
 Create the mode handler class,
 e.g. C<Data::ModeMerge::Mode::FOO>. It's probably best to subclass
 from L<Data::ModeMerge::Mode::Base>. The class must implement name(),
 precedence_level(), default_prefix(), default_prefix_re(), and
 merge_{SCALAR,ARRAY,HASH}_{SCALAR,ARRAY,HASH}(). For more details, see
 the source code of Base.pm and one of the mode handlers
 (e.g. NORMAL.pm).
 
 To use the mode, register it:
 
  my $mm = Data::ModeMerge->new;
  $mm->register_mode('FOO');
 
 This will require C<Data::ModeMerge::Mode::FOO>. After that, define
 the operations against other modes:
 
  # if there's FOO on the left and NORMAL on the right, what mode
  # should the merge be done in (FOO), and what the mode should be
  # after the merge? (NORMAL)
  $mm->combine_rules->{"FOO+NORMAL"} = ["FOO", "NORMAL"];
 
  # we don't define FOO+ADD
 
  $mm->combine_rules->{"FOO+KEEP"} = ["KEEP", "KEEP"];
 
  # and so on
 
 =head1 FAQ
 
 =head2 What is this module good for? Why would I want to use this module instead of the other hash merge modules?
 
 If you just need to (deeply) merge two hashes, chances are you do not
 need this module. Use, for example, L<Hash::Merge>, which is also
 flexible enough because it allows you to set merging behaviour for
 merging different types (e.g. SCALAR vs ARRAY).
 
 You might need this module if your data is recursive/self-referencing
 (which, last time I checked, is not handled well by Hash::Merge), or
 if you want to be able to merge differently (i.e. apply different
 merging B<modes>) according to different prefixes on the key, or
 through special key. In other words, you specify merging modes from
 inside the hash itself.
 
 I originally wrote Data::ModeMerge this for L<Data::Schema> and
 L<Config::Tree>. I want to reuse the "parent" schema (or
 configuration) in more ways other than just override conflicting
 keys. I also want to be able to allow the parent to protect certain
 keys from being overriden. I found these two features lacking in all
 merging modules that I've evaluated prior to writing Data::ModeMerge.
 
 =head1 SEE ALSO
 
 L<Data::ModeMerge::Config>
 
 Other merging modules on CPAN: L<Data::Merger> (from Data-Utilities),
 L<Hash::Merge>, L<Hash::Merge::Simple>
 
 L<Data::Schema> and L<Config::Tree> (among others, two modules which
 use Data::ModeMerge)
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-ModeMerge>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-ModeMerge>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-ModeMerge>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/ModeMerge/Config.pm ###
 package Data::ModeMerge::Config;
 
 our $DATE = '2015-02-21'; # DATE
 our $VERSION = '0.32'; # VERSION
 
 use 5.010;
 use Mo qw(build default);
 
 has recurse_hash          => (is => 'rw', default => sub{1});
 has recurse_array         => (is => 'rw', default => sub{0});
 has parse_prefix          => (is => 'rw', default => sub{1});
 has wanted_path           => (is => 'rw');
 has default_mode          => (is => 'rw', default => sub{'NORMAL'});
 has disable_modes         => (is => 'rw');
 has allow_create_array    => (is => 'rw', default => sub{1});
 has allow_create_hash     => (is => 'rw', default => sub{1});
 has allow_destroy_array   => (is => 'rw', default => sub{1});
 has allow_destroy_hash    => (is => 'rw', default => sub{1});
 has exclude_parse         => (is => 'rw');
 has exclude_parse_regex   => (is => 'rw');
 has include_parse         => (is => 'rw');
 has include_parse_regex   => (is => 'rw');
 has exclude_merge         => (is => 'rw');
 has exclude_merge_regex   => (is => 'rw');
 has include_merge         => (is => 'rw');
 has include_merge_regex   => (is => 'rw');
 has set_prefix            => (is => 'rw');
 has readd_prefix          => (is => 'rw', default => sub{1});
 has premerge_pair_filter  => (is => 'rw');
 has options_key           => (is => 'rw', default => sub{''});
 has allow_override        => (is => 'rw');
 has disallow_override     => (is => 'rw');
 
 # list of config settings only available in merger-object's config
 # (not in options key)
 sub _config_config {
     state $a = [qw/
         wanted_path
         options_key
         allow_override
         disallow_override
                   /];
 }
 
 # list of config settings available in options key
 sub _config_ok {
     state $a = [qw/
         recurse_hash
         recurse_array
         parse_prefix
         default_mode
         disable_modes
         allow_create_array
         allow_create_hash
         allow_destroy_array
         allow_destroy_hash
         exclude_parse
         exclude_parse_regex
         include_parse
         include_parse_regex
         exclude_merge
         exclude_merge_regex
         include_merge
         include_merge_regex
         set_prefix
         readd_prefix
         premerge_pair_filter
                   /];
 }
 
 1;
 # ABSTRACT: Data::ModeMerge configuration
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::ModeMerge::Config - Data::ModeMerge configuration
 
 =head1 VERSION
 
 This document describes version 0.32 of Data::ModeMerge::Config (from Perl distribution Data-ModeMerge), released on 2015-02-21.
 
 =head1 SYNOPSIS
 
  # getting configuration
  if ($mm->config->allow_extra_hash_keys) { ... }
 
  # setting configuration
  $mm->config->max_warnings(100);
 
 =head1 DESCRIPTION
 
 Configuration variables for Data::ModeMerge.
 
 =head1 ATTRIBUTES
 
 =head2 recurse_hash => BOOL
 
 Context: config, options key
 
 Default: 1
 
 Whether to recursively merge hash. When 1, each key-value pair between
 2 hashes will be recursively merged. Otherwise, the right-side hash
 will just replace the left-side.
 
 Options key will not be parsed under recurse_hash=0.
 
 Example:
 
  mode_merge({h=>{a=>1}}, {h=>{b=>1}}                   ); # {h=>{a=>1, b=>1}}
  mode_merge({h=>{a=>1}}, {h=>{b=>1}}, {recurse_hash=>0}); # {h=>{b=>1}}
 
 =head2 recurse_array => BOOL
 
 Context: config, options key
 
 Default: 0
 
 Whether to recursively merge array. When 1, each element is
 recursively merged. Otherwise, the right-side array will just replace
 the left-side.
 
 Example:
 
  mode_merge([1, 1], [4]                    ); # [4, 1]
  mode_merge([1, 1], [4], {recurse_array=>0}); # [2]
 
 =head2 parse_prefix => BOOL
 
 Context: config, options key
 
 Default: 1
 
 Whether to parse merge prefix in hash keys. If set to 0, merging
 behaviour is similar to most other nested merge modules.
 
  mode_merge({a=>1}, {"+a"=>2}                   ); # {a=>3}
  mode_merge({a=>1}, {"+a"=>2}, {parse_prefix=>0}); # {a=>1, "+a"=>2}
 
 =head2 wanted_path => ARRAYREF
 
 Context: config, options key
 
 Default: undef
 
 If set, merging is only done to the specified "branch". Useful to save
 time/storage when merging large hash "trees" while you only want a
 certain branch of the trees (e.g. resolving just a config variable
 from several config hashes).
 
 Example:
 
  mode_merge(
    {
     user => {
       jajang => { quota => 100, admin => 1 },
       paijo  => { quota =>  50, admin => 0 },
       kuya   => { quota => 150, admin => 0 },
     },
     groups => [qw/admin staff/],
    },
    {
     user => {
       jajang => { quota => 1000 },
     }
    }
  );
 
 With wanted_path unset, the result would be:
 
    {
     user => {
       jajang => { quota => 1000, admin => 1 },
       paijo  => { quota =>   50, admin => 0 },
       kuya   => { quota =>  150, admin => 0 },
     }
     groups => [qw/admin staff/],
    }
 
 With wanted_path set to ["user", "jajang", "quota"] (in other words,
 you're saying that you'll be disregarding other branches), the result
 would be:
 
    {
     user => {
       jajang => { quota => 1000, admin => undef },
     }
    }
 
 =head2 default_mode => 'NORMAL' | 'ADD' | 'CONCAT' | 'SUBTRACT' | 'DELETE' | 'KEEP' | ...
 
 Context: config, options key
 
 Default: NORMAL
 
 Example:
 
  mode_merge(3, 4                         ); # 4
  mode_merge(3, 4, {default_mode => "ADD"}); # 7
 
 =head2 disable_modes => ARRAYREF
 
 Context: config, options key
 
 Default: []
 
 List of modes to ignore the prefixes of.
 
 Example:
 
  mode_merge({add=>1, del=>2, concat=>3},
             {add=>2, "!del"=>0, .concat=>4},
             {disable_modes=>[qw/CONCAT/]});
  #          {add=>3,         concat=>3, .concat=>4}
 
 See also: C<parse_prefix> which if set to 0 will in effect disable all
 modes except the default mode.
 
 =head2 allow_create_array => BOOL
 
 Context: config, options key
 
 Default: 1
 
 If enabled, then array creation will be allowed (from something
 non-array, like a hash/scalar). Setting to 0 is useful if you want to
 avoid the merge to "change the structure" of the left side.
 
 Example:
 
  mode_merge(1, [1,2]                         ); # success, result=[1,2]
  mode_merge(1, [1,2], {allow_create_array=>0}); # failed, can't create array
 
 =head2 allow_create_hash => BOOL
 
 Context: config, options key
 
 Default: 1
 
 If enabled, then hash creation will be allowed (from something
 non-hash, like array/scalar). Setting to 0 is useful if you want to
 avoid the merge to "change the structure" of the left side.
 
 Example:
 
  mode_merge(1, {a=>1}                        ); # success, result={a=>1}
  mode_merge(1, {a=>1}, {allow_create_hash=>0}); # failed, can't create hash
 
 =head2 allow_destroy_array => BOOL
 
 Context: config, options key
 
 Default: 1
 
 If enabled, then replacing array on the left side with non-array
 (e.g. hash/scalar) on the right side is allowed. Setting to 0 is
 useful if you want to avoid the merge to "change the structure" of the
 left side.
 
 Example:
 
  mode_merge([1,2], {}                          ); # success, result={}
  mode_merge([1,2], {}, {allow_destroy_array=>0}); # failed, can't destroy array
 
 =head2 allow_destroy_hash => BOOL
 
 Context: config, options key
 
 Default: 1
 
 If enabled, then replacing hash on the left side with non-hash
 (e.g. array/scalar) on the right side is allowed. Setting to 0 is
 useful if you want to avoid the merge to "change the structure" of the
 left side.
 
 Example:
 
  mode_merge({a=>1}, []                         ); # success, result=[]
  mode_merge({a=>1}, [], {allow_destroy_hash=>0}); # failed, can't destroy hash
 
 =head2 exclude_parse => ARRAYREF
 
 Context: config, options key
 
 Default: undef
 
 The list of hash keys that should not be parsed for prefix and merged
 as-is using the default mode.
 
 If C<include_parse> is also mentioned then only keys in
 C<include_parse> and not in C<exclude_parse> will be parsed for
 prefix.
 
 Example:
 
  mode_merge({a=>1, b=>2}, {"+a"=>3, "+b"=>4}, {exclude_parse=>["+b"]}); # {a=>4, b=>2, "+b"=>4}
 
 =head2 exclude_parse_regex => REGEX
 
 Context: config, options key
 
 Default: undef
 
 Just like C<exclude_parse> but using regex instead of list.
 
 =head2 include_parse => ARRAYREF
 
 Context: config, options key
 
 Default: undef
 
 If specified, then only hash keys listed by this setting will be
 parsed for prefix. The rest of the keys will not be parsed and merged
 as-is using the default mode.
 
 If C<exclude_parse> is also mentioned then only keys in
 C<include_parse> and not in C<exclude_parse> will be parsed for
 prefix.
 
 Example:
 
  mode_merge({a=>1, b=>2, c=>3}, {"+a"=>4, "+b"=>5, "+c"=>6},
             {include_parse=>["+a"]}); # {a=>1, "+a"=>4, b=>7, c=>3, "+c"=>6}
 
 =head2 include_parse_regex => REGEX
 
 Context: config, options key
 
 Default: undef
 
 Just like C<include_parse> but using regex instead of list.
 
 =head2 exclude_merge => ARRAYREF
 
 Context: config, options key
 
 Default: undef
 
 The list of hash keys on the left side that should not be merged and
 instead copied directly to the result. All merging keys on the right
 side will be ignored.
 
 If C<include_merge> is also mentioned then only keys in
 C<include_merge> and not in C<exclude_merge> will be merged.
 
 Example:
 
  mode_merge({a=>1}, {"+a"=>20, "-a"=>30}, {exclude_merge=>["a"]}); # {a=>1}
 
 =head2 exclude_merge_regex => REGEX
 
 Context: config, options key
 
 Default: undef
 
 Just like C<exclude_merge> but using regex instead of list.
 
 =head2 include_merge => ARRAYREF
 
 Context: config, options key
 
 Default: undef
 
 If specified, then only hash keys listed by this setting will be
 merged.
 
 If C<exclude_merge> is also mentioned then only keys in
 C<include_merge> and not in C<exclude_merge> will be merged.
 
 Example:
 
  mode_merge({a=>1, b=>2, c=>3}, {"+a"=>40, "+b"=>50, "+c"=>60, "!c"=>70},
             {include_merge=>["a"]}); # {a=>41, b=>2, c=>3}
 
 =head2 include_merge_regex => ARRAYREF
 
 Context: config, options key
 
 Default: undef
 
 Just like C<include_merge> but using regex instead of list.
 
 =head2 set_prefix => HASHREF
 
 Context: config, options key
 
 Default: undef
 
 Temporarily change the prefix character for each mode. Value is
 hashref where each hash key is mode and the value is a new prefix
 string.
 
  mode_merge({a=>1, c=>2}, {'+a'=>10, '.c'=>20});                                        # {a=>11, c=>220}
  mode_merge({a=>1, c=>2}, {'+a'=>10, '.c'=>20}, {set_prefix=>{ADD=>'.', CONCAT=>'+'}}); # {a=>110, c=>22}
 
 =head2 readd_prefix => BOOL
 
 Context: config, options key
 
 Default: 1
 
 When merging two hashes, the prefixes are first stripped before
 merging. After merging is done, the prefixes by default will be
 re-added. This is done so that modes which are "sticky" (like KEEP)
 can propagate their mode). Setting C<readd_prefix> to 0 will prevent
 their stickiness.
 
  mode_merge({"^a"=>1}, {a=>2});                    # {"^a"=>1}
  mode_merge({"^a"=>1}, {a=>2}, {readd_prefix=>0}); # { "a"=>1}
 
 =head2 premerge_pair_filter => CODEREF
 
 Context: config, options key
 
 Default: undef
 
 Pass the key and value of each hash pair to a subroutine before
 merging (and before the keys are stripped for mode prefixes). Will
 push error if there is conflicting key in the hash.
 
 The subroutine should return a list of new key(s) and value(s). If key
 is undef then it means the pair should be discarded. This way, the
 filter is able to add or remove pairs from the hash.
 
  mode_merge({a=>1}, {"+amok"=>2},
             {premerge_pair_filter=>sub{ uc(substr($_[0],0,2)), $_[1]*2 }});
  # {"A"=>6}
 
 =head2 options_key => STR
 
 Context: config
 
 Default: '' (empty string)
 
 If defined, then when merging two hashes, this key will be searched
 first on the left-side and right-side hash. The values will then be
 merged and override (many of) the configuration.
 
 Options key is analogous to Apache's C<.htaccess> mechanism, which
 allows setting configuration on a per-directory (per-hash)
 basis. There's even an C<allow_override> config similar to Apache
 directive of the same name.
 
 If you want to disable processing of options key, set this to undef.
 
 Example:
 
  mode_merge({a=>1, {x=>3}},
             {a=>2, {x=>4}},
             {default_mode=>'ADD'}); # {a=>3, {x=>7}}
  mode_merge({a=>1, {x=>3}},
             {a=>2, {x=>4, ''=>{default_mode=>'CONCAT'}}},
             {default_mode=>'ADD'}); # {a=>3, {x=>34}}
 
 On the above example, C<default_mode> is set to ADD. But in the
 {x=>...} subhash, C<default_mode> is changed to CONCAT by the options
 key.
 
 =head2 allow_override => REGEX
 
 Context: config
 
 Default: undef
 
 If defined, then only config names matching regex will be able to be
 set in options key.
 
 If C<disallow_override> is also set, then only config names matching
 C<allow_override> and not matching C<disallow_override> will be able
 to be set in options key.
 
 =head2 disallow_override => REGEX
 
 Context: config
 
 Default: undef
 
 If defined, then config names matching regex will not be able to be
 set in options key.
 
 For example, if you want to restrict "structural changes" in merging
 while still allowing options key, you can set C<allow_create_hash>,
 C<allow_destroy_hash>, C<allow_create_array>, and
 C<allow_destroy_array> all to 0 and C<disallow_override> to
 C<allow_create|allow_destroy> to forbid overriding via options key.
 
 If C<disallow_override> is also set, then only config names matching
 C<allow_override> and not matching C<disallow_override> will be able
 to be set in options key.
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-ModeMerge>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-ModeMerge>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-ModeMerge>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/ModeMerge/Mode/ADD.pm ###
 package Data::ModeMerge::Mode::ADD;
 
 our $DATE = '2015-02-21'; # DATE
 our $VERSION = '0.32'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 use Mo qw(build default);
 extends 'Data::ModeMerge::Mode::NORMAL';
 
 sub name { 'ADD' }
 
 sub precedence_level { 3 }
 
 sub default_prefix { '+' }
 
 sub default_prefix_re { qr/^\+/ }
 
 sub merge_SCALAR_SCALAR {
     my ($self, $key, $l, $r) = @_;
     ($key, ( $l // 0 ) + $r);
 }
 
 sub merge_SCALAR_ARRAY {
     my ($self, $key, $l, $r) = @_;
     $self->merger->push_error("Can't add scalar and array");
     return;
 }
 
 sub merge_SCALAR_HASH {
     my ($self, $key, $l, $r) = @_;
     $self->merger->push_error("Can't add scalar and hash");
     return;
 }
 
 sub merge_ARRAY_SCALAR {
     my ($self, $key, $l, $r) = @_;
     $self->merger->push_error("Can't add array and scalar");
     return;
 }
 
 sub merge_ARRAY_ARRAY {
     my ($self, $key, $l, $r) = @_;
     ($key, [ @$l, @$r ]);
 }
 
 sub merge_ARRAY_HASH {
     my ($self, $key, $l, $r) = @_;
     $self->merger->push_error("Can't add array and hash");
     return;
 }
 
 sub merge_HASH_SCALAR {
     my ($self, $key, $l, $r) = @_;
     $self->merger->push_error("Can't add hash and scalar");
     return;
 }
 
 sub merge_HASH_ARRAY {
     my ($self, $key, $l, $r) = @_;
     $self->merger->push_error("Can't add hash and array");
     return;
 }
 
 1;
 # ABSTRACT: Handler for Data::ModeMerge ADD merge mode
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::ModeMerge::Mode::ADD - Handler for Data::ModeMerge ADD merge mode
 
 =head1 VERSION
 
 This document describes version 0.32 of Data::ModeMerge::Mode::ADD (from Perl distribution Data-ModeMerge), released on 2015-02-21.
 
 =head1 SYNOPSIS
 
  use Data::ModeMerge;
 
 =head1 DESCRIPTION
 
 This is the class to handle ADD merge mode.
 
 =for Pod::Coverage ^merge_.*
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-ModeMerge>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-ModeMerge>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-ModeMerge>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/ModeMerge/Mode/Base.pm ###
 package Data::ModeMerge::Mode::Base;
 
 our $DATE = '2015-02-21'; # DATE
 our $VERSION = '0.32'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 
 #use Log::Any '$log';
 use Mo qw(build default);
 
 #use Data::Clone qw/clone/;
 
 has merger => (is => 'rw');
 has prefix => (is => 'rw');
 has prefix_re => (is => 'rw');
 has check_prefix_sub => (is => 'rw');
 has add_prefix_sub => (is => 'rw');
 has remove_prefix_sub => (is => 'rw');
 
 sub name {
     die "Subclass must provide name()";
 }
 
 sub precedence_level {
     die "Subclass must provide precedence_level()";
 }
 
 sub default_prefix {
     die "Subclass must provide default_prefix()";
 }
 
 sub default_prefix_re {
     die "Subclass must provide default_prefix_re()";
 }
 
 sub BUILD {
     my ($self) = @_;
     $self->prefix($self->default_prefix);
     $self->prefix_re($self->default_prefix_re);
 }
 
 sub check_prefix {
     my ($self, $hash_key) = @_;
     if ($self->check_prefix_sub) {
         $self->check_prefix_sub->($hash_key);
     } else {
         $hash_key =~ $self->prefix_re;
     }
 }
 
 sub add_prefix {
     my ($self, $hash_key) = @_;
     if ($self->add_prefix_sub) {
         $self->add_prefix_sub->($hash_key);
     } else {
         $self->prefix . $hash_key;
     }
 }
 
 sub remove_prefix {
     my ($self, $hash_key) = @_;
     if ($self->remove_prefix_sub) {
         $self->remove_prefix_sub->($hash_key);
     } else {
         my $re = $self->prefix_re;
         $hash_key =~ s/$re//;
         $hash_key;
     }
 }
 
 sub merge_ARRAY_ARRAY {
     my ($self, $key, $l, $r) = @_;
     my $mm = $self->merger;
     my $c = $mm->config;
     return $self->merge_SCALAR_SCALAR($key, $l, $r) unless $c->recurse_array;
     return if $c->wanted_path && !$mm->_path_is_included($mm->path, $c->wanted_path);
 
     my @res;
     my @backup;
     my $la = @$l;
     my $lb = @$r;
     push @{ $mm->path }, -1;
     for my $i (0..($la > $lb ? $la : $lb)-1) {
         #print "DEBUG: merge_A_A: #$i: a->[$i]=".Data::Dumper->new([$l->[$i]])->Indent(0)->Terse(1)->Dump.", b->[$i]=".Data::Dumper->new([$r->[$i]])->Indent(0)->Terse(1)->Dump."\n";
         $mm->path->[-1] = $i;
         if ($i < $la && $i < $lb) {
             push @backup, $l->[$i];
             my ($subnewkey, $subres, $subbackup, $is_circular) = $mm->_merge($i, $l->[$i], $r->[$i], $c->default_mode);
             last if @{ $mm->errors };
             if ($is_circular) {
                 push @res, undef;
                 #print "DEBUG: pushing todo to mem<".$mm->cur_mem_key.">\n";
                 push @{ $mm->mem->{ $mm->cur_mem_key }{todo} }, sub {
                     my ($subnewkey, $subres, $subbackup) = @_;
                     #print "DEBUG: Entering todo subroutine (i=$i)\n";
                     $res[$i] = $subres;
                 }
             } else {
                 push @res, $subres;# if defined($newkey); = we allow DELETE on array?
             }
         } elsif ($i < $la) {
             push @res, $l->[$i];
         } else {
             push @res, $r->[$i];
         }
     }
     pop @{ $mm->path };
     ($key, \@res, \@backup);
 }
 
 sub _prefilter_hash {
     my ($self, $h, $desc, $sub) = @_;
     my $mm = $self->merger;
 
     if (ref($sub) ne 'CODE') {
         $mm->push_error("$desc failed: filter must be a coderef");
         return;
     }
 
     my $res = {};
     for (keys %$h) {
         my @r = $sub->($_, $h->{$_});
         while (my ($k, $v) = splice @r, 0, 2) {
             next unless defined $k;
             if (exists $res->{$k}) {
                 $mm->push_error("$desc failed; key conflict: ".
                                 "$_ -> $k, but key $k already exists");
                 return;
             }
             $res->{$k} = $v;
         }
     }
 
     $res;
 }
 
 # turn {[prefix]key => val, ...} into { key => [MODE, val], ...}, push
 # error if there's conflicting key
 sub _gen_left {
     my ($self, $l, $mode, $esub, $ep, $ip, $epr, $ipr) = @_;
     my $mm = $self->merger;
     my $c = $mm->config;
 
     #print "DEBUG: Entering _gen_left(".$mm->_dump($l).", $mode, ...)\n";
 
     if ($c->premerge_pair_filter) {
         $l = $self->_prefilter_hash($l, "premerge filter left hash",
                                     $c->premerge_pair_filter);
         return if @{ $mm->errors };
     }
 
     my $hl = {};
     if ($c->parse_prefix) {
         for (keys %$l) {
             my $do_parse = 1;
             $do_parse = 0 if $do_parse && $ep  &&  $mm->_in($_, $ep);
             $do_parse = 0 if $do_parse && $ip  && !$mm->_in($_, $ip);
             $do_parse = 0 if $do_parse && $epr &&  /$epr/;
             $do_parse = 0 if $do_parse && $ipr && !/$ipr/;
 
             if ($do_parse) {
                 my $old = $_;
                 my $m2;
                 ($_, $m2) = $mm->remove_prefix($_);
                 next if $esub && !$esub->($_);
                 if ($old ne $_ && exists($l->{$_})) {
                     $mm->push_error("Conflict when removing prefix on left-side ".
                                     "hash key: $old -> $_ but $_ already exists");
                     return;
                 }
                 $hl->{$_} = [$m2, $l->{$old}];
             } else {
                 next if $esub && !$esub->($_);
                 $hl->{$_} = [$mode, $l->{$_}];
             }
         }
     } else {
         for (keys %$l) {
             next if $esub && !$esub->($_);
             $hl->{$_} = [$mode, $l->{$_}];
         }
     }
 
     #print "DEBUG: Leaving _gen_left, result = ".$mm->_dump($hl)."\n";
     $hl;
 }
 
 # turn {[prefix]key => val, ...} into { key => {MODE=>val, ...}, ...},
 # push error if there's conflicting key+MODE
 sub _gen_right {
     my ($self, $r, $mode, $esub, $ep, $ip, $epr, $ipr) = @_;
     my $mm = $self->merger;
     my $c = $mm->config;
 
     #print "DEBUG: Entering _gen_right(".$mm->_dump($r).", $mode, ...)\n";
 
     if ($c->premerge_pair_filter) {
         $r = $self->_prefilter_hash($r, "premerge filter right hash",
                                     $c->premerge_pair_filter);
         return if @{ $mm->errors };
     }
 
     my $hr = {};
     if ($c->parse_prefix) {
         for (keys %$r) {
             my $do_parse = 1;
             $do_parse = 0 if $do_parse && $ep  &&  $mm->_in($_, $ep);
             $do_parse = 0 if $do_parse && $ip  && !$mm->_in($_, $ip);
             $do_parse = 0 if $do_parse && $epr &&  /$epr/;
             $do_parse = 0 if $do_parse && $ipr && !/$ipr/;
 
             if ($do_parse) {
                 my $old = $_;
                 my $m2;
                 ($_, $m2) = $mm->remove_prefix($_);
                 next if $esub && !$esub->($_);
                 if (exists $hr->{$_}{$m2}) {
                     $mm->push_error("Conflict when removing prefix on right-side ".
                                     "hash key: $old($m2) -> $_ ($m2) but $_ ($m2) ".
                                     "already exists");
                     return;
                 }
                 $hr->{$_}{$m2} = $r->{$old};
             } else {
                 next if $esub && !$esub->($_);
                 $hr->{$_} = {$mode => $r->{$_}};
             }
         }
     } else {
         for (keys %$r) {
             next if $esub && !$esub->($_);
             $hr->{$_} = {$mode => $r->{$_}}
         }
     }
     #print "DEBUG: Leaving _gen_right, result = ".$mm->_dump($hr)."\n";
     $hr;
 }
 
 # merge two hashes which have been prepared by _gen_left and
 # _gen_right, will result in { key => [final_mode, val], ... }
 sub _merge_gen {
     my ($self, $hl, $hr, $mode, $em, $im, $emr, $imr) = @_;
     my $mm = $self->merger;
     my $c = $mm->config;
 
     #print "DEBUG: Entering _merge_gen(".$mm->_dump($hl).", ".$mm->_dump($hr).", $mode, ...)\n";
 
     my $res = {};
     my $backup = {};
 
     my %k = map {$_=>1} keys(%$hl), keys(%$hr);
     push @{ $mm->path }, "";
   K:
     for my $k (keys %k) {
         my @o;
         $mm->path->[-1] = $k;
         my $do_merge = 1;
         $do_merge = 0 if $do_merge && $em  &&  $mm->_in($k, $em);
         $do_merge = 0 if $do_merge && $im  && !$mm->_in($k, $im);
         $do_merge = 0 if $do_merge && $emr && $k =~ /$emr/;
         $do_merge = 0 if $do_merge && $imr && $k !~ /$imr/;
 
         if (!$do_merge) {
             $res->{$k} = $hl->{$k} if $hl->{$k};
             next K;
         }
 
         $backup->{$k} = $hl->{$k}[1] if $hl->{$k} && $hr->{$k};
         if ($hl->{$k}) {
             push @o, $hl->{$k};
         }
         if ($hr->{$k}) {
             my %m = map {$_=>$mm->modes->{$_}->precedence_level} keys %{ $hr->{$k} };
             #print "DEBUG: \\%m=".Data::Dumper->new([\%m])->Indent(0)->Terse(1)->Dump."\n";
             push @o, map { [$_, $hr->{$k}{$_}] } sort { $m{$b} <=> $m{$a} } keys %m;
         }
         my $final_mode;
         my $is_circular;
         my $v;
         #print "DEBUG: k=$k, o=".Data::Dumper->new([\@o])->Indent(0)->Terse(1)->Dump."\n";
         for my $i (0..$#o) {
             if ($i == 0) {
                 my $mh = $mm->modes->{$o[$i][0]};
                 if (@o == 1 &&
                         (($hl->{$k} && $mh->can("merge_left_only")) ||
                          ($hr->{$k} && $mh->can("merge_right_only")))) {
                     # there's only left-side or right-side
                     my $meth = $hl->{$k} ? "merge_left_only" : "merge_right_only";
                     my ($subnewkey, $v, $subbackup, $is_circular, $newmode) = $mh->$meth($k, $o[$i][1]); # XXX handle circular?
                     next K unless defined($subnewkey);
                     $final_mode = $newmode;
                     $v = $res;
                 } else {
                     $final_mode = $o[$i][0];
                     $v = $o[$i][1];
                 }
             } else {
                 my $m = $mm->combine_rules->{"$final_mode+$o[$i][0]"}
                     or do {
                         $mm->push_error("Can't merge $final_mode + $o[$i][0]");
                         return;
                     };
                 #print "DEBUG: merge $final_mode+$o[$i][0] = $m->[0], $m->[1]\n";
                 my ($subnewkey, $subbackup);
                 ($subnewkey, $v, $subbackup, $is_circular) = $mm->_merge($k, $v, $o[$i][1], $m->[0]);
                 return if @{ $mm->errors };
                 if ($is_circular) {
                     if ($i < $#o) {
                         $mm->push_error("Can't handle circular at $i of $#o merges (mode $m->[0]): not the last merge");
                         return;
                     }
                     #print "DEBUG: pushing todo to mem<".$mm->cur_mem_key.">\n";
                     push @{ $mm->mem->{ $mm->cur_mem_key }{todo} }, sub {
                         my ($subnewkey, $subres, $subbackup) = @_;
                         #print "DEBUG: Entering todo subroutine (k=$k)\n";
                         my $final_mode = $m->[1];
                         #XXX return unless defined($subnewkey);
                         $res->{$k} = [$m->[1], $subres];
                         if ($c->readd_prefix) {
                             # XXX if there is a conflict error in
                             # _readd_prefix, how to adjust path?
                             $self->_readd_prefix($res, $k, $c->default_mode);
                         } else {
                             $res->{$k} = $res->{$k}[1];
                         }
                     };
                     delete $res->{$k};
                 }
                 next K unless defined $subnewkey;
                 $final_mode = $m->[1];
             }
         }
         $res->{$k} = [$final_mode, $v] unless $is_circular;
     }
     pop @{ $mm->path };
     #print "DEBUG: Leaving _merge_gen, res = ".$mm->_dump($res)."\n";
     ($res, $backup);
 }
 
 # hh is {key=>[MODE, val], ...} which is the format returned by _merge_gen
 sub _readd_prefix {
     my ($self, $hh, $k, $defmode) = @_;
     my $mm = $self->merger;
     my $c = $mm->config;
 
     my $m = $hh->{$k}[0];
     if ($m eq $defmode) {
         $hh->{$k} = $hh->{$k}[1];
     } else {
         my $kp = $mm->modes->{$m}->add_prefix($k);
         if (exists $hh->{$kp}) {
             $mm->push_error("BUG: conflict when re-adding prefix after merge: $kp");
             return;
         }
         $hh->{$kp} = $hh->{$k}[1];
         delete $hh->{$k};
     }
 }
 
 sub merge_HASH_HASH {
     my ($self, $key, $l, $r, $mode) = @_;
     my $mm = $self->merger;
     my $c = $mm->config;
     $mode //= $c->default_mode;
     #print "DEBUG: entering merge_H_H(".$mm->_dump($l).", ".$mm->_dump($r).", $mode), config=($c)=",$mm->_dump($c),"\n";
     #$log->trace("using config($c)");
 
     return $self->merge_SCALAR_SCALAR($key, $l, $r) unless $c->recurse_hash;
     return if $c->wanted_path && !$mm->_path_is_included($mm->path, $c->wanted_path);
 
     # STEP 1. MERGE LEFT & RIGHT OPTIONS KEY
     my $config_replaced;
     my $orig_c = $c;
     my $ok = $c->options_key;
     {
         last unless defined $ok;
 
         my $okl = $self->_gen_left ($l, $mode, sub {$_[0] eq $ok});
         return if @{ $mm->errors };
 
         my $okr = $self->_gen_right($r, $mode, sub {$_[0] eq $ok});
         return if @{ $mm->errors };
 
         push @{ $mm->path }, $ok;
         my ($res, $backup);
         {
             local $c->{readd_prefix} = 0;
             ($res, $backup) = $self->_merge_gen($okl, $okr, $mode);
         }
         pop @{ $mm->path };
         return if @{ $mm->errors };
 
         #print "DEBUG: merge options key (".$mm->_dump($okl).", ".$mm->_dump($okr).") = ".$mm->_dump($res)."\n";
 
         $res = $res->{$ok} ? $res->{$ok}[1] : undef;
         if (defined($res) && ref($res) ne 'HASH') {
             $mm->push_error("Invalid options key after merge: value must be hash");
             return;
         }
         last unless keys %$res;
         #$log->tracef("cloning config ...");
         # Data::Clone by default does *not* deep-copy object
         #my $c2 = clone($c);
         my $c2 = bless({ %$c }, ref($c));
 
         for (keys %$res) {
             if ($c->allow_override) {
                 my $re = $c->allow_override;
                 if (!/$re/) {
                     $mm->push_error("Configuration in options key `$_` not allowed by allow_override $re");
                     return;
                 }
             }
             if ($c->disallow_override) {
                 my $re = $c->disallow_override;
                 if (/$re/) {
                     $mm->push_error("Configuration in options key `$_` not allowed by disallow_override $re");
                     return;
                 }
             }
             if ($mm->_in($_, $c->_config_config)) {
                 $mm->push_error("Configuration not allowed in options key: $_");
                 return;
             }
             if ($_ ne $ok && !$mm->_in($_, $c->_config_ok)) {
                 $mm->push_error("Unknown configuration in options key: $_");
                 return;
             }
             $c2->$_($res->{$_}) unless $_ eq $ok;
         }
         $mm->config($c2);
         $config_replaced++;
         $c = $c2;
         #$log->trace("config now changed to $c2");
     }
 
     my $sp = $c->set_prefix;
     my $saved_prefixes;
     if (defined($sp)) {
         if (ref($sp) ne 'HASH') {
             $mm->push_error("Invalid config value `set_prefix`: must be a hash");
             return;
         }
         $saved_prefixes = {};
         for my $mh (values %{ $mm->modes }) {
             my $n = $mh->name;
             if ($sp->{$n}) {
                 $saved_prefixes->{$n} = {
                     prefix => $mh->prefix,
                     prefix_re => $mh->prefix_re,
                     check_prefix_sub => $mh->check_prefix_sub,
                     add_prefix_sub => $mh->add_prefix_sub,
                     remove_prefix_sub => $mh->remove_prefix_sub,
                 };
                 $mh->prefix($sp->{$n});
                 my $re = quotemeta($sp->{$n});
                 $mh->prefix_re(qr/^$re/);
                 $mh->check_prefix_sub(undef);
                 $mh->add_prefix_sub(undef);
                 $mh->remove_prefix_sub(undef);
             }
         }
     }
 
     my $ep = $c->exclude_parse;
     my $ip = $c->include_parse;
     if (defined($ep) && ref($ep) ne 'ARRAY') {
         $mm->push_error("Invalid config value `exclude_parse`: must be an array");
         return;
     }
     if (defined($ip) && ref($ip) ne 'ARRAY') {
         $mm->push_error("Invalid config value `include_parse`: must be an array");
         return;
     }
 
     my $epr = $c->exclude_parse_regex;
     my $ipr = $c->include_parse_regex;
     if (defined($epr)) {
         eval { $epr = qr/$epr/ };
         if ($@) {
             $mm->push_error("Invalid config value `exclude_parse_regex`: invalid regex: $@");
             return;
         }
     }
     if (defined($ipr)) {
         eval { $ipr = qr/$ipr/ };
         if ($@) {
             $mm->push_error("Invalid config value `include_parse_regex`: invalid regex: $@");
             return;
         }
     }
 
     # STEP 2. PREPARE LEFT HASH
     my $hl = $self->_gen_left ($l, $mode, sub {defined($ok) ? $_[0] ne $ok : 1}, $ep, $ip, $epr, $ipr);
     return if @{ $mm->errors };
 
     # STEP 3. PREPARE RIGHT HASH
     my $hr = $self->_gen_right($r, $mode, sub {defined($ok) ? $_[0] ne $ok : 1}, $ep, $ip, $epr, $ipr);
     return if @{ $mm->errors };
 
     #print "DEBUG: hl=".Data::Dumper->new([$hl])->Indent(0)->Terse(1)->Dump."\n";
     #print "DEBUG: hr=".Data::Dumper->new([$hr])->Indent(0)->Terse(1)->Dump."\n";
 
     my $em = $c->exclude_merge;
     my $im = $c->include_merge;
     if (defined($em) && ref($em) ne 'ARRAY') {
         $mm->push_error("Invalid config value `exclude_marge`: must be an array");
         return;
     }
     if (defined($im) && ref($im) ne 'ARRAY') {
         $mm->push_error("Invalid config value `include_merge`: must be an array");
         return;
     }
 
     my $emr = $c->exclude_merge_regex;
     my $imr = $c->include_merge_regex;
     if (defined($emr)) {
         eval { $emr = qr/$emr/ };
         if ($@) {
             $mm->push_error("Invalid config value `exclude_merge_regex`: invalid regex: $@");
             return;
         }
     }
     if (defined($imr)) {
         eval { $imr = qr/$imr/ };
         if ($@) {
             $mm->push_error("Invalid config value `include_merge_regex`: invalid regex: $@");
             return;
         }
     }
 
     # STEP 4. MERGE LEFT & RIGHT
     my ($res, $backup) = $self->_merge_gen($hl, $hr, $mode, $em, $im, $emr, $imr);
     return if @{ $mm->errors };
 
     #print "DEBUG: intermediate res(5) = ".Data::Dumper->new([$res])->Indent(0)->Terse(1)->Dump."\n";
 
     # STEP 5. TURN BACK {key=>[MODE=>val]}, ...} INTO {(prefix)key => val, ...}
     if ($c->readd_prefix) {
         for my $k (keys %$res) {
             $self->_readd_prefix($res, $k, $c->default_mode);
         }
     } else {
         $res->{$_} = $res->{$_}[1] for keys %$res;
     }
 
     if ($saved_prefixes) {
         for (keys %$saved_prefixes) {
             my $mh = $mm->modes->{$_};
             my $s = $saved_prefixes->{$_};
             $mh->prefix($s->{prefix});
             $mh->prefix_re($s->{prefix_re});
             $mh->check_prefix_sub($s->{check_prefix_sub});
             $mh->add_prefix_sub($s->{add_prefix_sub});
             $mh->remove_prefix_sub($s->{remove_prefix_sub});
         }
     }
 
     # restore config
     if ($config_replaced) {
         $mm->config($orig_c);
         #print "DEBUG: Restored config, config=", $mm->_dump($mm->config), "\n";
     }
 
     #print "DEBUG: backup = ".Data::Dumper->new([$backup])->Indent(0)->Terse(1)->Dump."\n";
     #print "DEBUG: leaving merge_H_H, result = ".$mm->_dump($res)."\n";
     ($key, $res, $backup);
 }
 
 1;
 # ABSTRACT: Base class for Data::ModeMerge mode handler
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::ModeMerge::Mode::Base - Base class for Data::ModeMerge mode handler
 
 =head1 VERSION
 
 This document describes version 0.32 of Data::ModeMerge::Mode::Base (from Perl distribution Data-ModeMerge), released on 2015-02-21.
 
 =head1 SYNOPSIS
 
  use Data::ModeMerge;
 
 =head1 DESCRIPTION
 
 This is the base class for mode type handlers.
 
 =for Pod::Coverage ^(BUILD|merge_.+)$
 
 =head1 ATTRIBUTES
 
 =head2 merger
 
 =head2 prefix
 
 =head2 prefix_re
 
 =head2 check_prefix_sub
 
 =head2 add_prefix_sub
 
 =head2 remove_prefix_sub
 
 =head1 METHODS
 
 =head2 name
 
 Return name of mode. Subclass must override this method.
 
 =head2 precedence_level
 
 Return precedence level, which is a number. The greater the number,
 the higher the precedence. Subclass must override this method.
 
 =head2 default_prefix
 
 Return default prefix. Subclass must override this method.
 
 =head2 default_prefix_re
 
 Return default prefix regex. Subclass must override this method.
 
 =head2 check_prefix($hash_key)
 
 Return true if hash key has prefix for this mode.
 
 =head2 add_prefix($hash_key)
 
 Return hash key with added prefix of this mode.
 
 =head2 remove_prefix($hash_key)
 
 Return hash key with prefix of this mode prefix removed.
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-ModeMerge>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-ModeMerge>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-ModeMerge>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/ModeMerge/Mode/CONCAT.pm ###
 package Data::ModeMerge::Mode::CONCAT;
 
 our $DATE = '2015-02-21'; # DATE
 our $VERSION = '0.32'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 use Mo qw(build default);
 extends 'Data::ModeMerge::Mode::ADD';
 
 sub name { 'CONCAT' }
 
 sub precedence_level { 2 }
 
 sub default_prefix { '.' }
 
 sub default_prefix_re { qr/^\./ }
 
 sub merge_SCALAR_SCALAR {
     my ($self, $key, $l, $r) = @_;
     ($key, ($l // "") . $r);
 }
 
 1;
 # ABSTRACT: Handler for Data::ModeMerge CONCAT merge mode
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::ModeMerge::Mode::CONCAT - Handler for Data::ModeMerge CONCAT merge mode
 
 =head1 VERSION
 
 This document describes version 0.32 of Data::ModeMerge::Mode::CONCAT (from Perl distribution Data-ModeMerge), released on 2015-02-21.
 
 =head1 SYNOPSIS
 
  use Data::ModeMerge;
 
 =head1 DESCRIPTION
 
 This is the class to handle CONCAT merge mode.
 
 =for Pod::Coverage ^merge_.*
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-ModeMerge>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-ModeMerge>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-ModeMerge>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/ModeMerge/Mode/DELETE.pm ###
 package Data::ModeMerge::Mode::DELETE;
 
 our $DATE = '2015-02-21'; # DATE
 our $VERSION = '0.32'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 use Mo qw(build default);
 extends 'Data::ModeMerge::Mode::Base';
 
 sub name { 'DELETE' }
 
 sub precedence_level { 1 }
 
 sub default_prefix { '!' }
 
 sub default_prefix_re { qr/^!/ }
 
 # merge_left_only and merge_right_only are a bit different: they are
 # called with $l only or $r only instead of both, and should return an
 # extra argument $mode, i.e. ($key, $result, $backup, $is_circular,
 # $mode)
 sub merge_left_only {
     my ($self, $key, $l) = @_;
     return;
 }
 
 sub merge_right_only {
     my ($self, $key, $r) = @_;
     return;
 }
 
 sub merge_SCALAR_SCALAR {
     return;
 }
 
 sub merge_SCALAR_ARRAY {
     return;
 }
 
 sub merge_SCALAR_HASH {
     return;
 }
 
 sub merge_ARRAY_SCALAR {
     return;
 }
 
 sub merge_ARRAY_ARRAY {
     my ($self, $key, $l, $r) = @_;
     $self->merger->config->allow_destroy_array or
         $self->merger->push_error("Now allowed to destroy array via DELETE mode");
     return;
 }
 
 sub merge_ARRAY_HASH {
     return;
 }
 
 sub merge_HASH_SCALAR {
     return;
 }
 
 sub merge_HASH_ARRAY {
     return;
 }
 
 sub merge_HASH_HASH {
     my ($self, $key, $l, $r) = @_;
     $self->merger->config->allow_destroy_hash or
         $self->merger->push_error("Now allowed to destroy hash via DELETE mode");
     return;
 }
 
 1;
 # ABSTRACT: Handler for Data::ModeMerge DELETE merge mode
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::ModeMerge::Mode::DELETE - Handler for Data::ModeMerge DELETE merge mode
 
 =head1 VERSION
 
 This document describes version 0.32 of Data::ModeMerge::Mode::DELETE (from Perl distribution Data-ModeMerge), released on 2015-02-21.
 
 =head1 SYNOPSIS
 
  use Data::ModeMerge;
 
 =head1 DESCRIPTION
 
 This is the class to handle DELETE merge mode.
 
 =for Pod::Coverage ^merge_.*
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-ModeMerge>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-ModeMerge>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-ModeMerge>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/ModeMerge/Mode/KEEP.pm ###
 package Data::ModeMerge::Mode::KEEP;
 
 our $DATE = '2015-02-21'; # DATE
 our $VERSION = '0.32'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 use Mo qw(build default);
 extends 'Data::ModeMerge::Mode::Base';
 
 sub name { 'KEEP' }
 
 sub precedence_level { 6 }
 
 sub default_prefix { '^' }
 
 sub default_prefix_re { qr/^\^/ }
 
 sub merge_SCALAR_SCALAR {
     my ($self, $key, $l, $r) = @_;
     ($key, $l);
 }
 
 sub merge_SCALAR_ARRAY {
     my ($self, $key, $l, $r) = @_;
     ($key, $l);
 }
 
 sub merge_SCALAR_HASH {
     my ($self, $key, $l, $r) = @_;
     ($key, $l);
 }
 
 sub merge_ARRAY_SCALAR {
     my ($self, $key, $l, $r) = @_;
     ($key, $l);
 }
 
 sub merge_ARRAY_ARRAY {
     my ($self, $key, $l, $r) = @_;
     $self->SUPER::merge_ARRAY_ARRAY($key, $l, $r, 'KEEP');
 };
 
 sub merge_ARRAY_HASH {
     my ($self, $key, $l, $r) = @_;
     ($key, $l);
 }
 
 sub merge_HASH_SCALAR {
     my ($self, $key, $l, $r) = @_;
     ($key, $l);
 }
 
 sub merge_HASH_ARRAY {
     my ($self, $key, $l, $r) = @_;
     ($key, $l);
 }
 
 sub merge_HASH_HASH {
     my ($self, $key, $l, $r) = @_;
     $self->SUPER::merge_HASH_HASH($key, $l, $r, 'KEEP');
 };
 
 1;
 # ABSTRACT: Handler for Data::ModeMerge KEEP merge mode
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::ModeMerge::Mode::KEEP - Handler for Data::ModeMerge KEEP merge mode
 
 =head1 VERSION
 
 This document describes version 0.32 of Data::ModeMerge::Mode::KEEP (from Perl distribution Data-ModeMerge), released on 2015-02-21.
 
 =head1 SYNOPSIS
 
  use Data::ModeMerge;
 
 =head1 DESCRIPTION
 
 This is the class to handle KEEP merge mode.
 
 =for Pod::Coverage ^merge_.*
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-ModeMerge>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-ModeMerge>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-ModeMerge>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/ModeMerge/Mode/NORMAL.pm ###
 package Data::ModeMerge::Mode::NORMAL;
 
 our $DATE = '2015-02-21'; # DATE
 our $VERSION = '0.32'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 use Mo qw(build default);
 extends 'Data::ModeMerge::Mode::Base';
 
 sub name { 'NORMAL' }
 
 sub precedence_level { 5 }
 
 sub default_prefix { '*' }
 
 sub default_prefix_re { qr/^\*/ }
 
 sub merge_SCALAR_SCALAR {
     my ($self, $key, $l, $r) = @_;
     ($key, $r);
 }
 
 sub merge_SCALAR_ARRAY {
     my ($self, $key, $l, $r) = @_;
     ($key, $r);
 }
 
 sub merge_SCALAR_HASH {
     my ($self, $key, $l, $r) = @_;
     ($key, $r);
 }
 
 sub merge_SCALAR_CODE {
     my ($self, $key, $l, $r) = @_;
     ($key, $r);
 }
 
 sub merge_ARRAY_SCALAR {
     my ($self, $key, $l, $r) = @_;
     ($key, $r);
 }
 
 sub merge_ARRAY_HASH {
     my ($self, $key, $l, $r) = @_;
     ($key, $r);
 }
 
 sub merge_ARRAY_CODE {
     my ($self, $key, $l, $r) = @_;
     ($key, $r);
 }
 
 sub merge_HASH_SCALAR {
     my ($self, $key, $l, $r) = @_;
     ($key, $r);
 }
 
 sub merge_HASH_ARRAY {
     my ($self, $key, $l, $r) = @_;
     ($key, $r);
 }
 
 sub merge_HASH_CODE {
     my ($self, $key, $l, $r) = @_;
     ($key, $r);
 }
 
 sub merge_CODE_SCALAR {
     my ($self, $key, $l, $r) = @_;
     ($key, $r);
 }
 
 sub merge_CODE_ARRAY {
     my ($self, $key, $l, $r) = @_;
     ($key, $r);
 }
 
 sub merge_CODE_HASH {
     my ($self, $key, $l, $r) = @_;
     ($key, $r);
 }
 
 sub merge_CODE_CODE {
     my ($self, $key, $l, $r) = @_;
     ($key, $r);
 }
 
 1;
 # ABSTRACT: Handler for Data::ModeMerge NORMAL merge mode
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::ModeMerge::Mode::NORMAL - Handler for Data::ModeMerge NORMAL merge mode
 
 =head1 VERSION
 
 This document describes version 0.32 of Data::ModeMerge::Mode::NORMAL (from Perl distribution Data-ModeMerge), released on 2015-02-21.
 
 =head1 SYNOPSIS
 
  use Data::ModeMerge;
 
 =head1 DESCRIPTION
 
 This is the class to handle NORMAL merge mode.
 
 =for Pod::Coverage ^merge_.*
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-ModeMerge>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-ModeMerge>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-ModeMerge>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/ModeMerge/Mode/SUBTRACT.pm ###
 package Data::ModeMerge::Mode::SUBTRACT;
 
 our $DATE = '2015-02-21'; # DATE
 our $VERSION = '0.32'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 use Mo qw(build default);
 extends 'Data::ModeMerge::Mode::NORMAL';
 
 sub name { 'SUBTRACT' }
 
 sub precedence_level { 4 }
 
 sub default_prefix { '-' }
 
 sub default_prefix_re { qr/^-/ }
 
 sub merge_SCALAR_SCALAR {
     my ($self, $key, $l, $r) = @_;
     ($key, $l - $r);
 }
 
 sub merge_SCALAR_ARRAY {
     my ($self, $key, $l, $r) = @_;
     $self->merger->push_error("Can't subtract scalar and array");
     return;
 }
 
 sub merge_SCALAR_HASH {
     my ($self, $key, $l, $r) = @_;
     $self->merger->push_error("Can't subtract scalar and hash");
     return;
 }
 
 sub merge_ARRAY_SCALAR {
     my ($self, $key, $l, $r) = @_;
     $self->merger->push_error("Can't subtract array and scalar");
     return;
 }
 
 sub merge_ARRAY_ARRAY {
     my ($self, $key, $l, $r) = @_;
     my @res;
     my $mm = $self->merger;
     for (@$l) {
         push @res, $_ unless $mm->_in($_, $r);
     }
     ($key, \@res);
 }
 
 sub merge_ARRAY_HASH {
     my ($self, $key, $l, $r) = @_;
     $self->merger->push_error("Can't subtract array and hash");
     return;
 }
 
 sub merge_HASH_SCALAR {
     my ($self, $key, $l, $r) = @_;
     $self->merger->push_error("Can't subtract hash and scalar");
     return;
 }
 
 sub merge_HASH_ARRAY {
     my ($self, $key, $l, $r) = @_;
     $self->merger->push_error("Can't subtract hash and array");
     return;
 }
 
 sub merge_HASH_HASH {
     my ($self, $key, $l, $r) = @_;
     my $mm = $self->merger;
 
     my %res;
     my $r2 = {};
     for (keys %$r) {
         my $k = $mm->check_prefix($_) ? $_ : $mm->add_prefix($_, 'DELETE');
         if ($k ne $_ && exists($r->{$k})) {
             $mm->push_error("Conflict when adding DELETE prefix on right-side hash key $_ ".
                             "for SUBTRACT merge: key $k already exists");
             return;
         }
         $r2->{$k} = $r->{$_};
     }
     $mm->_merge($key, $l, $r2, 'NORMAL');
 }
 
 1;
 # ABSTRACT: Handler for Data::ModeMerge SUBTRACT merge mode
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::ModeMerge::Mode::SUBTRACT - Handler for Data::ModeMerge SUBTRACT merge mode
 
 =head1 VERSION
 
 This document describes version 0.32 of Data::ModeMerge::Mode::SUBTRACT (from Perl distribution Data-ModeMerge), released on 2015-02-21.
 
 =head1 SYNOPSIS
 
  use Data::ModeMerge;
 
 =head1 DESCRIPTION
 
 This is the class to handle SUBTRACT merge mode.
 
 =for Pod::Coverage ^merge_.*
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-ModeMerge>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-ModeMerge>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-ModeMerge>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah.pm ###
 package Data::Sah;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use 5.010001;
 use strict;
 use warnings;
 #use Log::Any qw($log);
 
 use Mo qw(build default);
 
 our $Log_Validator_Code = $ENV{LOG_SAH_VALIDATOR_CODE} // 0;
 
 use Data::Sah::Normalize qw(
                        $type_re
                        $clause_name_re
                        $clause_re
                        $attr_re
                        $funcset_re
                        $compiler_re
                        );
 
 require Exporter;
 our @ISA       = qw(Exporter);
 our @EXPORT_OK = qw(normalize_schema gen_validator);
 
 # store Data::Sah::Compiler::* instances
 has compilers    => (is => 'rw', default => sub { {} });
 
 has _merger      => (
     is      => 'rw',
     lazy    => 1,
     default => sub {
         require Data::ModeMerge;
         my $mm = Data::ModeMerge->new(config => {
             recurse_array => 1,
         });
         $mm->modes->{NORMAL}  ->prefix   ('merge.normal.');
         $mm->modes->{NORMAL}  ->prefix_re(qr/\Amerge\.normal\./);
         $mm->modes->{ADD}     ->prefix   ('merge.add.');
         $mm->modes->{ADD}     ->prefix_re(qr/\Amerge\.add\./);
         $mm->modes->{CONCAT}  ->prefix   ('merge.concat.');
         $mm->modes->{CONCAT}  ->prefix_re(qr/\Amerge\.concat\./);
         $mm->modes->{SUBTRACT}->prefix   ('merge.subtract.');
         $mm->modes->{SUBTRACT}->prefix_re(qr/\Amerge\.subtract\./);
         $mm->modes->{DELETE}  ->prefix   ('merge.delete.');
         $mm->modes->{DELETE}  ->prefix_re(qr/\Amerge\.delete\./);
         $mm->modes->{KEEP}    ->prefix   ('merge.keep.');
         $mm->modes->{KEEP}    ->prefix_re(qr/\Amerge\.keep\./);
         $mm;
     },
 );
 
 has _var_enumer  => (
     is      => 'rw',
     lazy    => 1,
     default => sub {
         require Language::Expr::Interpreter::VarEnumer;
         Language::Expr::Interpreter::VarEnumer->new;
     },
 );
 
 sub normalize_clset {
     require Scalar::Util;
 
     my $self;
     if (Scalar::Util::blessed($_[0])) {
         $self = shift;
     } else {
         $self = __PACKAGE__->new;
     }
 
     Data::Sah::Normalize::normalize_clset($_[0]);
 }
 
 sub normalize_schema {
     require Scalar::Util;
 
     my $self;
     if (Scalar::Util::blessed($_[0])) {
         $self = shift;
     } else {
         $self = __PACKAGE__->new;
     }
     my ($s) = @_;
 
     Data::Sah::Normalize::normalize_schema($_[0]);
 }
 
 sub gen_validator {
     require Scalar::Util;
 
     my $self;
     if (Scalar::Util::blessed($_[0])) {
         $self = shift;
     } else {
         $self = __PACKAGE__->new;
     }
     my ($schema, $opts) = @_;
     my %args = (schema => $schema, %{$opts // {}});
     my $opt_source = delete $args{source};
 
     $args{log_result} = 1 if $Log_Validator_Code;
 
     my $pl = $self->get_compiler("perl");
     my $code = $pl->expr_validator_sub(%args);
     return $code if $opt_source;
 
     my $res = eval $code;
     die "Can't compile validator: $@" if $@;
     $res;
 }
 
 sub _merge_clause_sets {
     my ($self, @clause_sets) = @_;
     my @merged;
 
     my $mm = $self->_merger;
 
     my @c;
     for (@clause_sets) {
         push @c, {cs=>$_, has_prefix=>$mm->check_prefix_on_hash($_)};
     }
     for (reverse @c) {
         if ($_->{has_prefix}) { $_->{last_with_prefix} = 1; last }
     }
 
     my $i = -1;
     for my $c (@c) {
         $i++;
         if (!$i || !$c->{has_prefix} && !$c[$i-1]{has_prefix}) {
             push @merged, $c->{cs};
             next;
         }
         $mm->config->readd_prefix(
             ($c->{last_with_prefix} || $c[$i-1]{last_with_prefix}) ? 0 : 1);
         my $mres = $mm->merge($merged[-1], $c->{cs});
         die "Can't merge clause sets: $mres->{error}" unless $mres->{success};
         $merged[-1] = $mres->{result};
     }
     \@merged;
 }
 
 sub get_compiler {
     my ($self, $name) = @_;
     return $self->compilers->{$name} if $self->compilers->{$name};
 
     die "Invalid compiler name `$name`" unless $name =~ $compiler_re;
     my $module = "Data::Sah::Compiler::$name";
     if (!eval "require $module; 1") {
         die "Can't load compiler module $module".($@ ? ": $@" : "");
     }
 
     my $obj = $module->new(main => $self);
     $self->compilers->{$name} = $obj;
 
     return $obj;
 }
 
 sub normalize_var {
     my ($self, $var, $curpath) = @_;
     die "Not yet implemented";
 }
 
 1;
 # ABSTRACT: Fast and featureful data structure validation
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah - Fast and featureful data structure validation
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =head1 SYNOPSIS
 
 Non-OO interface:
 
  use Data::Sah qw(
      normalize_schema
      gen_validator
  );
 
  # generate a validator for schema
  my $v = gen_validator(["int*", min=>1, max=>10]);
 
  # validate your data using the generated validator
  say "valid" if $v->(5);     # valid
  say "valid" if $v->(11);    # invalid
  say "valid" if $v->(undef); # invalid
  say "valid" if $v->("x");   # invalid
 
  # generate validator which reports error message string, in Indonesian
  my $v = gen_validator(["int*", min=>1, max=>10],
                        {return_type=>'str', lang=>'id_ID'});
  say $v->(5);  # ''
  say $v->(12); # 'Data tidak boleh lebih besar dari 10'
                # (in English: 'Data must not be larger than 10')
 
  # normalize a schema
  my $nschema = normalize_schema("int*"); # => ["int", {req=>1}, {}]
  normalize_schema(["int*", min=>0]); # => ["int", {min=>0, req=>1}, {}]
 
 OO interface (more advanced usage):
 
  use Data::Sah;
  my $sah = Data::Sah->new;
 
  # get perl compiler
  my $pl = $sah->get_compiler("perl");
 
  # compile schema into Perl code
  my $cd = $pl->compile(schema => ["int*", min=>0]);
  say $cd->{result};
 
 will print something like:
 
  # req #0
  (defined($data))
  &&
  # check type 'int'
  (Scalar::Util::Numeric::isint($data))
  &&
  (# clause: min
  ($data >= 0))
 
 To see the full validator code (with C<sub {}> and all), you can do something
 like:
 
  % LOG=1 LOG_SAH_VALIDATOR_CODE=1 TRACE=1 perl -MLog::Any::App -MData::Sah=gen_validator -E'gen_validator(["int*", min=>0])'
 
 which will print log message like:
 
  normalized schema=['int',{min => 0,req => 1},{}]
  validator code:
     1|do {
     2|    require Scalar::Util::Numeric;
     3|    sub {
     4|        my ($data) = @_;
     5|        my $_sahv_res =
      |
     7|            # req #0
     8|            (defined($data))
      |
    10|            &&
      |
    12|            # check type 'int'
    13|            (Scalar::Util::Numeric::isint($data))
      |
    15|            &&
      |
    17|            (# clause: min
    18|            ($data >= 0));
      |
    20|        return($_sahv_res);
    21|    }}
 
 =head1 DESCRIPTION
 
 This module, L<Data::Sah>, implements compilers for producing Perl and
 JavaScript validators, as well as translatable human description text from
 L<Sah> schemas. Compiler approach is used instead of interpreter for faster
 speed.
 
 The generated validator code can run without this module.
 
 =head1 STATUS
 
 Some features are not implemented yet:
 
 =over
 
 =item * def/subschema
 
 =item * expression
 
 =item * buf type
 
 =item * date/datetime type
 
 =item * obj: meths, attrs properties
 
 =item * .prio, .err_msg, .ok_err_msg attributes
 
 =item * .result_var attribute
 
 =item * BaseType: if, prefilters, postfilters, check, prop, check_prop clauses
 
 =item * HasElems: each_elem, each_index, check_each_elem, check_each_index, exists clauses
 
 =item * HasElems: len, elems, indices properties
 
 =item * hash: check_each_key, check_each_value, allowed_keys_re, forbidden_keys_re clauses
 
 =item * array: uniq clauses
 
 =item * human compiler: markdown output
 
 =item * markdown output
 
 =back
 
 =head1 EXPORTS
 
 None exported by default.
 
 =head2 normalize_schema($schema) => ARRAY
 
 Normalize C<$schema>.
 
 Can also be used as a method.
 
 =head2 gen_validator($schema, \%opts) => CODE (or STR)
 
 Generate validator code for C<$schema>. Can also be used as a method. Known
 options (unknown options will be passed to Perl schema compiler):
 
 =over
 
 =item * accept_ref => BOOL (default: 0)
 
 Normally the generated validator accepts data, as in:
 
  $res = $vdr->($data);
  $res = $vdr->(42);
 
 If this option is set to true, validator accepts reference to data instead, as
 in:
 
  $res = $vdr->(\$data);
 
 This allows $data to be modified by the validator (mainly, to set default value
 specified in schema). For example:
 
  my $data;
  my $vdr = gen_validator([int => {min=>0, max=>10, default=>5}],
                          {accept_ref=>1});
  my $res = $vdr->(\$data);
  say $res;  # => 1 (success)
  say $data; # => 5
 
 =item * source => BOOL (default: 0)
 
 If set to 1, return source code string instead of compiled subroutine. Usually
 only needed for debugging (but see also C<$Log_Validator_Code> and
 C<LOG_SAH_VALIDATOR_CODE> if you want to log validator source code).
 
 =back
 
 =head1 ATTRIBUTES
 
 =head2 compilers => HASH
 
 A mapping of compiler name and compiler (Data::Sah::Compiler::*) objects.
 
 =head1 VARIABLES
 
 =head2 C<$Log_Validator_Code> (bool, default: 0)
 
 =head1 ENVIRONMENT
 
 L<LOG_SAH_VALIDATOR_CODE>
 
 =head1 METHODS
 
 =head2 new() => OBJ
 
 Create a new Data::Sah instance.
 
 =head2 $sah->get_compiler($name) => OBJ
 
 Get compiler object. C<Data::Sah::Compiler::$name> will be loaded first and
 instantiated if not already so. After that, the compiler object is cached.
 
 Example:
 
  my $plc = $sah->get_compiler("perl"); # loads Data::Sah::Compiler::perl
 
 =head2 $sah->normalize_schema($schema) => HASH
 
 Normalize a schema, e.g. change C<int*> into C<< [int => {req=>1}] >>, as well
 as do some sanity checks on it. Returns the normalized schema if succeeds, or
 dies on error.
 
 Can also be used as a function.
 
 Note: this functionality is implemented in L<Data::Sah::Normalize> (distributed
 separately in Data-Sah-Normalize). Use that module instead if you just need
 normalizing schemas, to reduce dependencies.
 
 =head2 $sah->normalize_clset($clset[, \%opts]) => HASH
 
 Normalize a clause set, e.g. change C<< {"!match"=>"abc"} >> into C<<
 {"match"=>"abc", "match.op"=>"not"} >>. Produce a shallow copy of the input
 clause set hash.
 
 Can also be used as a function.
 
 =head2 $sah->normalize_var($var) => STR
 
 Normalize a variable name in expression into its fully qualified/absolute form.
 
 Not yet implemented (pending specification).
 
 For example:
 
  [int => {min => 10, 'max=' => '2*$min'}]
 
 $min in the above expression will be normalized as C<schema:clauses.min>.
 
 =head2 $sah->gen_validator($schema, \%opts) => CODE
 
 Use the Perl compiler to generate validator code. Can also be used as a
 function. See the documentation as a function for list of known options.
 
 =head1 MODULE ORGANIZATION
 
 B<Data::Sah::Type::*> roles specify Sah types, e.g. C<Data::Sah::Type::bool>
 specifies the bool type. It can also be used to name distributions that
 introduce new types, e.g. C<Data-Sah-Type-complex> which introduces complex
 number type.
 
 B<Data::Sah::FuncSet::*> roles specify bundles of functions, e.g.
 <Data::Sah::FuncSet::Core> specifies the core/standard functions.
 
 B<Data::Sah::Compiler::$LANG::> namespace is for compilers. Each compiler might
 further contain <::TH::*> and <::FSH::*> subnamespaces to implement appropriate
 functionalities, e.g. C<Data::Sah::Compiler::perl::TH::bool> is the bool type
 handler for the Perl compiler and C<Data::Sah::Compiler::perl::FSH::Core> is the
 Core funcset handler for Perl compiler.
 
 B<Data::Sah::TypeX::$TYPENAME::$CLAUSENAME> namespace can be used to name
 distributions that extend an existing Sah type by introducing a new clause for
 it. See L<Data::Sah::Manual::Extending> for an example.
 
 B<Data::Sah::Lang::$LANGCODE> namespaces are for modules that contain
 translations. They are further organized according to the organization of other
 Data::Sah modules, e.g. L<Data::Sah::Lang::en_US::Type::int> or
 C<Data::Sah::Lang::en_US::TypeX::str::is_palindrome>.
 
 B<Sah::Schema::> namespace is reserved for modules that contain bundles of
 schemas. For example, C<Sah::Schema::CPANMeta> contains the schema to validate
 CPAN META.yml. L<Sah::Schema::Int> contains various schemas for integers such as
 C<pos_int>, C<int8>, C<uint32>. L<Sah::Schema::Sah> contains the schema for Sah
 schema itself.
 
 =head1 FAQ
 
 See also L<Sah::FAQ>.
 
 =head2 Relation to Data::Schema?
 
 L<Data::Schema> is the old incarnation of this module, deprecated since 2011.
 
 There are enough incompatibilities between the two (some different syntaxes,
 renamed clauses). Also, some terminology have been changed, e.g. "attribute"
 become "clauses", "suffix" becomes "attributes". This warrants a new name.
 
 Compared to Data::Schema, Sah always compiles schemas and there is much greater
 flexibility in code generation (can customize data term, code can return boolean
 or error message string or detailed hash, can generate code to validate multiple
 schemas, etc). There is no longer hash form, schema is either a string or an
 array. Some clauses have been renamed (mostly, commonly used clauses are
 abbreviated, Huffman encoding thingy), some removed (usually because they are
 replaced by a more general solution), and new ones have been added.
 
 If you use Data::Schema, I recommend you migrate to Data::Sah as I will not be
 developing Data::Schema anymore. Sorry, there's currently no tool to convert
 your Data::Schema schemas to Sah, but it should be relatively straightforward.
 
 =head2 Comparison to {JSON::Schema, Data::Rx, Data::FormValidator, ...}?
 
 See L<Sah::FAQ>.
 
 =head2 Why is it so slow?
 
 You probably do not reuse the compiled schema, e.g. you continually destroy and
 recreate Data::Sah object, or repeatedly recompile the same schema. To gain the
 benefit of compilation, you need to keep the compiled result and use the
 generated Perl code repeatedly.
 
 =head2 Can I generate another schema dynamically from within the schema?
 
 For example:
 
  // if first element is an integer, require the array to contain only integers,
  // otherwise require the array to contain only strings.
  ["array", {"min_len": 1, "of=": "[is_int($_[0]) ? 'int':'str']"}]
 
 Currently no, Data::Sah does not support expression on clauses that contain
 other schemas. In other words, dynamically generated schemas are not supported.
 To support this, if the generated code needs to run independent of Data::Sah, it
 needs to contain the compiler code itself (or an interpreter) to compile or
 evaluate the generated schema.
 
 However, an C<eval_schema()> Sah function which uses Data::Sah can be trivially
 declared and target the Perl compiler.
 
 =head2 How to display the validator code being generated?
 
 Use the C<< source => 1 >> option in C<gen_validator()>.
 
 If you use the OO interface, e.g.:
 
  # generate perl code
  my $cd = $plc->compile(schema=>..., ...);
 
 then the generated code is in C<< $cd->{result} >> and you can just print it.
 
 If you generate validator using C<gen_validator()>, you can set environment
 LOG_SAH_VALIDATOR_CODE or package variable C<$Log_Validator_Code> to true and
 the generated code will be logged at trace level using L<Log::Any>. The log can
 be displayed using, e.g., L<Log::Any::App>:
 
  % LOG_SAH_VALIDATOR_CODE=1 TRACE=1 \
    perl -MLog::Any::App -MData::Sah=gen_validator \
    -e '$sub = gen_validator([int => min=>1, max=>10])'
 
 Sample output:
 
  normalized schema=['int',{max => 10,min => 1},{}]
  schema already normalized, skipped normalization
  validator code:
     1|do {
     2|    require Scalar::Util::Numeric;
     3|    sub {
     4|        my ($data) = @_;
     5|        my $_sahv_res =
      |
     7|            # skip if undef
     8|            (!defined($data) ? 1 :
      |
    10|            (# check type 'int'
    11|            (Scalar::Util::Numeric::isint($data))
      |
    13|            &&
      |
    15|            (# clause: min
    16|            ($data >= 1))
      |
    18|            &&
      |
    20|            (# clause: max
    21|            ($data <= 10))));
      |
    23|        return($_sahv_res);
    24|    }}
 
 Lastly, you can also use L<validate-with-sah> CLI utility from the
 L<App::SahUtils> distribution (use the C<--show-code> option).
 
 =head2 How to show the validation error message? The validator only returns true/false!
 
 Pass the C<< return_type=>"str" >> to get an error message string on error, or
 C<< return_type=>"full" >> to get a hash of detailed error messages. Note also
 that the error messages are translateable (e.g. use C<LANG> or C<< lang=>... >>
 option. For example:
 
  my $v = gen_validator([int => between => [1,10]], {return_type=>"str"});
  say "$_: ", $v->($_) for 1, "x", 12;
 
 will output:
 
  1:
  "x": Input is not of type integer
  12: Must be between 1 and 10
 
 =head2 What does the C<@...> prefix that is sometimes shown on the error message mean?
 
 It shows the path to data item that fails the validation, e.g.:
 
  my $v = gen_validator([array => of => [int=>min=>5], {return_type=>"str"});
  say $v->([10, 5, "x"]);
 
 prints:
 
  @2: Input is not of type integer
 
 which means that the third element (subscript 2) of the array fails the
 validation. Another example:
 
  my $v = gen_validator([array => of => [hash=>keys=>{a=>"int"}]]);
  say $v->([{}, {a=>1.1}]);
 
 prints:
 
  @1/a: Input is not of type integer
 
 =head2 How to show the process of validation by the compiled code?
 
 If you are generating Perl code from schema, you can pass C<< debug=>1 >> option
 so the code contains logging (L<Log::Any>-based) and other debugging
 information, which you can display. For example:
 
  % TRACE=1 perl -MLog::Any::App -MData::Sah=gen_validator -E'
    $v = gen_validator([array => of => [hash => {req_keys=>["a"]}]],
                       {return_type=>"str", debug=>1});
    say "Validation result: ", $v->([{a=>1}, "x"]);'
 
 will output:
 
  ...
  [spath=[]]skip if undef ...
  [spath=[]]check type 'array' ...
  [spath=['of']]clause: {"of":["hash",{"req_keys":["a"]}]} ...
  [spath=['of']]skip if undef ...
  [spath=['of']]check type 'hash' ...
  [spath=['of','req_keys']]clause: {"req_keys":["a"]} ...
  [spath=['of']]skip if undef ...
  [spath=['of']]check type 'hash' ...
  Validation result: [spath=of]@1: Input is not of type hash
 
 =head2 What else can I do with the compiled code?
 
 Data::Sah offers some options in code generation. Beside compiling the validator
 code into a subroutine, there are also some other options. Examples:
 
 =over
 
 =item * L<Dist::Zilla::Plugin::Rinci::Validate>
 
 This plugin inserts the generated code (without the C<sub { ... }> wrapper) to
 validate the content of C<%args> right before C<# VALIDATE_ARG> or C<#
 VALIDATE_ARGS> like below:
 
  $SPEC{foo} = {
      args => {
          arg1 => { schema => ..., req=>1 },
          arg2 => { schema => ... },
      },
      ...
  };
  sub foo {
      my %args = @_; # VALIDATE_ARGS
  }
 
 The schemas will be retrieved from the Rinci metadata (C<$SPEC{foo}> above).
 This means, subroutines in your built distribution will do argument validation.
 
 =item * L<Perinci::Sub::Wrapper>
 
 This module is part of the L<Perinci> family. What the module does is basically
 wrap your subroutine with a wrapper code that can include validation code (among
 others). This is a convenient way to add argument validation to an existing
 subroutine/code.
 
 =back
 
 =head1 SEE ALSO
 
 =head3 Other compiled validators
 
 =head3 Other interpreted validators
 
 L<Params::Validate> is very fast, although minimal. L<Data::Rx>, L<Kwalify>,
 L<Data::Verifier>, L<Data::Validator>, L<JSON::Schema>, L<Validation::Class>.
 
 For Moo/Mouse/Moose stuffs: L<Moose> type system, L<MooseX::Params::Validate>,
 L<Type::Tiny>, among others.
 
 Form-oriented: L<Data::FormValidator>, L<FormValidator::Lite>, among others.
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Compiler.pm ###
 package Data::Sah::Compiler;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 
 #use Carp;
 use Mo qw(default);
 use Role::Tiny::With;
 use Log::Any::IfLOG qw($log);
 
 with 'Data::Sah::Compiler::TextResultRole';
 
 use Scalar::Util qw(blessed);
 
 has main => (is => 'rw');
 
 # instance to Language::Expr instance
 has expr_compiler => (
     is => 'rw',
     lazy => 1,
     default => sub {
         require Language::Expr;
         Language::Expr->new;
     },
 );
 
 sub name {
     die "BUG: Please override name()";
 }
 
 # literal representation in target language
 sub literal {
     die "BUG: Please override literal()";
 }
 
 # compile expression to target language
 sub expr {
     die "BUG: Please override expr()";
 }
 
 sub _die {
     my ($self, $cd, $msg) = @_;
     die join(
         "",
         "Sah ". $self->name . " compiler: ",
         "at schema:/", join("/", @{$cd->{spath} // []}), ": ",
         # XXX show (snippet of) current schema
         $msg,
     );
 }
 
 # form dependency list from which clauses are mentioned in expressions NEED TO
 # BE UPDATED: NEED TO CHECK EXPR IN ALL ATTRS FOR THE WHOLE SCHEMA/SUBSCHEMAS
 # (NOT IN THE CURRENT CLSET ONLY), THERE IS NO LONGER A ctbl, THE WAY EXPR IS
 # STORED IS NOW DIFFERENT. PLAN: NORMALIZE ALL SUBSCHEMAS, GATHER ALL EXPR VARS
 # AND STORE IN $cd->{all_expr_vars} (SKIP DOING THIS IS
 # $cd->{outer_cd}{all_expr_vars} is already defined).
 sub _form_deps {
     require Algorithm::Dependency::Ordered;
     require Algorithm::Dependency::Source::HoA;
     require Language::Expr::Interpreter::VarEnumer;
 
     my ($self, $cd, $ctbl) = @_;
     my $main = $self->main;
 
     my %depends;
     for my $crec (values %$ctbl) {
         my $cn = $crec->{name};
         my $expr = defined($crec->{expr}) ? $crec->{value} :
             $crec->{attrs}{expr};
         if (defined $expr) {
             my $vars = $main->_var_enumer->eval($expr);
             for (@$vars) {
                 /^\w+$/ or $self->_die($cd,
                     "Invalid variable syntax '$_', ".
                         "currently only the form \$abc is supported");
                 $ctbl->{$_} or $self->_die($cd,
                     "Unhandled clause specified in variable '$_'");
             }
             $depends{$cn} = $vars;
             for (@$vars) {
                 push @{ $ctbl->{$_}{depended_by} }, $cn;
             }
         } else {
             $depends{$cn} = [];
         }
     }
     #$log->tracef("deps: %s", \%depends);
     my $ds = Algorithm::Dependency::Source::HoA->new(\%depends);
     my $ad = Algorithm::Dependency::Ordered->new(source => $ds)
         or die "Failed to set up dependency algorithm";
     my $sched = $ad->schedule_all
         or die "Can't resolve dependencies, please check your expressions";
     #$log->tracef("sched: %s", $sched);
     my %rsched = map
         {@{ $depends{$sched->[$_]} } ? ($sched->[$_] => $_) : ()}
             0..@$sched-1;
     #$log->tracef("deps: %s", \%rsched);
     \%rsched;
 }
 
 # since a schema can be based on another schema, we need to resolve to get the
 # "base" type's handler (and collect clause sets in the process). for example:
 # if pos_int is [int => {min=>0}], and pos_even is [pos_int, {div_by=>2}] then
 # resolving pos_even will result in: ["int", [{min=>0}, {div_by=>2}], []]. The
 # first element is the base type, the second is merged clause sets, the third is
 # merged extras.
 sub _resolve_base_type {
     require Scalar::Util;
 
     my ($self, %args) = @_;
     my $ns   = $args{schema};
     my $t    = $ns->[0];
     my $cd   = $args{cd};
     my $th   = $self->get_th(name=>$t, cd=>$cd);
     my $seen = $args{seen} // {};
     my $res  = $args{res} // [$t, [], []];
 
     $self->_die($cd, "Recursive dependency on type '$t'") if $seen->{$t}++;
 
     $res->[0] = $t;
     unshift @{$res->[1]}, $ns->[1] if keys(%{$ns->[1]});
     unshift @{$res->[2]}, $ns->[2] if $ns->[2];
     if (Scalar::Util::blessed $th) {
         $res->[1] = $self->main->_merge_clause_sets(@{$res->[1]}) if @{$res->[1]} > 1;
         $res->[2] = $self->main->_merge_clause_sets(@{$res->[2]}) if @{$res->[2]} > 1;
     } else {
         $self->_resolve_base_type(schema=>$th, cd=>$cd, seen=>$seen, res=>$res);
     }
     $res;
 }
 
 # generate a list of clauses in clsets, in order of evaluation. clauses are
 # sorted based on expression dependencies and priority. result is array of
 # [CLSET_NUM, CLAUSE, CLAUSEMETA] triplets, e.g. ([0, 'default', {...}], [1,
 # 'default', {...}], [0, 'min', {...}], [0, 'max', {...}]).
 sub _get_clauses_from_clsets {
     my ($self, $cd, $clsets) = @_;
     my $tn = $cd->{type};
     my $th = $cd->{th};
 
     my $deps;
     ## temporarily disabled, expr needs to be sorted globally
     #if ($self->_clset_has_expr($clset)) {
     #    $deps = $self->_form_deps($ctbl);
     #} else {
     #    $deps = {};
     #}
     #$deps = {};
 
     my $sorter = sub {
         my ($ia, $ca, $metaa) = @$a;
         my ($ib, $cb, $metab) = @$b;
         my $res;
 
         # dependency
         #$res = ($deps->{"$ca.$ia"} // -1) <=> ($deps->{"$cb.$ib"} // -1);
         #return $res if $res;
 
         {
             $res = $metaa->{prio} <=> $metab->{prio};
             #$log->errorf("TMP:   sort1");
             last if $res;
 
             # prio from schema
             my $sprioa = $clsets->[$ia]{"$ca.prio"} // 50;
             my $spriob = $clsets->[$ib]{"$cb.prio"} // 50;
             $res = $sprioa <=> $spriob;
             #$log->errorf("TMP:   sort2");
             last if $res;
 
             # alphabetical order of clause name
             $res = $ca cmp $cb;
             #$log->errorf("TMP:   sort3");
             last if $res;
 
             # clause set order
             $res = $ia <=> $ib;
             #$log->errorf("TMP:   sort4");
             last if $res;
 
             $res = 0;
         }
 
         #$log->errorf("TMP:   sort [%s,%s] vs [%s,%s] = %s", $ia, $ca, $ib, $cb, $res);
         $res;
     };
 
     my @clauses;
     for my $i (0..@$clsets-1) {
         for my $k (grep {!/\A_/ && !/\./} keys %{$clsets->[$i]}) {
             my $meta;
             eval {
                 $meta = "Data::Sah::Type::$tn"->${\("clausemeta_$k")};
             };
             if ($@) {
                 for ($cd->{args}{on_unhandled_clause}) {
                     my $msg = "Unhandled clause for type $tn: $k ($@)";
                     next if $_ eq 'ignore';
                     next if $_ eq 'warn'; # don't produce multiple warnings
                     $self->_die($cd, $msg);
                 }
             }
             $meta //= {prio=>50};
             push @clauses, [$i, $k, $meta];
         }
     }
 
     my $res = [sort $sorter @clauses];
     #$log->errorf("TMP: sorted clauses: %s", $res);
     $res;
 }
 
 sub get_th {
     my ($self, %args) = @_;
     my $cd    = $args{cd};
     my $name  = $args{name};
 
     my $th_map = $cd->{th_map};
     return $th_map->{$name} if $th_map->{$name};
 
     if ($args{load} // 1) {
         no warnings;
         $self->_die($cd, "Invalid syntax for type name '$name', please use ".
                         "letters/numbers/underscores only")
             unless $name =~ $Data::Sah::type_re;
         my $main = $self->main;
         my $module = ref($self) . "::TH::$name";
         if (!eval "require $module; 1") {
             $self->_die($cd, "Can't load type handler $module".
                             ($@ ? ": $@" : ""));
         }
 
         my $obj = $module->new(compiler=>$self);
         $th_map->{$name} = $obj;
     }
     use experimental 'smartmatch';
 
     return $th_map->{$name};
 }
 
 sub get_fsh {
     my ($self, %args) = @_;
     my $cd    = $args{cd};
     my $name  = $args{name};
 
     my $fsh_table = $cd->{fsh_table};
     return $fsh_table->{$name} if $fsh_table->{$name};
 
     if ($args{load} // 1) {
         no warnings;
         $self->_die($cd, "Invalid syntax for func set name '$name', ".
                         "please use letters/numbers/underscores")
             unless $name =~ $Data::Sah::funcset_re;
         my $module = ref($self) . "::FSH::$name";
         if (!eval "require $module; 1") {
             $self->_die($cd, "Can't load func set handler $module".
                             ($@ ? ": $@" : ""));
         }
 
         my $obj = $module->new();
         $fsh_table->{$name} = $obj;
     }
     use experimental 'smartmatch';
 
     return $fsh_table->{$name};
 }
 
 sub init_cd {
     require Time::HiRes;
 
     my ($self, %args) = @_;
 
     my $cd = {};
     $cd->{args} = \%args;
 
     if (my $ocd = $args{outer_cd}) {
         # for checking later, because outer_cd might be autovivified to hash
         # later
         $cd->{_inner}       = 1;
 
         $cd->{outer_cd}     = $ocd;
         $cd->{indent_level} = $ocd->{indent_level};
         $cd->{th_map}       = { %{ $ocd->{th_map}  } };
         $cd->{fsh_map}      = { %{ $ocd->{fsh_map} } };
         $cd->{default_lang} = $ocd->{default_lang};
         $cd->{spath}        = [@{ $ocd->{spath} }];
     } else {
         $cd->{indent_level} = $cd->{args}{indent_level} // 0;
         $cd->{th_map}       = {};
         $cd->{fsh_map}      = {};
         # we use || here because in some env, LANG/LANGUAGE is set to ''
         $cd->{default_lang} = $ENV{LANG} || "en_US";
         $cd->{default_lang} =~ s/\..+//; # en_US.UTF-8 -> en_US
         $cd->{spath}        = [];
     }
     $cd->{_id} = Time::HiRes::gettimeofday(); # compilation id
     $cd->{ccls} = [];
 
     $cd;
 }
 
 sub check_compile_args {
     my ($self, $args) = @_;
 
     return if $args->{_args_checked}++;
 
     $args->{data_name} //= 'data';
     $args->{data_name} =~ /\A[A-Za-z_]\w*\z/ or $self->_die(
         {}, "Invalid syntax in data_name '$args->{data_name}', ".
             "please use letters/nums only");
     $args->{allow_expr} //= 1;
     $args->{on_unhandled_attr}   //= 'die';
     $args->{on_unhandled_clause} //= 'die';
     $args->{skip_clause}         //= [];
     $args->{mark_missing_translation} //= 1;
     for ($args->{lang}) {
         $_ //= $ENV{LANG} || $ENV{LANGUAGE} || "en_US";
         s/\W.*//; # LANG=en_US.UTF-8, LANGUAGE=en_US:en
     }
     # locale, no default
 }
 
 sub _process_clause {
     use experimental 'smartmatch';
 
     my ($self, $cd, $clset_num, $clause) = @_;
 
     my $th = $cd->{th};
     my $tn = $cd->{type};
     my $clsets = $cd->{clsets};
 
     my $clset = $clsets->[$clset_num];
     local $cd->{spath}       = [@{$cd->{spath}}, $clause];
     local $cd->{clset}       = $clset;
     local $cd->{clset_num}   = $clset_num;
     local $cd->{uclset}      = $cd->{uclsets}[$clset_num];
     local $cd->{clset_dlang} = $cd->{_clset_dlangs}[$clset_num];
     #$log->tracef("Processing clause %s", $clause);
 
     delete $cd->{uclset}{$clause};
     delete $cd->{uclset}{"$clause.prio"};
 
     if ($clause ~~ @{ $cd->{args}{skip_clause} }) {
         delete $cd->{uclset}{$_}
             for grep /^\Q$clause\E(\.|\z)/, keys(%{$cd->{uclset}});
         return;
     }
 
     my $meth  = "clause_$clause";
     my $mmeth = "clausemeta_$clause";
     unless ($th->can($meth)) {
         for ($cd->{args}{on_unhandled_clause}) {
             next if $_ eq 'ignore';
             do { warn "Can't handle clause $clause"; next }
                 if $_ eq 'warn';
             $self->_die($cd, "Can't handle clause $clause");
         }
     }
 
     # put information about the clause to $cd
 
     my $meta;
     if ($th->can($mmeth)) {
         $meta = $th->$mmeth;
     } else {
         $meta = {};
     }
     local $cd->{cl_meta} = $meta;
     $self->_die($cd, "Clause $clause doesn't allow expression")
         if $clset->{"$clause.is_expr"} && !$meta->{allow_expr};
     for my $a (keys %{ $meta->{attrs} }) {
         my $av = $meta->{attrs}{$a};
         $self->_die($cd, "Attribute $clause.$a doesn't allow ".
                         "expression")
             if $clset->{"$clause.$a.is_expr"} && !$av->{allow_expr};
     }
     local $cd->{clause} = $clause;
     my $cv = $clset->{$clause};
     my $ie = $clset->{"$clause.is_expr"};
     my $op = $clset->{"$clause.op"};
     local $cd->{cl_value}   = $cv;
     local $cd->{cl_term}    = $ie ? $self->expr($cv) : $self->literal($cv);
     local $cd->{cl_is_expr} = $ie;
     local $cd->{cl_op}      = $op;
     delete $cd->{uclset}{"$clause.is_expr"};
     delete $cd->{uclset}{"$clause.op"};
 
     if ($self->can("before_clause")) {
         $self->before_clause($cd);
     }
     if ($th->can("before_clause")) {
         $th->before_clause($cd);
     }
     my $tmpnam = "before_clause_$clause";
     if ($th->can($tmpnam)) {
         $th->$tmpnam($cd);
     }
 
     my $is_multi;
     if (defined($op) && !$ie) {
         if ($op =~ /\A(and|or|none)\z/) {
             $is_multi = 1;
         } elsif ($op eq 'not') {
             $is_multi = 0;
         } else {
             $self->_die($cd, "Invalid value for $clause.op, ".
                             "must be one of and/or/not/none");
         }
     }
     $self->_die($cd, "'$clause.op' attribute set to $op, ".
                     "but value of '$clause' clause not an array")
         if $is_multi && ref($cv) ne 'ARRAY';
     if (!$th->can($meth)) {
         # skip
     } elsif ($cd->{CLAUSE_DO_MULTI} || !$is_multi) {
         local $cd->{cl_is_multi} = 1 if $is_multi;
         $th->$meth($cd);
     } else {
         my $i = 0;
         for my $cv2 (@$cv) {
             local $cd->{spath} = [@{ $cd->{spath} }, $i];
             local $cd->{cl_value} = $cv2;
             local $cd->{cl_term}  = $self->literal($cv2);
             local $cd->{_debug_ccl_note} = "" if $i;
             $i++;
             $th->$meth($cd);
         }
     }
 
     $tmpnam = "after_clause_$clause";
     if ($th->can($tmpnam)) {
         $th->$tmpnam($cd);
     }
     if ($th->can("after_clause")) {
         $th->after_clause($cd);
     }
     if ($self->can("after_clause")) {
         $self->after_clause($cd);
     }
 
     delete $cd->{uclset}{"$clause.err_msg"};
     delete $cd->{uclset}{"$clause.err_level"};
     delete $cd->{uclset}{$_} for
         grep /\A\Q$clause\E\.human(\..+)?\z/, keys(%{$cd->{uclset}});
 }
 
 sub _process_clsets {
     my ($self, $cd, $which) = @_;
 
     # $which can be left undef/false if called from compile(), or set to 'from
     # clause_clset' if called from within clause_clset(), in which case
     # before_handle_type, handle_type, before_all_clauses, and after_all_clauses
     # won't be called.
 
     my $th = $cd->{th};
     my $tn = $cd->{type};
     my $clsets = $cd->{clsets};
 
     my $cname = $self->name;
     local $cd->{uclsets} = [];
     $cd->{_clset_dlangs} = []; # default lang for each clset
     for my $clset (@$clsets) {
         for (keys %$clset) {
             if (!$cd->{args}{allow_expr} && /\.is_expr\z/ && $clset->{$_}) {
                 $self->_die($cd, "Expression not allowed: $_");
             }
         }
         push @{ $cd->{uclsets} }, {
             map {$_=>$clset->{$_}}
                 grep {
                     !/\A_|\._/ && (!/\Ac\./ || /\Ac\.\Q$cname\E\./)
                 } keys %$clset
         };
         my $dl = $clset->{default_lang} // $cd->{outer_cd}{clset_dlang} //
             "en_US";
         push @{ $cd->{_clset_dlangs} }, $dl;
     }
 
     my $clauses = $self->_get_clauses_from_clsets($cd, $clsets);
     $cd->{has_constraint_clause} = 0;
     for my $cl (@$clauses) {
         next if $cl->[1] =~ /\A(req|forbidden)\z/;
         next unless !$cl->[2]{tags} ||
             grep {$_ eq 'constraint'} @{ $cl->[2]{tags} };
         $cd->{has_constraint_clause} = 1;
         last;
     }
 
     if ($which) {
         # {before,after}_clause_sets is currently internal/undocumented, created
         # only for clause_clset
         if ($self->can("before_clause_sets")) {
             $self->before_clause_sets($cd);
         }
         if ($th->can("before_clause_sets")) {
             $th->before_clause_sets($cd);
         }
     } else {
         if ($self->can("before_handle_type")) {
             $self->before_handle_type($cd);
         }
 
         $th->handle_type($cd);
 
         if ($self->can("before_all_clauses")) {
             $self->before_all_clauses($cd);
         }
         if ($th->can("before_all_clauses")) {
             $th->before_all_clauses($cd);
         }
     }
 
     for my $clause0 (@$clauses) {
         my ($clset_num, $clause) = @$clause0;
         $self->_process_clause($cd, $clset_num, $clause);
     } # for clause
 
     for my $uclset (@{ $cd->{uclsets} }) {
         if (keys %$uclset) {
             for ($cd->{args}{on_unhandled_attr}) {
                 my $msg = "Unhandled attribute(s) for type $tn: ".
                     join(", ", keys %$uclset);
                 next if $_ eq 'ignore';
                 do { warn $msg; next } if $_ eq 'warn';
                 $self->_die($cd, $msg);
             }
         }
     }
 
     if ($which) {
         # {before,after}_clause_sets is currently internal/undocumented, created
         # only for clause_clset
         if ($th->can("after_clause_sets")) {
             $th->after_clause_sets($cd);
         }
         if ($self->can("after_clause_sets")) {
             $self->after_clause_sets($cd);
         }
     } else {
         if ($th->can("after_all_clauses")) {
             $th->after_all_clauses($cd);
         }
         if ($self->can("after_all_clauses")) {
             $self->after_all_clauses($cd);
         }
     }
 }
 
 sub compile {
     my ($self, %args) = @_;
 
     # XXX schema
     $self->check_compile_args(\%args);
 
     my $main   = $self->main;
     my $cd     = $self->init_cd(%args);
 
     if ($self->can("before_compile")) {
         $self->before_compile($cd);
     }
 
     # normalize schema
     my $schema0 = $args{schema} or $self->_die($cd, "No schema");
     my $nschema;
     if ($args{schema_is_normalized}) {
         $nschema = $schema0;
         #$log->tracef("schema already normalized, skipped normalization");
     } else {
         $nschema = $main->normalize_schema($schema0);
         #$log->tracef("normalized schema=%s", $nschema);
     }
     $cd->{nschema} = $nschema;
     local $cd->{schema} = $nschema;
 
     {
         my $defs = $nschema->[2]{def};
         if ($defs) {
             for my $name (sort keys %$defs) {
                 my $def = $defs->{$name};
                 my $opt = $name =~ s/[?]\z//;
                 local $cd->{def_optional} = $opt;
                 local $cd->{def_name}     = $name;
                 $self->_die($cd, "Invalid name syntax in def: '$name'")
                     unless $name =~ $Data::Sah::type_re;
                 local $cd->{def_def}      = $def;
                 $self->def($cd);
                 #$log->tracef("=> def() name=%s, def=>%s, optional=%s)",
                 #             $name, $def, $opt);
             }
         }
     }
 
     my $res       = $self->_resolve_base_type(schema=>$nschema, cd=>$cd);
     my $tn        = $res->[0];
     my $th        = $self->get_th(name=>$tn, cd=>$cd);
     my $clsets    = $res->[1];
     $cd->{th}     = $th;
     $cd->{type}   = $tn;
     $cd->{clsets} = $clsets;
 
     $self->_process_clsets($cd);
 
     if ($self->can("after_compile")) {
         $self->after_compile($cd);
     }
 
     if ($args{log_result}) {# && $log->is_trace) {
         require String::LineNumber;
         $log->tracef(
             "Schema compilation result:\n%s",
             !ref($cd->{result}) && ($ENV{LINENUM} // 1) ?
                 String::LineNumber::linenum($cd->{result}) :
                       $cd->{result}
                   );
     }
     return $cd;
 }
 
 sub def {
     my ($self, $cd) = @_;
     my $name = $cd->{def_name};
     my $def  = $cd->{def_def};
     my $opt  = $cd->{def_optional};
 
     my $th = $self->get_th(cd=>$cd, name=>$name, load=>0);
     if ($th) {
         if ($opt) {
             #$log->tracef("Not redefining already-defined schema/type '$name'");
             return;
         }
         $self->_die($cd, "Redefining existing type ($name) not allowed");
     }
 
     my $nschema = $self->main->normalize_schema($def);
     $cd->{th_map}{$name} = $nschema;
 }
 
 sub _ignore_clause {
     my ($self, $cd) = @_;
     my $cl = $cd->{clause};
     delete $cd->{uclset}{$cl};
 }
 
 sub _ignore_clause_and_attrs {
     my ($self, $cd) = @_;
     my $cl = $cd->{clause};
     delete $cd->{uclset}{$cl};
     delete $cd->{uclset}{$_} for grep /\A\Q$cl\E\./, keys %{$cd->{uclset}};
 }
 
 sub _die_unimplemented_clause {
     my ($self, $cd, $note) = @_;
 
     $self->_die($cd, "Clause '$cd->{clause}' for type '$cd->{type}' ".
                     ($note ? "($note) " : "") .
                         "is currently unimplemented");
 }
 
 1;
 # ABSTRACT: Base class for Sah compilers (Data::Sah::Compiler::*)
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Compiler - Base class for Sah compilers (Data::Sah::Compiler::*)
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Compiler (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =for Pod::Coverage ^(check_compile_args|def|expr|init_cd|literal|name)$
 
 =head1 ATTRIBUTES
 
 =head2 main => OBJ
 
 Reference to the main Data::Sah object.
 
 =head2 expr_compiler => OBJ
 
 Reference to expression compiler object. In the perl compiler, for example, this
 will be an instance of L<Language::Expr::Compiler::Perl> object.
 
 =head1 METHODS
 
 =head2 new() => OBJ
 
 =head2 $c->compile(%args) => HASH
 
 Compile schema into target language.
 
 Arguments (C<*> denotes required arguments, subclass may introduce others):
 
 =over 4
 
 =item * data_name => STR (default: 'data')
 
 A unique name. Will be used as default for variable names, etc. Should only be
 comprised of letters/numbers/underscores.
 
 =item * schema* => STR|ARRAY
 
 The schema to use. Will be normalized by compiler, unless
 C<schema_is_normalized> is set to true.
 
 =item * lang => STR (default: from LANG/LANGUAGE or C<en_US>)
 
 Desired output human language. Defaults (and falls back to) C<en_US>.
 
 =item * mark_missing_translation => BOOL (default: 1)
 
 If a piece of text is not found in desired human language, C<en_US> version of
 the text will be used but using this format:
 
  (en_US:the text to be translated)
 
 If you do not want this marker, set the C<mark_missing_translation> option to 0.
 
 =item * locale => STR
 
 Locale name, to be set during generating human text description. This sometimes
 needs to be if setlocale() fails to set locale using only C<lang>.
 
 =item * schema_is_normalized => BOOL (default: 0)
 
 If set to true, instruct the compiler not to normalize the input schema and
 assume it is already normalized.
 
 =item * allow_expr => BOOL (default: 1)
 
 Whether to allow expressions. If false, will die when encountering expression
 during compilation. Usually set to false for security reason, to disallow
 complex expressions when schemas come from untrusted sources.
 
 =item * on_unhandled_attr => STR (default: 'die')
 
 What to do when an attribute can't be handled by compiler (either it is an
 invalid attribute, or the compiler has not implemented it yet). Valid values
 include: C<die>, C<warn>, C<ignore>.
 
 =item * on_unhandled_clause => STR (default: 'die')
 
 What to do when a clause can't be handled by compiler (either it is an invalid
 clause, or the compiler has not implemented it yet). Valid values include:
 C<die>, C<warn>, C<ignore>.
 
 =item * indent_level => INT (default: 0)
 
 Start at a specified indent level. Useful when generated code will be inserted
 into another code (e.g. inside C<sub {}> where it is nice to be able to indent
 the inside code).
 
 =item * skip_clause => ARRAY (default: [])
 
 List of clauses to skip (to assume as if it did not exist). Example when
 compiling with the human compiler:
 
  # schema
  [int => {default=>1, between=>[1, 10]}]
 
  # generated human description in English
  integer, between 1 and 10, default 1
 
  # generated human description, with skip_clause => ['default']
  integer, between 1 and 10
 
 =back
 
 =head3 Compilation data
 
 During compilation, compile() will call various hooks (listed below). The hooks
 will be passed compilation data (C<$cd>) which is a hashref containing various
 compilation state and result. Compilation data is written to this hashref
 instead of on the object's attributes to make it easy to do recursive
 compilation (compilation of subschemas).
 
 Subclasses may add more data (see their documentation).
 
 Keys which contain input data, compilation state, and others (many of these keys
 might exist only temporarily during certain phases of compilation and will no
 longer exist at the end of compilation, for example C<clause> will only exist
 during processing of a clause and will be seen by hooks like C<before_clause>
 and C<after_clause>, it will not be seen by C<before_all_clauses> or
 C<after_compile>):
 
 =over 4
 
 =item * B<args> => HASH
 
 Arguments given to C<compile()>.
 
 =item * B<compiler> => OBJ
 
 The compiler object.
 
 =item * B<outer_cd> => HASH
 
 If compilation is called from within another C<compile()>, this will be set to
 the outer compilation's C<$cd>. The inner compilation will inherit some values
 from the outer, like list of types (C<th_map>) and function sets (C<fsh_map>).
 
 =item * B<th_map> => HASH
 
 Mapping of fully-qualified type names like C<int> and its
 C<Data::Sah::Compiler::*::TH::*> type handler object (or array, a normalized
 schema).
 
 =item * B<fsh_map> => HASH
 
 Mapping of function set name like C<core> and its
 C<Data::Sah::Compiler::*::FSH::*> handler object.
 
 =item * B<schema> => ARRAY
 
 The current schema (normalized) being processed. Since schema can contain other
 schemas, there will be subcompilation and this value will not necessarily equal
 to C<< $cd->{args}{schema} >>.
 
 =item * B<spath> = ARRAY
 
 An array of strings, with empty array (C<[]>) as the root. Point to current
 location in schema during compilation. Inner compilation will continue/append
 the path.
 
 Example:
 
  # spath, with pointer to location in the schema
 
  spath: ["elems"] ----
                       \
  schema: ["array", {elems => ["float", [int => {min=>3}], [int => "div_by&" => [2, 3]]]}
 
  spath: ["elems", 0] ------------
                                  \
  schema: ["array", {elems => ["float", [int => {min=>3}], [int => "div_by&" => [2, 3]]]}
 
  spath: ["elems", 1, "min"] ---------------------
                                                  \
  schema: ["array", {elems => ["float", [int => {min=>3}], [int => "div_by&" => [2, 3]]]}
 
  spath: ["elems", 2, "div_by", 1] -------------------------------------------------
                                                                                    \
  schema: ["array", {elems => ["float", [int => {min=>3}], [int => "div_by&" => [2, 3]]]}
 
 Note: aside from C<spath>, there is also the analogous C<dpath> which points to
 the location of I<data> (e.g. array element, hash key). But this is declared and
 maintained by the generated code, not by the compiler.
 
 =item * B<th> => OBJ
 
 Current type handler.
 
 =item * B<type> => STR
 
 Current type name.
 
 =item * B<clsets> => ARRAY
 
 All the clause sets. Each schema might have more than one clause set, due to
 processing base type's clause set.
 
 =item * B<clset> => HASH
 
 Current clause set being processed. Note that clauses are evaluated not strictly
 in clset order, but instead based on expression dependencies and priority.
 
 =item * B<clset_dlang> => HASH
 
 Default language of the current clause set. This value is taken from C<<
 $cd->{clset}{default_lang} >> or C<< $cd->{outer_cd}{default_lang} >> or the
 default C<en_US>.
 
 =item * B<clset_num> => INT
 
 Set to 0 for the first clause set, 1 for the second, and so on. Due to merging,
 we might process more than one clause set during compilation.
 
 =item * B<uclset> => HASH
 
 Short for "unprocessed clause set", a shallow copy of C<clset>, keys will be
 removed from here as they are processed by clause handlers, remaining keys after
 processing the clause set means they are not recognized by hooks and thus
 constitutes an error.
 
 =item * B<uclsets> => ARRAY
 
 All the C<uclset> for each clause set.
 
 =item * B<clause> => STR
 
 Current clause name.
 
 =item * B<cl_meta> => HASH
 
 Metadata information about the clause, from the clause definition. This include
 C<prio> (priority), C<attrs> (list of attributes specific for this clause),
 C<allow_expr> (whether clause allows expression in its value), etc. See
 C<Data::Sah::Type::$TYPENAME> for more information.
 
 =item * B<cl_value> => ANY
 
 Clause value. Note: for putting in generated code, use C<cl_term>.
 
 =item * B<cl_term> => STR
 
 Clause value term. If clause value is a literal (C<.is_expr> is false) then it
 is produced by passing clause value to C<literal()>. Otherwise, it is produced
 by passing clause value to C<expr()>.
 
 =item * B<cl_is_expr> => BOOL
 
 A copy of C<< $cd->{clset}{"${clause}.is_expr"} >>, for convenience.
 
 =item * B<cl_op> => STR
 
 A copy of C<< $cd->{clset}{"${clause}.op"} >>, for convenience.
 
 =item * B<cl_is_multi> => BOOL
 
 Set to true if cl_value contains multiple clause values. This will happen if
 C<.op> is either C<and>, C<or>, or C<none> and C<< $cd->{CLAUSE_DO_MULTI} >> is
 set to true.
 
 =item * B<indent_level> => INT
 
 Current level of indent when printing result using C<< $c->line() >>. 0 means
 unindented.
 
 =item * B<all_expr_vars> => ARRAY
 
 All variables in all expressions in the current schema (and all of its
 subschemas). Used internally by compiler. For example (XXX syntax not not
 finalized):
 
  # schema
  [array => {of=>'str1', min_len=>1, 'max_len=' => '$min_len*3'},
   {def => {
       str1 => [str => {min_len=>6, 'max_len=' => '$min_len*2',
                        check=>'substr($_,0,1) eq "a"'}],
   }}]
 
  all_expr_vars => ['schema:///clsets/0/min_len', # or perhaps .../min_len/value
                    'schema://str1/clsets/0/min_len']
 
 This data can be used to order the compilation of clauses based on dependencies.
 In the above example, C<min_len> needs to be evaluated before C<max_len>
 (especially if C<min_len> is an expression).
 
 =back
 
 Keys which contain compilation result:
 
 =over 4
 
 =item * B<ccls> => [HASH, ...]
 
 Compiled clauses, collected during processing of schema's clauses. Each element
 will contain the compiled code in the target language, error message, and other
 information. At the end of processing, these will be joined together.
 
 =item * B<result>
 
 The final result. For most compilers, it will be string/text.
 
 =item * has_constraint_clause => bool
 
 Convenience. True if there is at least one constraint clause in the schema. This
 I<excludes> special clause C<req> and C<forbidden>.
 
 =back
 
 =head3 Return value
 
 The compilation data will be returned as return value. Main result will be in
 the C<result> key. There is also C<ccls>, and subclasses may put additional
 results in other keys. Final usable result might need to be pieced together from
 these results, depending on your needs.
 
 =head3 Hooks
 
 By default this base compiler does not define any hooks; subclasses can define
 hooks to implement their compilation process. Each hook will be passed
 compilation data, and should modify or set the compilation data as needed. The
 hooks that compile() will call at various points, in calling order, are:
 
 =over 4
 
 =item * $c->before_compile($cd)
 
 Called once at the beginning of compilation.
 
 =item * $c->before_handle_type($cd)
 
 =item * $th->handle_type($cd)
 
 =item * $c->before_all_clauses($cd)
 
 Called before calling handler for any clauses.
 
 =item * $th->before_all_clauses($cd)
 
 Called before calling handler for any clauses, after compiler's
 before_all_clauses().
 
 =item * $c->before_clause($cd)
 
 Called for each clause, before calling the actual clause handler
 ($th->clause_NAME() or $th->clause).
 
 =item * $th->before_clause($cd)
 
 After compiler's before_clause() is called, I<type handler>'s before_clause()
 will also be called if available.
 
 Input and output interpretation is the same as compiler's before_clause().
 
 =item * $th->before_clause_NAME($cd)
 
 Can be used to customize clause.
 
 Introduced in v0.10.
 
 =item * $th->clause_NAME($cd)
 
 Clause handler. Will be called only once (if C<$cd->{CLAUSE_DO_MULTI}> is set to
 by other hooks before this) or once for each value in a multi-value clause (e.g.
 when C<.op> attribute is set to C<and> or C<or>). For example, in this schema:
 
  [int => {"div_by&" => [2, 3, 5]}]
 
 C<clause_div_by()> can be called only once with C<< $cd->{cl_value} >> set to
 [2, 3, 5] or three times, each with C<< $cd->{value} >> set to 2, 3, and 5
 respectively.
 
 =item * $th->after_clause_NAME($cd)
 
 Can be used to customize clause.
 
 Introduced in v0.10.
 
 =item * $th->after_clause($cd)
 
 Called for each clause, after calling the actual clause handler
 ($th->clause_NAME()).
 
 =item * $c->after_clause($cd)
 
 Called for each clause, after calling the actual clause handler
 ($th->clause_NAME()).
 
 Output interpretation is the same as $th->after_clause().
 
 =item * $th->after_all_clauses($cd)
 
 Called after all clauses have been compiled, before compiler's
 after_all_clauses().
 
 =item * $c->after_all_clauses($cd)
 
 Called after all clauses have been compiled.
 
 =item * $c->after_compile($cd)
 
 Called at the very end before compiling process end.
 
 =back
 
 =head2 $c->get_th
 
 =head2 $c->get_fsh
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Compiler/Prog.pm ###
 package Data::Sah::Compiler::Prog;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 use Log::Any::IfLOG qw($log);
 
 use Mo qw(build default);
 extends 'Data::Sah::Compiler';
 
 #use Digest::MD5 qw(md5_hex);
 
 # human compiler, to produce error messages
 has hc => (is => 'rw');
 
 # subclass should provide a default, choices: 'shell', 'c', 'ini', 'cpp'
 has comment_style => (is => 'rw');
 
 has var_sigil => (is => 'rw');
 
 has concat_op => (is => 'rw');
 
 has logical_and_op => (is => 'rw', default => sub {'&&'});
 
 has logical_not_op => (is => 'rw', default => sub {'!'});
 
 #has logical_or_op => (is => 'rw', default => sub {'||'});
 
 sub init_cd {
     my ($self, %args) = @_;
 
     my $cd = $self->SUPER::init_cd(%args);
     $cd->{vars} = {};
 
     my $hc = $self->hc;
     if (!$hc) {
         $hc = $self->main->get_compiler("human");
         $self->hc($hc);
     }
 
     if (my $ocd = $cd->{outer_cd}) {
         $cd->{vars}    = $ocd->{vars};
         $cd->{modules} = $ocd->{modules};
         $cd->{_hc}     = $ocd->{_hc};
         $cd->{_hcd}    = $ocd->{_hcd};
         $cd->{_subdata_level} = $ocd->{_subdata_level};
     } else {
         $cd->{vars}    = {};
         $cd->{modules} = [];
         $cd->{_hc}     = $hc;
         $cd->{_subdata_level} = 0;
     }
 
     $cd;
 }
 
 sub check_compile_args {
     my ($self, $args) = @_;
 
     return if $args->{_args_checked_Prog}++;
 
     $self->SUPER::check_compile_args($args);
 
     my $ct = ($args->{code_type} //= 'validator');
     if ($ct ne 'validator') {
         $self->_die({}, "code_type currently can only be 'validator'");
     }
     my $rt = ($args->{return_type} //= 'bool');
     if ($rt !~ /\A(bool|str|full)\z/) {
         $self->_die({}, "Invalid value for return_type, ".
                         "use bool|str|full");
     }
     $args->{var_prefix} //= "_sahv_";
     $args->{sub_prefix} //= "_sahs_";
     $args->{data_term}  //= $self->var_sigil . $args->{data_name};
     $args->{data_term_is_lvalue} //= 1;
     $args->{tmp_data_name} //= "tmp_$args->{data_name}";
     $args->{tmp_data_term} //= $self->var_sigil . $args->{tmp_data_name};
     $args->{comment}    //= 1;
     $args->{err_term}   //= $self->var_sigil . "err_$args->{data_name}";
 }
 
 sub comment {
     my ($self, $cd, @args) = @_;
     return '' unless $cd->{args}{comment};
 
     my $content = join("", @args);
     $content =~ s/\n+/ /g;
 
     my $style = $self->comment_style;
     if ($style eq 'shell') {
         return join("", "# ", $content, "\n");
     } elsif ($style eq 'shell2') {
         return join("", "## ", $content, "\n");
     } elsif ($style eq 'cpp') {
         return join("", "// ", $content, "\n");
     } elsif ($style eq 'c') {
         return join("", "/* ", $content, '*/');
     } elsif ($style eq 'ini') {
         return join("", "; ", $content, "\n");
     } else {
         $self->_die($cd, "BUG: Unknown comment style: $style");
     }
 }
 
 # enclose expression with parentheses, unless it already is
 sub enclose_paren {
     my ($self, $expr, $force) = @_;
     if ($expr =~ /\A(\s*)(\(.+\)\s*)\z/os) {
         return $expr if !$force;
         return "$1($2)";
     } else {
         $expr =~ /\A(\s*)(.*)/os;
         return "$1($2)";
     }
 }
 
 sub add_module {
     use experimental 'smartmatch';
 
     my ($self, $cd, $name) = @_;
 
     return 0 if $name ~~ @{ $cd->{modules} };
     push @{ $cd->{modules} }, $name;
     1;
 }
 
 sub add_var {
     my ($self, $cd, $name, $value) = @_;
 
     return if exists $cd->{vars}{$name};
     #$log->tracef("TMP: add_var %s", $name);
     $cd->{vars}{$name} = $value;
 }
 
 # naming convention: expr_NOUN(), stmt_VERB(_NOUN)?()
 
 sub expr_assign {
     my ($self, $v, $t) = @_;
     "$v = $t";
 }
 
 sub _xlt {
     my ($self, $cd, $text) = @_;
 
     my $hc  = $cd->{_hc};
     my $hcd = $cd->{_hcd};
     #$log->tracef("(Prog) Translating text %s ...", $text);
     $hc->_xlt($hcd, $text);
 }
 
 sub expr_concat {
     my ($self, @t) = @_;
     join(" " . $self->concat_op . " ", @t);
 }
 
 sub expr_var {
     my ($self, $v) = @_;
     $self->var_sigil. $v;
 }
 
 sub expr_preinc {
     my ($self, $t) = @_;
     "++$t";
 }
 
 sub expr_preinc_var {
     my ($self, $v) = @_;
     "++" . $self->var_sigil. $v;
 }
 
 # expr_postinc
 # expr_predec
 # expr_postdec
 
 # args: log_result, var_term, err_term. the rest is the same/supplied to
 # compile().
 sub expr_validator_sub {
     my ($self, %args) = @_;
 
     my $log_result = delete $args{log_result};
     my $dt         = $args{data_term};
     my $vt         = delete($args{var_term}) // $dt;
     my $do_log     = $args{debug_log} // $args{debug};
     my $rt         = $args{return_type} // 'bool';
 
     $args{indent_level} = 1;
 
     my $cd = $self->compile(%args);
     my $et = $cd->{args}{err_term};
 
     if ($rt ne 'bool') {
         my ($ev) = $et =~ /(\w+)/; # to remove sigil
         $self->add_var($cd, $ev, $rt eq 'str' ? undef : {});
     }
     my $resv = '_sahv_res';
     my $rest = $self->var_sigil . $resv;
 
     my $needs_expr_block = @{ $cd->{modules} } || $do_log;
 
     my $code = join(
         "",
         ($self->stmt_require_log_module."\n") x !!$do_log,
         (map { $self->stmt_require_module($_, $cd)."\n" } @{ $cd->{modules} }),
         $self->expr_anon_sub(
             [$vt],
             join(
                 "",
                 (map {$self->stmt_declare_local_var(
                     $_, $self->literal($cd->{vars}{$_}))."\n"}
                      sort keys %{ $cd->{vars} }),
                 #$log->tracef('-> (validator)(%s) ...', $dt);\n";
                 $self->stmt_declare_local_var($resv, "\n\n" . $cd->{result})."\n\n",
 
                 # when rt=bool, return true/false result
                 #(";\n\n\$log->tracef('<- validator() = %s', \$res)")
                 #    x !!($do_log && $rt eq 'bool'),
                 ($self->stmt_return($rest)."\n")
                     x !!($rt eq 'bool'),
 
                 # when rt=str, return string error message
                 #($log->tracef('<- validator() = %s', ".
                 #     "\$err_data);\n\n";
                 #    x !!($do_log && $rt eq 'str'),
                 ($self->expr_set_err_str($et, $self->literal('')).";",
                  "\n\n".$self->stmt_return($et)."\n")
                     x !!($rt eq 'str'),
 
                 # when rt=full, return error hash
                 ($self->stmt_return($et)."\n")
                     x !!($rt eq 'full'),
             )
         ),
     );
 
     if ($needs_expr_block) {
         $code = $self->expr_block($code);
     }
 
     if ($log_result && $log->is_trace) {
         require String::LineNumber;
         $log->tracef("validator code:\n%s",
                      ($ENV{LINENUM} // 1) ?
                          String::LineNumber::linenum($code) :
                                $code);
     }
 
     $code;
 }
 
 # add compiled clause to ccls, along with extra information useful for joining
 # later (like error level, code for adding error message, etc). available
 # options:
 #
 # - err_level (str, the default will be taken from current clause's .err_level
 # if not specified),
 #
 # - err_expr (str, a string expression in the target language that evaluates to
 # an error message, the more general and dynamic alternative to err_msg.
 #
 # - err_msg (str, the default will be produced by human compiler if not
 # supplied, or taken from current clause's .err_msg),
 #
 # - subdata (bool, default false, if set to true then this means we are
 # delving into subdata, e.g. array elements or hash pair values, and appropriate
 # things must be done to adjust for this [e.g. push_dpath/pop_dpath at the end
 # so that error message can show the proper data path].
 #
 # - assert (bool, default false, if set to true means this ccl is an assert ccl,
 # meaning it always returns true and is not translated from an actual clause. it
 # will not affect number of errors nor produce error messages.)
 sub add_ccl {
     my ($self, $cd, $ccl, $opts) = @_;
     $opts //= {};
     my $clause = $cd->{clause} // "";
     my $op     = $cd->{cl_op} // "";
     #$log->errorf("TMP: adding ccl %s, current ccls=%s", $ccl, $cd->{ccls});
 
     my $use_dpath = $cd->{args}{return_type} ne 'bool';
 
     my $el = $opts->{err_level} // $cd->{clset}{"$clause.err_level"} // "error";
     my $err_expr = $opts->{err_expr};
     my $err_msg  = $opts->{err_msg};
 
     if (defined $err_expr) {
         $self->add_var($cd, '_sahv_dpath', []) if $use_dpath;
         $err_expr = $self->expr_prefix_dpath($err_expr) if $use_dpath;
     } else {
         unless (defined $err_msg) { $err_msg = $cd->{clset}{"$clause.err_msg"} }
         unless (defined $err_msg) {
             # XXX how to invert on op='none' or op='not'?
 
             my @msgpath = @{$cd->{spath}};
             my $msgpath;
             my $hc  = $cd->{_hc};
             my $hcd = $cd->{_hcd};
             while (1) {
                 # search error message, use more general one if the more
                 # specific one is not available
                 last unless @msgpath;
                 $msgpath = join("/", @msgpath);
                 my $ccls = $hcd->{result}{$msgpath};
                 pop @msgpath;
                 if ($ccls) {
                     local $hcd->{args}{format} = 'inline_err_text';
                     $err_msg = $hc->format_ccls($hcd, $ccls);
                     # show path when debugging
                     $err_msg = "(msgpath=$msgpath) $err_msg"
                         if $cd->{args}{debug};
                     last;
                 }
             }
             if (!$err_msg) {
                 $err_msg = "ERR (clause=".($cd->{clause} // "").")";
             } else {
                 $err_msg = ucfirst($err_msg);
             }
         }
         if ($err_msg) {
             $self->add_var($cd, '_sahv_dpath', []) if $use_dpath;
             $err_expr = $self->literal($err_msg);
             $err_expr = $self->expr_prefix_dpath($err_expr) if $use_dpath;
         }
     }
 
     my $rt = $cd->{args}{return_type};
     my $et = $cd->{args}{err_term};
     my $err_code;
     if ($rt eq 'full') {
         $self->add_var($cd, '_sahv_dpath', []) if $use_dpath;
         my $k = $el eq 'warn' ? 'warnings' : 'errors';
         $err_code = $self->expr_set_err_full($et, $k, $err_expr) if $err_expr;
     } elsif ($rt eq 'str') {
         if ($el ne 'warn') {
             $err_code = $self->expr_set_err_str($et, $err_expr) if $err_expr;
         }
     }
 
     my $res = {
         ccl             => $ccl,
         err_level       => $el,
         err_code        => $err_code,
         (_debug_ccl_note => $cd->{_debug_ccl_note}) x !!$cd->{_debug_ccl_note},
         subdata         => $opts->{subdata},
     };
     push @{ $cd->{ccls} }, $res;
     delete $cd->{uclset}{"$clause.err_level"};
     delete $cd->{uclset}{"$clause.err_msg"};
 }
 
 # join ccls to handle .op and insert error messages. opts = op
 sub join_ccls {
     my ($self, $cd, $ccls, $opts) = @_;
     $opts //= {};
     my $op = $opts->{op} // "and";
     #$log->errorf("TMP: joining ccl %s", $ccls);
     #warn "join_ccls"; #TMP
 
     my ($min_ok, $max_ok, $min_nok, $max_nok);
     if ($op eq 'and') {
         $max_nok = 0;
     } elsif ($op eq 'or') {
         $min_ok = 1;
     } elsif ($op eq 'none') {
         $max_ok = 0;
     } elsif ($op eq 'not') {
 
     }
     my $dmin_ok  = defined($min_ok);
     my $dmax_ok  = defined($max_ok);
     my $dmin_nok = defined($min_nok);
     my $dmax_nok = defined($max_nok);
 
     return "" unless @$ccls;
 
     my $rt      = $cd->{args}{return_type};
     my $vp      = $cd->{args}{var_prefix};
 
     my $aop = $self->logical_and_op;
     my $nop = $self->logical_not_op;
 
     my $true = $self->true;
 
     # insert comment, error message, and $ok/$nok counting. $which is 0 by
     # default (normal), or 1 (reverse logic, for 'not' or 'none'), or 2 (for
     # $ok/$nok counting), or 3 (like 2, but for the last clause).
     my $_ice = sub {
         my ($ccl, $which) = @_;
 
         return $self->enclose_paren($ccl->{ccl}) if $ccl->{assert};
 
         my $res = "";
 
         if ($ccl->{_debug_ccl_note}) {
             if ($cd->{args}{debug_log} // $cd->{args}{debug}) {
                 $res .= $self->expr_log(
                     $cd, $self->literal($ccl->{_debug_ccl_note})) . " $aop\n";
             } else {
                 $res .= $self->comment($cd, $ccl->{_debug_ccl_note});
             }
         }
 
         $which //= 0;
         # clause code
         my $cc = ($which == 1 ? $nop:"") . $self->enclose_paren($ccl->{ccl});
         my ($ec, $oec);
         my ($ret, $oret);
         if ($which >= 2) {
             my @chk;
             if ($ccl->{err_level} eq 'warn') {
                 $oret = 1;
                 $ret  = 1;
             } elsif ($ccl->{err_level} eq 'fatal') {
                 $oret = 1;
                 $ret  = 0;
             } else {
                 $oret = $self->expr_preinc_var("${vp}ok");
                 $ret  = $self->expr_preinc_var("${vp}nok");
                 push @chk, $self->expr_var("${vp}ok"). " <= $max_ok"
                     if $dmax_ok;
                 push @chk, $self->expr_var("${vp}nok")." <= $max_nok"
                     if $dmax_nok;
                 if ($which == 3) {
                     push @chk, $self->expr_var("${vp}ok"). " >= $min_ok"
                         if $dmin_ok;
                     push @chk, $self->expr_var("${vp}nok")." >= $min_nok"
                         if $dmin_nok;
 
                     # we need to clear the error message previously set
                     if ($rt ne 'bool') {
                         my $et = $cd->{args}{err_term};
                         my $clerrc;
                         if ($rt eq 'full') {
                             $clerrc = $self->expr_reset_err_full($et);
                         } else {
                             $clerrc = $self->expr_reset_err_str($et);
                         }
                         push @chk, $clerrc;
                     }
                 }
             }
             $res .= "($cc ? $oret : $ret)";
             $res .= " $aop " . join(" $aop ", @chk) if @chk;
         } else {
             $ec = $ccl->{err_code};
             $ret =
                 $ccl->{err_level} eq 'fatal' ? 0 :
                     # this must not be done because it messes up ok/nok counting
                     #$rt eq 'full' ? 1 :
                         $ccl->{err_level} eq 'warn' ? 1 : 0;
             if ($rt eq 'bool' && $ret) {
                 $res .= $true;
             } elsif ($rt eq 'bool' || !$ec) {
                 $res .= $self->enclose_paren($cc);
             } else {
                 $res .= $self->enclose_paren(
                     $self->enclose_paren($cc). " ? $true : ($ec,$ret)",
                     "force");
             }
         }
 
         # insert dpath handling
         my $use_dpath = $rt ne 'bool' && $ccl->{subdata};
         $res = $self->expr_push_and_pop_dpath_between_expr($res) if $use_dpath;
         $res;
 
     };
 
     my $j = "\n\n$aop\n\n";
     if ($op eq 'not') {
         return $_ice->($ccls->[0], 1);
     } elsif ($op eq 'and') {
         return join $j, map { $_ice->($_) } @$ccls;
     } elsif ($op eq 'none') {
         return join $j, map { $_ice->($_, 1) } @$ccls;
     } else {
         my $jccl = join $j, map {$_ice->($ccls->[$_], $_ == @$ccls-1 ? 3:2)}
             0..@$ccls-1;
         {
             local $cd->{ccls} = [];
             local $cd->{_debug_ccl_note} = "op=$op";
             $self->add_ccl(
                 $cd,
                 $self->expr_block(
                     join(
                         "",
                         $self->stmt_declare_local_var("${vp}ok" , "0"), "\n",
                         $self->stmt_declare_local_var("${vp}nok", "0"), "\n",
                         "\n",
                         $self->block_uses_sub ?
                             $self->stmt_return($jccl) : $jccl,
                     )
                 ),
             );
             $_ice->($cd->{ccls}[0]);
         }
     }
 }
 
 sub before_compile {
     my ($self, $cd) = @_;
 
     if ($cd->{args}{data_term_is_lvalue}) {
         $cd->{data_term} = $cd->{args}{data_term};
     } else {
         my $v = $cd->{args}{var_prefix} . $cd->{args}{data_name};
         push @{ $cd->{vars} }, $v; # XXX unless already there
         $cd->{data_term} = $self->var_sigil . $v;
         # XXX perl specific!
         push @{ $cd->{ccls} }, ["(local($cd->{data_term} = $cd->{args}{data_term}), 1)"];
     }
 }
 
 sub before_handle_type {
     my ($self, $cd) = @_;
 
     # do a human compilation first to collect all the error messages
 
     unless ($cd->{_inner}) {
         my $hc = $cd->{_hc};
         my %hargs = %{$cd->{args}};
         $hargs{format}               = 'msg_catalog';
         $hargs{schema_is_normalized} = 1;
         $hargs{schema}               = $cd->{nschema};
         $hargs{on_unhandled_clause}  = 'ignore';
         $hargs{on_unhandled_attr}    = 'ignore';
         $hargs{hash_values}          = $cd->{args}{human_hash_values};
         $cd->{_hcd} = $hc->compile(%hargs);
     }
 }
 
 sub before_all_clauses {
     my ($self, $cd) = @_;
 
     # handle ok/default/prefilters/req/forbidden clauses
 
     my $dt     = $cd->{data_term};
     my $clsets = $cd->{clsets};
 
     # handle ok, this is very high priority because !ok=>1 should fail undef
     # too. we need to handle its .op=not here.
     for my $i (0..@$clsets-1) {
         my $clset  = $clsets->[$i];
         next unless exists $clset->{ok};
         my $op = $clset->{"ok.op"} // "";
         if ($op && $op ne 'not') {
             $self->_die($cd, "ok can only be combined with .op=not");
         }
         if ($op eq 'not') {
             local $cd->{_debug_ccl_note} = "!ok #$i";
             $self->add_ccl($cd, $self->false);
         } else {
             local $cd->{_debug_ccl_note} = "ok #$i";
             $self->add_ccl($cd, $self->true);
         }
         delete $cd->{uclsets}[$i]{"ok"};
         delete $cd->{uclsets}[$i]{"ok.is_expr"};
     }
 
     # handle default
     for my $i (0..@$clsets-1) {
         my $clset  = $clsets->[$i];
         my $def    = $clset->{default};
         my $defie  = $clset->{"default.is_expr"};
         if (defined $def) {
             local $cd->{_debug_ccl_note} = "default #$i";
             my $ct = $defie ?
                 $self->expr($def) : $self->literal($def);
             $self->add_ccl(
                 $cd,
                 "(".$self->expr_setif($dt, $ct).", ".$self->true.")",
                 {err_msg => ""},
             );
         }
         delete $cd->{uclsets}[$i]{"default"};
         delete $cd->{uclsets}[$i]{"default.is_expr"};
     }
 
     # XXX handle prefilters
 
     # handle req
     my $has_req;
     for my $i (0..@$clsets-1) {
         my $clset  = $clsets->[$i];
         my $req    = $clset->{req};
         my $reqie  = $clset->{"req.is_expr"};
         my $req_err_msg = $self->_xlt($cd, "Required but not specified");
         local $cd->{_debug_ccl_note} = "req #$i";
         if ($req && !$reqie) {
             $has_req++;
             $self->add_ccl(
                 $cd, $self->expr_defined($dt),
                 {
                     err_msg   => $req_err_msg,
                     err_level => 'fatal',
                 },
             );
         } elsif ($reqie) {
             $has_req++;
             my $ct = $self->expr($req);
             $self->add_ccl(
                 $cd, "!($ct) || ".$self->expr_defined($dt),
                 {
                     err_msg   => $req_err_msg,
                     err_level => 'fatal',
                 },
             );
         }
         delete $cd->{uclsets}[$i]{"req"};
         delete $cd->{uclsets}[$i]{"req.is_expr"};
     }
 
     # handle forbidden
     my $has_fbd;
     for my $i (0..@$clsets-1) {
         my $clset  = $clsets->[$i];
         my $fbd    = $clset->{forbidden};
         my $fbdie  = $clset->{"forbidden.is_expr"};
         my $fbd_err_msg = $self->_xlt($cd, "Forbidden but specified");
         local $cd->{_debug_ccl_note} = "forbidden #$i";
         if ($fbd && !$fbdie) {
             $has_fbd++;
             $self->add_ccl(
                 $cd, "!".$self->expr_defined($dt),
                 {
                     err_msg   => $fbd_err_msg,
                     err_level => 'fatal',
                 },
             );
         } elsif ($fbdie) {
             $has_fbd++;
             my $ct = $self->expr($fbd);
             $self->add_ccl(
                 $cd, "!($ct) || !".$self->expr_defined($dt),
                 {
                     err_msg   => $fbd_err_msg,
                     err_level => 'fatal',
                 },
             );
         }
         delete $cd->{uclsets}[$i]{"forbidden"};
         delete $cd->{uclsets}[$i]{"forbidden.is_expr"};
     }
 
     if (!$has_req && !$has_fbd) {
         $cd->{_skip_undef} = 1;
         $cd->{_ccls_idx1} = @{$cd->{ccls}};
     }
 
 
     $self->_die($cd, "BUG: type handler did not produce _ccl_check_type")
         unless defined($cd->{_ccl_check_type});
     local $cd->{_debug_ccl_note} = "check type '$cd->{type}'";
     $self->add_ccl(
         $cd, $cd->{_ccl_check_type},
         {
             err_msg   => sprintf(
                 $self->_xlt($cd, "Not of type %s"),
                 $self->_xlt(
                     $cd,
                     $cd->{_hc}->get_th(name=>$cd->{type})->name //
                         $cd->{type}
                     ),
             ),
             err_level => 'fatal',
         },
     );
 }
 
 sub before_clause {
     my ($self, $cd) = @_;
 
     $self->_die($cd, "Sorry, .op + .is_expr not yet supported ".
                     "(found in clause $cd->{clause})")
         if $cd->{cl_is_expr} && $cd->{cl_op};
 
     if ($cd->{args}{debug}) {
         state $json = do {
             require JSON;
             JSON->new->allow_nonref;
         };
         my $clset = $cd->{clset};
         my $cl    = $cd->{clause};
         my $res   = $json->encode({
             map { $_ => $clset->{$_}}
                 grep {/\A\Q$cl\E(?:\.|\z)/}
                     keys %$clset });
         $res =~ s/\n+/ /g;
         # a one-line dump of the clause, suitable for putting in generated
         # code's comment
         $cd->{_debug_ccl_note} = "clause: $res";
     } else {
         $cd->{_debug_ccl_note} = "clause: $cd->{clause}";
     }
 
     # we save ccls to save_ccls and empty ccls for each clause, to let clause
     # join and do stuffs to ccls. at after_clause(), we push the clause's result
     # as a single ccl to the original ccls.
 
     push @{ $cd->{_save_ccls} }, $cd->{ccls};
     $cd->{ccls} = [];
 }
 
 sub after_clause {
     my ($self, $cd) = @_;
 
     if ($cd->{args}{debug}) {
         delete $cd->{_debug_ccl_note};
     }
 
     my $save = pop @{ $cd->{_save_ccls} };
     if (@{ $cd->{ccls} }) {
         push @$save, {
             ccl       => $self->join_ccls($cd, $cd->{ccls}, {op=>$cd->{cl_op}}),
             err_level => $cd->{clset}{"$cd->{clause}.err_level"} // "error",
         }
     }
     $cd->{ccls} = $save;
 }
 
 sub after_clause_sets {
     my ($self, $cd) = @_;
 
     # simply join them together with &&
     $cd->{result} = $self->indent(
         $cd,
         $self->join_ccls($cd, $cd->{ccls}, {err_msg => ''}),
     );
 }
 
 sub after_all_clauses {
     my ($self, $cd) = @_;
 
     if (delete $cd->{_skip_undef}) {
         my $jccl = $self->join_ccls(
             $cd,
             [splice(@{ $cd->{ccls} }, $cd->{_ccls_idx1})],
         );
         local $cd->{_debug_ccl_note} = "skip if undef";
         $self->add_ccl(
             $cd,
             "!".$self->expr_defined($cd->{data_term})." ? ".$self->true." : \n\n".
                 $self->enclose_paren($jccl),
             {err_msg => ''},
         );
     }
 
     # simply join them together with &&
     $cd->{result} = $self->indent(
         $cd,
         $self->join_ccls($cd, $cd->{ccls}, {err_msg => ''}),
     );
 }
 
 1;
 # ABSTRACT: Base class for programming language compilers
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Compiler::Prog - Base class for programming language compilers
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Compiler::Prog (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =head1 SYNOPSIS
 
 =head1 DESCRIPTION
 
 This class is derived from L<Data::Sah::Compiler>. It is used as base class for
 compilers which compile schemas into code (validator) in several programming
 languages, Perl (L<Data::Sah::Compiler::perl>) and JavaScript
 (L<Data::Sah::Compiler::js>) being two of them. (Other similar programming
 languages like PHP and Ruby might also be supported later on if needed).
 
 Compilers using this base class are flexible in the kind of code they produce:
 
 =over 4
 
 =item * configurable validator return type
 
 Can generate validator that returns a simple bool result, str, or full data
 structure (containing errors, warnings, and potentially other information).
 
 =item * configurable data term
 
 For flexibility in combining the validator code with other code, e.g. putting
 inside subroutine wrapper (see L<Perinci::Sub::Wrapper>) or directly embedded to
 your source code (see L<Dist::Zilla::Plugin::Rinci::Validate>).
 
 =back
 
 =for Pod::Coverage ^(after_.+|before_.+|add_module|add_var|add_ccl|join_ccls|check_compile_args|enclose_paren|init_cd|expr|expr_.+|stmt_.+)$
 
 =head1 HOW IT WORKS
 
 The compiler generates code in the following form:
 
  EXPR && EXPR2 && ...
 
 where C<EXPR> can be a single expression or multiple expressions joined by the
 list operator (which Perl and JavaScript support). Each C<EXPR> is typically
 generated out of a single schema clause. Some pseudo-example of generated
 JavaScript code:
 
  (data >= 0)  # from clause: min => 0
  &&
  (data <= 10) # from clause: max => 10
 
 Another example, a fuller translation of schema C<< [int => {min=>0, max=>10}]
 >> to Perl, returning string result (error message) instead of boolean:
 
  # from clause: req => 0
  !defined($data) ? 1 : (
 
      # type check
      ($data =~ /^[+-]?\d+$/ ? 1 : ($err //= "Data is not an integer", 0))
 
      &&
 
      # from clause: min => 0
      ($data >=  0 ? 1 : ($err //= "Must be at least 0", 0))
 
      &&
 
      # from clause: max => 10
      ($data <= 10 ? 1 : ($err //= "Must be at most 10", 0))
 
  )
 
 The final validator code will add enclosing subroutine and variable declaration,
 loading of modules, etc.
 
 Note: Current assumptions/hard-coded things for the supported languages: ternary
 operator (C<? :>), semicolon as statement separator.
 
 =head1 ATTRIBUTES
 
 These usually need not be set/changed by users.
 
 =head2 hc => OBJ
 
 Instance of L<Data::Sah::Compiler::human>, to generate error messages.
 
 =head2 comment_style => STR
 
 Specify how comments are written in the target language. Either 'cpp' (C<//
 comment>), 'shell' (C<# comment>), 'c' (C</* comment */>), or 'ini' (C<;
 comment>). Each programming language subclass will set this, for example, the
 perl compiler sets this to 'shell' while js sets this to 'cpp'.
 
 =head2 var_sigil => STR
 
 =head2 concat_op => STR
 
 =head2 logical_and_op => STR
 
 =head2 logical_not_op => STR
 
 =head1 METHODS
 
 =head2 new() => OBJ
 
 =head2 $c->compile(%args) => RESULT
 
 Aside from base class' arguments, this class supports these arguments (suffix
 C<*> denotes required argument):
 
 =over 4
 
 =item * data_term => STR
 
 A variable name or an expression in the target language that contains the data,
 defaults to I<var_sigil> + C<name> if not specified.
 
 =item * data_term_is_lvalue => BOOL (default: 1)
 
 Whether C<data_term> can be assigned to.
 
 =item * tmp_data_name => STR
 
 Normally need not be set manually, as it will be set to "tmp_" . data_name. Used
 to store temporary data during clause evaluation.
 
 =item * tmp_data_term => STR
 
 Normally need not be set manually, as it will be set to var_sigil .
 tmp_data_name. Used to store temporary data during clause evaluation. For
 example, in JavaScript, the 'int' and 'float' type pass strings in the type
 check. But for further checking with the clauses (like 'min', 'max',
 'divisible_by') the string data needs to be converted to number first. Likewise
 with prefiltering. This variable holds the temporary value. The clauses compare
 against this value. At the end of clauses, the original data_term is restored.
 So the output validator code for schema C<< [int => min => 1] >> will look
 something like:
 
  // type check 'int'
  type(data)=='number' && Math.round(data)==data || parseInt(data)==data)
 
  &&
 
  // convert to number
  (tmp_data = type(data)=='number' ? data : parseFloat(data), true)
 
  &&
 
  // check clause 'min'
  (tmp_data >= 1)
 
 =item * err_term => STR
 
 A variable name or lvalue expression to store error message(s), defaults to
 I<var_sigil> + C<err_NAME> (e.g. C<$err_data> in the Perl compiler).
 
 =item * var_prefix => STR (default: _sahv_)
 
 Prefix for variables declared by generated code.
 
 =item * sub_prefix => STR (default: _sahs_)
 
 Prefix for subroutines declared by generated code.
 
 =item * code_type => STR (default: validator)
 
 The kind of code to generate. For now the only valid (and default) value is
 'validator'. Compiler can perhaps generate other kinds of code in the future.
 
 =item * return_type => STR (default: bool)
 
 Specify what kind of return value the generated code should produce. Either
 C<bool>, C<str>, or C<full>.
 
 C<bool> means generated validator code should just return true/false depending
 on whether validation succeeds/fails.
 
 C<str> means validation should return an error message string (the first one
 encountered) if validation fails and an empty string/undef if validation
 succeeds.
 
 C<full> means validation should return a full data structure. From this
 structure you can check whether validation succeeds, retrieve all the collected
 errors/warnings, etc.
 
 =item * debug => BOOL (default: 0)
 
 This is a general debugging option which should turn on all debugging-related
 options, e.g. produce more comments in the generated code, etc. Each compiler
 might have more specific debugging options.
 
 If turned on, specific debugging options can be explicitly turned off
 afterwards, e.g. C<< debug=>1, debug_log=>0 >> will turn on all debugging
 options but turn off the C<debug_log> setting.
 
 Currently turning on C<debug> means:
 
 =over
 
 =item - Turning on the other debug_* options, like debug_log
 
 =item - Prefixing error message with msgpath
 
 =back
 
 =item * debug_log => BOOL (default: 0)
 
 Whether to add logging to generated code. This aids in debugging generated code
 specially for more complex validation.
 
 =item * comment => BOOL (default: 1)
 
 If set to false, generated code will be devoid of comments.
 
 =item * human_hash_values => hash
 
 Optional. Will be passed to C<hash_values> argument during C<compile()> by human
 compiler.
 
 =back
 
 =head3 Compilation data
 
 This subclass adds the following compilation data (C<$cd>).
 
 Keys which contain compilation state:
 
 =over 4
 
 =item * B<data_term> => ARRAY
 
 Input data term. Set to C<< $cd->{args}{data_term} >> or a temporary variable
 (if C<< $cd->{args}{data_term_is_lvalue} >> is false). Hooks should use this
 instead of C<< $cd->{args}{data_term} >> directly, because aside from the
 aforementioned temporary variable, data term can also change, for example if
 C<default.temp> or C<prefilters.temp> attribute is set, where generated code
 will operate on another temporary variable to avoid modifying the original data.
 Or when C<.input> attribute is set, where generated code will operate on
 variable other than data.
 
 =back
 
 Keys which contain compilation result:
 
 =over 4
 
 =item * B<modules> => ARRAY
 
 List of module names that are required by the code, e.g. C<["Scalar::Utils",
 "List::Util"]>).
 
 =item * B<subs> => ARRAY
 
 Contains pairs of subroutine names and definition code string, e.g. C<< [
 [_sahs_zero => 'sub _sahs_zero { $_[0] == 0 }'], [_sahs_nonzero => 'sub
 _sah_s_nonzero { $_[0] != 0 }'] ] >>. For flexibility, you'll need to do this
 bit of arranging yourself to get the final usable code you can compile in your
 chosen programming language.
 
 =item * B<vars> => HASH
 
 =back
 
 =head2 $c->comment($cd, @args) => STR
 
 Generate a comment. For example, in perl compiler:
 
  $c->comment($cd, "123"); # -> "# 123\n"
 
 Will return an empty string if compile argument C<comment> is set to false.
 
 =head1 INTERNAL VARIABLES IN THE GENERATED CODE
 
 The generated code maintains the following variables. C<_sahv_> prefix stands
 for "Sah validator", it is used to minimize clash with data_term.
 
 =over
 
 =item * _sahv_dpath => ARRAY
 
 Analogous to C<spath> in compilation data, this variable stands for "data path"
 and is used to track location within data. If a clause is checking each element
 of an array (like the 'each_elem' or 'elems' array clause), this variable will
 be adjusted accordingly. Error messages thus can be more informative by pointing
 more exactly where in the data the problem lies.
 
 =item * C<tmp_data_term> => ANY
 
 As explained in the C<compile()> method, this is used to store temporary value
 when checking against clauses.
 
 =item * _sahv_stack => ARRAY
 
 This variable is used to store validation result of subdata. It is only used if
 the validator is returning a string or full structure, not a single boolean
 value. See C<Data::Sah::Compiler::js::TH::hash> for an example.
 
 =item * _sahv_x
 
 Usually used as temporary variable in short, anonymous functions.
 
 =back
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Compiler/Prog/TH.pm ###
 package Data::Sah::Compiler::Prog::TH;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 #use Log::Any '$log';
 
 use Mo qw(build default);
 
 extends 'Data::Sah::Compiler::TH';
 
 # handled in compiler's before_all_clauses()
 
 sub clause_default {}
 sub clause_ok {}
 sub clause_req {}
 sub clause_forbidden {}
 sub clause_prefilters {}
 
 # handled in compiler's after_all_clauses()
 
 #sub clause_postfilters {}
 
 sub clause_name {
     my ($self, $cd) = @_;
     $self->compiler->_ignore_clause_and_attrs($cd);
 }
 
 sub clause_summary {
     my ($self, $cd) = @_;
     $self->compiler->_ignore_clause_and_attrs($cd);
 }
 
 sub clause_description {
     my ($self, $cd) = @_;
     $self->compiler->_ignore_clause_and_attrs($cd);
 }
 
 sub clause_comment {
     my ($self, $cd) = @_;
     $self->compiler->_ignore_clause($cd);
 }
 
 sub clause_tags {
     my ($self, $cd) = @_;
     $self->compiler->_ignore_clause($cd);
 }
 
 sub clause_defhash_v {
     my ($self, $cd) = @_;
     $self->compiler->_ignore_clause($cd);
 }
 
 sub clause_v {
     my ($self, $cd) = @_;
     $self->compiler->_ignore_clause($cd);
 }
 
 # temporarily use temporary variable for referring to data (e.g. when converting
 # non-number to number for checking in clauses, or prefiltering)
 sub set_tmp_data_term {
     my ($self, $cd, $expr) = @_;
     my $c = $self->compiler;
     #$log->errorf("TMP: set_tmp_data_term");
 
     my $tdn = $cd->{args}{tmp_data_name};
     my $tdt = $cd->{args}{tmp_data_term};
     my $t = $c->expr_array_subscript($tdt, $cd->{_subdata_level});
     unless ($cd->{_save_data_term}) {
         $c->add_var($cd, $tdn, []);
         $cd->{_save_data_term} = $cd->{data_term};
         $cd->{data_term} = $t;
     }
     local $cd->{_debug_ccl_note} = 'set temporary data term';
     $c->add_ccl($cd, "(".$c->expr_assign($t, $expr). ", ".$c->true.")");
 }
 
 sub restore_data_term {
     my ($self, $cd) = @_;
     my $c = $self->compiler;
     #$log->errorf("TMP: restore_data_term");
 
     my $tdt = $cd->{args}{tmp_data_term};
     if ($cd->{_save_data_term}) {
         $cd->{data_term} = delete($cd->{_save_data_term});
         local $cd->{_debug_ccl_note} = 'restore original data term';
         $c->add_ccl($cd, "(".$c->expr_pop($tdt). ", ".$c->true.")");
     }
 }
 
 sub gen_any_or_all_of {
     my ($self, $which, $cd) = @_;
     my $c  = $self->compiler;
     my $cv = $cd->{cl_value};
     my $dt = $cd->{data_term};
 
     my $jccl;
     {
         local $cd->{ccls} = [];
         for my $i (0..@$cv-1) {
             local $cd->{spath} = [@{ $cd->{spath} }, $i];
             my $sch  = $cv->[$i];
             my %iargs = %{$cd->{args}};
             $iargs{outer_cd}             = $cd;
             $iargs{schema}               = $sch;
             $iargs{schema_is_normalized} = 0;
             $iargs{indent_level}++;
             my $icd  = $c->compile(%iargs);
             my @code = (
                 $icd->{result},
             );
             $c->add_ccl($cd, join("", @code));
         }
         if ($which eq 'all') {
             $jccl = $c->join_ccls(
                 $cd, $cd->{ccls}, {err_msg=>''});
         } else {
             $jccl = $c->join_ccls(
                 $cd, $cd->{ccls}, {err_msg=>'', op=>'or'});
         }
     }
     $c->add_ccl($cd, $jccl);
 }
 
 1;
 # ABSTRACT: Base class for programming-language emiting compiler's type handlers
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Compiler::Prog::TH - Base class for programming-language emiting compiler's type handlers
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Compiler::Prog::TH (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =for Pod::Coverage ^(compiler|clause_.+|handle_.+|gen_.+|set_tmp_data_term|restore_data_term)$
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Compiler/Prog/TH/all.pm ###
 package Data::Sah::Compiler::Prog::TH::all;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 #use Log::Any '$log';
 
 use Mo qw(build default);
 use Role::Tiny::With;
 
 extends 'Data::Sah::Compiler::Prog::TH';
 with 'Data::Sah::Type::all';
 
 sub handle_type {
     my ($self, $cd) = @_;
     my $c = $self->compiler;
 
     my $dt = $cd->{data_term};
     $cd->{_ccl_check_type} = $c->true;
 }
 
 sub clause_of {
     my ($self, $cd) = @_;
     $self->gen_any_or_all_of("all", $cd);
 }
 
 1;
 # ABSTRACT: Base class for programming language compiler handler for type "all"
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Compiler::Prog::TH::all - Base class for programming language compiler handler for type "all"
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Compiler::Prog::TH::all (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =for Pod::Coverage ^(clause_.+|superclause_.+)$
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Compiler/Prog/TH/any.pm ###
 package Data::Sah::Compiler::Prog::TH::any;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 #use Log::Any '$log';
 
 use Mo qw(build default);
 use Role::Tiny::With;
 
 extends 'Data::Sah::Compiler::js::TH';
 with 'Data::Sah::Type::any';
 
 sub handle_type {
     my ($self, $cd) = @_;
     my $c = $self->compiler;
 
     my $dt = $cd->{data_term};
     $cd->{_ccl_check_type} = $c->true;
 }
 
 sub clause_of {
     my ($self, $cd) = @_;
     $self->gen_any_or_all_of("any", $cd);
 }
 
 1;
 # ABSTRACT: Base class for programming language compiler handler for type "any"
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Compiler::Prog::TH::any - Base class for programming language compiler handler for type "any"
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Compiler::Prog::TH::any (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =for Pod::Coverage ^(clause_.+|superclause_.+)$
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Compiler/TH.pm ###
 package Data::Sah::Compiler::TH;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 use Mo qw(build default);
 
 # reference to compiler object
 has compiler => (is => 'rw');
 
 sub clause_v {
     my ($self, $cd) = @_;
     $self->compiler->_ignore_clause($cd);
 }
 
 sub clause_defhash_v {
     my ($self, $cd) = @_;
     $self->compiler->_ignore_clause($cd);
 }
 
 sub clause_schema_v {
     my ($self, $cd) = @_;
     $self->compiler->_ignore_clause($cd);
 }
 
 sub clause_base_v {
     my ($self, $cd) = @_;
     $self->compiler->_ignore_clause($cd);
 }
 
 sub clause_default_lang {
     my ($self, $cd) = @_;
     $self->compiler->_ignore_clause($cd);
 }
 
 sub clause_clause {
     my ($self, $cd) = @_;
     my $c  = $self->compiler;
     my $cv = $cd->{cl_value};
 
     my ($clause, $clv) = @$cv;
     my $meth   = "clause_$clause";
     my $mmeth  = "clausemeta_$clause";
 
     # provide an illusion of a clsets
     my $clsets = [{$clause => $clv}];
     local $cd->{clsets} = $clsets;
 
     $c->_process_clause($cd, 0, $clause);
 }
 
 # clause_clset, like clause_clause, also works by doing what compile() does.
 
 sub clause_clset {
     my ($self, $cd) = @_;
     my $c  = $self->compiler;
     my $cv = $cd->{cl_value};
 
     # provide an illusion of a clsets
     local $cd->{clsets} = [$cv];
     $c->_process_clsets($cd, 'from clause_clset');
 }
 
 1;
 # ABSTRACT: Base class for type handlers
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Compiler::TH - Base class for type handlers
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Compiler::TH (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =for Pod::Coverage ^(compiler|clause_.+)$
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Compiler/TextResultRole.pm ###
 package Data::Sah::Compiler::TextResultRole;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 
 use Mo qw(default);
 use Role::Tiny;
 
 use String::Indent ();
 
 # can be changed to tab, for example
 has indent_character => (is => 'rw', default => sub {''});
 
 sub add_result {
     my ($self, $cd, @args) = @_;
 
     $cd->{result} //= [];
     push @{ $cd->{result} }, $self->indent($cd, join("", @args));
     $self;
 }
 
 sub indent {
     my ($self, $cd, $str) = @_;
     String::Indent::indent(
         $self->indent_character x $cd->{indent_level},
         $str,
     );
 }
 
 sub inc_indent {
     my ($self, $cd) = @_;
     $cd->{indent_level}++;
 }
 
 sub dec_indent {
     my ($self, $cd) = @_;
     $cd->{indent_level}--;
 }
 
 sub indent_str {
     my ($self, $cd) = @_;
     $self->indent_character x $cd->{indent_level};
 }
 
 1;
 # ABSTRACT: Role for compilers that produce text result (array of lines)
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Compiler::TextResultRole - Role for compilers that produce text result (array of lines)
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Compiler::TextResultRole (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =head1 ATTRIBUTES
 
 =head2 indent_character => STR
 
 =head1 METHODS
 
 =head2 $c->add_result($cd, @arg)
 
 Append result to C<< $cd->{result} >>. Will use C<< $cd->{indent_level} >> to
 indent the line. Used by compiler; users normally do not need this.
 
 =head2 $c->inc_indent($cd)
 
 Increase indent level. This is done by increasing C<< $cd->{indent_level} >> by
 1.
 
 =head2 $c->dec_indent($cd)
 
 Decrease indent level. This is done by decreasing C<< $cd->{indent_level} >> by
 1.
 
 =head2 $c->indent_str($cd)
 
 Shortcut for C<< $c->indent_character x $cd->{indent_level} >>.
 
 =head2 $c->indent($cd, $str) => STR
 
 Indent each line in $str with indent_str and return the result.
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Compiler/human.pm ###
 package Data::Sah::Compiler::human;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 #use Log::Any::IfLOG qw($log);
 
 use Data::Dmp qw(dmp);
 use Mo qw(build default);
 use POSIX qw(locale_h);
 use Text::sprintfn;
 
 extends 'Data::Sah::Compiler';
 
 # every type extension is registered here
 our %typex; # key = type, val = [clause, ...]
 
 sub name { "human" }
 
 sub _add_msg_catalog {
     my ($self, $cd, $msg) = @_;
     return unless $cd->{args}{format} eq 'msg_catalog';
 
     my $spath = join("/", @{ $cd->{spath} });
     $cd->{_msg_catalog}{$spath} = $msg;
 }
 
 sub check_compile_args {
     use experimental 'smartmatch';
 
     my ($self, $args) = @_;
 
     $self->SUPER::check_compile_args($args);
 
     my @fmts = ('inline_text', 'inline_err_text', 'markdown', 'msg_catalog');
     $args->{format} //= $fmts[0];
     unless ($args->{format} ~~ @fmts) {
         $self->_die({}, "Unsupported format, use one of: ".join(", ", @fmts));
     }
 }
 
 sub init_cd {
     my ($self, %args) = @_;
 
     my $cd = $self->SUPER::init_cd(%args);
     if (($cd->{args}{format} // '') eq 'msg_catalog') {
         $cd->{_msg_catalog} //= $cd->{outer_cd}{_msg_catalog};
         $cd->{_msg_catalog} //= {};
     }
     $cd;
 }
 
 sub expr {
     my ($self, $cd, $expr) = @_;
 
     # for now we dump expression as is. we should probably parse it first to
     # localize number, e.g. "1.1 + 2" should become "1,1 + 2" in id_ID.
 
     # XXX for nicer output, perhaps say "the expression X" instead of just "X",
     # especially if X has a variable or rather complex.
     $expr;
 }
 
 sub literal {
     my ($self, $val) = @_;
 
     return $val unless ref($val);
     dmp($val);
 }
 
 # translate
 sub _xlt {
     my ($self, $cd, $text) = @_;
 
     my $lang = $cd->{args}{lang};
 
     #$log->tracef("translating text '%s' to '%s'", $text, $lang);
 
     return $text if $lang eq 'en_US';
     my $translations;
     {
         no strict 'refs';
         $translations = \%{"Data::Sah::Lang::$lang\::translations"};
     }
     return $translations->{$text} if defined($translations->{$text});
     if ($cd->{args}{mark_missing_translation}) {
         return "(no $lang text:$text)";
     } else {
         return $text;
     }
 }
 
 # ($cd, 3, "element") -> "3rd element"
 sub _ordinate {
     my ($self, $cd, $n, $noun) = @_;
 
     my $lang = $cd->{args}{lang};
 
     # we assume _xlt() has been called (and thus the appropriate
     # Data::Sah::Lang::* has been loaded)
 
     if ($lang eq 'en_US') {
         require Lingua::EN::Numbers::Ordinate;
         return Lingua::EN::Numbers::Ordinate::ordinate($n) . " $noun";
     } else {
         no strict 'refs';
         return "Data::Sah::Lang::$lang\::ordinate"->($n, $noun);
     }
 }
 
 sub _add_ccl {
     use experimental 'smartmatch';
 
     my ($self, $cd, $ccl) = @_;
     #$log->errorf("TMP: add_ccl %s", $ccl);
 
     $ccl->{xlt} //= 1;
 
     my $clause = $cd->{clause} // "";
     $ccl->{type} //= "clause";
 
     my $do_xlt = 1;
 
     my $hvals = {
         modal_verb     => $self->_xlt($cd, "must"),
         modal_verb_neg => $self->_xlt($cd, "must not"),
 
         # so they can overriden through hash_values
         field          => $self->_xlt($cd, "field"),
         fields         => $self->_xlt($cd, "fields"),
 
         %{ $cd->{args}{hash_values} // {} },
     };
     my $mod="";
 
     # is .human for desired language specified? if yes, use that instead
 
     {
         my $lang   = $cd->{args}{lang};
         my $dlang  = $cd->{clset_dlang} // "en_US"; # undef if not in clause
         my $suffix = $lang eq $dlang ? "" : ".alt.lang.$lang";
         if ($clause) {
             delete $cd->{uclset}{$_} for
                 grep /\A\Q$clause.human\E(\.|\z)/, keys %{$cd->{uclset}};
             if (defined $cd->{clset}{"$clause.human$suffix"}) {
                 $ccl->{type} = 'clause';
                 $ccl->{fmt}  = $cd->{clset}{"$clause.human$suffix"};
                 goto FILL_FORMAT;
             }
         } else {
             delete $cd->{uclset}{$_} for
                 grep /\A\.name(\.|\z)/, keys %{$cd->{uclset}};
             if (defined $cd->{clset}{".name$suffix"}) {
                 $ccl->{type} = 'noun';
                 $ccl->{fmt}  = $cd->{clset}{".name$suffix"};
                 $ccl->{vals} = undef;
                 goto FILL_FORMAT;
             }
         }
     }
 
     goto TRANSLATE unless $clause;
 
     my $ie    = $cd->{cl_is_expr};
     my $im    = $cd->{cl_is_multi};
     my $op    = $cd->{cl_op} // "";
     my $cv    = $cd->{clset}{$clause};
     my $vals  = $ccl->{vals} // [$cv];
 
     # handle .is_expr
 
     if ($ie) {
         if (!$ccl->{expr}) {
             $ccl->{fmt} = "($clause -> %s" . ($op ? " op=$op" : "") . ")";
             $do_xlt = 0;
             $vals = [$self->expr($cd, $vals)];
         }
         goto ERR_LEVEL;
     }
 
     # handle .op
 
     if ($op eq 'not') {
         ($hvals->{modal_verb}, $hvals->{modal_verb_neg}) =
             ($hvals->{modal_verb_neg}, $hvals->{modal_verb});
         $vals = [map {$self->literal($_)} @$vals];
     } elsif ($im && $op eq 'and') {
         if (@$cv == 2) {
             $vals = [sprintf($self->_xlt($cd, "%s and %s"),
                              $self->literal($cv->[0]),
                              $self->literal($cv->[1]))];
         } else {
             $vals = [sprintf($self->_xlt($cd, "all of %s"),
                              $self->literal($cv))];
         }
     } elsif ($im && $op eq 'or') {
         if (@$cv == 2) {
             $vals = [sprintf($self->_xlt($cd, "%s or %s"),
                              $self->literal($cv->[0]),
                              $self->literal($cv->[1]))];
         } else {
             $vals = [sprintf($self->_xlt($cd, "one of %s"),
                              $self->literal($cv))];
         }
     } elsif ($im && $op eq 'none') {
         ($hvals->{modal_verb}, $hvals->{modal_verbneg}) =
             ($hvals->{modal_verb_neg}, $hvals->{modal_verb});
         if (@$cv == 2) {
             $vals = [sprintf($self->_xlt($cd, "%s nor %s"),
                              $self->literal($cv->[0]),
                              $self->literal($cv->[1]))];
         } else {
             $vals = [sprintf($self->_xlt($cd, "any of %s"),
                              $self->literal($cv))];
         }
     } else {
         $vals = [map {$self->literal($_)} @$vals];
     }
 
   ERR_LEVEL:
 
     # handle .err_level
     if ($ccl->{type} eq 'clause' && 'constraint' ~~ $cd->{cl_meta}{tags}) {
         if (($cd->{clset}{"$clause.err_level"}//'error') eq 'warn') {
             if ($op eq 'not') {
                 $hvals->{modal_verb}     = $self->_xlt($cd, "should not");
                 $hvals->{modal_verb_neg} = $self->_xlt($cd, "should");
             } else {
                 $hvals->{modal_verb}     = $self->_xlt($cd, "should");
                 $hvals->{modal_verb_neg} = $self->_xlt($cd, "should not");
             }
         }
     }
     delete $cd->{uclset}{"$clause.err_level"};
 
   TRANSLATE:
 
     if ($ccl->{xlt}) {
         if (ref($ccl->{fmt}) eq 'ARRAY') {
             $ccl->{fmt}  = [map {$self->_xlt($cd, $_)} @{$ccl->{fmt}}];
         } elsif (!ref($ccl->{fmt})) {
             $ccl->{fmt}  = $self->_xlt($cd, $ccl->{fmt});
         }
     }
 
   FILL_FORMAT:
 
     if (ref($ccl->{fmt}) eq 'ARRAY') {
         $ccl->{text} = [map {sprintfn($_, (map {$_//""} ($hvals, @$vals)))}
                             @{$ccl->{fmt}}];
     } elsif (!ref($ccl->{fmt})) {
         $ccl->{text} = sprintfn($ccl->{fmt}, (map {$_//""} ($hvals, @$vals)));
     }
     delete $ccl->{fmt} unless $cd->{args}{debug};
 
   PUSH:
     push @{$cd->{ccls}}, $ccl;
 
     $self->_add_msg_catalog($cd, $ccl);
 }
 
 # add a compiled clause (ccl), which will be combined at the end of compilation
 # to be the final result. args is a hashref with these keys:
 #
 # * type* - str (default 'clause'). either 'noun', 'clause', 'list' (bulleted
 #   list, a clause followed by a list of items, each of them is also a ccl)
 #
 # * fmt* - str/2-element array. human text which can be used as the first
 #   argument to sprintf. string. if type=noun, can be a two-element arrayref to
 #   contain singular and plural version of noun.
 #
 # * expr - bool. fmt can handle .is_expr=1. for example, 'len=' => '1+1' can be
 #   compiled into 'length must be 1+1'. other clauses cannot handle expression,
 #   e.g. 'between=' => '[2, 2*2]'. this clause will be using the generic message
 #   'between must [2, 2*2]'
 #
 # * vals - arrayref (default [clause value]). values to fill fmt with.
 #
 # * items - arrayref. required if type=list. a single ccl or a list of ccls.
 #
 # * xlt - bool (default 1). set to 0 if fmt has been translated, and should not
 #   be translated again.
 #
 # add_ccl() is called by clause handlers and handles using .human, translating
 # fmt, sprintf(fmt, vals) into 'text', .err_level (adding 'must be %s', 'should
 # not be %s'), .is_expr, .op.
 sub add_ccl {
     my ($self, $cd, @ccls) = @_;
 
     my $op     = $cd->{cl_op} // '';
 
     my $ccl;
     if (@ccls == 1) {
         $self->_add_ccl($cd, $ccls[0]);
     } else {
         my $inner_cd = $self->init_cd(outer_cd => $cd);
         $inner_cd->{args} = $cd->{args};
         $inner_cd->{clause} = $cd->{clause};
         for (@ccls) {
             $self->_add_ccl($inner_cd, $_);
         }
 
         $ccl = {
             type  => 'list',
             vals  => [],
             items => $inner_cd->{ccls},
             multi => 0,
         };
         if ($op eq 'or') {
             $ccl->{fmt} = 'any of the following %(modal_verb)s be true';
         } elsif ($op eq 'and') {
             $ccl->{fmt} = 'all of the following %(modal_verb)s be true';
         } elsif ($op eq 'none') {
             $ccl->{fmt} = 'none of the following %(modal_verb)s be true';
             # or perhaps, fmt = 'All of the following ...' but set op to 'not'?
         }
         $self->_add_ccl($cd, $ccl);
     }
 }
 
 # format ccls to form final result. at the end of compilation, we have a tree of
 # ccls. this method accept a single ccl (of type either noun/clause) or an array
 # of ccls (which it will join together).
 sub format_ccls {
     my ($self, $cd, $ccls) = @_;
 
     # used internally to determine if the result is a single noun, in which case
     # when format is inline_err_text, we add 'Not of type '. XXX: currently this
     # is the wrong way to count? we shouldn't count children? perhaps count from
     # msg_catalog instead?
     local $cd->{_fmt_noun_count} = 0;
     local $cd->{_fmt_etc_count} = 0;
 
     my $f = $cd->{args}{format};
     my $res;
     if ($f eq 'inline_text' || $f eq 'inline_err_text' || $f eq 'msg_catalog') {
         $res = $self->_format_ccls_itext($cd, $ccls);
         if ($f eq 'inline_err_text') {
             #$log->errorf("TMP: noun=%d, etc=%d", $cd->{_fmt_noun_count}, $cd->{_fmt_etc_count});
             if ($cd->{_fmt_noun_count} == 1 && $cd->{_fmt_etc_count} == 0) {
                 # a single noun (type name), we should add some preamble
                 $res = sprintf(
                     $self->_xlt($cd, "Not of type %s"),
                     $res
                 );
             } elsif (!$cd->{_fmt_noun_count}) {
                 # a clause (e.g. "must be >= 10"), already looks like errmsg
             } else {
                 # a noun + clauses (e.g. "integer, must be even"). add preamble
                 $res = sprintf(
                     $self->_xlt(
                         $cd, "Does not satisfy the following schema: %s"),
                     $res
                 );
             }
         }
     } else {
         $res = $self->_format_ccls_markdown($cd, $ccls);
     }
     $res;
 }
 
 sub _format_ccls_itext {
     my ($self, $cd, $ccls) = @_;
 
     local $cd->{args}{mark_missing_translation} = 0;
     my $c_comma = $self->_xlt($cd, ", ");
 
     if (ref($ccls) eq 'HASH' && $ccls->{type} =~ /^(noun|clause)$/) {
         if ($ccls->{type} eq 'noun') {
             $cd->{_fmt_noun_count}++;
         } else {
             $cd->{_fmt_etc_count}++;
         }
         # handle a single noun/clause ccl
         my $ccl = $ccls;
         return ref($ccl->{text}) eq 'ARRAY' ? $ccl->{text}[0] : $ccl->{text};
     } elsif (ref($ccls) eq 'HASH' && $ccls->{type} eq 'list') {
         # handle a single list ccl
         my $c_openpar  = $self->_xlt($cd, "(");
         my $c_closepar = $self->_xlt($cd, ")");
         my $c_colon    = $self->_xlt($cd, ": ");
         my $ccl = $ccls;
 
         my $txt = $ccl->{text}; $txt =~ s/\s+$//;
         my @t = ($txt, $c_colon);
         my $i = 0;
         for (@{ $ccl->{items} }) {
             push @t, $c_comma if $i;
             my $it = $self->_format_ccls_itext($cd, $_);
             if ($it =~ /\Q$c_comma/) {
                 push @t, $c_openpar, $it, $c_closepar;
             } else {
                 push @t, $it;
             }
             $i++;
         }
         return join("", @t);
     } elsif (ref($ccls) eq 'ARRAY') {
         # handle an array of ccls
         return join($c_comma, map {$self->_format_ccls_itext($cd, $_)} @$ccls);
     } else {
         $self->_die($cd, "Can't format $ccls");
     }
 }
 
 sub _format_ccls_markdown {
     my ($self, $cd, $ccls) = @_;
 
     $self->_die($cd, "Sorry, markdown not yet implemented");
 }
 
 sub _load_lang_modules {
     my ($self, $cd) = @_;
 
     my $lang = $cd->{args}{lang};
     die "Invalid language '$lang', please use letters only"
         unless $lang =~ /\A\w+\z/;
 
     my @modp;
     unless ($lang eq 'en_US') {
         push @modp, "Data/Sah/Lang/$lang.pm";
         for my $cl (@{ $typex{$cd->{type}} // []}) {
             my $modp = "Data/Sah/Lang/$lang/TypeX/$cd->{type}/$cl.pm";
             $modp =~ s!::!/!g; # $cd->{type} might still contain '::'
             push @modp, $modp;
         }
     }
     my $i;
     for my $modp (@modp) {
         $i++;
         unless (exists $INC{$modp}) {
             if ($i == 1) {
                 # test to check whether Data::Sah::Lang::$lang exists. if it
                 # does not, we fallback to en_US.
                 require Module::Path::More;
                 my $mod = $modp; $mod =~ s/\.pm$//;
                 if (!Module::Path::More::module_path(module=>$modp)) {
                     #$log->debug("$mod cannot be found, falling back to en_US");
                     $cd->{args}{lang} = 'en_US';
                     last;
                 }
             }
             #$log->trace("Loading $modp ...");
             require $modp;
 
             # negative-cache, so we don't have to try again
             $INC{$modp} = undef;
         }
     }
 }
 
 sub before_compile {
     my ($self, $cd) = @_;
 
     # set locale so that numbers etc are printed according to locale (e.g.
     # sprintf("%s", 1.2) prints '1,2' in id_ID).
     $cd->{_orig_locale} = setlocale(LC_ALL);
 
     # XXX do we need to set everything? LC_ADDRESS, LC_TELEPHONE, LC_PAPER, ...
     my $res = setlocale(LC_ALL, $cd->{args}{locale} // $cd->{args}{lang});
     warn "Unsupported locale $cd->{args}{lang}"
         if $cd->{args}{debug} && !defined($res);
 }
 
 sub before_handle_type {
     my ($self, $cd) = @_;
 
     $self->_load_lang_modules($cd);
 }
 
 sub before_clause {
     my ($self, $cd) = @_;
 
     # by default, human clause handler can handle multiple values (e.g.
     # "div_by&"=>[2, 3] becomes "must be divisible by 2 and 3" instead of having
     # to be ["must be divisible by 2", "must be divisible by 3"]. some clauses
     # that don't can override this value to 0.
     $cd->{CLAUSE_DO_MULTI} = 1;
 }
 
 sub after_clause {
     my ($self, $cd) = @_;
 
     # reset what we set in before_clause()
     delete $cd->{CLAUSE_DO_MULTI};
 }
 
 sub after_all_clauses {
     use experimental 'smartmatch';
 
     my ($self, $cd) = @_;
 
     # quantify NOUN (e.g. integer) into 'required integer', 'optional integer',
     # or 'forbidden integer'.
 
     # my $q;
     # if (!$cd->{clset}{'required.is_expr'} &&
     #         !('required' ~~ $cd->{args}{skip_clause})) {
     #     if ($cd->{clset}{required}) {
     #         $q = 'required %s';
     #     } else {
     #         $q = 'optional %s';
     #     }
     # } elsif ($cd->{clset}{forbidden} && !$cd->{clset}{'forbidden.is_expr'} &&
     #              !('forbidden' ~~ $cd->{args}{skip_clause})) {
     #     $q = 'forbidden %s';
     # }
     # if ($q && @{$cd->{ccls}} && $cd->{ccls}[0]{type} eq 'noun') {
     #     $q = $self->_xlt($cd, $q);
     #     for (ref($cd->{ccls}[0]{text}) eq 'ARRAY' ?
     #              @{ $cd->{ccls}[0]{text} } : $cd->{ccls}[0]{text}) {
     #         $_ = sprintf($q, $_);
     #     }
     # }
 
     $cd->{result} = $self->format_ccls($cd, $cd->{ccls});
 }
 
 sub after_compile {
     my ($self, $cd) = @_;
 
     setlocale(LC_ALL, $cd->{_orig_locale});
 
     if ($cd->{args}{format} eq 'msg_catalog') {
         $cd->{result} = $cd->{_msg_catalog};
     }
 }
 
 1;
 # ABSTRACT: Compile Sah schema to human language
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Compiler::human - Compile Sah schema to human language
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Compiler::human (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =head1 SYNOPSIS
 
 =head1 DESCRIPTION
 
 This class is derived from L<Data::Sah::Compiler>. It generates human language
 text.
 
 =for Pod::Coverage ^(name|literal|expr|add_ccl|format_ccls|check_compile_args|handle_.+|before_.+|after_.+)$
 
 =head1 ATTRIBUTES
 
 =head1 METHODS
 
 =head2 new() => OBJ
 
 =head2 $c->compile(%args) => RESULT
 
 Aside from base class' arguments, this class supports these arguments (suffix
 C<*> denotes required argument):
 
 =over
 
 =item * format => STR (default: C<inline_text>)
 
 Format of text to generate. Either C<inline_text>, C<inline_err_text>, or
 C<markdown>. Note that you can easily convert Markdown to HTML, there are
 libraries in Perl, JavaScript, etc to do that.
 
 Sample C<inline_text> output:
 
  integer, must satisfy all of the following: (divisible by 3, at least 10)
 
 C<inline_err_text> is just like C<inline_text>, except geared towards producing
 an error message. Currently, instead of producing "integer" from schema "int",
 it produces "Not of type integer". The rest is identical.
 
 Sample C<markdown> output:
 
  integer, must satisfy all of the following:
 
  * divisible by 3
  * at least 10
 
 =item * hash_values => hash
 
 Optional, supply more keys to hash value to C<sprintfn> which will be used
 during compilation.
 
 =back
 
 =head3 Compilation data
 
 This subclass adds the following compilation data (C<$cd>).
 
 Keys which contain compilation state:
 
 =over 4
 
 =back
 
 Keys which contain compilation result:
 
 =over 4
 
 =back
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Compiler/human/TH.pm ###
 package Data::Sah::Compiler::human::TH;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 #use Log::Any '$log';
 
 use Mo qw(build default);
 use Role::Tiny::With;
 
 extends 'Data::Sah::Compiler::TH';
 
 sub name { undef }
 
 sub handle_type {
     my ($self, $cd) = @_;
     my $c = $self->compiler;
 
     # give the class name
     my $pkg = ref($self);
     $pkg =~ s/^Data::Sah::Compiler::human::TH:://;
 
     $c->add_ccl($cd, {type=>'noun', fmt=>$pkg});
 }
 
 # not translated
 
 sub clause_name {}
 sub clause_summary {}
 sub clause_description {}
 sub clause_comment {}
 sub clause_tags {}
 
 sub clause_prefilters {}
 sub clause_postfilters {}
 
 # ignored
 
 sub clause_ok {}
 
 # handled in after_all_clauses
 
 sub clause_req {}
 sub clause_forbidden {}
 
 # default implementation
 
 sub clause_default {
     my ($self, $cd) = @_;
     my $c = $self->compiler;
 
     $c->add_ccl($cd, {expr=>1,
                       fmt => 'default value %s'});
 }
 
 sub before_clause_clause {
     my ($self, $cd) = @_;
     $cd->{CLAUSE_DO_MULTI} = 0;
 }
 
 sub before_clause_clset {
     my ($self, $cd) = @_;
     $cd->{CLAUSE_DO_MULTI} = 0;
 }
 
 1;
 # ABSTRACT: Base class for human type handlers
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Compiler::human::TH - Base class for human type handlers
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Compiler::human::TH (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =for Pod::Coverage ^(name|compiler|clause_.+|handle_.+|before_.+|after_.+)$
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Compiler/human/TH/Comparable.pm ###
 package Data::Sah::Compiler::human::TH::Comparable;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 #use Log::Any '$log';
 
 use Mo qw(build default);
 use Role::Tiny;
 use Role::Tiny::With;
 
 with 'Data::Sah::Type::Comparable';
 
 sub superclause_comparable {
     my ($self, $which, $cd) = @_;
     my $c = $self->compiler;
 
     my $fmt;
     if ($which eq 'is') {
         $c->add_ccl($cd, {expr=>1, multi=>1,
                           fmt => '%(modal_verb)s have the value %s'});
     } elsif ($which eq 'in') {
         $c->add_ccl($cd, {expr=>1, multi=>1,
                           fmt => '%(modal_verb)s be one of %s'});
     }
 }
 1;
 # ABSTRACT: human's type handler for role "Comparable"
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Compiler::human::TH::Comparable - human's type handler for role "Comparable"
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Compiler::human::TH::Comparable (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =for Pod::Coverage ^(clause_.+|superclause_.+)$
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Compiler/human/TH/HasElems.pm ###
 package Data::Sah::Compiler::human::TH::HasElems;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 #use Log::Any '$log';
 
 use Mo qw(build default);
 use Role::Tiny;
 use Role::Tiny::With;
 
 with 'Data::Sah::Type::HasElems';
 
 sub before_clause {
     my ($self_th, $which, $cd) = @_;
 }
 
 sub before_clause_len_between {
     my ($self, $cd) = @_;
     $cd->{CLAUSE_DO_MULTI} = 0;
 }
 
 sub superclause_has_elems {
     my ($self_th, $which, $cd) = @_;
     my $c  = $self_th->compiler;
     my $cv = $cd->{cl_value};
 
     if ($which eq 'len') {
         $c->add_ccl($cd, {
             expr  => 1,
             fmt   => q[length %(modal_verb)s be %s],
         });
     } elsif ($which eq 'min_len') {
         $c->add_ccl($cd, {
             expr  => 1,
             fmt   => q[length %(modal_verb)s be at least %s],
         });
     } elsif ($which eq 'max_len') {
         $c->add_ccl($cd, {
             expr  => 1,
             fmt   => q[length %(modal_verb)s be at most %s],
         });
     } elsif ($which eq 'len_between') {
         $c->add_ccl($cd, {
             fmt   => q[length %(modal_verb)s be between %s and %s],
             vals  => $cv,
         });
     } elsif ($which eq 'has') {
         $c->add_ccl($cd, {
             expr=>1, multi=>1,
             fmt => "%(modal_verb)s have %s in its elements"});
     } elsif ($which eq 'each_index') {
         $self_th->clause_each_index($cd);
     } elsif ($which eq 'each_elem') {
         $self_th->clause_each_elem($cd);
     } elsif ($which eq 'check_each_index') {
         $self_th->compiler->_die_unimplemented_clause($cd);
     } elsif ($which eq 'check_each_elem') {
         $self_th->compiler->_die_unimplemented_clause($cd);
     } elsif ($which eq 'uniq') {
         $self_th->compiler->_die_unimplemented_clause($cd);
     } elsif ($which eq 'exists') {
         $self_th->compiler->_die_unimplemented_clause($cd);
     }
 }
 
 1;
 # ABSTRACT: human's type handler for role "HasElems"
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Compiler::human::TH::HasElems - human's type handler for role "HasElems"
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Compiler::human::TH::HasElems (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =for Pod::Coverage ^(name|clause_.+|superclause_.+|before_.+|after_.+)$
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Compiler/human/TH/Sortable.pm ###
 package Data::Sah::Compiler::human::TH::Sortable;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 #use Log::Any '$log';
 
 use Mo qw(build default);
 use Role::Tiny;
 use Role::Tiny::With;
 
 with 'Data::Sah::Type::Sortable';
 
 sub before_clause_between {
     my ($self, $cd) = @_;
     $cd->{CLAUSE_DO_MULTI} = 0;
 }
 
 sub before_clause_xbetween {
     my ($self, $cd) = @_;
     $cd->{CLAUSE_DO_MULTI} = 0;
 }
 
 sub superclause_sortable {
     my ($self, $which, $cd) = @_;
     my $c = $self->compiler;
     my $cv = $cd->{cl_value};
 
     if ($which eq 'min') {
         $c->add_ccl($cd, {
             expr=>1,
             fmt => '%(modal_verb)s be at least %s',
         });
     } elsif ($which eq 'xmin') {
         $c->add_ccl($cd, {
             expr=>1,
             fmt => '%(modal_verb)s be larger than %s',
         });
     } elsif ($which eq 'max') {
         $c->add_ccl($cd, {
             expr=>1,
             fmt => '%(modal_verb)s be at most %s',
         });
     } elsif ($which eq 'xmax') {
         $c->add_ccl($cd, {
             expr=>1,
             fmt => '%(modal_verb)s be smaller than %s',
         });
     } elsif ($which eq 'between') {
         $c->add_ccl($cd, {
             fmt => '%(modal_verb)s be between %s and %s',
             vals => $cv,
         });
     } elsif ($which eq 'xbetween') {
         $c->add_ccl($cd, {
             fmt => '%(modal_verb)s be larger than %s and smaller than %s',
             vals => $cv,
         });
     }
 }
 
 1;
 # ABSTRACT: human's type handler for role "Sortable"
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Compiler::human::TH::Sortable - human's type handler for role "Sortable"
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Compiler::human::TH::Sortable (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =for Pod::Coverage ^(name|clause_.+|superclause_.+|before_.+|after_.+)$
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Compiler/human/TH/all.pm ###
 package Data::Sah::Compiler::human::TH::all;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 #use Log::Any '$log';
 
 use Mo qw(build default);
 use Role::Tiny::With;
 
 extends 'Data::Sah::Compiler::human::TH';
 with 'Data::Sah::Type::all';
 
 sub handle_type {
 }
 
 sub clause_of {
     my ($self, $cd) = @_;
     my $c  = $self->compiler;
     my $cv = $cd->{cl_value};
 
     my @result;
     my $i = 0;
     for my $cv2 (@$cv) {
         local $cd->{spath} = [@{$cd->{spath}}, $i];
         my %iargs = %{$cd->{args}};
         $iargs{outer_cd}             = $cd;
         $iargs{schema}               = $cv2;
         $iargs{schema_is_normalized} = 0;
         my $icd = $c->compile(%iargs);
         push @result, $icd->{ccls};
         $c->_add_msg_catalog($cd, $icd->{ccls});
         $i++;
     }
 
     # can we say 'NOUN1 as well as NOUN2 as well as NOUN3 ...'?
     my $can = 1;
     for my $r (@result) {
         unless (@$r == 1 && $r->[0]{type} eq 'noun') {
             $can = 0;
             last;
         }
     }
 
     my $vals;
     if ($can) {
         my $c0  = $c->_xlt($cd, '%(modal_verb)s be %s');
         my $awa = $c->_xlt($cd, 'as well as %s');
         my $wb  = $c->_xlt($cd, ' ');
         my $fmt;
         my $i = 0;
         for my $r (@result) {
             $fmt .= $i ? $wb . $awa : $c0;
             push @$vals, ref($r->[0]{text}) eq 'ARRAY' ?
                 $r->[0]{text}[0] : $r->[0]{text};
             $i++;
         }
         $c->add_ccl($cd, {
             fmt  => $fmt,
             vals => $vals,
             xlt  => 0,
             type => 'noun',
         });
     } else {
         $c->add_ccl($cd, {
             type  => 'list',
             fmt   => '%(modal_verb)s be all of the following',
             items => [
                 @result,
             ],
             vals  => [],
         });
     }
 }
 
 1;
 # ABSTRACT: perl's type handler for type "all"
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Compiler::human::TH::all - perl's type handler for type "all"
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Compiler::human::TH::all (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =for Pod::Coverage ^(clause_.+|superclause_.+)$
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Compiler/human/TH/any.pm ###
 package Data::Sah::Compiler::human::TH::any;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 #use Log::Any '$log';
 
 use Mo qw(build default);
 use Role::Tiny::With;
 
 extends 'Data::Sah::Compiler::human::TH';
 with 'Data::Sah::Type::any';
 
 sub handle_type {
     # does not have a noun
 }
 
 sub clause_of {
     my ($self, $cd) = @_;
     my $c  = $self->compiler;
     my $cv = $cd->{cl_value};
 
     my @result;
     my $i = 0;
     for my $cv2 (@$cv) {
         local $cd->{spath} = [@{$cd->{spath}}, $i];
         my %iargs = %{$cd->{args}};
         $iargs{outer_cd}             = $cd;
         $iargs{schema}               = $cv2;
         $iargs{schema_is_normalized} = 0;
         my $icd = $c->compile(%iargs);
         push @result, $icd->{ccls};
         $i++;
     }
 
     # can we say 'either NOUN1 or NOUN2 or NOUN3 ...'?
     my $can = 1;
     for my $r (@result) {
         unless (@$r == 1 && $r->[0]{type} eq 'noun') {
             $can = 0;
             last;
         }
     }
 
     my $vals;
     if ($can) {
         my $c0  = $c->_xlt($cd, '%(modal_verb)s be either %s');
         my $awa = $c->_xlt($cd, 'or %s');
         my $wb  = $c->_xlt($cd, ' ');
         my $fmt;
         my $i = 0;
         for my $r (@result) {
             $fmt .= $i ? $wb . $awa : $c0;
             push @$vals, ref($r->[0]{text}) eq 'ARRAY' ?
                 $r->[0]{text}[0] : $r->[0]{text};
             $i++;
         }
         $c->add_ccl($cd, {
             fmt  => $fmt,
             vals => $vals,
             xlt  => 0,
             type => 'noun',
         });
     } else {
         $c->add_ccl($cd, {
             type  => 'list',
             fmt   => '%(modal_verb)s be one of the following',
             items => [
                 @result,
             ],
             vals  => [],
         });
     }
 }
 
 1;
 # ABSTRACT: perl's type handler for type "any"
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Compiler::human::TH::any - perl's type handler for type "any"
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Compiler::human::TH::any (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =for Pod::Coverage ^(clause_.+|superclause_.+)$
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Compiler/human/TH/array.pm ###
 package Data::Sah::Compiler::human::TH::array;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 #use Log::Any '$log';
 
 use Mo qw(build default);
 use Role::Tiny::With;
 
 extends 'Data::Sah::Compiler::human::TH';
 with 'Data::Sah::Compiler::human::TH::Comparable';
 with 'Data::Sah::Compiler::human::TH::HasElems';
 with 'Data::Sah::Type::array';
 
 sub handle_type {
     my ($self, $cd) = @_;
     my $c = $self->compiler;
 
     $c->add_ccl($cd, {
         fmt   => ["array", "arrays"],
         type  => 'noun',
     });
 }
 
 sub clause_each_index {
     my ($self, $cd) = @_;
     my $c  = $self->compiler;
     my $cv = $cd->{cl_value};
 
     my %iargs = %{$cd->{args}};
     $iargs{outer_cd}             = $cd;
     $iargs{schema}               = $cv;
     $iargs{schema_is_normalized} = 0;
     my $icd = $c->compile(%iargs);
 
     $c->add_ccl($cd, {
         type  => 'list',
         fmt   => 'each array subscript %(modal_verb)s be',
         items => [
             $icd->{ccls},
         ],
         vals  => [],
     });
 }
 
 sub clause_each_elem {
     my ($self, $cd) = @_;
     my $c  = $self->compiler;
     my $cv = $cd->{cl_value};
 
     my %iargs = %{$cd->{args}};
     $iargs{outer_cd}             = $cd;
     $iargs{schema}               = $cv;
     $iargs{schema_is_normalized} = 0;
     my $icd = $c->compile(%iargs);
 
     # can we say 'array of INOUNS', e.g. 'array of integers'?
     if (@{$icd->{ccls}} == 1) {
         my $c0 = $icd->{ccls}[0];
         if ($c0->{type} eq 'noun' && ref($c0->{text}) eq 'ARRAY' &&
                 @{$c0->{text}} > 1 && @{$cd->{ccls}} &&
                     $cd->{ccls}[0]{type} eq 'noun') {
             for (ref($cd->{ccls}[0]{text}) eq 'ARRAY' ?
                      @{$cd->{ccls}[0]{text}} : ($cd->{ccls}[0]{text})) {
                 my $fmt = $c->_xlt($cd, '%s of %s');
                 $_ = sprintf $fmt, $_, $c0->{text}[1];
             }
             return;
         }
     }
 
     # nope, we can't
     $c->add_ccl($cd, {
         type  => 'list',
         fmt   => 'each array element %(modal_verb)s be',
         items => [
             $icd->{ccls},
         ],
         vals  => [],
     });
 }
 
 sub clause_elems {
     my ($self, $cd) = @_;
     my $c  = $self->compiler;
     my $cv = $cd->{cl_value};
 
     for my $i (0..@$cv-1) {
         local $cd->{spath} = [@{$cd->{spath}}, $i];
         my $v = $cv->[$i];
         my %iargs = %{$cd->{args}};
         $iargs{outer_cd}             = $cd;
         $iargs{schema}               = $v;
         $iargs{schema_is_normalized} = 0;
         my $icd = $c->compile(%iargs);
         $c->add_ccl($cd, {
             type  => 'list',
             fmt   => '%s %(modal_verb)s be',
             vals  => [
                 $c->_ordinate($cd, $i+1, $c->_xlt($cd, "element")),
             ],
             items => [ $icd->{ccls} ],
         });
     }
 }
 
 1;
 # ABSTRACT: human's type handler for type "array"
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Compiler::human::TH::array - human's type handler for type "array"
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Compiler::human::TH::array (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =for Pod::Coverage ^(clause_.+|superclause_.+)$
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Compiler/human/TH/bool.pm ###
 package Data::Sah::Compiler::human::TH::bool;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 #use Log::Any '$log';
 
 use Mo qw(build default);
 use Role::Tiny::With;
 
 extends 'Data::Sah::Compiler::human::TH';
 with 'Data::Sah::Compiler::human::TH::Comparable';
 with 'Data::Sah::Compiler::human::TH::Sortable';
 with 'Data::Sah::Type::bool';
 
 sub name { "boolean value" }
 
 sub handle_type {
     my ($self, $cd) = @_;
     my $c = $self->compiler;
 
     $c->add_ccl($cd, {
         fmt   => ["boolean value", "boolean values"],
         type  => 'noun',
     });
 }
 
 sub before_clause_is_true {
     my ($self, $cd) = @_;
     $cd->{CLAUSE_DO_MULTI} = 0;
 }
 
 sub clause_is_true {
     my ($self, $cd) = @_;
     my $c  = $self->compiler;
     my $cv = $cd->{cl_value};
 
     $c->add_ccl($cd, {
         fmt   => $cv ? q[%(modal_verb)s be true] : q[%(modal_verb)s be false],
     });
 }
 
 sub clause_is_re {
     my ($self, $cd) = @_;
     my $c  = $self->compiler;
     my $cv = $cd->{cl_value};
 
     $c->add_ccl($cd, {
         fmt   => q[%(modal_verb)s be a regex pattern],
     });
 }
 
 1;
 # ABSTRACT: perl's type handler for type "bool"
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Compiler::human::TH::bool - perl's type handler for type "bool"
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Compiler::human::TH::bool (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =for Pod::Coverage ^(name|clause_.+|superclause_.+|before_.+|after_.+)$
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Compiler/human/TH/buf.pm ###
 package Data::Sah::Compiler::human::TH::buf;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 #use Log::Any '$log';
 
 use Mo qw(build default);
 use Role::Tiny::With;
 
 extends 'Data::Sah::Compiler::human::TH::str';
 
 sub name { "buffer" }
 
 sub handle_type {
     my ($self, $cd) = @_;
     my $c = $self->compiler;
 
     $c->add_ccl($cd, {
         fmt   => ["buffer", "buffers"],
         type  => 'noun',
     });
 }
 
 1;
 # ABSTRACT: perl's type handler for type "buf"
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Compiler::human::TH::buf - perl's type handler for type "buf"
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Compiler::human::TH::buf (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =for Pod::Coverage ^(name|clause_.+|superclause_.+|before_.+|after_.+)$
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Compiler/human/TH/cistr.pm ###
 package Data::Sah::Compiler::human::TH::cistr;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 #use Log::Any '$log';
 
 use Mo qw(build default);
 use Role::Tiny::With;
 
 extends 'Data::Sah::Compiler::human::TH::str';
 
 1;
 # ABSTRACT: perl's type handler for type "cistr"
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Compiler::human::TH::cistr - perl's type handler for type "cistr"
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Compiler::human::TH::cistr (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =for Pod::Coverage ^(name|clause_.+|superclause_.+|before_.+|after_.+)$
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Compiler/human/TH/code.pm ###
 package Data::Sah::Compiler::human::TH::code;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 #use Log::Any '$log';
 
 use Mo qw(build default);
 use Role::Tiny::With;
 
 extends 'Data::Sah::Compiler::human::TH';
 with 'Data::Sah::Type::code';
 
 sub handle_type {
     my ($self, $cd) = @_;
     my $c = $self->compiler;
 
     $c->add_ccl($cd, {
         fmt   => ["code", "codes"],
         type  => 'noun',
     });
 }
 
 1;
 # ABSTRACT: perl's type handler for type "code"
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Compiler::human::TH::code - perl's type handler for type "code"
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Compiler::human::TH::code (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =for Pod::Coverage ^(clause_.+|superclause_.+)$
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Compiler/human/TH/date.pm ###
 package Data::Sah::Compiler::human::TH::date;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 #use Log::Any '$log';
 
 use Mo qw(build default);
 use Role::Tiny::With;
 
 extends 'Data::Sah::Compiler::human::TH';
 with 'Data::Sah::Compiler::human::TH::Comparable';
 with 'Data::Sah::Compiler::human::TH::Sortable';
 with 'Data::Sah::Type::date';
 
 sub name { "date" }
 
 sub handle_type {
     my ($self, $cd) = @_;
     my $c = $self->compiler;
 
     $c->add_ccl($cd, {type=>'noun', fmt => ["date", "dates"]});
 }
 
 1;
 # ABSTRACT: human's type handler for type "date"
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Compiler::human::TH::date - human's type handler for type "date"
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Compiler::human::TH::date (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =for Pod::Coverage ^(name|clause_.+|superclause_.+|before_.+|after_.+)$
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Compiler/human/TH/duration.pm ###
 package Data::Sah::Compiler::human::TH::duration;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 #use Log::Any '$log';
 
 use Mo qw(build default);
 use Role::Tiny::With;
 
 extends 'Data::Sah::Compiler::human::TH';
 with 'Data::Sah::Type::duration';
 
 sub name { "duration" }
 
 sub handle_type {
     my ($self, $cd) = @_;
     my $c = $self->compiler;
 
     $c->add_ccl($cd, {type=>'noun', fmt => ["duration", "durations"]});
 }
 
 1;
 # ABSTRACT: human's type handler for type "duration"
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Compiler::human::TH::duration - human's type handler for type "duration"
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Compiler::human::TH::duration (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =for Pod::Coverage ^(name|clause_.+|superclause_.+|before_.+|after_.+)$
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Compiler/human/TH/float.pm ###
 package Data::Sah::Compiler::human::TH::float;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 #use Log::Any '$log';
 
 use Mo qw(build default);
 use Role::Tiny::With;
 
 extends 'Data::Sah::Compiler::human::TH';
 with 'Data::Sah::Compiler::human::TH::Comparable';
 with 'Data::Sah::Compiler::human::TH::Sortable';
 with 'Data::Sah::Type::float';
 
 sub name { "decimal number" }
 
 sub handle_type {
     my ($self, $cd) = @_;
     my $c = $self->compiler;
 
     $c->add_ccl($cd, {
         type=>'noun',
         fmt => ["decimal number", "decimal numbers"],
     });
 }
 
 sub clause_is_nan {
     my ($self, $cd) = @_;
     my $c = $self->compiler;
 
     my $cv = $cd->{cl_value};
     if ($cd->{cl_is_expr}) {
         $c->add_ccl($cd, {});
     } else {
         $c->add_ccl($cd, {
             fmt => $cv ?
                 q[%(modal_verb)s be a NaN] :
                     q[%(modal_verb_neg)s be a NaN],
         });
     }
 }
 
 sub clause_is_inf {
     my ($self, $cd) = @_;
     my $c = $self->compiler;
 
     my $cv = $cd->{cl_value};
     if ($cd->{cl_is_expr}) {
         $c->add_ccl($cd, {});
     } else {
         $c->add_ccl($cd, {
             fmt => $cv ?
                 q[%(modal_verb)s an infinity] :
                     q[%(modal_verb_neg)s an infinity],
         });
     }
 }
 
 sub clause_is_pos_inf {
     my ($self, $cd) = @_;
     my $c = $self->compiler;
 
     my $cv = $cd->{cl_value};
     if ($cd->{cl_is_expr}) {
         $c->add_ccl($cd, {});
     } else {
         $c->add_ccl($cd, {
             fmt => $cv ?
                 q[%(modal_verb)s a positive infinity] :
                     q[%(modal_verb_neg)s a positive infinity],
         });
     }
 }
 
 sub clause_is_neg_inf {
     my ($self, $cd) = @_;
     my $c = $self->compiler;
 
     my $cv = $cd->{cl_value};
     if ($cd->{cl_is_expr}) {
         $c->add_ccl($cd, {});
     } else {
         $c->add_ccl($cd, {
             fmt => $cv ?
                 q[%(modal_verb)s a negative infinity] :
                     q[%(modal_verb_neg)s a negative infinity],
         });
     }
 }
 
 1;
 # ABSTRACT: human's type handler for type "num"
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Compiler::human::TH::float - human's type handler for type "num"
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Compiler::human::TH::float (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =for Pod::Coverage ^(name|clause_.+|superclause_.+)$
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Compiler/human/TH/hash.pm ###
 package Data::Sah::Compiler::human::TH::hash;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 #use Log::Any '$log';
 
 use Mo qw(build default);
 use Role::Tiny::With;
 
 extends 'Data::Sah::Compiler::human::TH';
 with 'Data::Sah::Compiler::human::TH::Comparable';
 with 'Data::Sah::Compiler::human::TH::HasElems';
 with 'Data::Sah::Type::hash';
 
 sub handle_type {
     my ($self, $cd) = @_;
     my $c = $self->compiler;
 
     $c->add_ccl($cd, {
         fmt   => ["hash", "hashes"],
         type  => 'noun',
     });
 }
 
 sub clause_has {
     my ($self, $cd) = @_;
     my $c  = $self->compiler;
 
     $c->add_ccl($cd, {
         expr=>1, multi=>1,
         fmt => "%(modal_verb)s have %s in its %(field)s values"});
 }
 
 sub clause_each_index {
     my ($self, $cd) = @_;
     my $c  = $self->compiler;
     my $cv = $cd->{cl_value};
 
     my %iargs = %{$cd->{args}};
     $iargs{outer_cd}             = $cd;
     $iargs{schema}               = $cv;
     $iargs{schema_is_normalized} = 0;
     my $icd = $c->compile(%iargs);
 
     $c->add_ccl($cd, {
         type  => 'list',
         fmt   => '%(field)s name %(modal_verb)s be',
         items => [
             $icd->{ccls},
         ],
         vals  => [],
     });
 }
 
 sub clause_each_elem {
     my ($self, $cd) = @_;
     my $c  = $self->compiler;
     my $cv = $cd->{cl_value};
 
     my %iargs = %{$cd->{args}};
     $iargs{outer_cd}             = $cd;
     $iargs{schema}               = $cv;
     $iargs{schema_is_normalized} = 0;
     my $icd = $c->compile(%iargs);
 
     $c->add_ccl($cd, {
         type  => 'list',
         fmt   => 'each %(field)s %(modal_verb)s be',
         items => [
             $icd->{ccls},
         ],
         vals  => [],
     });
 }
 
 sub clause_keys {
     my ($self, $cd) = @_;
     my $c  = $self->compiler;
     my $cv = $cd->{cl_value};
 
     for my $k (sort keys %$cv) {
         local $cd->{spath} = [@{$cd->{spath}}, $k];
         my $v = $cv->{$k};
         my %iargs = %{$cd->{args}};
         $iargs{outer_cd}             = $cd;
         $iargs{schema}               = $v;
         $iargs{schema_is_normalized} = 0;
         my $icd = $c->compile(%iargs);
         $c->add_ccl($cd, {
             type  => 'list',
             fmt   => '%(field)s %s %(modal_verb)s be',
             vals  => [$k],
             items => [ $icd->{ccls} ],
         });
     }
 }
 
 sub clause_re_keys {
     my ($self, $cd) = @_;
     my $c  = $self->compiler;
     my $cv = $cd->{cl_value};
 
     for my $k (sort keys %$cv) {
         local $cd->{spath} = [@{$cd->{spath}}, $k];
         my $v = $cv->{$k};
         my %iargs = %{$cd->{args}};
         $iargs{outer_cd}             = $cd;
         $iargs{schema}               = $v;
         $iargs{schema_is_normalized} = 0;
         my $icd = $c->compile(%iargs);
         $c->add_ccl($cd, {
             type  => 'list',
             fmt   => '%(fields)s whose names match regex pattern %s %(modal_verb)s be',
             vals  => [$k],
             items => [ $icd->{ccls} ],
         });
     }
 }
 
 sub clause_req_keys {
     my ($self, $cd) = @_;
     my $c  = $self->compiler;
 
     $c->add_ccl($cd, {
         fmt   => q[%(modal_verb)s have required %(fields)s %s],
         expr  => 1,
     });
 }
 
 sub clause_allowed_keys {
     my ($self, $cd) = @_;
     my $c  = $self->compiler;
 
     $c->add_ccl($cd, {
         fmt   => q[%(modal_verb)s only have these allowed %(fields)s %s],
         expr  => 1,
     });
 }
 
 sub clause_allowed_keys_re {
     my ($self, $cd) = @_;
     my $c  = $self->compiler;
 
     $c->add_ccl($cd, {
         fmt   => q[%(modal_verb)s only have %(fields)s matching regex pattern %s],
         expr  => 1,
     });
 }
 
 sub clause_forbidden_keys {
     my ($self, $cd) = @_;
     my $c  = $self->compiler;
 
     $c->add_ccl($cd, {
         fmt   => q[%(modal_verb_neg)s have these forbidden %(fields)s %s],
         expr  => 1,
     });
 }
 
 sub clause_forbidden_keys_re {
     my ($self, $cd) = @_;
     my $c  = $self->compiler;
 
     $c->add_ccl($cd, {
         fmt   => q[%(modal_verb_neg)s have %(fields)s matching regex pattern %s],
         expr  => 1,
     });
 }
 
 sub clause_choose_one_key {
     my ($self, $cd) = @_;
     my $c  = $self->compiler;
 
     my $multi = $cd->{cl_is_multi};
     $cd->{cl_is_multi} = 0;
 
     my @ccls;
     for my $cv ($multi ? @{ $cd->{cl_value} } : ($cd->{cl_value})) {
         push @ccls, {
             fmt   => q[%(modal_verb)s contain at most one of these %(fields)s %s],
             vals  => [$cv],
         };
     }
     $c->add_ccl($cd, @ccls);
 }
 
 sub clause_choose_all_keys {
     my ($self, $cd) = @_;
     my $c  = $self->compiler;
 
     my $multi = $cd->{cl_is_multi};
     $cd->{cl_is_multi} = 0;
 
     my @ccls;
     for my $cv ($multi ? @{ $cd->{cl_value} } : ($cd->{cl_value})) {
         push @ccls, {
             fmt   => q[%(modal_verb)s contain either none or all of these %(fields)s %s],
             vals  => [$cv],
         };
     }
     $c->add_ccl($cd, @ccls);
 }
 
 sub clause_req_one_key {
     my ($self, $cd) = @_;
     my $c  = $self->compiler;
 
     my $multi = $cd->{cl_is_multi};
     $cd->{cl_is_multi} = 0;
 
     my @ccls;
     for my $cv ($multi ? @{ $cd->{cl_value} } : ($cd->{cl_value})) {
         push @ccls, {
             fmt   => q[%(modal_verb)s contain exactly one of these %(fields)s %s],
             vals  => [$cv],
         };
     }
     $c->add_ccl($cd, @ccls);
 }
 
 sub clause_dep_any {
     my ($self, $cd) = @_;
     my $c  = $self->compiler;
 
     my $multi = $cd->{cl_is_multi};
     $cd->{cl_is_multi} = 0;
 
     my @ccls;
     for my $cv ($multi ? @{ $cd->{cl_value} } : ($cd->{cl_value})) {
         if (@{ $cv->[1] } == 1) {
             push @ccls, {
                 fmt   => q[%(field)s %2$s %(modal_verb)s be present before %(field)s %1$s can be present],
                 vals  => [$cv->[0], $cv->[1][0]],
             };
         } else {
             push @ccls, {
                 fmt   => q[one of %(fields)s %2$s %(modal_verb)s be present before %(field)s %1$s can be present],
                 vals  => $cv,
                 multi => 0,
             };
         }
     }
     $c->add_ccl($cd, @ccls);
 }
 
 sub clause_dep_all {
     my ($self, $cd) = @_;
     my $c  = $self->compiler;
 
     my $multi = $cd->{cl_is_multi};
     $cd->{cl_is_multi} = 0;
 
     my @ccls;
     for my $cv ($multi ? @{ $cd->{cl_value} } : ($cd->{cl_value})) {
         if (@{ $cv->[1] } == 1) {
             push @ccls, {
                 fmt   => q[%(field)s %2$s %(modal_verb)s be present before %(field)s %1$s can be present],
                 vals  => [$cv->[0], $cv->[1][0]],
             };
         } else {
             push @ccls, {
                 fmt   => q[all of %(fields)s %2$s %(modal_verb)s be present before %(field)s %1$s can be present],
                 vals  => $cv,
             };
         }
     }
     $c->add_ccl($cd, @ccls);
 }
 
 sub clause_req_dep_any {
     my ($self, $cd) = @_;
     my $c  = $self->compiler;
 
     my $multi = $cd->{cl_is_multi};
     $cd->{cl_is_multi} = 0;
 
     my @ccls;
     for my $cv ($multi ? @{ $cd->{cl_value} } : ($cd->{cl_value})) {
         if (@{ $cv->[1] } == 1) {
             push @ccls, {
                 fmt   => q[%(field)s %1$s %(modal_verb)s be present when %(field)s %2$s is present],
                 vals  => [$cv->[0], $cv->[1][0]],
             };
         } else {
             push @ccls, {
                 fmt   => q[%(field)s %1$s %(modal_verb)s be present when one of %(fields)s %2$s is present],
                 vals  => $cv,
             };
         }
     }
     $c->add_ccl($cd, @ccls);
 }
 
 sub clause_req_dep_all {
     my ($self, $cd) = @_;
     my $c  = $self->compiler;
 
     my $multi = $cd->{cl_is_multi};
     $cd->{cl_is_multi} = 0;
 
     my @ccls;
     for my $cv ($multi ? @{ $cd->{cl_value} } : ($cd->{cl_value})) {
         if (@{ $cv->[1] } == 1) {
             push @ccls, {
                 fmt   => q[%(field)s %1$s %(modal_verb)s be present when %(field)s %2$s is present],
                 vals  => [$cv->[0], $cv->[1][0]],
             };
         } else {
             push @ccls, {
                 fmt   => q[%(field)s %1$s %(modal_verb)s be present when all of %(fields)s %2$s are present],
                 vals  => $cv,
             };
         }
     }
     $c->add_ccl($cd, @ccls);
 }
 
 1;
 # ABSTRACT: human's type handler for type "hash"
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Compiler::human::TH::hash - human's type handler for type "hash"
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Compiler::human::TH::hash (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =for Pod::Coverage ^(clause_.+|superclause_.+)$
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Compiler/human/TH/int.pm ###
 package Data::Sah::Compiler::human::TH::int;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 #use Log::Any '$log';
 
 use Mo qw(build default);
 use Role::Tiny::With;
 
 extends 'Data::Sah::Compiler::human::TH::num';
 with 'Data::Sah::Type::int';
 
 sub name { "integer" }
 
 sub handle_type {
     my ($self, $cd) = @_;
     my $c = $self->compiler;
 
     $c->add_ccl($cd, {
         type  => 'noun',
         fmt   => ["integer", "integers"],
     });
 }
 
 sub clause_div_by {
     my ($self, $cd) = @_;
     my $c  = $self->compiler;
     my $cv = $cd->{cl_value};
 
     if (!$cd->{cl_is_multi} && !$cd->{cl_is_expr} &&
             $cv == 2) {
         $c->add_ccl($cd, {
             fmt   => q[%(modal_verb)s be even],
         });
         return;
     }
 
     $c->add_ccl($cd, {
         fmt   => q[%(modal_verb)s be divisible by %s],
         expr  => 1,
     });
 }
 
 sub clause_mod {
     my ($self, $cd) = @_;
     my $c  = $self->compiler;
     my $cv = $cd->{cl_value};
 
     if (!$cd->{cl_is_multi} && !$cd->{cl_is_expr}) {
         if ($cv->[0] == 2 && $cv->[1] == 0) {
             $c->add_ccl($cd, {
                 fmt   => q[%(modal_verb)s be even],
             });
             return;
         } elsif ($cv->[0] == 2 && $cv->[1] == 1) {
             $c->add_ccl($cd, {
                 fmt   => q[%(modal_verb)s be odd],
             });
             return;
         }
     }
 
     my @ccls;
     for my $cv ($cd->{cl_is_multi} ? @{ $cd->{cl_value} } : ($cd->{cl_value})) {
         push @ccls, {
             fmt  => q[%(modal_verb)s leave a remainder of %2$s when divided by %1$s],
             vals => $cv,
         };
     }
     $c->add_ccl($cd, @ccls);
 }
 
 1;
 # ABSTRACT: human's type handler for type "int"
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Compiler::human::TH::int - human's type handler for type "int"
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Compiler::human::TH::int (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =for Pod::Coverage ^(name|clause_.+|superclause_.+|before_.+|after_.+)$
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Compiler/human/TH/num.pm ###
 package Data::Sah::Compiler::human::TH::num;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 #use Log::Any '$log';
 
 use Mo qw(build default);
 use Role::Tiny::With;
 
 extends 'Data::Sah::Compiler::human::TH';
 with 'Data::Sah::Compiler::human::TH::Comparable';
 with 'Data::Sah::Compiler::human::TH::Sortable';
 with 'Data::Sah::Type::num';
 
 sub name { "number" }
 
 sub handle_type {
     my ($self, $cd) = @_;
     my $c = $self->compiler;
 
     $c->add_ccl($cd, {type=>'noun', fmt => ["number", "numbers"]});
 }
 
 1;
 # ABSTRACT: human's type handler for type "num"
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Compiler::human::TH::num - human's type handler for type "num"
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Compiler::human::TH::num (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =for Pod::Coverage ^(name|clause_.+|superclause_.+|before_.+|after_.+)$
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Compiler/human/TH/obj.pm ###
 package Data::Sah::Compiler::human::TH::obj;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 #use Log::Any '$log';
 
 use Mo qw(build default);
 use Role::Tiny::With;
 
 extends 'Data::Sah::Compiler::human::TH';
 with 'Data::Sah::Type::obj';
 
 sub name { "object" }
 
 sub handle_type {
     my ($self, $cd) = @_;
     my $c = $self->compiler;
 
     $c->add_ccl($cd, {
         fmt   => ["object", "objects"],
         type  => 'noun',
     });
 }
 
 sub clause_can {
     my ($self, $cd) = @_;
     my $c  = $self->compiler;
     my $cv = $cd->{cl_value};
 
     $c->add_ccl($cd, {
         fmt   => q[%(modal_verb)s have method(s) %s],
         #expr  => 1, # weird
     });
 }
 
 sub clause_isa {
     my ($self, $cd) = @_;
     my $c  = $self->compiler;
     my $cv = $cd->{cl_value};
 
     $c->add_ccl($cd, {
         fmt   => q[%(modal_verb)s be subclass of %s],
     });
 }
 
 1;
 # ABSTRACT: perl's type handler for type "obj"
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Compiler::human::TH::obj - perl's type handler for type "obj"
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Compiler::human::TH::obj (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =for Pod::Coverage ^(name|clause_.+|superclause_.+|before_.+|after_.+)$
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Compiler/human/TH/re.pm ###
 package Data::Sah::Compiler::human::TH::re;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 #use Log::Any '$log';
 
 use Mo qw(build default);
 use Role::Tiny::With;
 
 extends 'Data::Sah::Compiler::human::TH';
 with 'Data::Sah::Type::re';
 
 sub name { "regex pattern" }
 
 sub handle_type {
     my ($self, $cd) = @_;
     my $c = $self->compiler;
 
     $c->add_ccl($cd, {
         fmt   => ["regex pattern", "regex patterns"],
         type  => 'noun',
     });
 }
 
 1;
 # ABSTRACT: perl's type handler for type "re"
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Compiler::human::TH::re - perl's type handler for type "re"
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Compiler::human::TH::re (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =for Pod::Coverage ^(name|clause_.+|superclause_.+|before_.+|after_.+)$
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Compiler/human/TH/str.pm ###
 package Data::Sah::Compiler::human::TH::str;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 #use Log::Any '$log';
 
 use Mo qw(build default);
 use Role::Tiny::With;
 
 extends 'Data::Sah::Compiler::human::TH';
 with 'Data::Sah::Compiler::human::TH::Sortable';
 with 'Data::Sah::Compiler::human::TH::Comparable';
 with 'Data::Sah::Compiler::human::TH::HasElems';
 with 'Data::Sah::Type::str';
 
 sub name { "text" }
 
 sub handle_type {
     my ($self, $cd) = @_;
     my $c = $self->compiler;
 
     $c->add_ccl($cd, {
         fmt   => ["text", "texts"],
         type  => 'noun',
     });
 }
 
 sub clause_each_index {
     my ($self, $cd) = @_;
     my $c  = $self->compiler;
     my $cv = $cd->{cl_value};
 
     my %iargs = %{$cd->{args}};
     $iargs{outer_cd}             = $cd;
     $iargs{schema}               = $cv;
     $iargs{schema_is_normalized} = 0;
     my $icd = $c->compile(%iargs);
 
     $c->add_ccl($cd, {
         type  => 'list',
         fmt   => 'each subscript of text %(modal_verb)s be',
         items => [
             $icd->{ccls},
         ],
         vals  => [],
     });
 }
 
 sub clause_each_elem {
     my ($self, $cd) = @_;
     my $c  = $self->compiler;
     my $cv = $cd->{cl_value};
 
     my %iargs = %{$cd->{args}};
     $iargs{outer_cd}             = $cd;
     $iargs{schema}               = $cv;
     $iargs{schema_is_normalized} = 0;
     my $icd = $c->compile(%iargs);
 
     $c->add_ccl($cd, {
         type  => 'list',
         fmt   => 'each character of the text %(modal_verb)s be',
         items => [
             $icd->{ccls},
         ],
         vals  => [],
     });
 }
 
 sub clause_encoding {
     my ($self, $cd) = @_;
     my $c  = $self->compiler;
     my $cv = $cd->{cl_value};
 
     $c->_die($cd, "Only 'utf8' encoding is currently supported")
         unless $cv eq 'utf8';
     # currently does nothing
 }
 
 sub clause_match {
     my ($self, $cd) = @_;
     my $c  = $self->compiler;
     my $cv = $cd->{cl_value};
 
     $c->add_ccl($cd, {
         fmt   => q[%(modal_verb)s match regex pattern %s],
         #expr  => 1, # weird
     });
 }
 
 sub clause_is_re {
     my ($self, $cd) = @_;
     my $c  = $self->compiler;
     my $cv = $cd->{cl_value};
 
     $c->add_ccl($cd, {
         fmt   => q[%(modal_verb)s be a regex pattern],
     });
 }
 
 1;
 # ABSTRACT: perl's type handler for type "str"
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Compiler::human::TH::str - perl's type handler for type "str"
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Compiler::human::TH::str (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =for Pod::Coverage ^(name|clause_.+|superclause_.+|before_.+|after_.+)$
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Compiler/human/TH/undef.pm ###
 package Data::Sah::Compiler::human::TH::undef;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 #use Log::Any '$log';
 
 use Mo qw(build default);
 use Role::Tiny::With;
 
 extends 'Data::Sah::Compiler::human::TH';
 with 'Data::Sah::Type::undef';
 
 sub name { "undefined value" }
 
 sub handle_type {
     my ($self, $cd) = @_;
     my $c = $self->compiler;
 
     $c->add_ccl($cd, {
         fmt   => ["undefined value", "undefined values"],
         type  => 'noun',
     });
 }
 
 1;
 # ABSTRACT: perl's type handler for type "undef"
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Compiler::human::TH::undef - perl's type handler for type "undef"
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Compiler::human::TH::undef (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =for Pod::Coverage ^(name|clause_.+|superclause_.+|before_.+|after_.+)$
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Compiler/js.pm ###
 package Data::Sah::Compiler::js;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 #use Log::Any '$log';
 
 use Mo qw(build default);
 use String::Indent ();
 
 extends 'Data::Sah::Compiler::Prog';
 
 sub BUILD {
     my ($self, $args) = @_;
 
     $self->comment_style('cpp');
     $self->indent_character(" " x 4);
     $self->var_sigil("");
     $self->concat_op("+");
 }
 
 sub name { "js" }
 
 sub expr {
     my ($self, $expr) = @_;
     $self->expr_compiler->js($expr);
 }
 
 sub literal {
     my ($self, $val) = @_;
 
     state $json = do {
         require JSON;
         JSON->new->allow_nonref;
     };
 
     # we need cleaning since json can't handle qr//, for one.
     state $cleanser = do {
         require Data::Clean::JSON;
         Data::Clean::JSON->get_cleanser;
     };
 
     $json->encode($cleanser->clone_and_clean($val));
 }
 
 sub compile {
     my ($self, %args) = @_;
 
     #$self->expr_compiler->compiler->hook_var(
     # ...
     #);
 
     #$self->expr_compiler->compiler->hook_func(
     # ...
     #);
 
     $self->SUPER::compile(%args);
 }
 
 sub true { "true" }
 
 sub false { "false" }
 
 sub expr_defined {
     my ($self, $t) = @_;
     "!($t === undefined || $t === null)";
 }
 
 sub expr_array_subscript {
     my ($self, $at, $idxt) = @_;
     "$at\[$idxt]";
 }
 
 sub expr_last_elem {
     my ($self, $at, $idxt) = @_;
     "$at\[($at).length-1]";
 }
 
 sub expr_array_0_nmin1 {
     my ($self, $n) = @_;
     "Array($n).join().split(',').map(function(e,i){return i})";
 }
 
 sub expr_array_1_n {
     my ($self, $n) = @_;
     "Array($n).join().split(',').map(function(e,i){return i+1})";
 }
 
 sub expr_push {
     my ($self, $at, $elt) = @_;
     "($at).push($elt)";
 }
 
 sub expr_pop {
     my ($self, $at, $elt) = @_;
     "($at).pop()";
 }
 
 sub expr_push_and_pop_dpath_between_expr {
     my ($self, $et) = @_;
     join(
         "",
         "[",
         $self->expr_push('_sahv_dpath', $self->literal(undef)), ", ", # 0
         $self->enclose_paren($et), ", ", #1
         $self->expr_pop('_sahv_dpath'), # 2
         "][1]",
     );
 }
 
 sub expr_prefix_dpath {
     my ($self, $t) = @_;
     '(_sahv_dpath.length ? "@" + _sahv_dpath.join("/") + ": " : "") + ' . $t;
 }
 
 # $l //= $r
 sub expr_setif {
     my ($self, $l, $r) = @_;
     "$l = " . $self->expr_defined($l) . " ? $l : $r";
 }
 
 sub expr_set_err_str {
     my ($self, $et, $err_expr) = @_;
     $self->expr_setif($et, $err_expr);
 }
 
 sub expr_set_err_full {
     my ($self, $et, $k, $err_expr) = @_;
     join(
         "",
         "(",
         $self->expr_setif("$et\['$k']", "{}"),
         ",",
         $self->expr_setif("$et\['$k'][_sahv_dpath.join('/')]", $err_expr),
         ")",
     );
 }
 
 sub expr_reset_err_str {
     my ($self, $et, $err_expr) = @_;
     "($et = null, true)";
 }
 
 sub expr_reset_err_full {
     my ($self, $et) = @_;
     join(
         "",
         "(",
         $self->expr_setif("$et\['errors']", "{}"),
         ",",
         "delete($et\['errors'][_sahv_dpath.join('/')])",
         ")",
     );
 }
 
 sub expr_log {
     my ($self, $cd, $ccl) = @_;
     # currently not supported
     "";
 }
 
 sub expr_block {
     my ($self, $code) = @_;
     join(
         "",
         "(function() {\n",
         String::Indent::indent(
             $self->indent_character,
             $code,
         ),
         "})()",
     );
 }
 
 # whether block is implemented using function
 sub block_uses_sub { 1 }
 
 sub stmt_declare_local_var {
     my $self = shift;
     my $v = shift;
     if (@_) {
         "var $v = $_[0];";
     } else {
         "var $v;";
     }
 }
 
 sub expr_anon_sub {
     my ($self, $args, $code) = @_;
     join(
         "",
         "function(".join(", ", @$args).") {\n",
         String::Indent::indent(
             $self->indent_character,
             $code,
         ),
         "}"
     );
 }
 
 sub stmt_require_module {
     my ($self, $mod, $cd) = @_;
     # currently loading module is not supported by js?
     #"require $mod;";
     '';
 }
 
 sub stmt_require_log_module {
     my ($self, $mod) = @_;
     # currently logging is not supported by js
     '';
 }
 
 sub stmt_return {
     my $self = shift;
     if (@_) {
         "return($_[0]);";
     } else {
         'return;';
     }
 }
 
 sub expr_validator_sub {
     my ($self, %args) = @_;
 
     $args{data_term} = 'data';
     $self->SUPER::expr_validator_sub(%args);
 }
 
 sub _str2reliteral {
     my ($self, $cd, $str) = @_;
 
     my $re;
     if (ref($str) eq 'Regexp') {
         $re = "$str";
     } else {
         eval { qr/$str/ };
         $self->_die($cd, "Invalid regex $str: $@") if $@;
         $re = $str;
     }
 
     # i don't know if this is safe?
     $re = "$re";
     $re =~ s!/!\\/!g;
     "/$re/";
 }
 
 1;
 # ABSTRACT: Compile Sah schema to JavaScript code
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Compiler::js - Compile Sah schema to JavaScript code
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Compiler::js (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =head1 SYNOPSIS
 
  # see Data::Sah
 
 =head1 DESCRIPTION
 
 Derived from L<Data::Sah::Compiler::Prog>.
 
 =for Pod::Coverage BUILD ^(after_.+|before_.+|name|expr|true|false|literal|expr_.+|stmt_.+|block_uses_sub)$
 
 =head1 METHODS
 
 =head2 new() => OBJ
 
 =head2 $c->compile(%args) => RESULT
 
 Aside from Prog's arguments, this class supports these arguments:
 
 =over
 
 =back
 
 =head1 DEVELOPER NOTES
 
 To generate expression code that says "all subexpression must be true", you can
 do:
 
  ARRAY.every(function(x) { return blah(x) })
 
 which shortcuts to false after the first item failure.
 
 To say "at least one subexpression must be true":
 
  !ARRAY.every(function(x) { return !blah(x) })
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Compiler/js/TH.pm ###
 package Data::Sah::Compiler::js::TH;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 #use Log::Any '$log';
 
 use Mo qw(build default);
 
 extends 'Data::Sah::Compiler::Prog::TH';
 
 sub gen_each {
     my ($self, $cd, $indices_expr, $data_name, $data_term, $code_at_sub_begin) = @_;
     my $c  = $self->compiler;
     my $cv = $cd->{cl_value};
     my $dt = $cd->{data_term};
 
     local $cd->{_subdata_level} = $cd->{_subdata_level} + 1;
     my $use_dpath = $cd->{args}{return_type} ne 'bool';
 
     my %iargs = %{$cd->{args}};
     $iargs{outer_cd}             = $cd;
     $iargs{data_name}            = $data_name,
     $iargs{data_term}            = $data_term,
     $iargs{schema}               = $cv;
     $iargs{schema_is_normalized} = 0;
     $iargs{indent_level}++;
     my $icd = $c->compile(%iargs);
     my @code = (
         "(", $indices_expr, ").every(function(_sahv_idx){", ($code_at_sub_begin // ''), " return(\n",
         # if ary == [], then set ary[0] = 0, else set ary[-1] = ary[-1]+1
         ($c->indent_str($cd), "(_sahv_dpath[_sahv_dpath.length ? _sahv_dpath.length-1 : 0] = _sahv_idx),\n") x !!$use_dpath,
         $icd->{result}, "\n",
         $c->indent_str($icd), ")})",
     );
     $c->add_ccl($cd, join("", @code), {subdata=>1});
 }
 
 1;
 # ABSTRACT: Base class for js type handlers
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Compiler::js::TH - Base class for js type handlers
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Compiler::js::TH (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =for Pod::Coverage ^(compiler|clause_.+|gen_.+)$
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Compiler/js/TH/all.pm ###
 package Data::Sah::Compiler::js::TH::all;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 #use Log::Any '$log';
 
 use Mo qw(build default);
 use Role::Tiny::With;
 
 # Mo currently doesn't support multiple classes in 'extends'
 #extends
 #    'Data::Sah::Compiler::js::TH',
 #    'Data::Sah::Compiler::Prog::TH::all';
 
 use parent (
     'Data::Sah::Compiler::js::TH',
     'Data::Sah::Compiler::Prog::TH::all',
 );
 
 1;
 # ABSTRACT: js's type handler for type "all"
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Compiler::js::TH::all - js's type handler for type "all"
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Compiler::js::TH::all (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =for Pod::Coverage ^(clause_.+|superclause_.+)$
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Compiler/js/TH/any.pm ###
 package Data::Sah::Compiler::js::TH::any;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 #use Log::Any '$log';
 
 use Mo qw(build default);
 #use Role::Tiny::With;
 
 # Mo currently doesn't support multiple classes in 'extends'
 #extends
 #    'Data::Sah::Compiler::js::TH',
 #    'Data::Sah::Compiler::Prog::TH::any';
 
 use parent (
     'Data::Sah::Compiler::js::TH',
     'Data::Sah::Compiler::Prog::TH::any',
 );
 
 1;
 # ABSTRACT: js's type handler for type "any"
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Compiler::js::TH::any - js's type handler for type "any"
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Compiler::js::TH::any (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =for Pod::Coverage ^(clause_.+|superclause_.+)$
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Compiler/js/TH/array.pm ###
 package Data::Sah::Compiler::js::TH::array;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 #use Log::Any '$log';
 
 use Mo qw(build default);
 use Role::Tiny::With;
 
 extends 'Data::Sah::Compiler::js::TH';
 with 'Data::Sah::Type::array';
 
 sub handle_type {
     my ($self, $cd) = @_;
     my $c = $self->compiler;
 
     my $dt = $cd->{data_term};
     $cd->{_ccl_check_type} = "$dt instanceof Array";
 }
 
 my $STR = "JSON.stringify";
 
 sub superclause_comparable {
     my ($self, $which, $cd) = @_;
     my $c  = $self->compiler;
     my $ct = $cd->{cl_term};
     my $dt = $cd->{data_term};
 
     if ($which eq 'is') {
         $c->add_ccl($cd, "$STR($dt) == $STR($ct)");
     } elsif ($which eq 'in') {
         $c->add_ccl(
             $cd,
             "!($ct).every(function(x){return $STR(x) != $STR($dt) })");
     }
 }
 
 sub superclause_has_elems {
     my ($self_th, $which, $cd) = @_;
     my $c  = $self_th->compiler;
     my $cv = $cd->{cl_value};
     my $ct = $cd->{cl_term};
     my $dt = $cd->{data_term};
 
     if ($which eq 'len') {
         $c->add_ccl($cd, "($dt).length == $ct");
     } elsif ($which eq 'min_len') {
         $c->add_ccl($cd, "($dt).length >= $ct");
     } elsif ($which eq 'max_len') {
         $c->add_ccl($cd, "($dt).length <= $ct");
     } elsif ($which eq 'len_between') {
         if ($cd->{cl_is_expr}) {
             $c->add_ccl(
                 $cd, "($dt).length >= $ct\->[0] && ($dt).length >= $ct\->[1]");
         } else {
             # simplify code
             $c->add_ccl(
                 $cd, "($dt).length >= $cv->[0] && ($dt).length <= $cv->[1]");
         }
     } elsif ($which eq 'has') {
         $c->add_ccl(
             $cd,
             "($dt).map(function(x){return $STR(x)}).indexOf($STR($ct)) > -1");
     } elsif ($which eq 'each_index') {
         $self_th->gen_each($cd,
                            $c->expr_array_0_nmin1("($dt).length"), '_sahv_idx', '_sahv_idx');
     } elsif ($which eq 'each_elem') {
         $self_th->gen_each($cd,
                            $c->expr_array_0_nmin1("($dt).length"), '_sahv_idx', "$dt\[_sahv_idx]");
     } elsif ($which eq 'check_each_index') {
         $self_th->compiler->_die_unimplemented_clause($cd);
     } elsif ($which eq 'check_each_elem') {
         $self_th->compiler->_die_unimplemented_clause($cd);
     } elsif ($which eq 'uniq') {
         $self_th->compiler->_die_unimplemented_clause($cd);
     } elsif ($which eq 'exists') {
         $self_th->compiler->_die_unimplemented_clause($cd);
     }
 }
 
 sub clause_elems {
     my ($self_th, $cd) = @_;
     my $c  = $self_th->compiler;
     my $cv = $cd->{cl_value};
     my $dt = $cd->{data_term};
 
     local $cd->{_subdata_level} = $cd->{_subdata_level} + 1;
     my $use_dpath = $cd->{args}{return_type} ne 'bool';
 
     my $jccl;
     {
         local $cd->{ccls} = [];
         #local $cd->{args}{return_type} = 'bool';
 
         my $cdef = $cd->{clset}{"elems.create_default"} // 1;
         delete $cd->{uclset}{"elems.create_default"};
 
         for my $i (0..@$cv-1) {
             local $cd->{spath} = [@{$cd->{spath}}, $i];
             my $sch = $c->main->normalize_schema($cv->[$i]);
             my $edt = "$dt\[$i]";
             my %iargs = %{$cd->{args}};
             $iargs{outer_cd}             = $cd;
             $iargs{data_name}            = "$cd->{args}{data_name}_$i";
             $iargs{data_term}            = $edt;
             $iargs{schema}               = $sch;
             $iargs{schema_is_normalized} = 1;
             $iargs{indent_level}++;
             my $icd = $c->compile(%iargs);
             my @code = (
                 ($c->indent_str($cd), "(_sahv_dpath[-1] = $i),\n") x !!$use_dpath,
                 $icd->{result}, "\n",
             );
             my $ires = join("", @code);
             local $cd->{_debug_ccl_note} = "elem: $i";
             if ($cdef && defined($sch->[1]{default})) {
                 $c->add_ccl($cd, $ires);
             } else {
                 $c->add_ccl($cd, "($dt).length < ".($i+1)." || ($ires)");
             }
         }
         $jccl = $c->join_ccls(
             $cd, $cd->{ccls}, {err_msg => ''});
     }
     $c->add_ccl($cd, $jccl, {subdata=>1});
 }
 
 1;
 # ABSTRACT: js's type handler for type "array"
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Compiler::js::TH::array - js's type handler for type "array"
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Compiler::js::TH::array (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =for Pod::Coverage ^(clause_.+|superclause_.+)$
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Compiler/js/TH/bool.pm ###
 package Data::Sah::Compiler::js::TH::bool;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 #use Log::Any '$log';
 
 use Mo qw(build default);
 use Role::Tiny::With;
 
 extends 'Data::Sah::Compiler::js::TH';
 with 'Data::Sah::Type::bool';
 
 sub handle_type {
     my ($self, $cd) = @_;
     my $c = $self->compiler;
 
     my $dt = $cd->{data_term};
     $cd->{_ccl_check_type} = "typeof($dt)=='boolean' || typeof($dt)=='number' || typeof($dt)=='string'";
 }
 
 sub superclause_comparable {
     my ($self, $which, $cd) = @_;
     my $c  = $self->compiler;
     my $ct = $cd->{cl_term};
     my $dt = $cd->{data_term};
 
     if ($which eq 'is') {
         $c->add_ccl($cd, "!!($dt) == !!($ct)");
     } elsif ($which eq 'in') {
         $c->add_ccl($cd, "($ct).map(function(x){return !!x}).indexOf(!!($dt)) > -1");
     }
 }
 
 sub superclause_sortable {
     my ($self, $which, $cd) = @_;
     my $c  = $self->compiler;
     my $cv = $cd->{cl_value};
     my $ct = $cd->{cl_term};
     my $dt = $cd->{data_term};
 
     if ($which eq 'min') {
         $c->add_ccl($cd, "!!($dt) >= !!($ct)");
     } elsif ($which eq 'xmin') {
         $c->add_ccl($cd, "!!($dt) > !!($ct)");
     } elsif ($which eq 'max') {
         $c->add_ccl($cd, "!!($dt) <= !!($ct)");
     } elsif ($which eq 'xmax') {
         $c->add_ccl($cd, "!!($dt) < !!($ct)");
     } elsif ($which eq 'between') {
         if ($cd->{cl_is_expr}) {
             $c->add_ccl($cd, "!!($dt) >= !!($ct\->[0]) && ".
                             "!!($dt) <= !!($ct\->[1])");
         } else {
             # simplify code
             $c->add_ccl($cd, "!!($dt) >= !!($cv->[0]) && ".
                             "!!($dt) <= !!($cv->[1])");
         }
     } elsif ($which eq 'xbetween') {
         if ($cd->{cl_is_expr}) {
             $c->add_ccl($cd, "!!($dt) > !!($ct\->[0]) && ".
                             "!!($dt) < !!($ct\->[1])");
         } else {
             # simplify code
             $c->add_ccl($cd, "!!($dt) > !!($cv->[0]) && ".
                             "!!($dt) < !!($cv->[1])");
         }
     }
 }
 
 sub clause_is_true {
     my ($self, $cd) = @_;
     my $c  = $self->compiler;
     my $ct = $cd->{cl_term};
     my $dt = $cd->{data_term};
 
     $c->add_ccl($cd, "$ct ? !!($dt) : !(".$c->expr_defined($ct).") ? true : !($dt)");
 }
 
 1;
 # ABSTRACT: js's type handler for type "bool"
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Compiler::js::TH::bool - js's type handler for type "bool"
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Compiler::js::TH::bool (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =for Pod::Coverage ^(clause_.+|superclause_.+)$
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Compiler/js/TH/buf.pm ###
 package Data::Sah::Compiler::js::TH::buf;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 #use Log::Any '$log';
 
 use Mo qw(build default);
 use Role::Tiny::With;
 
 extends 'Data::Sah::Compiler::js::TH::str';
 with 'Data::Sah::Type::buf';
 
 1;
 # ABSTRACT: js's type handler for type "buf"
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Compiler::js::TH::buf - js's type handler for type "buf"
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Compiler::js::TH::buf (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =for Pod::Coverage ^(clause_.+|superclause_.+|handle_.+|before_.+|after_.+)$
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Compiler/js/TH/cistr.pm ###
 package Data::Sah::Compiler::js::TH::cistr;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 #use Log::Any '$log';
 
 use Mo qw(build default);
 use Role::Tiny::With;
 
 extends 'Data::Sah::Compiler::js::TH::str';
 with 'Data::Sah::Type::cistr';
 
 sub before_all_clauses {
     my ($self, $cd) = @_;
     my $c = $self->compiler;
     my $dt = $cd->{data_term};
 
     # XXX only do this when there are clauses
 
     # convert number to string
     $self->set_tmp_data_term($cd, "typeof($dt)=='number' ? ''+$dt : typeof($dt)=='string' ? ($dt).toLowerCase() : $dt");
 }
 
 sub after_all_clauses {
     my ($self, $cd) = @_;
     my $c = $self->compiler;
     my $dt = $cd->{data_term};
 
     $self->restore_data_term($cd);
 }
 
 sub superclause_comparable {
     my ($self, $which, $cd) = @_;
     my $c  = $self->compiler;
     my $ct = $cd->{cl_term};
     my $dt = $cd->{data_term};
 
     if ($which eq 'is') {
         $c->add_ccl($cd, "$dt == ($ct).toLowerCase()");
     } elsif ($which eq 'in') {
         $c->add_ccl($cd, "($ct).map(function(x) { return x.toLowerCase() }).indexOf($dt) > -1");
     }
 }
 
 sub superclause_sortable {
     my ($self, $which, $cd) = @_;
     my $c  = $self->compiler;
     my $cv = $cd->{cl_value};
     my $ct = $cd->{cl_term};
     my $dt = $cd->{data_term};
 
     if ($which eq 'min') {
         $c->add_ccl($cd, "$dt >= ($ct).toLowerCase()");
     } elsif ($which eq 'xmin') {
         $c->add_ccl($cd, "$dt > ($ct).toLowerCase()");
     } elsif ($which eq 'max') {
         $c->add_ccl($cd, "$dt <= ($ct).toLowerCase()");
     } elsif ($which eq 'xmax') {
         $c->add_ccl($cd, "$dt < ($ct).toLowerCase()");
     } elsif ($which eq 'between') {
         if ($cd->{cl_is_expr}) {
             $c->add_ccl($cd, "$dt >= (($ct)[0]).toLowerCase() && ".
                             "$dt <= (($ct)[1]).toLowerCase()");
         } else {
             # simplify code
             $c->add_ccl($cd, "$dt >= ".$c->literal(lc $cv->[0]).
                             " && $dt <= ".$c->literal(lc $cv->[1]));
         }
     } elsif ($which eq 'xbetween') {
         if ($cd->{cl_is_expr}) {
             $c->add_ccl($cd, "$dt > (($ct)[0]).toLowerCase() && ".
                             "$dt < (($ct)[1]).toLowerCase()");
         } else {
             # simplify code
             $c->add_ccl($cd, "$dt > ".$c->literal(lc $cv->[0]).
                             " && $dt < ".$c->literal(lc $cv->[1]));
         }
     }
 }
 
 sub superclause_has_elems {
     my ($self_th, $which, $cd) = @_;
     my $c  = $self_th->compiler;
     my $cv = $cd->{cl_value};
     my $ct = $cd->{cl_term};
     my $dt = $cd->{data_term};
 
     if ($which eq 'has') {
         $c->add_ccl($cd, "($dt).indexOf(($ct).toLowerCase()) > -1");
     } else {
         $self_th->SUPER::superclause_has_elems($which, $cd);
     }
 }
 
 sub clause_match {
     my ($self, $cd) = @_;
     my $c  = $self->compiler;
     my $cv = $cd->{cl_value};
     my $ct = $cd->{cl_term};
     my $dt = $cd->{data_term};
 
     my $re;
     if ($cd->{cl_is_expr}) {
         $re = $ct;
     } else {
         $re = $c->_str2reliteral($cd, $cv);
     }
 
     $c->add_ccl($cd, join(
         "",
         "(function(){ ",
         "var _sahv_match = true; ",
         "try { _sahv_match = ($dt).match(RegExp($re)) } catch(e) { if (e.name=='SyntaxError') _sahv_match = false } ",
         ($cd->{cl_is_expr} ?
              "return _sahv_match == !!($ct);" :
                  "return ".($cv ? '':'!')."!!_sahv_match;"),
         "} )()",
     ));
 }
 
 1;
 # ABSTRACT: js's type handler for type "cistr"
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Compiler::js::TH::cistr - js's type handler for type "cistr"
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Compiler::js::TH::cistr (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =for Pod::Coverage ^(clause_.+|superclause_.+|handle_.+|before_.+|after_.+)$
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Compiler/js/TH/code.pm ###
 package Data::Sah::Compiler::js::TH::code;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 #use Log::Any '$log';
 
 use Mo qw(build default);
 use Role::Tiny::With;
 
 extends 'Data::Sah::Compiler::js::TH';
 with 'Data::Sah::Type::code';
 
 sub handle_type {
     my ($self, $cd) = @_;
     my $c = $self->compiler;
 
     my $dt = $cd->{data_term};
     $cd->{_ccl_check_type} = "typeof($dt)=='function'";
 }
 
 1;
 # ABSTRACT: js's type handler for type "code"
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Compiler::js::TH::code - js's type handler for type "code"
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Compiler::js::TH::code (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =for Pod::Coverage ^(clause_.+|superclause_.+)$
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Compiler/js/TH/date.pm ###
 package Data::Sah::Compiler::js::TH::date;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 #use Log::Any '$log';
 
 use Mo qw(build default);
 use Role::Tiny::With;
 use Scalar::Util qw(blessed looks_like_number);
 
 extends 'Data::Sah::Compiler::js::TH';
 with 'Data::Sah::Type::date';
 
 my $epoch_low  = 10**8;
 my $epoch_high = 2**31;
 
 # Date() accept these arguments:
 # - Date(milliseconds epoch)
 # - Date(year, month, date, hour, minute, sec, millisec) tapi year=114 utk 2014, month=0 utk jan
 # - Date(datestring)
 # - Date(another Date object)
 # if arguments are invalid, Date() will still return a Date object,
 # but if we try to do d.getMonth() or d.getYear() it will return NaN
 #
 # to compare 2 date, we can use d1 > d2, d1 < d2, but for anything
 # involving =, we need to prefix using +: +d1 === +d2.
 
 sub expr_coerce_term {
     my ($self, $cd, $t) = @_;
 
     join(
         '',
         "(",
         "($t instanceof Date) ? $t : ",
         "typeof($t)=='number' ? (new Date($t * 1000)) : ",
         "parseFloat($t)==$t   ? (new Date(parseFloat($t)) * 1000) : ",
         "(new Date($t))",
         ")",
     );
 }
 
 sub expr_coerce_value {
     my ($self, $cd, $v) = @_;
 
     if (blessed($v) && $v->isa('DateTime')) {
         return join(
             '',
             "(new Date(",
             $v->year, ",",
             $v->month, ",",
             $v->day, ",",
             $v->hour, ",",
             $v->minute, ",",
             $v->second, ",",
             $v->millisecond,
             "))",
         );
     } elsif (looks_like_number($v) && $v >= 10**8 && $v <= 2**31) {
         return "(new Date($v*1000))";
     } elsif ($v =~ /\A([0-9]{4})-([0-9]{2})-([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})Z\z/) {
         require DateTime;
         eval { DateTime->new(year=>$1, month=>$2, day=>$3,
                              hour=>$4, minute=>$5, second=>$6,
                              time_zone=>'UTC') ; 1 }
             or die "Invalid date literal '$v': $@";
         return "(new Date(\"$v\"))";
     } elsif ($v =~ /\A([0-9]{4})-([0-9]{2})-([0-9]{2})\z/) {
         require DateTime;
         eval { DateTime->new(year=>$1, month=>$2, day=>$3) ; 1 }
             or die "Invalid date literal '$v': $@";
         return "(new Date(\"$v\"))";
     } else {
         die "Invalid date literal '$v'";
     }
 }
 
 sub handle_type {
     my ($self, $cd) = @_;
 
     my $dt = $cd->{data_term};
     $cd->{_ccl_check_type} = join(
         '',
         "(",
         "typeof($dt)=='number' ? ($dt >= $epoch_low && $dt <= $epoch_high) : ",
         "parseFloat($dt)==$dt ? (parseFloat($dt) >= $epoch_low && parseFloat($dt) <= $epoch_high) : ",
         "!isNaN((new Date($dt)).getYear())",
         ")",
     );
 }
 
 sub before_all_clauses {
     my ($self, $cd) = @_;
     my $c = $self->compiler;
     my $dt = $cd->{data_term};
 
     # XXX only do this when there are clauses
 
     # coerce to DateTime object during validation
     $self->set_tmp_data_term($cd, $self->expr_coerce_term($cd, $dt));
 }
 
 sub after_all_clauses {
     my ($self, $cd) = @_;
     my $c = $self->compiler;
     my $dt = $cd->{data_term};
 
     $self->restore_data_term($cd);
 }
 
 sub superclause_comparable {
     my ($self, $which, $cd) = @_;
     my $c  = $self->compiler;
     my $cv = $cd->{cl_value};
     my $ct = $cd->{cl_term};
     my $dt = $cd->{data_term};
 
     if ($which eq 'is') {
         if ($cd->{cl_is_expr}) {
             $ct = $self->expr_coerce_term($cd, $ct);
         } else {
             $ct = $self->expr_coerce_value($cd, $cv);
         }
         $c->add_ccl($cd, "+($dt) === +($ct)");
     } elsif ($which eq 'in') {
         $c->add_module('List::Util');
         if ($cd->{cl_is_expr}) {
             # i'm lazy, technical debt
             $c->_die($cd, "date's in clause with expression not yet supported");
         }
         $ct = '['.join(', ', map { "+(".$self->expr_coerce_value($cd, $_).")" } @$ct).']';
         $c->add_ccl($cd, "($ct).indexOf(+($dt)) > -1");
     }
 }
 
 sub superclause_sortable {
     my ($self, $which, $cd) = @_;
     my $c  = $self->compiler;
     my $cv = $cd->{cl_value};
     my $ct = $cd->{cl_term};
     my $dt = $cd->{data_term};
 
     if ($cd->{cl_is_expr}) {
         # i'm lazy, technical debt
         $c->_die($cd, "date's comparison with expression not yet supported");
     }
 
     if ($which eq 'min') {
         $c->add_ccl($cd, "+($dt) >= +(".$self->expr_coerce_value($cd, $cv).")");
     } elsif ($which eq 'xmin') {
         $c->add_ccl($cd, "+($dt) > +(".$self->expr_coerce_value($cd, $cv).")");
     } elsif ($which eq 'max') {
         $c->add_ccl($cd, "+($dt) <= +(".$self->expr_coerce_value($cd, $cv).")");
     } elsif ($which eq 'xmax') {
         $c->add_ccl($cd, "+($dt) < +(".$self->expr_coerce_value($cd, $cv).")");
     } elsif ($which eq 'between') {
         $c->add_ccl($cd, "+($dt) >= +(".$self->expr_coerce_value($cd, $cv->[0]).") && ".
                         "+($dt) <= +(".$self->expr_coerce_value($cd, $cv->[1]).")");
     } elsif ($which eq 'xbetween') {
         $c->add_ccl($cd, "+($dt) > +(".$self->expr_coerce_value($cd, $cv->[0]).") && ".
                         "+($dt) < +(".$self->expr_coerce_value($cd, $cv->[1]).")");
     }
 }
 
 1;
 # ABSTRACT: js's type handler for type "date"
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Compiler::js::TH::date - js's type handler for type "date"
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Compiler::js::TH::date (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =for Pod::Coverage ^(clause_.+|superclause_.+|handle_.+|before_.+|after_.+|expr_coerce_.+)$
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Compiler/js/TH/float.pm ###
 package Data::Sah::Compiler::js::TH::float;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 #use Log::Any '$log';
 
 use Mo qw(build default);
 use Role::Tiny::With;
 
 extends 'Data::Sah::Compiler::js::TH::num';
 with 'Data::Sah::Type::float';
 
 sub handle_type {
     my ($self, $cd) = @_;
     my $c = $self->compiler;
     my $dt = $cd->{data_term};
 
     $cd->{_ccl_check_type} = "(typeof($dt)=='number' || parseFloat($dt)==$dt)";
 }
 
 sub clause_is_nan {
     my ($self, $cd) = @_;
     my $c  = $self->compiler;
     my $ct = $cd->{cl_term};
     my $dt = $cd->{data_term};
 
     if ($cd->{cl_is_expr}) {
         $c->add_ccl(
             $cd,
             join(
                 "",
                 "$ct ? isNaN($dt) : ",
                 $self->expr_defined($ct), " ? !isNaN($dt) : true",
             )
         );
     } else {
         if ($cd->{cl_value}) {
             $c->add_ccl($cd, "isNaN($dt)");
         } elsif (defined $cd->{cl_value}) {
             $c->add_ccl($cd, "!isNaN($dt)");
         }
     }
 }
 
 sub clause_is_pos_inf {
     my ($self, $cd) = @_;
     my $c  = $self->compiler;
     my $ct = $cd->{cl_term};
     my $dt = $cd->{data_term};
 
     if ($cd->{cl_is_expr}) {
         $c->add_ccl(
             $cd,
             join(
                 "",
                 "$ct ? $dt == Infinity : ",
                 $self->expr_defined($ct), " ? $dt != Infinity : true",
             )
         );
     } else {
         if ($cd->{cl_value}) {
             $c->add_ccl($cd, "$dt == Infinity");
         } elsif (defined $cd->{cl_value}) {
             $c->add_ccl($cd, "$dt != Infinity");
         }
     }
 }
 
 sub clause_is_neg_inf {
     my ($self, $cd) = @_;
     my $c  = $self->compiler;
     my $ct = $cd->{cl_term};
     my $dt = $cd->{data_term};
 
     if ($cd->{cl_is_expr}) {
         $c->add_ccl(
             $cd,
             join(
                 "",
                 "$ct ? $dt == -Infinity : ",
                 $self->expr_defined($ct), " ? $dt != -Infinity : true",
             )
         );
     } else {
         if ($cd->{cl_value}) {
             $c->add_ccl($cd, "$dt == -Infinity");
         } elsif (defined $cd->{cl_value}) {
             $c->add_ccl($cd, "$dt != -Infinity");
         }
     }
 }
 
 sub clause_is_inf {
     my ($self, $cd) = @_;
     my $c  = $self->compiler;
     my $ct = $cd->{cl_term};
     my $dt = $cd->{data_term};
 
     if ($cd->{cl_is_expr}) {
         $c->add_ccl(
             $cd,
             join(
                 "",
                 "$ct ? Math.abs($dt) == Infinity : ",
                 $self->expr_defined($ct), " ? Math.abs($dt) != Infinity : true",
             )
         );
     } else {
         if ($cd->{cl_value}) {
             $c->add_ccl($cd, "Math.abs($dt) == Infinity");
         } elsif (defined $cd->{cl_value}) {
             $c->add_ccl($cd, "Math.abs($dt) != Infinity");
         }
     }
 }
 
 1;
 # ABSTRACT: js's type handler for type "float"
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Compiler::js::TH::float - js's type handler for type "float"
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Compiler::js::TH::float (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =for Pod::Coverage ^(compiler|clause_.+|handle_.+)$
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Compiler/js/TH/hash.pm ###
 package Data::Sah::Compiler::js::TH::hash;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 #use Log::Any '$log';
 
 use Mo qw(build default);
 use Role::Tiny::With;
 
 extends 'Data::Sah::Compiler::js::TH';
 with 'Data::Sah::Type::hash';
 
 sub handle_type {
     my ($self, $cd) = @_;
     my $c = $self->compiler;
 
     my $dt = $cd->{data_term};
     # XXX also exclude RegExp, ...
     $cd->{_ccl_check_type} = "typeof($dt)=='object' && !($dt instanceof Array)";
 }
 
 my $STR = "JSON.stringify";
 
 sub superclause_comparable {
     my ($self, $which, $cd) = @_;
     my $c  = $self->compiler;
     my $ct = $cd->{cl_term};
     my $dt = $cd->{data_term};
 
     if ($which eq 'is') {
         $c->add_ccl($cd, "$STR($dt) == $STR($ct)");
     } elsif ($which eq 'in') {
         $c->add_ccl(
             $cd,
             "!($ct).every(function(x){return $STR(x) != $STR($dt) })");
     }
 }
 
 sub superclause_has_elems {
     my ($self_th, $which, $cd) = @_;
     my $c  = $self_th->compiler;
     my $cv = $cd->{cl_value};
     my $ct = $cd->{cl_term};
     my $dt = $cd->{data_term};
 
     # XXX need to optimize, Object.keys(h).length is not efficient
 
     if ($which eq 'len') {
         $c->add_ccl($cd, "Object.keys($dt).length == $ct");
     } elsif ($which eq 'min_len') {
         $c->add_ccl($cd, "Object.keys($dt).length >= $ct");
     } elsif ($which eq 'max_len') {
         $c->add_ccl($cd, "Object.keys($dt).length <= $ct");
     } elsif ($which eq 'len_between') {
         if ($cd->{cl_is_expr}) {
             $c->add_ccl(
                 $cd, "Object.keys($dt).length >= $ct\->[0] && ".
                     "Object.keys($dt).length >= $ct\->[1]");
         } else {
             # simplify code
             $c->add_ccl(
                 $cd, "Object.keys($dt).length >= $cv->[0] && ".
                     "Object.keys($dt).length <= $cv->[1]");
         }
     } elsif ($which eq 'has') {
         $c->add_ccl(
             $cd,
             "!Object.keys($dt).every(function(x){return $STR(($dt)[x]) != $STR($ct) })");
     } elsif ($which eq 'each_index') {
         $self_th->gen_each($cd, "Object.keys($dt)", '_sahv_idx', '_sahv_idx');
     } elsif ($which eq 'each_elem') {
         $self_th->gen_each($cd, "Object.keys($dt)", '_sahv_idx', "$dt\[_sahv_idx]");
     } elsif ($which eq 'check_each_index') {
         $self_th->compiler->_die_unimplemented_clause($cd);
     } elsif ($which eq 'check_each_elem') {
         $self_th->compiler->_die_unimplemented_clause($cd);
     } elsif ($which eq 'uniq') {
         $self_th->compiler->_die_unimplemented_clause($cd);
     } elsif ($which eq 'exists') {
         $self_th->compiler->_die_unimplemented_clause($cd);
     }
 }
 
 sub _clause_keys_or_re_keys {
     my ($self_th, $which, $cd) = @_;
     my $c  = $self_th->compiler;
     my $cv = $cd->{cl_value};
     my $dt = $cd->{data_term};
 
     local $cd->{_subdata_level} = $cd->{_subdata_level} + 1;
     my $use_dpath = $cd->{args}{return_type} ne 'bool';
 
     # we handle subdata manually here, because in generated code for
     # keys.restrict, we haven't delved into the keys
 
     my $jccl;
     {
         local $cd->{ccls} = [];
 
         my $chk_x_unknown;
         my $filt_x_unknown;
         if ($which eq 'keys') {
             my $lit_valid_keys = $c->literal([keys %$cv]);
             $chk_x_unknown  = "$lit_valid_keys.indexOf(x) > -1";
             $filt_x_unknown = "$lit_valid_keys.indexOf(x) == -1";
         } else {
             my $lit_regexes = "[".
                 join(",", map { $c->_str2reliteral($cd, $_) }
                          keys %$cv)."]";
             $chk_x_unknown  = "!$lit_regexes.every(function(y) { return !x.match(y) })";
             $filt_x_unknown = "$lit_regexes.every(function(y) { return !x.match(y) })";
         }
 
         if ($cd->{clset}{"$which.restrict"} // 1) {
             local $cd->{_debug_ccl_note} = "$which.restrict";
             $c->add_ccl(
                 $cd,
                 "Object.keys($dt).every(function(x){ return $chk_x_unknown })",
                 {
                     err_msg => 'TMP1',
                     err_expr => join(
                         "",
                         $c->literal($c->_xlt(
                             $cd, "hash contains ".
                                 "unknown field(s) (%s)")),
                         '.replace("%s", ',
                         "Object.keys($dt).filter(function(x){ return $filt_x_unknown }).join(', ')",
                         ')',
                     ),
                 },
             );
         }
         delete $cd->{uclset}{"$which.restrict"};
 
         my $cdef;
         if ($which eq 'keys') {
             $cdef = $cd->{clset}{"keys.create_default"} // 1;
             delete $cd->{uclset}{"keys.create_default"};
         }
 
         #local $cd->{args}{return_type} = 'bool';
         my $nkeys = scalar(keys %$cv);
         my $i = 0;
         for my $k (sort keys %$cv) {
             my $kre = $c->_str2reliteral($cd, $k);
             local $cd->{spath} = [@{ $cd->{spath} }, $k];
             ++$i;
             my $sch = $c->main->normalize_schema($cv->{$k});
             my $kdn = $k; $kdn =~ s/\W+/_/g;
             my $klit = $which eq 're_keys' ? 'x' : $c->literal($k);
             my $kdt = "$dt\[$klit]";
             my %iargs = %{$cd->{args}};
             $iargs{outer_cd}             = $cd;
             $iargs{data_name}            = $kdn;
             $iargs{data_term}            = $kdt;
             $iargs{schema}               = $sch;
             $iargs{schema_is_normalized} = 1;
             $iargs{indent_level}++;
             my $icd = $c->compile(%iargs);
 
             # should we set default for hash value?
             my $sdef = $cdef && defined($sch->[1]{default});
 
             $c->add_var($cd, '_sahv_stack', []) if $use_dpath;
 
             my @code = (
                 ($c->indent_str($cd), "(_sahv_dpath.push(null), _sahv_stack.push(null), _sahv_stack[_sahv_stack.length-1] = \n")
                     x !!($use_dpath && $i == 1),
 
                 # for re_keys, we iterate over all data's keys which match regex
                 ("Object.keys($dt).every(function(x) { return (")
                     x !!($which eq 're_keys'),
 
                 $which eq 're_keys' ? "!x.match($kre) || (" :
                     ($sdef ? "" : "!$dt.hasOwnProperty($klit) || ("),
 
                 ($c->indent_str($cd), "(_sahv_dpath[_sahv_dpath.length-1] = ".
                      ($which eq 're_keys' ? 'x' : $klit)."),\n") x !!$use_dpath,
                 $icd->{result}, "\n",
 
                 $which eq 're_keys' || !$sdef ? ")" : "",
 
                 # close iteration over all data's keys which match regex
                 (") })")
                     x !!($which eq 're_keys'),
 
                 ($c->indent_str($cd), "), _sahv_dpath.pop(), _sahv_stack.pop()\n")
                     x !!($use_dpath && $i == $nkeys),
             );
             my $ires = join("", @code);
             local $cd->{_debug_ccl_note} = "$which: ".$c->literal($k);
             $c->add_ccl($cd, $ires);
         }
         $jccl = $c->join_ccls(
             $cd, $cd->{ccls}, {err_msg => ''});
     }
     $c->add_ccl($cd, $jccl, {});
 }
 
 sub clause_keys {
     my ($self, $cd) = @_;
     $self->_clause_keys_or_re_keys('keys', $cd);
 }
 
 sub clause_re_keys {
     my ($self, $cd) = @_;
     $self->_clause_keys_or_re_keys('re_keys', $cd);
 }
 
 sub clause_req_keys {
     my ($self, $cd) = @_;
     my $c  = $self->compiler;
     my $ct = $cd->{cl_term};
     my $dt = $cd->{data_term};
 
     $c->add_ccl(
       $cd,
       "($ct).every(function(x){ return Object.keys($dt).indexOf(x) > -1 })", # XXX cache Object.keys($dt)
       {
         err_msg => 'TMP',
         err_expr => join(
             "",
             $c->literal($c->_xlt(
                 $cd, "hash has missing required field(s) (%s)")),
             '.replace("%s", ',
             "($ct).filter(function(x){ return Object.keys($dt).indexOf(x) == -1 }).join(', ')",
             ')',
         ),
       }
     );
 }
 
 sub clause_allowed_keys {
     my ($self, $cd) = @_;
     my $c  = $self->compiler;
     my $ct = $cd->{cl_term};
     my $dt = $cd->{data_term};
 
     $c->add_ccl(
       $cd,
       "Object.keys($dt).every(function(x){ return ($ct).indexOf(x) > -1 })", # XXX cache Object.keys($ct)
       {
         err_msg => 'TMP',
         err_expr => join(
             "",
             $c->literal($c->_xlt(
                 $cd, "hash contains non-allowed field(s) (%s)")),
             '.replace("%s", ',
             "Object.keys($dt).filter(function(x){ return ($ct).indexOf(x) == -1 }).join(', ')",
             ')',
         ),
       }
     );
 }
 
 sub clause_allowed_keys_re {
     my ($self, $cd) = @_;
     my $c  = $self->compiler;
     #my $ct = $cd->{cl_term};
     my $cv = $cd->{cl_value};
     my $dt = $cd->{data_term};
 
     if ($cd->{cl_is_expr}) {
         # i'm lazy atm and does not need expr yet
         $c->_die_unimplemented_clause($cd, "with expr");
     }
 
     my $re = $c->_str2reliteral($cd, $cv);
     $c->add_ccl(
       $cd,
       "Object.keys($dt).every(function(x){ return x.match(RegExp($re)) })",
       {
         err_msg => 'TMP',
         err_expr => join(
             "",
             $c->literal($c->_xlt(
                 $cd, "hash contains non-allowed field(s) (%s)")),
             '.replace("%s", ',
             "Object.keys($dt).filter(function(x){ return !x.match(RegExp($re)) }).join(', ')",
             ')',
         ),
       }
     );
 }
 
 sub clause_forbidden_keys {
     my ($self, $cd) = @_;
     my $c  = $self->compiler;
     my $ct = $cd->{cl_term};
     my $dt = $cd->{data_term};
 
     $c->add_ccl(
       $cd,
       "Object.keys($dt).every(function(x){ return ($ct).indexOf(x) == -1 })", # XXX cache Object.keys($ct)
       {
         err_msg => 'TMP',
         err_expr => join(
             "",
             $c->literal($c->_xlt(
                 $cd, "hash contains forbidden field(s) (%s)")),
             '.replace("%s", ',
             "Object.keys($dt).filter(function(x){ return ($ct).indexOf(x) > -1 }).join(', ')",
             ')',
         ),
       }
     );
 }
 
 sub clause_forbidden_keys_re {
     my ($self, $cd) = @_;
     my $c  = $self->compiler;
     #my $ct = $cd->{cl_term};
     my $cv = $cd->{cl_value};
     my $dt = $cd->{data_term};
 
     if ($cd->{cl_is_expr}) {
         # i'm lazy atm and does not need expr yet
         $c->_die_unimplemented_clause($cd, "with expr");
     }
 
     my $re = $c->_str2reliteral($cd, $cv);
     $c->add_ccl(
       $cd,
       "Object.keys($dt).every(function(x){ return !x.match(RegExp($re)) })",
       {
         err_msg => 'TMP',
         err_expr => join(
             "",
             $c->literal($c->_xlt(
                 $cd, "hash contains forbidden field(s) (%s)")),
             '.replace("%s", ',
             "Object.keys($dt).filter(function(x){ return x.match(RegExp($re)) }).join(', ')",
             ')',
         ),
       }
     );
 }
 
 sub clause_choose_one_key {
     my ($self, $cd) = @_;
     my $c  = $self->compiler;
     my $ct = $cd->{cl_term};
     my $dt = $cd->{data_term};
 
     $c->add_ccl(
         $cd,
         join(
             "",
             "($ct).map(function(x) {",
             "  return ($dt).hasOwnProperty(x) ? 1:0",
             "}).reduce(function(a,b){ return a+b }) <= 1",
         ),
         {},
     );
 }
 
 sub clause_choose_all_keys {
     my ($self, $cd) = @_;
     my $c  = $self->compiler;
     my $ct = $cd->{cl_term};
     my $dt = $cd->{data_term};
 
     $c->add_ccl(
         $cd,
         join(
             "",
             "[0, ($ct).length].indexOf(",
             "  ($ct).map(function(x) {",
             "    return ($dt).hasOwnProperty(x) ? 1:0",
             "  }).reduce(function(a,b){ return a+b })",
             ") >= 0",
         ),
         {},
     );
 }
 
 sub clause_req_one_key {
     my ($self, $cd) = @_;
     my $c  = $self->compiler;
     my $ct = $cd->{cl_term};
     my $dt = $cd->{data_term};
 
     $c->add_ccl(
         $cd,
         join(
             "",
             "($ct).map(function(x) {",
             "  return ($dt).hasOwnProperty(x) ? 1:0",
             "}).reduce(function(a,b){ return a+b }) == 1",
         ),
         {},
     );
 }
 
 sub clause_dep_any {
     my ($self, $cd) = @_;
     my $c  = $self->compiler;
     my $ct = $cd->{cl_term};
     my $dt = $cd->{data_term};
 
     $c->add_ccl(
         $cd,
         join(
             "",
             "(function(_sahv_ct, _sahv_has_prereq, _sahv_has_dep) {", # a trick to have lexical variable like 'let', 'let' is only supported in js >= 1.7 (ES6)
             "  _sahv_ct = $ct; ",
             "  _sahv_has_prereq = (_sahv_ct[1]).map(function(x) {",
             "    return ($dt).hasOwnProperty(x) ? 1:0",
             "  }).reduce(function(a,b){ return a+b }) > 0; ",
             "  _sahv_has_dep    = (_sahv_ct[0].constructor===Array ? _sahv_ct[0] : [_sahv_ct[0]]).map(function(x) {",
             "    return ($dt).hasOwnProperty(x) ? 1:0",
             "  }).reduce(function(a,b){ return a+b }) > 0; ",
             "  return !_sahv_has_dep || _sahv_has_prereq",
             "})()",
         ),
         {},
     );
 }
 
 sub clause_dep_all {
     my ($self, $cd) = @_;
     my $c  = $self->compiler;
     my $ct = $cd->{cl_term};
     my $dt = $cd->{data_term};
 
     $c->add_ccl(
         $cd,
         join(
             "",
             "(function(_sahv_ct, _sahv_has_prereq, _sahv_has_dep) {", # a trick to have lexical variable like 'let', 'let' is only supported in js >= 1.7 (ES6)
             "  _sahv_ct = $ct; ",
             "  _sahv_has_prereq = (_sahv_ct[1]).map(function(x) {",
             "    return ($dt).hasOwnProperty(x) ? 1:0",
             "  }).reduce(function(a,b){ return a+b }) == _sahv_ct[1].length; ",
             "  _sahv_has_dep    = (_sahv_ct[0].constructor===Array ? _sahv_ct[0] : [_sahv_ct[0]]).map(function(x) {",
             "    return ($dt).hasOwnProperty(x) ? 1:0",
             "  }).reduce(function(a,b){ return a+b }) > 0; ",
             "  return !_sahv_has_dep || _sahv_has_prereq",
             "})()",
         ),
         {},
     );
 }
 
 sub clause_req_dep_any {
     my ($self, $cd) = @_;
     my $c  = $self->compiler;
     my $ct = $cd->{cl_term};
     my $dt = $cd->{data_term};
 
     $c->add_ccl(
         $cd,
         join(
             "",
             "(function(_sahv_ct, _sahv_has_prereq, _sahv_has_dep) {", # a trick to have lexical variable like 'let', 'let' is only supported in js >= 1.7 (ES6)
             "  _sahv_ct = $ct; ",
             "  _sahv_has_prereq = (_sahv_ct[1]).map(function(x) {",
             "    return ($dt).hasOwnProperty(x) ? 1:0",
             "  }).reduce(function(a,b){ return a+b }) > 0; ",
             "  _sahv_has_dep    = (_sahv_ct[0].constructor===Array ? _sahv_ct[0] : [_sahv_ct[0]]).map(function(x) {",
             "    return ($dt).hasOwnProperty(x) ? 1:0",
             "  }).reduce(function(a,b){ return a+b }) > 0; ",
             "  return _sahv_has_dep || !_sahv_has_prereq",
             "})()",
         ),
         {},
     );
 }
 
 sub clause_req_dep_all {
     my ($self, $cd) = @_;
     my $c  = $self->compiler;
     my $ct = $cd->{cl_term};
     my $dt = $cd->{data_term};
 
     $c->add_ccl(
         $cd,
         join(
             "",
             "(function(_sahv_ct, _sahv_has_prereq, _sahv_has_dep) {", # a trick to have lexical variable like 'let', 'let' is only supported in js >= 1.7 (ES6)
             "  _sahv_ct = $ct; ",
             "  _sahv_has_prereq = (_sahv_ct[1]).map(function(x) {",
             "    return ($dt).hasOwnProperty(x) ? 1:0",
             "  }).reduce(function(a,b){ return a+b }) == _sahv_ct[1].length; ",
             "  _sahv_has_dep    = (_sahv_ct[0].constructor===Array ? _sahv_ct[0] : [_sahv_ct[0]]).map(function(x) {",
             "    return ($dt).hasOwnProperty(x) ? 1:0",
             "  }).reduce(function(a,b){ return a+b }) > 0; ",
             "  return _sahv_has_dep || !_sahv_has_prereq",
             "})()",
         ),
         {},
     );
 }
 
 1;
 # ABSTRACT: js's type handler for type "hash"
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Compiler::js::TH::hash - js's type handler for type "hash"
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Compiler::js::TH::hash (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =for Pod::Coverage ^(clause_.+|superclause_.+)$
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Compiler/js/TH/int.pm ###
 package Data::Sah::Compiler::js::TH::int;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 #use Log::Any '$log';
 
 use Mo qw(build default);
 use Role::Tiny::With;
 
 extends 'Data::Sah::Compiler::js::TH::num';
 with 'Data::Sah::Type::int';
 
 sub handle_type {
     my ($self, $cd) = @_;
     my $c = $self->compiler;
     my $dt = $cd->{data_term};
 
     $cd->{_ccl_check_type} = "(typeof($dt)=='number' && Math.round($dt)==$dt || parseInt($dt)==$dt)";
 }
 
 sub clause_div_by {
     my ($self, $cd) = @_;
     my $c  = $self->compiler;
     my $ct = $cd->{cl_term};
     my $dt = $cd->{data_term};
 
     $c->add_ccl($cd, "$dt % $ct == 0");
 }
 
 sub clause_mod {
     my ($self, $cd) = @_;
     my $c  = $self->compiler;
     my $ct = $cd->{cl_term};
     my $dt = $cd->{data_term};
 
     $c->add_ccl($cd, "$dt % $ct\[0] == $ct\[1]");
 }
 
 1;
 # ABSTRACT: js's type handler for type "int"
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Compiler::js::TH::int - js's type handler for type "int"
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Compiler::js::TH::int (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =for Pod::Coverage ^(clause_.+|superclause_.+)$
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Compiler/js/TH/num.pm ###
 package Data::Sah::Compiler::js::TH::num;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 #use Log::Any '$log';
 
 use Mo qw(build default);
 use Role::Tiny::With;
 
 extends 'Data::Sah::Compiler::js::TH';
 with 'Data::Sah::Type::num';
 
 sub handle_type {
     my ($self, $cd) = @_;
     my $c = $self->compiler;
     my $dt = $cd->{data_term};
 
     $cd->{_ccl_check_type} = "(typeof($dt)=='number' || parseFloat($dt)==$dt)";
 }
 
 sub before_all_clauses {
     my ($self, $cd) = @_;
     my $c = $self->compiler;
     my $dt = $cd->{data_term};
 
     # XXX only do this when there are clauses
 
     # convert non-number to number, if we need further testing like <, >=, etc.
     $self->set_tmp_data_term(
         $cd, "typeof($dt)=='number' ? $dt : parseFloat($dt)");
 }
 
 sub after_all_clauses {
     my ($self, $cd) = @_;
     my $c = $self->compiler;
     my $dt = $cd->{data_term};
 
     $self->restore_data_term($cd);
 }
 
 sub superclause_comparable {
     my ($self, $which, $cd) = @_;
     my $c  = $self->compiler;
     my $ct = $cd->{cl_term};
     my $dt = $cd->{data_term};
 
     if ($which eq 'is') {
         $c->add_ccl($cd, "$dt == $ct");
     } elsif ($which eq 'in') {
         $c->add_ccl($cd, "($ct).indexOf($dt) > -1");
     }
 }
 
 sub superclause_sortable {
     my ($self, $which, $cd) = @_;
     my $c  = $self->compiler;
     my $cv = $cd->{cl_value};
     my $ct = $cd->{cl_term};
     my $dt = $cd->{data_term};
 
     if ($which eq 'min') {
         $c->add_ccl($cd, "$dt >= $ct");
     } elsif ($which eq 'xmin') {
         $c->add_ccl($cd, "$dt > $ct");
     } elsif ($which eq 'max') {
         $c->add_ccl($cd, "$dt <= $ct");
     } elsif ($which eq 'xmax') {
         $c->add_ccl($cd, "$dt < $ct");
     } elsif ($which eq 'between') {
         if ($cd->{cl_is_expr}) {
             $c->add_ccl($cd, "$dt >= $ct\[0] && $dt <= $ct\[1]");
         } else {
             # simplify code
             $c->add_ccl($cd, "$dt >= $cv->[0] && $dt <= $cv->[1]");
         }
     } elsif ($which eq 'xbetween') {
         if ($cd->{cl_is_expr}) {
             $c->add_ccl($cd, "$dt > $ct\[0] && $dt < $ct\[1]");
         } else {
             # simplify code
             $c->add_ccl($cd, "$dt > $cv->[0] && $dt < $cv->[1]");
         }
     }
 }
 
 1;
 # ABSTRACT: js's type handler for type "num"
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Compiler::js::TH::num - js's type handler for type "num"
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Compiler::js::TH::num (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =for Pod::Coverage ^(clause_.+|superclause_.+|before_.+|after_.+)$
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Compiler/js/TH/obj.pm ###
 package Data::Sah::Compiler::js::TH::obj;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 #use Log::Any '$log';
 
 use Mo qw(build default);
 use Role::Tiny::With;
 
 extends 'Data::Sah::Compiler::js::TH';
 with 'Data::Sah::Type::obj';
 
 sub handle_type {
     my ($self, $cd) = @_;
     my $c = $self->compiler;
     my $dt = $cd->{data_term};
 
     $cd->{_ccl_check_type} = "typeof($dt) == 'object'";
 }
 
 sub clause_can {
     my ($self, $cd) = @_;
     my $c  = $self->compiler;
     my $ct = $cd->{cl_term};
     my $dt = $cd->{data_term};
 
     $c->add_ccl($cd, "typeof($dt\[$ct])=='function'");
     # for property: ($dt).hasOwnProperty($ct)
 }
 
 sub clause_isa {
     my ($self, $cd) = @_;
     my $c  = $self->compiler;
     my $ct = $cd->{cl_term};
     my $dt = $cd->{data_term};
 
     $c->_die_unimplemented_clause($cd);
     # doesn't work? in nodejs?
     #$c->add_ccl($cd, "$dt instanceOf global($ct)");
 }
 
 1;
 # ABSTRACT: js's type handler for type "obj"
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Compiler::js::TH::obj - js's type handler for type "obj"
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Compiler::js::TH::obj (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =for Pod::Coverage ^(clause_.+|superclause_.+)$
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Compiler/js/TH/re.pm ###
 package Data::Sah::Compiler::js::TH::re;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 #use Log::Any '$log';
 
 use Mo qw(build default);
 use Role::Tiny::With;
 
 extends 'Data::Sah::Compiler::js::TH';
 with 'Data::Sah::Type::re';
 
 # XXX prefilter to convert string to regex object
 
 sub handle_type {
     my ($self, $cd) = @_;
     my $c = $self->compiler;
 
     my $dt = $cd->{data_term};
     $cd->{_ccl_check_type} = "$dt instanceof RegExp";
 }
 
 1;
 # ABSTRACT: js's type handler for type "re"
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Compiler::js::TH::re - js's type handler for type "re"
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Compiler::js::TH::re (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =for Pod::Coverage ^(clause_.+|superclause_.+)$
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Compiler/js/TH/str.pm ###
 package Data::Sah::Compiler::js::TH::str;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 #use Log::Any '$log';
 
 use Mo qw(build default);
 use Role::Tiny::With;
 
 extends 'Data::Sah::Compiler::js::TH';
 with 'Data::Sah::Type::str';
 
 sub handle_type {
     my ($self, $cd) = @_;
     my $c = $self->compiler;
 
     my $dt = $cd->{data_term};
     $cd->{_ccl_check_type} = "typeof($dt)=='string' || typeof($dt)=='number'";
 }
 
 sub before_all_clauses {
     my ($self, $cd) = @_;
     my $c = $self->compiler;
     my $dt = $cd->{data_term};
 
     # XXX only do this when there are clauses
 
     # convert number to string
     $self->set_tmp_data_term($cd, "typeof($dt)=='number' ? ''+$dt : $dt");
 }
 
 sub after_all_clauses {
     my ($self, $cd) = @_;
     my $c = $self->compiler;
     my $dt = $cd->{data_term};
 
     $self->restore_data_term($cd);
 }
 
 sub superclause_comparable {
     my ($self, $which, $cd) = @_;
     my $c  = $self->compiler;
     my $ct = $cd->{cl_term};
     my $dt = $cd->{data_term};
 
     if ($which eq 'is') {
         $c->add_ccl($cd, "$dt == $ct");
     } elsif ($which eq 'in') {
         $c->add_ccl($cd, "($ct).indexOf($dt) > -1");
     }
 }
 
 sub superclause_sortable {
     my ($self, $which, $cd) = @_;
     my $c  = $self->compiler;
     my $cv = $cd->{cl_value};
     my $ct = $cd->{cl_term};
     my $dt = $cd->{data_term};
 
     if ($which eq 'min') {
         $c->add_ccl($cd, "$dt >= $ct");
     } elsif ($which eq 'xmin') {
         $c->add_ccl($cd, "$dt > $ct");
     } elsif ($which eq 'max') {
         $c->add_ccl($cd, "$dt <= $ct");
     } elsif ($which eq 'xmax') {
         $c->add_ccl($cd, "$dt < $ct");
     } elsif ($which eq 'between') {
         if ($cd->{cl_is_expr}) {
             $c->add_ccl($cd, "$dt >= ($ct)[0] && $dt <= ($ct)[1]");
         } else {
             # simplify code
             $c->add_ccl($cd, "$dt >= ".$c->literal($cv->[0]).
                             " && $dt <= ".$c->literal($cv->[1]));
         }
     } elsif ($which eq 'xbetween') {
         if ($cd->{cl_is_expr}) {
             $c->add_ccl($cd, "$dt > ($ct)[0] && $dt < ($ct)[1]");
         } else {
             # simplify code
             $c->add_ccl($cd, "$dt > ".$c->literal($cv->[0]).
                             " && $dt < ".$c->literal($cv->[1]));
         }
     }
 }
 
 sub superclause_has_elems {
     my ($self_th, $which, $cd) = @_;
     my $c  = $self_th->compiler;
     my $cv = $cd->{cl_value};
     my $ct = $cd->{cl_term};
     my $dt = $cd->{data_term};
 
     if ($which eq 'len') {
         $c->add_ccl($cd, "($dt).length == $ct");
     } elsif ($which eq 'min_len') {
         $c->add_ccl($cd, "($dt).length >= $ct");
     } elsif ($which eq 'max_len') {
         $c->add_ccl($cd, "($dt).length <= $ct");
     } elsif ($which eq 'len_between') {
         if ($cd->{cl_is_expr}) {
             $c->add_ccl(
                 $cd, "($dt).length >= ($ct)[0] && ".
                     "($dt).length >= ($ct)[1]");
         } else {
             # simplify code
             $c->add_ccl(
                 $cd, "($dt).length >= $cv->[0] && ".
                     "($dt).length <= $cv->[1]");
         }
     } elsif ($which eq 'has') {
         $c->add_ccl($cd, "($dt).indexOf($ct) > -1");
     } elsif ($which eq 'each_index') {
         $self_th->gen_each($cd, $c->expr_array_0_nmin1("($dt).length"), '_sahv_idx', '_sahv_idx');
     } elsif ($which eq 'each_elem') {
         $self_th->gen_each($cd, $c->expr_array_0_nmin1("($dt).length"), '_sahv_idx', "$dt.charAt(_sahv_idx)");
     } elsif ($which eq 'check_each_index') {
         $self_th->compiler->_die_unimplemented_clause($cd);
     } elsif ($which eq 'check_each_elem') {
         $self_th->compiler->_die_unimplemented_clause($cd);
     } elsif ($which eq 'uniq') {
         $self_th->compiler->_die_unimplemented_clause($cd);
     } elsif ($which eq 'exists') {
         $self_th->compiler->_die_unimplemented_clause($cd);
     }
 }
 
 sub clause_encoding {
     my ($self, $cd) = @_;
     my $c  = $self->compiler;
     my $cv = $cd->{cl_value};
     my $ct = $cd->{cl_term};
     my $dt = $cd->{data_term};
 
     $c->_die($cd, "Only 'utf8' encoding is currently supported")
         unless $cv eq 'utf8';
     # currently does nothing
 }
 
 sub clause_match {
     my ($self, $cd) = @_;
     my $c  = $self->compiler;
     my $cv = $cd->{cl_value};
     my $ct = $cd->{cl_term};
     my $dt = $cd->{data_term};
 
     my $re;
     if ($cd->{cl_is_expr}) {
         $re = $ct;
     } else {
         $re = $c->_str2reliteral($cd, $cv);
     }
 
     $c->add_ccl($cd, join(
         "",
         "(function(){ ",
         "var _sahv_match = true; ",
         "try { _sahv_match = ($dt).match(RegExp($re)) } catch(e) { if (e.name=='SyntaxError') _sahv_match = false } ",
         ($cd->{cl_is_expr} ?
              "return _sahv_match == !!($ct);" :
                  "return ".($cv ? '':'!')."!!_sahv_match;"),
         "} )()",
     ));
 }
 
 sub clause_is_re {
     my ($self, $cd) = @_;
     my $c  = $self->compiler;
     my $cv = $cd->{cl_value};
     my $ct = $cd->{cl_term};
     my $dt = $cd->{data_term};
 
     $c->add_ccl($cd, join(
         "",
         "(function(){ var _sahv_is_re = true; ",
         "try { RegExp($dt) } catch(e) { if (e.name=='SyntaxError') _sahv_is_re = false } ",
         ($cd->{cl_is_expr} ?
             "return _sahv_is_re == !!($ct);" :
                 "return ".($cv ? '':'!')."_sahv_is_re;"),
         "} )()",
     ));
 }
 
 1;
 # ABSTRACT: js's type handler for type "str"
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Compiler::js::TH::str - js's type handler for type "str"
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Compiler::js::TH::str (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =for Pod::Coverage ^(clause_.+|superclause_.+|handle_.+|before_.+|after_.+)$
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Compiler/js/TH/undef.pm ###
 package Data::Sah::Compiler::js::TH::undef;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 #use Log::Any '$log';
 
 use Mo qw(build default);
 use Role::Tiny::With;
 
 extends 'Data::Sah::Compiler::js::TH';
 with 'Data::Sah::Type::undef';
 
 sub handle_type {
     my ($self, $cd) = @_;
     my $c = $self->compiler;
 
     my $dt = $cd->{data_term};
     $cd->{_ccl_check_type} = "$dt === undefined || $dt === null";
 }
 
 1;
 # ABSTRACT: js's type handler for type "re"
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Compiler::js::TH::undef - js's type handler for type "re"
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Compiler::js::TH::undef (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =for Pod::Coverage ^(clause_.+|superclause_.+)$
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Compiler/perl.pm ###
 package Data::Sah::Compiler::perl;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 #use Log::Any qw($log);
 
 use Data::Dmp qw(dmp);
 use Mo qw(build default);
 use String::Indent ();
 
 extends 'Data::Sah::Compiler::Prog';
 
 our $PP;
 our $CORE;
 our $CORE_OR_PP;
 our $NO_MODULES;
 
 sub BUILD {
     my ($self, $args) = @_;
 
     $self->comment_style('shell');
     $self->indent_character(" " x 4);
     $self->var_sigil('$');
     $self->concat_op(".");
 }
 
 sub name { "perl" }
 
 sub literal {
     dmp($_[1]);
 }
 
 sub expr {
     my ($self, $expr) = @_;
     $self->expr_compiler->perl($expr);
 }
 
 sub compile {
     my ($self, %args) = @_;
 
     #$self->expr_compiler->compiler->hook_var(
     #    sub {
     #        $_[0];
     #    }
     #);
 
     #$self->expr_compiler->compiler->hook_func(
     #    sub {
     #        my ($name, @args) = @_;
     #        die "Unknown function $name"
     #            unless $self->main->func_names->{$name};
     #        my $subname = "func_$name";
     #        $self->define_sub_start($subname);
     #        my $meth = "func_$name";
     #        $self->func_handlers->{$name}->$meth;
     #        $self->define_sub_end();
     #        $subname . "(" . join(", ", @args) . ")";
     #    }
     #);
 
     $args{pp} //= $PP // $ENV{DATA_SAH_PP} // 0;
     $args{core} //= $CORE // $ENV{DATA_SAH_CORE} // 0;
     $args{core_or_pp} //= $CORE_OR_PP // $ENV{DATA_SAH_CORE_OR_PP} // 0;
     $args{no_modules} //= $NO_MODULES // $ENV{DATA_SAH_NO_MODULES} // 0;
 
     $self->SUPER::compile(%args);
 }
 
 sub init_cd {
     my ($self, %args) = @_;
 
     my $cd = $self->SUPER::init_cd(%args);
 
     if (my $ocd = $cd->{outer_cd}) {
         $cd->{module_statements} = $ocd->{module_statements};
     } else {
         $cd->{module_statements} = {};
     }
 
     $self->add_no($cd, 'warnings', ["'void'"]) unless $cd->{args}{no_modules};
 
     $cd;
 }
 
 sub true { "1" }
 
 sub false { "''" }
 
 sub add_module {
     my ($self, $cd, $name) = @_;
     $self->SUPER::add_module($cd, $name);
 
     if ($cd->{args}{no_modules}) {
         die "BUG: Use of module '$name' when compile option no_modules=1";
     }
 
     if ($cd->{args}{pp}) {
         if ($name =~ /\A(DateTime|List::Util|Scalar::Util|Scalar::Util::Numeric|Storable|Time::Moment|Time::Piece)\z/) {
             die "Use of XS module '$name' when compile option pp=1";
         } elsif ($name =~ /\A(experimental|warnings|DateTime::Duration|Scalar::Util::Numeric::PP)\z/) {
             # module is PP
         } else {
             die "BUG: Haven't noted about Perl module '$name' as being pp/xs";
         }
     }
 
     if ($cd->{args}{core}) {
         if ($name =~ /\A(experimental|DateTime|DateTime::Duration|Scalar::Util::Numeric|Scalar::Util::Numeric::PP|Time::Moment)\z/) {
             die "Use of non-core module '$name' when compile option core=1";
         } elsif ($name =~ /\A(warnings|List::Util|Scalar::Util|Storable|Time::Piece)\z/) {
             # module is core
         } else {
             die "BUG: Haven't noted about Perl module '$name' as being core/non-core";
         }
     }
 
     if ($cd->{args}{core_or_pp}) {
         if ($name =~ /\A(DateTime|Scalar::Util::Numeric|Time::Moment)\z/) {
             die "Use of non-core XS module '$name' when compile option core_or_pp=1";
         } elsif ($name =~ /\A(experimental|warnings|DateTime::Duration|List::Util|Scalar::Util|Scalar::Util::Numeric::PP|Storable|Time::Piece)\z/) {
             # module is core or PP
         } else {
             die "BUG: Haven't noted about Perl module '$name' as being core_or_pp/not";
         }
     }
 }
 
 sub add_use {
     my ($self, $cd, $name, $imports) = @_;
 
     die "BUG: imports must be an arrayref"
         if defined($imports) && ref($imports) ne 'ARRAY';
     $self->add_module($cd, $name);
     $cd->{module_statements}{$name} = ['use', $imports];
 }
 
 sub add_no {
     my ($self, $cd, $name, $imports) = @_;
 
     die "BUG: imports must be an arrayref"
         if defined($imports) && ref($imports) ne 'ARRAY';
     $self->add_module($cd, $name);
     $cd->{module_statements}{$name} = ['no', $imports];
 }
 
 sub add_smartmatch_pragma {
     my ($self, $cd) = @_;
     $self->add_use($cd, 'experimental', ["'smartmatch'"]);
 }
 
 sub add_sun_module {
     my ($self, $cd) = @_;
     if ($cd->{args}{pp} || $cd->{args}{core_or_pp} ||
             !eval { require Scalar::Util::Numeric; 1 }) {
         $cd->{_sun_module} = 'Scalar::Util::Numeric::PP';
     } elsif ($cd->{args}{core}) {
         # just to make sure compilation will fail if we mistakenly use a sun
         # module
         $cd->{_sun_module} = 'Foo';
     } else {
         $cd->{_sun_module} = 'Scalar::Util::Numeric';
     }
     $self->add_module($cd, $cd->{_sun_module});
 }
 
 sub expr_defined {
     my ($self, $t) = @_;
     "defined($t)";
 }
 
 sub expr_array_subscript {
     my ($self, $at, $idxt) = @_;
     "$at->\[$idxt]";
 }
 
 sub expr_last_elem {
     my ($self, $at, $idxt) = @_;
     "$at->\[-1]";
 }
 
 sub expr_push {
     my ($self, $at, $elt) = @_;
     "push(\@{$at}, $elt)";
 }
 
 sub expr_pop {
     my ($self, $at, $elt) = @_;
     "pop(\@{$at})";
 }
 
 sub expr_push_and_pop_dpath_between_expr {
     my ($self, $et) = @_;
     join(
         "",
         "[",
         $self->expr_push('$_sahv_dpath', $self->literal(undef)), ", ", # 0
         "~~", $self->enclose_paren($et), ", ", #1 (~~ to avoid list flattening)
         $self->expr_pop('$_sahv_dpath'), # 2
         "]->[1]",
     );
 }
 
 sub expr_prefix_dpath {
     my ($self, $t) = @_;
     '(@$_sahv_dpath ? \'@\'.join("/",@$_sahv_dpath).": " : "") . ' . $t;
 }
 
 # $l //= $r
 sub expr_setif {
     my ($self, $l, $r) = @_;
     "($l //= $r)";
 }
 
 sub expr_set_err_str {
     my ($self, $et, $err_expr) = @_;
     "($et //= $err_expr)";
 }
 
 sub expr_set_err_full {
     my ($self, $et, $k, $err_expr) = @_;
     "($et\->{$k}{join('/',\@\$_sahv_dpath)} //= $err_expr)";
 }
 
 sub expr_reset_err_str {
     my ($self, $et, $err_expr) = @_;
     "($et = undef, 1)";
 }
 
 sub expr_reset_err_full {
     my ($self, $et) = @_;
     "(delete($et\->{errors}{join('/',\@\$_sahv_dpath)}), 1)";
 }
 
 sub expr_log {
     my ($self, $cd, @expr) = @_;
 
     "\$log->tracef('[sah validator](spath=%s) %s', " .
         $self->literal($cd->{spath}).", " . join(", ", @expr) . ")";
 }
 
 # wrap statements into an expression
 sub expr_block {
     my ($self, $code) = @_;
     join(
         "",
         "do {\n",
         String::Indent::indent(
             $self->indent_character,
             $code,
         ),
         "}",
     );
 }
 
 # whether block is implemented using function
 sub block_uses_sub { 0 }
 
 sub stmt_declare_local_var {
     my ($self, $v, $vt) = @_;
     if ($vt eq 'undef') {
         "my \$$v;";
     } else {
         "my \$$v = $vt;";
     }
 }
 
 sub expr_anon_sub {
     my ($self, $args, $code) = @_;
     join(
         "",
         "sub {\n",
         String::Indent::indent(
             $self->indent_character,
             join(
                 "",
                 ("my (".join(", ", @$args).") = \@_;\n") x !!@$args,
                 $code,
             ),
         ),
         "}"
     );
 }
 
 sub stmt_require_module {
     my ($self, $mod, $cd) = @_;
     my $ms = $cd->{module_statements};
 
     if (!$ms->{$mod}) {
         "require $mod;";
     } elsif ($ms->{$mod}[0] eq 'use' || $ms->{$mod}[0] eq 'no') {
         my $verb = $ms->{$mod}[0];
         if (!$ms->{$mod}[1]) {
             "$verb $mod;";
         } else {
             "$verb $mod (".join(", ", @{ $ms->{$mod}[1] }).");";
         }
     }
 }
 
 sub stmt_require_log_module {
     my ($self, $mod) = @_;
     'use Log::Any qw($log);';
 }
 
 sub stmt_return {
     my $self = shift;
     if (@_) {
         "return($_[0]);";
     } else {
         'return;';
     }
 }
 
 sub expr_validator_sub {
     my ($self, %args) = @_;
 
     $self->check_compile_args(\%args);
 
     my $aref = delete $args{accept_ref};
     if ($aref) {
         $args{var_term}  = '$ref_'.$args{data_name};
         $args{data_term} = '$$ref_'.$args{data_name};
     } else {
         $args{var_term}  = '$'.$args{data_name};
         $args{data_term} = '$'.$args{data_name};
     }
 
     $self->SUPER::expr_validator_sub(%args);
 }
 
 sub _str2reliteral {
     require Regexp::Stringify;
 
     my ($self, $cd, $str) = @_;
 
     my $re;
     if (ref($str) eq 'Regexp') {
         $re = $str;
     } else {
         eval { $re = qr/$str/ };
         $self->_die($cd, "Invalid regex $str: $@") if $@;
     }
 
     Regexp::Stringify::stringify_regexp(regexp=>$re, plver=>5.010);
 }
 
 1;
 # ABSTRACT: Compile Sah schema to Perl code
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Compiler::perl - Compile Sah schema to Perl code
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Compiler::perl (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =head1 SYNOPSIS
 
  # see Data::Sah
 
 =head1 DESCRIPTION
 
 Derived from L<Data::Sah::Compiler::Prog>.
 
 =for Pod::Coverage BUILD ^(after_.+|before_.+|name|expr|true|false|literal|expr_.+|stmt_.+|block_uses_sub)$
 
 =head1 METHODS
 
 =head2 new() => OBJ
 
 =head3 Compilation data
 
 This subclass adds the following compilation data (C<$cd>).
 
 Keys which contain compilation result:
 
 =over
 
 =item * B<module_statements> => HASH
 
 This hash, keyed by module name, lets the Perl compiler differentiate on the
 different statements to use when loading modules, e.g.:
 
  {
      "Foo"      => undef,    # or does not exist
      "Bar::Baz" => ['use'],
      "Qux"      => ['use', []],
      "Quux"     => ['use', ["'a'", 123]],
      "warnings" => ['no'],
  }
 
 will lead to these codes (in the order specified by C<< $cd->{modules} >>, BTW)
 being generated:
 
  require Foo;
  use Bar::Baz;
  use Qux ();
  use Quux ('a', 123);
  no warnings;
 
 =back
 
 =head2 $c->comment($cd, @args) => STR
 
 Generate a comment. For example, in perl compiler:
 
  $c->comment($cd, "123"); # -> "# 123\n"
 
 Will return an empty string if compile argument C<comment> is set to false.
 
 =head2 $c->compile(%args) => RESULT
 
 Aside from Prog's arguments, this class supports these arguments:
 
 =over
 
 =item * pp => bool (default: 0)
 
 If set to true, will avoid the use of XS modules in the generated code and will
 opt instead to use pure-perl modules.
 
 =item * core => bool (default: 0)
 
 If set to true, will avoid the use of non-core modules in the generated code and
 will opt instead to use core modules.
 
 =item * core_or_pp => bool (default: 0)
 
 If set to true, will stick to using only core or PP modules in the generated
 code.
 
 =back
 
 =head2 $c->add_use($cd, $module, \@imports)
 
 This is like C<add_module()>, but indicate that C<$module> needs to be C<use>-d
 in the generated code (for example, Perl pragmas). Normally if C<add_module()>
 is used, the generated code will use C<require>.
 
 If you use C<< $c->add_use($cd, 'foo') >>, this code will be generated:
 
  use foo;
 
 If you use C<< $c->add_use($cd, 'foo', ["'a'", "'b'", "123"]) >>, this code will
 be generated:
 
  use foo ('a', 'b', 123);
 
 If you use C<< $c->add_use($cd, 'foo', []) >>, this code will be generated:
 
  use foo ();
 
 The generated statement will be added at the top (top-level lexical scope) and
 duplicates are ignored. To generate multiple and lexically-scoped C<use> and
 C<no> statements, e.g. like below, currently you can generate them manually:
 
  if (blah) {
      no warnings;
      ...
  }
 
 =head2 $c->add_no($cd, $module)
 
 This is the counterpart of C<add_use()>, to generate C<no foo> statement.
 
 See also: C<add_use()>.
 
 =head2 $c->add_smartmatch_pragma($cd)
 
 Equivalent to:
 
  $c->add_use($cd, 'experimental', ["'smartmatch'"]);
 
 =head2 $c->add_sun_module($cd)
 
 Add L<Scalar::Util::Numeric> module, or L<Scalar::Util::Numeric::PP> when C<pp>
 compile argument is true.
 
 =head1 VARIABLES
 
 =head2 $PP => bool
 
 Set default for C<pp> compile argument. Takes precedence over environment
 C<DATA_SAH_PP>.
 
 =head2 $CORE => bool
 
 Set default for C<core> compile argument. Takes precedence over environment
 C<DATA_SAH_CORE>.
 
 =head2 $CORE_OR_PP => bool
 
 Set default for C<core_or_pp> compile argument. Takes precedence over
 environment C<DATA_SAH_CORE_OR_PP>.
 
 =head2 $NO_MODULES => bool
 
 Set default for C<no_modules> compile argument. Takes precedence over
 environment C<DATA_SAH_NO_MODULES>.
 
 =head1 ENVIRONMENT
 
 =head2 DATA_SAH_PP => bool
 
 Set default for C<pp> compile argument.
 
 =head2 DATA_SAH_CORE => bool
 
 Set default for C<core> compile argument.
 
 =head2 DATA_SAH_CORE_OR_PP => bool
 
 Set default for C<core_or_pp> compile argument.
 
 =head2 DATA_SAH_NO_MODULES => bool
 
 Set default for C<no_modules> compile argument.
 
 =head1 DEVELOPER NOTES
 
 To generate expression code that says "all subexpression must be true", you can
 do:
 
  !defined(List::Util::first(sub { blah($_) }, "value", ...))
 
 This is a bit harder to read than:
 
  !grep { !blah($_) } "value", ...
 
 but has the advantage of the ability to shortcut on the first item that fails.
 
 Similarly, to say "at least one subexpression must be true":
 
  defined(List::Util::first(sub { blah($_) }, "value", ...))
 
 which can shortcut in contrast to:
 
  grep { blah($_) } "value", ...
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Compiler/perl/TH.pm ###
 package Data::Sah::Compiler::perl::TH;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 #use Log::Any '$log';
 
 use Mo qw(build default);
 use Role::Tiny::With;
 
 extends 'Data::Sah::Compiler::Prog::TH';
 
 sub gen_each {
     my ($self, $cd, $indices_expr, $data_name, $data_term, $code_at_sub_begin) = @_;
     my $c  = $self->compiler;
     my $cv = $cd->{cl_value};
     my $dt = $cd->{data_term};
 
     local $cd->{_subdata_level} = $cd->{_subdata_level} + 1;
     my $use_dpath = $cd->{args}{return_type} ne 'bool';
 
     $c->add_module($cd, 'List::Util');
     my %iargs = %{$cd->{args}};
     $iargs{outer_cd}             = $cd;
     $iargs{data_name}            = $data_name;
     $iargs{data_term}            = $data_term;
     $iargs{schema}               = $cv;
     $iargs{schema_is_normalized} = 0;
     $iargs{indent_level}++;
     my $icd = $c->compile(%iargs);
     my @code = (
         "!defined(List::Util::first(sub {", ($code_at_sub_begin // ''), "!(\n",
         ($c->indent_str($cd),
          "(\$_sahv_dpath->[-1] = \$_),\n") x !!$use_dpath,
          $icd->{result}, "\n",
          $c->indent_str($icd), ")}, ",
          $indices_expr,
          "))",
     );
     $c->add_ccl($cd, join("", @code), {subdata=>1});
 }
 
 1;
 # ABSTRACT: Base class for perl type handlers
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Compiler::perl::TH - Base class for perl type handlers
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Compiler::perl::TH (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =for Pod::Coverage ^(compiler|clause_.+|gen_.+)$
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Compiler/perl/TH/all.pm ###
 package Data::Sah::Compiler::perl::TH::all;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 #use Log::Any '$log';
 
 use Mo qw(build default);
 use Role::Tiny::With;
 
 # Mo currently doesn't support multiple classes in 'extends'
 #extends
 #    'Data::Sah::Compiler::perl::TH',
 #    'Data::Sah::Compiler::Prog::TH::all';
 
 use parent (
     'Data::Sah::Compiler::perl::TH',
     'Data::Sah::Compiler::Prog::TH::all',
 );
 
 1;
 # ABSTRACT: perl's type handler for type "all"
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Compiler::perl::TH::all - perl's type handler for type "all"
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Compiler::perl::TH::all (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =for Pod::Coverage ^(clause_.+|superclause_.+)$
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Compiler/perl/TH/any.pm ###
 package Data::Sah::Compiler::perl::TH::any;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 #use Log::Any '$log';
 
 use Mo qw(build default);
 use Role::Tiny::With;
 
 # Mo currently doesn't support multiple classes in 'extends'
 #extends
 #    'Data::Sah::Compiler::perl::TH',
 #    'Data::Sah::Compiler::Prog::TH::any';
 
 use parent (
     'Data::Sah::Compiler::perl::TH',
     'Data::Sah::Compiler::Prog::TH::any',
 );
 
 1;
 # ABSTRACT: perl's type handler for type "any"
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Compiler::perl::TH::any - perl's type handler for type "any"
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Compiler::perl::TH::any (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =for Pod::Coverage ^(clause_.+|superclause_.+)$
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Compiler/perl/TH/array.pm ###
 package Data::Sah::Compiler::perl::TH::array;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 #use Log::Any '$log';
 
 use Mo qw(build default);
 use Role::Tiny::With;
 
 extends 'Data::Sah::Compiler::perl::TH';
 with 'Data::Sah::Type::array';
 
 sub handle_type {
     my ($self, $cd) = @_;
     my $c = $self->compiler;
 
     my $dt = $cd->{data_term};
     $cd->{_ccl_check_type} = "ref($dt) eq 'ARRAY'";
 }
 
 my $FRZ = "Storable::freeze";
 
 sub superclause_comparable {
     my ($self, $which, $cd) = @_;
     my $c  = $self->compiler;
     my $ct = $cd->{cl_term};
     my $dt = $cd->{data_term};
 
     # Storable is chosen because it's core and fast. ~~ is not very
     # specific.
     $c->add_module($cd, 'Storable');
 
     if ($which eq 'is') {
         $c->add_ccl($cd, "$FRZ($dt) eq $FRZ($ct)");
     } elsif ($which eq 'in') {
         $c->add_smartmatch_pragma($cd);
         $c->add_ccl($cd, "$FRZ($dt) ~~ [map {$FRZ(\$_)} \@{ $ct }]");
     }
 }
 
 sub superclause_has_elems {
     my ($self_th, $which, $cd) = @_;
     my $c  = $self_th->compiler;
     my $cv = $cd->{cl_value};
     my $ct = $cd->{cl_term};
     my $dt = $cd->{data_term};
 
     if ($which eq 'len') {
         $c->add_ccl($cd, "\@{$dt} == $ct");
     } elsif ($which eq 'min_len') {
         $c->add_ccl($cd, "\@{$dt} >= $ct");
     } elsif ($which eq 'max_len') {
         $c->add_ccl($cd, "\@{$dt} <= $ct");
     } elsif ($which eq 'len_between') {
         if ($cd->{cl_is_expr}) {
             $c->add_ccl(
                 $cd, "\@{$dt} >= $ct\->[0] && \@{$dt} >= $ct\->[1]");
         } else {
             # simplify code
             $c->add_ccl(
                 $cd, "\@{$dt} >= $cv->[0] && \@{$dt} <= $cv->[1]");
         }
     } elsif ($which eq 'has') {
         $c->add_smartmatch_pragma($cd);
         #$c->add_ccl($cd, "$FRZ($ct) ~~ [map {$FRZ(\$_)} \@{ $dt }]");
 
         # XXX currently we choose below for speed, but only works for array of
         # scalars
         $c->add_ccl($cd, "$ct ~~ $dt");
     } elsif ($which eq 'each_index') {
         $self_th->gen_each($cd, "0..\@{$dt}-1", '_', '$_');
     } elsif ($which eq 'each_elem') {
         $self_th->gen_each($cd, "0..\@{$dt}-1", '_', "$dt\->[\$_]");
     } elsif ($which eq 'check_each_index') {
         $self_th->compiler->_die_unimplemented_clause($cd);
     } elsif ($which eq 'check_each_elem') {
         $self_th->compiler->_die_unimplemented_clause($cd);
     } elsif ($which eq 'uniq') {
         $self_th->compiler->_die_unimplemented_clause($cd);
     } elsif ($which eq 'exists') {
         $self_th->compiler->_die_unimplemented_clause($cd);
     }
 }
 
 sub clause_elems {
     my ($self_th, $cd) = @_;
     my $c  = $self_th->compiler;
     my $cv = $cd->{cl_value};
     my $dt = $cd->{data_term};
 
     local $cd->{_subdata_level} = $cd->{_subdata_level} + 1;
     my $use_dpath = $cd->{args}{return_type} ne 'bool';
 
     my $jccl;
     {
         local $cd->{ccls} = [];
         #local $cd->{args}{return_type} = 'bool';
 
         my $cdef = $cd->{clset}{"elems.create_default"} // 1;
         delete $cd->{uclset}{"elems.create_default"};
 
         for my $i (0..@$cv-1) {
             local $cd->{spath} = [@{$cd->{spath}}, $i];
             my $sch = $c->main->normalize_schema($cv->[$i]);
             my $edt = "$dt\->[$i]";
             my %iargs = %{$cd->{args}};
             $iargs{outer_cd}             = $cd;
             $iargs{data_name}            = "$cd->{args}{data_name}_$i";
             $iargs{data_term}            = $edt;
             $iargs{schema}               = $sch;
             $iargs{schema_is_normalized} = 1;
             $iargs{indent_level}++;
             my $icd = $c->compile(%iargs);
             my @code = (
                 ($c->indent_str($cd), "(\$_sahv_dpath->[-1] = $i),\n") x !!$use_dpath,
                 $icd->{result}, "\n",
             );
             my $ires = join("", @code);
             local $cd->{_debug_ccl_note} = "elem: $i";
             if ($cdef && defined($sch->[1]{default})) {
                 $c->add_ccl($cd, $ires);
             } else {
                 $c->add_ccl($cd, "\@{$dt} < ".($i+1)." || ($ires)");
             }
         }
         $jccl = $c->join_ccls(
             $cd, $cd->{ccls}, {err_msg => ''});
     }
     $c->add_ccl($cd, $jccl, {subdata=>1});
 }
 
 1;
 # ABSTRACT: perl's type handler for type "array"
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Compiler::perl::TH::array - perl's type handler for type "array"
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Compiler::perl::TH::array (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =for Pod::Coverage ^(clause_.+|superclause_.+)$
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Compiler/perl/TH/bool.pm ###
 package Data::Sah::Compiler::perl::TH::bool;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 #use Log::Any '$log';
 
 use Mo qw(build default);
 use Role::Tiny::With;
 
 extends 'Data::Sah::Compiler::perl::TH';
 with 'Data::Sah::Type::bool';
 
 sub handle_type {
     my ($self, $cd) = @_;
     my $c = $self->compiler;
 
     my $dt = $cd->{data_term};
     $cd->{_ccl_check_type} = "!ref($dt)";
 }
 
 sub superclause_comparable {
     my ($self, $which, $cd) = @_;
     my $c  = $self->compiler;
     my $ct = $cd->{cl_term};
     my $dt = $cd->{data_term};
 
     if ($which eq 'is') {
         $c->add_ccl($cd, "($dt ? 1:0) == ($ct ? 1:0)");
     } elsif ($which eq 'in') {
         $c->add_smartmatch_pragma($cd);
         $c->add_ccl($cd, "($dt ? 1:0) ~~ [map {\$_?1:0} \@{$ct}]");
     }
 }
 
 sub superclause_sortable {
     my ($self, $which, $cd) = @_;
     my $c  = $self->compiler;
     my $cv = $cd->{cl_value};
     my $ct = $cd->{cl_term};
     my $dt = $cd->{data_term};
 
     if ($which eq 'min') {
         $c->add_ccl($cd, "($dt ? 1:0) >= ($ct ? 1:0)");
     } elsif ($which eq 'xmin') {
         $c->add_ccl($cd, "($dt ? 1:0) > ($ct ? 1:0)");
     } elsif ($which eq 'max') {
         $c->add_ccl($cd, "($dt ? 1:0) <= ($ct ? 1:0)");
     } elsif ($which eq 'xmax') {
         $c->add_ccl($cd, "($dt ? 1:0) < ($ct ? 1:0)");
     } elsif ($which eq 'between') {
         if ($cd->{cl_is_expr}) {
             $c->add_ccl($cd, "($dt ? 1:0) >= ($ct\->[0] ? 1:0) && ".
                             "($dt ? 1:0) <= ($ct\->[1] ? 1:0)");
         } else {
             # simplify code
             $c->add_ccl($cd, "($dt ? 1:0) >= ($cv->[0] ? 1:0) && ".
                             "($dt ? 1:0) <= ($cv->[1] ? 1:0)");
         }
     } elsif ($which eq 'xbetween') {
         if ($cd->{cl_is_expr}) {
             $c->add_ccl($cd, "($dt ? 1:0) > ($ct\->[0] ? 1:0) && ".
                             "($dt ? 1:0) < ($ct\->[1] ? 1:0)");
         } else {
             # simplify code
             $c->add_ccl($cd, "($dt ? 1:0) > ($cv->[0] ? 1:0) && ".
                             "($dt ? 1:0) < ($cv->[1] ? 1:0)");
         }
     }
 }
 
 sub clause_is_true {
     my ($self, $cd) = @_;
     my $c  = $self->compiler;
     my $ct = $cd->{cl_term};
     my $dt = $cd->{data_term};
 
     $c->add_ccl($cd, "($ct) ? $dt : !defined($ct) ? 1 : !$dt");
 }
 
 1;
 # ABSTRACT: perl's type handler for type "bool"
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Compiler::perl::TH::bool - perl's type handler for type "bool"
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Compiler::perl::TH::bool (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =for Pod::Coverage ^(clause_.+|superclause_.+)$
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Compiler/perl/TH/buf.pm ###
 package Data::Sah::Compiler::perl::TH::buf;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 #use Log::Any '$log';
 
 use Mo qw(build default);
 use Role::Tiny::With;
 
 extends 'Data::Sah::Compiler::perl::TH::str';
 with 'Data::Sah::Type::buf';
 
 1;
 # ABSTRACT: perl's type handler for type "buf"
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Compiler::perl::TH::buf - perl's type handler for type "buf"
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Compiler::perl::TH::buf (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =for Pod::Coverage ^(clause_.+|superclause_.+)$
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Compiler/perl/TH/cistr.pm ###
 package Data::Sah::Compiler::perl::TH::cistr;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 #use Log::Any '$log';
 
 use Mo qw(build default);
 use Role::Tiny::With;
 
 extends 'Data::Sah::Compiler::perl::TH::str';
 with 'Data::Sah::Type::cistr';
 
 sub before_all_clauses {
     my ($self, $cd) = @_;
     my $c = $self->compiler;
     my $dt = $cd->{data_term};
 
     # XXX only do this when there are clauses
 
     # convert to lowercase so we don't lc() the data repeatedly
     $self->set_tmp_data_term($cd, "lc($dt)");
 }
 
 sub after_all_clauses {
     my ($self, $cd) = @_;
     my $c = $self->compiler;
     my $dt = $cd->{data_term};
 
     $self->restore_data_term($cd);
 }
 
 sub superclause_comparable {
     my ($self, $which, $cd) = @_;
     my $c  = $self->compiler;
     my $ct = $cd->{cl_term};
     my $dt = $cd->{data_term};
 
     if ($which eq 'is') {
         $c->add_ccl($cd, "$dt eq lc($ct)");
     } elsif ($which eq 'in') {
         $c->add_smartmatch_pragma($cd);
         $c->add_ccl($cd, "$dt ~~ [map {lc} \@{ $ct }]");
     }
 }
 
 sub superclause_sortable {
     my ($self, $which, $cd) = @_;
     my $c  = $self->compiler;
     my $cv = $cd->{cl_value};
     my $ct = $cd->{cl_term};
     my $dt = $cd->{data_term};
 
     if ($which eq 'min') {
         $c->add_ccl($cd, "$dt ge lc($ct)");
     } elsif ($which eq 'xmin') {
         $c->add_ccl($cd, "$dt gt lc($ct)");
     } elsif ($which eq 'max') {
         $c->add_ccl($cd, "$dt le lc($ct)");
     } elsif ($which eq 'xmax') {
         $c->add_ccl($cd, "$dt lt lc($ct)");
     } elsif ($which eq 'between') {
         if ($cd->{cl_is_expr}) {
             $c->add_ccl($cd, "$dt ge lc($ct\->[0]) && ".
                             "$dt le lc($ct\->[1])");
         } else {
             # simplify code
             $c->add_ccl($cd, "$dt ge ".$c->literal(lc $cv->[0]).
                             " && $dt le ".$c->literal(lc $cv->[1]));
         }
     } elsif ($which eq 'xbetween') {
         if ($cd->{cl_is_expr}) {
             $c->add_ccl($cd, "$dt gt lc($ct\->[0]) && ".
                             "$dt lt lc($ct\->[1])");
         } else {
             # simplify code
             $c->add_ccl($cd, "$dt gt ".$c->literal(lc $cv->[0]).
                             " && $dt lt ".$c->literal(lc $cv->[1]));
         }
     }
 }
 
 sub superclause_has_elems {
     my ($self_th, $which, $cd) = @_;
     my $c  = $self_th->compiler;
     my $cv = $cd->{cl_value};
     my $ct = $cd->{cl_term};
     my $dt = $cd->{data_term};
 
     if ($which eq 'has') {
         $c->add_ccl($cd, "index($dt, lc($ct)) > -1");
     } else {
         $self_th->SUPER::superclause_has_elems($which, $cd);
     }
 }
 
 # turn "(?-xism:blah)" to "(?i-xsm:blah)"
 sub __change_re_str_switch {
     my $re = shift;
 
     if ($^V ge v5.14.0) {
         state $sub = sub { my $s = shift; $s =~ /i/ ? $s : "i$s" };
         $re =~ s/\A\(\?\^(\w*):/"(?".$sub->($1).":"/e;
     } else {
         state $subl = sub { my $s = shift; $s =~ /i/ ? $s : "i$s" };
         state $subr = sub { my $s = shift; $s =~ s/i//; $s };
         $re =~ s/\A\(\?(\w*)-(\w*):/"(?".$subl->($1)."-".$subr->($2).":"/e;
     }
     return $re;
 }
 
 sub clause_match {
     my ($self, $cd) = @_;
     my $c  = $self->compiler;
     my $cv = $cd->{cl_value};
     my $ct = $cd->{cl_term};
     my $dt = $cd->{data_term};
 
     if ($cd->{cl_is_expr}) {
         $c->add_ccl($cd, join(
             "",
             "ref($ct) eq 'Regexp' ? $dt =~ qr/$ct/i : ",
             "do { my \$re = $ct; eval { \$re = /\$re/i; 1 } && ",
             "$dt =~ \$re }",
         ));
     } else {
         # simplify code and we can check regex at compile time
         my $re = $c->_str2reliteral($cd, $cv);
         $re = __change_re_str_switch($re);
         $c->add_ccl($cd, "$dt =~ /$re/i");
     }
 }
 
 1;
 # ABSTRACT: perl's type handler for type "cistr"
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Compiler::perl::TH::cistr - perl's type handler for type "cistr"
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Compiler::perl::TH::cistr (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =for Pod::Coverage ^(clause_.+|superclause_.+|handle_.+|before_.+|after_.+)$
 
 =head1 NOTES
 
 Should probably be reimplemented using special Perl string type, or special Perl
 operators, instead of simulated using C<lc()> on a per-clause basis. The
 implementation as it is now is not "contagious", e.g. C<< [cistr =>
 check_each_elem => '$_ eq "A"'] >> should be true even if data is C<"Aaa">,
 since one would expect C<< $_ eq "A" >> is also done case-insensitively, but it
 is currently internally implemented by converting data to lowercase and
 splitting per character to become C<< ["a", "a", "a"] >>.
 
 Or, avoid C<cistr> altogether and use C<prefilters> to convert to
 lowercase/uppercase first before processing.
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Compiler/perl/TH/code.pm ###
 package Data::Sah::Compiler::perl::TH::code;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 #use Log::Any '$log';
 
 use Mo qw(build default);
 use Role::Tiny::With;
 
 extends 'Data::Sah::Compiler::perl::TH';
 with 'Data::Sah::Type::code';
 
 sub handle_type {
     my ($self, $cd) = @_;
     my $c = $self->compiler;
 
     my $dt = $cd->{data_term};
     $cd->{_ccl_check_type} = "ref($dt) eq 'CODE'";
 }
 
 1;
 # ABSTRACT: perl's type handler for type "code"
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Compiler::perl::TH::code - perl's type handler for type "code"
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Compiler::perl::TH::code (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =for Pod::Coverage ^(clause_.+|superclause_.+)$
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Compiler/perl/TH/date.pm ###
 package Data::Sah::Compiler::perl::TH::date;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 #use Log::Any '$log';
 
 use Mo qw(build default);
 use Role::Tiny::With;
 use Scalar::Util qw(blessed looks_like_number);
 
 extends 'Data::Sah::Compiler::perl::TH';
 with 'Data::Sah::Type::date';
 
 sub expr_coerce_term {
     my ($self, $cd, $t) = @_;
 
     my $c = $self->compiler;
 
     # to reduce unnecessary overhead, we don't explicitly load DateTime here,
     # but on demand when doing validation
     #$c->add_module($cd, 'DateTime');
     $c->add_module($cd, 'Scalar::Util');
 
     join(
         '',
         "(",
         "(Scalar::Util::blessed($t) && $t->isa('DateTime')) ? $t : ",
         "(Scalar::Util::looks_like_number($t) && $t >= 10**8 && $t <= 2**31) ? (require DateTime && DateTime->from_epoch(epoch=>$t)) : ",
         "$t =~ /\\A([0-9]{4})-([0-9]{2})-([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})Z\\z/ ? require DateTime && DateTime->new(year=>\$1, month=>\$2, day=>\$3, hour=>\$4, minute=>\$5, second=>\$6, time_zone=>'UTC') : ",
         "$t =~ /\\A([0-9]{4})-([0-9]{2})-([0-9]{2})\\z/ ? require DateTime && DateTime->new(year=>\$1, month=>\$2, day=>\$3, time_zone=>'UTC') : die(\"BUG: can't coerce date\")",
         ")",
     );
 }
 
 sub expr_coerce_value {
     my ($self, $cd, $v) = @_;
 
     my $c = $self->compiler;
 
     if (blessed($v) && $v->isa('DateTime')) {
         return join(
             '',
             "DateTime->new(",
             "year=>",   $v->year, ",",
             "month=>",  $v->month, ",",
             "day=>",    $v->day, ",",
             "hour=>",   $v->hour, ",",
             "minute=>", $v->minute, ",",
             "second=>", $v->second, ",",
             "timezone=>'UTC',",
             ")",
         );
     } elsif (looks_like_number($v) && $v >= 10**8 && $v <= 2**31) {
         return "require DateTime && DateTime->from_epoch(epoch=>$v)";
     } elsif ($v =~ /\A([0-9]{4})-([0-9]{2})-([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})Z\z/) {
         require DateTime;
         eval { DateTime->new(year=>$1, month=>$2, day=>$3,
                              hour=>$4, minute=>$5, second=>$6,
                              time_zone=>'UTC') ; 1 }
             or die "Invalid date literal '$v': $@";
         return "DateTime->new(year=>$1, month=>$2, day=>$3, hour=>$4, minute=>$5, second=>$6, time_zone=>'UTC')";
     } elsif ($v =~ /\A([0-9]{4})-([0-9]{2})-([0-9]{2})\z/) {
         require DateTime;
         eval { DateTime->new(year=>$1, month=>$2, day=>$3, time_zone=>'UTC') ; 1 }
             or die "Invalid date literal '$v': $@";
         return "DateTime->new(year=>$1, month=>$2, day=>$3, time_zone=>'UTC')";
     } else {
         die "Invalid date literal '$v'";
     }
 }
 
 sub handle_type {
     my ($self, $cd) = @_;
     my $c  = $self->compiler;
     my $dt = $cd->{data_term};
 
     $c->add_module($cd, 'Scalar::Util');
     $cd->{_ccl_check_type} = join(
         '',
         "(",
         "(Scalar::Util::blessed($dt) && $dt->isa('DateTime'))",
         " || ",
         "(Scalar::Util::looks_like_number($dt) && $dt >= 10**8 && $dt <= 2**31)",
         " || ",
         "($dt =~ /\\A([0-9]{4})-([0-9]{2})-([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})Z\\z/ && eval { require DateTime; DateTime->new(year=>\$1, month=>\$2, day=>\$3, hour=>\$4, minute=>\$5, second=>\$6, time_zone=>'UTC'); 1})",
         " || ",
         "($dt =~ /\\A([0-9]{4})-([0-9]{2})-([0-9]{2})\\z/ && eval { require DateTime; DateTime->new(year=>\$1, month=>\$2, day=>\$3, time_zone=>'UTC'); 1})",
         ")",
     );
 }
 
 sub before_all_clauses {
     my ($self, $cd) = @_;
     my $c = $self->compiler;
     my $dt = $cd->{data_term};
 
     # coerce to DateTime object during validation
     $self->set_tmp_data_term($cd, $self->expr_coerce_term($cd, $dt))
         if $cd->{has_constraint_clause}; # remember to sync with after_all_clauses()
 }
 
 sub after_all_clauses {
     my ($self, $cd) = @_;
     my $c = $self->compiler;
     my $dt = $cd->{data_term};
 
     $self->restore_data_term($cd)
         if $cd->{has_constraint_clause};
 }
 
 sub superclause_comparable {
     my ($self, $which, $cd) = @_;
     my $c  = $self->compiler;
     my $cv = $cd->{cl_value};
     my $ct = $cd->{cl_term};
     my $dt = $cd->{data_term};
 
     if ($which eq 'is') {
         if ($cd->{cl_is_expr}) {
             $ct = $self->expr_coerce_term($cd, $ct);
         } else {
             $ct = $self->expr_coerce_value($cd, $cv);
         }
         $c->add_ccl($cd, "DateTime->compare($dt, $ct)==0");
     } elsif ($which eq 'in') {
         $c->add_module('List::Util');
         if ($cd->{cl_is_expr}) {
             # i'm lazy, technical debt
             $c->_die($cd, "date's in clause with expression not yet supported");
         } else {
             $ct = join(', ', map { $self->expr_coerce_value($cd, $_) } @$cv);
         };
         $c->add_ccl($cd, "List::Util::first(sub{DateTime->compare($dt, \$_)==0}, $ct)");
     }
 }
 
 sub superclause_sortable {
     my ($self, $which, $cd) = @_;
     my $c  = $self->compiler;
     my $cv = $cd->{cl_value};
     my $ct = $cd->{cl_term};
     my $dt = $cd->{data_term};
 
     if ($cd->{cl_is_expr}) {
         # i'm lazy, technical debt
         $c->_die($cd, "date's comparison with expression not yet supported");
     }
 
     if ($which eq 'min') {
         $c->add_ccl($cd, "DateTime->compare($dt, ".
                         $self->expr_coerce_value($cd, $cv).") >= 0");
     } elsif ($which eq 'xmin') {
         $c->add_ccl($cd, "DateTime->compare($dt, ".
                         $self->expr_coerce_value($cd, $cv).") > 0");
     } elsif ($which eq 'max') {
         $c->add_ccl($cd, "DateTime->compare($dt, ".
                         $self->expr_coerce_value($cd, $cv).") <= 0");
     } elsif ($which eq 'xmax') {
         $c->add_ccl($cd, "DateTime->compare($dt, ".
                         $self->expr_coerce_value($cd, $cv).") < 0");
     } elsif ($which eq 'between') {
         $c->add_ccl($cd,
                     join(
                         '',
                         "DateTime->compare($dt, ",
                         $self->expr_coerce_value($cd, $cv->[0]).") >= 0 && ",
                         "DateTime->compare($dt, ",
                         $self->expr_coerce_value($cd, $cv->[1]).") <= 0",
                     ));
     } elsif ($which eq 'xbetween') {
         $c->add_ccl($cd,
                     join(
                         '',
                         "DateTime->compare($dt, ",
                         $self->expr_coerce_value($cd, $cv->[0]).") > 0 && ",
                         "DateTime->compare($dt, ",
                         $self->expr_coerce_value($cd, $cv->[1]).") < 0",
                     ));
     }
 }
 
 1;
 # ABSTRACT: perl's type handler for type "date"
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Compiler::perl::TH::date - perl's type handler for type "date"
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Compiler::perl::TH::date (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =head1 DESCRIPTION
 
 What constitutes a valid date value:
 
 =over
 
 =item * L<DateTime> object
 
 =item * integers from 100 million to 2^31
 
 For convenience, some integers are accepted and interpreted as Unix epoch (32
 bit). They will be converted to DateTime objects during validation. The values
 correspond to dates from Mar 3rd, 1973 to Jan 19, 2038 (Y2038).
 
 Choosing 100 million (9 decimal digits) as the lower limit is to avoid parsing
 numbers like 20141231 (8 digit) as YMD date.
 
 =item * string in the form of "YYYY-MM-DD"
 
 For convenience, string of this form, like C<2014-04-25> is accepted and will be
 converted to DateTime object. Invalid dates like C<2014-04-31> will of course
 fail the validation.
 
 =item * string in the form of "YYYY-MM-DDThh:mm:ssZ"
 
 This is the Zulu form of ISO8601 date+time.
 
 =back
 
 =for Pod::Coverage ^(clause_.+|superclause_.+|handle_.+|before_.+|after_.+|expr_coerce_.+)$
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Compiler/perl/TH/duration.pm ###
 package Data::Sah::Compiler::perl::TH::duration;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 #use Log::Any '$log';
 
 use Mo qw(build default);
 use Role::Tiny::With;
 use Scalar::Util qw(blessed looks_like_number);
 
 extends 'Data::Sah::Compiler::perl::TH';
 with 'Data::Sah::Type::duration';
 
 sub expr_coerce_term {
     my ($self, $cd, $t) = @_;
 
     my $c = $self->compiler;
 
     # to reduce unnecessary overhead, we don't explicitly load
     # DateTime::Duration here, but on demand when doing validation
     #$c->add_module($cd, 'DateTime::Duration');
 
     # although this module is very lightweight, we also load it on-demand.
     #$c->add_module($cd, 'Time::Duration::Parse::AsHash');
 
     $c->add_module($cd, 'Scalar::Util');
 
     join(
         '',
         "(",
         "(Scalar::Util::blessed($t) && $t->isa('DateTime::Duration')) ? $t : ",
         "(Scalar::Util::looks_like_number($t) && $t >= 0 ? $t : (require DateTime::Duration && DateTime::Duration->new(seconds=>$t))",
         "$t =~ /\\AP(?:([0-9]+(?:\\.[0-9]+)?)Y)? (?:([0-9]+(?:\\.[0-9]+)?)M)? (?:([0-9]+(?:\\.[0-9]+)?)W)? (?:([0-9]+(?:\\.[0-9]+)?)D)? (?: T (?:([0-9]+(?:\\.[0-9]+)?)H)? (?:([0-9]+(?:\\.[0-9]+)?)M)? (?:([0-9]+(?:\\.[0-9]+)?)S)? )?\\z/x ? require DateTime::Duration && DateTime::Duration->new(years=>\$1||0, months=>\$2||0, weeks=>\$3||0, days=>\$4||0, hours=>\$5||0, minutes=>\$6||0, seconds=>\$7||0) : ",
         "do { my \$d; eval { require Time::Duration::Parse::AsHash; \$d = Time::Duration::Parse::AsHash::parse_duration($t) }; \$@ ? undef : require DateTime::Duration && DateTime::Duration->new(years=>\$d->{years}//0, months=>\$d->{months}//0, weeks=>\$d->{weeks}//0, days=>\$d->{days}//0, hours=>\$d->{hours}//0, minutes=>\$d->{minutes}//0, seconds=>\$d->{seconds}//0) } : die(\"BUG: can't coerce duration\")",
         ")",
     );
 }
 
 sub expr_coerce_value {
     my ($self, $cd, $v) = @_;
 
     my $c = $self->compiler;
 
     my $d;
 
     if (blessed($v) && $v->isa('DateTime::Duration')) {
         return join(
             '',
             "DateTime::Duration->new(",
             "years=>",   $v->years,   ",",
             "months=>",  $v->months,  ",",
             "weeks=>",   $v->weeks,   ",",
             "days=>",    $v->days,    ",",
             "hours=>",   $v->hours,   ",",
             "minutes=>", $v->minutes, ",",
             "seconds=>", $v->seconds, ",",
             ")",
         );
     } if (looks_like_number($v) && $v >= 0) {
         return "require DateTime::Duration && DateTime::Duration->new(seconds=>$v)";
     } elsif ($v =~ /\AP
                     (?:([0-9]+(?:\.[0-9]+)?)Y)?
                     (?:([0-9]+(?:\.[0-9]+)?)M)?
                     (?:([0-9]+(?:\.[0-9]+)?)W)?
                     (?:([0-9]+(?:\.[0-9]+)?)D)?
                     (?: T
                         (?:([0-9]+(?:\.[0-9]+)?)H)?
                         (?:([0-9]+(?:\.[0-9]+)?)M)?
                         (?:([0-9]+(?:\.[0-9]+)?)S)?
                     )?\z/x) {
         #require DateTime::Duration;
         #eval { DateTime::Duration->new(years=>$1||0, months =>$2||0, weeks  =>$3||0, days=>$4||0,
         #                               hours=>$5||0, minutes=>$6||0, seconds=>$7||0); 1 }
         #    or die "Invalid duration literal '$v': $@";
         return "require DateTime::Duration && DateTime::Duration->new(years=>".($1||0).", months=>".($2||0).", weeks=>".($3||0).", days=>".($4||0).", hours=>".($5||0).", minutes=>".($6||0).", seconds=>".($7||0).")";
     } elsif (eval { require Time::Duration::Parse::AsHash; $d = Time::Duration::Parse::AsHash::parse_duration($v) } && !$@) {
         return "require DateTime::Duration && DateTime::Duration->new(years=>".($d->{years}||0).", months=>".($d->{months}||0).", weeks=>".($d->{weeks}||0).", days=>".($d->{days}||0).", hours=>".($d->{hours}||0).", minutes=>".($d->{minutes}||0).", seconds=>".($d->{seconds}||0).")";
     } else {
         die "Invalid duration literal '$v'";
     }
 }
 
 sub handle_type {
     my ($self, $cd) = @_;
     my $c  = $self->compiler;
     my $dt = $cd->{data_term};
 
     $c->add_module($cd, 'Scalar::Util');
     $cd->{_ccl_check_type} = join(
         '',
         "(",
         "(Scalar::Util::blessed($dt) && $dt->isa('DateTime::Duration'))",
         " || ",
         "(Scalar::Util::looks_like_number($dt) && $dt >= 0)",
         " || ",
         "($dt =~ /\\AP(?:([0-9]+(?:\\.[0-9]+)?)Y)? (?:([0-9]+(?:\\.[0-9]+)?)M)? (?:([0-9]+(?:\\.[0-9]+)?)W)? (?:([0-9]+(?:\\.[0-9]+)?)D)? (?: T (?:([0-9]+(?:\\.[0-9]+)?)H)? (?:([0-9]+(?:\\.[0-9]+)?)M)? (?:([0-9]+(?:\\.[0-9]+)?)S)? )?\\z/x)", # XXX need this? && eval { DateTime::Duration->new(...); 1 }
         " || ",
         "do { my \$d; eval { require Time::Duration::Parse::AsHash; \$d = Time::Duration::Parse::AsHash::parse_duration($dt) }; !\$@ }",
         ")",
     );
 }
 
 sub before_all_clauses {
     my ($self, $cd) = @_;
     my $c = $self->compiler;
     my $dt = $cd->{data_term};
 
     # XXX only do this when there are clauses
 
     # coerce to DateTime::Duration object during validation
     $self->set_tmp_data_term($cd, $self->expr_coerce_term($cd, $dt))
         if $cd->{has_constraint_clause}; # remember to sync with after_all_clauses()
 }
 
 sub after_all_clauses {
     my ($self, $cd) = @_;
     my $c = $self->compiler;
     my $dt = $cd->{data_term};
 
     $self->restore_data_term($cd)
         if $cd->{has_constraint_clause};
 }
 
 1;
 # ABSTRACT: perl's type handler for type "duration"
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Compiler::perl::TH::duration - perl's type handler for type "duration"
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Compiler::perl::TH::duration (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =head1 DESCRIPTION
 
 What constitutes a valid duration value:
 
 =over
 
 =item * L<DateTime::Duration> object
 
 =item * a positive number (of seconds)
 
 =item * string in the form of ISO8601 duration format: "PnYnMnWnDTnHnMnS"
 
 For example: "P1Y2M" (equals to "P14M", 14 months), "P1DT13M" (1 day, 13
 minutes).
 
 =back
 
 =for Pod::Coverage ^(clause_.+|superclause_.+|handle_.+|before_.+|after_.+|expr_coerce_.+)$
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Compiler/perl/TH/float.pm ###
 package Data::Sah::Compiler::perl::TH::float;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 #use Log::Any '$log';
 
 use Mo qw(build default);
 use Role::Tiny::With;
 
 extends 'Data::Sah::Compiler::perl::TH::num';
 with 'Data::Sah::Type::float';
 
 sub handle_type {
     my ($self, $cd) = @_;
     my $c = $self->compiler;
 
     my $dt = $cd->{data_term};
     if ($cd->{args}{core} || $cd->{args}{no_modules}) {
         $cd->{_ccl_check_type} = "$dt =~ ".'/\A(?:[+-]?(?:0|[1-9][0-9]*)(\.[0-9]+)?([eE][+-]?[0-9]+)?|((?i)\s*nan\s*)|((?i)\s*[+-]?inf(inity)?)\s*)\z/';
     } else {
         $c->add_sun_module($cd);
         # we use isnum = isint + isfloat, because isfloat(3) is false
         $cd->{_ccl_check_type} = "$cd->{_sun_module}::isnum($dt)";
     }
 }
 
 sub clause_is_nan {
     my ($self, $cd) = @_;
     my $c  = $self->compiler;
     my $ct = $cd->{cl_term};
     my $dt = $cd->{data_term};
 
     if ($cd->{cl_is_expr}) {
         if ($cd->{args}{core} || $cd->{args}{no_modules}) {
             $c->add_ccl(
                 $cd,
                 qq[$ct ? lc($dt+0) eq "nan" : defined($ct) ? lc($dt+0) ne "nan" : 1],
             );
         } else {
             $c->add_ccl(
                 $cd,
                 join(
                     "",
                     "$ct ? $cd->{_sun_module}::isnan($dt) : ",
                     "defined($ct) ? !$cd->{_sun_module}::isnan($dt) : 1",
                 )
             );
         }
     } else {
         if ($cd->{cl_value}) {
             if ($cd->{args}{core} || $cd->{args}{no_modules}) {
                 $c->add_ccl($cd, qq[lc($dt+0) eq "nan"]);
             } else {
                 $c->add_ccl($cd, "$cd->{_sun_module}::isnan($dt)");
             }
         } elsif (defined $cd->{cl_value}) {
             if ($cd->{args}{core} || $cd->{args}{no_modules}) {
                 $c->add_ccl($cd, qq[lc($dt+0) ne "nan"]);
             } else {
                 $c->add_ccl($cd, "!$cd->{_sun_module}::isnan($dt)");
             }
         }
     }
 }
 
 sub clause_is_neg_inf {
     my ($self, $cd) = @_;
     my $c  = $self->compiler;
     my $ct = $cd->{cl_term};
     my $dt = $cd->{data_term};
 
     if ($cd->{cl_is_expr}) {
         if ($cd->{args}{core} || $cd->{args}{no_modules}) {
             $c->add_ccl(
                 $cd, join(
                     '',
                     qq[$ct ? $dt =~ /\\A\\s*-inf(inity)?\\s*\\z/i : ],
                     qq[defined($ct) ? $dt !~ /\\A\\s*inf(inity)?\\s*\\z/i : 1]
                 ));
         } else {
             $c->add_ccl(
                 $cd, join(
                     '',
                     "$ct ? $cd->{_sun_module}::isinf($dt) && $cd->{_sun_module}::isneg($dt) : ",
                     "defined($ct) ? !($cd->{_sun_module}::isinf($dt) && $cd->{_sun_module}::isneg($dt)) : 1",
                 ));
         }
     } else {
         if ($cd->{cl_value}) {
             if ($cd->{args}{core} || $cd->{args}{no_modules}) {
                 $c->add_ccl($cd, qq[$dt =~ /\\A\\s*-inf(inity)?\\s*\\z/i]);
             } else {
                 $c->add_ccl($cd, "$cd->{_sun_module}::isinf($dt) && $cd->{_sun_module}::isneg($dt)");
             }
         } elsif (defined $cd->{cl_value}) {
             if ($cd->{args}{core} || $cd->{args}{no_modules}) {
                 $c->add_ccl($cd, qq[$dt !~ /\\A\\s*-inf(inity)?\\s*\\z/i]);
             } else {
                 $c->add_ccl($cd, "!($cd->{_sun_module}::isinf($dt) && $cd->{_sun_module}::isneg($dt))");
             }
         }
     }
 }
 
 sub clause_is_pos_inf {
     my ($self, $cd) = @_;
     my $c  = $self->compiler;
     my $ct = $cd->{cl_term};
     my $dt = $cd->{data_term};
 
     if ($cd->{cl_is_expr}) {
         if ($cd->{args}{core} || $cd->{args}{no_modules}) {
             $c->add_ccl(
                 $cd, join(
                     '',
                     qq[$ct ? $dt =~ /\\A\\s*inf(inity)?\\s*\\z/i : ],
                     qq[defined($ct) ? $dt !~ /\\A\\s*inf(inity)?\\s*\\z/i : 1]
                 ));
         } else {
             $c->add_ccl(
                 $cd, join(
                     '',
                     "$ct ? $cd->{_sun_module}::isinf($dt) && !$cd->{_sun_module}::isneg($dt) : ",
                     "defined($ct) ? !($cd->{_sun_module}::isinf($dt) && !$cd->{_sun_module}::isneg($dt)) : 1",
                 ));
         }
     } else {
         if ($cd->{cl_value}) {
             if ($cd->{args}{core} || $cd->{args}{no_modules}) {
                 $c->add_ccl($cd, qq[$dt =~ /\\A\\s*inf(inity)?\\s*\\z/i]);
             } else {
                 $c->add_ccl($cd, "$cd->{_sun_module}::isinf($dt) && !$cd->{_sun_module}::isneg($dt)");
             }
         } elsif (defined $cd->{cl_value}) {
             if ($cd->{args}{core} || $cd->{args}{no_modules}) {
                 $c->add_ccl($cd, qq[$dt !~ /\\A\\s*inf(inity)?\\s*\\z/i]);
             } else {
                 $c->add_ccl($cd, "!($cd->{_sun_module}::isinf($dt) && !$cd->{_sun_module}::isneg($dt))");
             }
         }
     }
 }
 
 sub clause_is_inf {
     my ($self, $cd) = @_;
     my $c  = $self->compiler;
     my $ct = $cd->{cl_term};
     my $dt = $cd->{data_term};
 
     if ($cd->{cl_is_expr}) {
         if ($cd->{args}{core} || $cd->{args}{no_modules}) {
             $c->add_ccl(
                 $cd, join(
                     '',
                     qq[$ct ? $dt =~ /\\A\\s*-?inf(inity)?\\s*\\z/i : ],
                     qq[defined($ct) ? $dt+0 !~ /\\A-?inf\\z/ : 1]
                 ));
         } else {
             $c->add_ccl($cd, "$ct ? $cd->{_sun_module}::isinf($dt) : ".
                             "defined($ct) ? $cd->{_sun_module}::isinf($dt) : 1");
         }
     } else {
         if ($cd->{cl_value}) {
             if ($cd->{args}{core} || $cd->{args}{no_modules}) {
                 $c->add_ccl($cd, qq[$dt =~ /\\A\\s*-?inf(inity)?\\s*\\z/i]);
             } else {
                 $c->add_ccl($cd, "$cd->{_sun_module}::isinf($dt)");
             }
         } elsif (defined $cd->{cl_value}) {
             if ($cd->{args}{core} || $cd->{args}{no_modules}) {
                 $c->add_ccl($cd, qq[$dt !~ /\\A\\s*-?inf(inity)?\\s*\\z/i]);
             } else {
                 $c->add_ccl($cd, "!$cd->{_sun_module}::isinf($dt)");
             }
         }
     }
 }
 
 1;
 # ABSTRACT: perl's type handler for type "float"
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Compiler::perl::TH::float - perl's type handler for type "float"
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Compiler::perl::TH::float (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =for Pod::Coverage ^(compiler|clause_.+|handle_.+)$
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Compiler/perl/TH/hash.pm ###
 package Data::Sah::Compiler::perl::TH::hash;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 #use Log::Any '$log';
 
 use Mo qw(build default);
 use Role::Tiny::With;
 
 extends 'Data::Sah::Compiler::perl::TH';
 with 'Data::Sah::Type::hash';
 
 sub handle_type {
     my ($self, $cd) = @_;
     my $c = $self->compiler;
 
     my $dt = $cd->{data_term};
     $cd->{_ccl_check_type} = "ref($dt) eq 'HASH'";
 }
 
 my $FRZ = "Storable::freeze";
 
 sub superclause_comparable {
     my ($self, $which, $cd) = @_;
     my $c  = $self->compiler;
     my $ct = $cd->{cl_term};
     my $dt = $cd->{data_term};
 
     # Storable is chosen because it's core and fast. ~~ is not very
     # specific.
     $c->add_module($cd, 'Storable');
 
     if ($which eq 'is') {
         $c->add_ccl($cd, "$FRZ($dt) eq $FRZ($ct)");
     } elsif ($which eq 'in') {
         $c->add_smartmatch_pragma($cd);
         $c->add_ccl($cd, "$FRZ($dt) ~~ [map {$FRZ(\$_)} \@{ $ct }]");
     }
 }
 
 sub superclause_has_elems {
     my ($self_th, $which, $cd) = @_;
     my $c  = $self_th->compiler;
     my $cv = $cd->{cl_value};
     my $ct = $cd->{cl_term};
     my $dt = $cd->{data_term};
 
     if ($which eq 'len') {
         $c->add_ccl($cd, "keys(\%{$dt}) == $ct");
     } elsif ($which eq 'min_len') {
         $c->add_ccl($cd, "keys(\%{$dt}) >= $ct");
     } elsif ($which eq 'max_len') {
         $c->add_ccl($cd, "keys(\%{$dt}) <= $ct");
     } elsif ($which eq 'len_between') {
         if ($cd->{cl_is_expr}) {
             $c->add_ccl(
                 $cd, "keys(\%{$dt}) >= $ct\->[0] && ".
                     "keys(\%{$dt}) >= $ct\->[1]");
         } else {
             # simplify code
             $c->add_ccl(
                 $cd, "keys(\%{$dt}) >= $cv->[0] && ".
                     "keys(\%{$dt}) <= $cv->[1]");
         }
     } elsif ($which eq 'has') {
         $c->add_smartmatch_pragma($cd);
         #$c->add_ccl($cd, "$FRZ($ct) ~~ [map {$FRZ(\$_)} values \%{ $dt }]");
 
         # XXX currently we choose below for speed, but only works for hash of
         # scalars. stringifying is required because smartmatch will switch to
         # numeric if we feed something like {a=>1}
         $c->add_ccl($cd, "$ct ~~ [values \%{ $dt }]");
     } elsif ($which eq 'each_index') {
         $self_th->gen_each($cd, "sort keys(\%{$dt})", '', '$_');
     } elsif ($which eq 'each_elem') {
         $self_th->gen_each($cd, "sort keys(\%{$dt})", '_', "$dt\->{\$_}");
     } elsif ($which eq 'check_each_index') {
         $self_th->compiler->_die_unimplemented_clause($cd);
     } elsif ($which eq 'check_each_elem') {
         $self_th->compiler->_die_unimplemented_clause($cd);
     } elsif ($which eq 'uniq') {
         $self_th->compiler->_die_unimplemented_clause($cd);
     } elsif ($which eq 'exists') {
         $self_th->compiler->_die_unimplemented_clause($cd);
     }
 }
 
 sub _clause_keys_or_re_keys {
     my ($self_th, $which, $cd) = @_;
     my $c  = $self_th->compiler;
     my $cv = $cd->{cl_value};
     my $dt = $cd->{data_term};
 
     local $cd->{_subdata_level} = $cd->{_subdata_level} + 1;
     my $use_dpath = $cd->{args}{return_type} ne 'bool';
 
     # we handle subdata manually here, because in generated code for
     # {keys,re_keys}.restrict, we haven't delved into the keys
 
     my $jccl;
     {
         local $cd->{ccls} = [];
 
         my $lit_valid_keys;
         if ($which eq 'keys') {
             $lit_valid_keys = $c->literal([sort keys %$cv]);
         } else {
             $lit_valid_keys = "[".
                 join(",", map { "qr/".$c->_str2reliteral($cd, $_)."/" }
                          sort keys %$cv)."]";
         }
 
         if ($cd->{clset}{"$which.restrict"} // 1) {
             local $cd->{_debug_ccl_note} = "$which.restrict";
             $c->add_module($cd, "List::Util");
             $c->add_smartmatch_pragma($cd);
             $c->add_ccl(
                 $cd,
                 # here we need ~~ because it can match against strs or regexes
                 "!defined(List::Util::first(sub {!(\$_ ~~ $lit_valid_keys)}, ".
                     "keys %{$dt}))",
                 {
                     err_msg => 'TMP1',
                     err_expr => join(
                         "",
                         'sprintf(',
                         $c->literal($c->_xlt(
                             $cd, "hash contains ".
                                 "unknown field(s) (%s)")),
                         ',',
                         "join(', ', sort grep {!(\$_ ~~ $lit_valid_keys)} ",
                         "keys %{$dt})",
                         ')',
                     ),
                 },
             );
         }
         delete $cd->{uclset}{"$which.restrict"};
 
         my $cdef;
         if ($which eq 'keys') {
             $cdef = $cd->{clset}{"keys.create_default"} // 1;
             delete $cd->{uclset}{"keys.create_default"};
         }
 
         #local $cd->{args}{return_type} = 'bool';
         my $nkeys = scalar(keys %$cv);
         my $i = 0;
         for my $k (sort keys %$cv) {
             my $kre = $c->_str2reliteral($cd, $k);
             local $cd->{spath} = [@{ $cd->{spath} }, $k];
             ++$i;
             my $sch = $c->main->normalize_schema($cv->{$k});
             my $kdn = $k; $kdn =~ s/\W+/_/g;
             my $klit = $which eq 're_keys' ? '$_' : $c->literal($k);
             my $kdt = "$dt\->{$klit}";
             my %iargs = %{$cd->{args}};
             $iargs{outer_cd}             = $cd;
             $iargs{data_name}            = $kdn;
             $iargs{data_term}            = $kdt;
             $iargs{schema}               = $sch;
             $iargs{schema_is_normalized} = 1;
             $iargs{indent_level}++;
             my $icd = $c->compile(%iargs);
 
             # should we set default for hash value?
             my $sdef = $cdef && defined($sch->[1]{default});
 
             # stack is used to store (non-bool) subresults
             $c->add_var($cd, '_sahv_stack', []) if $use_dpath;
 
             my @code = (
                 ($c->indent_str($cd), "(push(@\$_sahv_dpath, undef), push(\@\$_sahv_stack, undef), \$_sahv_stack->[-1] = \n")
                     x !!($use_dpath && $i == 1),
 
                 # for re_keys, we iterate over all data's keys which match regex
                 ('(!defined(List::Util::first(sub {!(')
                     x !!($which eq 're_keys'),
 
                 $which eq 're_keys' ? "\$_ !~ /$kre/ || (" :
                     ($sdef ? "" : "!exists($kdt) || ("),
 
                 ($c->indent_str($cd), "(\$_sahv_dpath->[-1] = ".
                      ($which eq 're_keys' ? '$_' : $klit)."),\n")
                          x !!$use_dpath,
                 $icd->{result}, "\n",
 
                 $which eq 're_keys' || !$sdef ? ")" : "",
 
                 # close iteration over all data's keys which match regex
                 (")}, sort keys %{ $dt })))")
                     x !!($which eq 're_keys'),
 
                 ($c->indent_str($cd), "), pop(\@\$_sahv_dpath), pop(\@\$_sahv_stack)\n")
                     x !!($use_dpath && $i == $nkeys),
             );
             my $ires = join("", @code);
             local $cd->{_debug_ccl_note} = "$which: ".$c->literal($k);
             $c->add_ccl($cd, $ires);
         }
         $jccl = $c->join_ccls(
             $cd, $cd->{ccls}, {err_msg => ''});
     }
     $c->add_ccl($cd, $jccl, {});
 }
 
 sub clause_keys {
     my ($self, $cd) = @_;
     $self->_clause_keys_or_re_keys('keys', $cd);
 }
 
 sub clause_re_keys {
     my ($self, $cd) = @_;
     $self->_clause_keys_or_re_keys('re_keys', $cd);
 }
 
 sub clause_req_keys {
     my ($self, $cd) = @_;
     my $c  = $self->compiler;
     my $ct = $cd->{cl_term};
     my $dt = $cd->{data_term};
 
     # we assign to $_sahv_h first to avoid variable clashing if $dt is '$_'.
 
     $c->add_module($cd, "List::Util");
     $c->add_ccl(
       $cd,
       "do { my \$_sahv_h = $dt; !defined(List::Util::first(sub {!exists(\$_sahv_h\->{\$_})}, \@{ $ct })) }",
       {
         err_msg => 'TMP',
         err_expr =>
           "sprintf(".
           $c->literal($c->_xlt($cd, "hash has missing required field(s) (%s)")).
           ",join(', ', do { my \$_sahv_h = $dt; grep { !exists(\$_sahv_h\->{\$_}) } \@{ $ct } }))"
       }
     );
 }
 
 sub clause_allowed_keys {
     my ($self, $cd) = @_;
     my $c  = $self->compiler;
     my $ct = $cd->{cl_term};
     my $dt = $cd->{data_term};
 
     $c->add_module($cd, "List::Util");
     $c->add_smartmatch_pragma($cd);
     $c->add_ccl(
       $cd,
       "!defined(List::Util::first(sub {!(\$_ ~~ $ct)}, keys \%{ $dt }))",
       {
         err_msg => 'TMP',
         err_expr =>
           "sprintf(".
           $c->literal($c->_xlt($cd, "hash contains non-allowed field(s) (%s)")).
           ",join(', ', sort grep { !(\$_ ~~ $ct) } keys \%{ $dt }))"
       }
     );
 }
 
 sub clause_allowed_keys_re {
     my ($self, $cd) = @_;
     my $c  = $self->compiler;
     #my $ct = $cd->{cl_term};
     my $cv = $cd->{cl_value};
     my $dt = $cd->{data_term};
 
     if ($cd->{cl_is_expr}) {
         # i'm lazy atm and does not need expr yet
         $c->_die_unimplemented_clause($cd, "with expr");
     }
 
     my $re = $c->_str2reliteral($cd, $cv);
     $c->add_module($cd, "List::Util");
     $c->add_smartmatch_pragma($cd);
     $c->add_ccl(
         $cd,
         "!defined(List::Util::first(sub {\$_ !~ /$re/}, keys \%{ $dt }))",
         {
           err_msg => 'TMP',
           err_expr =>
           "sprintf(".
           $c->literal($c->_xlt($cd, "hash contains non-allowed field(s) (%s)")).
           ",join(', ', sort grep { \$_ !~ /$re/ } keys \%{ $dt }))"
       }
     );
 }
 
 sub clause_forbidden_keys {
     my ($self, $cd) = @_;
     my $c  = $self->compiler;
     my $ct = $cd->{cl_term};
     my $dt = $cd->{data_term};
 
     $c->add_module($cd, "List::Util");
     $c->add_smartmatch_pragma($cd);
     $c->add_ccl(
       $cd,
       "!defined(List::Util::first(sub {\$_ ~~ $ct}, keys \%{ $dt }))",
       {
         err_msg => 'TMP',
         err_expr =>
           "sprintf(".
           $c->literal($c->_xlt($cd, "hash contains forbidden field(s) (%s)")).
           ",join(', ', sort grep { \$_ ~~ $ct } keys \%{ $dt }))"
       }
     );
 }
 
 sub clause_forbidden_keys_re {
     my ($self, $cd) = @_;
     my $c  = $self->compiler;
     #my $ct = $cd->{cl_term};
     my $cv = $cd->{cl_value};
     my $dt = $cd->{data_term};
 
     if ($cd->{cl_is_expr}) {
         # i'm lazy atm and does not need expr yet
         $c->_die_unimplemented_clause($cd, "with expr");
     }
 
     my $re = $c->_str2reliteral($cd, $cv);
     $c->add_module($cd, "List::Util");
     $c->add_smartmatch_pragma($cd);
     $c->add_ccl(
         $cd,
         "!defined(List::Util::first(sub {\$_ =~ /$re/}, keys \%{ $dt }))",
         {
           err_msg => 'TMP',
           err_expr =>
           "sprintf(".
           $c->literal($c->_xlt($cd, "hash contains forbidden field(s) (%s)")).
           ",join(', ', sort grep { \$_ =~ /$re/ } keys \%{ $dt }))"
       }
     );
 }
 
 sub clause_choose_one_key {
     my ($self, $cd) = @_;
     my $c  = $self->compiler;
     my $ct = $cd->{cl_term};
     my $dt = $cd->{data_term};
 
     # we assign to $_sahv_h first to avoid variable clashing if $dt is '$_'.
 
     $c->add_module($cd, "List::Util");
     $c->add_ccl(
       $cd,
       "do { my \$_sahv_h = $dt; List::Util::sum(map {exists(\$_sahv_h\->{\$_}) ? 1:0} \@{ $ct }) <= 1 }",
       {},
     );
 }
 
 sub clause_choose_all_keys {
     my ($self, $cd) = @_;
     my $c  = $self->compiler;
     my $ct = $cd->{cl_term};
     my $dt = $cd->{data_term};
 
     # we assign to $h first to avoid variable clashing if $dt is '$_'.
 
     $c->add_module($cd, "List::Util");
     $c->add_ccl(
       $cd,
       "do { my \$_sahv_h = $dt; my \$_sahv_keys = $ct; my \$_sahv_tot = List::Util::sum(map {exists(\$_sahv_h\->{\$_}) ? 1:0} \@\$_sahv_keys); \$_sahv_tot==0 || \$_sahv_tot==\@\$_sahv_keys }",
       {},
     );
 }
 
 sub clause_req_one_key {
     my ($self, $cd) = @_;
     my $c  = $self->compiler;
     my $ct = $cd->{cl_term};
     my $dt = $cd->{data_term};
 
     # we assign to $_sahv_h first to avoid variable clashing if $dt is '$_'.
 
     $c->add_module($cd, "List::Util");
     $c->add_ccl(
       $cd,
       "do { my \$_sahv_h = $dt; List::Util::sum(map {exists(\$_sahv_h\->{\$_}) ? 1:0} \@{ $ct }) == 1 }",
       {},
     );
 }
 
 sub clause_dep_any {
     my ($self, $cd) = @_;
     my $c  = $self->compiler;
     my $ct = $cd->{cl_term};
     my $dt = $cd->{data_term};
 
     # we assign to $_sahv_h first to avoid variable clashing if $dt is '$_'.
 
     $c->add_module($cd, "List::Util");
     $c->add_ccl(
       $cd,
       "do { my \$_sahv_h = $dt; my \$_sahv_ct = $ct; ".
           "my \$_sahv_has_prereq = List::Util::sum(map {exists(\$_sahv_h\->{\$_}) ? 1:0} \@{ \$_sahv_ct->[1] }) ? 1:0; ".
           "my \$_sahv_has_dep    = List::Util::sum(map {exists(\$_sahv_h\->{\$_}) ? 1:0} (ref(\$_sahv_ct->[0]) eq 'ARRAY' ? \@{ \$_sahv_ct->[0] } : (\$_sahv_ct->[0]))) ? 1:0; ".
           "!\$_sahv_has_dep || \$_sahv_has_prereq }",
       {},
     );
 }
 
 sub clause_dep_all {
     my ($self, $cd) = @_;
     my $c  = $self->compiler;
     my $ct = $cd->{cl_term};
     my $dt = $cd->{data_term};
 
     # we assign to $_sahv_h first to avoid variable clashing if $dt is '$_'.
 
     $c->add_module($cd, "List::Util");
     $c->add_ccl(
       $cd,
       "do { my \$_sahv_h = $dt; my \$_sahv_ct = $ct; ".
           "my \$_sahv_has_prereq = List::Util::sum(map {exists(\$_sahv_h\->{\$_}) ? 1:0} \@{ \$_sahv_ct->[1] }) == \@{ \$_sahv_ct->[1] } ? 1:0; ".
           "my \$_sahv_has_dep    = List::Util::sum(map {exists(\$_sahv_h\->{\$_}) ? 1:0} (ref(\$_sahv_ct->[0]) eq 'ARRAY' ? \@{ \$_sahv_ct->[0] } : (\$_sahv_ct->[0]))) ? 1:0; ".
           "!\$_sahv_has_dep || \$_sahv_has_prereq }",
       {},
     );
 }
 
 sub clause_req_dep_any {
     my ($self, $cd) = @_;
     my $c  = $self->compiler;
     my $ct = $cd->{cl_term};
     my $dt = $cd->{data_term};
 
     # we assign to $_sahv_h first to avoid variable clashing if $dt is '$_'.
 
     $c->add_module($cd, "List::Util");
     $c->add_ccl(
       $cd,
       "do { my \$_sahv_h = $dt; my \$_sahv_ct = $ct; ".
           "my \$_sahv_has_prereq = List::Util::sum(map {exists(\$_sahv_h\->{\$_}) ? 1:0} \@{ \$_sahv_ct->[1] }) ? 1:0; ".
           "my \$_sahv_has_dep    = List::Util::sum(map {exists(\$_sahv_h\->{\$_}) ? 1:0} (ref(\$_sahv_ct->[0]) eq 'ARRAY' ? \@{ \$_sahv_ct->[0] } : (\$_sahv_ct->[0]))) ? 1:0; ".
           "\$_sahv_has_dep || !\$_sahv_has_prereq }",
       {},
     );
 }
 
 sub clause_req_dep_all {
     my ($self, $cd) = @_;
     my $c  = $self->compiler;
     my $ct = $cd->{cl_term};
     my $dt = $cd->{data_term};
 
     # we assign to $_sahv_h first to avoid variable clashing if $dt is '$_'.
 
     $c->add_module($cd, "List::Util");
     $c->add_ccl(
       $cd,
       "do { my \$_sahv_h = $dt; my \$_sahv_ct = $ct; ".
           "my \$_sahv_has_prereq = List::Util::sum(map {exists(\$_sahv_h\->{\$_}) ? 1:0} \@{ \$_sahv_ct->[1] }) == \@{ \$_sahv_ct->[1] } ? 1:0; ".
           "my \$_sahv_has_dep    = List::Util::sum(map {exists(\$_sahv_h\->{\$_}) ? 1:0} (ref(\$_sahv_ct->[0]) eq 'ARRAY' ? \@{ \$_sahv_ct->[0] } : (\$_sahv_ct->[0]))) ? 1:0; ".
           "\$_sahv_has_dep || !\$_sahv_has_prereq }",
       {},
     );
 }
 
 1;
 # ABSTRACT: perl's type handler for type "hash"
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Compiler::perl::TH::hash - perl's type handler for type "hash"
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Compiler::perl::TH::hash (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =for Pod::Coverage ^(clause_.+|superclause_.+)$
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Compiler/perl/TH/int.pm ###
 package Data::Sah::Compiler::perl::TH::int;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 #use Log::Any '$log';
 
 use Mo qw(build default);
 use Role::Tiny::With;
 
 extends 'Data::Sah::Compiler::perl::TH::num';
 with 'Data::Sah::Type::int';
 
 sub handle_type {
     my ($self, $cd) = @_;
     my $c = $self->compiler;
 
     my $dt = $cd->{data_term};
     if ($cd->{args}{core} || $cd->{args}{no_modules}) {
         $cd->{_ccl_check_type} = "$dt =~ ".'/\A[+-]?(?:0|[1-9][0-9]*)\z/';
     } else {
         $c->add_sun_module($cd);
         $cd->{_ccl_check_type} =
             "$cd->{_sun_module}::isint($dt)";
     }
 }
 
 sub clause_div_by {
     my ($self, $cd) = @_;
     my $c  = $self->compiler;
     my $ct = $cd->{cl_term};
     my $dt = $cd->{data_term};
 
     $c->add_ccl($cd, "$dt % $ct == 0");
 }
 
 sub clause_mod {
     my ($self, $cd) = @_;
     my $c  = $self->compiler;
     my $ct = $cd->{cl_term};
     my $dt = $cd->{data_term};
 
     $c->add_ccl($cd, "$dt % $ct\->[0] == $ct\->[1]");
 }
 
 1;
 # ABSTRACT: perl's type handler for type "int"
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Compiler::perl::TH::int - perl's type handler for type "int"
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Compiler::perl::TH::int (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =for Pod::Coverage ^(clause_.+|superclause_.+)$
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Compiler/perl/TH/num.pm ###
 package Data::Sah::Compiler::perl::TH::num;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 #use Log::Any '$log';
 
 use Mo qw(build default);
 use Role::Tiny::With;
 
 extends 'Data::Sah::Compiler::perl::TH';
 with 'Data::Sah::Type::num';
 
 sub handle_type {
     my ($self, $cd) = @_;
     my $c = $self->compiler;
     my $dt = $cd->{data_term};
 
     if ($cd->{args}{core} || $cd->{args}{no_modules}) {
         $cd->{_ccl_check_type} = "$dt =~ ".'/\A(?:[+-]?(?:0|[1-9][0-9]*)(\.[0-9]+)?([eE][+-]?[0-9]+)?|((?i)\s*nan\s*)|((?i)\s*[+-]?inf(inity)?)\s*)\z/';
     } else {
         $c->add_sun_module($cd);
         $cd->{_ccl_check_type} = "$cd->{_sun_module}::isnum($dt)";
     }
 }
 
 sub superclause_comparable {
     my ($self, $which, $cd) = @_;
     my $c  = $self->compiler;
     my $ct = $cd->{cl_term};
     my $dt = $cd->{data_term};
 
     if ($which eq 'is') {
         $c->add_ccl($cd, "$dt == $ct");
     } elsif ($which eq 'in') {
         $c->add_smartmatch_pragma($cd);
         $c->add_ccl($cd, "$dt ~~ $ct");
     }
 }
 
 sub superclause_sortable {
     my ($self, $which, $cd) = @_;
     my $c  = $self->compiler;
     my $cv = $cd->{cl_value};
     my $ct = $cd->{cl_term};
     my $dt = $cd->{data_term};
 
     if ($which eq 'min') {
         $c->add_ccl($cd, "$dt >= $ct");
     } elsif ($which eq 'xmin') {
         $c->add_ccl($cd, "$dt > $ct");
     } elsif ($which eq 'max') {
         $c->add_ccl($cd, "$dt <= $ct");
     } elsif ($which eq 'xmax') {
         $c->add_ccl($cd, "$dt < $ct");
     } elsif ($which eq 'between') {
         if ($cd->{cl_is_expr}) {
             $c->add_ccl($cd, "$dt >= $ct\->[0] && $dt <= $ct\->[1]");
         } else {
             # simplify code
             $c->add_ccl($cd, "$dt >= $cv->[0] && $dt <= $cv->[1]");
         }
     } elsif ($which eq 'xbetween') {
         if ($cd->{cl_is_expr}) {
             $c->add_ccl($cd, "$dt > $ct\->[0] && $dt < $ct\->[1]");
         } else {
             # simplify code
             $c->add_ccl($cd, "$dt > $cv->[0] && $dt < $cv->[1]");
         }
     }
 }
 
 1;
 # ABSTRACT: perl's type handler for type "num"
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Compiler::perl::TH::num - perl's type handler for type "num"
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Compiler::perl::TH::num (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =for Pod::Coverage ^(clause_.+|superclause_.+)$
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Compiler/perl/TH/obj.pm ###
 package Data::Sah::Compiler::perl::TH::obj;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 #use Log::Any '$log';
 
 use Mo qw(build default);
 use Role::Tiny::With;
 
 extends 'Data::Sah::Compiler::perl::TH';
 with 'Data::Sah::Type::obj';
 
 sub handle_type {
     my ($self, $cd) = @_;
     my $c = $self->compiler;
 
     my $dt = $cd->{data_term};
     $c->add_module($cd, 'Scalar::Util');
     $cd->{_ccl_check_type} = "Scalar::Util::blessed($dt)";
 }
 
 sub clause_can {
     my ($self, $cd) = @_;
     my $c  = $self->compiler;
     my $ct = $cd->{cl_term};
     my $dt = $cd->{data_term};
 
     $c->add_ccl($cd, "$dt->can($ct)");
 }
 
 sub clause_isa {
     my ($self, $cd) = @_;
     my $c  = $self->compiler;
     my $ct = $cd->{cl_term};
     my $dt = $cd->{data_term};
 
     $c->add_ccl($cd, "$dt->isa($ct)");
 }
 
 1;
 # ABSTRACT: perl's type handler for type "obj"
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Compiler::perl::TH::obj - perl's type handler for type "obj"
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Compiler::perl::TH::obj (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =for Pod::Coverage ^(clause_.+|superclause_.+)$
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Compiler/perl/TH/re.pm ###
 package Data::Sah::Compiler::perl::TH::re;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 #use Log::Any '$log';
 
 use Mo qw(build default);
 use Role::Tiny::With;
 
 extends 'Data::Sah::Compiler::perl::TH';
 with 'Data::Sah::Type::re';
 
 # XXX prefilter to convert string to regex object
 
 sub handle_type {
     my ($self, $cd) = @_;
     my $c = $self->compiler;
 
     my $dt = $cd->{data_term};
     $cd->{_ccl_check_type} = "ref($dt) eq 'Regexp' || !ref($dt) && ".
         "eval { my \$tmp = $dt; qr/\$tmp/; 1 }";
 }
 
 1;
 # ABSTRACT: perl's type handler for type "re"
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Compiler::perl::TH::re - perl's type handler for type "re"
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Compiler::perl::TH::re (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =for Pod::Coverage ^(clause_.+|superclause_.+)$
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Compiler/perl/TH/str.pm ###
 package Data::Sah::Compiler::perl::TH::str;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 #use Log::Any '$log';
 
 use Mo qw(build default);
 use Role::Tiny::With;
 
 extends 'Data::Sah::Compiler::perl::TH';
 with 'Data::Sah::Type::str';
 
 sub handle_type {
     my ($self, $cd) = @_;
     my $c = $self->compiler;
 
     my $dt = $cd->{data_term};
     $cd->{_ccl_check_type} = "!ref($dt)";
 }
 
 sub superclause_comparable {
     my ($self, $which, $cd) = @_;
     my $c  = $self->compiler;
     my $ct = $cd->{cl_term};
     my $dt = $cd->{data_term};
 
     if ($which eq 'is') {
         $c->add_ccl($cd, "$dt eq $ct");
     } elsif ($which eq 'in') {
         $c->add_smartmatch_pragma($cd);
         $c->add_ccl($cd, "$dt ~~ $ct");
     }
 }
 
 sub superclause_sortable {
     my ($self, $which, $cd) = @_;
     my $c  = $self->compiler;
     my $cv = $cd->{cl_value};
     my $ct = $cd->{cl_term};
     my $dt = $cd->{data_term};
 
     if ($which eq 'min') {
         $c->add_ccl($cd, "$dt ge $ct");
     } elsif ($which eq 'xmin') {
         $c->add_ccl($cd, "$dt gt $ct");
     } elsif ($which eq 'max') {
         $c->add_ccl($cd, "$dt le $ct");
     } elsif ($which eq 'xmax') {
         $c->add_ccl($cd, "$dt lt $ct");
     } elsif ($which eq 'between') {
         if ($cd->{cl_is_expr}) {
             $c->add_ccl($cd, "$dt ge $ct\->[0] && $dt le $ct\->[1]");
         } else {
             # simplify code
             $c->add_ccl($cd, "$dt ge ".$c->literal($cv->[0]).
                             " && $dt le ".$c->literal($cv->[1]));
         }
     } elsif ($which eq 'xbetween') {
         if ($cd->{cl_is_expr}) {
             $c->add_ccl($cd, "$dt gt $ct\->[0] && $dt lt $ct\->[1]");
         } else {
             # simplify code
             $c->add_ccl($cd, "$dt gt ".$c->literal($cv->[0]).
                             " && $dt lt ".$c->literal($cv->[1]));
         }
     }
 }
 
 sub superclause_has_elems {
     my ($self_th, $which, $cd) = @_;
     my $c  = $self_th->compiler;
     my $cv = $cd->{cl_value};
     my $ct = $cd->{cl_term};
     my $dt = $cd->{data_term};
 
     if ($which eq 'len') {
         $c->add_ccl($cd, "length($dt) == $ct");
     } elsif ($which eq 'min_len') {
         $c->add_ccl($cd, "length($dt) >= $ct");
     } elsif ($which eq 'max_len') {
         $c->add_ccl($cd, "length($dt) <= $ct");
     } elsif ($which eq 'len_between') {
         if ($cd->{cl_is_expr}) {
             $c->add_ccl(
                 $cd, "length($dt) >= $ct\->[0] && ".
                     "length($dt) >= $ct\->[1]");
         } else {
             # simplify code
             $c->add_ccl(
                 $cd, "length($dt) >= $cv->[0] && ".
                     "length($dt) <= $cv->[1]");
         }
     } elsif ($which eq 'has') {
         $c->add_ccl($cd, "index($dt, $ct) >= 0");
     } elsif ($which eq 'each_index') {
         $self_th->gen_each($cd, "0..length($dt)-1", '_', '$_');
     } elsif ($which eq 'each_elem') {
         $self_th->gen_each($cd, "0..length($dt)-1", '_', "substr($dt, \$_, 1)");
     } elsif ($which eq 'check_each_index') {
         $self_th->compiler->_die_unimplemented_clause($cd);
     } elsif ($which eq 'check_each_elem') {
         $self_th->compiler->_die_unimplemented_clause($cd);
     } elsif ($which eq 'uniq') {
         $self_th->compiler->_die_unimplemented_clause($cd);
     } elsif ($which eq 'exists') {
         $self_th->compiler->_die_unimplemented_clause($cd);
     }
 }
 
 sub clause_encoding {
     my ($self, $cd) = @_;
     my $c  = $self->compiler;
     my $cv = $cd->{cl_value};
     my $ct = $cd->{cl_term};
     my $dt = $cd->{data_term};
 
     $c->_die($cd, "Only 'utf8' encoding is currently supported")
         unless $cv eq 'utf8';
     # currently does nothing
 }
 
 sub clause_match {
     my ($self, $cd) = @_;
     my $c  = $self->compiler;
     my $cv = $cd->{cl_value};
     my $ct = $cd->{cl_term};
     my $dt = $cd->{data_term};
 
     if ($cd->{cl_is_expr}) {
         $c->add_ccl($cd, join(
             "",
             "ref($ct) eq 'Regexp' ? $dt =~ $ct : ",
             "do { my \$re = $ct; eval { \$re = /\$re/; 1 } && ",
             "$dt =~ \$re }",
         ));
     } else {
         # simplify code and we can check regex at compile time
         my $re = $c->_str2reliteral($cd, $cv);
         $c->add_ccl($cd, "$dt =~ qr($re)");
     }
 }
 
 sub clause_is_re {
     my ($self, $cd) = @_;
     my $c  = $self->compiler;
     my $cv = $cd->{cl_value};
     my $ct = $cd->{cl_term};
     my $dt = $cd->{data_term};
 
     if ($cd->{cl_is_expr}) {
         $c->add_ccl($cd, join(
             "",
             "do { my \$re = $dt; ",
             "(eval { \$re = qr/\$re/; 1 } ? 1:0) == ($ct ? 1:0) }",
         ));
     } else {
         # simplify code
         $c->add_ccl($cd, join(
             "",
             "do { my \$re = $dt; ",
             ($cv ? "" : "!"), "(eval { \$re = qr/\$re/; 1 })",
             "}",
         ));
     }
 }
 
 1;
 # ABSTRACT: perl's type handler for type "str"
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Compiler::perl::TH::str - perl's type handler for type "str"
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Compiler::perl::TH::str (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =for Pod::Coverage ^(clause_.+|superclause_.+)$
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Compiler/perl/TH/undef.pm ###
 package Data::Sah::Compiler::perl::TH::undef;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 #use Log::Any '$log';
 
 use Mo qw(build default);
 use Role::Tiny::With;
 
 extends 'Data::Sah::Compiler::perl::TH';
 with 'Data::Sah::Type::undef';
 
 sub handle_type {
     my ($self, $cd) = @_;
     my $c = $self->compiler;
 
     my $dt = $cd->{data_term};
     $cd->{_ccl_check_type} = "!defined($dt)";
 }
 
 1;
 # ABSTRACT: perl's type handler for type "undef"
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Compiler::perl::TH::undef - perl's type handler for type "undef"
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Compiler::perl::TH::undef (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =for Pod::Coverage ^(clause_.+|superclause_.+)$
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Human.pm ###
 package Data::Sah::Human;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 #use Log::Any::IfLOG qw($log);
 
 our $Log_Validator_Code = $ENV{LOG_SAH_VALIDATOR_CODE} // 0;
 
 require Exporter;
 our @ISA       = qw(Exporter);
 our @EXPORT_OK = qw(gen_human_msg);
 
 sub gen_human_msg {
     require Data::Sah;
 
     my ($schema, $opts) = @_;
 
     state $hc = Data::Sah->new->get_compiler("human");
 
     my %args = (schema => $schema, %{$opts // {}});
     my $opt_source = delete $args{source};
 
     $args{log_result} = 1 if $Log_Validator_Code;
 
     my $cd = $hc->compile(%args);
     $opt_source ? $cd : $cd->{result};
 }
 
 1;
 # ABSTRACT: Some functions to use Data::Sah human compiler
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Human - Some functions to use Data::Sah human compiler
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Human (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =head1 SYNOPSIS
 
  use Data::Sah::Human qw(gen_human_msg);
 
  say gen_human_msg(["int*", min=>2]); # -> "Integer, minimum 2"
 
 =head1 DESCRIPTION
 
 =head1 FUNCTIONS
 
 None exported by default.
 
 =head2 gen_human_msg($schema, \%opts) => STR (or ANY)
 
 Compile schema using human compiler and return the result.
 
 Known options (unknown ones will be passed to the compiler):
 
 =over
 
 =item * source => BOOL (default: 0)
 
 If set to true, will return raw compilation result.
 
 =back
 
 =head1 ENVIRONMENT
 
 L<LOG_SAH_VALIDATOR_CODE>
 
 =head1 SEE ALSO
 
 L<Data::Sah>, L<Data::Sah::Compiler::human>.
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/JS.pm ###
 package Data::Sah::JS;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 #use Log::Any qw($log);
 
 our $Log_Validator_Code = $ENV{LOG_SAH_VALIDATOR_CODE} // 0;
 
 require Exporter;
 our @ISA       = qw(Exporter);
 our @EXPORT_OK = qw(gen_validator);
 
 # check availability of the node.js executable, return the path to executable or
 # undef if none is available. node.js is normally installed as 'node', except on
 # debian ('nodejs').
 sub get_nodejs_path {
     require File::Which;
 
     my $path;
     for my $name (qw/nodejs node/) {
         $path = File::Which::which($name);
         next unless $path;
 
         # check if it's really nodejs
         my $cmd = "$path -e 'console.log(1+1)'";
         my $out = `$cmd`;
         if ($out =~ /\A2\n?\z/) {
             return $path;
         } else {
             #say "D:Output of $cmd: $out";
         }
     }
     return undef;
 }
 
 sub gen_validator {
     require Data::Sah;
 
     my ($schema, $opts) = @_;
 
     state $jsc = Data::Sah->new->get_compiler("js");
 
     my %args = (schema => $schema, %{$opts // {}});
     my $opt_source = delete $args{source};
 
     $args{log_result} = 1 if $Log_Validator_Code;
 
     my $v_src = $jsc->expr_validator_sub(%args);
     return $v_src if $opt_source;
 
     state $nodejs_path = get_nodejs_path();
     die "Can't find node.js in PATH" unless $nodejs_path;
 
 
     sub {
         require File::Temp;
         require JSON;
         #require String::ShellQuote;
 
         my $data = shift;
 
         state $json = JSON->new->allow_nonref;
 
         # code to be sent to nodejs
         my $src = "var validator = $v_src;\n\n".
             "console.log(JSON.stringify(validator(".
                 $json->encode($data).")))";
 
         my ($jsh, $jsfn) = File::Temp::tempfile();
         print $jsh $src;
         close($jsh) or die "Can't write JS code to file $jsfn: $!";
 
         my $cmd = "$nodejs_path $jsfn";
         my $out = `$cmd`;
         $json->decode($out);
     };
 }
 
 1;
 # ABSTRACT: Some functions to use JavaScript Sah validator code from Perl
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::JS - Some functions to use JavaScript Sah validator code from Perl
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::JS (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =head1 SYNOPSIS
 
  use Data::Sah::JS qw(gen_validator);
 
  my $v = gen_validator(["int*", min=>1, max=>10]);
 
  # validate your data using the generated validator
  say "valid" if $v->(5);     # valid
  say "valid" if $v->(11);    # invalid
  say "valid" if $v->(undef); # invalid
  say "valid" if $v->("x");   # invalid
 
  # generate validator which reports error message string, in Indonesian
  my $v = gen_validator(["int*", min=>1, max=>10],
                        {return_type=>'str', lang=>'id_ID'});
  say $v->(5);  # ''
  say $v->(12); # 'Data tidak boleh lebih besar dari 10'
                # (in English: 'Data must not be larger than 10')
 
 =head1 DESCRIPTION
 
 =for Pod::Coverage ^(get_nodejs_path)$
 
 =head1 FUNCTIONS
 
 None exported by default.
 
 =head2 gen_validator($schema, \%opts) => CODE (or STR)
 
 Generate validator code for C<$schema>. This is currently used for testing
 purposes only, as this will first generate JavaScript validator code, then
 generate a Perl coderef that will feed generated JavaScript validator code to a
 JavaScript engine (currently node.js) via command-line. Not exactly efficient.
 
 Known options (unknown options will be passed to JS schema compiler):
 
 =over
 
 =item * source => BOOL (default: 0)
 
 If set to 1, return JavaScript source code string instead of Perl coderef.
 Usually only needed for debugging (but see also
 C<$Data::Sah::Log_Validator_Code> and C<LOG_SAH_VALIDATOR_CODE> if you want to
 log validator source code).
 
 =back
 
 =head1 ENVIRONMENT
 
 L<LOG_SAH_VALIDATOR_CODE>
 
 =head1 SEE ALSO
 
 L<Data::Sah>, L<Data::Sah::Compiler::js>.
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Lang.pm ###
 package Data::Sah::Lang;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 
 our @ISA    = qw(Exporter);
 our @EXPORT = qw(add_translations);
 
 sub add_translations {
     my %args = @_;
 
     # XXX check caller package and determine language, fill translations in
     # %Data::Sah::Lang::<lang>::translations
 }
 
 1;
 # ABSTRACT: Language routines
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Lang - Language routines
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Lang (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =for Pod::Coverage add_translations
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Lang/fr_FR.pm ###
 package Data::Sah::Lang::fr_FR;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 
 use Tie::IxHash;
 
 # currently incomplete
 
 our %translations;
 tie %translations, 'Tie::IxHash', (
 
     # punctuations
 
     q[ ], # inter-word boundary
     q[ ],
 
     q[, ],
     q[, ],
 
     q[: ],
     q[: ],
 
     q[. ],
     q[. ],
 
     q[(],
     q[(],
 
     q[)],
     q[)],
 
     # modal verbs
 
     q[must],
     q[doit],
 
     q[must not],
     q[ne doit pas],
 
     q[should],
     q[devrait],
 
     q[should not],
     q[ne devrait pas],
 
     # field/fields/argument/arguments
 
     q[field],
     q[champ],
 
     q[fields],
     q[champs],
 
     q[argument],
     q[argument],
 
     q[arguments],
     q[arguments],
 
     # multi
 
     q[%s and %s],
     q[%s et %s],
 
     q[%s or %s],
     q[%s ou %s],
 
     q[one of %s],
     q[une des %s],
 
     q[all of %s],
     q[toutes les valeurs %s],
 
     q[%(modal_verb)s satisfy all of the following],
     q[%(modal_verb)s satisfaire à toutes les conditions suivantes],
 
     q[%(modal_verb)s satisfy one of the following],
     q[%(modal_verb)s satisfaire l'une des conditions suivantes],
 
     q[%(modal_verb)s satisfy none of the following],
     q[%(modal_verb)s satisfaire à aucune des conditions suivantes],
 
     # type: BaseType
 
     # type: Sortable
 
     # type: Comparable
 
     # type: HasElems
 
     # type: num
 
     # type: int
 
     q[integer],
     q[nombre entier],
 
     q[integers],
     q[nombres entiers],
 
     q[%(modal_verb)s be divisible by %s],
     q[%(modal_verb)s être divisible par %s],
 
     q[%(modal_verb)s leave a remainder of %2$s when divided by %1$s],
     q[%(modal_verb)s laisser un reste %2$s si divisé par %1$s],
 
 );
 
 1;
 # ABSTRACT: fr_FR locale
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Lang::fr_FR - fr_FR locale
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Lang::fr_FR (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =for Pod::Coverage .+
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Lang/id_ID.pm ###
 package Data::Sah::Lang::id_ID;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 
 use Tie::IxHash;
 
 sub ordinate {
     my ($n, $noun) = @_;
     "$noun ke-$n";
 }
 
 our %translations;
 tie %translations, 'Tie::IxHash', (
 
     # punctuations
 
     q[ ], # inter-word boundary
     q[ ],
 
     q[, ],
     q[, ],
 
     q[: ],
     q[: ],
 
     q[. ],
     q[. ],
 
     q[(],
     q[(],
 
     q[)],
     q[)],
 
     # modal verbs
 
     q[must],
     q[harus],
 
     q[must not],
     q[tidak boleh],
 
     q[should],
     q[sebaiknya],
 
     q[should not],
     q[sebaiknya tidak],
 
     # field/fields/argument/arguments
 
     q[field],
     q[field],
 
     q[fields],
     q[field],
 
     q[argument],
     q[argumen],
 
     q[arguments],
     q[argumen],
 
     # multi
 
     q[%s and %s],
     q[%s dan %s],
 
     q[%s or %s],
     q[%s atau %s],
 
     q[%s nor %s],
     q[%s maupun %s],
 
     q[one of %s],
     q[salah satu dari %s],
 
     q[all of %s],
     q[semua dari nilai-nilai %s],
 
     q[any of %s],
     q[satupun dari %s],
 
     q[none of %s],
     q[tak satupun dari %s],
 
     q[%(modal_verb)s satisfy all of the following],
     q[%(modal_verb)s memenuhi semua ketentuan ini],
 
     q[%(modal_verb)s satisfy none all of the following],
     q[%(modal_verb)s melanggar semua ketentuan ini],
 
     q[%(modal_verb)s satisfy one of the following],
     q[%(modal_verb)s memenuhi salah satu ketentuan ini],
 
     # type: BaseType
 
     q[default value is %s],
     q[jika tidak diisi diset ke %s],
 
     q[required %s],
     q[%s wajib diisi],
 
     q[optional %s],
     q[%s opsional],
 
     q[forbidden %s],
     q[%s tidak boleh diisi],
 
     # type: Comparable
 
     q[%(modal_verb)s have the value %s],
     q[%(modal_verb)s bernilai %s],
 
     q[%(modal_verb)s be one of %s],
     q[%(modal_verb)s salah satu dari %s],
 
     # type: HasElems
 
     q[length %(modal_verb)s be %s],
     q[panjang %(modal_verb)s %s],
 
     q[length %(modal_verb)s be at least %s],
     q[panjang %(modal_verb)s minimal %s],
 
     q[length %(modal_verb)s be at most %s],
     q[panjang %(modal_verb)s maksimal %s],
 
     q[length %(modal_verb)s be between %s and %s],
     q[panjang %(modal_verb)s antara %s dan %s],
 
     q[%(modal_verb)s have %s in its elements],
     q[%(modal_verb)s mengandung %s di elemennya],
 
     # type: Sortable
 
     q[%(modal_verb)s be at least %s],
     q[%(modal_verb)s minimal %s],
 
     q[%(modal_verb)s be larger than %s],
     q[%(modal_verb)s lebih besar dari %s],
 
     q[%(modal_verb)s be at most %s],
     q[%(modal_verb)s maksimal %s],
 
     q[%(modal_verb)s be smaller than %s],
     q[%(modal_verb)s lebih kecil dari %s],
 
     q[%(modal_verb)s be between %s and %s],
     q[%(modal_verb)s antara %s dan %s],
 
     q[%(modal_verb)s be larger than %s and smaller than %s],
     q[%(modal_verb)s lebih besar dari %s dan lebih kecil dari %s],
 
     # type: undef
 
     q[undefined value],
     q[nilai tak terdefinisi],
 
     q[undefined values],
     q[nilai tak terdefinisi],
 
     # type: all
 
     q[%(modal_verb)s be %s],
     q[%(modal_verb)s %s],
 
     q[as well as %s],
     q[juga %s],
 
     q[%(modal_verb)s be all of the following],
     q[%(modal_verb)s merupakan semua ini],
 
     # type: any
 
     q[%(modal_verb)s be either %s],
     q[%s],
 
     q[or %s],
     q[atau %s],
 
     q[%(modal_verb)s be one of the following],
     q[%(modal_verb)s merupakan salah satu dari],
 
     # type: array
 
     q[array],
     q[larik],
 
     q[arrays],
     q[larik],
 
     q[%s of %s],
     q[%s %s],
 
     q[each array element %(modal_verb)s be],
     q[setiap elemen larik %(modal_verb)s],
 
     q[%s %(modal_verb)s be],
     q[%s %(modal_verb)s],
 
     q[element],
     q[elemen],
 
     q[each array subscript %(modal_verb)s be],
     q[setiap subskrip larik %(modal_verb)s],
 
     # type: bool
 
     q[boolean value],
     q[nilai boolean],
 
     q[boolean values],
     q[nilai boolean],
 
     q[%(modal_verb)s be true],
     q[%(modal_verb)s bernilai benar],
 
     q[%(modal_verb)s be false],
     q[%(modal_verb)s bernilai salah],
 
     # type: code
 
     q[code],
     q[kode],
 
     q[codes],
     q[kode],
 
     # type: float
 
     q[decimal number],
     q[bilangan desimal],
 
     q[decimal numbers],
     q[bilangan desimal],
 
     q[%(modal_verb)s be a NaN],
     q[%(modal_verb)s NaN],
 
     q[%(modal_verb_neg)s be a NaN],
     q[%(modal_verb_neg)s NaN],
 
     q[%(modal_verb)s be an infinity],
     q[%(modal_verb)s tak hingga],
 
     q[%(modal_verb_neg)s be an infinity],
     q[%(modal_verb_neg)s tak hingga],
 
     q[%(modal_verb)s be a positive infinity],
     q[%(modal_verb)s positif tak hingga],
 
     q[%(modal_verb_neg)s be a positive infinity],
     q[%(modal_verb_neg)s positif tak hingga],
 
     q[%(modal_verb)s be a negative infinity],
     q[%(modal_verb)s negatif tak hingga],
 
     q[%(modal_verb)s be a negative infinity],
     q[%(modal_verb)s negatif tak hingga],
 
     # type: hash
 
     q[hash],
     q[hash],
 
     q[hashes],
     q[hash],
 
     q[field %s %(modal_verb)s be],
     q[field %s %(modal_verb)s],
 
     q[field name %(modal_verb)s be],
     q[nama field %(modal_verb)s],
 
     q[each field %(modal_verb)s be],
     q[setiap field %(modal_verb)s],
 
     q[hash contains unknown field(s) (%s)],
     q[hash mengandung field yang tidak dikenali (%s)],
 
     q[hash contains unknown field(s) (%s)],
     q[hash mengandung field yang tidak dikenali (%s)],
 
     q[%(modal_verb)s have required fields %s],
     q[%(modal_verb)s mengandung field wajib %s],
 
     q[hash has missing required field(s) (%s)],
     q[hash kekurangan field wajib (%s)],
 
     q[%(modal_verb)s have %s in its field values],
     q[%(modal_verb)s mengandung %s di nilai field],
 
     q[%(modal_verb)s only have these allowed fields %s],
     q[%(modal_verb)s hanya mengandung field yang diizinkan %s],
 
     q[%(modal_verb)s only have fields matching regex pattern %s],
     q[%(modal_verb)s hanya mengandung field yang namanya mengikuti pola regex %s],
 
     q[%(modal_verb_neg)s have these forbidden fields %s],
     q[%(modal_verb_neg)s mengandung field yang dilarang %s],
 
     q[%(modal_verb_neg)s have fields matching regex pattern %s],
     q[%(modal_verb_neg)s mengandung field yang namanya mengikuti pola regex %s],
 
     q[hash contains non-allowed field(s) (%s)],
     q[hash mengandung field yang tidak diizinkan (%s)],
 
     q[hash contains forbidden field(s) (%s)],
     q[hash mengandung field yang dilarang (%s)],
 
     q[fields whose names match regex pattern %s %(modal_verb)s be],
     q[field yang namanya cocok dengan pola regex %s %(modal_verb)s],
 
     # type: int
 
     q[integer],
     q[bilangan bulat],
 
     q[integers],
     q[bilangan bulat],
 
     q[%(modal_verb)s be divisible by %s],
     q[%(modal_verb)s dapat dibagi oleh %s],
 
     q[%(modal_verb)s be odd],
     q[%(modal_verb)s ganjil],
 
     q[%(modal_verb)s be even],
     q[%(modal_verb)s genap],
 
     q[%(modal_verb)s leave a remainder of %2$s when divided by %1$s],
     q[jika dibagi %1$s %(modal_verb)s menyisakan %2$s],
 
     # type: num
 
     q[number],
     q[bilangan],
 
     q[numbers],
     q[bilangan],
 
     # type: obj
 
     q[object],
     q[objek],
 
     q[objects],
     q[objek],
 
     # type: re
 
     q[regex pattern],
     q[pola regex],
 
     q[regex patterns],
     q[pola regex],
 
     # type: str
 
     q[text],
     q[teks],
 
     q[texts],
     q[teks],
 
     q[%(modal_verb)s match regex pattern %s],
     q[%(modal_verb)s cocok dengan pola regex %s],
 
     q[%(modal_verb)s be a regex pattern],
     q[%(modal_verb)s pola regex],
 
     q[each subscript of text %(modal_verb)s be],
     q[setiap subskrip dari teks %(modal_verb)s],
 
     q[each character of the text %(modal_verb)s be],
     q[setiap karakter dari teks %(modal_verb)s],
 
     q[character],
     q[karakter],
 
     # type: cistr
 
     # type: buf
 
     q[buffer],
     q[buffer],
 
     q[buffers],
     q[buffer],
 
     # messages for compiler
 
     q[Does not satisfy the following schema: %s],
     q[Tidak memenuhi skema ini: %s],
 
     q[Not of type %s],
     q[Tidak bertipe %s],
 
     q[Required but not specified],
     q[Wajib tapi belum diisi],
 
     q[Forbidden but specified],
     q[Dilarang tapi diisi],
 
     q[Structure contains unknown field(s) [%%s]],
     q[Struktur mengandung field yang tidak dikenal [%%s]],
 
 );
 
 1;
 # ABSTRACT: id_ID locale
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Lang::id_ID - id_ID locale
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Lang::id_ID (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =for Pod::Coverage .+
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Lang/zh_CN.pm ###
 package Data::Sah::Lang::zh_CN;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 
 use Tie::IxHash;
 
 # currently incomplete
 
 our %translations;
 tie %translations, 'Tie::IxHash', (
 
     # punctuations
 
     q[ ], # inter-word boundary
     q[],
 
     q[, ],
     q[，],
 
     q[: ],
     q[：],
 
     q[. ],
     q[。],
 
     q[(],
     q[（],
 
     q[)],
     q[）],
 
     # modal verbs
 
     q[must],
     q[必须],
 
     q[must not],
     q[必须不],
 
     q[should],
     q[应],
 
     q[should not],
     q[应不],
 
     # field/fields/argument/arguments
 
     q[field],
     q[字段],
 
     q[fields],
     q[字段],
 
     q[argument],
     q[参数],
 
     q[arguments],
     q[参数],
 
     # multi
 
     q[%s and %s],
     q[%s和%s],
 
     q[%s or %s],
     q[%s或%s],
 
     q[one of %s],
     q[这些值%s之一],
 
     q[all of %s],
     q[所有这些值%s],
 
     q[%(modal_verb)s satisfy all of the following],
     q[%(modal_verb)s满足所有这些条件],
 
     q[%(modal_verb)s satisfy one of the following],
     q[%(modal_verb)s满足这些条件之一],
 
     q[%(modal_verb)s satisfy none of the following],
     q[%(modal_verb_neg)s满足所有这些条件],
 
     # type: BaseType
 
     # type: Sortable
 
     # type: Comparable
 
     # type: HasElems
 
     # type: num
 
     # type: int
 
     q[integer],
     q[整数],
 
     q[integers],
     q[整数],
 
     q[%(modal_verb)s be divisible by %s],
     q[%(modal_verb)s被%s整除],
 
     q[%(modal_verb)s leave a remainder of %2$s when divided by %1$s],
     q[除以%1$s时余数%(modal_verb)s为%2$s],
 
 );
 
 1;
 # ABSTRACT: zh_CN locale
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Lang::zh_CN - zh_CN locale
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Lang::zh_CN (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =for Pod::Coverage .+
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Normalize.pm ###
 package Data::Sah::Normalize;
 
 use 5.010001;
 use strict;
 use warnings;
 
 our $DATE = '2015-09-06'; # DATE
 our $VERSION = '0.04'; # VERSION
 
 require Exporter;
 our @ISA       = qw(Exporter);
 our @EXPORT_OK = qw(
                        normalize_clset
                        normalize_schema
 
                        $type_re
                        $clause_name_re
                        $clause_re
                        $attr_re
                        $funcset_re
                        $compiler_re
                );
 
 our $type_re        = qr/\A(?:[A-Za-z_]\w*::)*[A-Za-z_]\w*\z/;
 our $clause_name_re = qr/\A[A-Za-z_]\w*\z/;
 our $clause_re      = qr/\A[A-Za-z_]\w*(?:\.[A-Za-z_]\w*)*\z/;
 our $attr_re        = $clause_re;
 our $funcset_re     = qr/\A(?:[A-Za-z_]\w*::)*[A-Za-z_]\w*\z/;
 our $compiler_re    = qr/\A[A-Za-z_]\w*\z/;
 our $clause_attr_on_empty_clause_re = qr/\A(?:\.[A-Za-z_]\w*)+\z/;
 
 sub normalize_clset($;$) {
     my ($clset0, $opts) = @_;
     $opts //= {};
 
     my $clset = {};
     for my $c (sort keys %$clset0) {
         my $c0 = $c;
 
         my $v = $clset0->{$c};
 
         # ignore expression
         my $expr;
         if ($c =~ s/=\z//) {
             $expr++;
             # XXX currently can't disregard merge prefix when checking
             # conflict
             die "Conflict between '$c=' and '$c'" if exists $clset0->{$c};
             $clset->{"$c.is_expr"} = 1;
             }
 
         my $sc = "";
         my $cn;
         {
             my $errp = "Invalid clause name syntax '$c0'"; # error prefix
             if (!$expr && $c =~ s/\A!(?=.)//) {
                 die "$errp, syntax should be !CLAUSE"
                     unless $c =~ $clause_name_re;
                 $sc = "!";
             } elsif (!$expr && $c =~ s/(?<=.)\|\z//) {
                 die "$errp, syntax should be CLAUSE|"
                     unless $c =~ $clause_name_re;
                 $sc = "|";
             } elsif (!$expr && $c =~ s/(?<=.)\&\z//) {
                 die "$errp, syntax should be CLAUSE&"
                     unless $c =~ $clause_name_re;
                 $sc = "&";
             } elsif (!$expr && $c =~ /\A([^.]+)(?:\.(.+))?\((\w+)\)\z/) {
                 my ($c2, $a, $lang) = ($1, $2, $3);
                 die "$errp, syntax should be CLAUSE(LANG) or C.ATTR(LANG)"
                     unless $c2 =~ $clause_name_re &&
                         (!defined($a) || $a =~ $attr_re);
                 $sc = "(LANG)";
                 $cn = $c2 . (defined($a) ? ".$a" : "") . ".alt.lang.$lang";
             } elsif ($c !~ $clause_re &&
                          $c !~ $clause_attr_on_empty_clause_re) {
                 die "$errp, please use letter/digit/underscore only";
             }
         }
 
         # XXX can't disregard merge prefix when checking conflict
         if ($sc eq '!') {
             die "Conflict between clause shortcuts '!$c' and '$c'"
                 if exists $clset0->{$c};
             die "Conflict between clause shortcuts '!$c' and '$c|'"
                 if exists $clset0->{"$c|"};
             die "Conflict between clause shortcuts '!$c' and '$c&'"
                 if exists $clset0->{"$c&"};
             $clset->{$c} = $v;
             $clset->{"$c.op"} = "not";
         } elsif ($sc eq '&') {
             die "Conflict between clause shortcuts '$c&' and '$c'"
                 if exists $clset0->{$c};
             die "Conflict between clause shortcuts '$c&' and '$c|'"
                 if exists $clset0->{"$c|"};
             die "Clause 'c&' value must be an array"
                 unless ref($v) eq 'ARRAY';
             $clset->{$c} = $v;
             $clset->{"$c.op"} = "and";
         } elsif ($sc eq '|') {
             die "Conflict between clause shortcuts '$c|' and '$c'"
                 if exists $clset0->{$c};
             die "Clause 'c|' value must be an array"
                 unless ref($v) eq 'ARRAY';
             $clset->{$c} = $v;
             $clset->{"$c.op"} = "or";
         } elsif ($sc eq '(LANG)') {
             die "Conflict between clause '$c' and '$cn'"
                 if exists $clset0->{$cn};
             $clset->{$cn} = $v;
         } else {
             $clset->{$c} = $v;
         }
 
     }
     $clset->{req} = 1 if $opts->{has_req};
 
     # XXX option to recursively normalize clset, any's of, all's of, ...
     #if ($clset->{clset}) {
     #    local $opts->{has_req};
     #    if ($clset->{'clset.op'} && $clset->{'clset.op'} =~ /and|or/) {
     #        # multiple clause sets
     #        $clset->{clset} = map { $self->normalize_clset($_, $opts) }
     #            @{ $clset->{clset} };
     #    } else {
     #        $clset->{clset} = $self->normalize_clset($_, $opts);
     #    }
     #}
 
     $clset;
 }
 
 sub normalize_schema($) {
     my $s = shift;
 
     my $ref = ref($s);
     if (!defined($s)) {
 
         die "Schema is missing";
 
     } elsif (!$ref) {
 
         my $has_req = $s =~ s/\*\z//;
         $s =~ $type_re or die "Invalid type syntax $s, please use ".
             "letter/digit/underscore only";
         return [$s, $has_req ? {req=>1} : {}, {}];
 
     } elsif ($ref eq 'ARRAY') {
 
         my $t = $s->[0];
         my $has_req = $t && $t =~ s/\*\z//;
         if (!defined($t)) {
             die "For array form, at least 1 element is needed for type";
         } elsif (ref $t) {
             die "For array form, first element must be a string";
         }
         $t =~ $type_re or die "Invalid type syntax $s, please use ".
             "letter/digit/underscore only";
 
         my $clset0;
         my $extras;
         if (defined($s->[1])) {
             if (ref($s->[1]) eq 'HASH') {
                 $clset0 = $s->[1];
                 $extras = $s->[2];
                 die "For array form, there should not be more than 3 elements"
                     if @$s > 3;
             } else {
                 # flattened clause set [t, c=>1, c2=>2, ...]
                 die "For array in the form of [t, c1=>1, ...], there must be ".
                     "3 elements (or 5, 7, ...)"
                         unless @$s % 2;
                 $clset0 = { @{$s}[1..@$s-1] };
             }
         } else {
             $clset0 = {};
         }
 
         # check clauses and parse shortcuts (!c, c&, c|, c=)
         my $clset = normalize_clset($clset0, {has_req=>$has_req});
         if (defined $extras) {
             die "For array form with 3 elements, extras must be hash"
                 unless ref($extras) eq 'HASH';
             die "'def' in extras must be a hash"
                 if exists $extras->{def} && ref($extras->{def}) ne 'HASH';
             return [$t, $clset, { %{$extras} }];
         } else {
             return [$t, $clset, {}];
         }
     }
 
     die "Schema must be a string or arrayref (not $ref)";
 }
 
 1;
 # ABSTRACT: Normalize Sah schema
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Normalize - Normalize Sah schema
 
 =head1 VERSION
 
 This document describes version 0.04 of Data::Sah::Normalize (from Perl distribution Data-Sah-Normalize), released on 2015-09-06.
 
 =head1 SYNOPSIS
 
  use Data::Sah::Normalize qw(normalize_clset normalize_schema);
 
  my $nclset = normalize_clset({'!a'=>1}); # -> {a=>1, 'a.op'=>'not'}
  my $nsch   = normalize_schema("int");    # -> ["int", {}, {}]
 
 =head1 DESCRIPTION
 
 This often-needed functionality is split from the main L<Data::Sah> to keep it
 in a small and minimal-dependencies package.
 
 =head1 FUNCTIONS
 
 =head2 normalize_clset($clset) => HASH
 
 Normalize a clause set (hash). Return a shallow copy of the original hash. Die
 on failure.
 
 TODO: option to recursively normalize clause which contains sah clauses (e.g.
 C<of>).
 
 =head2 normalize_schema($sch) => ARRAY
 
 Normalize a Sah schema (scalar or array). Return an array. Produce a 2-level
 copy of schema, so it's safe to add/delete/modify the normalized schema's clause
 set and extras (but clause set's and extras' values are still references to the
 original). Die on failure.
 
 TODO: recursively normalize clause which contains sah clauses (e.g. C<of>).
 
 =head1 SEE ALSO
 
 L<Sah>, L<Data::Sah>
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah-Normalize>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah-Normalize>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah-Normalize>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Type/BaseType.pm ###
 package Data::Sah::Type::BaseType;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 # why name it BaseType instead of Base? because I'm sick of having 5 files named
 # Base.pm in my editor (there would be Type::Base and the various
 # Compiler::*::Type::Base).
 
 use 5.010;
 use strict;
 use warnings;
 
 use Data::Sah::Util::Role 'has_clause';
 use Role::Tiny;
 #use Sah::Schema::Common;
 #use Sah::Schema::Sah;
 
 requires 'handle_type';
 
 has_clause 'v',
     prio=>0, tags=>['meta', 'defhash'],
     arg=>['float*'=>{is=>1}];
 
 has_clause 'defhash_v',
     prio=>0, tags=>['meta', 'defhash'],
     arg=>['float*'=>{is=>1}];
 
 has_clause 'schema_v',
     prio=>0, tags=>['meta'],
     arg=>['float*'=>{}];
 
 has_clause 'base_v',
     prio=>0, tags=>['meta'],
     arg=>['float*'=>{}];
 
 has_clause 'ok',
     tags       => ['constraint'],
     prio       => 1,
     arg        => 'any',
     allow_expr => 1,
     ;
 has_clause 'default',
     prio       => 1,
     tags       => [],
     arg        => 'any',
     allow_expr => 1,
     attrs      => {
         temp => {
             arg        => [bool => default=>0],
             allow_expr => 0,
         },
     },
     ;
 # has_clause 'prefilters',
 #     tags       => ['filter'],
 #     prio       => 10,
 #     arg        => ['array*' => of=>'expr*'],
 #     attrs      => {
 #         temp => {
 #         },
 #     }
 #     ;
 has_clause 'default_lang',
     tags       => ['meta', 'defhash'],
     prio       => 2,
     arg        => ['str*'=>{default=>'en_US'}],
     ;
 has_clause 'name',
     tags       => ['meta', 'defhash'],
     prio       => 2,
     arg        => 'str*'
     ;
 has_clause 'summary',
     prio       => 2,
     tags       => ['meta', 'defhash'],
     arg        => 'str*',
     ;
 has_clause 'description',
     tags       => ['meta', 'defhash'],
     prio       => 2,
     arg        => 'str*',
     ;
 has_clause 'tags',
     tags       => ['meta', 'defhash'],
     prio       => 2,
     arg        => ['array*', of=>'str*'],
     ;
 has_clause 'req',
     tags       => ['constraint'],
     prio       => 3,
     arg        => 'bool',
     allow_expr => 1,
     ;
 has_clause 'forbidden',
     tags       => ['constraint'],
     prio       => 3,
     arg        => 'bool',
     allow_expr => 1,
     ;
 #has_clause 'if', tags=>['constraint'];
 
 #has_clause 'each', tags=>['constraint'];
 
 #has_clause 'check_each', tags=>['constraint'];
 
 #has_clause 'exists', tags=>['constraint'];
 
 #has_clause 'check_exists', tags=>['constraint'];
 
 #has_clause 'check', arg=>'expr*', tags=>['constraint'];
 
 has_clause 'clause',
     tags       => ['constraint'],
     prio       => 50,
     arg        => ['array*' => elems => ['clname*', 'any']],
     ;
 has_clause 'clset',
     prio=>50, tags=>['constraint'],
     arg=>['clset*']
     ;
 # has_clause 'postfilters',
 #     tags       => ['filter'],
 #     prio       => 90,
 #     arg        => ['array*' => of=>'expr*'],
 #     attrs      => {
 #         temp => {
 #         },
 #     }
 #     ;
 
 1;
 # ABSTRACT: Base type
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Type::BaseType - Base type
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Type::BaseType (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =for Pod::Coverage ^(clause_.+|clausemeta_.+)$
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Type/Comparable.pm ###
 package Data::Sah::Type::Comparable;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use Data::Sah::Util::Role 'has_clause';
 use Role::Tiny;
 
 requires 'superclause_comparable';
 
 has_clause 'in',
     tags       => ['constraint'],
     arg        => '(any[])*',
     allow_expr => 1,
     code       => sub {
         my ($self, $cd) = @_;
         $self->superclause_comparable('in', $cd);
     };
 has_clause 'is',
     tags       => ['constraint'],
     arg        => 'any',
     allow_expr => 1,
     code       => sub {
         my ($self, $cd) = @_;
         $self->superclause_comparable('is', $cd);
     };
 
 1;
 # ABSTRACT: Comparable type role
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Type::Comparable - Comparable type role
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Type::Comparable (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =head1 DESCRIPTION
 
 Role consumer must provide method C<superclause_comparable> which will be given
 normal C<%args> given to clause methods, but with extra key C<-which> (either
 C<in>, C<is>).
 
 =for Pod::Coverage ^(clause_.+|clausemeta_.+)$
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Type/HasElems.pm ###
 package Data::Sah::Type::HasElems;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use Data::Sah::Util::Role 'has_clause';
 use Role::Tiny;
 
 requires 'superclause_has_elems';
 
 has_clause 'max_len',
     prio       => 51,
     arg        => ['int*' => {min=>0}],
     allow_expr => 1,
     code       => sub {
         my ($self, $cd) = @_;
         $self->superclause_has_elems('max_len', $cd);
     };
 
 has_clause 'min_len',
     arg        => ['int*' => {min=>0}],
     allow_expr => 1,
     code       => sub {
         my ($self, $cd) = @_;
         $self->superclause_has_elems('min_len', $cd);
     };
 
 has_clause 'len_between',
     arg        => ['array*' => {elems => ['int*', 'int*']}],
     allow_expr => 1,
     code       => sub {
         my ($self, $cd) = @_;
         $self->superclause_has_elems('len_between', $cd);
     };
 
 has_clause 'len',
     arg        => ['int*' => {min=>0}],
     allow_expr => 1,
     code       => sub {
         my ($self, $cd) = @_;
         $self->superclause_has_elems('len', $cd);
     };
 
 has_clause 'has',
     arg        => 'any',
     allow_expr => 1,
     code       => sub {
         my ($self, $cd) = @_;
         $self->superclause_has_elems('has', $cd);
     };
 
 has_clause 'each_index',
     arg        => 'schema*',
     allow_expr => 0,
     code       => sub {
         my ($self, $cd) = @_;
         $self->superclause_has_elems('each_index', $cd);
     };
 
 has_clause 'each_elem',
     arg        => 'schema*',
     allow_expr => 0,
     code       => sub {
         my ($self, $cd) = @_;
         $self->superclause_has_elems('each_elem', $cd);
     };
 
 has_clause 'check_each_index',
     arg        => 'schema*',
     allow_expr => 0,
     code       => sub {
         my ($self, $cd) = @_;
         $self->superclause_has_elems('check_each_index', $cd);
     };
 
 has_clause 'check_each_elem',
     arg        => 'schema*',
     allow_expr => 0,
     code       => sub {
         my ($self, $cd) = @_;
         $self->superclause_has_elems('check_each_elem', $cd);
     };
 
 has_clause 'uniq',
     arg        => 'schema*',
     allow_expr => 1,
     code       => sub {
         my ($self, $cd) = @_;
         $self->superclause_has_elems('uniq', $cd);
     };
 
 has_clause 'exists',
     arg        => 'schema*',
     allow_expr => 0,
     code       => sub {
         my ($self, $cd) = @_;
         $self->superclause_has_elems('exists', $cd);
     };
 
 # has_prop 'len';
 
 # has_prop 'elems';
 
 # has_prop 'indices';
 
 1;
 # ABSTRACT: HasElems role
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Type::HasElems - HasElems role
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Type::HasElems (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =for Pod::Coverage ^(clause_.+|clausemeta_.+)$
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Type/Sortable.pm ###
 package Data::Sah::Type::Sortable;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use Data::Sah::Util::Role 'has_clause';
 use Role::Tiny;
 
 requires 'superclause_sortable';
 
 has_clause 'min',
     tags       => ['constraint'],
     arg        => 'any*',
     allow_expr => 1,
     code       => sub {
         my ($self, $cd) = @_;
         $self->superclause_sortable('min', $cd);
     },
     ;
 has_clause 'xmin',
     tags       => ['constraint'],
     arg        => 'any*',
     allow_expr => 1,
     code       => sub {
         my ($self, $cd) = @_;
         $self->superclause_sortable('xmin', $cd);
     },
     ;
 has_clause 'max',
     prio       => 51,
     tags       => ['constraint'],
     arg        => 'any*',
     allow_expr => 1,
     code       => sub {
         my ($self, $cd) = @_;
         $self->superclause_sortable('max', $cd);
     },
     ;
 has_clause 'xmax',
     prio       => 51,
     tags       => ['constraint'],
     arg        => 'any*',
     allow_expr => 1,
     code       => sub {
         my ($self, $cd) = @_;
         $self->superclause_sortable('xmax', $cd);
     },
     ;
 has_clause 'between',
     tags       => ['constraint'],
     arg        => '[any*, any*]*',
     allow_expr => 1,
     code       => sub {
         my ($self, $cd) = @_;
         $self->superclause_sortable('between', $cd);
     },
     ;
 has_clause 'xbetween',
     tags       => ['constraint'],
     arg        => '[any*, any*]*',
     allow_expr => 1,
     code => sub {
         my ($self, $cd) = @_;
         $self->superclause_sortable('xbetween', $cd);
     },
     ;
 
 1;
 # ABSTRACT: Role for sortable types
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Type::Sortable - Role for sortable types
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Type::Sortable (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =head1 DESCRIPTION
 
 Role consumer must provide method C<superclause_sortable> which will receive the
 same C<%args> as clause methods, but with additional key: C<-which> (either
 C<min>, C<max>, C<xmin>, C<xmax>, C<between>, C<xbetween>).
 
 =for Pod::Coverage ^(clause_.+|clausemeta_.+)$
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Type/all.pm ###
 package Data::Sah::Type::all;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use Data::Sah::Util::Role 'has_clause';
 use Role::Tiny;
 use Role::Tiny::With;
 
 with 'Data::Sah::Type::BaseType';
 
 has_clause 'of',
     tags       => ['constraint'],
     arg        => ['array*' => {min_len=>1, each_elem => 'schema*'}],
     allow_expr => 0,
     ;
 
 1;
 # ABSTRACT: all type
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Type::all - all type
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Type::all (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =for Pod::Coverage ^(clause_.+|clausemeta_.+)$
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Type/any.pm ###
 package Data::Sah::Type::any;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use Data::Sah::Util::Role 'has_clause';
 use Role::Tiny;
 use Role::Tiny::With;
 
 with 'Data::Sah::Type::BaseType';
 
 has_clause 'of',
     tags       => ['constraint'],
     arg        => ['array*' => {min_len=>1, each_elem => 'schema*'}],
     allow_expr => 0,
     ;
 
 1;
 # ABSTRACT: any type
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Type::any - any type
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Type::any (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =for Pod::Coverage ^(clause_.+|clausemeta_.+)$
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Type/array.pm ###
 package Data::Sah::Type::array;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use Data::Sah::Util::Role 'has_clause', 'has_clause_alias';
 use Role::Tiny;
 use Role::Tiny::With;
 
 with 'Data::Sah::Type::BaseType';
 with 'Data::Sah::Type::Comparable';
 with 'Data::Sah::Type::HasElems';
 
 has_clause 'elems',
     tags       => ['constraint'],
     arg        => ['array*' => {of=>'schema*'}],
     allow_expr => 0,
     attrs      => {
         create_default => {
             arg        => [bool => default=>1],
             allow_expr => 0, # TODO
         },
     },
     ;
 has_clause_alias each_elem => 'of';
 
 1;
 # ABSTRACT: array type
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Type::array - array type
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Type::array (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =for Pod::Coverage ^(clause_.+|clausemeta_.+)$
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Type/bool.pm ###
 package Data::Sah::Type::bool;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use Data::Sah::Util::Role 'has_clause';
 use Role::Tiny;
 use Role::Tiny::With;
 
 with 'Data::Sah::Type::BaseType';
 with 'Data::Sah::Type::Comparable';
 with 'Data::Sah::Type::Sortable';
 
 has_clause 'is_true',
     tags       => ['constraint'],
     arg        => 'bool',
     allow_expr => 1,
     ;
 
 1;
 # ABSTRACT: bool type
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Type::bool - bool type
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Type::bool (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =for Pod::Coverage ^(clause_.+|clausemeta_.+)$
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Type/buf.pm ###
 package Data::Sah::Type::buf;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use Role::Tiny;
 use Role::Tiny::With;
 
 with 'Data::Sah::Type::str';
 
 1;
 # ABSTRACT: buf type
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Type::buf - buf type
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Type::buf (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =for Pod::Coverage ^(clause_.+|clausemeta_.+)$
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Type/cistr.pm ###
 package Data::Sah::Type::cistr;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use Role::Tiny;
 use Role::Tiny::With;
 
 with 'Data::Sah::Type::str';
 
 1;
 # ABSTRACT: cistr type
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Type::cistr - cistr type
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Type::cistr (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =for Pod::Coverage ^(clause_.+|clausemeta_.+)$
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Type/code.pm ###
 package Data::Sah::Type::code;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use Role::Tiny;
 use Role::Tiny::With;
 
 with 'Data::Sah::Type::BaseType';
 
 1;
 # ABSTRACT: code type
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Type::code - code type
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Type::code (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =for Pod::Coverage ^(clause_.+|clausemeta_.+)$
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Type/date.pm ###
 package Data::Sah::Type::date;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use Data::Sah::Util::Role 'has_clause';
 use Role::Tiny;
 use Role::Tiny::With;
 
 with 'Data::Sah::Type::BaseType';
 with 'Data::Sah::Type::Comparable';
 with 'Data::Sah::Type::Sortable';
 
 # XXX prop: year
 # XXX prop: quarter (1-4)
 # XXX prop: month
 # XXX prop: day
 # XXX prop: day_of_month
 # XXX prop: hour
 # XXX prop: minute
 # XXX prop: second
 # XXX prop: millisecond
 # XXX prop: microsecond
 # XXX prop: nanosecond
 # XXX prop: day_of_week
 # XXX prop: day_of_quarter
 # XXX prop: day_of_year
 # XXX prop: week_of_month
 # XXX prop: week_of_year
 # XXX prop: date?
 # XXX prop: time?
 # XXX prop: time_zone_long_name
 # XXX prop: time_zone_offset
 # XXX prop: is_leap_year
 
 1;
 # ABSTRACT: date type
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Type::date - date type
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Type::date (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =for Pod::Coverage ^(clause_.+|clausemeta_.+)$
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Type/duration.pm ###
 package Data::Sah::Type::duration;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use Data::Sah::Util::Role 'has_clause';
 use Role::Tiny;
 use Role::Tiny::With;
 
 with 'Data::Sah::Type::BaseType';
 #with 'Data::Sah::Type::Comparable';
 #with 'Data::Sah::Type::Sortable';
 
 # XXX prop: ...
 
 1;
 # ABSTRACT: date/time duration type
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Type::duration - date/time duration type
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Type::duration (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =for Pod::Coverage ^(clause_.+|clausemeta_.+)$
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Type/float.pm ###
 package Data::Sah::Type::float;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use Data::Sah::Util::Role 'has_clause';
 use Role::Tiny;
 use Role::Tiny::With;
 
 with 'Data::Sah::Type::num';
 
 has_clause 'is_nan',
     tags        => ['constraint'],
     arg         => ['bool'],
     allow_expr  => 1,
     allow_multi => 0,
     ;
 
 has_clause 'is_inf',
     tags        => ['constraint'],
     arg         => ['bool'],
     allow_expr  => 1,
     allow_multi => 1,
     ;
 
 has_clause 'is_pos_inf',
     tags        => ['constraint'],
     arg         => ['bool'],
     allow_expr  => 1,
     allow_multi => 1,
     ;
 
 has_clause 'is_neg_inf',
     tags        => ['constraint'],
     arg         => ['bool'],
     allow_expr  => 1,
     allow_multi => 1,
     ;
 
 1;
 # ABSTRACT: float type
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Type::float - float type
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Type::float (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =for Pod::Coverage ^(clause_.+|clausemeta_.+)$
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Type/hash.pm ###
 package Data::Sah::Type::hash;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use Data::Sah::Util::Role 'has_clause', 'has_clause_alias';
 use Role::Tiny;
 use Role::Tiny::With;
 
 with 'Data::Sah::Type::BaseType';
 with 'Data::Sah::Type::Comparable';
 with 'Data::Sah::Type::HasElems';
 
 has_clause_alias each_elem => 'of';
 
 has_clause "keys",
     tags       => ['constraint'],
     arg        => ['hash*' => {values => 'schema*'}],
     allow_expr => 0,
     attrs      => {
         restrict => {
             arg        => [bool => default=>1],
             allow_expr => 0, # TODO
         },
         create_default => {
             arg        => [bool => default=>1],
             allow_expr => 0, # TODO
         },
     },
     ;
 has_clause "re_keys",
     prio       => 51,
     tags       => ['constraint'],
     arg        => ['hash*' => {keys => 're*', values => 'schema*'}],
     allow_expr => 0,
     attrs      => {
         restrict => {
             arg        => [bool => default=>1],
             allow_expr => 0, # TODO
         },
     },
     ;
 has_clause "req_keys",
     tags       => ['constraint'],
     arg        => ['array*'],
     allow_expr => 1,
     ;
 has_clause "allowed_keys",
     tags       => ['constraint'],
     arg        => ['array*'],
     allow_expr => 1,
     ;
 has_clause "allowed_keys_re",
     prio       => 51,
     tags       => ['constraint'],
     arg        => 're*',
     allow_expr => 1,
     ;
 has_clause "forbidden_keys",
     tags       => ['constraint'],
     arg        => ['array*'],
     allow_expr => 1,
     ;
 has_clause "forbidden_keys_re",
     prio       => 51,
     tags       => ['constraint'],
     arg        => 're*',
     allow_expr => 1,
     ;
 has_clause_alias each_index => 'each_key';
 has_clause_alias each_elem => 'each_value';
 has_clause_alias check_each_index => 'check_each_key';
 has_clause_alias check_each_elem => 'check_each_value';
 
 has_clause "choose_one_key",
     prio       => 50,
     tags       => ['constraint'],
     arg        => ['array*', {of=>'str*', min_len=>1}],
     allow_expr => 0, # for now
     ;
 has_clause_alias choose_one_key => 'choose_one';
 has_clause "choose_all_keys",
     prio       => 50,
     tags       => ['constraint'],
     arg        => ['array*', {of=>'str*', min_len=>1}],
     allow_expr => 0, # for now
     ;
 has_clause_alias choose_all_keys => 'choose_all';
 has_clause "req_one_key",
     prio       => 50,
     tags       => ['constraint'],
     arg        => ['array*', {of=>'str*', min_len=>1}],
     allow_expr => 0, # for now
     ;
 has_clause_alias req_one_key => 'req_one';
 has_clause_alias req_keys => 'req_all_keys';
 has_clause_alias req_keys => 'req_all';
 
 # for now we only support the first argument as str, not array[str]
 #my $dep_arg = ['array*', {elems=>[ ['any*', of=>['str*', ['array*',{of=>'str*'}]]], ['array*',of=>'str*'] ]}];
 my $dep_arg = ['array*', {elems=>[ 'str*', ['array*',of=>'str*'] ]}];
 
 has_clause "dep_any",
     prio       => 50,
     tags       => ['constraint'],
     arg        => $dep_arg,
     allow_expr => 0, # for now
     ;
 has_clause "dep_all",
     prio       => 50,
     tags       => ['constraint'],
     arg        => $dep_arg,
     allow_expr => 0, # for now
     ;
 has_clause "req_dep_any",
     prio       => 50,
     tags       => ['constraint'],
     arg        => $dep_arg,
     allow_expr => 0, # for now
     ;
 has_clause "req_dep_all",
     prio       => 50,
     tags       => ['constraint'],
     arg        => $dep_arg,
     allow_expr => 0, # for now
     ;
 
 # prop_alias indices => 'keys'
 
 # prop_alias elems => 'values'
 
 1;
 # ABSTRACT: hash type
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Type::hash - hash type
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Type::hash (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =for Pod::Coverage ^(clause_.+|clausemeta_.+)$
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Type/int.pm ###
 package Data::Sah::Type::int;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use Data::Sah::Util::Role 'has_clause';
 use Role::Tiny;
 use Role::Tiny::With;
 
 with 'Data::Sah::Type::num';
 
 has_clause 'mod',
     tags       => ['constraint'],
     arg        => ['array*' => {elems => [['int*' => {'!is'=>0}], 'int*']}],
     allow_expr => 1,
     ;
 has_clause 'div_by',
     tags       => ['constraint'],
     arg        => ['int*' => {'!is'=>0}],
     allow_expr => 1,
     ;
 
 1;
 # ABSTRACT: int type
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Type::int - int type
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Type::int (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =for Pod::Coverage ^(clause_.+|clausemeta_.+)$
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Type/num.pm ###
 package Data::Sah::Type::num;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use Role::Tiny;
 use Role::Tiny::With;
 
 with 'Data::Sah::Type::BaseType';
 with 'Data::Sah::Type::Comparable';
 with 'Data::Sah::Type::Sortable';
 
 1;
 # ABSTRACT: num type
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Type::num - num type
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Type::num (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =for Pod::Coverage ^(clause_.+|clausemeta_.+)$
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Type/obj.pm ###
 package Data::Sah::Type::obj;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use Data::Sah::Util::Role 'has_clause';
 use Role::Tiny;
 use Role::Tiny::With;
 
 with 'Data::Sah::Type::BaseType';
 
 has_clause 'can',
     tags       => ['constraint'],
     arg        => 'str*', # XXX perl_method_name
     allow_expr => 1,
     ;
 has_clause 'isa',
     tags       => ['constraint'],
     arg        => 'str*', # XXX perl_class_name
     allow_expr => 1,
     ;
 
 1;
 # ABSTRACT: obj type
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Type::obj - obj type
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Type::obj (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =for Pod::Coverage ^(clause_.+|clausemeta_.+)$
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Type/re.pm ###
 package Data::Sah::Type::re;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use Data::Sah::Util::Role 'has_clause';
 use Role::Tiny;
 use Role::Tiny::With;
 
 with 'Data::Sah::Type::BaseType';
 
 1;
 # ABSTRACT: re type
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Type::re - re type
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Type::re (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =for Pod::Coverage ^(clause_.+|clausemeta_.+)$
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Type/str.pm ###
 package Data::Sah::Type::str;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use Data::Sah::Util::Role 'has_clause';
 use Role::Tiny;
 use Role::Tiny::With;
 
 with 'Data::Sah::Type::BaseType';
 with 'Data::Sah::Type::Comparable';
 with 'Data::Sah::Type::Sortable';
 with 'Data::Sah::Type::HasElems';
 
 my $t_re = 'regex*|{*=>regex*}';
 
 has_clause 'encoding',
     tags       => ['constraint'],
     arg        => 'str*',
     allow_expr => 0,
     ;
 has_clause 'match',
     tags       => ['constraint'],
     arg        => $t_re,
     allow_expr => 1,
     ;
 has_clause 'is_re',
     tags       => ['constraint'],
     arg        => 'bool',
     allow_expr => 1,
     ;
 
 1;
 # ABSTRACT: str type
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Type::str - str type
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Type::str (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =for Pod::Coverage ^(clause_.+|clausemeta_.+)$
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Type/undef.pm ###
 package Data::Sah::Type::undef;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use Role::Tiny;
 use Data::Sah::Util::Role 'has_clause';
 
 1;
 # ABSTRACT: undef type
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Type::undef - undef type
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Type::undef (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =for Pod::Coverage ^(clause_.+|clausemeta_.+)$
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Util/Func.pm ###
 package Data::Sah::Util::Func;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 #use Log::Any '$log';
 
 #use Sub::Install qw(install_sub);
 
 require Exporter;
 our @ISA = qw(Exporter);
 our @EXPORT_OK = qw(
                        add_func
                );
 
 sub add_func {
     my ($funcset, $func, %opts) = @_;
     # not yet implemented
 }
 
 1;
 # ABSTRACT: Sah utility routines for adding function
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Util::Func - Sah utility routines for adding function
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Util::Func (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =head1 DESCRIPTION
 
 This module provides some utility routines to be used by modules that add Sah
 functions.
 
 =head1 FUNCTIONS
 
 =head2 add_func($funcset, $func, %opts)
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Util/Role.pm ###
 package Data::Sah::Util::Role;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 #use Log::Any '$log';
 
 use Sub::Install qw(install_sub);
 
 require Exporter;
 our @ISA = qw(Exporter);
 our @EXPORT_OK = qw(
                        has_clause has_clause_alias
                        has_func   has_func_alias
                );
 
 sub has_clause {
     my ($name, %args) = @_;
     my $caller = caller;
     my $into   = $args{into} // $caller;
 
     if ($args{code}) {
         install_sub({code => $args{code}, into => $into,
                      as => "clause_$name"});
     } else {
         eval "package $into; use Role::Tiny; ".
             "requires 'clause_$name';";
     }
     install_sub({code => sub {
                      state $meta = {
                          names      => [$name],
                          tags       => $args{tags},
                          prio       => $args{prio} // 50,
                          arg        => $args{arg},
                          allow_expr => $args{allow_expr},
                          attrs      => $args{attrs} // {},
                      };
                      $meta;
                  },
                  into => $into,
                  as => "clausemeta_$name"});
     has_clause_alias($name, $args{alias}  , $into);
     has_clause_alias($name, $args{aliases}, $into);
 }
 
 sub has_clause_alias {
     my ($name, $aliases, $into) = @_;
     my $caller   = caller;
     $into      //= $caller;
     my @aliases = !$aliases ? () :
         ref($aliases) eq 'ARRAY' ? @$aliases : $aliases;
     my $meta = $into->${\("clausemeta_$name")};
 
     for my $alias (@aliases) {
         push @{ $meta->{names} }, $alias;
         eval
             "package $into;".
             "sub clause_$alias { shift->clause_$name(\@_) } ".
             "sub clausemeta_$alias { shift->clausemeta_$name(\@_) } ";
         $@ and die "Can't make clause alias $alias -> $name: $@";
     }
 }
 
 sub has_func {
     my ($name, %args) = @_;
     my $caller = caller;
     my $into   = $args{into} // $caller;
 
     if ($args{code}) {
         install_sub({code => $args{code}, into => $into, as => "func_$name"});
     } else {
         eval "package $into; use Role::Tiny; requires 'func_$name';";
     }
     install_sub({code => sub {
                      state $meta = {
                          names => [$name],
                          args  => $args{args},
                      };
                      $meta;
                  },
                  into => $into,
                  as => "funcmeta_$name"});
     my @aliases =
         map { (!$args{$_} ? () :
                    ref($args{$_}) eq 'ARRAY' ? @{ $args{$_} } : $args{$_}) }
             qw/alias aliases/;
     has_func_alias($name, $args{alias}  , $into);
     has_func_alias($name, $args{aliases}, $into);
 }
 
 sub has_func_alias {
     my ($name, $aliases, $into) = @_;
     my $caller   = caller;
     $into      //= $caller;
     my @aliases = !$aliases ? () :
         ref($aliases) eq 'ARRAY' ? @$aliases : $aliases;
     my $meta = $into->${\("funcmeta_$name")};
 
     for my $alias (@aliases) {
         push @{ $meta->{names} }, $alias;
         eval
             "package $into;".
             "sub func_$alias { shift->func_$name(\@_) } ".
             "sub funcmeta_$alias { shift->funcmeta_$name(\@_) } ";
         $@ and die "Can't make func alias $alias -> $name: $@";
     }
 }
 
 1;
 # ABSTRACT: Sah utility routines for roles
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Util::Role - Sah utility routines for roles
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Util::Role (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =head1 DESCRIPTION
 
 This module provides some utility routines to be used in roles, e.g.
 C<Data::Sah::Type::*> and C<Data::Sah::FuncSet::*>.
 
 =head1 FUNCTIONS
 
 =head2 has_clause($name, %opts)
 
 Define a clause. Used in type roles (C<Data::Sah::Type::*>). Internally it adds
 a L<Moo> C<requires> for C<clause_$name>.
 
 Options:
 
 =over 4
 
 =item * arg => $schema
 
 Define schema for clause value.
 
 =item * prio => $priority
 
 Optional. Default is 50. The higher the priority, the earlier the clause will be
 processed.
 
 =item * aliases => \@aliases OR $alias
 
 Define aliases. Optional.
 
 =item * code => $code
 
 Optional. Define implementation for the clause. The code will be installed as
 'clause_$name'.
 
 =item * into => $package
 
 By default it is the caller package, but can be set to other package.
 
 =back
 
 Example:
 
  has_clause minimum => (arg => 'int*', aliases => 'min');
 
 =head2 has_clause_alias TARGET => ALIAS | [ALIAS1, ...]
 
 Specify that clause named ALIAS is an alias for TARGET.
 
 You have to define TARGET clause first (see B<has_clause> above).
 
 Example:
 
  has_clause max_length => ...;
  has_clause_alias max_length => "max_len";
 
 =head2 has_func($name, %opts)
 
 Define a Sah function. Used in function set roles (C<Data::Sah::FuncSet::*>).
 Internally it adds a L<Moo> C<requires> for C<func_$name>.
 
 Options:
 
 =over 4
 
 =item * args => [$schema_arg0, $schema_arg1, ...]
 
 Declare schema for arguments.
 
 =item * aliases => \@aliases OR $alias
 
 Optional. Declare aliases.
 
 =item * code => $code
 
 Supply implementation for the function. The code will be installed as
 'func_$name'.
 
 =item * into => $package
 
 By default it is the caller package, but can be set to other package.
 
 =back
 
 Example:
 
  has_func abs => (args => 'num');
 
 =head2 has_func_alias TARGET => ALIAS | [ALIASES...]
 
 Specify that function named ALIAS is an alias for TARGET.
 
 You have to specify TARGET function first (see B<has_func> above).
 
 Example:
 
  has_func_alias 'atan' => 'arctan';
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Util/Type.pm ###
 package Data::Sah::Util::Type;
 
 our $DATE = '2015-01-20'; # DATE
 our $VERSION = '0.42'; # VERSION
 
 use 5.010001;
 use strict;
 use warnings;
 
 require Exporter;
 our @ISA       = qw(Exporter);
 our @EXPORT_OK = qw(get_type is_simple is_numeric is_collection is_ref);
 
 # XXX absorb and use metadata from Data::Sah::Type::*
 my $type_metas = {
     all   => {scalar=>0, numeric=>0, ref=>0},
     any   => {scalar=>0, numeric=>0, ref=>0},
     array => {scalar=>0, numeric=>0, ref=>1},
     bool  => {scalar=>1, numeric=>0, ref=>0},
     buf   => {scalar=>1, numeric=>0, ref=>0},
     cistr => {scalar=>1, numeric=>0, ref=>0},
     code  => {scalar=>1, numeric=>0, ref=>1},
     float => {scalar=>1, numeric=>1, ref=>0},
     hash  => {scalar=>0, numeric=>0, ref=>1},
     int   => {scalar=>1, numeric=>1, ref=>0},
     num   => {scalar=>1, numeric=>1, ref=>0},
     obj   => {scalar=>1, numeric=>0, ref=>1},
     re    => {scalar=>1, numeric=>0, ref=>1, simple=>1},
     str   => {scalar=>1, numeric=>0, ref=>0},
     undef => {scalar=>1, numeric=>0, ref=>0},
 };
 
 sub get_type {
     my $sch = shift;
 
     if (ref($sch) eq 'ARRAY') {
         $sch = $sch->[0];
     }
 
     if (defined($sch) && !ref($sch)) {
         $sch =~ s/\*\z//;
         return $sch;
     } else {
         return undef;
     }
 }
 
 sub _normalize {
     require Data::Sah::Normalize;
 
     my ($sch, $opts) = @_;
     return $sch if $opts->{schema_is_normalized};
     return Data::Sah::Normalize::normalize_schema($sch);
 }
 
 # for any|all to pass a criteria, we assume that all of the schemas in the 'of'
 # clause must also pass (and there must not be '!of', 'of&', or that kind of
 # thing.
 sub _handle_any_all {
     my ($sch, $opts, $crit) = @_;
     $sch = _normalize($sch, $opts);
     return 0 if $sch->[1]{'of.op'};
     my $of = $sch->[1]{of};
     return 0 unless $of && ref($of) eq 'ARRAY' && @$of;
     for (@$of) {
         return 0 unless $crit->($_);
     }
     1;
 }
 
 sub is_simple {
     my ($sch, $opts) = @_;
     $opts //= {};
 
     my $type = get_type($sch) or return undef;
     my $tmeta = $type_metas->{$type} or return undef;
     if ($type eq 'any' || $type eq 'all') {
         return _handle_any_all($sch, $opts, sub { is_simple(shift) });
     }
     return $tmeta->{simple} // ($tmeta->{scalar} && !$tmeta->{ref});
 }
 
 sub is_collection {
     my ($sch, $opts) = @_;
     $opts //= {};
 
     my $type = get_type($sch) or return undef;
     my $tmeta = $type_metas->{$type} or return undef;
     if ($type eq 'any' || $type eq 'all') {
         return _handle_any_all($sch, $opts, sub { is_collection(shift) });
     }
     return !$tmeta->{scalar};
 }
 
 sub is_numeric {
     my ($sch, $opts) = @_;
     $opts //= {};
 
     my $type = get_type($sch) or return undef;
     my $tmeta = $type_metas->{$type} or return undef;
     if ($type eq 'any' || $type eq 'all') {
         return _handle_any_all($sch, $opts, sub { is_numeric(shift) });
     }
     return $tmeta->{numeric};
 }
 
 sub is_ref {
     my ($sch, $opts) = @_;
     $opts //= {};
 
     my $type = get_type($sch) or return undef;
     my $tmeta = $type_metas->{$type} or return undef;
     if ($type eq 'any' || $type eq 'all') {
         return _handle_any_all($sch, $opts, sub { is_ref(shift) });
     }
     return $tmeta->{ref};
 }
 
 1;
 # ABSTRACT: Utility functions related to types
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Util::Type - Utility functions related to types
 
 =head1 VERSION
 
 This document describes version 0.42 of Data::Sah::Util::Type (from Perl distribution Data-Sah-Util-Type), released on 2015-01-20.
 
 =head1 SYNOPSIS
 
  use Data::Sah::Util::Type qw(
      get_type
      is_simple is_numeric is_collection is_ref
  );
 
  say get_type("int");                          # -> int
  say get_type("int*");                         # -> int
  say get_type([int => min=>0]);                # -> int
 
  say is_simple("int");                          # -> 1
  say is_simple("array");                        # -> 0
  say is_simple([any => of => ["float", "str"]); # -> 1
 
  say is_numeric(["int", min=>0]); # -> 1
 
  say is_collection("array*"); # -> 1
 
  say is_ref("code*"); # -> 1
 
 =head1 DESCRIPTION
 
 This module provides some secondary utility functions related to L<Sah> and
 L<Data::Sah>. It is deliberately distributed separately from the Data-Sah main
 distribution to be differentiated from Data::Sah::Util which contains "primary"
 utilities and is distributed with Data-Sah.
 
 =head1 FUNCTIONS
 
 None exported by default, but they are exportable.
 
 =head2 get_type($sch) => STR
 
 =head2 is_simple($sch[, \%opts]) => BOOL
 
 Simple means scalar and not a reference.
 
 Options:
 
 =over
 
 =item * schema_is_normalized => BOOL
 
 =back
 
 =head2 is_collection($sch[, \%opts]) => BOOL
 
 =head2 is_numeric($sch[, \%opts]) => BOOL
 
 Currently, only C<num>, C<int>, and C<float> are numeric.
 
 =head2 is_ref($sch[, \%opts]) => BOOL
 
 =head1 SEE ALSO
 
 L<Data::Sah>
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah-Util-Type>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Data-Sah-Util-Type>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah-Util-Type>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Util/Type/Date.pm ###
 package Data::Sah::Util::Type::Date;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 #use Log::Any '$log';
 
 use Scalar::Util qw(blessed looks_like_number);
 
 require Exporter;
 our @ISA = qw(Exporter);
 our @EXPORT_OK = qw(
                        coerce_date
                        coerce_duration
                );
 
 our $DATE_MODULE = $ENV{DATA_SAH_DATE_MODULE} // $ENV{PERL_DATE_MODULE} //
     "DateTime"; # XXX change defaults to Time::Piece (core)
 
 my $re_ymd = qr/\A([0-9]{4})-([0-9]{2})-([0-9]{2})\z/;
 my $re_ymdThmsZ = qr/\A([0-9]{4})-([0-9]{2})-([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})Z\z/;
 
 sub coerce_date {
     my $val = shift;
     if (!defined($val)) {
         return undef;
     }
 
     if ($DATE_MODULE eq 'DateTime') {
         require DateTime;
         if (blessed($val) && $val->isa('DateTime')) {
             return $val;
         } elsif (looks_like_number($val) && $val >= 10**8 && $val <= 2**31) {
             return DateTime->from_epoch(epoch => $val);
         } elsif ($val =~ $re_ymd) {
             my $d;
             eval { $d = DateTime->new(year=>$1, month=>$2, day=>$3, time_zone=>'UTC') };
             return undef if $@;
             return $d;
         } elsif ($val =~ $re_ymdThmsZ) {
             my $d;
             eval { $d = DateTime->new(year=>$1, month=>$2, day=>$3, hour=>$4, minute=>$5, second=>$6, time_zone=>'UTC') };
             return undef if $@;
             return $d;
         } elsif (blessed($val) && $val->isa('Time::Moment')) {
             return DateTime->from_epoch(epoch => $val->epoch);
         } elsif (blessed($val) && $val->isa('Time::Piece')) {
             return DateTime->from_epoch(epoch => $val->epoch);
         } else {
             return undef;
         }
     } elsif ($DATE_MODULE eq 'Time::Moment') {
         require Time::Moment;
         if (blessed($val) && $val->isa('Time::Moment')) {
             return $val;
         } elsif (looks_like_number($val) && $val >= 10**8 && $val <= 2**31) {
             return Time::Moment->from_epoch(int($val), $val-int($val));
         } elsif ($val =~ $re_ymd) {
             my $d;
             eval { $d = Time::Moment->new(year=>$1, month=>$2, day=>$3) };
             return undef if $@;
             return $d;
         } elsif ($val =~ $re_ymdThmsZ) {
             my $d;
             eval { $d = Time::Moment->new(year=>$1, month=>$2, day=>$3, hour=>$4, minute=>$5, second=>$6) };
             return undef if $@;
             return $d;
         } elsif (blessed($val) && $val->isa('DateTime')) {
             return Time::Moment->from_epoch($val->epoch);
         } elsif (blessed($val) && $val->isa('Time::Piece')) {
             return Time::Moment->from_epoch($val->epoch);
         } else {
             return undef;
         }
     } elsif ($DATE_MODULE eq 'Time::Piece') {
         require Time::Piece;
         if (blessed($val) && $val->isa('Time::Piece')) {
             return $val;
         } elsif (looks_like_number($val) && $val >= 10**8 && $val <= 2**31) {
             return scalar Time::Piece->gmtime($val);
         } elsif ($val =~ $re_ymd) {
             my $d;
             eval { $d = Time::Piece->strptime($val, "%Y-%m-%d") };
             return undef if $@;
             return $d;
         } elsif ($val =~ $re_ymdThmsZ) {
             my $d;
             eval { $d = Time::Piece->strptime($val, "%Y-%m-%dT%H:%M:%SZ") };
             return undef if $@;
             return $d;
         } elsif (blessed($val) && $val->isa('DateTime')) {
             return scalar Time::Piece->gmtime(epoch => $val->epoch);
         } elsif (blessed($val) && $val->isa('Time::Moment')) {
             return scalar Time::Piece->gmtime(epoch => $val->epoch);
         } else {
             return undef;
         }
     } else {
         die "BUG: Unknown Perl date module '$DATE_MODULE'";
     }
 }
 
 sub coerce_duration {
     my $val = shift;
     if (!defined($val)) {
         return undef;
     } elsif (blessed($val) && $val->isa('DateTime::Duration')) {
         return $val;
     } elsif ($val =~ /\AP
                       (?: ([0-9]+(?:\.[0-9]+)?)Y )?
                       (?: ([0-9]+(?:\.[0-9]+)?)M )?
                       (?: ([0-9]+(?:\.[0-9]+)?)W )?
                       (?: ([0-9]+(?:\.[0-9]+)?)D )?
                       (?:
                           T
                           (?: ([0-9]+(?:\.[0-9]+)?)H )?
                           (?: ([0-9]+(?:\.[0-9]+)?)M )?
                           (?: ([0-9]+(?:\.[0-9]+)?)S )?
                       )?
                       \z/x) {
         require DateTime::Duration;
         my $d;
         eval {
             $d = DateTime::Duration->new(
                 years   => $1 // 0,
                 months  => $2 // 0,
                 weeks   => $3 // 0,
                 days    => $4 // 0,
                 hours   => $5 // 0,
                 minutes => $6 // 0,
                 seconds => $7 // 0,
             );
         };
         return undef if $@;
         return $d;
     } else {
         return undef;
     }
 }
 
 1;
 # ABSTRACT: Utility related to date/duration type
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Util::Type::Date - Utility related to date/duration type
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Util::Type::Date (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =head1 DESCRIPTION
 
 =head1 FUNCTIONS
 
 =head2 coerce_date($val) => DATETIME OBJ|undef
 
 Coerce value to DateTime object according to perl Sah compiler (see
 L<Data::Sah::Compiler::perl::TH::date>). Return undef if value is not
 acceptable.
 
 =head2 coerce_duration($val) => DATETIME_DURATION OBJ|undef
 
 Coerce value to DateTime::Duration object according to perl Sah compiler (see
 L<Data::Sah::Compiler::perl::TH::duration>). Return undef if value is not
 acceptable.
 
 =head1 ENVIRONMENT
 
 =head2 DATA_SAH_DATE_MODULE => string (default: DateTime)
 
 Pick the date module to use. Available choices: DateTime, Time::Moment.
 
 =head2 PERL_DATE_MODULE => string (default: DateTime)
 
 Pick the date module to use. Available choices: DateTime, Time::Moment. Has
 lower priority compared to DATA_SAH_DATE_MODULE.
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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/Sah/Util/TypeX.pm ###
 package Data::Sah::Util::TypeX;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 #use Log::Any '$log';
 
 #use Sub::Install qw(install_sub);
 
 require Exporter;
 our @ISA = qw(Exporter);
 our @EXPORT_OK = qw(
                        add_clause
                );
 
 sub add_clause {
     my ($type, $clause, %opts) = @_;
     # not yet implemented
 
     # * check duplicate
 
     # * call Data::Sah::Util::Role::has_clause
     # * install handlers to Data::Sah::Compiler::$Compiler::TH::$type
     # * push @{ $Data::Sah::Compiler::human::TypeX{$type} }, $clause;
 }
 
 1;
 # ABSTRACT: Sah utility routines for type extensions
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Data::Sah::Util::TypeX - Sah utility routines for type extensions
 
 =head1 VERSION
 
 This document describes version 0.74 of Data::Sah::Util::TypeX (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =head1 DESCRIPTION
 
 This module provides some utility routines to be used by type extension modules
 (C<Data::Sah::TypeX::*>).
 
 =head1 FUNCTIONS
 
 =head2 add_clause($type, $clause, %opts)
 
 Add a clause. Used when wanting to add a clause to an existing type.
 
 Options:
 
 =over 4
 
 =item * definition => HASH
 
 Will be passed to L<Data::Sah::Util::Role>'s C<has_clause>.
 
 =item * handlers => HASH
 
 A mapping of compiler name and coderefs. Coderef will be installed as
 C<clause_$clause> in the C<Data::Sah::Compiler::$Compiler::TH::>.
 
 =item * prio => $priority
 
 Optional. Default is 50. The higher the priority, the earlier the clause will be
 processed.
 
 =item * aliases => \@aliases OR $alias
 
 Define aliases. Optional.
 
 =item * code => $code
 
 Optional. Define implementation for the clause. The code will be installed as
 'clause_$name'.
 
 =back
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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
### Devel/GlobalDestruction.pm ###
 package Devel::GlobalDestruction;
 
 use strict;
 use warnings;
 
 our $VERSION = '0.13';
 
 use Sub::Exporter::Progressive -setup => {
   exports => [ qw(in_global_destruction) ],
   groups  => { default => [ -all ] },
 };
 
 # we run 5.14+ - everything is in core
 #
 if (defined ${^GLOBAL_PHASE}) {
   eval 'sub in_global_destruction () { ${^GLOBAL_PHASE} eq q[DESTRUCT] }; 1'
     or die $@;
 }
 # try to load the xs version if it was compiled
 #
 elsif (eval {
   require Devel::GlobalDestruction::XS;
   no warnings 'once';
   *in_global_destruction = \&Devel::GlobalDestruction::XS::in_global_destruction;
   1;
 }) {
   # the eval already installed everything, nothing to do
 }
 else {
   # internally, PL_main_cv is set to Nullcv immediately before entering
   # global destruction and we can use B to detect that.  B::main_cv will
   # only ever be a B::CV or a B::SPECIAL that is a reference to 0
   require B;
   eval 'sub in_global_destruction () { ${B::main_cv()} == 0 }; 1'
     or die $@;
 }
 
 1;  # keep require happy
 
 
 __END__
 
 =head1 NAME
 
 Devel::GlobalDestruction - Provides function returning the equivalent of
 C<${^GLOBAL_PHASE} eq 'DESTRUCT'> for older perls.
 
 =head1 SYNOPSIS
 
     package Foo;
     use Devel::GlobalDestruction;
 
     use namespace::clean; # to avoid having an "in_global_destruction" method
 
     sub DESTROY {
         return if in_global_destruction;
 
         do_something_a_little_tricky();
     }
 
 =head1 DESCRIPTION
 
 Perl's global destruction is a little tricky to deal with WRT finalizers
 because it's not ordered and objects can sometimes disappear.
 
 Writing defensive destructors is hard and annoying, and usually if global
 destruction is happening you only need the destructors that free up non
 process local resources to actually execute.
 
 For these constructors you can avoid the mess by simply bailing out if global
 destruction is in effect.
 
 =head1 EXPORTS
 
 This module uses L<Sub::Exporter::Progressive> so the exports may be renamed,
 aliased, etc. if L<Sub::Exporter> is present.
 
 =over 4
 
 =item in_global_destruction
 
 Returns true if the interpreter is in global destruction. In perl 5.14+, this
 returns C<${^GLOBAL_PHASE} eq 'DESTRUCT'>, and on earlier perls, detects it using
 the value of C<PL_main_cv> or C<PL_dirty>.
 
 =back
 
 =head1 AUTHORS
 
 Yuval Kogman E<lt>nothingmuch@woobling.orgE<gt>
 
 Florian Ragwitz E<lt>rafl@debian.orgE<gt>
 
 Jesse Luehrs E<lt>doy@tozt.netE<gt>
 
 Peter Rabbitson E<lt>ribasushi@cpan.orgE<gt>
 
 Arthur Axel 'fREW' Schmidt E<lt>frioux@gmail.comE<gt>
 
 Elizabeth Mattijsen E<lt>liz@dijkmat.nlE<gt>
 
 Greham Knop E<lt>haarg@haarg.orgE<gt>
 
 =head1 COPYRIGHT
 
     Copyright (c) 2008 Yuval Kogman. All rights reserved
     This program is free software; you can redistribute
     it and/or modify it under the same terms as Perl itself.
 
 =cut
### Dist/CheckConflicts.pm ###
 package Dist::CheckConflicts;
 BEGIN {
   $Dist::CheckConflicts::AUTHORITY = 'cpan:DOY';
 }
 $Dist::CheckConflicts::VERSION = '0.11';
 use strict;
 use warnings;
 use 5.006;
 # ABSTRACT: declare version conflicts for your dist
 
 use base 'Exporter';
 our @EXPORT = our @EXPORT_OK = (
     qw(conflicts check_conflicts calculate_conflicts dist)
 );
 
 use Carp;
 use Module::Runtime 0.009 'module_notional_filename', 'require_module';
 
 
 my %CONFLICTS;
 my %HAS_CONFLICTS;
 my %DISTS;
 
 sub import {
     my $pkg = shift;
     my $for = caller;
 
     my ($conflicts, $alsos, $dist);
     ($conflicts, @_) = _strip_opt('-conflicts' => @_);
     ($alsos, @_)     = _strip_opt('-also' => @_);
     ($dist, @_)      = _strip_opt('-dist' => @_);
 
     my %conflicts = %{ $conflicts || {} };
     for my $also (@{ $alsos || [] }) {
         eval { require_module($also) } or next;
         if (!exists $CONFLICTS{$also}) {
             $also .= '::Conflicts';
             eval { require_module($also) } or next;
         }
         if (!exists $CONFLICTS{$also}) {
             next;
         }
         my %also_confs = $also->conflicts;
         for my $also_conf (keys %also_confs) {
             $conflicts{$also_conf} = $also_confs{$also_conf}
                 if !exists $conflicts{$also_conf}
                 || $conflicts{$also_conf} lt $also_confs{$also_conf};
         }
     }
 
     $CONFLICTS{$for} = \%conflicts;
     $DISTS{$for}     = $dist || $for;
 
     if (grep { $_ eq ':runtime' } @_) {
         for my $conflict (keys %conflicts) {
             $HAS_CONFLICTS{$conflict} ||= [];
             push @{ $HAS_CONFLICTS{$conflict} }, $for;
         }
 
         # warn for already loaded things...
         for my $conflict (keys %conflicts) {
             if (exists $INC{module_notional_filename($conflict)}) {
                 _check_version([$for], $conflict);
             }
         }
 
         # and warn for subsequently loaded things...
         @INC = grep {
             !(ref($_) eq 'ARRAY' && @$_ > 1 && $_->[1] == \%CONFLICTS)
         } @INC;
         unshift @INC, [
             sub {
                 my ($sub, $file) = @_;
 
                 (my $mod = $file) =~ s{\.pm$}{};
                 $mod =~ s{/}{::}g;
                 return unless $mod =~ /[\w:]+/;
 
                 return unless defined $HAS_CONFLICTS{$mod};
 
                 {
                     local $HAS_CONFLICTS{$mod};
                     require $file;
                 }
 
                 _check_version($HAS_CONFLICTS{$mod}, $mod);
 
                 # the previous require already handled it
                 my $called;
                 return sub {
                     return 0 if $called;
                     $_ = "1;";
                     $called = 1;
                     return 1;
                 };
             },
             \%CONFLICTS, # arbitrary but unique, see above
         ];
     }
 
     $pkg->export_to_level(1, @_);
 }
 
 sub _strip_opt {
     my ($opt, @args) = @_;
 
     my $val;
     for my $idx ( 0 .. $#args - 1 ) {
         if (defined $args[$idx] && $args[$idx] eq $opt) {
             $val = (splice @args, $idx, 2)[1];
             last;
         }
     }
 
     return ( $val, @args );
 }
 
 sub _check_version {
     my ($fors, $mod) = @_;
 
     for my $for (@$fors) {
         my $conflict_ver = $CONFLICTS{$for}{$mod};
         my $version = do {
             no strict 'refs';
             ${ ${ $mod . '::' }{VERSION} };
         };
 
         if ($version le $conflict_ver) {
             warn <<EOF;
 Conflict detected for $DISTS{$for}:
   $mod is version $version, but must be greater than version $conflict_ver
 EOF
             return;
         }
     }
 }
 
 
 sub conflicts {
     my $package = shift;
     return %{ $CONFLICTS{ $package } };
 }
 
 
 sub dist {
     my $package = shift;
     return $DISTS{ $package };
 }
 
 
 sub check_conflicts {
     my $package = shift;
     my $dist = $package->dist;
     my @conflicts = $package->calculate_conflicts;
     return unless @conflicts;
 
     my $err = "Conflicts detected for $dist:\n";
     for my $conflict (@conflicts) {
         $err .= "  $conflict->{package} is version "
                 . "$conflict->{installed}, but must be greater than version "
                 . "$conflict->{required}\n";
     }
     die $err;
 }
 
 
 sub calculate_conflicts {
     my $package = shift;
     my %conflicts = $package->conflicts;
 
     my @ret;
 
 
     CONFLICT:
     for my $conflict (keys %conflicts) {
         my $success = do {
             local $SIG{__WARN__} = sub {};
             eval { require_module($conflict) };
         };
         my $error = $@;
         my $file = module_notional_filename($conflict);
         next if not $success and $error =~ /Can't locate \Q$file\E in \@INC/;
 
         warn "Warning: $conflict did not compile" if not $success;
         my $installed = $success ? $conflict->VERSION : 'unknown';
         push @ret, {
             package   => $conflict,
             installed => $installed,
             required  => $conflicts{$conflict},
         } if not $success or $installed le $conflicts{$conflict};
     }
 
     return sort { $a->{package} cmp $b->{package} } @ret;
 }
 
 
 1;
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Dist::CheckConflicts - declare version conflicts for your dist
 
 =head1 VERSION
 
 version 0.11
 
 =head1 SYNOPSIS
 
     use Dist::CheckConflicts
         -dist => 'Class-MOP',
         -conflicts => {
             'Moose'                => '1.14',
             'namespace::autoclean' => '0.08',
         },
         -also => [
             'Package::Stash::Conflicts',
         ];
 
     __PACKAGE__->check_conflicts;
 
 =head1 DESCRIPTION
 
 One shortcoming of the CPAN clients that currently exist is that they have no
 way of specifying conflicting downstream dependencies of modules. This module
 attempts to work around this issue by allowing you to specify conflicting
 versions of modules separately, and deal with them after the module is done
 installing.
 
 For instance, say you have a module C<Foo>, and some other module C<Bar> uses
 C<Foo>. If C<Foo> were to change its API in a non-backwards-compatible way,
 this would cause C<Bar> to break until it is updated to use the new API. C<Foo>
 can't just depend on the fixed version of C<Bar>, because this will cause a
 circular dependency (because C<Bar> is already depending on C<Foo>), and this
 doesn't express intent properly anyway - C<Foo> doesn't use C<Bar> at all. The
 ideal solution would be for there to be a way to specify conflicting versions
 of modules in a way that would let CPAN clients update conflicting modules
 automatically after an existing module is upgraded, but until that happens,
 this module will allow users to do this manually.
 
 This module accepts a hash of options passed to its C<use> statement, with
 these keys being valid:
 
 =over 4
 
 =item -conflicts
 
 A hashref of conflict specifications, where keys are module names, and values
 are the last broken version - any version greater than the specified version
 should work.
 
 =item -also
 
 Additional modules to get conflicts from (potentially recursively). This should
 generally be a list of modules which use Dist::CheckConflicts, which correspond
 to the dists that your dist depends on. (In an ideal world, this would be
 intuited directly from your dependency list, but the dependency list isn't
 available outside of build time).
 
 =item -dist
 
 The name of the distribution, to make the error message from check_conflicts
 more user-friendly.
 
 =back
 
 The methods listed below are exported by this module into the module that uses
 it, so you should call these methods on your module, not Dist::CheckConflicts.
 
 As an example, this command line can be used to update your modules, after
 installing the C<Foo> dist (assuming that C<Foo::Conflicts> is the module in
 the C<Foo> dist which uses Dist::CheckConflicts):
 
     perl -MFoo::Conflicts -e'print "$_\n"
         for map { $_->{package} } Foo::Conflicts->calculate_conflicts' | cpanm
 
 As an added bonus, loading your conflicts module will provide warnings at
 runtime if conflicting modules are detected (regardless of whether they are
 loaded before or afterwards).
 
 =head1 METHODS
 
 =head2 conflicts
 
 Returns the conflict specification (the C<-conflicts> parameter to
 C<import()>), as a hash.
 
 =head2 dist
 
 Returns the dist name (either as specified by the C<-dist> parameter to
 C<import()>, or the package name which C<use>d this module).
 
 =head2 check_conflicts
 
 Examine the modules that are currently installed, and throw an exception with
 useful information if any modules are at versions which conflict with the dist.
 
 =head2 calculate_conflicts
 
 Examine the modules that are currently installed, and return a list of modules
 which conflict with the dist. The modules will be returned as a list of
 hashrefs, each containing C<package>, C<installed>, and C<required> keys.
 
 =head1 BUGS
 
 No known bugs.
 
 Please report any bugs to GitHub Issues at
 L<https://github.com/doy/dist-checkconflicts/issues>.
 
 =head1 SEE ALSO
 
 L<Module::Install::CheckConflicts>
 
 L<Dist::Zilla::Plugin::Conflicts>
 
 =head1 SUPPORT
 
 You can find this documentation for this module with the perldoc command.
 
     perldoc Dist::CheckConflicts
 
 You can also look for information at:
 
 =over 4
 
 =item * MetaCPAN
 
 L<https://metacpan.org/release/Dist-CheckConflicts>
 
 =item * Github
 
 L<https://github.com/doy/dist-checkconflicts>
 
 =item * RT: CPAN's request tracker
 
 L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=Dist-CheckConflicts>
 
 =item * CPAN Ratings
 
 L<http://cpanratings.perl.org/d/Dist-CheckConflicts>
 
 =back
 
 =head1 AUTHOR
 
 Jesse Luehrs <doy@tozt.net>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2014 by Jesse Luehrs.
 
 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
### Exporter/Lite.pm ###
 package Exporter::Lite;
 
 require 5.006;
 use warnings;
 use strict;
 
 our $VERSION = '0.06';
 our @EXPORT = qw(import);
 
 
 sub import {
     my($exporter, @imports)  = @_;
     my($caller, $file, $line) = caller;
 
     no strict 'refs';
 
     unless( @imports ) {        # Default import.
         @imports = @{$exporter.'::EXPORT'};
     }
     else {
         # Because @EXPORT_OK = () would indicate that nothing is
         # to be exported, we cannot simply check the length of @EXPORT_OK.
         # We must to oddness to see if the variable exists at all as
         # well as avoid autovivification.
         # XXX idea stolen from base.pm, this might be all unnecessary
         my $eokglob;
         if( $eokglob = ${$exporter.'::'}{EXPORT_OK} and *$eokglob{ARRAY} ) {
             if( @{$exporter.'::EXPORT_OK'} ) {
                 # This can also be cached.
                 my %ok = map { s/^&//; $_ => 1 } @{$exporter.'::EXPORT_OK'},
                                                  @{$exporter.'::EXPORT'};
 
                 my($denied) = grep {s/^&//; !$ok{$_}} @imports;
                 _not_exported($denied, $exporter, $file, $line) if $denied;
             }
             else {      # We don't export anything.
                 _not_exported($imports[0], $exporter, $file, $line);
             }
         }
     }
 
     _export($caller, $exporter, @imports);
 }
 
 
 
 sub _export {
     my($caller, $exporter, @imports) = @_;
 
     no strict 'refs';
 
     # Stole this from Exporter::Heavy.  I'm sure it can be written better
     # but I'm lazy at the moment.
     foreach my $sym (@imports) {
         # shortcut for the common case of no type character
         (*{$caller.'::'.$sym} = \&{$exporter.'::'.$sym}, next)
             unless $sym =~ s/^(\W)//;
 
         my $type = $1;
         my $caller_sym = $caller.'::'.$sym;
         my $export_sym = $exporter.'::'.$sym;
         *{$caller_sym} =
             $type eq '&' ? \&{$export_sym} :
             $type eq '$' ? \${$export_sym} :
             $type eq '@' ? \@{$export_sym} :
             $type eq '%' ? \%{$export_sym} :
             $type eq '*' ?  *{$export_sym} :
             do { require Carp; Carp::croak("Can't export symbol: $type$sym") };
     }
 }
 
 
 #"#
 sub _not_exported {
     my($thing, $exporter, $file, $line) = @_;
     die sprintf qq|"%s" is not exported by the %s module at %s line %d\n|,
         $thing, $exporter, $file, $line;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Exporter::Lite - lightweight exporting of functions and variables
 
 =head1 SYNOPSIS
 
   package Foo;
   use Exporter::Lite;
 
   our @EXPORT    = qw($This That);      # default exports
   our @EXPORT_OK = qw(@Left %Right);    # optional exports
 
 Then in code using the module:
 
   use Foo;
   # $This and &That are imported here
 
 You have to explicitly ask for optional exports:
 
  use Foo qw/ @Left %Right /;
 
 =head1 DESCRIPTION
 
 Exporter::Lite is an alternative to L<Exporter>,
 intended to provide a lightweight subset
 of the most commonly-used functionality.
 It supports C<import()>, C<@EXPORT> and
 C<@EXPORT_OK> and not a whole lot else.
 
 Unlike Exporter, it is not necessary to inherit from Exporter::Lite;
 Ie you don't need to write:
 
  @ISA = qw(Exporter::Lite);
 
 Exporter::Lite simply exports its import() function into your namespace.
 This might be called a "mix-in" or a "role".
 
 Setting up a module to export its variables and functions is simple:
 
     package My::Module;
     use Exporter::Lite;
 
     our @EXPORT = qw($Foo bar);
 
 Functions and variables listed in the C<@EXPORT> package variable
 are automatically exported if you use the module and don't explicitly
 list any imports.
 Now, when you C<use My::Module>, C<$Foo> and C<bar()> will show up.
 
 Optional exports are listed in the C<@EXPORT_OK> package variable:
 
     package My::Module;
     use Exporter::Lite;
 
     our @EXPORT_OK = qw($Foo bar);
 
 When My::Module is used, C<$Foo> and C<bar()> will I<not> show up,
 unless you explicitly ask for them:
 
     use My::Module qw($Foo bar);
 
 Note that when you specify one or more functions or variables to import,
 then you must also explicitly list any of the default symbols you want to use.
 So if you have an exporting module:
 
     package Games;
     our @EXPORT    = qw/ pacman defender  /;
     our @EXPORT_OK = qw/ galaga centipede /;
 
 Then if you want to use both C<pacman> and C<galaga>, then you'd write:
 
     use Games qw/ pacman galaga /;
 
 =head1 Methods
 
 Export::Lite has one public method, import(), which is called
 automatically when your modules is use()'d.  
 
 In normal usage you don't have to worry about this at all.
 
 =over 4
 
 =item B<import>
 
   Some::Module->import;
   Some::Module->import(@symbols);
 
 Works just like C<Exporter::import()> excepting it only honors
 @Some::Module::EXPORT and @Some::Module::EXPORT_OK.
 
 The given @symbols are exported to the current package provided they
 are in @Some::Module::EXPORT or @Some::Module::EXPORT_OK.  Otherwise
 an exception is thrown (ie. the program dies).
 
 If @symbols is not given, everything in @Some::Module::EXPORT is
 exported.
 
 =back
 
 =head1 DIAGNOSTICS
 
 =over 4
 
 =item '"%s" is not exported by the %s module'
 
 Attempted to import a symbol which is not in @EXPORT or @EXPORT_OK.
 
 =item 'Can\'t export symbol: %s'
 
 Attempted to import a symbol of an unknown type (ie. the leading $@% salad
 wasn't recognized).
 
 =back
 
 
 =head1 SEE ALSO
 
 L<Exporter> is the grandaddy of all Exporter modules, and bundled with Perl
 itself, unlike the rest of the modules listed here.
 
 L<Attribute::Exporter> defines attributes which you use to mark
 which subs and variables you want to export, and how.
 
 L<Exporter::Simple> also uses attributes to control the export of
 functions and variables from your module.
 
 L<Const::Exporter> makes it easy to create a module that exports constants.
 
 L<Constant::Exporter> is another module that makes it easy to create
 modules that define and export constants.
 
 L<Sub::Exporter> is a "sophisticated exporter for custom-built routines";
 it lets you provide generators that can be used to customise what
 gets imported when someone uses your module.
 
 L<Exporter::Tiny> provides the same features as L<Sub::Exporter>,
 but relying only on core dependencies.
 
 L<Exporter::Shiny> is a shortcut for L<Exporter::Tiny> that
 provides a more concise notation for providing optional exports.
 
 L<Exporter::Declare> provides syntactic sugar to make the export
 status of your functions part of their declaration. Kind of.
 
 L<AppConfig::Exporter> lets you export part of an L<AppConfig>-based
 configuration.
 
 L<Exporter::Lexical> lets you export lexical subs from your module.
 
 L<Constant::Exporter::Lazy> lets you write a module that exports
 function-style constants, which are instantiated lazily.
 
 L<Exporter::Auto> will export everything from your module that
 it thinks is a public function (name doesn't start with an underscore).
 
 L<Class::Exporter> lets you export class methods as regular subroutines.
 
 L<Xporter> is like Exporter, but with persistent defaults and auto-ISA.
 
 
 =head1 REPOSITORY
 
 L<https://github.com/neilbowers/Exporter-Lite>
 
 =head1 AUTHORS
 
 Michael G Schwern <schwern@pobox.com>
 
 =head1 LICENSE
 
 This program is free software; you can redistribute it and/or
 modify it under the same terms as Perl itself.
 
 See F<http://www.perl.com/perl/misc/Artistic.html>
 
 =cut
### File/Flock.pm ###
 package File::Flock;
 
 require Exporter;
 @ISA = qw(Exporter);
 @EXPORT = qw(lock unlock lock_rename forget_locks);
 
 use Carp;
 use POSIX qw(EAGAIN EACCES EWOULDBLOCK ENOENT EEXIST O_EXCL O_CREAT O_RDWR); 
 use Fcntl qw(LOCK_SH LOCK_EX LOCK_NB LOCK_UN);
 use IO::File;
 use Data::Structure::Util qw(unbless);
 
 use vars qw($VERSION $debug $av0debug);
 
 BEGIN	{
 	$VERSION = 2014.01;
 	$debug = 0;
 	$av0debug = 0;
 }
 
 use strict;
 no strict qw(refs);
 
 my %locks;		# did we create the file?
 my %lockHandle;
 my %shared;
 my %pid;
 my %rm;
 
 sub new_flock {
 	my ($pkg, $file, $shared, $nonblocking) = @_;
 	lock_flock($file, $shared, $nonblocking) or return undef;
 	return bless [$file], $pkg;
 }
 
 sub DESTROY
 {
 	my ($this) = @_;
 	unlock_flock($this->[0]);
 }
 
 sub lock_flock
 {
 	my ($file, $shared, $nonblocking) = @_;
 
 	my $f = new IO::File;
 
 	my $created = 0;
 	my $previous = exists $locks{$file};
 
 	# the file may be springing in and out of existence...
 	OPEN:
 	for(;;) {
 		if (-e $file) {
 			unless (sysopen($f, $file, O_RDWR)) {
 				redo OPEN if $! == ENOENT;
 				croak "open $file: $!";
 			}
 		} else {
 			unless (sysopen($f, $file, O_CREAT|O_EXCL|O_RDWR)) {
 				redo OPEN if $! == EEXIST;
 				croak "open >$file: $!";
 			}
 			print STDERR " {$$ " if $debug; # }
 			$created = 1;
 		}
 		last;
 	}
 	$locks{$file} = $created || $locks{$file} || 0;
 	$shared{$file} = $shared;
 	$pid{$file} = $$;
 	
 	$lockHandle{$file} = $f;
 
 	my $flags;
 
 	$flags = $shared ? LOCK_SH : LOCK_EX;
 	$flags |= LOCK_NB
 		if $nonblocking;
 	
 	local($0) = "$0 - locking $file" if $av0debug && ! $nonblocking;
 	my $r = flock($f, $flags);
 
 	print STDERR " ($$ " if $debug and $r;
 
 	if ($r) {
 		# let's check to make sure the file wasn't
 		# removed on us!
 
 		my $ifile = (stat($file))[1];
 		my $ihandle;
 		eval { $ihandle = (stat($f))[1] };
 		croak $@ if $@;
 
 		return 1 if defined $ifile 
 			and defined $ihandle 
 			and $ifile == $ihandle;
 
 		# oh well, try again
 		flock($f, LOCK_UN);
 		close($f);
 		return lock_flock($file);
 	}
 
 	return 1 if $r;
 	if ($nonblocking and 
 		(($! == EAGAIN) 
 		or ($! == EACCES)
 		or ($! == EWOULDBLOCK))) 
 	{
 		if (! $previous) {
 			delete $locks{$file};
 			delete $lockHandle{$file};
 			delete $shared{$file};
 			delete $pid{$file};
 		}
 		if ($created) {
 			# oops, a bad thing just happened.  
 			# We don't want to block, but we made the file.
 			&background_remove($f, $file);
 		}
 		close($f);
 		return 0;
 	}
 	croak "flock $f $flags: $!";
 }
 
 #
 # get a lock on a file and remove it if it's empty.  This is to
 # remove files that were created just so that they could be locked.
 #
 # To do this without blocking, defer any files that are locked to the
 # the END block.
 #
 sub background_remove
 {
 	my ($f, $file) = @_;
 
 	if (flock($f, LOCK_EX|LOCK_NB)) {
 		unlink($file)
 			if -s $file == 0;
 		flock($f, LOCK_UN);
 		return 1;
 	} else {
 		$rm{$file} = 1
 			unless exists $rm{$file};
 		return 0;
 	}
 }
 
 sub unlock_flock
 {
 	my ($file) = @_;
 
 	if (ref $file eq 'File::Flock') {
 		unbless $file; # avoid destructor later
 		$file = $file->[0];
 	}
 
 	croak "no lock on $file" unless exists $locks{$file};
 	my $created = $locks{$file};
 	my $unlocked = 0;
 
 
 	my $size = -s $file;
 	if ($created && defined($size) && $size == 0) {
 		if ($shared{$file}) {
 			$unlocked = 
 				&background_remove($lockHandle{$file}, $file);
 		} else { 
 			# {
 			print STDERR " $$} " if $debug;
 			unlink($file) 
 				or croak "unlink $file: $!";
 		}
 	}
 	delete $locks{$file};
 	delete $pid{$file};
 
 	my $f = $lockHandle{$file};
 
 	delete $lockHandle{$file};
 
 	return 0 unless defined $f;
 
 	print STDERR " $$) " if $debug;
 	$unlocked or flock($f, LOCK_UN)
 		or croak "flock $file UN: $!";
 
 	close($f);
 	return 1;
 }
 
 sub lock_rename_flock
 {
 	croak "arguments to lock_rename" unless @_ == 2;
 	my ($oldfile, $newfile) = @_;
 
 	if (ref $oldfile eq 'File::Flock') {
 		my $obj = $oldfile;
 		$oldfile = $obj->[0];
 		$obj->[0] = $newfile;
 	}
 	if (exists $locks{$newfile}) {
 		unlock_flock($newfile);
 	}
 	delete $locks{$newfile};
 	delete $shared{$newfile};
 	delete $pid{$newfile};
 	delete $lockHandle{$newfile};
 	delete $rm{$newfile};
 
 	$locks{$newfile}	= $locks{$oldfile}	if exists $locks{$oldfile};
 	$shared{$newfile}	= $shared{$oldfile}	if exists $shared{$oldfile};
 	$pid{$newfile}		= $pid{$oldfile}	if exists $pid{$oldfile};
 	$lockHandle{$newfile}	= $lockHandle{$oldfile} if exists $lockHandle{$oldfile};
 	$rm{$newfile}		= $rm{$oldfile}		if exists $rm{$oldfile};
 
 	delete $locks{$oldfile};
 	delete $shared{$oldfile};
 	delete $pid{$oldfile};
 	delete $lockHandle{$oldfile};
 	delete $rm{$oldfile};
 
 	return 1;
 }
 
 sub forget_locks_flock
 {
 	%locks = ();
 	%shared = ();
 	%pid = ();
 	%lockHandle = ();
 	%rm = ();
 }
 
 #
 # Unlock any files that are still locked and remove any files
 # that were created just so that they could be locked.
 #
 
 sub final_cleanup_flock
 {
 	my $f;
 	for $f (keys %locks) {
 		unlock_flock($f)
 			if $pid{$f} == $$;
 	}
 
 	my %bgrm;
 	for my $file (keys %rm) {
 		my $f = new IO::File;
 		if (sysopen($f, $file, O_RDWR)) {
 			if (flock($f, LOCK_EX|LOCK_NB)) {
 				unlink($file)
 					if -s $file == 0;
 				flock($f, LOCK_UN);
 			} else {
 				$bgrm{$file} = 1;
 			}
 			close($f);
 		}
 	}
 	if (%bgrm) {
 		my $ppid = fork;
 		croak "cannot fork" unless defined $ppid;
 		my $pppid = $$;
 		my $b0 = $0;
 		$0 = "$b0: waiting for child ($ppid) to fork()";
 		unless ($ppid) {
 			my $pid = fork;
 			croak "cannot fork" unless defined $pid;
 			unless ($pid) {
 				for my $file (keys %bgrm) {
 					my $f = new IO::File;
 					if (sysopen($f, $file, O_RDWR)) {
 						if (flock($f, LOCK_EX)) {
 							unlink($file)
 								if -s $file == 0;
 							flock($f, LOCK_UN);
 						}
 						close($f);
 					}
 				}
 				print STDERR " $pppid] $pppid)" if $debug;
 			}
 			kill(9, $$); # exit w/o END or anything else
 		}
 		waitpid($ppid, 0);
 		kill(9, $$); # exit w/o END or anything else
 	}
 
 	%locks = ();
 	%lockHandle = ();
 	%shared = ();
 	%pid = ();
 	%rm = ();
 	%bgrm = ();
 }
 
 END {
 	final_cleanup();
 }
 
 BEGIN {
 	if ($File::Flock::Forking::SubprocessEnabled) {
 		require File::Flock::Subprocess;
 		*new	        = *File::Flock::Subprocess::new;
 		*final_cleanup	= *File::Flock::Subprocess::final_cleanup;
 		*lock		= *File::Flock::Subprocess::lock;
 		*unlock		= *File::Flock::Subprocess::unlock;
 		*lock_rename	= *File::Flock::Subprocess::lock_rename;
 		*forget_locks	= *File::Flock::Subprocess::forget_locks;
 	} else {
 		*new	        = *new_flock;
 		*final_cleanup	= *final_cleanup_flock;
 		*lock		= *lock_flock;
 		*unlock		= *unlock_flock;
 		*lock_rename	= *lock_rename_flock;
 		*forget_locks	= *forget_locks_flock;
 	}
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
  File::Flock - file locking with flock
 
 =head1 SYNOPSIS
 
  use File::Flock;
 
  lock($filename);
 
  lock($filename, 'shared');
 
  lock($filename, undef, 'nonblocking');
 
  lock($filename, 'shared', 'nonblocking');
 
  unlock($filename);
 
  lock_rename($oldfilename, $newfilename)
 
  my $lock = new File::Flock '/somefile';
 
  $lock->unlock();
 
  $lock->lock_rename('/new/file');
 
  forget_locks();
 
 =head1 DESCRIPTION
 
 Lock files using the flock() call.  If the file to be locked does not
 exist, then the file is created.  If the file was created then it will
 be removed when it is unlocked assuming it's still an empty file.
 
 Locks can be created by new'ing a B<File::Flock> object.  Such locks
 are automatically removed when the object goes out of scope.  The
 B<unlock()> method may also be used.
 
 B<lock_rename()> is used to tell File::Flock when a file has been
 renamed (and thus the internal locking data that is stored based
 on the filename should be moved to a new name).  B<unlock()> the
 new name rather than the original name.
 
 Locks are released on process exit when the process that created the
 lock exits.  Subprocesses that exit do not remove locks.
 Use forget_locks() or POSIX::_exit() to prevent unlocking on process exit.
 
 =head1 SEE ALSO
 
 See L<File::Flock::Subprocess> for a variant that uses a subprocess to hold
 the locks so that the locks survive when the parent process forks.
 See L<File::Flock::Forking> for a way to automatically choose between
 File::Flock and L<File::Flock::Subprocess>.
 
 =head1 LICENSE
 
 Copyright (C) 1996-2012 David Muir Sharnoff <cpan@dave.sharnoff.org>
 Copyright (C) 2013 Google, Inc.
 This module may be used/copied/etc on the same terms as Perl itself.
 
 =head1 PACKAGERS
 
 File::Flock is packaged for Fedora by Emmanuel Seyman <emmanuel.seyman@club-internet.fr>.
 
### File/Flock/Forking.pm ###
 
 package File::Flock::Forking;
 
 require Exporter;
 @ISA = qw(Exporter);
 
 use strict;
 use Config;
 
 die "Import File::Flock::Forking before importing File::Flock"
 	if defined $File::Flock::VERSION;
 
 if ((!$Config{d_flock} && ! ($ENV{FLOCK_FORKING_USE} || '') eq 'flock')
 	|| (($ENV{FLOCK_FORKING_USE} || '') eq 'subprocess'))
 {
 	$File::Flock::Forking::SubprocessEnabled = 1;
 	require File::Flock::Subprocess;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
  File::Flock::Forking - adjust File::Flock to handle fork()
 
 =head1 SYNOPSIS
 
  use File::Flock::Forking;
  use File::Flock;
 
 =head1 DESCRIPTION
 
 The purpose of File::Flock::Forking is to change the implementation
 of L<File::Flock> to handle locking on systems that do not hold
 locks across calls to fork().
 
 If you are using L<File::Flock> or any module that uses L<File::Flock>
 then and your program uses fork(), then you should import
 File::Flock::Forking before you import L<File::Flock> or any module that
 uses L<File::Flock>.
 
 On most operating systems, File::Flock::Forking does nothing.  On
 Solaris, it changes the behavior of L<File::Flock> to be implemented
 by L<File::Flock::Subprocess>.
 
 You can also force it to use L<FIle::Flock::Subprocess> by with
 
 	$ENV{FLOCK_FORKING_USE} = 'subprocess'
 
 Or force it to use L<File::Flock> with
 
 	$ENV{FLOCK_FORKING_USE} = 'flock'
 
 =head1 LICENSE
 
 Copyright (C) 2013 Google, Inc.
 This module may be used/copied/etc on the same terms as Perl itself.
### File/Flock/Retry.pm ###
 package File::Flock::Retry;
 
 our $DATE = '2015-09-03'; # DATE
 our $VERSION = '0.60'; # VERSION
 
 use 5.010001;
 use strict;
 use warnings;
 
 use Fcntl ':flock';
 
 sub lock {
     my ($class, $path, $opts) = @_;
     $opts //= {};
     my %h;
 
     defined($path) or die "Please specify path";
     $h{path}    = $path;
     $h{retries} = $opts->{retries} // 60;
 
     my $self = bless \%h, $class;
     $self->_lock;
     $self;
 }
 
 # return 1 if we lock, 0 if already locked. die on failure.
 sub _lock {
     my $self = shift;
 
     # already locked
     return 0 if $self->{_fh};
 
     my $path = $self->{path};
     my $existed = -f $path;
     my $exists;
     my $tries = 0;
   TRY:
     while (1) {
         $tries++;
 
         # 1
         open $self->{_fh}, ">>", $path
             or die "Can't open lock file '$path': $!";
 
         # 2
         my @st1 = stat($self->{_fh}); # stat before lock
 
         # 3
         if (flock($self->{_fh}, LOCK_EX | LOCK_NB)) {
             # if file is unlinked by another process between 1 & 2, @st1 will be
             # empty and we check here.
             redo TRY unless @st1;
 
             # 4
             my @st2 = stat($path); # stat after lock
 
             # if file is unlinked between 3 & 4, @st2 will be empty and we check
             # here.
             redo TRY unless @st2;
 
             # if file is recreated between 2 & 4, @st1 and @st2 will differ in
             # dev/inode, we check here.
             redo TRY if $st1[0] != $st2[0] || $st1[1] != $st2[1];
 
             # everything seems okay
             last;
         } else {
             $tries <= $self->{retries}
                 or die "Can't acquire lock on '$path' after $tries seconds";
             sleep 1;
         }
     }
     $self->{_created} = !$existed;
     1;
 }
 
 # return 1 if we unlock, 0 if already unlocked. die on failure.
 sub _unlock {
     my ($self) = @_;
 
     my $path = $self->{path};
 
     # don't unlock if we are not holding the lock
     return 0 unless $self->{_fh};
 
     unlink $self->{path} if $self->{_created} && !(-s $self->{path});
 
     {
         # to shut up warning about flock on closed filehandle (XXX but why
         # closed if we are holding the lock?)
         no warnings;
 
         flock $self->{_fh}, LOCK_UN;
     }
     close delete($self->{_fh});
     1;
 }
 
 sub release {
     my $self = shift;
     $self->_unlock;
 }
 
 sub unlock {
     my $self = shift;
     $self->_unlock;
 }
 
 sub DESTROY {
     my $self = shift;
     $self->_unlock;
 }
 
 1;
 # ABSTRACT: Yet another flock module
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 File::Flock::Retry - Yet another flock module
 
 =head1 VERSION
 
 This document describes version 0.60 of File::Flock::Retry (from Perl distribution File-Flock-Retry), released on 2015-09-03.
 
 =head1 SYNOPSIS
 
  use File::Flock::Retry;
 
  # try to acquire exclusive lock. if fail to acquire lock within 60s, die.
  my $lock = File::Flock::Retry->lock($file);
 
  # explicitly unlock
  $lock->release;
 
  # automatically unlock if object is DESTROY-ed.
  undef $lock;
 
 =head1 DESCRIPTION
 
 This is yet another flock module. It is a more lightweight alternative to
 L<File::Flock> with some other differences:
 
 =over 4
 
 =item * OO interface only
 
 =item * Autoretry (by default for 60s) when trying to acquire lock
 
 I prefer this approach to blocking/waiting indefinitely or failing immediately.
 
 =back
 
 =for Pod::Coverage ^(DESTROY)$
 
 =head1 METHODS
 
 =head2 $lock = File::Flock::Retry->lock($path, \%opts)
 
 Attempt to acquire an exclusive lock on C<$path>. C<$path> will be created if
 not already exists. If $path is already locked by another process, will retry
 every second for a number of seconds (by default 60). Will die if failed to
 acquire lock after all retries.
 
 Will automatically unlock if C<$lock> goes out of scope. Upon unlock, will
 remove C<$path> if it was created and is still empty (this behavior is the same
 as C<File::Flock>).
 
 Available options:
 
 =over
 
 =item * retries => int (default: 60)
 
 Number of retries (equals number of seconds, since retry is done every second).
 
 =back
 
 =head2 $lock->unlock
 
 Unlock.
 
 =head2 $lock->release
 
 Synonym for C<unlock()>.
 
 =head1 CAVEATS
 
 Not yet tested on Windows. Some filesystems do not support inode?
 
 =head1 SEE ALSO
 
 L<File::Flock>
 
 L<File::Flock::Tiny> which is also tiny, but does not have the autoremove and
 autoretry capability which I want. See also:
 https://github.com/trinitum/perl-File-Flock-Tiny/issues/1
 
 flock() Perl function.
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/File-Flock-Retry>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-File-Flock-Retry>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=File-Flock-Retry>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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
### File/Flock/Subprocess.pm ###
 package File::Flock::Subprocess;
 
 @ISA = qw(Exporter);
 @EXPORT = qw(lock unlock lock_rename forget_lock);
 
 # use Smart::Comments;
 use strict;
 use warnings;
 require Exporter;
 require POSIX;
 use Socket;
 use IO::Handle;
 use Time::HiRes qw(sleep time);
 use Carp;
 use File::Temp qw(tempdir);
 use IO::Socket::UNIX;
 use Data::Structure::Util qw(unbless);
 
 # shared
 my $dir;
 my $socket;
 my $av0;
 my $debug;
 
 BEGIN { $debug = 0; }
 
 # proxy server
 my $connections;
 my $parent_pid;
 my $timer;
 my $ioe_parent;
 my $counter = '0001';
 my %locks;
 
 # client side
 my $child;
 my %lock_pids;		# filename -> pid
 my %lock_proxies;	# pid -> proxy
 my %lock_count;		# pid -> count
 my $last_pid;
 
 sub new
 {
 	my ($pkg, $file, $shared, $nonblocking) = @_;
 	&lock($file, $shared, $nonblocking) or return undef;
 	return bless [$file], __PACKAGE__;
 }
 
 sub DESTROY
 {
 	my ($this) = @_;
 	unlock($this->[0]);
 }
 
 sub encode
 {
 	local($_);
 	for $_ (@_) {
 		### assert: defined $_
 		s/\\/\\\\/g;
 		s/\n/\\n/g;
 		s/\t/\\t/g;
 	}
 }
 
 sub decode
 {
 	local($_);
 	for $_ (@_) {
 		### assert: defined $_
 		s/\\t/\t/g;
 		s/\\n/\n/g;
 		s/\\\\/\\/g;
 	}
 }
 
 sub update_proxy_connections
 {
 use Carp qw(longmess);
 	print STDERR longmess("last_pid undefined") unless defined $last_pid;
 	return if $last_pid == $$;
 	### UPDATING PROXY CONNECTIONS: "$$ IS NOT $last_pid"
 	$last_pid = $$;
 	for my $pid (keys %lock_proxies) {
 		my $proxy = IO::Socket::UNIX->new(
 			Peer	=> "$socket.$pid",
 			Type	=> SOCK_STREAM,
 		) or carp "Could not open connection to lockserver $socket.$pid: $!";
 
 		### CLOSING OLD $$
 		$lock_proxies{$pid}->close();
 		$lock_proxies{$pid} = $proxy;
 	}
 	### DONE UPDATING: $$
 }
 
 sub request
 {
 	my ($request, $file) = @_;
 	my $av0 = $0;
 	local($0) = $av0;
 	$0 = "$av0 - lock proxy request $request";
 	my $ts_before = time;
 	### REQUEST: "$$ $request"
 
 	my $proxy = $lock_proxies{$lock_pids{$file}} or die;
 
 	$proxy->print("$$ $request\n")
 		or croak "print to lock proxy: $!";
 	for(;;) {
 		my $ok = $proxy->getline();
 		chomp($ok);
 		### RESPONSE: $ok
 		if ($ts_before) {
 			my $diff = time - $ts_before;
 		}
 		if ($ok =~ /^ERROR:(.*)/) {
 			my $error = $1;
 			decode($error);
 			### ................. $error
 			$error =~ s/\n.*//s;
 			### ..... $error
 			croak $error;
 		} elsif ($ok =~ /^RESULT=(\d+)/) {
 			### RESULT: $$.$1
 			return $1;
 		} else {
 			die "unexpected response from lock proxy: $ok";
 		}
 	}
 }
 
 sub lock
 {
 	my ($file, $shared, $nonblocking) = @_;
 
 	update_proxy_connections();
 
 	if (!$lock_pids{$file}) {
 		$lock_pids{$file} = $$;
 		$lock_count{$$}++;
 	}
 	if (!$lock_proxies{$$}) {
 		$lock_proxies{$$} = IO::Socket::UNIX->new(
 			Peer	=> $socket,
 			Type	=> SOCK_STREAM,
 		) or carp "Could not open connection to lockserver $socket: $!";
 
 		request("LISTEN", $file);
 	}
 
 	$shared = $shared ? "1" : "0";
 	$nonblocking = $nonblocking ? "1" : "0";
 	my $orig_file = $file;
 	encode($file);
 	my $r = request("LOCK $shared$nonblocking $file", $file);
 	$locks{$orig_file} = $$ if $r;
 	return $r;
 }
 
 sub unlock
 {
 	my ($file) = @_;
 
 	if (ref $file eq __PACKAGE__) {
 		unbless $file; # avoid destructor later
 		$file = $file->[0];
 	}
 
 	update_proxy_connections();
 
 	if (ref $file eq 'File::Flock') {
 		bless $file, 'UNIVERSAL'; # avoid destructor later
 		$file = $$file;
 	}
 	croak "File $file not locked" unless $lock_pids{$file};
 	my $orig_file = $file;
 	encode($file);
 	my $r = request("UNLOCK $file", $file);
 	my $lock_pid = delete $lock_pids{$orig_file};
 	if ($lock_count{$lock_pid} <= 0) {
 		delete $lock_proxies{$lock_pid};
 	}
 	delete $locks{$orig_file};
 	return $r;
 }
 
 sub lock_rename
 {
 	croak "arguments to lock_rename" unless @_ == 2;
 	my ($oldfile, $newfile) = @_;
 
 	if (ref $oldfile eq 'File::Flock::Subprocess') {
 		my $obj = $oldfile;
 		$oldfile = $obj->[0];
 		$obj->[0] = $newfile;
 	}
 
 	update_proxy_connections();
 
 	carp "File $oldfile not locked" unless $lock_pids{$oldfile};
 	carp "File $newfile already locked" if $lock_pids{$newfile};
 	my ($orig_oldfile, $orig_newfile) = ($oldfile, $newfile);
 	encode($oldfile, $newfile);
 	my $r = request("LOCK_RENAME $oldfile\t$newfile", $oldfile);
 	$lock_pids{$orig_newfile} = delete $lock_pids{$orig_oldfile};
 	$locks{$orig_newfile} = delete $locks{$orig_oldfile} if exists $locks{$orig_oldfile};
 	return $r;
 }
 
 sub forget_locks
 {
 	%locks = ();
 }
 
 sub final_cleanup
 {
 	for (keys %locks) {
 		unlock($_) if $locks{$_} == $$;
 	}
 	$child->close() if defined $child;
 	undef $child;
 	undef %lock_proxies;
 }
 
 END {
 	final_cleanup();
 }
 
 sub run_lockserver
 {
 	my ($parent) = @_;
 	require IO::Event;
 	import IO::Event 'AnyEvent';
 
 	my $ioe_listener = IO::Event::Socket::UNIX->new(
 		Type	=> SOCK_STREAM,
 		Local	=> $socket,
 		Listen	=> 255,
 		Handler	=> 'File::Flock::Subprocess::Master',
 		Description => "listen($socket)",
 	);
 	carp "could not listen on unix socket: $!" unless $ioe_listener;
 
 	# we don't add a connection for the listener
 
 	$parent->print("ready\n");
 
 	$ioe_parent = IO::Event->new($parent, __PACKAGE__,
 		{ description => 'socketpair', read_only => 1});
 
 	$connections->add($ioe_parent);
 
 	if ($debug) {
 		$timer = IO::Event->timer(
 			interval => 2,
 			cb	=> sub { $connections->display() },
 		);
 	}
 
 	IO::Event::loop();
 
 	File::Flock::final_cleanup_flock();
 }
 
 {
 	package File::Flock::Subprocess::Master;
 	use strict;
 	use warnings;
 
 	# lock proxy master accepting connection to start new child
 	sub ie_connection
 	{
 		my ($pkg, $ioe) = @_;
 		my $client = $ioe->accept('File::Flock::Subprocess') or die;
 		### CONNECT IN MASTER: "$$ - @{[$ioe->ie_desc()]}"
 		my $new_child;
 		for(;;) {
 			$new_child = fork();
 			### FORKED IN ACCEPT
 			### PID: $$ 
 			### CHILD: $new_child
 			last if defined $new_child;
 			warn "Could not fork: $!";
 			sleep(1);
 		}
 		if ($new_child) {
 			# now is as good a time as any to clean up zombies
 			my $kid;
 			do {
 				$kid = waitpid(-1, &POSIX::WNOHANG);
 				### CHILD PROXY ZOMBIE REAPED: $kid
 			} while $kid > 0;
 			$client->close();
 		} else {
 			$ioe->close();
 			$connections->remove($ioe_parent);
 			$ioe_parent->close();
 			undef $ioe_parent;
 			### NEW CHILD PROXY SERVER $$
 			$av0 = "Locking proxy slave for $parent_pid using $socket";
 			$connections->add($client, "connection($socket)");
 		}
 	}
 	sub ie_input {
 		die;
 	}
 	sub ie_eof {
 		die;
 	}
 }
 
 # lock proxy children accepting replacement connections
 sub ie_connection
 {
 	my ($pkg, $ioe) = @_;
 	my $replacement = $ioe->accept();
 	$connections->add($replacement, "slave(@{[$ioe->ie_desc().$counter++]})");
 }
 
 # could be lock server master losing socketpair or lock server
 # proxy child losing a client
 sub ie_eof
 {
 	### EOF IN CHILD
 	my ($handler, $ioe, $input_buffer_reference) = @_;
 	$ioe->close();
 	unless ($connections->remove($ioe)) {
 		### "PROXY SERVER $$ ALL DONE"
 		IO::Event::unloop_all();
 	}
 }
 
 sub ie_input
 {
 	### INPUT IN CHILD
 	my ($handler, $ioe, $input_buffer_reference) = @_;
 	$0 = "$av0: processing request";
 	while (my $request = $ioe->getline()) {
 		$0 = "$av0: handling $request";
 
 		my $pid;
 		$request =~ s/^(\d+) //
 			or die "bad request to lock proxy: $request";
 		$pid = $1;
 		$0 = "$av0: handling $request from $pid: $request";
 
 		my $r;
 		### PROCESSING REQUEST FROM $pid : $request
 		eval {
 			if ($request =~ m{^LOCK (.)(.) (.*)\n}s) {
 				my ($shared, $nonblocking, $file) = ($1, $2, $3);
 				decode($file);
 				$r = File::Flock::lock_flock($file, $shared, $nonblocking);
 			} elsif ($request =~ m{^UNLOCK (.*)\n}s) {
 				my $file = $1;
 				decode($file);
 				$r = File::Flock::unlock_flock($file);
 			} elsif ($request =~ m{^LOCK_RENAME (.*?)\t(.*)\n}) {
 				my ($oldfile, $newfile) = ($1, $2);
 				decode($oldfile, $newfile);
 				$r = File::Flock::lock_rename_flock($oldfile, $newfile);
 			} elsif ($request =~ m{^LISTEN\n}) {
 				IO::Event::Socket::UNIX->new(
 					Type	=> SOCK_STREAM,
 					Local	=> "$socket.$pid",
 					Listen	=> 255,
 					Description => "slave($socket.$pid)",
 				) or die "Listen $socket.$pid: $!";
 				$r = 1;
 			} elsif ($request =~ m{^QUIT\n}) {
 				$r = 1;
 			} else {
 				die "Unknown remote lock request: $request";
 			}
 		};
 		if ($@) {
 			my $error = $@;
 			encode($error);
 			$ioe->print("ERROR:$error\n");
 		} else {
 			$r = 0 + $r;
 			$ioe->print("RESULT=$r\n");
 		}
 		$0 = "$av0: idle";
 	}
 }
 
 {
 	package File::Flock::Subprocess::Connections;
 
 	use strict;
 	use warnings;
 
 	sub new {
 		return bless {};
 	}
 	sub add {
 		my ($self, $ioe, $label) = @_;
 		$ioe->ie_desc($label) if $label;
 		die "duplicate @{[$ioe->ie_desc()]}" if ++$self->{$ioe->ie_desc()} > 1;
 		print STDERR "PROXY $$: " . join(' ', 'ADD', $ioe->ie_desc(), ':', sort keys %$self) . "\n" if $debug;
 	}
 	sub remove
 	{	
 		my ($self, $ioe) = @_;
 		die $ioe unless $self->{$ioe->ie_desc()};
 		delete $self->{$ioe->ie_desc()};;
 		print STDERR "PROXY $$: " . join(' ', 'REMOVE', $ioe->ie_desc(), ':', sort keys %$self) . "\n" if $debug;
 		return scalar(keys %$self);
 	}
 	sub display {
 		my ($self) = @_;
 		print STDERR "PROXY $$: " . join(' ', sort keys %$self) . "\n" if $debug;
 	}
 }
 
 
 BEGIN {
 	# Let File::Flock know we're live with Subprocess
 	$File::Flock::Forking::SubprocessEnabled = 1;
 	require File::Flock;
 
 	$dir = tempdir(CLEANUP => 0);
 	$socket = "$dir/lock";
 
 	my $parent = new IO::Handle;
 	$child = new IO::Handle;
 	socketpair($parent, $child, AF_UNIX, SOCK_STREAM, PF_UNSPEC)
 		or die "cannot create socketpair: $!";
 
 	$parent_pid = $$;
 	my $child_pid;
 	### FORKING: $$
 	for(;;) {
 		$child_pid = fork();
 		### CHILD: $child_pid
 		last if defined $child_pid;
 		warn "Could not fork: $!";
 		sleep(1);
 	}
 	if ($child_pid) {
 		$parent->close();
 		my $ready = <$child>;
 		die unless $ready && $ready eq "ready\n";
 		$last_pid = $$;
 
 		# We need File::Flock->new() to work.  This is a bit gross:
 		*File::Flock::new = \&File::Flock::Subprocess::new
 			unless defined &File::Flock::new;
 
 		if ($debug) {
 			$SIG{ALRM} = sub {
 				print STDERR "$$ Alive with " . ($child ? "child defined" : "child undefined") . "\n";
 				alarm(2);
 			};
 			alarm(2);
 		}
 	} else {
 		require IO::Event;
 		$av0 = "Locking proxy master for $parent_pid, using $socket";
 		$0 = $av0;
 		$child->close();
 		undef $child;
 
 		$connections = File::Flock::Subprocess::Connections->new();
 
 		run_lockserver($parent);
 
 		POSIX::_exit(0);
 		die;
 
 	}
 }
 
 1;
 
 __END__
 
 Implementation notes.
 
 We're trying to mimic the bahavior of locking on systems that
 preserve locks across fork().
 
 We create connections to the proxy server as needed.  When we make
 such connections, we record (with the connection) our current process
 PID.
 
 Whenever we have a new lock()/unlock()/lock_rename() request, we check
 to see if we're still the same process we used to be.  If not, we
 re-open connections to the lock proxies.  This way connections aren't
 shared with child processes.
 
 
 
 =head1 NAME
 
  File::Flock::Subprocess - file locking with flock in a subprocess
 
 =head1 SYNOPSIS
 
  use File::Flock::Subprocess;
 
  lock($filename);
 
  lock($filename, 'shared');
 
  lock($filename, undef, 'nonblocking');
 
  lock($filename, 'shared', 'nonblocking');
 
  unlock($filename);
 
  lock_rename($oldfilename, $newfilename)
 
  my $lock = new File::Flock '/somefile';
 
  $lock->unlock();
 
  $lock->lock_rename('/new/file');
 
  forget_locks();
 
 =head1 DESCRIPTION
 
 This is a wrapper around L<File::Flock> that starts a subprocess and
 does the locking in the subprocess with L<File::Flock>.  The purpose of
 this is to handle operating systems (eg: Solaris) that do not retain
 locks across a call to fork().
 
 The sub-process for this is created with fork() when
 File::Flock::Subprocess is compiled.  I've tried to minimize the
 side-effects calling fork() by doing calling it early and by using
 POSIX::_exit() to quit but it is still worth being aware of.  I suggest
 loading File::Flock::Subprocess early.
 
 Use L<File::Flock::Forking> to automatically detect when this is needed.
 
 Read the docs for L<File::Flock> for details of the API.
 
 =head1 ERRATA
 
 Any errors reported by the locking proxy File::Flock::Subprocess starts
 will be reported as "Compilation Failed" errors because the proxy is
 started in a BEGIN{} block.
 
 =head1 LICENSE
 
 Copyright (C) 2013 Google, Inc.
 This module may be used/copied/etc on the same terms as Perl itself.
 
### File/HomeDir.pm ###
 package File::HomeDir;
 
 # See POD at end for documentation
 
 use 5.00503;
 use strict;
 use Carp        ();
 use Config      ();
 use File::Spec  ();
 use File::Which ();
 
 # Globals
 use vars qw{$VERSION @ISA @EXPORT @EXPORT_OK $IMPLEMENTED_BY};
 BEGIN {
 	$VERSION = '1.00';
 
 	# Inherit manually
 	require Exporter;
 	@ISA       = qw{ Exporter };
 	@EXPORT    = qw{ home     };
 	@EXPORT_OK = qw{
 		home
 		my_home
 		my_desktop
 		my_documents
 		my_music
 		my_pictures
 		my_videos
 		my_data
 		my_dist_config
 		my_dist_data
 		users_home
 		users_desktop
 		users_documents
 		users_music
 		users_pictures
 		users_videos
 		users_data
 	};
 
 	# %~ doesn't need (and won't take) exporting, as it's a magic
 	# symbol name that's always looked for in package 'main'.
 }
 
 # Inlined Params::Util functions
 sub _CLASS ($) {
 	(defined $_[0] and ! ref $_[0] and $_[0] =~ m/^[^\W\d]\w*(?:::\w+)*\z/s) ? $_[0] : undef;
 }
 sub _DRIVER ($$) {
 	(defined _CLASS($_[0]) and eval "require $_[0];" and ! $@ and $_[0]->isa($_[1]) and $_[0] ne $_[1]) ? $_[0] : undef;
 }
 
 # Platform detection
 if ( $IMPLEMENTED_BY ) {
 	# Allow for custom HomeDir classes
 	# Leave it as the existing value
 } elsif ( $^O eq 'MSWin32' ) {
 	# All versions of Windows
 	$IMPLEMENTED_BY = 'File::HomeDir::Windows';
 } elsif ( $^O eq 'darwin') {
 	# 1st: try Mac::SystemDirectory by chansen
 	if ( eval { require Mac::SystemDirectory; 1 } ) {
 		$IMPLEMENTED_BY = 'File::HomeDir::Darwin::Cocoa';
 	} elsif ( eval { require Mac::Files; 1 } ) {
 		# 2nd try Mac::Files: Carbon - unmaintained since 2006 except some 64bit fixes
 		$IMPLEMENTED_BY = 'File::HomeDir::Darwin::Carbon';
 	} else {
 		# 3rd: fallback: pure perl
 		$IMPLEMENTED_BY = 'File::HomeDir::Darwin';
 	}
 } elsif ( $^O eq 'MacOS' ) {
 	# Legacy Mac OS
 	$IMPLEMENTED_BY = 'File::HomeDir::MacOS9';
 } elsif ( File::Which::which('xdg-user-dir') ) {
 	# freedesktop unixes
 	$IMPLEMENTED_BY = 'File::HomeDir::FreeDesktop';
 } else {
 	# Default to Unix semantics
 	$IMPLEMENTED_BY = 'File::HomeDir::Unix';
 }
 unless ( _DRIVER($IMPLEMENTED_BY, 'File::HomeDir::Driver') ) {
 	Carp::croak("Missing or invalid File::HomeDir driver $IMPLEMENTED_BY");
 }
 
 
 
 
 
 #####################################################################
 # Current User Methods
 
 sub my_home {
 	$IMPLEMENTED_BY->my_home;
 }
 
 sub my_desktop {
 	$IMPLEMENTED_BY->can('my_desktop')
 		? $IMPLEMENTED_BY->my_desktop
 		: Carp::croak("The my_desktop method is not implemented on this platform");
 }
 
 sub my_documents {
 	$IMPLEMENTED_BY->can('my_documents')
 		? $IMPLEMENTED_BY->my_documents
 		: Carp::croak("The my_documents method is not implemented on this platform");
 }
 
 sub my_music {
 	$IMPLEMENTED_BY->can('my_music')
 		? $IMPLEMENTED_BY->my_music
 		: Carp::croak("The my_music method is not implemented on this platform");
 }
 
 sub my_pictures {
 	$IMPLEMENTED_BY->can('my_pictures')
 		? $IMPLEMENTED_BY->my_pictures
 		: Carp::croak("The my_pictures method is not implemented on this platform");
 }
 
 sub my_videos {
 	$IMPLEMENTED_BY->can('my_videos')
 		? $IMPLEMENTED_BY->my_videos
 		: Carp::croak("The my_videos method is not implemented on this platform");
 }
 
 sub my_data {
 	$IMPLEMENTED_BY->can('my_data')
 		? $IMPLEMENTED_BY->my_data
 		: Carp::croak("The my_data method is not implemented on this platform");
 }
 
 
 sub my_dist_data {
 	my $params = ref $_[-1] eq 'HASH' ? pop : {};
 	my $dist   = pop or Carp::croak("The my_dist_data method requires an argument");
 	my $data   = my_data();
 
         # If datadir is not defined, there's nothing we can do: bail out
         # and return nothing...	
 	return undef unless defined $data;
 
         # On traditional unixes, hide the top-level directory
 	my $var = $data eq home()
 		? File::Spec->catdir( $data, '.perl', 'dist', $dist )
 		: File::Spec->catdir( $data, 'Perl',  'dist', $dist );
 
 	# directory exists: return it
 	return $var if -d $var;
 
 	# directory doesn't exist: check if we need to create it...
 	return undef unless $params->{create};
 
 	# user requested directory creation
 	require File::Path;
 	File::Path::mkpath( $var );
 	return $var;
 }
 
 sub my_dist_config {
 	my $params = ref $_[-1] eq 'HASH' ? pop : {};
 	my $dist   = pop or Carp::croak("The my_dist_config method requires an argument");
 
 	# not all platforms support a specific my_config() method
 	my $config = $IMPLEMENTED_BY->can('my_config')
 		? $IMPLEMENTED_BY->my_config
 		: $IMPLEMENTED_BY->my_documents;
 
 	# If neither configdir nor my_documents is defined, there's
 	# nothing we can do: bail out and return nothing...	
 	return undef unless defined $config;
 
 	# On traditional unixes, hide the top-level dir
 	my $etc = $config eq home()
 		? File::Spec->catdir( $config, '.perl', $dist )
 		: File::Spec->catdir( $config, 'Perl',  $dist );
 
 	# directory exists: return it
 	return $etc if -d $etc;
 
 	# directory doesn't exist: check if we need to create it...
 	return undef unless $params->{create};
 
 	# user requested directory creation
 	require File::Path;
 	File::Path::mkpath( $etc );
 	return $etc;
 }
 
 
 
 
 #####################################################################
 # General User Methods
 
 sub users_home {
 	$IMPLEMENTED_BY->can('users_home')
 		? $IMPLEMENTED_BY->users_home( $_[-1] )
 		: Carp::croak("The users_home method is not implemented on this platform");
 }
 
 sub users_desktop {
 	$IMPLEMENTED_BY->can('users_desktop')
 		? $IMPLEMENTED_BY->users_desktop( $_[-1] )
 		: Carp::croak("The users_desktop method is not implemented on this platform");
 }
 
 sub users_documents {
 	$IMPLEMENTED_BY->can('users_documents')
 		? $IMPLEMENTED_BY->users_documents( $_[-1] )
 		: Carp::croak("The users_documents method is not implemented on this platform");
 }
 
 sub users_music {
 	$IMPLEMENTED_BY->can('users_music')
 		? $IMPLEMENTED_BY->users_music( $_[-1] )
 		: Carp::croak("The users_music method is not implemented on this platform");
 }
 
 sub users_pictures {
 	$IMPLEMENTED_BY->can('users_pictures')
 		? $IMPLEMENTED_BY->users_pictures( $_[-1] )
 		: Carp::croak("The users_pictures method is not implemented on this platform");
 }
 
 sub users_videos {
 	$IMPLEMENTED_BY->can('users_videos')
 		? $IMPLEMENTED_BY->users_videos( $_[-1] )
 		: Carp::croak("The users_videos method is not implemented on this platform");
 }
 
 sub users_data {
 	$IMPLEMENTED_BY->can('users_data')
 		? $IMPLEMENTED_BY->users_data( $_[-1] )
 		: Carp::croak("The users_data method is not implemented on this platform");
 }
 
 
 
 
 
 #####################################################################
 # Legacy Methods
 
 # Find the home directory of an arbitrary user
 sub home (;$) {
 	# Allow to be called as a method
 	if ( $_[0] and $_[0] eq 'File::HomeDir' ) {
 		shift();
 	}
 
 	# No params means my home
 	return my_home() unless @_;
 
 	# Check the param
 	my $name = shift;
 	if ( ! defined $name ) {
 		Carp::croak("Can't use undef as a username");
 	}
 	if ( ! length $name ) {
 		Carp::croak("Can't use empty-string (\"\") as a username");
 	}
 
 	# A dot also means my home
 	### Is this meant to mean File::Spec->curdir?
 	if ( $name eq '.' ) {
 		return my_home();
 	}
 
 	# Now hand off to the implementor
 	$IMPLEMENTED_BY->users_home($name);
 }
 
 
 
 
 
 #####################################################################
 # Tie-Based Interface
 
 # Okay, things below this point get scary
 
 CLASS: {
 	# Make the class for the %~ tied hash:
 	package File::HomeDir::TIE;
 
 	# Make the singleton object.
 	# (We don't use the hash for anything, though)
 	### THEN WHY MAKE IT???
 	my $SINGLETON = bless {};
 
 	sub TIEHASH { $SINGLETON }
 
 	sub FETCH {
 		# Catch a bad username
 		unless ( defined $_[1] ) {
 			Carp::croak("Can't use undef as a username");
 		}
 
 		# Get our homedir
 		unless ( length $_[1] ) {
 			return File::HomeDir::my_home();
 		}
 
 		# Get a named user's homedir
 		Carp::carp("The tied %~ hash has been deprecated");
 		return File::HomeDir::home($_[1]);
 	}
 
 	sub STORE    { _bad('STORE')    }
 	sub EXISTS   { _bad('EXISTS')   }
 	sub DELETE   { _bad('DELETE')   }
 	sub CLEAR    { _bad('CLEAR')    }
 	sub FIRSTKEY { _bad('FIRSTKEY') }
 	sub NEXTKEY  { _bad('NEXTKEY')  }
 
 	sub _bad ($) {
 		Carp::croak("You can't $_[0] with the %~ hash")
 	}
 }
 
 # Do the actual tie of the global %~ variable
 tie %~, 'File::HomeDir::TIE';
 
 1;
 
 __END__
 
 =pod
 
 =head1 NAME
 
 File::HomeDir - Find your home and other directories on any platform
 
 =head1 SYNOPSIS
 
   use File::HomeDir;
   
   # Modern Interface (Current User)
   $home     = File::HomeDir->my_home;
   $desktop  = File::HomeDir->my_desktop;
   $docs     = File::HomeDir->my_documents;
   $music    = File::HomeDir->my_music;
   $pics     = File::HomeDir->my_pictures;
   $videos   = File::HomeDir->my_videos;
   $data     = File::HomeDir->my_data;
   $dist     = File::HomeDir->my_dist_data('File-HomeDir');
   $dist     = File::HomeDir->my_dist_config('File-HomeDir');
   
   # Modern Interface (Other Users)
   $home    = File::HomeDir->users_home('foo');
   $desktop = File::HomeDir->users_desktop('foo');
   $docs    = File::HomeDir->users_documents('foo');
   $music   = File::HomeDir->users_music('foo');
   $pics    = File::HomeDir->users_pictures('foo');
   $video   = File::HomeDir->users_videos('foo');
   $data    = File::HomeDir->users_data('foo');
 
 =head1 DESCRIPTION
 
 B<File::HomeDir> is a module for locating the directories that are "owned"
 by a user (typicaly your user) and to solve the various issues that arise
 trying to find them consistently across a wide variety of platforms.
 
 The end result is a single API that can find your resources on any platform,
 making it relatively trivial to create Perl software that works elegantly
 and correctly no matter where you run it.
 
 This module provides two main interfaces.
 
 The first is a modern L<File::Spec>-style interface with a consistent
 OO API and different implementation modules to support various
 platforms. You are B<strongly> recommended to use this interface.
 
 The second interface is for legacy support of the original 0.07 interface
 that exported a C<home()> function by default and tied the C<%~> variable.
 
 It is generally not recommended that you use this interface, but due to
 back-compatibility reasons they will remain supported until at least 2010.
 
 The C<%~> interface has been deprecated. Documentation was removed in 2009,
 Unit test were removed in 2011, usage will issue warnings from 2012, and the
 interface will be removed entirely in 2015  (in line with the general Perl
 toolchain convention of a 10 year support period for legacy APIs that
 are potentially or actually in common use).
 
 =head2 Platform Neutrality
 
 In the Unix world, many different types of data can be mixed together
 in your home directory (although on some Unix platforms this is no longer
 the case, particularly for "desktop"-oriented platforms).
 
 On some non-Unix platforms, separate directories are allocated for
 different types of data and have been for a long time.
 
 When writing applications on top of B<File::HomeDir>, you should thus
 always try to use the most specific method you can. User documents should
 be saved in C<my_documents>, data that supports an application but isn't
 normally editing by the user directory should go into C<my_data>.
 
 On platforms that do not make any distinction, all these different
 methods will harmlessly degrade to the main home directory, but on
 platforms that care B<File::HomeDir> will always try to Do The Right
 Thing(tm).
 
 =head1 METHODS
 
 Two types of methods are provided. The C<my_method> series of methods for
 finding resources for the current user, and the C<users_method> (read as
 "user's method") series for finding resources for arbitrary users.
 
 This split is necessary, as on most platforms it is B<much> easier to find
 information about the current user compared to other users, and indeed
 on a number you cannot find out information such as C<users_desktop> at
 all, due to security restrictions.
 
 All methods will double check (using a C<-d> test) that a directory
 actually exists before returning it, so you may trust in the values
 that are returned (subject to the usual caveats of race conditions of
 directories being deleted at the moment between a directory being returned
 and you using it).
 
 However, because in some cases platforms may not support the concept of home
 directories at all, any method may return C<undef> (both in scalar and list
 context) to indicate that there is no matching directory on the system.
 
 For example, most untrusted 'nobody'-type users do not have a home
 directory. So any modules that are used in a CGI application that
 at some level of recursion use your code, will result in calls to
 File::HomeDir returning undef, even for a basic home() call.
 
 =head2 my_home
 
 The C<my_home> method takes no arguments and returns the main home/profile
 directory for the current user.
 
 If the distinction is important to you, the term "current" refers to the
 real user, and not the effective user.
 
 This is also the case for all of the other "my" methods.
 
 Returns the directory path as a string, C<undef> if the current user
 does not have a home directory, or dies on error.
 
 =head2 my_desktop
 
 The C<my_desktop> method takes no arguments and returns the "desktop"
 directory for the current user.
 
 Due to the diversity and complexity of implementions required to deal with
 implementing the required functionality fully and completely, the
 C<my_desktop> method may or may not be implemented on each platform.
 
 That said, I am extremely interested in code to implement C<my_desktop> on
 Unix, as long as it is capable of dealing (as the Windows implementation
 does) with internationalisation. It should also avoid false positive
 results by making sure it only returns the appropriate directories for the
 appropriate platforms.
 
 Returns the directory path as a string, C<undef> if the current user
 does not have a desktop directory, or dies on error.
 
 =head2 my_documents
 
 The C<my_documents> method takes no arguments and returns the directory (for
 the current user) where the user's documents are stored.
 
 Returns the directory path as a string, C<undef> if the current user
 does not have a documents directory, or dies on error.
 
 =head2 my_music
 
 The C<my_music> method takes no arguments and returns the directory
 where the current user's music is stored.
 
 No bias is made to any particular music type or music program, rather the
 concept of a directory to hold the user's music is made at the level of the
 underlying operating system or (at least) desktop environment.
 
 Returns the directory path as a string, C<undef> if the current user
 does not have a suitable directory, or dies on error.
 
 =head2 my_pictures
 
 The C<my_pictures> method takes no arguments and returns the directory
 where the current user's pictures are stored.
 
 No bias is made to any particular picture type or picture program, rather the
 concept of a directory to hold the user's pictures is made at the level of the
 underlying operating system or (at least) desktop environment.
 
 Returns the directory path as a string, C<undef> if the current user
 does not have a suitable directory, or dies on error.
 
 =head2 my_videos
 
 The C<my_videos> method takes no arguments and returns the directory
 where the current user's videos are stored.
 
 No bias is made to any particular video type or video program, rather the
 concept of a directory to hold the user's videos is made at the level of the
 underlying operating system or (at least) desktop environment.
 
 Returns the directory path as a string, C<undef> if the current user
 does not have a suitable directory, or dies on error.
 
 =head2 my_data
 
 The C<my_data> method takes no arguments and returns the directory where
 local applications should stored their internal data for the current
 user.
 
 Generally an application would create a subdirectory such as C<.foo>,
 beneath this directory, and store its data there. By creating your
 directory this way, you get an accurate result on the maximum number of
 platforms. But see the documentation about C<my_dist_config()> or
 C<my_dist_data()> below.
 
 For example, on Unix you get C<~/.foo> and on Win32 you get
 C<~/Local Settings/Application Data/.foo>
 
 Returns the directory path as a string, C<undef> if the current user
 does not have a data directory, or dies on error.
 
 
 =head2 my_dist_config
 
   File::HomeDir->my_dist_config( $dist [, \%params] );
   
   # For example...
   
   File::HomeDir->my_dist_config( 'File-HomeDir' );
   File::HomeDir->my_dist_config( 'File-HomeDir', { create => 1 } );
 
 The C<my_dist_config> method takes a distribution name as argument and
 returns an application-specific directory where they should store their
 internal configuration.
 
 The base directory will be either C<my_config> if the platform supports
 it, or C<my_documents> otherwise. The subdirectory itself will be 
 C<BASE/Perl/Dist-Name>. If the base directory is the user's homedir,
 C<my_dist_config> will be in C<~/.perl/Dist-Name> (and thus be hidden on
 all Unixes).
 
 The optional last argument is a hash reference to tweak the method
 behaviour. The following hash keys are recognized:
 
 =over 4
 
 =item * create
 
 Passing a true value to this key will force the creation of the
 directory if it doesn't exist (remember that C<File::HomeDir>'s policy
 is to return C<undef> if the directory doesn't exist).
 
 Defaults to false, meaning no automatic creation of directory.
 
 =back
 
 
 =head2 my_dist_data
 
   File::HomeDir->my_dist_data( $dist [, \%params] );
   
   # For example...
   
   File::HomeDir->my_dist_data( 'File-HomeDir' );
   File::HomeDir->my_dist_data( 'File-HomeDir', { create => 1 } );
 
 The C<my_dist_data> method takes a distribution name as argument and
 returns an application-specific directory where they should store their
 internal data.
 
 This directory will be of course a subdirectory of C<my_data>. Platforms
 supporting data-specific directories will use
 C<DATA_DIR/perl/dist/Dist-Name> following the common
 "DATA/vendor/application" pattern. If the C<my_data> directory is the
 user's homedir, C<my_dist_data> will be in C<~/.perl/dist/Dist-Name>
 (and thus be hidden on all Unixes).
 
 The optional last argument is a hash reference to tweak the method
 behaviour. The following hash keys are recognized:
 
 =over 4
 
 =item * create
 
 Passing a true value to this key will force the creation of the
 directory if it doesn't exist (remember that C<File::HomeDir>'s policy
 is to return C<undef> if the directory doesn't exist).
 
 Defaults to false, meaning no automatic creation of directory.
 
 =back
 
 =head2 users_home
 
   $home = File::HomeDir->users_home('foo');
 
 The C<users_home> method takes a single param and is used to locate the
 parent home/profile directory for an identified user on the system.
 
 While most of the time this identifier would be some form of user name,
 it is permitted to vary per-platform to support user ids or UUIDs as
 applicable for that platform.
 
 Returns the directory path as a string, C<undef> if that user
 does not have a home directory, or dies on error.
 
 =head2 users_documents
 
   $docs = File::HomeDir->users_documents('foo');
 
 Returns the directory path as a string, C<undef> if that user
 does not have a documents directory, or dies on error.
 
 =head2 users_data
 
   $data = File::HomeDir->users_data('foo');
 
 Returns the directory path as a string, C<undef> if that user
 does not have a data directory, or dies on error.
 
 =head1 FUNCTIONS
 
 =head2 home
 
   use File::HomeDir;
   $home = home();
   $home = home('foo');
   $home = File::HomeDir::home();
   $home = File::HomeDir::home('foo');
 
 The C<home> function is exported by default and is provided for
 compatibility with legacy applications. In new applications, you should
 use the newer method-based interface above.
 
 Returns the directory path to a named user's home/profile directory.
 
 If provided no param, returns the directory path to the current user's
 home/profile directory.
 
 =head1 TO DO
 
 =over 4
 
 =item * Add more granularity to Unix, and add support to VMS and other
 esoteric platforms, so we can consider going core.
 
 =item * Add consistent support for users_* methods 
 
 =back
 
 =head1 SUPPORT
 
 This module is stored in an Open Repository at the following address.
 
 L<http://svn.ali.as/cpan/trunk/File-HomeDir>
 
 Write access to the repository is made available automatically to any
 published CPAN author, and to most other volunteers on request.
 
 If you are able to submit your bug report in the form of new (failing)
 unit tests, or can apply your fix directly instead of submitting a patch,
 you are B<strongly> encouraged to do so as the author currently maintains
 over 100 modules and it can take some time to deal with non-Critical bug
 reports or patches.
 
 This will guarantee that your issue will be addressed in the next
 release of the module.
 
 If you cannot provide a direct test or fix, or don't have time to do so,
 then regular bug reports are still accepted and appreciated via the CPAN
 bug tracker.
 
 L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=File-HomeDir>
 
 For other issues, for commercial enhancement or support, or to have your
 write access enabled for the repository, contact the author at the email
 address above.
 
 =head1 ACKNOWLEDGEMENTS
 
 The biggest acknowledgement goes to Chris Nandor, who wielded his
 legendary Mac-fu and turned my initial fairly ordinary Darwin
 implementation into something that actually worked properly everywhere,
 and then donated a Mac OS X license to allow it to be maintained properly.
 
 =head1 AUTHORS
 
 Adam Kennedy E<lt>adamk@cpan.orgE<gt>
 
 Sean M. Burke E<lt>sburke@cpan.orgE<gt>
 
 Chris Nandor E<lt>cnandor@cpan.orgE<gt>
 
 Stephen Steneker E<lt>stennie@cpan.orgE<gt>
 
 =head1 SEE ALSO
 
 L<File::ShareDir>, L<File::HomeDir::Win32> (legacy)
 
 =head1 COPYRIGHT
 
 Copyright 2005 - 2012 Adam Kennedy.
 
 Some parts copyright 2000 Sean M. Burke.
 
 Some parts copyright 2006 Chris Nandor.
 
 Some parts copyright 2006 Stephen Steneker.
 
 Some parts copyright 2009-2011 Jérôme Quelin.
 
 This program is free software; you can redistribute
 it and/or modify it under the same terms as Perl itself.
 
 The full text of the license can be found in the
 LICENSE file included with this module.
 
 =cut
### File/HomeDir/Darwin.pm ###
 package File::HomeDir::Darwin;
 
 use 5.00503;
 use strict;
 use Cwd                 ();
 use Carp                ();
 use File::HomeDir::Unix ();
 
 use vars qw{$VERSION @ISA};
 BEGIN {
 	$VERSION = '1.00';
 	@ISA     = 'File::HomeDir::Unix';
 }
 
 
 
 
 
 #####################################################################
 # Current User Methods
 
 sub my_home {
 	my $class = shift;
 
 	if ( exists $ENV{HOME} and defined $ENV{HOME} ) {
 		return $ENV{HOME};
 	}
 
 	my $home = (getpwuid($<))[7];
 	return $home if $home && -d $home;
 
 	return undef;
 }
 
 sub _my_home {
 	my($class, $path) = @_;
 	my $home = $class->my_home;
 	return undef unless defined $home;
 
 	my $folder = "$home/$path";
 	unless ( -d $folder ) {
 		# Make sure that symlinks resolve to directories.
 		return undef unless -l $folder;
 		my $dir = readlink $folder or return;
 		return undef unless -d $dir;
 	}
 
 	return Cwd::abs_path($folder);
 }
 
 sub my_desktop {
 	my $class = shift;
 	$class->_my_home('Desktop');
 }
 
 sub my_documents {
 	my $class = shift;
 	$class->_my_home('Documents');
 }
 
 sub my_data {
 	my $class = shift;
 	$class->_my_home('Library/Application Support');
 }
 
 sub my_music {
 	my $class = shift;
 	$class->_my_home('Music');
 }
 
 sub my_pictures {
 	my $class = shift;
 	$class->_my_home('Pictures');
 }
 
 sub my_videos {
 	my $class = shift;
 	$class->_my_home('Movies');
 }
 
 
 
 
 
 #####################################################################
 # Arbitrary User Methods
 
 sub users_home {
 	my $class = shift;
 	my $home  = $class->SUPER::users_home(@_);
 	return defined $home ? Cwd::abs_path($home) : undef;
 }
 
 sub users_desktop {
 	my ($class, $name) = @_;
 	return undef if $name eq 'root';
 	$class->_to_user( $class->my_desktop, $name );
 }
 
 sub users_documents {
 	my ($class, $name) = @_;
 	return undef if $name eq 'root';
 	$class->_to_user( $class->my_documents, $name );
 }
 
 sub users_data {
 	my ($class, $name) = @_;
 	$class->_to_user( $class->my_data, $name )
 	||
 	$class->users_home($name);
 }
 
 # cheap hack ... not entirely reliable, perhaps, but ... c'est la vie, since
 # there's really no other good way to do it at this time, that i know of -- pudge
 sub _to_user {
 	my ($class, $path, $name) = @_;
 	my $my_home    = $class->my_home;
 	my $users_home = $class->users_home($name);
 	defined $users_home or return undef;
 	$path =~ s/^\Q$my_home/$users_home/;
 	return $path;
 }
 
 1;
 
 =pod
 
 =head1 NAME
 
 File::HomeDir::Darwin - Find your home and other directories on Darwin (OS X)
 
 =head1 DESCRIPTION
 
 This module provides Mac OS X specific file path for determining
 common user directories in pure perl, by just using C<$ENV{HOME}>
 without Carbon nor Cocoa API calls. In normal usage this module will
 always be used via L<File::HomeDir>.
 
 =head1 SYNOPSIS
 
   use File::HomeDir;
   
   # Find directories for the current user
   $home    = File::HomeDir->my_home;      # /Users/mylogin
   $desktop = File::HomeDir->my_desktop;   # /Users/mylogin/Desktop
   $docs    = File::HomeDir->my_documents; # /Users/mylogin/Documents
   $music   = File::HomeDir->my_music;     # /Users/mylogin/Music
   $pics    = File::HomeDir->my_pictures;  # /Users/mylogin/Pictures
   $videos  = File::HomeDir->my_videos;    # /Users/mylogin/Movies
   $data    = File::HomeDir->my_data;      # /Users/mylogin/Library/Application Support
 
 =cut
### File/HomeDir/Darwin/Carbon.pm ###
 package File::HomeDir::Darwin::Carbon;
 
 # Basic implementation for the Dawin family of operating systems.
 # This includes (most prominently) Mac OS X.
 
 use 5.00503;
 use strict;
 use Cwd                   ();
 use Carp                  ();
 use File::HomeDir::Darwin ();
 
 use vars qw{$VERSION @ISA};
 BEGIN {
 	$VERSION = '1.00';
 
 	# This is only a child class of the pure Perl darwin
 	# class so that we can do homedir detection of all three
 	# drivers at one via ->isa.
 	@ISA = 'File::HomeDir::Darwin';
 
 	# Load early if in a forking environment and we have
 	# prefork, or at run-time if not.
 	local $@;
 	eval "use prefork 'Mac::Files'";
 }
 
 
 
 
 
 #####################################################################
 # Current User Methods
 
 sub my_home {
 	my $class = shift;
 
 	# A lot of unix people and unix-derived tools rely on
 	# the ability to overload HOME. We will support it too
 	# so that they can replace raw HOME calls with File::HomeDir.
 	if ( exists $ENV{HOME} and defined $ENV{HOME} ) {
 		return $ENV{HOME};
 	}
 
 	require Mac::Files;
 	$class->_find_folder(
 		Mac::Files::kCurrentUserFolderType(),
 	);
 }
 
 sub my_desktop {
 	my $class = shift;
 
 	require Mac::Files;
 	$class->_find_folder(
 		Mac::Files::kDesktopFolderType(),
 	);
 }
 
 sub my_documents {
 	my $class = shift;
 
 	require Mac::Files;
 	$class->_find_folder(
 		Mac::Files::kDocumentsFolderType(),
 	);
 }
 
 sub my_data {
 	my $class = shift;
 
 	require Mac::Files;
 	$class->_find_folder(
 		Mac::Files::kApplicationSupportFolderType(),
 	);
 }
 
 sub my_music {
 	my $class = shift;
 
 	require Mac::Files;
 	$class->_find_folder(
 		Mac::Files::kMusicDocumentsFolderType(),
 	);
 }
 
 sub my_pictures {
 	my $class = shift;
 
 	require Mac::Files;
 	$class->_find_folder(
 		Mac::Files::kPictureDocumentsFolderType(),
 	);
 }
 
 sub my_videos {
 	my $class = shift;
 
 	require Mac::Files;
 	$class->_find_folder(
 		Mac::Files::kMovieDocumentsFolderType(),
 	);
 }
 
 sub _find_folder {
 	my $class = shift;
 	my $name  = shift;
 
 	require Mac::Files;
 	my $folder = Mac::Files::FindFolder(
 		Mac::Files::kUserDomain(),
 		$name,
 	);
 	return undef unless defined $folder;
 
 	unless ( -d $folder ) {
 		# Make sure that symlinks resolve to directories.
 		return undef unless -l $folder;
 		my $dir = readlink $folder or return;
 		return undef unless -d $dir;
 	}
 
 	return Cwd::abs_path($folder);
 }
 
 
 
 
 
 #####################################################################
 # Arbitrary User Methods
 
 sub users_home {
 	my $class = shift;
 	my $home  = $class->SUPER::users_home(@_);
 	return defined $home ? Cwd::abs_path($home) : undef;
 }
 
 # in theory this can be done, but for now, let's cheat, since the
 # rest is Hard
 sub users_desktop {
 	my ($class, $name) = @_;
 	return undef if $name eq 'root';
 	$class->_to_user( $class->my_desktop, $name );
 }
 
 sub users_documents {
 	my ($class, $name) = @_;
 	return undef if $name eq 'root';
 	$class->_to_user( $class->my_documents, $name );
 }
 
 sub users_data {
 	my ($class, $name) = @_;
 	$class->_to_user( $class->my_data, $name )
 	||
 	$class->users_home($name);
 }
 
 # cheap hack ... not entirely reliable, perhaps, but ... c'est la vie, since
 # there's really no other good way to do it at this time, that i know of -- pudge
 sub _to_user {
 	my ($class, $path, $name) = @_;
 	my $my_home    = $class->my_home;
 	my $users_home = $class->users_home($name);
 	defined $users_home or return undef;
 	$path =~ s/^\Q$my_home/$users_home/;
 	return $path;
 }
 
 1;
 
 =pod
 
 =head1 NAME
 
 File::HomeDir::Darwin - Find your home and other directories on Darwin (OS X)
 
 =head1 DESCRIPTION
 
 This module provides Darwin-specific implementations for determining
 common user directories.  In normal usage this module will always be
 used via L<File::HomeDir>.
 
 Note -- since this module requires Mac::Carbon and Mac::Carbon does
 not work with 64-bit perls, on such systems, File::HomeDir will try
 L<File::HomeDir::Darwin::Cocoa> and then fall back to the (pure Perl)
 L<File::HomeDir::Darwin>.
 
 =head1 SYNOPSIS
 
   use File::HomeDir;
 
   # Find directories for the current user
   $home    = File::HomeDir->my_home;      # /Users/mylogin
   $desktop = File::HomeDir->my_desktop;   # /Users/mylogin/Desktop
   $docs    = File::HomeDir->my_documents; # /Users/mylogin/Documents
   $music   = File::HomeDir->my_music;     # /Users/mylogin/Music
   $pics    = File::HomeDir->my_pictures;  # /Users/mylogin/Pictures
   $videos  = File::HomeDir->my_videos;    # /Users/mylogin/Movies
   $data    = File::HomeDir->my_data;      # /Users/mylogin/Library/Application Support
 
 =head1 TODO
 
 =over 4
 
 =item * Test with Mac OS (versions 7, 8, 9)
 
 =item * Some better way for users_* ?
 
 =back
### File/HomeDir/Darwin/Cocoa.pm ###
 package File::HomeDir::Darwin::Cocoa;
 
 use 5.00503;
 use strict;
 use Cwd                   ();
 use Carp                  ();
 use File::HomeDir::Darwin ();
 
 use vars qw{$VERSION @ISA};
 BEGIN {
 	$VERSION = '1.00';
 	@ISA     = 'File::HomeDir::Darwin';
 
 	# Load early if in a forking environment and we have
 	# prefork, or at run-time if not.
 	local $@;
 	eval "use prefork 'Mac::SystemDirectory'";
 }
 
 
 
 
 
 #####################################################################
 # Current User Methods
 
 sub my_home {
 	my $class = shift;
 
 	# A lot of unix people and unix-derived tools rely on
 	# the ability to overload HOME. We will support it too
 	# so that they can replace raw HOME calls with File::HomeDir.
 	if ( exists $ENV{HOME} and defined $ENV{HOME} ) {
 		return $ENV{HOME};
 	}
 
 	require Mac::SystemDirectory;
 	return Mac::SystemDirectory::HomeDirectory();
 }
 
 # from 10.4
 sub my_desktop {
 	my $class = shift;
 
 	require Mac::SystemDirectory;
 	eval {
 		$class->_find_folder(Mac::SystemDirectory::NSDesktopDirectory())
 	}
 	||
 	$class->SUPER::my_desktop;
 }
 
 # from 10.2
 sub my_documents {
 	my $class = shift;
 
 	require Mac::SystemDirectory;
 	eval {
 		$class->_find_folder(Mac::SystemDirectory::NSDocumentDirectory())
 	}
 	||
 	$class->SUPER::my_documents;
 }
 
 # from 10.4
 sub my_data {
 	my $class = shift;
 
 	require Mac::SystemDirectory;
 	eval {
 		$class->_find_folder(Mac::SystemDirectory::NSApplicationSupportDirectory())
 	}
 	||
 	$class->SUPER::my_data;
 }
 
 # from 10.6
 sub my_music {
 	my $class = shift;
 
 	require Mac::SystemDirectory;
 	eval {
 		$class->_find_folder(Mac::SystemDirectory::NSMusicDirectory())
 	}
 	||
 	$class->SUPER::my_music;
 }
 
 # from 10.6
 sub my_pictures {
 	my $class = shift;
 
 	require Mac::SystemDirectory;
 	eval {
 		$class->_find_folder(Mac::SystemDirectory::NSPicturesDirectory())
 	}
 	||
 	$class->SUPER::my_pictures;
 }
 
 # from 10.6
 sub my_videos {
 	my $class = shift;
 
 	require Mac::SystemDirectory;
 	eval {
 		$class->_find_folder(Mac::SystemDirectory::NSMoviesDirectory())
 	}
 	||
 	$class->SUPER::my_videos;
 }
 
 sub _find_folder {
 	my $class = shift;
 	my $name  = shift;
 
 	require Mac::SystemDirectory;
 	my $folder = Mac::SystemDirectory::FindDirectory($name);
 	return undef unless defined $folder;
 
 	unless ( -d $folder ) {
 		# Make sure that symlinks resolve to directories.
 		return undef unless -l $folder;
 		my $dir = readlink $folder or return;
 		return undef unless -d $dir;
 	}
 
 	return Cwd::abs_path($folder);
 }
 
 1;
 
 =pod
 
 =head1 NAME
 
 File::HomeDir::Darwin::Cocoa - Find your home and other directories on Darwin (OS X)
 
 =head1 DESCRIPTION
 
 This module provides Darwin-specific implementations for determining
 common user directories using Cocoa API through
 L<Mac::SystemDirectory>.  In normal usage this module will always be
 used via L<File::HomeDir>.
 
 Theoretically, this should return the same paths as both of the other
 Darwin drivers.
 
 Because this module requires L<Mac::SystemDirectory>, if the module
 is not installed, L<File::HomeDir> will fall back to L<File::HomeDir::Darwin>.
 
 =head1 SYNOPSIS
 
   use File::HomeDir;
   
   # Find directories for the current user
   $home    = File::HomeDir->my_home;      # /Users/mylogin
   $desktop = File::HomeDir->my_desktop;   # /Users/mylogin/Desktop
   $docs    = File::HomeDir->my_documents; # /Users/mylogin/Documents
   $music   = File::HomeDir->my_music;     # /Users/mylogin/Music
   $pics    = File::HomeDir->my_pictures;  # /Users/mylogin/Pictures
   $videos  = File::HomeDir->my_videos;    # /Users/mylogin/Movies
   $data    = File::HomeDir->my_data;      # /Users/mylogin/Library/Application Support
 
 =cut
### File/HomeDir/Driver.pm ###
 package File::HomeDir::Driver;
 
 # Abstract base class that provides no functionality,
 # but confirms the class is a File::HomeDir driver class.
 
 use 5.00503;
 use strict;
 use Carp ();
 
 use vars qw{$VERSION};
 BEGIN {
 	$VERSION = '1.00';
 }
 
 sub my_home {
 	Carp::croak("$_[0] does not implement compulsory method $_[1]");
 }
 
 1;
 
 =pod
 
 =head1 NAME
 
 File::HomeDir::Driver - Base class for all File::HomeDir drivers
 
 =head1 DESCRIPTION
 
 This module is the base class for all L<File::HomeDir> drivers, and must
 be inherited from to identify a class as a driver.
 
 It is primarily provided as a convenience for this specific identification
 purpose, as L<File::HomeDir> supports the specification of custom drivers
 and an C<-E<gt>isa> check is used during the loading of the driver.
 
 =head1 AUTHOR
 
 Adam Kennedy E<lt>adamk@cpan.orgE<gt>
 
 =head1 SEE ALSO
 
 L<File::HomeDir>
 
 =head1 COPYRIGHT
 
 Copyright 2009 - 2011 Adam Kennedy.
 
 This program is free software; you can redistribute
 it and/or modify it under the same terms as Perl itself.
 
 The full text of the license can be found in the
 LICENSE file included with this module.
 
 =cut
### File/HomeDir/FreeDesktop.pm ###
 package File::HomeDir::FreeDesktop;
 
 # Specific functionality for unixes running free desktops
 # compatible with (but not using) File-BaseDir-0.03
 
 # See POD at the end of the file for more documentation.
 
 use 5.00503;
 use strict;
 use Carp                ();
 use File::Spec          ();
 use File::Which         ();
 use File::HomeDir::Unix ();
 
 use vars qw{$VERSION @ISA};
 BEGIN {
 	$VERSION = '1.00';
 	@ISA     = 'File::HomeDir::Unix';
 }
 
 # xdg uses $ENV{XDG_CONFIG_HOME}/user-dirs.dirs to know where are the
 # various "my xxx" directories. That is a shell file. The official API
 # is the xdg-user-dir executable. It has no provision for assessing
 # the directories of a user that is different than the one we are
 # running under; the standard substitute user mechanisms are needed to
 # overcome this.
 
 my $xdgprog = File::Which::which('xdg-user-dir');
 
 sub _my {
 	# No quoting because input is hard-coded and only comes from this module
 	my $thingy = qx($xdgprog $_[1]);
 	chomp $thingy;
 	return $thingy;
 }
 
 # Simple stuff
 sub my_desktop   { shift->_my('DESKTOP')   }
 sub my_documents { shift->_my('DOCUMENTS') }
 sub my_music     { shift->_my('MUSIC')     }
 sub my_pictures  { shift->_my('PICTURES')  }
 sub my_videos    { shift->_my('VIDEOS')    }
 
 sub my_data {
 	$ENV{XDG_DATA_HOME}
 	or
 	File::Spec->catdir(
 		shift->my_home,
 		qw{ .local share }
 	);
 }
 
 sub my_config {
 	$ENV{XDG_CONFIG_HOME}
 	or
 	File::Spec->catdir(
 		shift->my_home,
 		qw{ .config }
 	);
 }
 
 # Custom locations (currently undocumented)
 sub my_download    { shift->_my('DOWNLOAD')    }
 sub my_publicshare { shift->_my('PUBLICSHARE') }
 sub my_templates   { shift->_my('TEMPLATES')   }
 
 sub my_cache {
     $ENV{XDG_CACHE_HOME}
     ||
     File::Spec->catdir(shift->my_home, qw{ .cache });
 }
 
 
 
 
 
 #####################################################################
 # General User Methods
 
 sub users_desktop   { Carp::croak('The users_desktop method is not available on an XDG based system.');   }
 sub users_documents { Carp::croak('The users_documents method is not available on an XDG based system.'); }
 sub users_music     { Carp::croak('The users_music method is not available on an XDG based system.');     }
 sub users_pictures  { Carp::croak('The users_pictures method is not available on an XDG based system.');  }
 sub users_videos    { Carp::croak('The users_videos method is not available on an XDG based system.');    }
 sub users_data      { Carp::croak('The users_data method is not available on an XDG based system.');      }
 
 1;
 
 =pod
 
 =head1 NAME
 
 File::HomeDir::FreeDesktop - Find your home and other directories on FreeDesktop.org Unix
 
 =head1 DESCRIPTION
 
 This module provides implementations for determining common user
 directories.  In normal usage this module will always be
 used via L<File::HomeDir>.
 
 =head1 SYNOPSIS
 
   use File::HomeDir;
   
   # Find directories for the current user
   $home    = File::HomeDir->my_home;        # /home/mylogin
   $desktop = File::HomeDir->my_desktop;
   $docs    = File::HomeDir->my_documents;
   $music   = File::HomeDir->my_music;
   $pics    = File::HomeDir->my_pictures;
   $videos  = File::HomeDir->my_videos;
   $data    = File::HomeDir->my_data;
 
 =head1 AUTHORS
 
 Jerome Quelin E<lt>jquellin@cpan.org<gt>
 
 Adam Kennedy E<lt>adamk@cpan.orgE<gt>
 
 =head1 SEE ALSO
 
 L<File::HomeDir>, L<File::HomeDir::Win32> (legacy)
 
 =head1 COPYRIGHT
 
 Copyright 2009 - 2011 Jerome Quelin.
 
 Some parts copyright 2010 Adam Kennedy.
 
 This program is free software; you can redistribute
 it and/or modify it under the same terms as Perl itself.
 
 The full text of the license can be found in the
 LICENSE file included with this module.
 
 =cut
### File/HomeDir/MacOS9.pm ###
 package File::HomeDir::MacOS9;
 
 # Half-assed implementation for the legacy Mac OS9 operating system.
 # Provided mainly to provide legacy compatibility. May be removed at
 # a later date.
 
 use 5.00503;
 use strict;
 use Carp                  ();
 use File::HomeDir::Driver ();
 
 use vars qw{$VERSION @ISA};
 BEGIN {
 	$VERSION = '1.00';
 	@ISA     = 'File::HomeDir::Driver';
 }
 
 # Load early if in a forking environment and we have
 # prefork, or at run-time if not.
 SCOPE: {
 	local $@;
 	eval "use prefork 'Mac::Files'";
 }
 
 
 
 
 
 #####################################################################
 # Current User Methods
 
 sub my_home {
 	my $class = shift;
 
 	# Try for $ENV{HOME} if we have it
 	if ( defined $ENV{HOME} ) {
 		return $ENV{HOME};
 	}
 
 	### DESPERATION SETS IN
 
 	# We could use the desktop
 	SCOPE: {
 		local $@;
 		eval {
 			my $home = $class->my_desktop;
 			return $home if $home and -d $home;
 		};
 	}
 
 	# Desperation on any platform
 	SCOPE: {
 		# On some platforms getpwuid dies if called at all
 		local $SIG{'__DIE__'} = '';
 		my $home = (getpwuid($<))[7];
 		return $home if $home and -d $home;
 	}
 
 	Carp::croak("Could not locate current user's home directory");
 }
 
 sub my_desktop {
 	my $class = shift;
 
 	# Find the desktop via Mac::Files
 	local $SIG{'__DIE__'} = '';
 	require Mac::Files;
 	my $home = Mac::Files::FindFolder(
 		Mac::Files::kOnSystemDisk(),
 		Mac::Files::kDesktopFolderType(),
 		);
 	return $home if $home and -d $home;
 
 	Carp::croak("Could not locate current user's desktop");
 }
 
 
 
 
 
 #####################################################################
 # General User Methods
 
 sub users_home {
 	my ($class, $name) = @_;
 
 	SCOPE: {
 		# On some platforms getpwnam dies if called at all
 		local $SIG{'__DIE__'} = '';
 		my $home = (getpwnam($name))[7];
 		return $home if defined $home and -d $home;
 	}
 
 	Carp::croak("Failed to find home directory for user '$name'");
 }
 
 1;
 
 =pod
 
 =head1 NAME
 
 File::HomeDir::MacOS9 - Find your home and other directories on legacy Macs
 
 =head1 SYNOPSIS
 
   use File::HomeDir;
   
   # Find directories for the current user
   $home    = File::HomeDir->my_home;
   $desktop = File::HomeDir->my_desktop;
 
 =head1 DESCRIPTION
 
 This module provides implementations for determining common user
 directories on legacy Mac hosts. In normal usage this module will always be
 used via L<File::HomeDir>.
 
 This module is no longer actively maintained, and is included only for
 extreme back-compatibility.
 
 Only the C<my_home> and C<my_desktop> methods are supported.
 
 =head1 SUPPORT
 
 See the support section the main L<File::HomeDir> module.
 
 =head1 AUTHORS
 
 Adam Kennedy E<lt>adamk@cpan.orgE<gt>
 
 Sean M. Burke E<lt>sburke@cpan.orgE<gt>
 
 =head1 SEE ALSO
 
 L<File::HomeDir>
 
 =head1 COPYRIGHT
 
 Copyright 2005 - 2011 Adam Kennedy.
 
 Some parts copyright 2000 Sean M. Burke.
 
 This program is free software; you can redistribute
 it and/or modify it under the same terms as Perl itself.
 
 The full text of the license can be found in the
 LICENSE file included with this module.
 
 =cut
### File/HomeDir/Test.pm ###
 package File::HomeDir::Test;
 
 use 5.00503;
 use strict;
 use Carp                  ();
 use File::Spec            ();
 use File::Temp            ();
 use File::HomeDir::Driver ();
 
 use vars qw{$VERSION @ISA %DIR $ENABLED};
 BEGIN {
 	$VERSION = '1.00';
 	@ISA     = 'File::HomeDir::Driver';
 	%DIR     = ();
 	$ENABLED = 0;
 }
 
 # Special magic use in test scripts
 sub import {
 	my $class = shift;
 	die "Attempted to initialise File::HomeDir::Test trice" if %DIR;
 
 	# Fill the test directories
 	my $BASE  = File::Temp::tempdir( CLEANUP => 1 );
 	%DIR = map { $_ => File::Spec->catdir( $BASE, $_ ) } qw{
 		my_home
 		my_desktop
 		my_documents
 		my_data
 		my_music
 		my_pictures
 		my_videos
 	};
 
 	# Hijack HOME to the home directory
 	$ENV{HOME} = $DIR{my_home};
 
 	# Make File::HomeDir load us instead of the native driver
 	$File::HomeDir::IMPLEMENTED_BY = # Prevent a warning
 	$File::HomeDir::IMPLEMENTED_BY = 'File::HomeDir::Test';
 
 	# Ready to go
 	$ENABLED = 1;
 }
 
 
 
 
 
 #####################################################################
 # Current User Methods
 
 sub my_home {
 	mkdir($DIR{my_home}, 0755) unless -d $DIR{my_home};
 	return $DIR{my_home};
 }
 
 sub my_desktop {
 	mkdir($DIR{my_desktop}, 0755) unless -d $DIR{my_desktop};
 	return $DIR{my_desktop};
 }
 
 sub my_documents {
 	mkdir($DIR{my_documents}, 0755) unless -f $DIR{my_documents};
 	return $DIR{my_documents};
 }
 
 sub my_data {
 	mkdir($DIR{my_data}, 0755) unless -d $DIR{my_data};
 	return $DIR{my_data};
 }
 
 sub my_music {
 	mkdir($DIR{my_music}, 0755) unless -d $DIR{my_music};
 	return $DIR{my_music};
 }
 
 sub my_pictures {
 	mkdir($DIR{my_pictures}, 0755) unless -d $DIR{my_pictures};
 	return $DIR{my_pictures};
 }
 
 sub my_videos {
 	mkdir($DIR{my_videos}, 0755) unless -d $DIR{my_videos};
 	return $DIR{my_videos};
 }
 
 sub users_home {
 	return undef;
 }
 
 1;
 
 __END__
 
 =pod
 
 =head1 NAME
 
 File::HomeDir::Test - Prevent the accidental creation of user-owned files during testing
 
 =head1 SYNOPSIS
 
   use Test::More test => 1;
   use File::HomeDir::Test;
   use File::HomeDir;
 
 =head1 DESCRIPTION
 
 B<File::HomeDir::Test> is a L<File::HomeDir> driver intended for use in the test scripts
 of modules or applications that write files into user-owned directories.
 
 It is designed to prevent the pollution of user directories with files that are not part
 of the application install itself, but were created during testing. These files can leak
 state information from the tests into the run-time usage of an application, and on Unix
 systems also prevents tests (which may be executed as root via sudo) from writing files
 which cannot later be modified or removed by the regular user.
 
 =head1 SUPPORT
 
 See the support section of the main L<File::HomeDir> documentation.
 
 =head1 AUTHOR
 
 Adam Kennedy E<lt>adamk@cpan.orgE<gt>
 
 =head1 COPYRIGHT
 
 Copyright 2005 - 2011 Adam Kennedy.
 
 This program is free software; you can redistribute
 it and/or modify it under the same terms as Perl itself.
 
 The full text of the license can be found in the
 LICENSE file included with this module.
 
 =cut
### File/HomeDir/Unix.pm ###
 package File::HomeDir::Unix;
 
 # See POD at the end of the file for documentation
 
 use 5.00503;
 use strict;
 use Carp                  ();
 use File::HomeDir::Driver ();
 
 use vars qw{$VERSION @ISA};
 BEGIN {
 	$VERSION = '1.00';
 	@ISA     = 'File::HomeDir::Driver';
 }
 
 
 
 
 
 #####################################################################
 # Current User Methods
 
 sub my_home {
 	my $class = shift;
 	my $home  = $class->_my_home(@_);
 
 	# On Unix in general, a non-existant home means "no home"
 	# For example, "nobody"-like users might use /nonexistant
 	if ( defined $home and ! -d $home ) {
 		$home = undef;
 	}
 
 	return $home;
 }
 
 sub _my_home {
 	my $class = shift;
 	if ( exists $ENV{HOME} and defined $ENV{HOME} ) {
 		return $ENV{HOME};
 	}
 
 	# This is from the original code, but I'm guessing
 	# it means "login directory" and exists on some Unixes.
 	if ( exists $ENV{LOGDIR} and $ENV{LOGDIR} ) {
 		return $ENV{LOGDIR};
 	}
 
 	### More-desperate methods
 
 	# Light desperation on any (Unixish) platform
 	SCOPE: {
 		my $home = (getpwuid($<))[7];
 		return $home if $home and -d $home;
 	}
 
 	return undef;
 }
 
 # On unix by default, everything is under the same folder
 sub my_desktop {
 	shift->my_home;
 }
 
 sub my_documents {
 	shift->my_home;
 }
 
 sub my_data {
 	shift->my_home;
 }
 
 sub my_music {
 	shift->my_home;
 }
 
 sub my_pictures {
 	shift->my_home;
 }
 
 sub my_videos {
 	shift->my_home;
 }
 
 
 
 
 
 #####################################################################
 # General User Methods
 
 sub users_home {
 	my ($class, $name) = @_;
 
 	# IF and only if we have getpwuid support, and the
 	# name of the user is our own, shortcut to my_home.
 	# This is needed to handle HOME environment settings.
 	if ( $name eq getpwuid($<) ) {
 		return $class->my_home;
 	}
 
 	SCOPE: {
 		my $home = (getpwnam($name))[7];
 		return $home if $home and -d $home;
 	}
 
 	return undef;
 }
 
 sub users_desktop {
 	shift->users_home(@_);
 }
 
 sub users_documents {
 	shift->users_home(@_);
 }
 
 sub users_data {
 	shift->users_home(@_);
 }
 
 sub users_music {
 	shift->users_home(@_);
 }
 
 sub users_pictures {
 	shift->users_home(@_);
 }
 
 sub users_videos {
 	shift->users_home(@_);
 }
 
 1;
 
 =pod
 
 =head1 NAME
 
 File::HomeDir::Unix - Find your home and other directories on legacy Unix
 
 =head1 SYNOPSIS
 
   use File::HomeDir;
   
   # Find directories for the current user
   $home    = File::HomeDir->my_home;        # /home/mylogin
   $desktop = File::HomeDir->my_desktop;     # All of these will... 
   $docs    = File::HomeDir->my_documents;   # ...default to home...
   $music   = File::HomeDir->my_music;       # ...directory
   $pics    = File::HomeDir->my_pictures;    #
   $videos  = File::HomeDir->my_videos;      #
   $data    = File::HomeDir->my_data;        # 
 
 =head1 DESCRIPTION
 
 This module provides implementations for determining common user
 directories.  In normal usage this module will always be
 used via L<File::HomeDir>.
 
 =head1 SUPPORT
 
 See the support section the main L<File::HomeDir> module.
 
 =head1 AUTHORS
 
 Adam Kennedy E<lt>adamk@cpan.orgE<gt>
 
 Sean M. Burke E<lt>sburke@cpan.orgE<gt>
 
 =head1 SEE ALSO
 
 L<File::HomeDir>, L<File::HomeDir::Win32> (legacy)
 
 =head1 COPYRIGHT
 
 Copyright 2005 - 2011 Adam Kennedy.
 
 Some parts copyright 2000 Sean M. Burke.
 
 This program is free software; you can redistribute
 it and/or modify it under the same terms as Perl itself.
 
 The full text of the license can be found in the
 LICENSE file included with this module.
 
 =cut
### File/HomeDir/Windows.pm ###
 package File::HomeDir::Windows;
 
 # See POD at the end of the file for documentation
 
 use 5.00503;
 use strict;
 use Carp                  ();
 use File::Spec            ();
 use File::HomeDir::Driver ();
 
 use vars qw{$VERSION @ISA};
 BEGIN {
 	$VERSION = '1.00';
 	@ISA     = 'File::HomeDir::Driver';
 }
 
 sub CREATE () { 1 }
 
 
 
 
 
 #####################################################################
 # Current User Methods
 
 sub my_home {
 	my $class = shift;
 
 	# A lot of unix people and unix-derived tools rely on
 	# the ability to overload HOME. We will support it too
 	# so that they can replace raw HOME calls with File::HomeDir.
 	if ( exists $ENV{HOME} and $ENV{HOME} ) {
 		return $ENV{HOME};
 	}
 
 	# Do we have a user profile?
 	if ( exists $ENV{USERPROFILE} and $ENV{USERPROFILE} ) {
 		return $ENV{USERPROFILE};
 	}
 
 	# Some Windows use something like $ENV{HOME}
 	if ( exists $ENV{HOMEDRIVE} and exists $ENV{HOMEPATH} and $ENV{HOMEDRIVE} and $ENV{HOMEPATH} ) {
 		return File::Spec->catpath(
 			$ENV{HOMEDRIVE}, $ENV{HOMEPATH}, '',
 		);
 	}
 
 	return undef;
 }
 
 sub my_desktop {
 	my $class = shift;
 
 	# The most correct way to find the desktop
 	SCOPE: {
 		require Win32;
 		my $dir = Win32::GetFolderPath(Win32::CSIDL_DESKTOP(), CREATE);
 		return $dir if $dir and $class->_d($dir);
 	}
 
 	# MSWindows sets WINDIR, MS WinNT sets USERPROFILE.
 	foreach my $e ( 'USERPROFILE', 'WINDIR' ) {
 		next unless $ENV{$e};
 		my $desktop = File::Spec->catdir($ENV{$e}, 'Desktop');
 		return $desktop if $desktop and $class->_d($desktop);
 	}
 
 	# As a last resort, try some hard-wired values
 	foreach my $fixed (
 		# The reason there are both types of slash here is because
 		# this set of paths has been kept from thethe original version
 		# of File::HomeDir::Win32 (before it was rewritten).
 		# I can only assume this is Cygwin-related stuff.
 		"C:\\windows\\desktop",
 		"C:\\win95\\desktop",
 		"C:/win95/desktop",
 		"C:/windows/desktop",
 	) {
 		return $fixed if $class->_d($fixed);
 	}
 
 	return undef;
 }
 
 sub my_documents {
 	my $class = shift;
 
 	# The most correct way to find my documents
 	SCOPE: {
 		require Win32;
 		my $dir = Win32::GetFolderPath(Win32::CSIDL_PERSONAL(), CREATE);
 		return $dir if $dir and $class->_d($dir);
 	}
 
 	return undef;
 }
 
 sub my_data {
 	my $class = shift;
 
 	# The most correct way to find my documents
 	SCOPE: {
 		require Win32;
 		my $dir = Win32::GetFolderPath(Win32::CSIDL_LOCAL_APPDATA(), CREATE);
 		return $dir if $dir and $class->_d($dir);
 	}
 
 	return undef;
 }
 
 sub my_music {
 	my $class = shift;
 
 	# The most correct way to find my music
 	SCOPE: {
 		require Win32;
 		my $dir = Win32::GetFolderPath(Win32::CSIDL_MYMUSIC(), CREATE);
 		return $dir if $dir and $class->_d($dir);
 	}
 
 	return undef;
 }
 
 sub my_pictures {
 	my $class = shift;
 
 	# The most correct way to find my pictures
 	SCOPE: {
 		require Win32;
 		my $dir = Win32::GetFolderPath(Win32::CSIDL_MYPICTURES(), CREATE);
 		return $dir if $dir and $class->_d($dir);
 	}
 
 	return undef;
 }
 
 sub my_videos {
 	my $class = shift;
 
 	# The most correct way to find my videos
 	SCOPE: {
 		require Win32;
 		my $dir = Win32::GetFolderPath(Win32::CSIDL_MYVIDEO(), CREATE);
 		return $dir if $dir and $class->_d($dir);
 	}
 
 	return undef;
 }
 
 # Special case version of -d
 sub _d {
 	my $self = shift;
 	my $path = shift;
 
 	# Window can legally return a UNC path from GetFolderPath.
 	# Not only is the meaning of -d complicated in this situation,
 	# but even on a local network calling -d "\\\\cifs\\path" can
 	# take several seconds. UNC can also do even weirder things,
 	# like launching processes and such.
 	# To avoid various crazy bugs caused by this, we do NOT attempt
 	# to validate UNC paths at all so that the code that is calling
 	# us has an opportunity to take special actions without our 
 	# blundering getting in the way.
 	if ( $path =~ /\\\\/ ) {
 		return 1;
 	}
 
 	# Otherwise do a stat as normal
 	return -d $path;
 }
 
 1;
 
 =pod
 
 =head1 NAME
 
 File::HomeDir::Windows - Find your home and other directories on Windows
 
 =head1 SYNOPSIS
 
   use File::HomeDir;
   
   # Find directories for the current user (eg. using Windows XP Professional)
   $home    = File::HomeDir->my_home;        # C:\Documents and Settings\mylogin
   $desktop = File::HomeDir->my_desktop;     # C:\Documents and Settings\mylogin\Desktop
   $docs    = File::HomeDir->my_documents;   # C:\Documents and Settings\mylogin\My Documents
   $music   = File::HomeDir->my_music;       # C:\Documents and Settings\mylogin\My Documents\My Music
   $pics    = File::HomeDir->my_pictures;    # C:\Documents and Settings\mylogin\My Documents\My Pictures
   $videos  = File::HomeDir->my_videos;      # C:\Documents and Settings\mylogin\My Documents\My Video
   $data    = File::HomeDir->my_data;        # C:\Documents and Settings\mylogin\Local Settings\Application Data
 
 =head1 DESCRIPTION
 
 This module provides Windows-specific implementations for determining
 common user directories.  In normal usage this module will always be
 used via L<File::HomeDir>.
 
 Internally this module will use L<Win32>::GetFolderPath to fetch the location
 of your directories. As a result of this, in certain unusual situations
 (usually found inside large organisations) the methods may return UNC paths
 such as C<\\cifs.local\home$>.
 
 If your application runs on Windows and you want to have it work comprehensively
 everywhere, you may need to implement your own handling for these paths as they
 can cause strange behaviour.
 
 For example, stat calls to UNC paths may work but block for several seconds, but
 opendir() may not be able to read any files (creating the appearance of an existing
 but empty directory).
 
 To avoid complicating the problem any further, in the rare situation that a UNC path
 is returned by C<GetFolderPath> the usual -d validation checks will B<not> be done.
 
 =head1 SUPPORT
 
 See the support section the main L<File::HomeDir> module.
 
 =head1 AUTHORS
 
 Adam Kennedy E<lt>adamk@cpan.orgE<gt>
 
 Sean M. Burke E<lt>sburke@cpan.orgE<gt>
 
 =head1 SEE ALSO
 
 L<File::HomeDir>, L<File::HomeDir::Win32> (legacy)
 
 =head1 COPYRIGHT
 
 Copyright 2005 - 2011 Adam Kennedy.
 
 Some parts copyright 2000 Sean M. Burke.
 
 This program is free software; you can redistribute
 it and/or modify it under the same terms as Perl itself.
 
 The full text of the license can be found in the
 LICENSE file included with this module.
 
 =cut
### File/Path.pm ###
 package File::Path;
 
 use 5.005_04;
 use strict;
 
 use Cwd 'getcwd';
 use File::Basename ();
 use File::Spec     ();
 
 BEGIN {
     if ($] < 5.006) {
         # can't say 'opendir my $dh, $dirname'
         # need to initialise $dh
         eval "use Symbol";
     }
 }
 
 use Exporter ();
 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK);
 $VERSION   = '2.09';
 @ISA       = qw(Exporter);
 @EXPORT    = qw(mkpath rmtree);
 @EXPORT_OK = qw(make_path remove_tree);
 
 my $Is_VMS     = $^O eq 'VMS';
 my $Is_MacOS   = $^O eq 'MacOS';
 
 # These OSes complain if you want to remove a file that you have no
 # write permission to:
 my $Force_Writeable = grep {$^O eq $_} qw(amigaos dos epoc MSWin32 MacOS os2);
 
 # Unix-like systems need to stat each directory in order to detect
 # race condition. MS-Windows is immune to this particular attack.
 my $Need_Stat_Check = !($^O eq 'MSWin32');
 
 sub _carp {
     require Carp;
     goto &Carp::carp;
 }
 
 sub _croak {
     require Carp;
     goto &Carp::croak;
 }
 
 sub _error {
     my $arg     = shift;
     my $message = shift;
     my $object  = shift;
 
     if ($arg->{error}) {
         $object = '' unless defined $object;
         $message .= ": $!" if $!;
         push @{${$arg->{error}}}, {$object => $message};
     }
     else {
         _carp(defined($object) ? "$message for $object: $!" : "$message: $!");
     }
 }
 
 sub make_path {
     push @_, {} unless @_ and UNIVERSAL::isa($_[-1],'HASH');
     goto &mkpath;
 }
 
 sub mkpath {
     my $old_style = !(@_ and UNIVERSAL::isa($_[-1],'HASH'));
 
     my $arg;
     my $paths;
 
     if ($old_style) {
         my ($verbose, $mode);
         ($paths, $verbose, $mode) = @_;
         $paths = [$paths] unless UNIVERSAL::isa($paths,'ARRAY');
         $arg->{verbose} = $verbose;
         $arg->{mode}    = defined $mode ? $mode : 0777;
     }
     else {
         $arg = pop @_;
         $arg->{mode}      = delete $arg->{mask} if exists $arg->{mask};
         $arg->{mode}      = 0777 unless exists $arg->{mode};
         ${$arg->{error}}  = [] if exists $arg->{error};
         $arg->{owner}     = delete $arg->{user} if exists $arg->{user};
         $arg->{owner}     = delete $arg->{uid}  if exists $arg->{uid};
         if (exists $arg->{owner} and $arg->{owner} =~ /\D/) {
             my $uid = (getpwnam $arg->{owner})[2];
             if (defined $uid) {
                 $arg->{owner} = $uid;
             }
             else {
                 _error($arg, "unable to map $arg->{owner} to a uid, ownership not changed");
                 delete $arg->{owner};
             }
         }
         if (exists $arg->{group} and $arg->{group} =~ /\D/) {
             my $gid = (getgrnam $arg->{group})[2];
             if (defined $gid) {
                 $arg->{group} = $gid;
             }
             else {
                 _error($arg, "unable to map $arg->{group} to a gid, group ownership not changed");
                 delete $arg->{group};
             }
         }
         if (exists $arg->{owner} and not exists $arg->{group}) {
             $arg->{group} = -1; # chown will leave group unchanged
         }
         if (exists $arg->{group} and not exists $arg->{owner}) {
             $arg->{owner} = -1; # chown will leave owner unchanged
         }
         $paths = [@_];
     }
     return _mkpath($arg, $paths);
 }
 
 sub _mkpath {
     my $arg   = shift;
     my $paths = shift;
 
     my(@created,$path);
     foreach $path (@$paths) {
         next unless defined($path) and length($path);
         $path .= '/' if $^O eq 'os2' and $path =~ /^\w:\z/s; # feature of CRT 
         # Logic wants Unix paths, so go with the flow.
         if ($Is_VMS) {
             next if $path eq '/';
             $path = VMS::Filespec::unixify($path);
         }
         next if -d $path;
         my $parent = File::Basename::dirname($path);
         unless (-d $parent or $path eq $parent) {
             push(@created,_mkpath($arg, [$parent]));
         }
         print "mkdir $path\n" if $arg->{verbose};
         if (mkdir($path,$arg->{mode})) {
             push(@created, $path);
             if (exists $arg->{owner}) {
 				# NB: $arg->{group} guaranteed to be set during initialisation
                 if (!chown $arg->{owner}, $arg->{group}, $path) {
                     _error($arg, "Cannot change ownership of $path to $arg->{owner}:$arg->{group}");
                 }
             }
         }
         else {
             my $save_bang = $!;
             my ($e, $e1) = ($save_bang, $^E);
             $e .= "; $e1" if $e ne $e1;
             # allow for another process to have created it meanwhile
             if (!-d $path) {
                 $! = $save_bang;
                 if ($arg->{error}) {
                     push @{${$arg->{error}}}, {$path => $e};
                 }
                 else {
                     _croak("mkdir $path: $e");
                 }
             }
         }
     }
     return @created;
 }
 
 sub remove_tree {
     push @_, {} unless @_ and UNIVERSAL::isa($_[-1],'HASH');
     goto &rmtree;
 }
 
 sub _is_subdir {
     my($dir, $test) = @_;
 
     my($dv, $dd) = File::Spec->splitpath($dir, 1);
     my($tv, $td) = File::Spec->splitpath($test, 1);
 
     # not on same volume
     return 0 if $dv ne $tv;
 
     my @d = File::Spec->splitdir($dd);
     my @t = File::Spec->splitdir($td);
 
     # @t can't be a subdir if it's shorter than @d
     return 0 if @t < @d;
 
     return join('/', @d) eq join('/', splice @t, 0, +@d);
 }
 
 sub rmtree {
     my $old_style = !(@_ and UNIVERSAL::isa($_[-1],'HASH'));
 
     my $arg;
     my $paths;
 
     if ($old_style) {
         my ($verbose, $safe);
         ($paths, $verbose, $safe) = @_;
         $arg->{verbose} = $verbose;
         $arg->{safe}    = defined $safe    ? $safe    : 0;
 
         if (defined($paths) and length($paths)) {
             $paths = [$paths] unless UNIVERSAL::isa($paths,'ARRAY');
         }
         else {
             _carp ("No root path(s) specified\n");
             return 0;
         }
     }
     else {
         $arg = pop @_;
         ${$arg->{error}}  = [] if exists $arg->{error};
         ${$arg->{result}} = [] if exists $arg->{result};
         $paths = [@_];
     }
 
     $arg->{prefix} = '';
     $arg->{depth}  = 0;
 
     my @clean_path;
     $arg->{cwd} = getcwd() or do {
         _error($arg, "cannot fetch initial working directory");
         return 0;
     };
     for ($arg->{cwd}) { /\A(.*)\Z/; $_ = $1 } # untaint
 
     for my $p (@$paths) {
         # need to fixup case and map \ to / on Windows
         my $ortho_root = $^O eq 'MSWin32' ? _slash_lc($p)          : $p;
         my $ortho_cwd  = $^O eq 'MSWin32' ? _slash_lc($arg->{cwd}) : $arg->{cwd};
         my $ortho_root_length = length($ortho_root);
         $ortho_root_length-- if $^O eq 'VMS'; # don't compare '.' with ']'
         if ($ortho_root_length && _is_subdir($ortho_root, $ortho_cwd)) {
             local $! = 0;
             _error($arg, "cannot remove path when cwd is $arg->{cwd}", $p);
             next;
         }
 
         if ($Is_MacOS) {
             $p  = ":$p" unless $p =~ /:/;
             $p .= ":"   unless $p =~ /:\z/;
         }
         elsif ($^O eq 'MSWin32') {
             $p =~ s{[/\\]\z}{};
         }
         else {
             $p =~ s{/\z}{};
         }
         push @clean_path, $p;
     }
 
     @{$arg}{qw(device inode perm)} = (lstat $arg->{cwd})[0,1] or do {
         _error($arg, "cannot stat initial working directory", $arg->{cwd});
         return 0;
     };
 
     return _rmtree($arg, \@clean_path);
 }
 
 sub _rmtree {
     my $arg   = shift;
     my $paths = shift;
 
     my $count  = 0;
     my $curdir = File::Spec->curdir();
     my $updir  = File::Spec->updir();
 
     my (@files, $root);
     ROOT_DIR:
     foreach $root (@$paths) {
         # since we chdir into each directory, it may not be obvious
         # to figure out where we are if we generate a message about
         # a file name. We therefore construct a semi-canonical
         # filename, anchored from the directory being unlinked (as
         # opposed to being truly canonical, anchored from the root (/).
 
         my $canon = $arg->{prefix}
             ? File::Spec->catfile($arg->{prefix}, $root)
             : $root
         ;
 
         my ($ldev, $lino, $perm) = (lstat $root)[0,1,2] or next ROOT_DIR;
 
         if ( -d _ ) {
             $root = VMS::Filespec::vmspath(VMS::Filespec::pathify($root)) if $Is_VMS;
 
             if (!chdir($root)) {
                 # see if we can escalate privileges to get in
                 # (e.g. funny protection mask such as -w- instead of rwx)
                 $perm &= 07777;
                 my $nperm = $perm | 0700;
                 if (!($arg->{safe} or $nperm == $perm or chmod($nperm, $root))) {
                     _error($arg, "cannot make child directory read-write-exec", $canon);
                     next ROOT_DIR;
                 }
                 elsif (!chdir($root)) {
                     _error($arg, "cannot chdir to child", $canon);
                     next ROOT_DIR;
                 }
             }
 
             my ($cur_dev, $cur_inode, $perm) = (stat $curdir)[0,1,2] or do {
                 _error($arg, "cannot stat current working directory", $canon);
                 next ROOT_DIR;
             };
 
             if ($Need_Stat_Check) {
                 ($ldev eq $cur_dev and $lino eq $cur_inode)
                     or _croak("directory $canon changed before chdir, expected dev=$ldev ino=$lino, actual dev=$cur_dev ino=$cur_inode, aborting.");
             }
 
             $perm &= 07777; # don't forget setuid, setgid, sticky bits
             my $nperm = $perm | 0700;
 
             # notabene: 0700 is for making readable in the first place,
             # it's also intended to change it to writable in case we have
             # to recurse in which case we are better than rm -rf for 
             # subtrees with strange permissions
 
             if (!($arg->{safe} or $nperm == $perm or chmod($nperm, $curdir))) {
                 _error($arg, "cannot make directory read+writeable", $canon);
                 $nperm = $perm;
             }
 
             my $d;
             $d = gensym() if $] < 5.006;
             if (!opendir $d, $curdir) {
                 _error($arg, "cannot opendir", $canon);
                 @files = ();
             }
             else {
                 no strict 'refs';
                 if (!defined ${"\cTAINT"} or ${"\cTAINT"}) {
                     # Blindly untaint dir names if taint mode is
                     # active, or any perl < 5.006
                     @files = map { /\A(.*)\z/s; $1 } readdir $d;
                 }
                 else {
                     @files = readdir $d;
                 }
                 closedir $d;
             }
 
             if ($Is_VMS) {
                 # Deleting large numbers of files from VMS Files-11
                 # filesystems is faster if done in reverse ASCIIbetical order.
                 # include '.' to '.;' from blead patch #31775
                 @files = map {$_ eq '.' ? '.;' : $_} reverse @files;
             }
 
             @files = grep {$_ ne $updir and $_ ne $curdir} @files;
 
             if (@files) {
                 # remove the contained files before the directory itself
                 my $narg = {%$arg};
                 @{$narg}{qw(device inode cwd prefix depth)}
                     = ($cur_dev, $cur_inode, $updir, $canon, $arg->{depth}+1);
                 $count += _rmtree($narg, \@files);
             }
 
             # restore directory permissions of required now (in case the rmdir
             # below fails), while we are still in the directory and may do so
             # without a race via '.'
             if ($nperm != $perm and not chmod($perm, $curdir)) {
                 _error($arg, "cannot reset chmod", $canon);
             }
 
             # don't leave the client code in an unexpected directory
             chdir($arg->{cwd})
                 or _croak("cannot chdir to $arg->{cwd} from $canon: $!, aborting.");
 
             # ensure that a chdir upwards didn't take us somewhere other
             # than we expected (see CVE-2002-0435)
             ($cur_dev, $cur_inode) = (stat $curdir)[0,1]
                 or _croak("cannot stat prior working directory $arg->{cwd}: $!, aborting.");
 
             if ($Need_Stat_Check) {
                 ($arg->{device} eq $cur_dev and $arg->{inode} eq $cur_inode)
                     or _croak("previous directory $arg->{cwd} changed before entering $canon, expected dev=$ldev ino=$lino, actual dev=$cur_dev ino=$cur_inode, aborting.");
             }
 
             if ($arg->{depth} or !$arg->{keep_root}) {
                 if ($arg->{safe} &&
                     ($Is_VMS ? !&VMS::Filespec::candelete($root) : !-w $root)) {
                     print "skipped $root\n" if $arg->{verbose};
                     next ROOT_DIR;
                 }
                 if ($Force_Writeable and !chmod $perm | 0700, $root) {
                     _error($arg, "cannot make directory writeable", $canon);
                 }
                 print "rmdir $root\n" if $arg->{verbose};
                 if (rmdir $root) {
                     push @{${$arg->{result}}}, $root if $arg->{result};
                     ++$count;
                 }
                 else {
                     _error($arg, "cannot remove directory", $canon);
                     if ($Force_Writeable && !chmod($perm, ($Is_VMS ? VMS::Filespec::fileify($root) : $root))
                     ) {
                         _error($arg, sprintf("cannot restore permissions to 0%o",$perm), $canon);
                     }
                 }
             }
         }
         else {
             # not a directory
             $root = VMS::Filespec::vmsify("./$root")
                 if $Is_VMS
                    && !File::Spec->file_name_is_absolute($root)
                    && ($root !~ m/(?<!\^)[\]>]+/);  # not already in VMS syntax
 
             if ($arg->{safe} &&
                 ($Is_VMS ? !&VMS::Filespec::candelete($root)
                          : !(-l $root || -w $root)))
             {
                 print "skipped $root\n" if $arg->{verbose};
                 next ROOT_DIR;
             }
 
             my $nperm = $perm & 07777 | 0600;
             if ($Force_Writeable and $nperm != $perm and not chmod $nperm, $root) {
                 _error($arg, "cannot make file writeable", $canon);
             }
             print "unlink $canon\n" if $arg->{verbose};
             # delete all versions under VMS
             for (;;) {
                 if (unlink $root) {
                     push @{${$arg->{result}}}, $root if $arg->{result};
                 }
                 else {
                     _error($arg, "cannot unlink file", $canon);
                     $Force_Writeable and chmod($perm, $root) or
                         _error($arg, sprintf("cannot restore permissions to 0%o",$perm), $canon);
                     last;
                 }
                 ++$count;
                 last unless $Is_VMS && lstat $root;
             }
         }
     }
     return $count;
 }
 
 sub _slash_lc {
     # fix up slashes and case on MSWin32 so that we can determine that
     # c:\path\to\dir is underneath C:/Path/To
     my $path = shift;
     $path =~ tr{\\}{/};
     return lc($path);
 }
 
 1;
 __END__
 
 =head1 NAME
 
 File::Path - Create or remove directory trees
 
 =head1 VERSION
 
 This document describes version 2.09 of File::Path, released
 2013-01-17.
 
 =head1 SYNOPSIS
 
   use File::Path qw(make_path remove_tree);
 
   make_path('foo/bar/baz', '/zug/zwang');
   make_path('foo/bar/baz', '/zug/zwang', {
       verbose => 1,
       mode => 0711,
   });
 
   remove_tree('foo/bar/baz', '/zug/zwang');
   remove_tree('foo/bar/baz', '/zug/zwang', {
       verbose => 1,
       error  => \my $err_list,
   });
 
   # legacy (interface promoted before v2.00)
   mkpath('/foo/bar/baz');
   mkpath('/foo/bar/baz', 1, 0711);
   mkpath(['/foo/bar/baz', 'blurfl/quux'], 1, 0711);
   rmtree('foo/bar/baz', 1, 1);
   rmtree(['foo/bar/baz', 'blurfl/quux'], 1, 1);
 
   # legacy (interface promoted before v2.06)
   mkpath('foo/bar/baz', '/zug/zwang', { verbose => 1, mode => 0711 });
   rmtree('foo/bar/baz', '/zug/zwang', { verbose => 1, mode => 0711 });
 
 =head1 DESCRIPTION
 
 This module provide a convenient way to create directories of
 arbitrary depth and to delete an entire directory subtree from the
 filesystem.
 
 The following functions are provided:
 
 =over
 
 =item make_path( $dir1, $dir2, .... )
 
 =item make_path( $dir1, $dir2, ...., \%opts )
 
 The C<make_path> function creates the given directories if they don't
 exists before, much like the Unix command C<mkdir -p>.
 
 The function accepts a list of directories to be created. Its
 behaviour may be tuned by an optional hashref appearing as the last
 parameter on the call.
 
 The function returns the list of directories actually created during
 the call; in scalar context the number of directories created.
 
 The following keys are recognised in the option hash:
 
 =over
 
 =item mode => $num
 
 The numeric permissions mode to apply to each created directory
 (defaults to 0777), to be modified by the current C<umask>. If the
 directory already exists (and thus does not need to be created),
 the permissions will not be modified.
 
 C<mask> is recognised as an alias for this parameter.
 
 =item verbose => $bool
 
 If present, will cause C<make_path> to print the name of each directory
 as it is created. By default nothing is printed.
 
 =item error => \$err
 
 If present, it should be a reference to a scalar.
 This scalar will be made to reference an array, which will
 be used to store any errors that are encountered.  See the L</"ERROR
 HANDLING"> section for more information.
 
 If this parameter is not used, certain error conditions may raise
 a fatal error that will cause the program will halt, unless trapped
 in an C<eval> block.
 
 =item owner => $owner
 
 =item user => $owner
 
 =item uid => $owner
 
 If present, will cause any created directory to be owned by C<$owner>.
 If the value is numeric, it will be interpreted as a uid, otherwise
 as username is assumed. An error will be issued if the username cannot be
 mapped to a uid, or the uid does not exist, or the process lacks the
 privileges to change ownership.
 
 Ownwership of directories that already exist will not be changed.
 
 C<user> and C<uid> are aliases of C<owner>.
 
 =item group => $group
 
 If present, will cause any created directory to be owned by the group C<$group>.
 If the value is numeric, it will be interpreted as a gid, otherwise
 as group name is assumed. An error will be issued if the group name cannot be
 mapped to a gid, or the gid does not exist, or the process lacks the
 privileges to change group ownership.
 
 Group ownwership of directories that already exist will not be changed.
 
     make_path '/var/tmp/webcache', {owner=>'nobody', group=>'nogroup'};
 
 =back
 
 =item mkpath( $dir )
 
 =item mkpath( $dir, $verbose, $mode )
 
 =item mkpath( [$dir1, $dir2,...], $verbose, $mode )
 
 =item mkpath( $dir1, $dir2,..., \%opt )
 
 The mkpath() function provide the legacy interface of make_path() with
 a different interpretation of the arguments passed.  The behaviour and
 return value of the function is otherwise identical to make_path().
 
 =item remove_tree( $dir1, $dir2, .... )
 
 =item remove_tree( $dir1, $dir2, ...., \%opts )
 
 The C<remove_tree> function deletes the given directories and any
 files and subdirectories they might contain, much like the Unix
 command C<rm -r> or C<del /s> on Windows.
 
 The function accepts a list of directories to be
 removed. Its behaviour may be tuned by an optional hashref
 appearing as the last parameter on the call.
 
 The functions returns the number of files successfully deleted.
 
 The following keys are recognised in the option hash:
 
 =over
 
 =item verbose => $bool
 
 If present, will cause C<remove_tree> to print the name of each file as
 it is unlinked. By default nothing is printed.
 
 =item safe => $bool
 
 When set to a true value, will cause C<remove_tree> to skip the files
 for which the process lacks the required privileges needed to delete
 files, such as delete privileges on VMS. In other words, the code
 will make no attempt to alter file permissions. Thus, if the process
 is interrupted, no filesystem object will be left in a more
 permissive mode.
 
 =item keep_root => $bool
 
 When set to a true value, will cause all files and subdirectories
 to be removed, except the initially specified directories. This comes
 in handy when cleaning out an application's scratch directory.
 
   remove_tree( '/tmp', {keep_root => 1} );
 
 =item result => \$res
 
 If present, it should be a reference to a scalar.
 This scalar will be made to reference an array, which will
 be used to store all files and directories unlinked
 during the call. If nothing is unlinked, the array will be empty.
 
   remove_tree( '/tmp', {result => \my $list} );
   print "unlinked $_\n" for @$list;
 
 This is a useful alternative to the C<verbose> key.
 
 =item error => \$err
 
 If present, it should be a reference to a scalar.
 This scalar will be made to reference an array, which will
 be used to store any errors that are encountered.  See the L</"ERROR
 HANDLING"> section for more information.
 
 Removing things is a much more dangerous proposition than
 creating things. As such, there are certain conditions that
 C<remove_tree> may encounter that are so dangerous that the only
 sane action left is to kill the program.
 
 Use C<error> to trap all that is reasonable (problems with
 permissions and the like), and let it die if things get out
 of hand. This is the safest course of action.
 
 =back
 
 =item rmtree( $dir )
 
 =item rmtree( $dir, $verbose, $safe )
 
 =item rmtree( [$dir1, $dir2,...], $verbose, $safe )
 
 =item rmtree( $dir1, $dir2,..., \%opt )
 
 The rmtree() function provide the legacy interface of remove_tree()
 with a different interpretation of the arguments passed. The behaviour
 and return value of the function is otherwise identical to
 remove_tree().
 
 =back
 
 =head2 ERROR HANDLING
 
 =over 4
 
 =item B<NOTE:>
 
 The following error handling mechanism is considered
 experimental and is subject to change pending feedback from
 users.
 
 =back
 
 If C<make_path> or C<remove_tree> encounter an error, a diagnostic
 message will be printed to C<STDERR> via C<carp> (for non-fatal
 errors), or via C<croak> (for fatal errors).
 
 If this behaviour is not desirable, the C<error> attribute may be
 used to hold a reference to a variable, which will be used to store
 the diagnostics. The variable is made a reference to an array of hash
 references.  Each hash contain a single key/value pair where the key
 is the name of the file, and the value is the error message (including
 the contents of C<$!> when appropriate).  If a general error is
 encountered the diagnostic key will be empty.
 
 An example usage looks like:
 
   remove_tree( 'foo/bar', 'bar/rat', {error => \my $err} );
   if (@$err) {
       for my $diag (@$err) {
           my ($file, $message) = %$diag;
           if ($file eq '') {
               print "general error: $message\n";
           }
           else {
               print "problem unlinking $file: $message\n";
           }
       }
   }
   else {
       print "No error encountered\n";
   }
 
 Note that if no errors are encountered, C<$err> will reference an
 empty array.  This means that C<$err> will always end up TRUE; so you
 need to test C<@$err> to determine if errors occured.
 
 =head2 NOTES
 
 C<File::Path> blindly exports C<mkpath> and C<rmtree> into the
 current namespace. These days, this is considered bad style, but
 to change it now would break too much code. Nonetheless, you are
 invited to specify what it is you are expecting to use:
 
   use File::Path 'rmtree';
 
 The routines C<make_path> and C<remove_tree> are B<not> exported
 by default. You must specify which ones you want to use.
 
   use File::Path 'remove_tree';
 
 Note that a side-effect of the above is that C<mkpath> and C<rmtree>
 are no longer exported at all. This is due to the way the C<Exporter>
 module works. If you are migrating a codebase to use the new
 interface, you will have to list everything explicitly. But that's
 just good practice anyway.
 
   use File::Path qw(remove_tree rmtree);
 
 =head3 API CHANGES
 
 The API was changed in the 2.0 branch. For a time, C<mkpath> and
 C<rmtree> tried, unsuccessfully, to deal with the two different
 calling mechanisms. This approach was considered a failure.
 
 The new semantics are now only available with C<make_path> and
 C<remove_tree>. The old semantics are only available through
 C<mkpath> and C<rmtree>. Users are strongly encouraged to upgrade
 to at least 2.08 in order to avoid surprises.
 
 =head3 SECURITY CONSIDERATIONS
 
 There were race conditions 1.x implementations of File::Path's
 C<rmtree> function (although sometimes patched depending on the OS
 distribution or platform). The 2.0 version contains code to avoid the
 problem mentioned in CVE-2002-0435.
 
 See the following pages for more information:
 
   http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=286905
   http://www.nntp.perl.org/group/perl.perl5.porters/2005/01/msg97623.html
   http://www.debian.org/security/2005/dsa-696
 
 Additionally, unless the C<safe> parameter is set (or the
 third parameter in the traditional interface is TRUE), should a
 C<remove_tree> be interrupted, files that were originally in read-only
 mode may now have their permissions set to a read-write (or "delete
 OK") mode.
 
 =head1 DIAGNOSTICS
 
 FATAL errors will cause the program to halt (C<croak>), since the
 problem is so severe that it would be dangerous to continue. (This
 can always be trapped with C<eval>, but it's not a good idea. Under
 the circumstances, dying is the best thing to do).
 
 SEVERE errors may be trapped using the modern interface. If the
 they are not trapped, or the old interface is used, such an error
 will cause the program will halt.
 
 All other errors may be trapped using the modern interface, otherwise
 they will be C<carp>ed about. Program execution will not be halted.
 
 =over 4
 
 =item mkdir [path]: [errmsg] (SEVERE)
 
 C<make_path> was unable to create the path. Probably some sort of
 permissions error at the point of departure, or insufficient resources
 (such as free inodes on Unix).
 
 =item No root path(s) specified
 
 C<make_path> was not given any paths to create. This message is only
 emitted if the routine is called with the traditional interface.
 The modern interface will remain silent if given nothing to do.
 
 =item No such file or directory
 
 On Windows, if C<make_path> gives you this warning, it may mean that
 you have exceeded your filesystem's maximum path length.
 
 =item cannot fetch initial working directory: [errmsg]
 
 C<remove_tree> attempted to determine the initial directory by calling
 C<Cwd::getcwd>, but the call failed for some reason. No attempt
 will be made to delete anything.
 
 =item cannot stat initial working directory: [errmsg]
 
 C<remove_tree> attempted to stat the initial directory (after having
 successfully obtained its name via C<getcwd>), however, the call
 failed for some reason. No attempt will be made to delete anything.
 
 =item cannot chdir to [dir]: [errmsg]
 
 C<remove_tree> attempted to set the working directory in order to
 begin deleting the objects therein, but was unsuccessful. This is
 usually a permissions issue. The routine will continue to delete
 other things, but this directory will be left intact.
 
 =item directory [dir] changed before chdir, expected dev=[n] ino=[n], actual dev=[n] ino=[n], aborting. (FATAL)
 
 C<remove_tree> recorded the device and inode of a directory, and then
 moved into it. It then performed a C<stat> on the current directory
 and detected that the device and inode were no longer the same. As
 this is at the heart of the race condition problem, the program
 will die at this point.
 
 =item cannot make directory [dir] read+writeable: [errmsg]
 
 C<remove_tree> attempted to change the permissions on the current directory
 to ensure that subsequent unlinkings would not run into problems,
 but was unable to do so. The permissions remain as they were, and
 the program will carry on, doing the best it can.
 
 =item cannot read [dir]: [errmsg]
 
 C<remove_tree> tried to read the contents of the directory in order
 to acquire the names of the directory entries to be unlinked, but
 was unsuccessful. This is usually a permissions issue. The
 program will continue, but the files in this directory will remain
 after the call.
 
 =item cannot reset chmod [dir]: [errmsg]
 
 C<remove_tree>, after having deleted everything in a directory, attempted
 to restore its permissions to the original state but failed. The
 directory may wind up being left behind.
 
 =item cannot remove [dir] when cwd is [dir]
 
 The current working directory of the program is F</some/path/to/here>
 and you are attempting to remove an ancestor, such as F</some/path>.
 The directory tree is left untouched.
 
 The solution is to C<chdir> out of the child directory to a place
 outside the directory tree to be removed.
 
 =item cannot chdir to [parent-dir] from [child-dir]: [errmsg], aborting. (FATAL)
 
 C<remove_tree>, after having deleted everything and restored the permissions
 of a directory, was unable to chdir back to the parent. The program
 halts to avoid a race condition from occurring.
 
 =item cannot stat prior working directory [dir]: [errmsg], aborting. (FATAL)
 
 C<remove_tree> was unable to stat the parent directory after have returned
 from the child. Since there is no way of knowing if we returned to
 where we think we should be (by comparing device and inode) the only
 way out is to C<croak>.
 
 =item previous directory [parent-dir] changed before entering [child-dir], expected dev=[n] ino=[n], actual dev=[n] ino=[n], aborting. (FATAL)
 
 When C<remove_tree> returned from deleting files in a child directory, a
 check revealed that the parent directory it returned to wasn't the one
 it started out from. This is considered a sign of malicious activity.
 
 =item cannot make directory [dir] writeable: [errmsg]
 
 Just before removing a directory (after having successfully removed
 everything it contained), C<remove_tree> attempted to set the permissions
 on the directory to ensure it could be removed and failed. Program
 execution continues, but the directory may possibly not be deleted.
 
 =item cannot remove directory [dir]: [errmsg]
 
 C<remove_tree> attempted to remove a directory, but failed. This may because
 some objects that were unable to be removed remain in the directory, or
 a permissions issue. The directory will be left behind.
 
 =item cannot restore permissions of [dir] to [0nnn]: [errmsg]
 
 After having failed to remove a directory, C<remove_tree> was unable to
 restore its permissions from a permissive state back to a possibly
 more restrictive setting. (Permissions given in octal).
 
 =item cannot make file [file] writeable: [errmsg]
 
 C<remove_tree> attempted to force the permissions of a file to ensure it
 could be deleted, but failed to do so. It will, however, still attempt
 to unlink the file.
 
 =item cannot unlink file [file]: [errmsg]
 
 C<remove_tree> failed to remove a file. Probably a permissions issue.
 
 =item cannot restore permissions of [file] to [0nnn]: [errmsg]
 
 After having failed to remove a file, C<remove_tree> was also unable
 to restore the permissions on the file to a possibly less permissive
 setting. (Permissions given in octal).
 
 =item unable to map [owner] to a uid, ownership not changed");
 
 C<make_path> was instructed to give the ownership of created
 directories to the symbolic name [owner], but C<getpwnam> did
 not return the corresponding numeric uid. The directory will
 be created, but ownership will not be changed.
 
 =item unable to map [group] to a gid, group ownership not changed
 
 C<make_path> was instructed to give the group ownership of created
 directories to the symbolic name [group], but C<getgrnam> did
 not return the corresponding numeric gid. The directory will
 be created, but group ownership will not be changed.
 
 =back
 
 =head1 SEE ALSO
 
 =over 4
 
 =item *
 
 L<File::Remove>
 
 Allows files and directories to be moved to the Trashcan/Recycle
 Bin (where they may later be restored if necessary) if the operating
 system supports such functionality. This feature may one day be
 made available directly in C<File::Path>.
 
 =item *
 
 L<File::Find::Rule>
 
 When removing directory trees, if you want to examine each file to
 decide whether to delete it (and possibly leaving large swathes
 alone), F<File::Find::Rule> offers a convenient and flexible approach
 to examining directory trees.
 
 =back
 
 =head1 BUGS
 
 Please report all bugs on the RT queue:
 
 L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=File-Path>
 
 You can also send pull requests to the Github repository:
 
 L<https://github.com/dland/File-Path>
 
 =head1 ACKNOWLEDGEMENTS
 
 Paul Szabo identified the race condition originally, and Brendan
 O'Dea wrote an implementation for Debian that addressed the problem.
 That code was used as a basis for the current code. Their efforts
 are greatly appreciated.
 
 Gisle Aas made a number of improvements to the documentation for
 2.07 and his advice and assistance is also greatly appreciated.
 
 =head1 AUTHORS
 
 Tim Bunce and Charles Bailey. Currently maintained by David Landgren
 <F<david@landgren.net>>.
 
 =head1 COPYRIGHT
 
 This module is copyright (C) Charles Bailey, Tim Bunce and
 David Landgren 1995-2013. All rights reserved.
 
 =head1 LICENSE
 
 This library is free software; you can redistribute it and/or modify
 it under the same terms as Perl itself.
 
 =cut
### File/RsyBak.pm ###
 package File::RsyBak;
 
 our $DATE = '2015-10-21'; # DATE
 our $VERSION = '0.28'; # VERSION
 
 use 5.010001;
 use strict;
 use warnings;
 use Log::Any::IfLOG '$log';
 
 use File::chdir;
 
 require Exporter;
 our @ISA       = qw(Exporter);
 our @EXPORT_OK = qw(backup);
 
 our %SPEC;
 
 sub _parse_path {
     require Cwd;
 
     my ($path) = @_;
     $path =~ s!/+$!!;
     if ($path =~ m!^(\S+)::([^/]+)/?(.*)$!) {
         return {
             raw=>$path, remote=>1, host=>$1,
             proto=>"rsync", module=>$2, path=>$3,
         };
     } elsif ($path =~ m!([^@]+)?\@?(^\S+):(.*)$!) {
         return {
             raw=>$path, remote=>1, host=>$2,
             user=>$1, proto=>"ssh", path=>$3,
         };
     } else {
         return {
             raw=>$path, remote=>0, path=>$path,
             abs_path=>Cwd::abs_path($path)
         };
     }
 }
 
 # rsync requires all source to be local, or remote (same host). check sources
 # before we run rsync, so we can report the error and die earlier.
 sub _check_sources {
     my ($sources) = @_;
 
     my $all_local = 1;
     for (@$sources) {
         if ($_->{remote}) { $all_local = 0; last }
     }
 
     my $all_remote = 1;
     for (@$sources) {
         if (!$_->{remote}) { $all_remote = 0; last }
     }
 
     return [400, "Sources must be all local or all remote"]
         unless $all_remote || $all_local;
 
     if ($all_remote) {
         my $host;
         for (@$sources) {
             $host //= $_->{host};
             return [400, "Remote sources must all be from the same machine"]
                 if $host ne $_->{host};
         }
     }
     [200, "OK"];
 }
 
 $SPEC{backup} = {
     v             => 1.1,
     summary       =>
         'Backup files/directories with histories, using rsync',
     args          => {
         source           => {
             summary      => 'Director(y|ies) to backup',
             #schema       => ['any*'   => {
             #    of => ['str*', ['array*' => {of=>'str*'}]]
             #}],
             schema       => 'str*', # temp, because in pericmd when specifying as arg#0, there is a warning of JSON decoding failure
             req          => 1,
             pos          => 0,
         },
         target           => {
             summary      => 'Backup destination',
             schema       => ['str*'   => {}],
             req          => 1,
             pos          => 1,
         },
         histories        => {
             summary      => 'Histories/history levels',
             schema       => ['array' => {
                 default      => [-7, 4, 3],
                 of           => 'int*',
             }],
             description  => <<'_',
 
 Specifies number of backup histories to keep for level 1, 2, and so on. If
 number is negative, specifies number of days to keep instead (regardless of
 number of histories).
 
 _
         },
         extra_dir        => {
             summary      =>
                 'Whether to force creation of source directory in target',
             schema       => ['bool'   => {}],
             description  => <<'_',
 
 If set to 1, then backup(source => '/a', target => '/backup/a') will create
 another 'a' directory in target, i.e. /backup/a/current/a. Otherwise, contents
 of a/ will be directly copied under /backup/a/current/.
 
 Will always be set to 1 if source is more than one, but default to 0 if source
 is a single directory. You can set this to 1 to so that behaviour when there is
 a single source is the same as behaviour when there are several sources.
 
 _
         },
         backup           => {
             summary      => 'Whether to do backup or not',
             schema       => [bool     => {
                 default      => 1,
             }],
             description  => <<'_',
 
 If backup=1 and rotate=0 then will only create new backup without rotating
 histories.
 
 _
         },
         rotate           => {
             summary      => 'Whether to do rotate after backup or not',
             schema       => [bool     => {
                 default      => 1,
             }],
             description  => <<'_',
 
 If backup=0 and rotate=1 then will only do history rotating.
 
 _
         },
         extra_rsync_opts => {
             summary      => 'Pass extra options to rsync command',
             schema       => [array    => {
                 of           => 'str*',
             }],
             description  => <<'_',
 
 Extra options to pass to rsync command when doing backup. Note that the options
 will be shell quoted, , so you should pass it unquoted, e.g. ['--exclude',
 '/Program Files'].
 
 _
         },
     },
 
     examples => [
         {
             argv         => ['/home/jajang/mydata','/backup/jajang/mydata'],
             test         => 0,
             description  => <<'_',
 
 Backup /home/jajang/mydata to /backup/jajang/mydata using the default number of
 histories ([-7, 4, 3]).
 
 _
         },
     ],
 
     deps => {
         all => [
             {prog => 'nice'},
             {prog => 'rsync'}, # XXX not needed if backup=0
             {prog => 'rm'},    # XXX not needed if rotate=0
         ],
     },
 };
 sub backup {
     require File::Flock;
     require File::Path;
     require File::Which;
 
     my %args = @_;
 
     # XXX schema
     my $source    = $args{source} or return [400, "Please specify source"];
     my @sources   = ref($source) eq 'ARRAY' ? @$source : ($source);
     for (@sources) { $_ = _parse_path($_) }
     my $res = _check_sources(\@sources);
     return $res unless $res->[0] == 200;
     my $target    = $args{target} or return [400, "Please specify target"];
     $target       = _parse_path($target);
     $target->{remote} and
         return [400, "Sorry, target can't be remote at the moment"];
     my $histories = $args{histories} // [-7, 4, 3];
     ref($histories) eq 'ARRAY' or return [400, "histories must be array"];
     my $backup    = $args{backup} // 1;
     my $rotate    = $args{rotate} // 1;
     my $extra_dir = $args{extra_dir} || (@sources > 1);
 
     # sanity
     my $rsync_path = File::Which::which("rsync")
         or return [500, "Can't find rsync in PATH"];
 
     unless (-d $target->{abs_path}) {
         $log->debugf("Creating target directory %s ...", $target->{abs_path});
         File::Path::make_path($target->{abs_path})
             or return [500, "Error: Can't create target directory ".
                 "$target->{abs_path}: $!"];
     }
 
     return [409, "Error: Can't lock $target->{abs_path}/.lock, ".
                 "perhaps another backup process is running"]
         unless File::Flock::lock("$target->{abs_path}/.lock", undef,
                                  "nonblocking");
 
     if ($backup) {
         _backup(
             \@sources, $target,
             {
                 extra_dir        => $extra_dir,
                 extra_rsync_opts => $args{extra_rsync_opts},
             });
     }
 
     if ($rotate) {
         _rotate($target->{abs_path}, $histories);
     }
 
     File::Flock::unlock("$target->{abs_path}/.lock");
 
     [200, "OK"];
 }
 
 sub _backup {
     require POSIX;
     require String::ShellQuote; String::ShellQuote->import;
 
     my ($sources, $target, $opts) = @_;
     $log->infof("Starting backup %s ==> %s ...",
                 [map {$_->{raw}} @$sources], $target);
     my $cmd;
     $cmd = join(
         "",
         "nice -n19 rsync ",
         ($opts->{extra_rsync_opts} ? map { shell_quote($_), " " }
              @{$opts->{extra_rsync_opts}} : ()),
         "-a --del --force --ignore-errors --ignore-existing ",
         ((-e "$target->{abs_path}/current") ?
              "--link-dest ".shell_quote("$target->{abs_path}/current")." "
                  : ""),
         map({ shell_quote($_->{raw}), ($opts->{extra_dir} ? "" : "/"), " " }
                 @$sources),
         shell_quote("$target->{abs_path}/.tmp/"),
     );
     $log->debug("Running rsync ...");
     $log->trace("system(): $cmd");
     system $cmd;
     $log->warn("rsync didn't succeed ($?)".
                    ", please recheck") if $?;
 
     # but continue anyway, half backups are better than nothing
 
     if (-e "$target->{abs_path}/current") {
         my $tspath = "$target->{abs_path}/.current.timestamp";
         my @st     = stat($tspath);
         my $tstamp = POSIX::strftime(
             "%Y-%m-%d\@%H:%M:%S+00",
             gmtime( $st[9] || time() )); # timestamp might not exist yet
         $log->debug("rename $target->{abs_path}/current ==> ".
                         "hist.$tstamp ...");
         unless (rename "$target->{abs_path}/current",
                 "$target->{abs_path}/hist.$tstamp") {
             $log->warn("Failed renaming $target->{abs_path}/current ==> ".
                          "hist.$tstamp: $!");
         }
         $log->debug("touch $tspath ...");
         system "touch ".shell_quote($tspath);
     }
 
     $log->debug("rename $target->{abs_path}/.tmp ==> current ...");
     unless (rename "$target->{abs_path}/.tmp",
             "$target->{abs_path}/current") {
         $log->warn("Failed renaming $target->{abs_path}/.tmp ==> current: $!");
     }
 
     $log->infof("Finished backup %s ==> %s", $sources, $target);
 }
 
 sub _rotate {
     require String::ShellQuote; String::ShellQuote->import;
     require Time::Local;
 
     my ($target, $histories) = @_;
     $log->infof("Rotating backup histories in %s (%s) ...",
                 $target, $histories);
 
     local $CWD = $target; # throws exception when failed
 
     my $now = time();
     for my $level (1 .. @$histories) {
         my $is_highest_level  = $level == @$histories;
         my $prefix            = "hist" . ($level == 1 ? '' : $level);
         my $prefix_next_level = "hist" . ($level + 1);
         my $n                 = $histories->[$level - 1];
         my $moved             = 0;
 
         if ($n > 0) {
             $log->debug("Only keeping $n level-$level histories ...");
             my @f = reverse sort grep { !/\.tmp$/ } glob "$prefix.*";
             #untaint for @f;
             my $any_tagged = (grep {/t$/} @f) ? 1 : 0;
             for my $f (@f[ $n .. @f - 1 ]) {
                 my ($st, $tagged) = $f =~ /[^.]+\.(.+?)(t)?$/;
                 my $f2 = "$prefix_next_level.$st";
                 if (!$is_highest_level &&
                         !$moved && ($tagged || !$any_tagged)) {
                     $log->debug("Moving history level: $f -> $f2");
                     rename $f, $f2;
                     $moved++;
                     if ($f ne $f[0]) {
                         rename $f[0], "$f[0]t";
                     }
                 } else {
                     $log->debug("Removing history: $f ...");
                     system "nice -n19 rm -rf " . shell_quote($f);
                 }
             }
         } else {
             $n = -$n;
             $log->debug("Only keeping $n day(s) of level-$level histories ...");
             my @f = reverse sort grep { !/\.tmp$/ } glob "$prefix.*";
             my $any_tagged = ( grep {/t$/} @f ) ? 1 : 0;
             for my $f (@f) {
                 my ($st, $tagged) = $f =~ /[^.]+\.(.+?)(t)?$/;
                 my $f2 = "$prefix_next_level.$st";
                 my $t;
                 $st =~ /(\d\d\d\d)-(\d\d)-(\d\d)\@(\d\d):(\d\d):(\d\d)\+00/;
                 $t = Time::Local::timegm($6, $5, $4, $3, $2 - 1, $1) if $1;
                 unless ($st && $t) {
                     $log->warn("Wrong format of history, ignored: $f");
                     next;
                 }
                 if ($t > $now) {
                     $log->warn("History in the future, ignored: $f");
                     next;
                 }
                 my $delta = ($now - $t) / 86400;
                 if ($delta > $n) {
                     if (!$is_highest_level &&
                             !$moved && ( $tagged || !$any_tagged)) {
                         $log->debug("Moving history level: $f -> $f2");
                         rename $f, $f2;
                         $moved++;
                         if ($f ne $f[0]) {
                             rename $f[0], "$f[0]t";
                         }
                     } else {
                         $log->debug("Removing history: $f ...");
                         system "nice -n19 rm -rf " . shell_quote($f);
                     }
                 }
             }
         }
     }
 }
 
 1;
 # ABSTRACT: Backup files/directories with histories, using rsync
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 File::RsyBak - Backup files/directories with histories, using rsync
 
 =head1 VERSION
 
 This document describes version 0.28 of File::RsyBak (from Perl distribution File-RsyBak), released on 2015-10-21.
 
 =head1 SYNOPSIS
 
 From your Perl program:
 
  use File::RsyBak qw(backup);
  backup(
      source    => '/path/to/mydata',
      target    => '/backup/mydata',
      histories => [-7, 4, 3],         # 7 days, 4 weeks, 3 months
      extra_rsync_opts => [qw/--exclude Cache --exclude cache --exclude tmp --exclude temp/],
  );
 
 Or, just use the provided script from the command-line:
 
  % rsybak --source /path/to/mydata --target /backup/mydata --extra-rsync-opts-json '["--exclude","Cache","--exclude","cache","--exclude","tmp","--exclude","temp"]'
 
 Or, if you have this configuration in C</etc/rsybak.conf> or C<~/rsybak.conf>:
 
  [system]
  source = /path/to/mydata
  target = /backup/mydata
  ; also specify as JSON
  extra_rsync_opts = ["--exclude","Cache","--exclude","cache","--exclude","tmp","--exclude","temp"]
 
 you can just run:
 
  % rsybak --config-profile system
 
 Example resulting backup (after several runs so that backup history has
 accumulated):
 
  % ls /path/to/mydata/
  myfile
  anotherfile
  mydir/
 
  % ls /backup/mydata/
  current/
  hist.2013-10-31@12:04:17+00/
  hist.2013-11-01@12:09:31+00/
  hist.2013-11-02@12:09:41+00t/
  hist.2013-11-03@12:15:02+00/
  hist.2013-11-04@12:13:19+00/
  hist.2013-11-05@12:11:31+00/
  hist2.2013-10-08@12:07:50+00/
  hist2.2013-10-15@12:06:03+00/
  hist2.2013-10-21@12:02:42+00/
  hist2.2013-10-27@12:06:25+00t/
  hist3.2013-06-25@12:15:39+00/
  hist3.2013-08-31@12:05:31+00/
  hist3.2013-10-02@12:05:57+00/
 
 Each directory under C</backup/mydata> is a "snapshot" backup of
 C</path/to/mydata>:
 
  % ls /backup/mydata/current/
  myfile
  anotherfile
  mydir/
 
  % ls /backup/mydata/hist.2013-10-31@12:04:17+00/
  myfile
  anotherfile
  mydir/
 
  % ls /backup/mydata/hist3.2013-10-02@12:05:57+00/
  myfile
  anotherfile
  mydir/
  someoldfile
 
 =head1 DESCRIPTION
 
 This module is basically just a wrapper around B<rsync> to create a filesystem
 backup system. Some characteristics of this backup system:
 
 =over 4
 
 =item * Supports backup histories and history levels
 
 For example, you can create 7 level-1 backup histories (equals 7 daily histories
 if you run backup once daily), 4 level-2 backup histories (equals 4 weekly
 histories) and 3 level-3 backup histories (roughly equals 3 monthly histories).
 The number of levels and history per levels are customizable.
 
 =item * Backups (and histories) are not compressed/archived ("tar"-ed)
 
 They are just verbatim copies (produced by L<rsync -a>) of source directory. The
 upside of this is ease of cherry-picking (taking/restoring individual files from
 backup). The downside is lack of compression and the backup not being a single
 archive file.
 
 This is because rsync needs two real directory trees when comparing. Perhaps if
 rsync supports tar virtual filesystem in the future...
 
 =item * Hardlinks are used between backup histories to save disk space
 
 This way, we can maintain several backup histories without wasting too much
 space duplicating data when there are not a lot of differences among them.
 
 =item * High performance
 
 Rsync is implemented in C and has been optimized for a long time. B<rm> is also
 used instead of Perl implementation File::Path::remove_path.
 
 =item * Unix-specific
 
 There are ports of rsync and rm on Windows, but this module hasn't been tested
 on those platforms.
 
 =back
 
 =head1 FUNCTIONS
 
 
 =head2 backup(%args) -> [status, msg, result, meta]
 
 Backup files/directories with histories, using rsync.
 
 Examples:
 
  backup( source => "/home/jajang/mydata", target => "/backup/jajang/mydata");
 
 
 Result:
 
  [
    500,
    "Error: Can't create target directory : No such file or directory",
  ]
 
 
 This function is not exported by default, but exportable.
 
 Arguments ('*' denotes required arguments):
 
 =over 4
 
 =item * B<backup> => I<bool> (default: 1)
 
 Whether to do backup or not.
 
 If backup=1 and rotate=0 then will only create new backup without rotating
 histories.
 
 =item * B<extra_dir> => I<bool>
 
 Whether to force creation of source directory in target.
 
 If set to 1, then backup(source => '/a', target => '/backup/a') will create
 another 'a' directory in target, i.e. /backup/a/current/a. Otherwise, contents
 of a/ will be directly copied under /backup/a/current/.
 
 Will always be set to 1 if source is more than one, but default to 0 if source
 is a single directory. You can set this to 1 to so that behaviour when there is
 a single source is the same as behaviour when there are several sources.
 
 =item * B<extra_rsync_opts> => I<array[str]>
 
 Pass extra options to rsync command.
 
 Extra options to pass to rsync command when doing backup. Note that the options
 will be shell quoted, , so you should pass it unquoted, e.g. ['--exclude',
 '/Program Files'].
 
 =item * B<histories> => I<array[int]> (default: [-7,4,3])
 
 Histories/history levels.
 
 Specifies number of backup histories to keep for level 1, 2, and so on. If
 number is negative, specifies number of days to keep instead (regardless of
 number of histories).
 
 =item * B<rotate> => I<bool> (default: 1)
 
 Whether to do rotate after backup or not.
 
 If backup=0 and rotate=1 then will only do history rotating.
 
 =item * B<source>* => I<str>
 
 Director(y|ies) to backup.
 
 =item * B<target>* => I<str>
 
 Backup destination.
 
 =back
 
 Returns an enveloped result (an array).
 
 First element (status) is an integer containing HTTP status code
 (200 means OK, 4xx caller error, 5xx function error). Second element
 (msg) is a string containing error message, or 'OK' if status is
 200. Third element (result) is optional, the actual result. Fourth
 element (meta) is called result metadata and is optional, a hash
 that contains extra information.
 
 Return value:  (any)
 
 =head1 HOW IT WORKS
 
 =head2 First-time backup
 
 First, we lock target directory to prevent other backup process from
 interfering:
 
  mkdir -p TARGET
  flock    TARGET/.lock
 
 Then we copy source to temporary directory:
 
  rsync    SRC            TARGET/.tmp
 
 If copy finishes successfully, we rename temporary directory to final directory
 'current':
 
  rename   TARGET/.tmp    TARGET/current
  touch    TARGET/.current.timestamp
 
 If copy fails in the middle, TARGET/.tmp will still be lying around and the next
 backup run will just continue the rsync process:
 
  rsync    SRC            TARGET/.tmp
 
 Finally, we remove lock:
 
  unlock   TARGET/.lock
 
 =head2 Subsequent backups (after TARGET/current exists)
 
 First, we lock target directory to prevent other backup process to interfere:
 
  flock    TARGET/.lock
 
 Then we rsync source to target directory (using --link-dest=TARGET/current):
 
  rsync    SRC            TARGET/.tmp
 
 If rsync finishes successfully, we rename target directories:
 
  rename   TARGET/current TARGET/hist.<timestamp>
  rename   TARGET/.tmp    TARGET/current
  touch    TARGET/.current.timestamp
 
 If rsync fails in the middle, TARGET/.tmp will be lying around and the next
 backup run will just continue the rsync process.
 
 Finally, we remove lock:
 
  unlock   TARGET/.lock
 
 =head2 Maintenance of histories/history levels
 
 TARGET/hist.* are level-1 backup histories. Each backup run will produce a new
 history:
 
  TARGET/hist.<timestamp1>
  TARGET/hist.<timestamp2> # produced by the next backup
  TARGET/hist.<timestamp3> # and the next ...
  TARGET/hist.<timestamp4> # and so on ...
  TARGET/hist.<timestamp5>
  ...
 
 You can specify the number of histories (or number of days) to maintain. If the
 number of histories exceeds the limit, older histories will be deleted, or one
 will be promoted to the next level, if a higher level is specified.
 
 For example, with B<histories> being set to [7, 4, 3], after
 TARGET/hist.<timestamp8> is created, TARGET/hist.<timestamp1> will be promoted
 to level 2:
 
  rename TARGET/hist.<timestamp1> TARGET/hist2.<timestamp1>
 
 TARGET/hist2.* directories are level-2 backup histories. After a while, they
 will also accumulate:
 
  TARGET/hist2.<timestamp1>
  TARGET/hist2.<timestamp8>
  TARGET/hist2.<timestamp15>
  TARGET/hist2.<timestamp22>
 
 When TARGET/hist2.<timestamp29> arrives, TARGET/hist2.<timestamp1> will be
 promoted to level 3: TARGET/hist3.<timestamp1>. After a while, level-3 backup
 histories too will accumulate:
 
  TARGET/hist3.<timestamp1>
  TARGET/hist3.<timestamp29>
  TARGET/hist3.<timestamp57>
 
 Finally, TARGET/hist3.<timestamp1> will be deleted after
 TARGET/hist3.<timestamp85> comes along.
 
 =head1 HISTORY
 
 The idea for this module came out in 2006 as part of the Spanel hosting control
 panel project. We need a daily backup system for shared hosting accounts that
 supports histories and cherry-picking. Previously we had been using a
 Python-based script B<rdiff-backup>. It was not very robust, the script chose to
 exit on many kinds of non-fatal errors instead of ignoring the errors and
 continuning backup. It was also very slow: on a server with hundreds of accounts
 with millions of files, backup process often took 12 hours or more. After
 evaluating several other solutions, we realized that nothing beats the raw
 performance of rsync. Thus we designed a simple backup system based on it.
 
 First public release of this module is in Feb 2011. I have since used this
 script in various production servers as well as personal PCs/laptops.
 
 =head1 FAQ
 
 =head2 How do I exclude some directories?
 
 Just use rsync's --exclude et al. Pass them to extra_rsync_opts.
 
 =head2 What is a good backup practice (using RsyBak)?
 
 Just follow the general practice. While this is not a place to discuss backups
 in general, some of the principles are:
 
 =over 4
 
 =item * backup regularly (e.g. once daily or more often)
 
 =item * automate the process (else you'll forget)
 
 =item * backup to another disk partition and computer
 
 =item * verify your backups often (what good are they if they can't be restored)
 
 =item * make sure your backup is secure (encrypted, correct permission, etc)
 
 =back
 
 =head2 How do I restore backups?
 
 Backups are just verbatim copies of files/directories, so just use whatever
 filesystem tools you like.
 
 =head2 How to do remote backup?
 
 From your backup host:
 
  [BAK-HOST]% rsybak --source USER@SRC-HOST:/path --dest /backup/dir
 
 Or alternatively, you can backup on SRC-HOST locally first, then send the
 resulting backup to BAK-HOST.
 
 =head1 SEE ALSO
 
 L<File::Backup>
 
 L<File::Rotate::Backup>
 
 L<Snapback2>, which is a backup system using the same basic principle (rsync
 snapshots), created in as early as 2004 (or earlier) by Mike Heins. Do check it
 out. I wish I had found it first before reinventing it in 2006 :-)
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/File-RsyBak>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-File-RsyBak>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=File-RsyBak>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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
### File/RsyBak/Packed.pm ###
 package File::RsyBak::Packed;
 
 our $DATE = '2015-10-21'; # DATE
 our $VERSION = '0.28'; # VERSION
 
 # PACKED_MODULES
 # PACKED_DISTS
 
 1;
 # ABSTRACT: Backup files/directories with histories, using rsync (just an empty module for metadata)
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 File::RsyBak::Packed - Backup files/directories with histories, using rsync (just an empty module for metadata)
 
 =head1 VERSION
 
 This document describes version 0.28 of File::RsyBak::Packed (from Perl distribution File-RsyBak), released on 2015-10-21.
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/File-RsyBak>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-File-RsyBak>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=File-RsyBak>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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
### File/Slurp.pm ###
 package File::Slurp;
 
 use 5.6.2 ;
 
 use strict;
 use warnings ;
 
 use Carp ;
 use Exporter ;
 use Fcntl qw( :DEFAULT ) ;
 use POSIX qw( :fcntl_h ) ;
 use Errno ;
 #use Symbol ;
 
 use vars qw( @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS $VERSION ) ;
 @ISA = qw( Exporter ) ;
 
 $VERSION = '9999.19';
 
 my @std_export = qw(
 	read_file
 	write_file
 	overwrite_file
 	append_file
 	read_dir
 ) ;
 
 my @edit_export = qw( 
 	edit_file
 	edit_file_lines
 ) ;
 
 my @ok_export = qw( 
 ) ;
 
 @EXPORT_OK = (
 	@edit_export,
 	qw(
 		slurp
 		prepend_file
 	),
 ) ;
 
 %EXPORT_TAGS = (
 	'all'	=> [ @std_export, @edit_export, @EXPORT_OK ],
 	'edit'	=> [ @edit_export ],
 	'std'	=> [ @std_export ],
 ) ;
 
 @EXPORT = @std_export ;
 
 my $max_fast_slurp_size = 1024 * 100 ;
 
 my $is_win32 = $^O =~ /win32/i ;
 
 # Install subs for various constants that aren't set in older perls
 # (< 5.005).  Fcntl on old perls uses Exporter to define subs without a
 # () prototype These can't be overridden with the constant pragma or
 # we get a prototype mismatch.  Hence this less than aesthetically
 # appealing BEGIN block:
 
 BEGIN {
 	unless( defined &SEEK_SET ) {
 		*SEEK_SET = sub { 0 };
 		*SEEK_CUR = sub { 1 };
 		*SEEK_END = sub { 2 };
 	}
 
 	unless( defined &O_BINARY ) {
 		*O_BINARY = sub { 0 };
 		*O_RDONLY = sub { 0 };
 		*O_WRONLY = sub { 1 };
 	}
 
 	unless ( defined &O_APPEND ) {
 
 		if ( $^O =~ /olaris/ ) {
 			*O_APPEND = sub { 8 };
 			*O_CREAT = sub { 256 };
 			*O_EXCL = sub { 1024 };
 		}
 		elsif ( $^O =~ /inux/ ) {
 			*O_APPEND = sub { 1024 };
 			*O_CREAT = sub { 64 };
 			*O_EXCL = sub { 128 };
 		}
 		elsif ( $^O =~ /BSD/i ) {
 			*O_APPEND = sub { 8 };
 			*O_CREAT = sub { 512 };
 			*O_EXCL = sub { 2048 };
 		}
 	}
 }
 
 # print "OS [$^O]\n" ;
 
 # print "O_BINARY = ", O_BINARY(), "\n" ;
 # print "O_RDONLY = ", O_RDONLY(), "\n" ;
 # print "O_WRONLY = ", O_WRONLY(), "\n" ;
 # print "O_APPEND = ", O_APPEND(), "\n" ;
 # print "O_CREAT   ", O_CREAT(), "\n" ;
 # print "O_EXCL   ", O_EXCL(), "\n" ;
 
 
 *slurp = \&read_file ;
 
 sub read_file {
 
 	my $file_name = shift ;
 	my $opts = ( ref $_[0] eq 'HASH' ) ? shift : { @_ } ;
 
 # this is the optimized read_file for shorter files.
 # the test for -s > 0 is to allow pseudo files to be read with the
 # regular loop since they return a size of 0.
 
 	if ( !ref $file_name && -e $file_name && -s _ > 0 &&
 	     -s _ < $max_fast_slurp_size && !%{$opts} && !wantarray ) {
 
 
 		my $fh ;
 		unless( sysopen( $fh, $file_name, O_RDONLY ) ) {
 
 			@_ = ( $opts, "read_file '$file_name' - sysopen: $!");
 			goto &_error ;
 		}
 
 		my $read_cnt = sysread( $fh, my $buf, -s _ ) ;
 
 		unless ( defined $read_cnt ) {
 
 			@_ = ( $opts,
 				"read_file '$file_name' - small sysread: $!");
 			goto &_error ;
 		}
 
 		$buf =~ s/\015\012/\n/g if $is_win32 ;
 		return $buf ;
 	}
 
 # set the buffer to either the passed in one or ours and init it to the null
 # string
 
 	my $buf ;
 	my $buf_ref = $opts->{'buf_ref'} || \$buf ;
 	${$buf_ref} = '' ;
 
 	my( $read_fh, $size_left, $blk_size ) ;
 
 # deal with ref for a file name
 # it could be an open handle or an overloaded object
 
 	if ( ref $file_name ) {
 
 		my $ref_result = _check_ref( $file_name ) ;
 
 		if ( ref $ref_result ) {
 
 # we got an error, deal with it
 
 			@_ = ( $opts, $ref_result ) ;
 			goto &_error ;
 		}
 
 		if ( $ref_result ) {
 
 # we got an overloaded object and the result is the stringified value
 # use it as the file name
 
 			$file_name = $ref_result ;
 		}
 		else {
 
 # here we have just an open handle. set $read_fh so we don't do a sysopen
 
 			$read_fh = $file_name ;
 			$blk_size = $opts->{'blk_size'} || 1024 * 1024 ;
 			$size_left = $blk_size ;
 		}
 	}
 
 # see if we have a path we need to open
 
 	unless ( $read_fh ) {
 
 # a regular file. set the sysopen mode
 
 		my $mode = O_RDONLY ;
 
 #printf "RD: BINARY %x MODE %x\n", O_BINARY, $mode ;
 
 		$read_fh = local( *FH ) ;
 #		$read_fh = gensym ;
 		unless ( sysopen( $read_fh, $file_name, $mode ) ) {
 			@_ = ( $opts, "read_file '$file_name' - sysopen: $!");
 			goto &_error ;
 		}
 
 		if ( my $binmode = $opts->{'binmode'} ) {
 			binmode( $read_fh, $binmode ) ;
 		}
 
 # get the size of the file for use in the read loop
 
 		$size_left = -s $read_fh ;
 
 #print "SIZE $size_left\n" ;
 
 # we need a blk_size if the size is 0 so we can handle pseudofiles like in
 # /proc. these show as 0 size but have data to be slurped.
 
 		unless( $size_left ) {
 
 			$blk_size = $opts->{'blk_size'} || 1024 * 1024 ;
 			$size_left = $blk_size ;
 		}
 	}
 
 # infinite read loop. we exit when we are done slurping
 
 	while( 1 ) {
 
 # do the read and see how much we got
 
 		my $read_cnt = sysread( $read_fh, ${$buf_ref},
 				$size_left, length ${$buf_ref} ) ;
 
 # since we're using sysread Perl won't automatically restart the call
 # when interrupted by a signal.
 
 		next if $!{EINTR};
 
 		unless ( defined $read_cnt ) {
 
 			@_ = ( $opts, "read_file '$file_name' - loop sysread: $!");
 			goto &_error ;
 		}
 
 # good read. see if we hit EOF (nothing left to read)
 
 		last if $read_cnt == 0 ;
 
 # loop if we are slurping a handle. we don't track $size_left then.
 
 		next if $blk_size ;
 
 # count down how much we read and loop if we have more to read.
 
 		$size_left -= $read_cnt ;
 		last if $size_left <= 0 ;
 	}
 
 # fix up cr/lf to be a newline if this is a windows text file
 
 	${$buf_ref} =~ s/\015\012/\n/g if $is_win32 && !$opts->{'binmode'} ;
 
 	my $sep = $/ ;
 	$sep = '\n\n+' if defined $sep && $sep eq '' ;
 
 # see if caller wants lines
 
 	if( wantarray || $opts->{'array_ref'} ) {
 
 		use re 'taint' ;
 
 		my @lines = length(${$buf_ref}) ?
 			${$buf_ref} =~ /(.*?$sep|.+)/sg : () ;
 
 		chomp @lines if $opts->{'chomp'} ;
 
 # caller wants an array ref
 
 		return \@lines if $opts->{'array_ref'} ;
 
 # caller wants list of lines
 
 		return @lines ;
 	}
 
 # caller wants a scalar ref to the slurped text
 
 	return $buf_ref if $opts->{'scalar_ref'} ;
 
 # caller wants a scalar with the slurped text (normal scalar context)
 
 	return ${$buf_ref} if defined wantarray ;
 
 # caller passed in an i/o buffer by reference (normal void context)
 
 	return ;
 }
 
 # errors in this sub are returned as scalar refs
 # a normal IO/GLOB handle is an empty return
 # an overloaded object returns its stringified as a scalarfilename
 
 sub _check_ref {
 
 	my( $handle ) = @_ ;
 
 # check if we are reading from a handle (GLOB or IO object)
 
 	if ( eval { $handle->isa( 'GLOB' ) || $handle->isa( 'IO' ) } ) {
 
 # we have a handle. deal with seeking to it if it is DATA
 
 		my $err = _seek_data_handle( $handle ) ;
 
 # return the error string if any
 
 		return \$err if $err ;
 
 # we have good handle
 		return ;
 	}
 
 	eval { require overload } ;
 
 # return an error if we can't load the overload pragma
 # or if the object isn't overloaded
 
 	return \"Bad handle '$handle' is not a GLOB or IO object or overloaded"
 		 if $@ || !overload::Overloaded( $handle ) ;
 
 # must be overloaded so return its stringified value
 
 	return "$handle" ;
 }
 
 sub _seek_data_handle {
 
 	my( $handle ) = @_ ;
 
 # DEEP DARK MAGIC. this checks the UNTAINT IO flag of a
 # glob/handle. only the DATA handle is untainted (since it is from
 # trusted data in the source file). this allows us to test if this is
 # the DATA handle and then to do a sysseek to make sure it gets
 # slurped correctly. on some systems, the buffered i/o pointer is not
 # left at the same place as the fd pointer. this sysseek makes them
 # the same so slurping with sysread will work.
 
 	eval{ require B } ;
 
 	if ( $@ ) {
 
 		return <<ERR ;
 Can't find B.pm with this Perl: $!.
 That module is needed to properly slurp the DATA handle.
 ERR
 	}
 
 	if ( B::svref_2object( $handle )->IO->IoFLAGS & 16 ) {
 
 # set the seek position to the current tell.
 
 		unless( sysseek( $handle, tell( $handle ), SEEK_SET ) ) {
 			return "read_file '$handle' - sysseek: $!" ;
 		}
 	}
 
 # seek was successful, return no error string
 
 	return ;
 }
 
 
 sub write_file {
 
 	my $file_name = shift ;
 
 # get the optional argument hash ref from @_ or an empty hash ref.
 
 	my $opts = ( ref $_[0] eq 'HASH' ) ? shift : {} ;
 
 	my( $buf_ref, $write_fh, $no_truncate, $orig_file_name, $data_is_ref ) ;
 
 # get the buffer ref - it depends on how the data is passed into write_file
 # after this if/else $buf_ref will have a scalar ref to the data.
 
 	if ( ref $opts->{'buf_ref'} eq 'SCALAR' ) {
 
 # a scalar ref passed in %opts has the data
 # note that the data was passed by ref
 
 		$buf_ref = $opts->{'buf_ref'} ;
 		$data_is_ref = 1 ;
 	}
 	elsif ( ref $_[0] eq 'SCALAR' ) {
 
 # the first value in @_ is the scalar ref to the data
 # note that the data was passed by ref
 
 		$buf_ref = shift ;
 		$data_is_ref = 1 ;
 	}
 	elsif ( ref $_[0] eq 'ARRAY' ) {
 
 # the first value in @_ is the array ref to the data so join it.
 
 		${$buf_ref} = join '', @{$_[0]} ;
 	}
 	else {
 
 # good old @_ has all the data so join it.
 
 		${$buf_ref} = join '', @_ ;
 	}
 
 # deal with ref for a file name
 
 	if ( ref $file_name ) {
 
 		my $ref_result = _check_ref( $file_name ) ;
 
 		if ( ref $ref_result ) {
 
 # we got an error, deal with it
 
 			@_ = ( $opts, $ref_result ) ;
 			goto &_error ;
 		}
 
 		if ( $ref_result ) {
 
 # we got an overloaded object and the result is the stringified value
 # use it as the file name
 
 			$file_name = $ref_result ;
 		}
 		else {
 
 # we now have a proper handle ref.
 # make sure we don't call truncate on it.
 
 			$write_fh = $file_name ;
 			$no_truncate = 1 ;
 		}
 	}
 
 # see if we have a path we need to open
 
 	unless( $write_fh ) {
 
 # spew to regular file.
 
 		if ( $opts->{'atomic'} ) {
 
 # in atomic mode, we spew to a temp file so make one and save the original
 # file name.
 			$orig_file_name = $file_name ;
 			$file_name .= ".$$" ;
 		}
 
 # set the mode for the sysopen
 
 		my $mode = O_WRONLY | O_CREAT ;
 		$mode |= O_APPEND if $opts->{'append'} ;
 		$mode |= O_EXCL if $opts->{'no_clobber'} ;
 
 		my $perms = $opts->{perms} ;
 		$perms = 0666 unless defined $perms ;
 
 #printf "WR: BINARY %x MODE %x\n", O_BINARY, $mode ;
 
 # open the file and handle any error.
 
 		$write_fh = local( *FH ) ;
 #		$write_fh = gensym ;
 		unless ( sysopen( $write_fh, $file_name, $mode, $perms ) ) {
 
 			@_ = ( $opts, "write_file '$file_name' - sysopen: $!");
 			goto &_error ;
 		}
 	}
 
 	if ( my $binmode = $opts->{'binmode'} ) {
 		binmode( $write_fh, $binmode ) ;
 	}
 
 	sysseek( $write_fh, 0, SEEK_END ) if $opts->{'append'} ;
 
 #print 'WR before data ', unpack( 'H*', ${$buf_ref}), "\n" ;
 
 # fix up newline to write cr/lf if this is a windows text file
 
 	if ( $is_win32 && !$opts->{'binmode'} ) {
 
 # copy the write data if it was passed by ref so we don't clobber the
 # caller's data
 		$buf_ref = \do{ my $copy = ${$buf_ref}; } if $data_is_ref ;
 		${$buf_ref} =~ s/\n/\015\012/g ;
 	}
 
 #print 'after data ', unpack( 'H*', ${$buf_ref}), "\n" ;
 
 # get the size of how much we are writing and init the offset into that buffer
 
 	my $size_left = length( ${$buf_ref} ) ;
 	my $offset = 0 ;
 
 # loop until we have no more data left to write
 
 	do {
 
 # do the write and track how much we just wrote
 
 		my $write_cnt = syswrite( $write_fh, ${$buf_ref},
 				$size_left, $offset ) ;
 
 # since we're using syswrite Perl won't automatically restart the call
 # when interrupted by a signal.
 
 		next if $!{EINTR};
 
 		unless ( defined $write_cnt ) {
 
 			@_ = ( $opts, "write_file '$file_name' - syswrite: $!");
 			goto &_error ;
 		}
 
 # track how much left to write and where to write from in the buffer
 
 		$size_left -= $write_cnt ;
 		$offset += $write_cnt ;
 
 	} while( $size_left > 0 ) ;
 
 # we truncate regular files in case we overwrite a long file with a shorter file
 # so seek to the current position to get it (same as tell()).
 
 	truncate( $write_fh,
 		  sysseek( $write_fh, 0, SEEK_CUR ) ) unless $no_truncate ;
 
 	close( $write_fh ) ;
 
 # handle the atomic mode - move the temp file to the original filename.
 
 	if ( $opts->{'atomic'} && !rename( $file_name, $orig_file_name ) ) {
 
 		@_ = ( $opts, "write_file '$file_name' - rename: $!" ) ;
 		goto &_error ;
 	}
 
 	return 1 ;
 }
 
 # this is for backwards compatibility with the previous File::Slurp module. 
 # write_file always overwrites an existing file
 
 *overwrite_file = \&write_file ;
 
 # the current write_file has an append mode so we use that. this
 # supports the same API with an optional second argument which is a
 # hash ref of options.
 
 sub append_file {
 
 # get the optional opts hash ref
 	my $opts = $_[1] ;
 	if ( ref $opts eq 'HASH' ) {
 
 # we were passed an opts ref so just mark the append mode
 
 		$opts->{append} = 1 ;
 	}
 	else {
 
 # no opts hash so insert one with the append mode
 
 		splice( @_, 1, 0, { append => 1 } ) ;
 	}
 
 # magic goto the main write_file sub. this overlays the sub without touching
 # the stack or @_
 
 	goto &write_file
 }
 
 # prepend data to the beginning of a file
 
 sub prepend_file {
 
 	my $file_name = shift ;
 
 #print "FILE $file_name\n" ;
 
 	my $opts = ( ref $_[0] eq 'HASH' ) ? shift : {} ;
 
 # delete unsupported options
 
 	my @bad_opts =
 		grep $_ ne 'err_mode' && $_ ne 'binmode', keys %{$opts} ;
 
 	delete @{$opts}{@bad_opts} ;
 
 	my $prepend_data = shift ;
 	$prepend_data = '' unless defined $prepend_data ;
 	$prepend_data = ${$prepend_data} if ref $prepend_data eq 'SCALAR' ;
 
 #print "PRE [$prepend_data]\n" ;
 
 	my $err_mode = delete $opts->{err_mode} ;
 	$opts->{ err_mode } = 'croak' ;
 	$opts->{ scalar_ref } = 1 ;
 
 	my $existing_data = eval { read_file( $file_name, $opts ) } ;
 
 	if ( $@ ) {
 
 		@_ = ( { err_mode => $err_mode },
 			"prepend_file '$file_name' - read_file: $!" ) ;
 		goto &_error ;
 	}
 
 #print "EXIST [$$existing_data]\n" ;
 
 	$opts->{atomic} = 1 ;
 	my $write_result =
 		eval { write_file( $file_name, $opts,
 		       $prepend_data, $$existing_data ) ;
 	} ;
 
 	if ( $@ ) {
 
 		@_ = ( { err_mode => $err_mode },
 			"prepend_file '$file_name' - write_file: $!" ) ;
 		goto &_error ;
 	}
 
 	return $write_result ;
 }
 
 # edit a file as a scalar in $_
 
 sub edit_file(&$;$) {
 
 	my( $edit_code, $file_name, $opts ) = @_ ;
 	$opts = {} unless ref $opts eq 'HASH' ;
 
 # 	my $edit_code = shift ;
 # 	my $file_name = shift ;
 # 	my $opts = ( ref $_[0] eq 'HASH' ) ? shift : {} ;
 
 #print "FILE $file_name\n" ;
 
 # delete unsupported options
 
 	my @bad_opts =
 		grep $_ ne 'err_mode' && $_ ne 'binmode', keys %{$opts} ;
 
 	delete @{$opts}{@bad_opts} ;
 
 # keep the user err_mode and force croaking on internal errors
 
 	my $err_mode = delete $opts->{err_mode} ;
 	$opts->{ err_mode } = 'croak' ;
 
 # get a scalar ref for speed and slurp the file into a scalar
 
 	$opts->{ scalar_ref } = 1 ;
 	my $existing_data = eval { read_file( $file_name, $opts ) } ;
 
 	if ( $@ ) {
 
 		@_ = ( { err_mode => $err_mode },
 			"edit_file '$file_name' - read_file: $!" ) ;
 		goto &_error ;
 	}
 
 #print "EXIST [$$existing_data]\n" ;
 
 	my( $edited_data ) = map { $edit_code->(); $_ } $$existing_data ;
 
 	$opts->{atomic} = 1 ;
 	my $write_result =
 		eval { write_file( $file_name, $opts, $edited_data ) } ;
 
 	if ( $@ ) {
 
 		@_ = ( { err_mode => $err_mode },
 			"edit_file '$file_name' - write_file: $!" ) ;
 		goto &_error ;
 	}
 
 	return $write_result ;
 }
 
 sub edit_file_lines(&$;$) {
 
 	my( $edit_code, $file_name, $opts ) = @_ ;
 	$opts = {} unless ref $opts eq 'HASH' ;
 
 # 	my $edit_code = shift ;
 # 	my $file_name = shift ;
 # 	my $opts = ( ref $_[0] eq 'HASH' ) ? shift : {} ;
 
 #print "FILE $file_name\n" ;
 
 # delete unsupported options
 
 	my @bad_opts =
 		grep $_ ne 'err_mode' && $_ ne 'binmode', keys %{$opts} ;
 
 	delete @{$opts}{@bad_opts} ;
 
 # keep the user err_mode and force croaking on internal errors
 
 	my $err_mode = delete $opts->{err_mode} ;
 	$opts->{ err_mode } = 'croak' ;
 
 # get an array ref for speed and slurp the file into lines
 
 	$opts->{ array_ref } = 1 ;
 	my $existing_data = eval { read_file( $file_name, $opts ) } ;
 
 	if ( $@ ) {
 
 		@_ = ( { err_mode => $err_mode },
 			"edit_file_lines '$file_name' - read_file: $!" ) ;
 		goto &_error ;
 	}
 
 #print "EXIST [$$existing_data]\n" ;
 
 	my @edited_data = map { $edit_code->(); $_ } @$existing_data ;
 
 	$opts->{atomic} = 1 ;
 	my $write_result =
 		eval { write_file( $file_name, $opts, @edited_data ) } ;
 
 	if ( $@ ) {
 
 		@_ = ( { err_mode => $err_mode },
 			"edit_file_lines '$file_name' - write_file: $!" ) ;
 		goto &_error ;
 	}
 
 	return $write_result ;
 }
 
 # basic wrapper around opendir/readdir
 
 sub read_dir {
 
 	my $dir = shift ;
 	my $opts = ( ref $_[0] eq 'HASH' ) ? shift : { @_ } ;
 
 # this handle will be destroyed upon return
 
 	local(*DIRH);
 
 # open the dir and handle any errors
 
 	unless ( opendir( DIRH, $dir ) ) {
 
 		@_ = ( $opts, "read_dir '$dir' - opendir: $!" ) ;
 		goto &_error ;
 	}
 
 	my @dir_entries = readdir(DIRH) ;
 
 	@dir_entries = grep( $_ ne "." && $_ ne "..", @dir_entries )
 		unless $opts->{'keep_dot_dot'} ;
 
 	if ( $opts->{'prefix'} ) {
 
 		substr( $_, 0, 0, "$dir/" ) for @dir_entries ;
 	}
 
 	return @dir_entries if wantarray ;
 	return \@dir_entries ;
 }
 
 # error handling section
 #
 # all the error handling uses magic goto so the caller will get the
 # error message as if from their code and not this module. if we just
 # did a call on the error code, the carp/croak would report it from
 # this module since the error sub is one level down on the call stack
 # from read_file/write_file/read_dir.
 
 
 my %err_func = (
 	'carp'	=> \&carp,
 	'croak'	=> \&croak,
 ) ;
 
 sub _error {
 
 	my( $opts, $err_msg ) = @_ ;
 
 # get the error function to use
 
  	my $func = $err_func{ $opts->{'err_mode'} || 'croak' } ;
 
 # if we didn't find it in our error function hash, they must have set
 # it to quiet and we don't do anything.
 
 	return unless $func ;
 
 # call the carp/croak function
 
 	$func->($err_msg) if $func ;
 
 # return a hard undef (in list context this will be a single value of
 # undef which is not a legal in-band value)
 
 	return undef ;
 }
 
 1;
 __END__
 
 =head1 NAME
 
 File::Slurp - Simple and Efficient Reading/Writing/Modifying of Complete Files
 
 =head1 SYNOPSIS
 
   use File::Slurp;
 
 # read in a whole file into a scalar
   my $text = read_file( 'filename' ) ;
 
 # read in a whole file into an array of lines
   my @lines = read_file( 'filename' ) ;
 
 # write out a whole file from a scalar
   write_file( 'filename', $text ) ;
 
 # write out a whole file from an array of lines
   write_file( 'filename', @lines ) ;
 
 # Here is a simple and fast way to load and save a simple config file
 # made of key=value lines.
   my %conf = read_file( $file_name ) =~ /^(\w+)=(.*)$/mg ;
   write_file( $file_name, {atomic => 1}, map "$_=$conf{$_}\n", keys %conf ) ;
 
 # insert text at the beginning of a file
   prepend_file( 'filename', $text ) ;
 
 # in-place edit to replace all 'foo' with 'bar' in file 
   edit_file { s/foo/bar/g } 'filename' ;
 
 # in-place edit to delete all lines with 'foo' from file
   edit_file_lines sub { $_ = '' if /foo/ }, 'filename' ;
 
 # read in a whole directory of file names (skipping . and ..)
   my @files = read_dir( '/path/to/dir' ) ;
 
 =head1 DESCRIPTION
 
 This module provides subs that allow you to read or write entire files
 with one simple call. They are designed to be simple to use, have
 flexible ways to pass in or get the file contents and to be very
 efficient.  There is also a sub to read in all the files in a
 directory other than C<.> and C<..>
 
 These slurp/spew subs work for files, pipes and sockets, stdio,
 pseudo-files, and the DATA handle. Read more about why slurping files is
 a good thing in the file 'slurp_article.pod' in the extras/ directory.
 
 If you are interested in how fast these calls work, check out the
 slurp_bench.pl program in the extras/ directory. It compares many
 different forms of slurping. You can select the I/O direction, context
 and file sizes. Use the --help option to see how to run it.
 
 =head2 B<read_file>
 
 This sub reads in an entire file and returns its contents to the
 caller.  In scalar context it returns the entire file as a single
 scalar. In list context it will return a list of lines (using the
 current value of $/ as the separator including support for paragraph
 mode when it is set to '').
 
   my $text = read_file( 'filename' ) ;
   my $bin = read_file( 'filename' { binmode => ':raw' } ) ;
   my @lines = read_file( 'filename' ) ;
   my $lines = read_file( 'filename', array_ref => 1 ) ;
 
 The first argument is the file to slurp in. If the next argument is a
 hash reference, then it is used as the options. Otherwise the rest of
 the argument list are is used as key/value options.
 
 If the file argument is a handle (if it is a ref and is an IO or GLOB
 object), then that handle is slurped in. This mode is supported so you
 slurp handles such as C<DATA> and C<STDIN>. See the test handle.t for
 an example that does C<open( '-|' )> and the child process spews data
 to the parant which slurps it in.  All of the options that control how
 the data is returned to the caller still work in this case.
 
 If the first argument is an overloaded object then its stringified value
 is used for the filename and that file is opened.  This is a new feature
 in 9999.14. See the stringify.t test for an example.
 
 By default C<read_file> returns an undef in scalar contex or a single
 undef in list context if it encounters an error. Those are both
 impossible to get with a clean read_file call which means you can check
 the return value and always know if you had an error. You can change how
 errors are handled with the C<err_mode> option.
 
 Speed Note: If you call read_file and just get a scalar return value
 it is now optimized to handle shorter files. This is only used if no
 options are used, the file is shorter then 100k bytes, the filename is
 a plain scalar and a scalar file is returned. If you want the fastest
 slurping, use the C<buf_ref> or C<scalar_ref> options (see below)
 
 NOTE: as of version 9999.06, read_file works correctly on the C<DATA>
 handle. It used to need a sysseek workaround but that is now handled
 when needed by the module itself.
 
 You can optionally request that C<slurp()> is exported to your code. This
 is an alias for read_file and is meant to be forward compatible with
 Perl 6 (which will have slurp() built-in).
 
 The options for C<read_file> are:
 
 =head3 binmode
 
 If you set the binmode option, then its value is passed to a call to
 binmode on the opened handle. You can use this to set the file to be
 read in binary mode, utf8, etc. See perldoc -f binmode for more.
 
 	my $bin_data = read_file( $bin_file, binmode => ':raw' ) ;
 	my $utf_text = read_file( $bin_file, binmode => ':utf8' ) ;
 
 =head3 array_ref
 
 If this boolean option is set, the return value (only in scalar
 context) will be an array reference which contains the lines of the
 slurped file. The following two calls are equivalent:
 
 	my $lines_ref = read_file( $bin_file, array_ref => 1 ) ;
 	my $lines_ref = [ read_file( $bin_file ) ] ;
 
 =head3 chomp
 
 If this boolean option is set, the lines are chomped. This only
 happens if you are slurping in a list context or using the
 C<array_ref> option.
 
 =head3 scalar_ref
 
 If this boolean option is set, the return value (only in scalar
 context) will be an scalar reference to a string which is the contents
 of the slurped file. This will usually be faster than returning the
 plain scalar. It will also save memory as it will not make a copy of
 the file to return. Run the extras/slurp_bench.pl script to see speed
 comparisons.
 
 	my $text_ref = read_file( $bin_file, scalar_ref => 1 ) ;
 
 =head3 buf_ref
 
 You can use this option to pass in a scalar reference and the slurped
 file contents will be stored in the scalar. This can be used in
 conjunction with any of the other options. This saves an extra copy of
 the slurped file and can lower ram usage vs returning the file. It is
 usually the fastest way to read a file into a scalar. Run the
 extras/slurp_bench.pl script to see speed comparisons.
 
 
 	read_file( $bin_file, buf_ref => \$buffer ) ;
 
 =head3 blk_size
 
 You can use this option to set the block size used when slurping from
 an already open handle (like \*STDIN). It defaults to 1MB.
 
 	my $text_ref = read_file( $bin_file, blk_size => 10_000_000,
 					     array_ref => 1 ) ;
 
 =head3 err_mode
 
 You can use this option to control how read_file behaves when an error
 occurs. This option defaults to 'croak'. You can set it to 'carp' or to
 'quiet to have no special error handling. This code wants to carp and
 then read another file if it fails.
 
 	my $text_ref = read_file( $file, err_mode => 'carp' ) ;
 	unless ( $text_ref ) {
 
 		# read a different file but croak if not found
 		$text_ref = read_file( $another_file ) ;
 	}
 	
 	# process ${$text_ref}
 
 =head2 B<write_file>
 
 This sub writes out an entire file in one call.
 
   write_file( 'filename', @data ) ;
 
 The first argument to C<write_file> is the filename. The next argument
 is an optional hash reference and it contains key/values that can
 modify the behavior of C<write_file>. The rest of the argument list is
 the data to be written to the file.
 
   write_file( 'filename', {append => 1 }, @data ) ;
   write_file( 'filename', {binmode => ':raw'}, $buffer ) ;
 
 As a shortcut if the first data argument is a scalar or array reference,
 it is used as the only data to be written to the file. Any following
 arguments in @_ are ignored. This is a faster way to pass in the output
 to be written to the file and is equivalent to the C<buf_ref> option of
 C<read_file>. These following pairs are equivalent but the pass by
 reference call will be faster in most cases (especially with larger
 files).
 
   write_file( 'filename', \$buffer ) ;
   write_file( 'filename', $buffer ) ;
 
   write_file( 'filename', \@lines ) ;
   write_file( 'filename', @lines ) ;
 
 If the first argument is a handle (if it is a ref and is an IO or GLOB
 object), then that handle is written to. This mode is supported so you
 spew to handles such as \*STDOUT. See the test handle.t for an example
 that does C<open( '-|' )> and child process spews data to the parent
 which slurps it in.  All of the options that control how the data are
 passed into C<write_file> still work in this case.
 
 If the first argument is an overloaded object then its stringified value
 is used for the filename and that file is opened.  This is new feature
 in 9999.14. See the stringify.t test for an example.
 
 By default C<write_file> returns 1 upon successfully writing the file or
 undef if it encountered an error. You can change how errors are handled
 with the C<err_mode> option.
 
 The options are:
 
 =head3 binmode
 
 If you set the binmode option, then its value is passed to a call to
 binmode on the opened handle. You can use this to set the file to be
 read in binary mode, utf8, etc. See perldoc -f binmode for more.
 
 	write_file( $bin_file, {binmode => ':raw'}, @data ) ;
 	write_file( $bin_file, {binmode => ':utf8'}, $utf_text ) ;
 
 =head3 perms
 
 The perms option sets the permissions of newly-created files. This value
 is modified by your process's umask and defaults to 0666 (same as
 sysopen).
 
 NOTE: this option is new as of File::Slurp version 9999.14;
 
 =head3 buf_ref
 
 You can use this option to pass in a scalar reference which has the
 data to be written. If this is set then any data arguments (including
 the scalar reference shortcut) in @_ will be ignored. These are
 equivalent:
 
 	write_file( $bin_file, { buf_ref => \$buffer } ) ;
 	write_file( $bin_file, \$buffer ) ;
 	write_file( $bin_file, $buffer ) ;
 
 =head3 atomic
 
 If you set this boolean option, the file will be written to in an
 atomic fashion. A temporary file name is created by appending the pid
 ($$) to the file name argument and that file is spewed to. After the
 file is closed it is renamed to the original file name (and rename is
 an atomic operation on most OS's). If the program using this were to
 crash in the middle of this, then the file with the pid suffix could
 be left behind.
 
 =head3 append
 
 If you set this boolean option, the data will be written at the end of
 the current file. Internally this sets the sysopen mode flag O_APPEND.
 
 	write_file( $file, {append => 1}, @data ) ;
 
  You
 can import append_file and it does the same thing.
 
 =head3 no_clobber
 
 If you set this boolean option, an existing file will not be overwritten.
 
 	write_file( $file, {no_clobber => 1}, @data ) ;
 
 =head3 err_mode
 
 You can use this option to control how C<write_file> behaves when an
 error occurs. This option defaults to 'croak'. You can set it to
 'carp' or to 'quiet' to have no error handling other than the return
 value. If the first call to C<write_file> fails it will carp and then
 write to another file. If the second call to C<write_file> fails, it
 will croak.
 
 	unless ( write_file( $file, { err_mode => 'carp', \$data ) ;
 
 		# write a different file but croak if not found
 		write_file( $other_file, \$data ) ;
 	}
 
 =head2 overwrite_file
 
 This sub is just a typeglob alias to write_file since write_file
 always overwrites an existing file. This sub is supported for
 backwards compatibility with the original version of this module. See
 write_file for its API and behavior.
 
 =head2 append_file
 
 This sub will write its data to the end of the file. It is a wrapper
 around write_file and it has the same API so see that for the full
 documentation. These calls are equivalent:
 
 	append_file( $file, @data ) ;
 	write_file( $file, {append => 1}, @data ) ;
 
 
 =head2 prepend_file
 
 This sub writes data to the beginning of a file. The previously existing
 data is written after that so the effect is prepending data in front of
 a file. It is a counterpart to the append_file sub in this module. It
 works by first using C<read_file> to slurp in the file and then calling
 C<write_file> with the new data and the existing file data.
 
 The first argument to C<prepend_file> is the filename. The next argument
 is an optional hash reference and it contains key/values that can modify
 the behavior of C<prepend_file>. The rest of the argument list is the
 data to be written to the file and that is passed to C<write_file> as is
 (see that for allowed data).
 
 Only the C<binmode> and C<err_mode> options are supported. The
 C<write_file> call has the C<atomic> option set so you will always have
 a consistant file. See above for more about those options.
 
 C<prepend_file> is not exported by default, you need to import it
 explicitly.
 
 	use File::Slurp qw( prepend_file ) ;
 	prepend_file( $file, $header ) ;
 	prepend_file( $file, \@lines ) ;
 	prepend_file( $file, { binmode => 'raw:'}, $bin_data ) ;
 
 
 =head2 edit_file, edit_file_lines
 
 These subs read in a file into $_, execute a code block which should
 modify $_ and then write $_ back to the file. The difference between
 them is that C<edit_file> reads the whole file into $_ and calls the
 code block one time. With C<edit_file_lines> each line is read into $_
 and the code is called for each line. In both cases the code should
 modify $_ if desired and it will be written back out. These subs are
 the equivalent of the -pi command line options of Perl but you can
 call them from inside your program and not fork out a process. They
 are in @EXPORT_OK so you need to request them to be imported on the
 use line or you can import both of them with:
 
 	use File::Slurp qw( :edit ) ;
 
 The first argument to C<edit_file> and C<edit_file_lines> is a code
 block or a code reference. The code block is not followed by a comma
 (as with grep and map) but a code reference is followed by a
 comma. See the examples below for both styles. The next argument is
 the filename. The last argument is an optional hash reference and it
 contains key/values that can modify the behavior of
 C<prepend_file>. 
 
 Only the C<binmode> and C<err_mode> options are supported. The
 C<write_file> call has the C<atomic> option set so you will always
 have a consistant file. See above for more about those options.
 
 Each group of calls below show a Perl command line instance and the
 equivalent calls to C<edit_file> and C<edit_file_lines>.
 
 	perl -0777 -pi -e 's/foo/bar/g' filename
 	use File::Slurp qw( edit_file ) ;
 	edit_file { s/foo/bar/g } 'filename' ;
 	edit_file sub { s/foo/bar/g }, 'filename' ;
 	edit_file \&replace_foo, 'filename' ;
 	sub replace_foo { s/foo/bar/g }
 
 	perl -pi -e '$_ = "" if /foo/' filename
 	use File::Slurp qw( edit_file_lines ) ;
 	use File::Slurp ;
 	edit_file_lines { $_ = '' if /foo/ } 'filename' ;
 	edit_file_lines sub { $_ = '' if /foo/ }, 'filename' ;
 	edit_file \&delete_foo, 'filename' ;
 	sub delete_foo { $_ = '' if /foo/ }
 
 =head2 read_dir
 
 This sub reads all the file names from directory and returns them to
 the caller but C<.> and C<..> are removed by default.
 
 	my @files = read_dir( '/path/to/dir' ) ;
 
 The first argument is the path to the directory to read.  If the next
 argument is a hash reference, then it is used as the options.
 Otherwise the rest of the argument list are is used as key/value
 options.
 
 In list context C<read_dir> returns a list of the entries in the
 directory. In a scalar context it returns an array reference which has
 the entries.
 
 =head3 err_mode
 
 If the C<err_mode> option is set, it selects how errors are handled (see
 C<err_mode> in C<read_file> or C<write_file>).
 
 =head3 keep_dot_dot
 
 If this boolean option is set, C<.> and C<..> are not removed from the
 list of files.
 
 	my @all_files = read_dir( '/path/to/dir', keep_dot_dot => 1 ) ;
 
 =head3 prefix
 
 If this boolean option is set, the string "$dir/" is prefixed to each
 dir entry. This means you can directly use the results to open
 files. A common newbie mistake is not putting the directory in front
 of entries when opening themn.
 
 	my @paths = read_dir( '/path/to/dir', prefix => 1 ) ;
 
 =head2 EXPORT
 
   These are exported by default or with
 	use File::Slurp qw( :std ) ;
 
   read_file write_file overwrite_file append_file read_dir
 
   These are exported with
 	use File::Slurp qw( :edit ) ;
 
   edit_file edit_file_lines
 
   You can get all subs in the module exported with 
 	use File::Slurp qw( :all ) ;
 
 =head2 LICENSE
 
   Same as Perl.
 
 =head2 SEE ALSO
 
 An article on file slurping in extras/slurp_article.pod. There is
 also a benchmarking script in extras/slurp_bench.pl.
 
 =head2 BUGS
 
 If run under Perl 5.004, slurping from the DATA handle will fail as
 that requires B.pm which didn't get into core until 5.005.
 
 =head1 AUTHOR
 
 Uri Guttman, E<lt>uri AT stemsystems DOT comE<gt>
 
 =cut
### File/Slurp/Tiny.pm ###
 package File::Slurp::Tiny;
 $File::Slurp::Tiny::VERSION = '0.004';
 use strict;
 use warnings;
 
 use Carp 'croak';
 use Exporter 5.57 'import';
 use File::Spec::Functions 'catfile';
 use FileHandle;
 our @EXPORT_OK = qw/read_file read_lines write_file read_dir/;
 
 my $default_layer = $^O eq 'MSWin32' ? ':crlf' : ':unix';
 
 sub read_file {
 	my ($filename, %options) = @_;
 	my $layer = $options{binmode} || $default_layer;
 	my $buf_ref = defined $options{buf_ref} ? $options{buf_ref} : \my $buf;
 
 	open my $fh, "<$layer", $filename or croak "Couldn't open $filename: $!";
 	if (my $size = -s $fh) {
 		my ($pos, $read) = 0;
 		do {
 			defined($read = read $fh, ${$buf_ref}, $size - $pos, $pos) or croak "Couldn't read $filename: $!";
 			$pos += $read;
 		} while ($read && $pos < $size);
 	}
 	else {
 		${$buf_ref} = do { local $/; <$fh> };
 	}
 	close $fh;
 	return if not defined wantarray or $options{buf_ref};
 	return $options{scalar_ref} ? $buf_ref : $buf;
 }
 
 sub read_lines {
 	my ($filename, %options) = @_;
 	my $layer = delete $options{binmode} || ':';
 	
 	open my $fh, "<$layer", $filename or croak "Couldn't open $filename: $!";
 	return <$fh> if not %options;
 	my @buf = <$fh>;
 	close $fh;
 	chomp @buf if $options{chomp};
 	return $options{array_ref} ? \@buf : @buf;
 }
 
 sub write_file {
 	my ($filename, undef, %options) = @_;
 	my $layer = $options{binmode} || $default_layer;
 	my $mode = $options{append} ? '>>' : '>';
 	my $buf_ref = defined $options{buf_ref} ? $options{buf_ref} : \$_[1];
 
 	open my $fh, $mode.$layer, $filename or croak "Couldn't open $filename: $!";
 	$fh->autoflush(1);
 	print $fh ${$buf_ref} or croak "Couldn't write to $filename: $!";
 	close $fh or croak "Couldn't close $filename: $!";
 	return;
 }
 
 sub read_dir {
 	my ($dirname, %options) = @_;
 	opendir my ($dir), $dirname or croak "Could not open $dirname: $!";
 	my @ret = grep { not m/ \A \.\.? \z /x } readdir $dir;
 	@ret = map { catfile($dirname, $_) } @ret if $options{prefix};
 	closedir $dir;
 	return @ret;
 }
 
 1;
 
 # ABSTRACT: A simple, sane and efficient file slurper [DISCOURAGED]
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 File::Slurp::Tiny - A simple, sane and efficient file slurper [DISCOURAGED]
 
 =head1 VERSION
 
 version 0.004
 
 =head1 SYNOPSIS
 
  use File::Slurp::Tiny 'read_file';
  my $content = read_file($filename);
 
 =head1 DISCOURAGED
 
 B<This module is discouraged in favor of L<File::Slurper|File::Slurper>>. While a useful experiment, it turned out to be both too similar to File::Slurp (still containing most problematic features of File::Slurp's interface) and yet not similar enough to be a true drop-in replacement.
 
 Bugs will still be fixed, but new features will probably not be added.
 
 =head1 DESCRIPTION
 
 This module provides functions for fast and correct slurping and spewing. All functions are optionally exported.
 
 =head1 FUNCTIONS
 
 =head2 read_file($filename, %options)
 
 Reads file C<$filename> into a scalar. By default it returns this scalar. Can optionally take these named arguments:
 
 =over 4
 
 =item * binmode
 
 Set the layers to read the file with. The default will be something sensible on your platform.
 
 =item * buf_ref
 
 Pass a reference to a scalar to read the file into, instead of returning it by value. This has performance benefits.
 
 =item * scalar_ref
 
 If set to true, C<read_file> will return a reference to a scalar containing the file content.
 
 =back
 
 =head2 read_lines($filename, %options)
 
 Reads file C<$filename> into a list/array. By default it returns this list. Can optionally take these named arguments:
 
 =over 4
 
 =item * binmode
 
 Set the layers to read the file with. The default will be something sensible on your platform.
 
 =item * array_ref
 
 Pass a reference to an array to read the lines into, instead of returning them by value. This has performance benefits.
 
 =item * chomp
 
 C<chomp> the lines.
 
 =back
 
 =head2 write_file($filename, $content, %options)
 
 Open C<$filename>, and write C<$content> to it. Can optionally take this named argument:
 
 =over 4
 
 =item * binmode
 
 Set the layers to write the file with. The default will be something sensible on your platform.
 
 =back
 
 =head2 read_dir($dirname, %options)
 
 Open C<dirname> and return all entries except C<.> and C<..>. Can optionally take this named argument:
 
 =over 4
 
 =item * prefix
 
 This will prepend C<$dir> to the entries
 
 =back
 
 =head1 SEE ALSO
 
 =over 4
 
 =item * L<Path::Tiny>
 
 A minimalistic abstraction not only around 
 
 =item * L<File::Slurp>
 
 Another file slurping tool.
 
 =back
 
 =head1 AUTHOR
 
 Leon Timmermans <leont@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2013 by Leon Timmermans.
 
 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
### File/Which.pm ###
 package File::Which;
 
 use strict;
 use warnings;
 use Exporter   ();
 use File::Spec ();
 
 # ABSTRACT: Perl implementation of the which utility as an API
 our $VERSION = '1.19'; # VERSION
 
 
 our @ISA       = 'Exporter';
 our @EXPORT    = 'which';
 our @EXPORT_OK = 'where';
 
 use constant IS_VMS => ($^O eq 'VMS');
 use constant IS_MAC => ($^O eq 'MacOS');
 use constant IS_DOS => ($^O eq 'MSWin32' or $^O eq 'dos' or $^O eq 'os2');
 use constant IS_CYG => ($^O eq 'cygwin');
 
 # For Win32 systems, stores the extensions used for
 # executable files
 # For others, the empty string is used
 # because 'perl' . '' eq 'perl' => easier
 my @PATHEXT = ('');
 if ( IS_DOS ) {
   # WinNT. PATHEXT might be set on Cygwin, but not used.
   if ( $ENV{PATHEXT} ) {
     push @PATHEXT, split ';', $ENV{PATHEXT};
   } else {
     # Win9X or other: doesn't have PATHEXT, so needs hardcoded.
     push @PATHEXT, qw{.com .exe .bat};
   }
 } elsif ( IS_VMS ) {
   push @PATHEXT, qw{.exe .com};
 } elsif ( IS_CYG ) {
   # See this for more info
   # http://cygwin.com/cygwin-ug-net/using-specialnames.html#pathnames-exe
   push @PATHEXT, qw{.exe .com};
 }
 
 
 sub which {
   my ($exec) = @_;
 
   return undef unless $exec;
 
   my $all = wantarray;
   my @results = ();
 
   # check for aliases first
   if ( IS_VMS ) {
     my $symbol = `SHOW SYMBOL $exec`;
     chomp($symbol);
     unless ( $? ) {
       return $symbol unless $all;
       push @results, $symbol;
     }
   }
   if ( IS_MAC ) {
     my @aliases = split /\,/, $ENV{Aliases};
     foreach my $alias ( @aliases ) {
       # This has not been tested!!
       # PPT which says MPW-Perl cannot resolve `Alias $alias`,
       # let's just hope it's fixed
       if ( lc($alias) eq lc($exec) ) {
         chomp(my $file = `Alias $alias`);
         last unless $file;  # if it failed, just go on the normal way
         return $file unless $all;
         push @results, $file;
         # we can stop this loop as if it finds more aliases matching,
         # it'll just be the same result anyway
         last;
       }
     }
   }
 
   return $exec
           if !IS_VMS and !IS_MAC and !IS_DOS and $exec =~ /\// and -f $exec and -x $exec;
 
   my @path = File::Spec->path;
   if ( IS_DOS or IS_VMS or IS_MAC ) {
     unshift @path, File::Spec->curdir;
   }
 
   foreach my $base ( map { File::Spec->catfile($_, $exec) } @path ) {
     for my $ext ( @PATHEXT ) {
       my $file = $base.$ext;
 
       # We don't want dirs (as they are -x)
       next if -d $file;
 
       if (
         # Executable, normal case
         -x _
         or (
           # MacOS doesn't mark as executable so we check -e
           IS_MAC
           ||
           (
             ( IS_DOS or IS_CYG )
             and
             grep {
               $file =~ /$_\z/i
             } @PATHEXT[1..$#PATHEXT]
           )
           # DOSish systems don't pass -x on
           # non-exe/bat/com files. so we check -e.
           # However, we don't want to pass -e on files
           # that aren't in PATHEXT, like README.
           and -e _
         )
       ) {
         return $file unless $all;
         push @results, $file;
       }
     }
   }
 
   if ( $all ) {
     return @results;
   } else {
     return undef;
   }
 }
 
 
 sub where {
   # force wantarray
   my @res = which($_[0]);
   return @res;
 }
 
 1;
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 File::Which - Perl implementation of the which utility as an API
 
 =head1 VERSION
 
 version 1.19
 
 =head1 SYNOPSIS
 
  use File::Which;                  # exports which()
  use File::Which qw(which where);  # exports which() and where()
  
  my $exe_path = which 'perldoc';
  
  my @paths = where 'perl';
  # Or
  my @paths = which 'perl'; # an array forces search for all of them
 
 =head1 DESCRIPTION
 
 L<File::Which> finds the full or relative paths to executable programs on
 the system.  This is normally the function of C<which> utility.  C<which> is
 typically implemented as either a program or a built in shell command.  On
 some platforms, such as Microsoft Windows it is not provided as part of the
 core operating system.  This module provides a consistent API to this
 functionality regardless of the underlying platform.
 
 The focus of this module is correctness and portability.  As a consequence
 platforms where the current directory is implicitly part of the search path
 such as Microsoft Windows will find executables in the current directory,
 whereas on platforms such as UNIX where this is not the case executables 
 in the current directory will only be found if the current directory is
 explicitly added to the path.
 
 If you need a portable C<which> on the command line in an environment that
 does not provide it, install L<App::pwhich> which provides a command line
 interface to this API.
 
 =head2 Implementations
 
 L<File::Which> searches the directories of the user's C<PATH> (the current
 implementation uses L<File::Spec#path> to determine the correct C<PATH>),
 looking for executable files having the name specified as a parameter to
 L</which>. Under Win32 systems, which do not have a notion of directly
 executable files, but uses special extensions such as C<.exe> and C<.bat>
 to identify them, C<File::Which> takes extra steps to assure that
 you will find the correct file (so for example, you might be searching for
 C<perl>, it'll try F<perl.exe>, F<perl.bat>, etc.)
 
 =head3 Linux, *BSD and other UNIXes
 
 There should not be any surprises here.  The current directory will not be
 searched unless it is explicitly added to the path.
 
 =head3 Modern Windows (including NT, XP, Vista, 7, 8, 10 etc)
 
 Windows NT has a special environment variable called C<PATHEXT>, which is used
 by the shell to look for executable files. Usually, it will contain a list in
 the form C<.EXE;.BAT;.COM;.JS;.VBS> etc. If C<File::Which> finds such an
 environment variable, it parses the list and uses it as the different
 extensions.
 
 =head3 Cygwin
 
 Cygwin provides a Unix-like environment for Microsoft Windows users.  In most
 ways it works like other Unix and Unix-like environments, but in a few key
 aspects it works like Windows.  As with other Unix environments, the current
 directory is not included in the search unless it is explicitly included in
 the search path.  Like on Windows, files with C<.EXE> or <.BAT> extensions will
 be discovered even if they are not part of the query.  C<.COM> or extensions
 specified using the C<PATHEXT> environment variable will NOT be discovered
 without the fully qualified name, however.
 
 =head3 Windows 95, 98, ME, MS-DOS, OS/2
 
 This set of operating systems don't have the C<PATHEXT> variable, and usually
 you will find executable files there with the extensions C<.exe>, C<.bat> and
 (less likely) C<.com>. C<File::Which> uses this hardcoded list if it's running
 under Win32 but does not find a C<PATHEXT> variable.
 
 As of 2015 none of these platforms are tested frequently (or perhaps ever),
 but the current maintainer is determined not to intentionally remove support
 for older operating systems.
 
 =head3 VMS
 
 Same case as Windows 9x: uses C<.exe> and C<.com> (in that order).
 
 As of 2015 the current maintainer does not test on VMS, and is in fact not
 certain it has ever been tested on VMS.  If this platform is important to you
 and you can help me verify and or support it on that platform please contact
 me.
 
 =head1 FUNCTIONS
 
 =head2 which
 
  my $path = which $short_exe_name;
  my @paths = which $short_exe_name;
 
 Exported by default.
 
 C<$short_exe_name> is the name used in the shell to call the program (for
 example, C<perl>).
 
 If it finds an executable with the name you specified, C<which()> will return
 the absolute path leading to this executable (for example, F</usr/bin/perl> or
 F<C:\Perl\Bin\perl.exe>).
 
 If it does I<not> find the executable, it returns C<undef>.
 
 If C<which()> is called in list context, it will return I<all> the
 matches.
 
 =head2 where
 
  my @paths = where $short_exe_name;
 
 Not exported by default.
 
 Same as L</which> in array context. Same as the
 C<where> utility, will return an array containing all the path names
 matching C<$short_exe_name>.
 
 =head1 CAVEATS
 
 This module has no non-core requirements for Perl 5.6.2 and better.
 
 This module is fully supported back to Perl 5.8.1.  It may work on 5.8.0.  
 It should work on Perl 5.6.x and I may even test on 5.6.2.  I will accept
 patches to maintain compatibility for such older Perls, but you may
 need to fix it on 5.6.x / 5.8.0 and send me a patch.
 
 Not tested on VMS although there is platform specific code
 for those. Anyone who haves a second would be very kind to send me a
 report of how it went.
 
 =head1 SUPPORT
 
 Bugs should be reported via the GitHub issue tracker
 
 L<https://github.com/plicease/File-Which/issues>
 
 For other issues, contact the maintainer.
 
 =head1 SEE ALSO
 
 =over 4
 
 =item L<pwhich>, L<App::pwhich>
 
 Command line interface to this module.
 
 =item L<IPC::Cmd>
 
 Comes with a C<can_run> function with slightly different semantics that
 the traditional UNIX where.  It will find executables in the current
 directory, even though the current directory is not searched for by
 default on Unix.
 
 =item L<Devel::CheckBin>
 
 This module purports to "check that a command is available", but does not
 provide any documentation on how you might use it.
 
 =back
 
 =head1 AUTHORS
 
 =over 4
 
 =item *
 
 Per Einar Ellefsen <pereinar@cpan.org>
 
 =item *
 
 Adam Kennedy <adamk@cpan.org>
 
 =item *
 
 Graham Ollis <plicease@cpan.org>
 
 =back
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2002 by Per Einar Ellefsen <pereinar@cpan.org>.
 
 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
### File/Write/Rotate.pm ###
 package File::Write::Rotate;
 
 our $DATE = '2015-10-20'; # DATE
 our $VERSION = '0.29'; # VERSION
 
 use 5.010001;
 use strict;
 use warnings;
 
 # we must not use Log::Any, looping if we are used as log output
 #use Log::Any '$log';
 
 use Carp;
 use File::Spec;
 use IO::Compress::Gzip qw(gzip $GzipError);
 use Scalar::Util qw(weaken);
 #use Taint::Runtime qw(untaint is_tainted);
 use Time::HiRes 'time';
 
 our $Debug;
 
 sub new {
     my $class = shift;
     my %args0 = @_;
 
     my %args;
 
     defined($args{dir} = delete $args0{dir})
         or croak "Please specify dir";
     defined($args{prefix} = delete $args0{prefix})
         or croak "Please specify prefix";
     $args{suffix} = delete($args0{suffix}) // "";
 
     $args{size} = delete($args0{size}) // 0;
 
     $args{period} = delete($args0{period});
     if ($args{period}) {
         $args{period} =~ /\A(daily|day|month|monthly|year|yearly)\z/
             or croak "Invalid period, please use daily/monthly/yearly";
     }
 
     for (map {"hook_$_"} qw(before_rotate after_rotate after_create
                             before_write a)) {
         next unless $args0{$_};
         $args{$_} = delete($args0{$_});
         croak "Invalid $_, please supply a coderef"
             unless ref($args{$_}) eq 'CODE';
     }
 
     if (!$args{period} && !$args{size}) {
         $args{size} = 10 * 1024 * 1024;
     }
 
     $args{histories} = delete($args0{histories}) // 10;
 
     $args{binmode} = delete($args0{binmode});
 
     $args{buffer_size} = delete($args0{buffer_size});
 
     $args{lock_mode} = delete($args0{lock_mode}) // 'write';
     $args{lock_mode} =~ /\A(none|write|exclusive)\z/
         or croak "Invalid lock_mode, please use none/write/exclusive";
 
     $args{rotate_probability} = delete($args0{rotate_probability});
     if (defined $args{rotate_probability}) {
         $args{rotate_probability} > 0 && $args{rotate_probability} < 1.0
             or croak "Invalid rotate_probability, must be 0 < x < 1";
     }
 
     if (keys %args0) {
         croak "Unknown arguments to new(): ".join(", ", sort keys %args0);
     }
 
     $args{_buffer} = [];
 
     my $self = bless \%args, $class;
 
     $self->{_exclusive_lock} = $self->_get_lock
         if $self->{lock_mode} eq 'exclusive';
 
     $self;
 }
 
 sub buffer_size {
     my $self = shift;
     if (@_) {
         my $old = $self->{buffer_size};
         $self->{buffer_size} = $_[0];
         return $old;
     } else {
         return $self->{buffer_size};
     }
 }
 
 sub handle {
     my $self = shift;
     $self->{_fh};
 }
 
 sub path {
     my $self = shift;
     $self->{_fp};
 }
 
 # file path, without the rotate suffix
 sub _file_path {
     my ($self) = @_;
 
     # _now is calculated every time we access this method
     $self->{_now} = time();
 
     my @lt = localtime($self->{_now});
     $lt[5] += 1900;
     $lt[4]++;
 
     my $period;
     if ($self->{period}) {
         if ($self->{period} =~ /year/i) {
             $period = sprintf("%04d", $lt[5]);
         } elsif ($self->{period} =~ /month/) {
             $period = sprintf("%04d-%02d", $lt[5], $lt[4]);
         } elsif ($self->{period} =~ /day|daily/) {
             $period = sprintf("%04d-%02d-%02d", $lt[5], $lt[4], $lt[3]);
         }
     } else {
         $period = "";
     }
 
     my $path = join(
         '',
         $self->{dir}, '/',
         $self->{prefix},
         length($period) ? ".$period" : "",
         $self->{suffix},
     );
     if (wantarray) {
         return ($path, $period);
     } else {
         return $path;
     }
 }
 
 sub lock_file_path {
     my ($self) = @_;
     return File::Spec->catfile($self->{dir}, $self->{prefix} . '.lck');
 }
 
 sub _get_lock {
     my ($self) = @_;
     return undef if $self->{lock_mode} eq 'none';
     return $self->{_weak_lock} if defined($self->{_weak_lock});
 
     require File::Flock::Retry;
     my $lock = File::Flock::Retry->lock($self->lock_file_path);
     $self->{_weak_lock} = $lock;
     weaken $self->{_weak_lock};
     return $lock;
 }
 
 # will return \@files. each entry is [filename without compress suffix,
 # rotate_suffix (for sorting), period (for sorting), compress suffix (for
 # renaming back)]
 sub _get_files {
     my ($self) = @_;
 
     opendir my ($dh), $self->{dir} or do {
         warn "Can't opendir '$self->{dir}': $!";
         return;
     };
 
     my @files;
     while (my $e = readdir($dh)) {
         my $cs = $1 if $e =~ s/(\.gz)\z//; # compress suffix
         next unless $e =~ /\A\Q$self->{prefix}\E
                            (?:\. (?<period>\d{4}(?:-\d\d(?:-\d\d)?)?) )?
                            \Q$self->{suffix}\E
                            (?:\. (?<rotate_suffix>\d+) )?
                            \z
                           /x;
         push @files,
           [ $e, $+{rotate_suffix} // 0, $+{period} // "", $cs // "" ];
     }
     closedir($dh);
 
     [ sort { $a->[2] cmp $b->[2] || $b->[1] <=> $a->[1] } @files ];
 }
 
 # rename (increase rotation suffix) and keep only n histories. note: failure in
 # rotating should not be fatal, we just warn and return.
 sub _rotate_and_delete {
     my ($self, %opts) = @_;
 
     my $delete_only = $opts{delete_only};
     my $lock = $self->_get_lock;
   CASE:
     {
         my $files = $self->_get_files or last CASE;
 
         # is there a compression process in progress? this is marked by the
         # existence of <prefix>-compress.pid PID file.
         #
         # XXX check validity of PID file, otherwise a stale PID file will always
         # prevent rotation to be done
         if (-f "$self->{dir}/$self->{prefix}-compress.pid") {
             warn "Compression is in progress, rotation is postponed";
             last CASE;
         }
 
         $self->{hook_before_rotate}->($self, [map {$_->[0]} @$files])
             if $self->{hook_before_rotate};
 
         my @deleted;
         my @renamed;
 
         my $i;
         my $dir = $self->{dir};
         my $rotating_period = @$files ? $files->[-1][2] : undef;
         for my $f (@$files) {
             my ($orig, $rs, $period, $cs) = @$f;
             $i++;
 
             #say "DEBUG: is_tainted \$dir? ".is_tainted($dir);
             #say "DEBUG: is_tainted \$orig? ".is_tainted($orig);
             #say "DEBUG: is_tainted \$cs? ".is_tainted($cs);
 
             # TODO actually, it's more proper to taint near the source (in this
             # case, _get_files)
             #untaint \$orig;
             ($orig) = $orig =~ /(.*)/s; # we use this instead, no module needed
 
             if ($i <= @$files - $self->{histories}) {
                 say "DEBUG: Deleting old rotated file $dir/$orig$cs ..."
                     if $Debug;
                 if (unlink "$dir/$orig$cs") {
                     push @deleted, "$orig$cs";
                 } else {
                     warn "Can't delete $dir/$orig$cs: $!";
                 }
                 next;
             }
             if (!$delete_only && defined($rotating_period) && $period eq $rotating_period) {
                 my $new = $orig;
                 if ($rs) {
                     $new =~ s/\.(\d+)\z/"." . ($1+1)/e;
                 } else {
                     $new .= ".1";
                 }
                 if ($new ne $orig) {
                     say "DEBUG: Renaming rotated file $dir/$orig$cs -> ".
                         "$dir/$new$cs ..." if $Debug;
                     if (rename "$dir/$orig$cs", "$dir/$new$cs") {
                         push @renamed, "$new$cs";
                     } else {
                         warn "Can't rename '$dir/$orig$cs' -> '$dir/$new$cs': $!";
                     }
                 }
             }
         }
 
         $self->{hook_after_rotate}->($self, \@renamed, \@deleted)
             if $self->{hook_after_rotate};
     } # CASE
 }
 
 sub _open {
     my $self = shift;
 
     my ($fp, $period) = $self->_file_path;
     open $self->{_fh}, ">>", $fp or die "Can't open '$fp': $!";
     if (defined $self->{binmode}) {
         binmode $self->{_fh}, $self->{binmode}
           or die "Can't set PerlIO layer on '$fp': $!";
     }
     my $oldfh = select $self->{_fh};
     $| = 1;
     select $oldfh;    # set autoflush
     $self->{_fp} = $fp;
     $self->{hook_after_create}->($self) if $self->{hook_after_create};
 }
 
 # (re)open file and optionally rotate if necessary
 sub _rotate_and_open {
 
     my $self = shift;
     my ($do_open, $do_rotate) = @_;
     my $fp;
     my %rotate_params;
 
   CASE:
     {
         # if instructed, only do rotate some of the time to shave overhead
         if ($self->{rotate_probability} && $self->{_fh}) {
             last CASE if rand() > $self->{rotate_probability};
         }
 
         $fp = $self->_file_path;
         unless (-e $fp) {
             $do_open++;
             $do_rotate++;
             $rotate_params{delete_only} = 1;
             last CASE;
         }
 
         # file is not opened yet, open
         unless ($self->{_fh}) {
             $self->_open;
         }
 
         # period has changed, rotate
         if ($self->{_fp} ne $fp) {
             $do_rotate++;
             $rotate_params{delete_only} = 1;
             last CASE;
         }
 
         # check whether size has been exceeded
         my $inode;
 
         if ($self->{size} > 0) {
 
             my @st   = stat($self->{_fh});
             my $size = $st[7];
             $inode = $st[1];
 
             if ($size >= $self->{size}) {
                 say "DEBUG: Size of $self->{_fp} is $size, exceeds $self->{size}, rotating ..."
                     if $Debug;
                 $do_rotate++;
                 last CASE;
             } else {
                 # stat the current file (not our handle _fp)
                 my @st = stat($fp);
                 die "Can't stat '$fp': $!" unless @st;
                 my $finode = $st[1];
 
                 # check whether other process has rename/rotate under us (for
                 # example, 'prefix' has been moved to 'prefix.1'), in which case
                 # we need to reopen
                 if (defined($inode) && $finode != $inode) {
                     $do_open++;
                 }
             }
 
         }
     } # CASE
 
     $self->_rotate_and_delete(%rotate_params) if $do_rotate;
     $self->_open if $do_rotate || $do_open;    # (re)open
 }
 
 sub write {
     my $self = shift;
 
     # the buffering implementation is currently pretty naive. it assume any
     # die() as a write failure and store the message to buffer.
 
     # FYI: if privilege is dropped from superuser, the failure is usually at
     # locking the lock file (permission denied).
 
     my @msg = (map( {@$_} @{ $self->{_buffer} } ), @_);
 
     eval {
         my $lock = $self->_get_lock;
 
         $self->_rotate_and_open;
 
         $self->{hook_before_write}->($self, \@msg, $self->{_fh})
             if $self->{hook_before_write};
 
         print { $self->{_fh} } @msg;
         $self->{_buffer} = [];
 
     };
     my $err = $@;
 
     if ($err) {
         if (($self->{buffer_size} // 0) > @{ $self->{_buffer} }) {
             # put message to buffer temporarily
             push @{ $self->{_buffer} }, [@_];
         } else {
             # buffer is already full, let's dump the buffered + current message
             # to the die message anyway.
             die join(
                 "",
                 "Can't write",
                 (
                     @{ $self->{_buffer} }
                     ? " (buffer is full, "
                       . ~~@{ $self->{_buffer} }
                       . " message(s))"
                     : ""
                 ),
                 ": $err, message(s)=",
                 @msg
             );
         }
     }
 }
 
 sub compress {
     my ($self) = shift;
 
     require Proc::PID::File;
 
     my $lock           = $self->_get_lock;
     my $files_ref        = $self->_get_files;
     my $done_compression = 0;
 
     if (@{$files_ref}) {
         my $pid = Proc::PID::File->new(
             dir    => $self->{dir},
             name   => "$self->{prefix}-compress",
             verify => 1,
         );
         my $latest_period = $files_ref->[-1][2];
 
         if ($pid->alive) {
             warn "Another compression is in progress";
         } else {
             my @tocompress;
             #use DD; dd $self;
             for my $file_ref (@{$files_ref}) {
                 my ($orig, $rs, $period, $cs) = @{ $file_ref };
                 #say "D:compress: orig=<$orig> rs=<$rs> period=<$period> cs=<$cs>";
                 next if $cs; # already compressed
                 next if !$self->{period} && !$rs; # not old file
                 next if  $self->{period} && $period eq $latest_period; # not old file
                 push @tocompress, File::Spec->catfile($self->{dir}, $orig);
             }
 
             if (@tocompress) {
                 for my $file (@tocompress) {
                     gzip($file => "$file.gz")
                         or do { warn "gzip failed: $GzipError\n"; next };
                     unlink $file;
                 }
                 $done_compression = 1;
             }
         }
     }
 
     return $done_compression;
 
 }
 
 sub DESTROY {
     my ($self) = @_;
 
     # Proc::PID::File's DESTROY seem to create an empty PID file, remove it.
     unlink "$self->{dir}/$self->{prefix}-compress.pid";
 }
 
 1;
 
 # ABSTRACT: Write to files that archive/rotate themselves
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 File::Write::Rotate - Write to files that archive/rotate themselves
 
 =head1 VERSION
 
 This document describes version 0.29 of File::Write::Rotate (from Perl distribution File-Write-Rotate), released on 2015-10-20.
 
 =head1 SYNOPSIS
 
  use File::Write::Rotate;
 
  my $fwr = File::Write::Rotate->new(
      dir          => '/var/log',    # required
      prefix       => 'myapp',       # required
      #suffix      => '.log',        # default is ''
      size         => 25*1024*1024,  # default is 10MB, unless period is set
      histories    => 12,            # default is 10
      #buffer_size => 100,           # default is none
  );
 
  # write, will write to /var/log/myapp.log, automatically rotate old log files
  # to myapp.log.1 when myapp.log reaches 25MB. will keep old log files up to
  # myapp.log.12.
  $fwr->write("This is a line\n");
  $fwr->write("This is", " another line\n");
 
 To compressing old log files:
 
  $fwr->compress;
 
 This is usually done in a separate process, because it potentially takes a long
 time if the files to compress are large; we are rotating automatically in
 write() so doing automatic compression too would annoyingly block writer for a
 potentially long time.
 
 =head1 DESCRIPTION
 
 This module can be used to write to file, usually for logging, that can rotate
 itself. File will be opened in append mode. By default, locking will be done to
 avoid conflict when there are multiple writers. Rotation can be done by size
 (after a certain size is reached), by time (daily/monthly/yearly), or both.
 
 I first wrote this module for logging script STDERR output to files (see
 L<Tie::Handle::FileWriteRotate>).
 
 =for Pod::Coverage ^(file_path|DESTROY)$
 
 =head1 ATTRIBUTES
 
 =head2 buffer_size => int
 
 Get or set buffer size. If set to a value larger than 0, then when a write()
 failed, instead of dying, the message will be stored in an internal buffer first
 (a regular Perl array). When the number of items in the buffer exceeds this
 size, then write() will die upon failure. Otherwise, every write() will try to
 flush the buffer.
 
 Can be used for example when a program runs as superuser/root then temporarily
 drops privilege to a normal user. During this period, logging can fail because
 the program cannot lock the lock file or write to the logging directory. Before
 dropping privilege, the program can set buffer_size to some larger-than-zero
 value to hold the messages emitted during dropping privilege. The next write()
 as the superuser/root will succeed and flush the buffer to disk (provided there
 is no other error condition, of course).
 
 =head2 path => str (ro)
 
 Current file's path.
 
 =head2 handle => (ro)
 
 Current file handle. You should not use this directly, but use write() instead.
 This attribute is provided for special circumstances (e.g. in hooks, see example
 in the hook section).
 
 =head2 hook_before_write => code
 
 Will be called by write() before actually writing to filehandle (but after
 locking is done). Code will be passed ($self, \@msgs, $fh) where @msgs is an
 array of strings to be written (the contents of buffer, if any, plus arguments
 passed to write()) and $fh is the filehandle.
 
 =head2 hook_before_rotate => code
 
 Will be called by the rotating routine before actually doing rotating. Code will
 be passed ($self).
 
 This can be used to write a footer to the end of each file, e.g.:
 
  # hook_before_rotate
  my ($self) = @_;
  my $fh = $self->handle;
  print $fh "Some footer\n";
 
 Since this hook is indirectly called by write(), locking is already done.
 
 =head2 hook_after_rotate => code
 
 Will be called by the rotating routine after the rotating process. Code will be
 passed ($self, \@renamed, \@deleted) where @renamed is array of new filenames
 that have been renamed, @deleted is array of new filenames that have been
 deleted.
 
 =head2 hook_after_create => code
 
 Will be called by after a new file is created. Code will be passed ($self).
 
 This hook can be used to write a header to each file, e.g.:
 
  # hook_after_create
  my ($self) = @_;
  my $fh $self->handle;
  print $fh "header\n";
 
 Since this is called indirectly by write(), locking is also already done.
 
 =head2 binmode => str
 
 =head1 METHODS
 
 =head2 $obj = File::Write::Rotate->new(%args)
 
 Create new object. Known arguments:
 
 =over
 
 =item * dir => STR (required)
 
 Directory to put the files in.
 
 =item * prefix => STR (required)
 
 Name of files. The files will be named like the following:
 
  <prefix><period><suffix><rotate_suffix>
 
 C<< <period> >> will only be given if the C<period> argument is set. If
 C<period> is set to C<yearly>, C<< <period> >> will be C<YYYY> (4-digit year).
 If C<period> is C<monthly>, C<< <period> >> will be C<YYYY-MM> (4-digit year and
 2-digit month). If C<period> is C<daily>, C<< <period> >> will be C<YYYY-MM-DD>
 (4-digit year, 2-digit month, and 2-digit day).
 
 C<< <rotate_suffix> >> is either empty string for current file; or C<.1>, C<.2>
 and so on for rotated files. C<.1> is the most recent rotated file, C<.2> is the
 next most recent, and so on.
 
 An example, with C<prefix> set to C<myapp>:
 
  myapp         # current file
  myapp.1       # most recently rotated
  myapp.2       # the next most recently rotated
 
 With C<prefix> set to C<myapp>, C<period> set to C<monthly>, C<suffix> set to
 C<.log>:
 
  myapp.2012-12.log     # file name for december 2012
  myapp.2013-01.log     # file name for january 2013
 
 Like previous, but additionally with C<size> also set (which will also rotate
 each period file if it exceeds specified size):
 
  myapp.2012-12.log     # file(s) for december 2012
  myapp.2012-12.log.1
  myapp.2012-12.log.2
  myapp.2013-01.log     # file(s) for january 2013
 
 All times will use local time, so you probably want to set C<TZ> environment
 variable or equivalent methods to set time zone.
 
 =item * suffix => STR (default: '')
 
 Suffix to give to file names, usually file extension like C<.log>. See C<prefix>
 for more details.
 
 If you use a yearly period, setting suffix is advised to avoid ambiguity with
 rotate suffix (for example, is C<myapp.2012> the current file for year 2012 or
 file with C<2012> rotate suffix?)
 
 =item * size => INT (default: 10*1024*1024)
 
 Maximum file size, in bytes, before rotation is triggered. The default is 10MB
 (10*1024*1024) I<if> C<period> is not set. If C<period> is set, no default for
 C<size> is provided, which means files will not be rotated for size (only for
 period).
 
 =item * period => STR
 
 Can be set to either C<daily>, C<monthly>, or C<yearly>. If set, will
 automatically rotate after period change. See C<prefix> for more details.
 
 =item * histories => INT (default: 10)
 
 Number of rotated files to keep. After the number of files exceeds this, the
 oldest one will be deleted. 0 means not to keep any history, 1 means to only
 keep C<.1> file, and so on.
 
 =item * buffer_size => INT (default: 0)
 
 Set initial value of buffer. See the C<buffer_size> attribute for more
 information.
 
 =item * lock_mode => STR (default: 'write')
 
 Can be set to either C<none>, C<write>, or C<exclusive>. C<none> disables
 locking and increases write performance, but should only be used when there is
 only one writer. C<write> acquires and holds the lock for each write.
 C<exclusive> acquires the lock at object creation and holds it until the the
 object is destroyed.
 
 Lock file is named C<< <prefix> >>C<.lck>. Will wait for up to 1 minute to
 acquire lock, will die if failed to acquire lock.
 
 =item * hook_before_write => CODE
 
 =item * hook_before_rotate => CODE
 
 =item * hook_after_rotate => CODE
 
 =item * hook_after_create => CODE
 
 See L</ATTRIBUTES>.
 
 =item * buffer_size => int
 
 =item * rotate_probability => float (between 0 < x < 1)
 
 If set, instruct to only check for rotation under a certain probability, for
 example if value is set to 0.1 then will only check for rotation 10% of the
 time.
 
 =back
 
 =head2 lock_file_path => STR
 
 Returns a string representing the complete pathname to the lock file, based
 on C<dir> and C<prefix> attributes.
 
 =head2 $fwr->write(@args)
 
 Write to file. Will automatically rotate file if period changes or file size
 exceeds specified limit. When rotating, will only keep a specified number of
 histories and delete the older ones.
 
 Does not append newline so you'll have to do it yourself.
 
 =head2 $fwr->compress
 
 Compress old rotated files and remove the uncompressed originals. Currently uses
 L<IO::Compress::Gzip> to do the compression. Extension given to compressed file
 is C<.gz>.
 
 Will not lock writers, but will create C<< <prefix> >>C<-compress.pid> PID file
 to prevent multiple compression processes running and to signal the writers to
 postpone rotation.
 
 After compression is finished, will remove the PID file, so rotation can be done
 again on the next C<write()> if necessary.
 
 =head1 FAQ
 
 =head2 Why use autorotating file?
 
 Mainly convenience and low maintenance. You no longer need a separate rotator
 process like the Unix B<logrotate> utility (which when accidentally disabled or
 misconfigured will cause your logs to stop being rotated and grow indefinitely).
 
 =head2 What is the downside of using FWR (and LDFR)?
 
 Mainly (significant) performance overhead. At (almost) every C<write()>, FWR
 needs to check file sizes and/or dates for rotation. Under default configuration
 (where C<lock_mode> is C<write>), it also performs locking on each C<write()> to
 make it safe to use with multiple processes. Below is a casual benchmark to give
 a sense of the overhead, tested on my Core i5-2400 3.1GHz desktop:
 
 Writing lines in the size of ~ 200 bytes, raw writing to disk (SSD) has the
 speed of around 3.4mil/s, while using FWR it goes down to around ~13k/s. Using
 C<lock_mode> C<none> or C<exclusive>, the speed is ~52k/s.
 
 However, this is not something you'll notice or need to worry about unless
 you're writing near that speed.
 
 If you need more speed, you can try setting C<rotate_probability> which will
 cause FWR to only check for rotation probabilistically, e.g. if you set this to
 0.1 then checks will only be done in about 1 of 10 writes. This can
 significantly reduce the overhead and increase write speed several times (e.g.
 5-8 times), but understand that this will make the writes "overflow" a bit, e.g.
 file sizes will exceed for a bit if you do size-based rotation. More suitable if
 you only do size-based rotation since it is usually okay to exceed sizes for a
 bit.
 
 =head1 SEE ALSO
 
 L<Log::Dispatch::FileRotate>, which inspires this module. Differences between
 File::Write::Rotate (FWR) and Log::Dispatch::FileRotate (LDFR) are as follows:
 
 =over
 
 =item * FWR is not part of the L<Log::Dispatch> family.
 
 This makes FWR more general to use.
 
 For using together with Log::Dispatch/Log4perl, I have also written
 L<Log::Dispatch::FileWriteRotate> which is a direct (although not a perfect
 drop-in) replacement for Log::Dispatch::FileRotate.
 
 =item * Secondly, FWR does not use L<Date::Manip>.
 
 Date::Manip is relatively large (loading Date::Manip 6.37 equals to loading 34
 files and ~ 22k lines; while FWR itself is only < 1k lines!)
 
 As a consequence of this, FWR does not support DatePattern; instead, FWR
 replaces it with a simple daily/monthly/yearly period.
 
 =item * And lastly, FWR supports compressing and rotating compressed old files.
 
 Using separate processes like the Unix B<logrotate> utility means having to deal
 with yet another race condition. FWR takes care of that for you (see the
 compress() method). You also have the option to do file compression in the same
 script/process if you want, which is convenient.
 
 =back
 
 There is no significant overhead difference between FWR and LDFR (FWR is
 slightly faster than LDFR on my testing).
 
 L<Tie::Handle::FileWriteRotate> and Log::Dispatch::FileWriteRotate, which use
 this module.
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/File-Write-Rotate>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-File-Write-Rotate>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=File-Write-Rotate>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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
### File/chdir.pm ###
 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.1010';
 
 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.1010
 
 =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. \
 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 CONTRIBUTOR
 
 =for stopwords Joel Berger
 
 Joel Berger <joel.a.berger@gmail.com>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 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
### Function/Fallback/CoreOrPP.pm ###
 package Function::Fallback::CoreOrPP;
 
 use 5.010001;
 use strict;
 use warnings;
 
 our $VERSION = '0.06'; # VERSION
 
 our $USE_NONCORE_XS_FIRST = 1;
 
 require Exporter;
 our @ISA       = qw(Exporter);
 our @EXPORT_OK = qw(
                        clone
                        unbless
                        uniq
                );
 
 sub clone {
     my $data = shift;
     goto FALLBACK unless $USE_NONCORE_XS_FIRST;
     goto FALLBACK unless eval { require Data::Clone; 1 };
 
   STANDARD:
     return Data::Clone::clone($data);
 
   FALLBACK:
     require Clone::PP;
     return Clone::PP::clone($data);
 }
 
 sub _unbless_fallback {
     my $ref = shift;
 
     my $r = ref($ref);
     # not a reference
     return $ref unless $r;
 
     # return if not a blessed ref
     my ($r2, $r3) = "$ref" =~ /(.+)=(.+?)\(/
         or return $ref;
 
     if ($r3 eq 'HASH') {
         return { %$ref };
     } elsif ($r3 eq 'ARRAY') {
         return [ @$ref ];
     } elsif ($r3 eq 'SCALAR') {
         return \( my $copy = ${$ref} );
     } else {
         die "Can't handle $ref";
     }
 }
 
 sub unbless {
     my $ref = shift;
 
     goto FALLBACK unless $USE_NONCORE_XS_FIRST;
     goto FALLBACK unless eval { require Acme::Damn; 1 };
 
   STANDARD:
     return Acme::Damn::damn($ref);
 
   FALLBACK:
     return _unbless_fallback($ref);
 }
 
 sub uniq {
     goto FALLBACK unless $USE_NONCORE_XS_FIRST;
     goto FALLBACK unless eval { require List::MoreUtils; 1 };
 
   STANDARD:
     return List::MoreUtils::uniq(@_);
 
   FALLBACK:
     my %h;
     my @res;
     for (@_) {
         push @res, $_ unless $h{$_}++;
     }
     return @res;
 }
 
 1;
 #ABSTRACT: Functions that use non-core XS module but provide pure-Perl/core fallback
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Function::Fallback::CoreOrPP - Functions that use non-core XS module but provide pure-Perl/core fallback
 
 =head1 VERSION
 
 This document describes version 0.06 of Function::Fallback::CoreOrPP (from Perl distribution Function-Fallback-CoreOrPP), released on 2014-09-16.
 
 =head1 SYNOPSIS
 
  use Function::Fallback::CoreOrPP qw(clone unbless uniq);
 
  my $clone = clone({blah=>1});
  my $unblessed = unbless($blessed_ref);
  my @uniq  = uniq(1, 3, 2, 1, 4);  # -> (1, 3, 2, 4)
 
 =head1 DESCRIPTION
 
 This module provides functions that use non-core XS modules (for best speed,
 reliability, feature, etc) but falls back to those that use core XS or pure-Perl
 modules when the non-core XS module is not available.
 
 This module helps when you want to bootstrap your Perl application with a
 portable, dependency-free Perl script. In a vanilla Perl installation (having
 only core modules), you can use L<App::FatPacker> to include non-core pure-Perl
 dependencies to your script.
 
 =for Pod::Coverage ^()$
 
 =head1 FUNCTIONS
 
 =head2 clone($data) => $cloned
 
 Try to use L<Data::Clone>'s C<clone>, but fall back to using L<Clone::PP>'s
 C<clone>.
 
 =head2 unbless($ref) => $unblessed_ref
 
 Try to use L<Acme::Damn>'s C<damn> to unbless a reference but fall back to
 shallow copying.
 
 NOTE: C<damn()> B<MODIFIES> the original reference. (XXX in the future an option
 to clone the reference first will be provided), while shallow copying will
 return a shallow copy.
 
 NOTE: The shallow copy method currently only handles blessed
 {scalar,array,hash}ref as those are the most common.
 
 =head2 uniq(@ary) => @uniq_ary
 
 Try to use L<List::MoreUtils>'s C<uniq>, but fall back to using slower,
 pure-Perl implementation.
 
 =head1 SEE ALSO
 
 L<Clone::Any> can also uses multiple backends, but I avoid it because I don't
 think L<Storable>'s C<dclone> should be used (no Regexp support out of the box +
 must use deparse to handle coderefs).
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Function-Fallback-CoreOrPP>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Function-Fallback-CoreOrPP>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Function-Fallback-CoreOrPP>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2014 by perlancar@cpan.org.
 
 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
### Getopt/Long/Negate/EN.pm ###
 package Getopt::Long::Negate::EN;
 
 our $DATE = '2015-03-19'; # DATE
 our $VERSION = '0.01'; # VERSION
 
 use 5.010001;
 use strict;
 use warnings;
 
 use Exporter qw(import);
 our @EXPORT_OK = qw(negations_for_option);
 
 sub negations_for_option {
     my $word = shift;
     if    ($word =~ /\Awith([_-].+)/   ) { return ("without$1") }
     elsif ($word =~ /\Awithout([_-].+)/) { return ("with$1")    }
     elsif ($word =~ /\Ais([_-].+)/     ) { return ("isnt$1")    }
     elsif ($word =~ /\Aisnt([_-].+)/   ) { return ("is$1")      }
     elsif ($word =~ /\Aare([_-].+)/    ) { return ("arent$1")   }
     elsif ($word =~ /\Aarent([_-].+)/  ) { return ("are$1")     }
     elsif ($word =~ /\Ano[_-](.+)/     ) { return ($1)          }
     else {
         # default from Getopt::Long
         return ("no-$word", "no$word");
     }
 }
 
 1;
 # ABSTRACT: Better negation of boolean option names
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Getopt::Long::Negate::EN - Better negation of boolean option names
 
 =head1 VERSION
 
 This document describes version 0.01 of Getopt::Long::Negate::EN (from Perl distribution Getopt-Long-Negate-EN), released on 2015-03-19.
 
 =head1 SYNOPSIS
 
  use Getopt::Long::Negate::EN qw(negations_for_option);
 
  # the Getopt::Long's default
  @negs = negations_for_option('foo'); # ('no-foo', 'nofoo')
 
  @negs = negations_for_option('with-foo');    # ('without-foo')
  @negs = negations_for_option('without-foo'); # ('with-foo')
 
  @negs = negations_for_option('is-foo');      # ('isnt-foo')
  @negs = negations_for_option('isnt-foo');    # ('is-foo')
 
  @negs = negations_for_option('are-foo');     # ('isnt-foo')
  @negs = negations_for_option('arent-foo');   # ('arent-foo')
 
  @negs = negations_for_option('no-foo');      # ('foo')
 
 =head1 DESCRIPTION
 
 This module aims to provide a nicer negative boolean option names. By default,
 L<Getopt::Long> provides options C<--foo> as well as C<--no-foo> and C<--nofoo>
 if you specify boolean option specification C<foo!>. But this produces
 awkward/incorrect English word like C<--nowith-foo> or C<--no-is-foo>. In those
 two cases, C<--without-foo> and C<--isnt-foo> are better option names.
 
 =head1 FUNCTIONS
 
 None are exported by default, but they are exportable.
 
 =head2 negations_for_option($str) => list
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Getopt-Long-Negate-EN>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Getopt-Long-Negate-EN>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Getopt-Long-Negate-EN>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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
### Getopt/Long/Util.pm ###
 package Getopt::Long::Util;
 
 our $DATE = '2015-06-11'; # DATE
 our $VERSION = '0.83'; # VERSION
 
 use 5.010001;
 use strict;
 use warnings;
 
 require Exporter;
 our @ISA       = qw(Exporter);
 our @EXPORT_OK = qw(
                        parse_getopt_long_opt_spec
                        humanize_getopt_long_opt_spec
                        detect_getopt_long_script
                );
 
 our %SPEC;
 
 $SPEC{parse_getopt_long_opt_spec} = {
     v => 1.1,
     summary => 'Parse a single Getopt::Long option specification',
     description => <<'_',
 
 Will produce a hash with some keys: `opts` (array of option names, in the order
 specified in the opt spec), `type` (string, type name), `desttype` (either '',
 or '@' or '%'), `is_neg` (true for `--opt!`), `is_inc` (true for `--opt+`),
 `min_vals` (int, usually 0 or 1), `max_vals` (int, usually 0 or 1 except for
 option that requires multiple values),
 
 Will return undef if it can't parse the string.
 
 _
     args => {
         optspec => {
             schema => 'str*',
             req => 1,
             pos => 0,
         },
     },
     args_as => 'array',
     result_naked => 1,
     result => {
         schema => 'hash*',
     },
     examples => [
         {
             args => {optspec => 'help|h|?'},
             result => {dash_prefix=>'', opts=>['help', 'h', '?']},
         },
         {
             args => {optspec=>'--foo=s'},
             result => {dash_prefix=>'--', opts=>['foo'], type=>'s', desttype=>''},
         },
     ],
 };
 # BEGIN_BLOCK: parse_getopt_long_opt_spec
 sub parse_getopt_long_opt_spec {
     my $optspec = shift;
     $optspec =~ qr/\A
                (?P<dash_prefix>-{0,2})
                (?P<name>[A-Za-z0-9_][A-Za-z0-9_-]*)
                (?P<aliases> (?: \| (?:[^:|!+=:-][^:|!+=:]*) )*)?
                (?:
                    (?P<is_neg>!) |
                    (?P<is_inc>\+) |
                    (?:
                        =
                        (?P<type>[siof])
                        (?P<desttype>|[%@])?
                        (?:
                            \{
                            (?: (?P<min_vals>\d+), )?
                            (?P<max_vals>\d+)
                            \}
                        )?
                    ) |
                    (?:
                        :
                        (?P<opttype>[siof])
                        (?P<desttype>|[%@])
                    ) |
                    (?:
                        :
                        (?P<optnum>\d+)
                        (?P<desttype>|[%@])
                    )
                    (?:
                        :
                        (?P<optplus>\+)
                        (?P<desttype>|[%@])
                    )
                )?
                \z/x
                    or return undef;
     my %res = %+;
 
     if ($res{aliases}) {
         my @als;
         for my $al (split /\|/, $res{aliases}) {
             next unless length $al;
             next if $al eq $res{name};
             next if grep {$_ eq $al} @als;
             push @als, $al;
         }
         $res{opts} = [$res{name}, @als];
     } else {
         $res{opts} = [$res{name}];
     }
     delete $res{name};
     delete $res{aliases};
 
     $res{is_neg} = 1 if $res{is_neg};
     $res{is_inc} = 1 if $res{is_inc};
 
     \%res;
 }
 # END_BLOCK: parse_getopt_long_opt_spec
 
 $SPEC{humanize_getopt_long_opt_spec} = {
     v => 1.1,
     description => <<'_',
 
 Convert `Getopt::Long` option specification like `help|h|?` or `--foo=s` or
 `debug!` into, respectively, `--help, -h, -?` or `--foo=s` or `--(no)debug`.
 Will die if can't parse the string. The output is suitable for including in
 help/usage text.
 
 _
     args => {
         optspec => {
             schema => 'str*',
             req => 1,
             pos => 0,
         },
     },
     args_as => 'array',
     result_naked => 1,
     result => {
         schema => 'str*',
     },
 };
 sub humanize_getopt_long_opt_spec {
     my $optspec = shift;
 
     my $parse = parse_getopt_long_opt_spec($optspec)
         or die "Can't parse opt spec $optspec";
 
     my $res = '';
     my $i = 0;
     for (@{ $parse->{opts} }) {
         $i++;
         $res .= ", " if length($res);
         if ($parse->{is_neg} && length($_) > 1) {
             $res .= "--(no)$_";
         } else {
             if (length($_) > 1) {
                 $res .= "--$_";
             } else {
                 $res .= "-$_";
             }
             $res .= "=$parse->{type}" if $i==1 && $parse->{type};
         }
     }
     $res;
 }
 
 $SPEC{detect_getopt_long_script} = {
     v => 1.1,
     summary => 'Detect whether a file is a Getopt::Long-based CLI script',
     description => <<'_',
 
 The criteria are:
 
 * the file must exist and readable;
 
 * (optional, if `include_noexec` is false) file must have its executable mode
   bit set;
 
 * content must start with a shebang C<#!>;
 
 * either: must be perl script (shebang line contains 'perl') and must contain
   something like `use Getopt::Long`;
 
 _
     args => {
         filename => {
             summary => 'Path to file to be checked',
             schema => 'str*',
             description => <<'_',
 
 Either `filename` or `string` must be specified.
 
 _
         },
         string => {
             summary => 'Path to file to be checked',
             schema => 'buf*',
             description => <<'_',
 
 Either `file` or `string` must be specified.
 
 _
         },
         include_noexec => {
             summary => 'Include scripts that do not have +x mode bit set',
             schema  => 'bool*',
             default => 1,
         },
     },
 };
 sub detect_getopt_long_script {
     my %args = @_;
 
     (defined($args{filename}) xor defined($args{string}))
         or return [400, "Please specify either filename or string"];
     my $include_noexec  = $args{include_noexec}  // 1;
 
     my $yesno = 0;
     my $reason = "";
 
     my $str = $args{string};
   DETECT:
     {
         if (defined $args{filename}) {
             my $fn = $args{filename};
             unless (-f $fn) {
                 $reason = "'$fn' is not a file";
                 last;
             };
             if (!$include_noexec && !(-x _)) {
                 $reason = "'$fn' is not an executable";
                 last;
             }
             my $fh;
             unless (open $fh, "<", $fn) {
                 $reason = "Can't be read";
                 last;
             }
             # for efficiency, we read a bit only here
             read $fh, $str, 2;
             unless ($str eq '#!') {
                 $reason = "Does not start with a shebang (#!) sequence";
                 last;
             }
             my $shebang = <$fh>;
             unless ($shebang =~ /perl/) {
                 $reason = "Does not have 'perl' in the shebang line";
                 last;
             }
             seek $fh, 0, 0;
             {
                 local $/;
                 $str = <$fh>;
             }
         }
         unless ($str =~ /\A#!/) {
             $reason = "Does not start with a shebang (#!) sequence";
             last;
         }
         unless ($str =~ /\A#!.*perl/) {
             $reason = "Does not have 'perl' in the shebang line";
             last;
         }
         if ($str =~ /^\s*(use|require)\s+Getopt::Long(\s|;)/m) {
             $yesno = 1;
             last DETECT;
         }
         $reason = "Can't find any statement requiring Getopt::Long module";
     } # DETECT
 
     [200, "OK", $yesno, {"func.reason"=>$reason}];
 }
 
 # ABSTRACT: Utilities for Getopt::Long
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Getopt::Long::Util - Utilities for Getopt::Long
 
 =head1 VERSION
 
 This document describes version 0.83 of Getopt::Long::Util (from Perl distribution Getopt-Long-Util), released on 2015-06-11.
 
 =head1 SEE ALSO
 
 L<Getopt::Long>
 
 L<Getopt::Long::Spec>, which can also parse Getopt::Long spec into hash as well
 as transform back the hash to Getopt::Long spec. OO interface. I should've found
 this module first before writing my own C<parse_getopt_long_opt_spec()>. But at
 least currently C<parse_getopt_long_opt_spec()> is at least about 30-100+%
 faster than Getopt::Long::Spec::Parser, has a much simpler implementation (a
 single regex match), and can handle valid Getopt::Long specs that
 Getopt::Long::Spec::Parser fails to parse, e.g. C<foo|f=s@>.
 
 =head1 FUNCTIONS
 
 
 =head2 detect_getopt_long_script(%args) -> [status, msg, result, meta]
 
 Detect whether a file is a Getopt::Long-based CLI script.
 
 The criteria are:
 
 =over
 
 =item * the file must exist and readable;
 
 =item * (optional, if C<include_noexec> is false) file must have its executable mode
 bit set;
 
 =item * content must start with a shebang C<#!>;
 
 =item * either: must be perl script (shebang line contains 'perl') and must contain
 something like C<use Getopt::Long>;
 
 =back
 
 Arguments ('*' denotes required arguments):
 
 =over 4
 
 =item * B<filename> => I<str>
 
 Path to file to be checked.
 
 Either C<filename> or C<string> must be specified.
 
 =item * B<include_noexec> => I<bool> (default: 1)
 
 Include scripts that do not have +x mode bit set.
 
 =item * B<string> => I<buf>
 
 Path to file to be checked.
 
 Either C<file> or C<string> must be specified.
 
 =back
 
 Returns an enveloped result (an array).
 
 First element (status) is an integer containing HTTP status code
 (200 means OK, 4xx caller error, 5xx function error). Second element
 (msg) is a string containing error message, or 'OK' if status is
 200. Third element (result) is optional, the actual result. Fourth
 element (meta) is called result metadata and is optional, a hash
 that contains extra information.
 
 Return value:  (any)
 
 
 =head2 humanize_getopt_long_opt_spec($optspec) -> str
 
 Convert C<Getopt::Long> option specification like C<help|h|?> or C<--foo=s> or
 C<debug!> into, respectively, C<--help, -h, -?> or C<--foo=s> or C<--(no)debug>.
 Will die if can't parse the string. The output is suitable for including in
 help/usage text.
 
 Arguments ('*' denotes required arguments):
 
 =over 4
 
 =item * B<optspec>* => I<str>
 
 =back
 
 Return value:  (str)
 
 
 =head2 parse_getopt_long_opt_spec($optspec) -> hash
 
 Parse a single Getopt::Long option specification.
 
 Examples:
 
  parse_getopt_long_opt_spec("help|h|?"); # -> { dash_prefix => "", opts => ["help", "h", "?"] }
  parse_getopt_long_opt_spec("--foo=s"); # -> { dash_prefix => "--", desttype => "", opts => ["foo"], type => "s" }
 Will produce a hash with some keys: C<opts> (array of option names, in the order
 specified in the opt spec), C<type> (string, type name), C<desttype> (either '',
 or '@' or '%'), C<is_neg> (true for C<--opt!>), C<is_inc> (true for C<--opt+>),
 C<min_vals> (int, usually 0 or 1), C<max_vals> (int, usually 0 or 1 except for
 option that requires multiple values),
 
 Will return undef if it can't parse the string.
 
 Arguments ('*' denotes required arguments):
 
 =over 4
 
 =item * B<optspec>* => I<str>
 
 =back
 
 Return value:  (hash)
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Getopt-Long-Util>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Getopt-Long-Util>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Getopt-Long-Util>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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
### HTML/Entities.pm ###
 package HTML::Entities;
 
 =encoding utf8
 
 =head1 NAME
 
 HTML::Entities - Encode or decode strings with HTML entities
 
 =head1 SYNOPSIS
 
  use HTML::Entities;
 
  $a = "V&aring;re norske tegn b&oslash;r &#230res";
  decode_entities($a);
  encode_entities($a, "\200-\377");
 
 For example, this:
 
  $input = "vis-à-vis Beyoncé's naïve\npapier-mâché résumé";
  print encode_entities($input), "\n"
 
 Prints this out:
 
  vis-&agrave;-vis Beyonc&eacute;'s na&iuml;ve
  papier-m&acirc;ch&eacute; r&eacute;sum&eacute;
 
 =head1 DESCRIPTION
 
 This module deals with encoding and decoding of strings with HTML
 character entities.  The module provides the following functions:
 
 =over 4
 
 =item decode_entities( $string, ... )
 
 This routine replaces HTML entities found in the $string with the
 corresponding Unicode character.  Unrecognized entities are left alone.
 
 If multiple strings are provided as argument they are each decoded
 separately and the same number of strings are returned.
 
 If called in void context the arguments are decoded in-place.
 
 This routine is exported by default.
 
 =item _decode_entities( $string, \%entity2char )
 
 =item _decode_entities( $string, \%entity2char, $expand_prefix )
 
 This will in-place replace HTML entities in $string.  The %entity2char
 hash must be provided.  Named entities not found in the %entity2char
 hash are left alone.  Numeric entities are expanded unless their value
 overflow.
 
 The keys in %entity2char are the entity names to be expanded and their
 values are what they should expand into.  The values do not have to be
 single character strings.  If a key has ";" as suffix,
 then occurrences in $string are only expanded if properly terminated
 with ";".  Entities without ";" will be expanded regardless of how
 they are terminated for compatibility with how common browsers treat
 entities in the Latin-1 range.
 
 If $expand_prefix is TRUE then entities without trailing ";" in
 %entity2char will even be expanded as a prefix of a longer
 unrecognized name.  The longest matching name in %entity2char will be
 used. This is mainly present for compatibility with an MSIE
 misfeature.
 
    $string = "foo&nbspbar";
    _decode_entities($string, { nb => "@", nbsp => "\xA0" }, 1);
    print $string;  # will print "foo bar"
 
 This routine is exported by default.
 
 =item encode_entities( $string )
 
 =item encode_entities( $string, $unsafe_chars )
 
 This routine replaces unsafe characters in $string with their entity
 representation. A second argument can be given to specify which characters to
 consider unsafe.  The unsafe characters is specified using the regular
 expression character class syntax (what you find within brackets in regular
 expressions).
 
 The default set of characters to encode are control chars, high-bit chars, and
 the C<< < >>, C<< & >>, C<< > >>, C<< ' >> and C<< " >> characters.  But this,
 for example, would encode I<just> the C<< < >>, C<< & >>, C<< > >>, and C<< "
 >> characters:
 
   $encoded = encode_entities($input, '<>&"');
 
 and this would only encode non-plain ascii:
 
   $encoded = encode_entities($input, '^\n\x20-\x25\x27-\x7e');
 
 This routine is exported by default.
 
 =item encode_entities_numeric( $string )
 
 =item encode_entities_numeric( $string, $unsafe_chars )
 
 This routine works just like encode_entities, except that the replacement
 entities are always C<&#xI<hexnum>;> and never C<&I<entname>;>.  For
 example, C<encode_entities("r\xF4le")> returns "r&ocirc;le", but
 C<encode_entities_numeric("r\xF4le")> returns "r&#xF4;le".
 
 This routine is I<not> exported by default.  But you can always
 export it with C<use HTML::Entities qw(encode_entities_numeric);>
 or even C<use HTML::Entities qw(:DEFAULT encode_entities_numeric);>
 
 =back
 
 All these routines modify the string passed as the first argument, if
 called in a void context.  In scalar and array contexts, the encoded or
 decoded string is returned (without changing the input string).
 
 If you prefer not to import these routines into your namespace, you can
 call them as:
 
   use HTML::Entities ();
   $decoded = HTML::Entities::decode($a);
   $encoded = HTML::Entities::encode($a);
   $encoded = HTML::Entities::encode_numeric($a);
 
 The module can also export the %char2entity and the %entity2char
 hashes, which contain the mapping from all characters to the
 corresponding entities (and vice versa, respectively).
 
 =head1 COPYRIGHT
 
 Copyright 1995-2006 Gisle Aas. All rights reserved.
 
 This library is free software; you can redistribute it and/or
 modify it under the same terms as Perl itself.
 
 =cut
 
 use strict;
 use vars qw(@ISA @EXPORT @EXPORT_OK $VERSION);
 use vars qw(%entity2char %char2entity);
 
 require 5.004;
 require Exporter;
 @ISA = qw(Exporter);
 
 @EXPORT = qw(encode_entities decode_entities _decode_entities);
 @EXPORT_OK = qw(%entity2char %char2entity encode_entities_numeric);
 
 $VERSION = "3.69";
 sub Version { $VERSION; }
 
 require HTML::Parser;  # for fast XS implemented decode_entities
 
 
 %entity2char = (
  # Some normal chars that have special meaning in SGML context
  amp    => '&',  # ampersand 
 'gt'    => '>',  # greater than
 'lt'    => '<',  # less than
  quot   => '"',  # double quote
  apos   => "'",  # single quote
 
  # PUBLIC ISO 8879-1986//ENTITIES Added Latin 1//EN//HTML
  AElig	=> chr(198),  # capital AE diphthong (ligature)
  Aacute	=> chr(193),  # capital A, acute accent
  Acirc	=> chr(194),  # capital A, circumflex accent
  Agrave	=> chr(192),  # capital A, grave accent
  Aring	=> chr(197),  # capital A, ring
  Atilde	=> chr(195),  # capital A, tilde
  Auml	=> chr(196),  # capital A, dieresis or umlaut mark
  Ccedil	=> chr(199),  # capital C, cedilla
  ETH	=> chr(208),  # capital Eth, Icelandic
  Eacute	=> chr(201),  # capital E, acute accent
  Ecirc	=> chr(202),  # capital E, circumflex accent
  Egrave	=> chr(200),  # capital E, grave accent
  Euml	=> chr(203),  # capital E, dieresis or umlaut mark
  Iacute	=> chr(205),  # capital I, acute accent
  Icirc	=> chr(206),  # capital I, circumflex accent
  Igrave	=> chr(204),  # capital I, grave accent
  Iuml	=> chr(207),  # capital I, dieresis or umlaut mark
  Ntilde	=> chr(209),  # capital N, tilde
  Oacute	=> chr(211),  # capital O, acute accent
  Ocirc	=> chr(212),  # capital O, circumflex accent
  Ograve	=> chr(210),  # capital O, grave accent
  Oslash	=> chr(216),  # capital O, slash
  Otilde	=> chr(213),  # capital O, tilde
  Ouml	=> chr(214),  # capital O, dieresis or umlaut mark
  THORN	=> chr(222),  # capital THORN, Icelandic
  Uacute	=> chr(218),  # capital U, acute accent
  Ucirc	=> chr(219),  # capital U, circumflex accent
  Ugrave	=> chr(217),  # capital U, grave accent
  Uuml	=> chr(220),  # capital U, dieresis or umlaut mark
  Yacute	=> chr(221),  # capital Y, acute accent
  aacute	=> chr(225),  # small a, acute accent
  acirc	=> chr(226),  # small a, circumflex accent
  aelig	=> chr(230),  # small ae diphthong (ligature)
  agrave	=> chr(224),  # small a, grave accent
  aring	=> chr(229),  # small a, ring
  atilde	=> chr(227),  # small a, tilde
  auml	=> chr(228),  # small a, dieresis or umlaut mark
  ccedil	=> chr(231),  # small c, cedilla
  eacute	=> chr(233),  # small e, acute accent
  ecirc	=> chr(234),  # small e, circumflex accent
  egrave	=> chr(232),  # small e, grave accent
  eth	=> chr(240),  # small eth, Icelandic
  euml	=> chr(235),  # small e, dieresis or umlaut mark
  iacute	=> chr(237),  # small i, acute accent
  icirc	=> chr(238),  # small i, circumflex accent
  igrave	=> chr(236),  # small i, grave accent
  iuml	=> chr(239),  # small i, dieresis or umlaut mark
  ntilde	=> chr(241),  # small n, tilde
  oacute	=> chr(243),  # small o, acute accent
  ocirc	=> chr(244),  # small o, circumflex accent
  ograve	=> chr(242),  # small o, grave accent
  oslash	=> chr(248),  # small o, slash
  otilde	=> chr(245),  # small o, tilde
  ouml	=> chr(246),  # small o, dieresis or umlaut mark
  szlig	=> chr(223),  # small sharp s, German (sz ligature)
  thorn	=> chr(254),  # small thorn, Icelandic
  uacute	=> chr(250),  # small u, acute accent
  ucirc	=> chr(251),  # small u, circumflex accent
  ugrave	=> chr(249),  # small u, grave accent
  uuml	=> chr(252),  # small u, dieresis or umlaut mark
  yacute	=> chr(253),  # small y, acute accent
  yuml	=> chr(255),  # small y, dieresis or umlaut mark
 
  # Some extra Latin 1 chars that are listed in the HTML3.2 draft (21-May-96)
  copy   => chr(169),  # copyright sign
  reg    => chr(174),  # registered sign
  nbsp   => chr(160),  # non breaking space
 
  # Additional ISO-8859/1 entities listed in rfc1866 (section 14)
  iexcl  => chr(161),
  cent   => chr(162),
  pound  => chr(163),
  curren => chr(164),
  yen    => chr(165),
  brvbar => chr(166),
  sect   => chr(167),
  uml    => chr(168),
  ordf   => chr(170),
  laquo  => chr(171),
 'not'   => chr(172),    # not is a keyword in perl
  shy    => chr(173),
  macr   => chr(175),
  deg    => chr(176),
  plusmn => chr(177),
  sup1   => chr(185),
  sup2   => chr(178),
  sup3   => chr(179),
  acute  => chr(180),
  micro  => chr(181),
  para   => chr(182),
  middot => chr(183),
  cedil  => chr(184),
  ordm   => chr(186),
  raquo  => chr(187),
  frac14 => chr(188),
  frac12 => chr(189),
  frac34 => chr(190),
  iquest => chr(191),
 'times' => chr(215),    # times is a keyword in perl
  divide => chr(247),
 
  ( $] > 5.007 ? (
   'OElig;'    => chr(338),
   'oelig;'    => chr(339),
   'Scaron;'   => chr(352),
   'scaron;'   => chr(353),
   'Yuml;'     => chr(376),
   'fnof;'     => chr(402),
   'circ;'     => chr(710),
   'tilde;'    => chr(732),
   'Alpha;'    => chr(913),
   'Beta;'     => chr(914),
   'Gamma;'    => chr(915),
   'Delta;'    => chr(916),
   'Epsilon;'  => chr(917),
   'Zeta;'     => chr(918),
   'Eta;'      => chr(919),
   'Theta;'    => chr(920),
   'Iota;'     => chr(921),
   'Kappa;'    => chr(922),
   'Lambda;'   => chr(923),
   'Mu;'       => chr(924),
   'Nu;'       => chr(925),
   'Xi;'       => chr(926),
   'Omicron;'  => chr(927),
   'Pi;'       => chr(928),
   'Rho;'      => chr(929),
   'Sigma;'    => chr(931),
   'Tau;'      => chr(932),
   'Upsilon;'  => chr(933),
   'Phi;'      => chr(934),
   'Chi;'      => chr(935),
   'Psi;'      => chr(936),
   'Omega;'    => chr(937),
   'alpha;'    => chr(945),
   'beta;'     => chr(946),
   'gamma;'    => chr(947),
   'delta;'    => chr(948),
   'epsilon;'  => chr(949),
   'zeta;'     => chr(950),
   'eta;'      => chr(951),
   'theta;'    => chr(952),
   'iota;'     => chr(953),
   'kappa;'    => chr(954),
   'lambda;'   => chr(955),
   'mu;'       => chr(956),
   'nu;'       => chr(957),
   'xi;'       => chr(958),
   'omicron;'  => chr(959),
   'pi;'       => chr(960),
   'rho;'      => chr(961),
   'sigmaf;'   => chr(962),
   'sigma;'    => chr(963),
   'tau;'      => chr(964),
   'upsilon;'  => chr(965),
   'phi;'      => chr(966),
   'chi;'      => chr(967),
   'psi;'      => chr(968),
   'omega;'    => chr(969),
   'thetasym;' => chr(977),
   'upsih;'    => chr(978),
   'piv;'      => chr(982),
   'ensp;'     => chr(8194),
   'emsp;'     => chr(8195),
   'thinsp;'   => chr(8201),
   'zwnj;'     => chr(8204),
   'zwj;'      => chr(8205),
   'lrm;'      => chr(8206),
   'rlm;'      => chr(8207),
   'ndash;'    => chr(8211),
   'mdash;'    => chr(8212),
   'lsquo;'    => chr(8216),
   'rsquo;'    => chr(8217),
   'sbquo;'    => chr(8218),
   'ldquo;'    => chr(8220),
   'rdquo;'    => chr(8221),
   'bdquo;'    => chr(8222),
   'dagger;'   => chr(8224),
   'Dagger;'   => chr(8225),
   'bull;'     => chr(8226),
   'hellip;'   => chr(8230),
   'permil;'   => chr(8240),
   'prime;'    => chr(8242),
   'Prime;'    => chr(8243),
   'lsaquo;'   => chr(8249),
   'rsaquo;'   => chr(8250),
   'oline;'    => chr(8254),
   'frasl;'    => chr(8260),
   'euro;'     => chr(8364),
   'image;'    => chr(8465),
   'weierp;'   => chr(8472),
   'real;'     => chr(8476),
   'trade;'    => chr(8482),
   'alefsym;'  => chr(8501),
   'larr;'     => chr(8592),
   'uarr;'     => chr(8593),
   'rarr;'     => chr(8594),
   'darr;'     => chr(8595),
   'harr;'     => chr(8596),
   'crarr;'    => chr(8629),
   'lArr;'     => chr(8656),
   'uArr;'     => chr(8657),
   'rArr;'     => chr(8658),
   'dArr;'     => chr(8659),
   'hArr;'     => chr(8660),
   'forall;'   => chr(8704),
   'part;'     => chr(8706),
   'exist;'    => chr(8707),
   'empty;'    => chr(8709),
   'nabla;'    => chr(8711),
   'isin;'     => chr(8712),
   'notin;'    => chr(8713),
   'ni;'       => chr(8715),
   'prod;'     => chr(8719),
   'sum;'      => chr(8721),
   'minus;'    => chr(8722),
   'lowast;'   => chr(8727),
   'radic;'    => chr(8730),
   'prop;'     => chr(8733),
   'infin;'    => chr(8734),
   'ang;'      => chr(8736),
   'and;'      => chr(8743),
   'or;'       => chr(8744),
   'cap;'      => chr(8745),
   'cup;'      => chr(8746),
   'int;'      => chr(8747),
   'there4;'   => chr(8756),
   'sim;'      => chr(8764),
   'cong;'     => chr(8773),
   'asymp;'    => chr(8776),
   'ne;'       => chr(8800),
   'equiv;'    => chr(8801),
   'le;'       => chr(8804),
   'ge;'       => chr(8805),
   'sub;'      => chr(8834),
   'sup;'      => chr(8835),
   'nsub;'     => chr(8836),
   'sube;'     => chr(8838),
   'supe;'     => chr(8839),
   'oplus;'    => chr(8853),
   'otimes;'   => chr(8855),
   'perp;'     => chr(8869),
   'sdot;'     => chr(8901),
   'lceil;'    => chr(8968),
   'rceil;'    => chr(8969),
   'lfloor;'   => chr(8970),
   'rfloor;'   => chr(8971),
   'lang;'     => chr(9001),
   'rang;'     => chr(9002),
   'loz;'      => chr(9674),
   'spades;'   => chr(9824),
   'clubs;'    => chr(9827),
   'hearts;'   => chr(9829),
   'diams;'    => chr(9830),
  ) : ())
 );
 
 
 # Make the opposite mapping
 while (my($entity, $char) = each(%entity2char)) {
     $entity =~ s/;\z//;
     $char2entity{$char} = "&$entity;";
 }
 delete $char2entity{"'"};  # only one-way decoding
 
 # Fill in missing entities
 for (0 .. 255) {
     next if exists $char2entity{chr($_)};
     $char2entity{chr($_)} = "&#$_;";
 }
 
 my %subst;  # compiled encoding regexps
 
 sub encode_entities
 {
     return undef unless defined $_[0];
     my $ref;
     if (defined wantarray) {
 	my $x = $_[0];
 	$ref = \$x;     # copy
     } else {
 	$ref = \$_[0];  # modify in-place
     }
     if (defined $_[1] and length $_[1]) {
 	unless (exists $subst{$_[1]}) {
 	    # Because we can't compile regex we fake it with a cached sub
 	    my $chars = $_[1];
 	    $chars =~ s,(?<!\\)([]/]),\\$1,g;
 	    $chars =~ s,(?<!\\)\\\z,\\\\,;
 	    my $code = "sub {\$_[0] =~ s/([$chars])/\$char2entity{\$1} || num_entity(\$1)/ge; }";
 	    $subst{$_[1]} = eval $code;
 	    die( $@ . " while trying to turn range: \"$_[1]\"\n "
 	      . "into code: $code\n "
 	    ) if $@;
 	}
 	&{$subst{$_[1]}}($$ref);
     } else {
 	# Encode control chars, high bit chars and '<', '&', '>', ''' and '"'
 	$$ref =~ s/([^\n\r\t !\#\$%\(-;=?-~])/$char2entity{$1} || num_entity($1)/ge;
     }
     $$ref;
 }
 
 sub encode_entities_numeric {
     local %char2entity;
     return &encode_entities;   # a goto &encode_entities wouldn't work
 }
 
 
 sub num_entity {
     sprintf "&#x%X;", ord($_[0]);
 }
 
 # Set up aliases
 *encode = \&encode_entities;
 *encode_numeric = \&encode_entities_numeric;
 *encode_numerically = \&encode_entities_numeric;
 *decode = \&decode_entities;
 
 1;
### HTML/Filter.pm ###
 package HTML::Filter;
 
 use strict;
 use vars qw(@ISA $VERSION);
 
 require HTML::Parser;
 @ISA=qw(HTML::Parser);
 
 $VERSION = "3.57";
 
 sub declaration { $_[0]->output("<!$_[1]>")     }
 sub process     { $_[0]->output($_[2])          }
 sub comment     { $_[0]->output("<!--$_[1]-->") }
 sub start       { $_[0]->output($_[4])          }
 sub end         { $_[0]->output($_[2])          }
 sub text        { $_[0]->output($_[1])          }
 
 sub output      { print $_[1] }
 
 1;
 
 __END__
 
 =head1 NAME
 
 HTML::Filter - Filter HTML text through the parser
 
 =head1 NOTE
 
 B<This module is deprecated.> The C<HTML::Parser> now provides the
 functionally of C<HTML::Filter> much more efficiently with the the
 C<default> handler.
 
 =head1 SYNOPSIS
 
  require HTML::Filter;
  $p = HTML::Filter->new->parse_file("index.html");
 
 =head1 DESCRIPTION
 
 C<HTML::Filter> is an HTML parser that by default prints the
 original text of each HTML element (a slow version of cat(1) basically).
 The callback methods may be overridden to modify the filtering for some
 HTML elements and you can override output() method which is called to
 print the HTML text.
 
 C<HTML::Filter> is a subclass of C<HTML::Parser>. This means that
 the document should be given to the parser by calling the $p->parse()
 or $p->parse_file() methods.
 
 =head1 EXAMPLES
 
 The first example is a filter that will remove all comments from an
 HTML file.  This is achieved by simply overriding the comment method
 to do nothing.
 
   package CommentStripper;
   require HTML::Filter;
   @ISA=qw(HTML::Filter);
   sub comment { }  # ignore comments
 
 The second example shows a filter that will remove any E<lt>TABLE>s
 found in the HTML file.  We specialize the start() and end() methods
 to count table tags and then make output not happen when inside a
 table.
 
   package TableStripper;
   require HTML::Filter;
   @ISA=qw(HTML::Filter);
   sub start
   {
      my $self = shift;
      $self->{table_seen}++ if $_[0] eq "table";
      $self->SUPER::start(@_);
   }
 
   sub end
   {
      my $self = shift;
      $self->SUPER::end(@_);
      $self->{table_seen}-- if $_[0] eq "table";
   }
 
   sub output
   {
       my $self = shift;
       unless ($self->{table_seen}) {
 	  $self->SUPER::output(@_);
       }
   }
 
 If you want to collect the parsed text internally you might want to do
 something like this:
 
   package FilterIntoString;
   require HTML::Filter;
   @ISA=qw(HTML::Filter);
   sub output { push(@{$_[0]->{fhtml}}, $_[1]) }
   sub filtered_html { join("", @{$_[0]->{fhtml}}) }
 
 =head1 SEE ALSO
 
 L<HTML::Parser>
 
 =head1 COPYRIGHT
 
 Copyright 1997-1999 Gisle Aas.
 
 This library is free software; you can redistribute it and/or
 modify it under the same terms as Perl itself.
 
 =cut
### HTML/HeadParser.pm ###
 package HTML::HeadParser;
 
 =head1 NAME
 
 HTML::HeadParser - Parse <HEAD> section of a HTML document
 
 =head1 SYNOPSIS
 
  require HTML::HeadParser;
  $p = HTML::HeadParser->new;
  $p->parse($text) and  print "not finished";
 
  $p->header('Title')          # to access <title>....</title>
  $p->header('Content-Base')   # to access <base href="http://...">
  $p->header('Foo')            # to access <meta http-equiv="Foo" content="...">
  $p->header('X-Meta-Author')  # to access <meta name="author" content="...">
  $p->header('X-Meta-Charset') # to access <meta charset="...">
 
 =head1 DESCRIPTION
 
 The C<HTML::HeadParser> is a specialized (and lightweight)
 C<HTML::Parser> that will only parse the E<lt>HEAD>...E<lt>/HEAD>
 section of an HTML document.  The parse() method
 will return a FALSE value as soon as some E<lt>BODY> element or body
 text are found, and should not be called again after this.
 
 Note that the C<HTML::HeadParser> might get confused if raw undecoded
 UTF-8 is passed to the parse() method.  Make sure the strings are
 properly decoded before passing them on.
 
 The C<HTML::HeadParser> keeps a reference to a header object, and the
 parser will update this header object as the various elements of the
 E<lt>HEAD> section of the HTML document are recognized.  The following
 header fields are affected:
 
 =over 4
 
 =item Content-Base:
 
 The I<Content-Base> header is initialized from the E<lt>base
 href="..."> element.
 
 =item Title:
 
 The I<Title> header is initialized from the E<lt>title>...E<lt>/title>
 element.
 
 =item Isindex:
 
 The I<Isindex> header will be added if there is a E<lt>isindex>
 element in the E<lt>head>.  The header value is initialized from the
 I<prompt> attribute if it is present.  If no I<prompt> attribute is
 given it will have '?' as the value.
 
 =item X-Meta-Foo:
 
 All E<lt>meta> elements containing a C<name> attribute will result in
 headers using the prefix C<X-Meta-> appended with the value of the
 C<name> attribute as the name of the header, and the value of the
 C<content> attribute as the pushed header value.
 
 E<lt>meta> elements containing a C<http-equiv> attribute will result
 in headers as in above, but without the C<X-Meta-> prefix in the
 header name.
 
 E<lt>meta> elements containing a C<charset> attribute will result in
 an C<X-Meta-Charset> header, using the value of the C<charset>
 attribute as the pushed header value.
 
 The ':' character can't be represented in header field names, so
 if the meta element contains this char it's substituted with '-'
 before forming the field name.
 
 =back
 
 =head1 METHODS
 
 The following methods (in addition to those provided by the
 superclass) are available:
 
 =over 4
 
 =cut
 
 
 require HTML::Parser;
 @ISA = qw(HTML::Parser);
 
 use HTML::Entities ();
 
 use strict;
 use vars qw($VERSION $DEBUG);
 #$DEBUG = 1;
 $VERSION = "3.71";
 
 =item $hp = HTML::HeadParser->new
 
 =item $hp = HTML::HeadParser->new( $header )
 
 The object constructor.  The optional $header argument should be a
 reference to an object that implement the header() and push_header()
 methods as defined by the C<HTTP::Headers> class.  Normally it will be
 of some class that is a or delegates to the C<HTTP::Headers> class.
 
 If no $header is given C<HTML::HeadParser> will create an
 C<HTTP::Headers> object by itself (initially empty).
 
 =cut
 
 sub new
 {
     my($class, $header) = @_;
     unless ($header) {
 	require HTTP::Headers;
 	$header = HTTP::Headers->new;
     }
 
     my $self = $class->SUPER::new(api_version => 3,
 				  start_h => ["start", "self,tagname,attr"],
 				  end_h   => ["end",   "self,tagname"],
 				  text_h  => ["text",  "self,text"],
 				  ignore_elements => [qw(script style)],
 				 );
     $self->{'header'} = $header;
     $self->{'tag'} = '';   # name of active element that takes textual content
     $self->{'text'} = '';  # the accumulated text associated with the element
     $self;
 }
 
 =item $hp->header;
 
 Returns a reference to the header object.
 
 =item $hp->header( $key )
 
 Returns a header value.  It is just a shorter way to write
 C<$hp-E<gt>header-E<gt>header($key)>.
 
 =cut
 
 sub header
 {
     my $self = shift;
     return $self->{'header'} unless @_;
     $self->{'header'}->header(@_);
 }
 
 sub as_string    # legacy
 {
     my $self = shift;
     $self->{'header'}->as_string;
 }
 
 sub flush_text   # internal
 {
     my $self = shift;
     my $tag  = $self->{'tag'};
     my $text = $self->{'text'};
     $text =~ s/^\s+//;
     $text =~ s/\s+$//;
     $text =~ s/\s+/ /g;
     print "FLUSH $tag => '$text'\n"  if $DEBUG;
     if ($tag eq 'title') {
 	my $decoded;
 	$decoded = utf8::decode($text) if $self->utf8_mode && defined &utf8::decode;
 	HTML::Entities::decode($text);
 	utf8::encode($text) if $decoded;
 	$self->{'header'}->push_header(Title => $text);
     }
     $self->{'tag'} = $self->{'text'} = '';
 }
 
 # This is an quote from the HTML3.2 DTD which shows which elements
 # that might be present in a <HEAD>...</HEAD>.  Also note that the
 # <HEAD> tags themselves might be missing:
 #
 # <!ENTITY % head.content "TITLE & ISINDEX? & BASE? & STYLE? &
 #                            SCRIPT* & META* & LINK*">
 #
 # <!ELEMENT HEAD O O  (%head.content)>
 #
 # From HTML 4.01:
 #
 # <!ENTITY % head.misc "SCRIPT|STYLE|META|LINK|OBJECT">
 # <!ENTITY % head.content "TITLE & BASE?">
 # <!ELEMENT HEAD O O (%head.content;) +(%head.misc;)>
 #
 # From HTML 5 as of WD-html5-20090825:
 #
 # One or more elements of metadata content, [...]
 # => base, command, link, meta, noscript, script, style, title
 
 sub start
 {
     my($self, $tag, $attr) = @_;  # $attr is reference to a HASH
     print "START[$tag]\n" if $DEBUG;
     $self->flush_text if $self->{'tag'};
     if ($tag eq 'meta') {
 	my $key = $attr->{'http-equiv'};
 	if (!defined($key) || !length($key)) {
 	    if ($attr->{name}) {
 		$key = "X-Meta-\u$attr->{name}";
 	    } elsif ($attr->{charset}) { # HTML 5 <meta charset="...">
 		$key = "X-Meta-Charset";
 		$self->{header}->push_header($key => $attr->{charset});
 		return;
 	    } else {
 		return;
 	    }
 	}
 	$key =~ s/:/-/g;
 	$self->{'header'}->push_header($key => $attr->{content});
     } elsif ($tag eq 'base') {
 	return unless exists $attr->{href};
 	(my $base = $attr->{href}) =~ s/^\s+//; $base =~ s/\s+$//; # HTML5
 	$self->{'header'}->push_header('Content-Base' => $base);
     } elsif ($tag eq 'isindex') {
 	# This is a non-standard header.  Perhaps we should just ignore
 	# this element
 	$self->{'header'}->push_header(Isindex => $attr->{prompt} || '?');
     } elsif ($tag =~ /^(?:title|noscript|object|command)$/) {
 	# Just remember tag.  Initialize header when we see the end tag.
 	$self->{'tag'} = $tag;
     } elsif ($tag eq 'link') {
 	return unless exists $attr->{href};
 	# <link href="http:..." rel="xxx" rev="xxx" title="xxx">
 	my $href = delete($attr->{href});
 	$href =~ s/^\s+//; $href =~ s/\s+$//; # HTML5
 	my $h_val = "<$href>";
 	for (sort keys %{$attr}) {
 	    next if $_ eq "/";  # XHTML junk
 	    $h_val .= qq(; $_="$attr->{$_}");
 	}
 	$self->{'header'}->push_header(Link => $h_val);
     } elsif ($tag eq 'head' || $tag eq 'html') {
 	# ignore
     } else {
 	 # stop parsing
 	$self->eof;
     }
 }
 
 sub end
 {
     my($self, $tag) = @_;
     print "END[$tag]\n" if $DEBUG;
     $self->flush_text if $self->{'tag'};
     $self->eof if $tag eq 'head';
 }
 
 sub text
 {
     my($self, $text) = @_;
     print "TEXT[$text]\n" if $DEBUG;
     unless ($self->{first_chunk}) {
 	# drop Unicode BOM if found
 	if ($self->utf8_mode) {
 	    $text =~ s/^\xEF\xBB\xBF//;
 	}
 	else {
 	    $text =~ s/^\x{FEFF}//;
 	}
 	$self->{first_chunk}++;
     }
     my $tag = $self->{tag};
     if (!$tag && $text =~ /\S/) {
 	# Normal text means start of body
         $self->eof;
 	return;
     }
     return if $tag ne 'title';
     $self->{'text'} .= $text;
 }
 
 BEGIN {
     *utf8_mode = sub { 1 } unless HTML::Entities::UNICODE_SUPPORT;
 }
 
 1;
 
 __END__
 
 =back
 
 =head1 EXAMPLE
 
  $h = HTTP::Headers->new;
  $p = HTML::HeadParser->new($h);
  $p->parse(<<EOT);
  <title>Stupid example</title>
  <base href="http://www.linpro.no/lwp/">
  Normal text starts here.
  EOT
  undef $p;
  print $h->title;   # should print "Stupid example"
 
 =head1 SEE ALSO
 
 L<HTML::Parser>, L<HTTP::Headers>
 
 The C<HTTP::Headers> class is distributed as part of the
 I<libwww-perl> package.  If you don't have that distribution installed
 you need to provide the $header argument to the C<HTML::HeadParser>
 constructor with your own object that implements the documented
 protocol.
 
 =head1 COPYRIGHT
 
 Copyright 1996-2001 Gisle Aas. All rights reserved.
 
 This library is free software; you can redistribute it and/or
 modify it under the same terms as Perl itself.
 
 =cut
 
### HTML/LinkExtor.pm ###
 package HTML::LinkExtor;
 
 require HTML::Parser;
 @ISA = qw(HTML::Parser);
 $VERSION = "3.69";
 
 =head1 NAME
 
 HTML::LinkExtor - Extract links from an HTML document
 
 =head1 SYNOPSIS
 
  require HTML::LinkExtor;
  $p = HTML::LinkExtor->new(\&cb, "http://www.perl.org/");
  sub cb {
      my($tag, %links) = @_;
      print "$tag @{[%links]}\n";
  }
  $p->parse_file("index.html");
 
 =head1 DESCRIPTION
 
 I<HTML::LinkExtor> is an HTML parser that extracts links from an
 HTML document.  The I<HTML::LinkExtor> is a subclass of
 I<HTML::Parser>. This means that the document should be given to the
 parser by calling the $p->parse() or $p->parse_file() methods.
 
 =cut
 
 use strict;
 use HTML::Tagset ();
 
 # legacy (some applications grabs this hash directly)
 use vars qw(%LINK_ELEMENT);
 *LINK_ELEMENT = \%HTML::Tagset::linkElements;
 
 =over 4
 
 =item $p = HTML::LinkExtor->new
 
 =item $p = HTML::LinkExtor->new( $callback )
 
 =item $p = HTML::LinkExtor->new( $callback, $base )
 
 The constructor takes two optional arguments. The first is a reference
 to a callback routine. It will be called as links are found. If a
 callback is not provided, then links are just accumulated internally
 and can be retrieved by calling the $p->links() method.
 
 The $base argument is an optional base URL used to absolutize all URLs found.
 You need to have the I<URI> module installed if you provide $base.
 
 The callback is called with the lowercase tag name as first argument,
 and then all link attributes as separate key/value pairs.  All
 non-link attributes are removed.
 
 =cut
 
 sub new
 {
     my($class, $cb, $base) = @_;
     my $self = $class->SUPER::new(
                     start_h => ["_start_tag", "self,tagname,attr"],
 		    report_tags => [keys %HTML::Tagset::linkElements],
 	       );
     $self->{extractlink_cb} = $cb;
     if ($base) {
 	require URI;
 	$self->{extractlink_base} = URI->new($base);
     }
     $self;
 }
 
 sub _start_tag
 {
     my($self, $tag, $attr) = @_;
 
     my $base = $self->{extractlink_base};
     my $links = $HTML::Tagset::linkElements{$tag};
     $links = [$links] unless ref $links;
 
     my @links;
     my $a;
     for $a (@$links) {
 	next unless exists $attr->{$a};
 	(my $link = $attr->{$a}) =~ s/^\s+//; $link =~ s/\s+$//; # HTML5
 	push(@links, $a, $base ? URI->new($link, $base)->abs($base) : $link);
     }
     return unless @links;
     $self->_found_link($tag, @links);
 }
 
 sub _found_link
 {
     my $self = shift;
     my $cb = $self->{extractlink_cb};
     if ($cb) {
 	&$cb(@_);
     } else {
 	push(@{$self->{'links'}}, [@_]);
     }
 }
 
 =item $p->links
 
 Returns a list of all links found in the document.  The returned
 values will be anonymous arrays with the following elements:
 
   [$tag, $attr => $url1, $attr2 => $url2,...]
 
 The $p->links method will also truncate the internal link list.  This
 means that if the method is called twice without any parsing
 between them the second call will return an empty list.
 
 Also note that $p->links will always be empty if a callback routine
 was provided when the I<HTML::LinkExtor> was created.
 
 =cut
 
 sub links
 {
     my $self = shift;
     exists($self->{'links'}) ? @{delete $self->{'links'}} : ();
 }
 
 # We override the parse_file() method so that we can clear the links
 # before we start a new file.
 sub parse_file
 {
     my $self = shift;
     delete $self->{'links'};
     $self->SUPER::parse_file(@_);
 }
 
 =back
 
 =head1 EXAMPLE
 
 This is an example showing how you can extract links from a document
 received using LWP:
 
   use LWP::UserAgent;
   use HTML::LinkExtor;
   use URI::URL;
 
   $url = "http://www.perl.org/";  # for instance
   $ua = LWP::UserAgent->new;
 
   # Set up a callback that collect image links
   my @imgs = ();
   sub callback {
      my($tag, %attr) = @_;
      return if $tag ne 'img';  # we only look closer at <img ...>
      push(@imgs, values %attr);
   }
 
   # Make the parser.  Unfortunately, we don't know the base yet
   # (it might be different from $url)
   $p = HTML::LinkExtor->new(\&callback);
 
   # Request document and parse it as it arrives
   $res = $ua->request(HTTP::Request->new(GET => $url),
                       sub {$p->parse($_[0])});
 
   # Expand all image URLs to absolute ones
   my $base = $res->base;
   @imgs = map { $_ = url($_, $base)->abs; } @imgs;
 
   # Print them out
   print join("\n", @imgs), "\n";
 
 =head1 SEE ALSO
 
 L<HTML::Parser>, L<HTML::Tagset>, L<LWP>, L<URI::URL>
 
 =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.
 
 =cut
 
 1;
### HTML/Parser.pm ###
 package HTML::Parser;
 
 # Copyright 1996-2009, Gisle Aas.
 # Copyright 1999-2000, Michael A. Chase.
 #
 # This library is free software; you can redistribute it and/or
 # modify it under the same terms as Perl itself.
 
 use strict;
 use vars qw($VERSION @ISA);
 
 $VERSION = "3.71";
 
 require HTML::Entities;
 
 require XSLoader;
 XSLoader::load('HTML::Parser', $VERSION);
 
 sub new
 {
     my $class = shift;
     my $self = bless {}, $class;
     return $self->init(@_);
 }
 
 
 sub init
 {
     my $self = shift;
     $self->_alloc_pstate;
 
     my %arg = @_;
     my $api_version = delete $arg{api_version} || (@_ ? 3 : 2);
     if ($api_version >= 4) {
 	require Carp;
 	Carp::croak("API version $api_version not supported " .
 		    "by HTML::Parser $VERSION");
     }
 
     if ($api_version < 3) {
 	# Set up method callbacks compatible with HTML-Parser-2.xx
 	$self->handler(text    => "text",    "self,text,is_cdata");
 	$self->handler(end     => "end",     "self,tagname,text");
 	$self->handler(process => "process", "self,token0,text");
 	$self->handler(start   => "start",
 		                  "self,tagname,attr,attrseq,text");
 
 	$self->handler(comment =>
 		       sub {
 			   my($self, $tokens) = @_;
 			   for (@$tokens) {
 			       $self->comment($_);
 			   }
 		       }, "self,tokens");
 
 	$self->handler(declaration =>
 		       sub {
 			   my $self = shift;
 			   $self->declaration(substr($_[0], 2, -1));
 		       }, "self,text");
     }
 
     if (my $h = delete $arg{handlers}) {
 	$h = {@$h} if ref($h) eq "ARRAY";
 	while (my($event, $cb) = each %$h) {
 	    $self->handler($event => @$cb);
 	}
     }
 
     # In the end we try to assume plain attribute or handler
     while (my($option, $val) = each %arg) {
 	if ($option =~ /^(\w+)_h$/) {
 	    $self->handler($1 => @$val);
 	}
         elsif ($option =~ /^(text|start|end|process|declaration|comment)$/) {
 	    require Carp;
 	    Carp::croak("Bad constructor option '$option'");
         }
 	else {
 	    $self->$option($val);
 	}
     }
 
     return $self;
 }
 
 
 sub parse_file
 {
     my($self, $file) = @_;
     my $opened;
     if (!ref($file) && ref(\$file) ne "GLOB") {
         # Assume $file is a filename
         local(*F);
         open(F, "<", $file) || return undef;
 	binmode(F);  # should we? good for byte counts
         $opened++;
         $file = *F;
     }
     my $chunk = '';
     while (read($file, $chunk, 512)) {
 	$self->parse($chunk) || last;
     }
     close($file) if $opened;
     $self->eof;
 }
 
 
 sub netscape_buggy_comment  # legacy
 {
     my $self = shift;
     require Carp;
     Carp::carp("netscape_buggy_comment() is deprecated.  " .
 	       "Please use the strict_comment() method instead");
     my $old = !$self->strict_comment;
     $self->strict_comment(!shift) if @_;
     return $old;
 }
 
 # set up method stubs
 sub text { }
 *start       = \&text;
 *end         = \&text;
 *comment     = \&text;
 *declaration = \&text;
 *process     = \&text;
 
 1;
 
 __END__
 
 
 =head1 NAME
 
 HTML::Parser - HTML parser class
 
 =head1 SYNOPSIS
 
  use HTML::Parser ();
 
  # Create parser object
  $p = HTML::Parser->new( api_version => 3,
                          start_h => [\&start, "tagname, attr"],
                          end_h   => [\&end,   "tagname"],
                          marked_sections => 1,
                        );
 
  # Parse document text chunk by chunk
  $p->parse($chunk1);
  $p->parse($chunk2);
  #...
  $p->eof;                 # signal end of document
 
  # Parse directly from file
  $p->parse_file("foo.html");
  # or
  open(my $fh, "<:utf8", "foo.html") || die;
  $p->parse_file($fh);
 
 =head1 DESCRIPTION
 
 Objects of the C<HTML::Parser> class will recognize markup and
 separate it from plain text (alias data content) in HTML
 documents.  As different kinds of markup and text are recognized, the
 corresponding event handlers are invoked.
 
 C<HTML::Parser> is not a generic SGML parser.  We have tried to
 make it able to deal with the HTML that is actually "out there", and
 it normally parses as closely as possible to the way the popular web
 browsers do it instead of strictly following one of the many HTML
 specifications from W3C.  Where there is disagreement, there is often
 an option that you can enable to get the official behaviour.
 
 The document to be parsed may be supplied in arbitrary chunks.  This
 makes on-the-fly parsing as documents are received from the network
 possible.
 
 If event driven parsing does not feel right for your application, you
 might want to use C<HTML::PullParser>.  This is an C<HTML::Parser>
 subclass that allows a more conventional program structure.
 
 
 =head1 METHODS
 
 The following method is used to construct a new C<HTML::Parser> object:
 
 =over
 
 =item $p = HTML::Parser->new( %options_and_handlers )
 
 This class method creates a new C<HTML::Parser> object and
 returns it.  Key/value argument pairs may be provided to assign event
 handlers or initialize parser options.  The handlers and parser
 options can also be set or modified later by the method calls described below.
 
 If a top level key is in the form "<event>_h" (e.g., "text_h") then it
 assigns a handler to that event, otherwise it initializes a parser
 option. The event handler specification value must be an array
 reference.  Multiple handlers may also be assigned with the 'handlers
 => [%handlers]' option.  See examples below.
 
 If new() is called without any arguments, it will create a parser that
 uses callback methods compatible with version 2 of C<HTML::Parser>.
 See the section on "version 2 compatibility" below for details.
 
 The special constructor option 'api_version => 2' can be used to
 initialize version 2 callbacks while still setting other options and
 handlers.  The 'api_version => 3' option can be used if you don't want
 to set any options and don't want to fall back to v2 compatible
 mode.
 
 Examples:
 
  $p = HTML::Parser->new(api_version => 3,
                         text_h => [ sub {...}, "dtext" ]);
 
 This creates a new parser object with a text event handler subroutine
 that receives the original text with general entities decoded.
 
  $p = HTML::Parser->new(api_version => 3,
 			start_h => [ 'my_start', "self,tokens" ]);
 
 This creates a new parser object with a start event handler method
 that receives the $p and the tokens array.
 
  $p = HTML::Parser->new(api_version => 3,
 		        handlers => { text => [\@array, "event,text"],
                                       comment => [\@array, "event,text"],
                                     });
 
 This creates a new parser object that stores the event type and the
 original text in @array for text and comment events.
 
 =back
 
 The following methods feed the HTML document
 to the C<HTML::Parser> object:
 
 =over
 
 =item $p->parse( $string )
 
 Parse $string as the next chunk of the HTML document.  Handlers invoked should
 not attempt to modify the $string in-place until $p->parse returns.
 
 If an invoked event handler aborts parsing by calling $p->eof, then $p->parse()
 will return a FALSE value.  Otherwise the return value is a reference to the
 parser object ($p).
 
 =item $p->parse( $code_ref )
 
 If a code reference is passed as the argument to be parsed, then the
 chunks to be parsed are obtained by invoking this function repeatedly.
 Parsing continues until the function returns an empty (or undefined)
 result.  When this happens $p->eof is automatically signaled.
 
 Parsing will also abort if one of the event handlers calls $p->eof.
 
 The effect of this is the same as:
 
  while (1) {
     my $chunk = &$code_ref();
     if (!defined($chunk) || !length($chunk)) {
         $p->eof;
         return $p;
     }
     $p->parse($chunk) || return undef;
  }
 
 But it is more efficient as this loop runs internally in XS code.
 
 =item $p->parse_file( $file )
 
 Parse text directly from a file.  The $file argument can be a
 filename, an open file handle, or a reference to an open file
 handle.
 
 If $file contains a filename and the file can't be opened, then the
 method returns an undefined value and $! tells why it failed.
 Otherwise the return value is a reference to the parser object.
 
 If a file handle is passed as the $file argument, then the file will
 normally be read until EOF, but not closed.
 
 If an invoked event handler aborts parsing by calling $p->eof,
 then $p->parse_file() may not have read the entire file.
 
 On systems with multi-byte line terminators, the values passed for the
 offset and length argspecs may be too low if parse_file() is called on
 a file handle that is not in binary mode.
 
 If a filename is passed in, then parse_file() will open the file in
 binary mode.
 
 =item $p->eof
 
 Signals the end of the HTML document.  Calling the $p->eof method
 outside a handler callback will flush any remaining buffered text
 (which triggers the C<text> event if there is any remaining text).
 
 Calling $p->eof inside a handler will terminate parsing at that point
 and cause $p->parse to return a FALSE value.  This also terminates
 parsing by $p->parse_file().
 
 After $p->eof has been called, the parse() and parse_file() methods
 can be invoked to feed new documents with the parser object.
 
 The return value from eof() is a reference to the parser object.
 
 =back
 
 
 Most parser options are controlled by boolean attributes.
 Each boolean attribute is enabled by calling the corresponding method
 with a TRUE argument and disabled with a FALSE argument.  The
 attribute value is left unchanged if no argument is given.  The return
 value from each method is the old attribute value.
 
 Methods that can be used to get and/or set parser options are:
 
 =over
 
 =item $p->attr_encoded
 
 =item $p->attr_encoded( $bool )
 
 By default, the C<attr> and C<@attr> argspecs will have general
 entities for attribute values decoded.  Enabling this attribute leaves
 entities alone.
 
 =item $p->backquote
 
 =item $p->backquote( $bool )
 
 By default, only ' and " are recognized as quote characters around
 attribute values.  MSIE also recognizes backquotes for some reason.
 Enabling this attribute provides compatibility with this behaviour.
 
 =item $p->boolean_attribute_value( $val )
 
 This method sets the value reported for boolean attributes inside HTML
 start tags.  By default, the name of the attribute is also used as its
 value.  This affects the values reported for C<tokens> and C<attr>
 argspecs.
 
 =item $p->case_sensitive
 
 =item $p->case_sensitive( $bool )
 
 By default, tagnames and attribute names are down-cased.  Enabling this
 attribute leaves them as found in the HTML source document.
 
 =item $p->closing_plaintext
 
 =item $p->closing_plaintext( $bool )
 
 By default, "plaintext" element can never be closed. Everything up to
 the end of the document is parsed in CDATA mode.  This historical
 behaviour is what at least MSIE does.  Enabling this attribute makes
 closing "</plaintext>" tag effective and the parsing process will resume
 after seeing this tag.  This emulates early gecko-based browsers.
 
 =item $p->empty_element_tags
 
 =item $p->empty_element_tags( $bool )
 
 By default, empty element tags are not recognized as such and the "/"
 before ">" is just treated like a normal name character (unless
 C<strict_names> is enabled).  Enabling this attribute make
 C<HTML::Parser> recognize these tags.
 
 Empty element tags look like start tags, but end with the character
 sequence "/>" instead of ">".  When recognized by C<HTML::Parser> they
 cause an artificial end event in addition to the start event.  The
 C<text> for the artificial end event will be empty and the C<tokenpos>
 array will be undefined even though the the token array will have one
 element containing the tag name.
 
 =item $p->marked_sections
 
 =item $p->marked_sections( $bool )
 
 By default, section markings like <![CDATA[...]]> are treated like
 ordinary text.  When this attribute is enabled section markings are
 honoured.
 
 There are currently no events associated with the marked section
 markup, but the text can be returned as C<skipped_text>.
 
 =item $p->strict_comment
 
 =item $p->strict_comment( $bool )
 
 By default, comments are terminated by the first occurrence of "-->".
 This is the behaviour of most popular browsers (like Mozilla, Opera and
 MSIE), but it is not correct according to the official HTML
 standard.  Officially, you need an even number of "--" tokens before
 the closing ">" is recognized and there may not be anything but
 whitespace between an even and an odd "--".
 
 The official behaviour is enabled by enabling this attribute.
 
 Enabling of 'strict_comment' also disables recognizing these forms as
 comments:
 
   </ comment>
   <! comment>
 
 
 =item $p->strict_end
 
 =item $p->strict_end( $bool )
 
 By default, attributes and other junk are allowed to be present on end tags in a
 manner that emulates MSIE's behaviour.
 
 The official behaviour is enabled with this attribute.  If enabled,
 only whitespace is allowed between the tagname and the final ">".
 
 =item $p->strict_names
 
 =item $p->strict_names( $bool )
 
 By default, almost anything is allowed in tag and attribute names.
 This is the behaviour of most popular browsers and allows us to parse
 some broken tags with invalid attribute values like:
 
    <IMG SRC=newprevlstGr.gif ALT=[PREV LIST] BORDER=0>
 
 By default, "LIST]" is parsed as a boolean attribute, not as
 part of the ALT value as was clearly intended.  This is also what
 Mozilla sees.
 
 The official behaviour is enabled by enabling this attribute.  If
 enabled, it will cause the tag above to be reported as text
 since "LIST]" is not a legal attribute name.
 
 =item $p->unbroken_text
 
 =item $p->unbroken_text( $bool )
 
 By default, blocks of text are given to the text handler as soon as
 possible (but the parser takes care always to break text at a
 boundary between whitespace and non-whitespace so single words and
 entities can always be decoded safely).  This might create breaks that
 make it hard to do transformations on the text. When this attribute is
 enabled, blocks of text are always reported in one piece.  This will
 delay the text event until the following (non-text) event has been
 recognized by the parser.
 
 Note that the C<offset> argspec will give you the offset of the first
 segment of text and C<length> is the combined length of the segments.
 Since there might be ignored tags in between, these numbers can't be
 used to directly index in the original document file.
 
 =item $p->utf8_mode
 
 =item $p->utf8_mode( $bool )
 
 Enable this option when parsing raw undecoded UTF-8.  This tells the
 parser that the entities expanded for strings reported by C<attr>,
 C<@attr> and C<dtext> should be expanded as decoded UTF-8 so they end
 up compatible with the surrounding text.
 
 If C<utf8_mode> is enabled then it is an error to pass strings
 containing characters with code above 255 to the parse() method, and
 the parse() method will croak if you try.
 
 Example: The Unicode character "\x{2665}" is "\xE2\x99\xA5" when UTF-8
 encoded.  The character can also be represented by the entity
 "&hearts;" or "&#x2665".  If we feed the parser:
 
   $p->parse("\xE2\x99\xA5&hearts;");
 
 then C<dtext> will be reported as "\xE2\x99\xA5\x{2665}" without
 C<utf8_mode> enabled, but as "\xE2\x99\xA5\xE2\x99\xA5" when enabled.
 The later string is what you want.
 
 This option is only available with perl-5.8 or better.
 
 =item $p->xml_mode
 
 =item $p->xml_mode( $bool )
 
 Enabling this attribute changes the parser to allow some XML
 constructs.  This enables the behaviour controlled by individually by
 the C<case_sensitive>, C<empty_element_tags>, C<strict_names> and
 C<xml_pic> attributes and also suppresses special treatment of
 elements that are parsed as CDATA for HTML.
 
 =item $p->xml_pic
 
 =item $p->xml_pic( $bool )
 
 By default, I<processing instructions> are terminated by ">". When
 this attribute is enabled, processing instructions are terminated by
 "?>" instead.
 
 =back
 
 As markup and text is recognized, handlers are invoked.  The following
 method is used to set up handlers for different events:
 
 =over
 
 =item $p->handler( event => \&subroutine, $argspec )
 
 =item $p->handler( event => $method_name, $argspec )
 
 =item $p->handler( event => \@accum, $argspec )
 
 =item $p->handler( event => "" );
 
 =item $p->handler( event => undef );
 
 =item $p->handler( event );
 
 This method assigns a subroutine, method, or array to handle an event.
 
 Event is one of C<text>, C<start>, C<end>, C<declaration>, C<comment>,
 C<process>, C<start_document>, C<end_document> or C<default>.
 
 The C<\&subroutine> is a reference to a subroutine which is called to handle
 the event.
 
 The C<$method_name> is the name of a method of $p which is called to handle
 the event.
 
 The C<@accum> is an array that will hold the event information as
 sub-arrays.
 
 If the second argument is "", the event is ignored.
 If it is undef, the default handler is invoked for the event.
 
 The C<$argspec> is a string that describes the information to be reported
 for the event.  Any requested information that does not apply to a
 specific event is passed as C<undef>.  If argspec is omitted, then it
 is left unchanged.
 
 The return value from $p->handler is the old callback routine or a
 reference to the accumulator array.
 
 Any return values from handler callback routines/methods are always
 ignored.  A handler callback can request parsing to be aborted by
 invoking the $p->eof method.  A handler callback is not allowed to
 invoke the $p->parse() or $p->parse_file() method.  An exception will
 be raised if it tries.
 
 Examples:
 
     $p->handler(start =>  "start", 'self, attr, attrseq, text' );
 
 This causes the "start" method of object $p to be called for 'start' events.
 The callback signature is $p->start(\%attr, \@attr_seq, $text).
 
     $p->handler(start =>  \&start, 'attr, attrseq, text' );
 
 This causes subroutine start() to be called for 'start' events.
 The callback signature is start(\%attr, \@attr_seq, $text).
 
     $p->handler(start =>  \@accum, '"S", attr, attrseq, text' );
 
 This causes 'start' event information to be saved in @accum.
 The array elements will be ['S', \%attr, \@attr_seq, $text].
 
    $p->handler(start => "");
 
 This causes 'start' events to be ignored.  It also suppresses
 invocations of any default handler for start events.  It is in most
 cases equivalent to $p->handler(start => sub {}), but is more
 efficient.  It is different from the empty-sub-handler in that
 C<skipped_text> is not reset by it.
 
    $p->handler(start => undef);
 
 This causes no handler to be associated with start events.
 If there is a default handler it will be invoked.
 
 =back
 
 Filters based on tags can be set up to limit the number of events
 reported.  The main bottleneck during parsing is often the huge number
 of callbacks made from the parser.  Applying filters can improve
 performance significantly.
 
 The following methods control filters:
 
 =over
 
 =item $p->ignore_elements( @tags )
 
 Both the C<start> event and the C<end> event as well as any events that
 would be reported in between are suppressed.  The ignored elements can
 contain nested occurrences of itself.  Example:
 
    $p->ignore_elements(qw(script style));
 
 The C<script> and C<style> tags will always nest properly since their
 content is parsed in CDATA mode.  For most other tags
 C<ignore_elements> must be used with caution since HTML is often not
 I<well formed>.
 
 =item $p->ignore_tags( @tags )
 
 Any C<start> and C<end> events involving any of the tags given are
 suppressed.  To reset the filter (i.e. don't suppress any C<start> and
 C<end> events), call C<ignore_tags> without an argument.
 
 =item $p->report_tags( @tags )
 
 Any C<start> and C<end> events involving any of the tags I<not> given
 are suppressed.  To reset the filter (i.e. report all C<start> and
 C<end> events), call C<report_tags> without an argument.
 
 =back
 
 Internally, the system has two filter lists, one for C<report_tags>
 and one for C<ignore_tags>, and both filters are applied.  This
 effectively gives C<ignore_tags> precedence over C<report_tags>.
 
 Examples:
 
    $p->ignore_tags(qw(style));
    $p->report_tags(qw(script style));
 
 results in only C<script> events being reported.
 
 =head2 Argspec
 
 Argspec is a string containing a comma-separated list that describes
 the information reported by the event.  The following argspec
 identifier names can be used:
 
 =over
 
 =item C<attr>
 
 Attr causes a reference to a hash of attribute name/value pairs to be
 passed.
 
 Boolean attributes' values are either the value set by
 $p->boolean_attribute_value, or the attribute name if no value has been
 set by $p->boolean_attribute_value.
 
 This passes undef except for C<start> events.
 
 Unless C<xml_mode> or C<case_sensitive> is enabled, the attribute
 names are forced to lower case.
 
 General entities are decoded in the attribute values and
 one layer of matching quotes enclosing the attribute values is removed.
 
 The Unicode character set is assumed for entity decoding.
 
 =item C<@attr>
 
 Basically the same as C<attr>, but keys and values are passed as
 individual arguments and the original sequence of the attributes is
 kept.  The parameters passed will be the same as the @attr calculated
 here:
 
    @attr = map { $_ => $attr->{$_} } @$attrseq;
 
 assuming $attr and $attrseq here are the hash and array passed as the
 result of C<attr> and C<attrseq> argspecs.
 
 This passes no values for events besides C<start>.
 
 =item C<attrseq>
 
 Attrseq causes a reference to an array of attribute names to be
 passed.  This can be useful if you want to walk the C<attr> hash in
 the original sequence.
 
 This passes undef except for C<start> events.
 
 Unless C<xml_mode> or C<case_sensitive> is enabled, the attribute
 names are forced to lower case.
 
 =item C<column>
 
 Column causes the column number of the start of the event to be passed.
 The first column on a line is 0.
 
 =item C<dtext>
 
 Dtext causes the decoded text to be passed.  General entities are
 automatically decoded unless the event was inside a CDATA section or
 was between literal start and end tags (C<script>, C<style>,
 C<xmp>, C<iframe>, C<title>, C<textarea> and C<plaintext>).
 
 The Unicode character set is assumed for entity decoding.  With Perl
 version 5.6 or earlier only the Latin-1 range is supported, and
 entities for characters outside the range 0..255 are left unchanged.
 
 This passes undef except for C<text> events.
 
 =item C<event>
 
 Event causes the event name to be passed.
 
 The event name is one of C<text>, C<start>, C<end>, C<declaration>,
 C<comment>, C<process>, C<start_document> or C<end_document>.
 
 =item C<is_cdata>
 
 Is_cdata causes a TRUE value to be passed if the event is inside a CDATA
 section or between literal start and end tags (C<script>,
 C<style>, C<xmp>, C<iframe>, C<title>, C<textarea> and C<plaintext>).
 
 if the flag is FALSE for a text event, then you should normally
 either use C<dtext> or decode the entities yourself before the text is
 processed further.
 
 =item C<length>
 
 Length causes the number of bytes of the source text of the event to
 be passed.
 
 =item C<line>
 
 Line causes the line number of the start of the event to be passed.
 The first line in the document is 1.  Line counting doesn't start
 until at least one handler requests this value to be reported.
 
 =item C<offset>
 
 Offset causes the byte position in the HTML document of the start of
 the event to be passed.  The first byte in the document has offset 0.
 
 =item C<offset_end>
 
 Offset_end causes the byte position in the HTML document of the end of
 the event to be passed.  This is the same as C<offset> + C<length>.
 
 =item C<self>
 
 Self causes the current object to be passed to the handler.  If the
 handler is a method, this must be the first element in the argspec.
 
 An alternative to passing self as an argspec is to register closures
 that capture $self by themselves as handlers.  Unfortunately this
 creates circular references which prevent the HTML::Parser object
 from being garbage collected.  Using the C<self> argspec avoids this
 problem.
 
 =item C<skipped_text>
 
 Skipped_text returns the concatenated text of all the events that have
 been skipped since the last time an event was reported.  Events might
 be skipped because no handler is registered for them or because some
 filter applies.  Skipped text also includes marked section markup,
 since there are no events that can catch it.
 
 If an C<"">-handler is registered for an event, then the text for this
 event is not included in C<skipped_text>.  Skipped text both before
 and after the C<"">-event is included in the next reported
 C<skipped_text>.
 
 =item C<tag>
 
 Same as C<tagname>, but prefixed with "/" if it belongs to an C<end>
 event and "!" for a declaration.  The C<tag> does not have any prefix
 for C<start> events, and is in this case identical to C<tagname>.
 
 =item C<tagname>
 
 This is the element name (or I<generic identifier> in SGML jargon) for
 start and end tags.  Since HTML is case insensitive, this name is
 forced to lower case to ease string matching.
 
 Since XML is case sensitive, the tagname case is not changed when
 C<xml_mode> is enabled.  The same happens if the C<case_sensitive> attribute
 is set.
 
 The declaration type of declaration elements is also passed as a tagname,
 even if that is a bit strange.
 In fact, in the current implementation tagname is
 identical to C<token0> except that the name may be forced to lower case.
 
 =item C<token0>
 
 Token0 causes the original text of the first token string to be
 passed.  This should always be the same as $tokens->[0].
 
 For C<declaration> events, this is the declaration type.
 
 For C<start> and C<end> events, this is the tag name.
 
 For C<process> and non-strict C<comment> events, this is everything
 inside the tag.
 
 This passes undef if there are no tokens in the event.
 
 =item C<tokenpos>
 
 Tokenpos causes a reference to an array of token positions to be
 passed.  For each string that appears in C<tokens>, this array
 contains two numbers.  The first number is the offset of the start of
 the token in the original C<text> and the second number is the length
 of the token.
 
 Boolean attributes in a C<start> event will have (0,0) for the
 attribute value offset and length.
 
 This passes undef if there are no tokens in the event (e.g., C<text>)
 and for artificial C<end> events triggered by empty element tags.
 
 If you are using these offsets and lengths to modify C<text>, you
 should either work from right to left, or be very careful to calculate
 the changes to the offsets.
 
 =item C<tokens>
 
 Tokens causes a reference to an array of token strings to be passed.
 The strings are exactly as they were found in the original text,
 no decoding or case changes are applied.
 
 For C<declaration> events, the array contains each word, comment, and
 delimited string starting with the declaration type.
 
 For C<comment> events, this contains each sub-comment.  If
 $p->strict_comments is disabled, there will be only one sub-comment.
 
 For C<start> events, this contains the original tag name followed by
 the attribute name/value pairs.  The values of boolean attributes will
 be either the value set by $p->boolean_attribute_value, or the
 attribute name if no value has been set by
 $p->boolean_attribute_value.
 
 For C<end> events, this contains the original tag name (always one token).
 
 For C<process> events, this contains the process instructions (always one
 token).
 
 This passes C<undef> for C<text> events.
 
 =item C<text>
 
 Text causes the source text (including markup element delimiters) to be
 passed.
 
 =item C<undef>
 
 Pass an undefined value.  Useful as padding where the same handler
 routine is registered for multiple events.
 
 =item C<'...'>
 
 A literal string of 0 to 255 characters enclosed
 in single (') or double (") quotes is passed as entered.
 
 =back
 
 The whole argspec string can be wrapped up in C<'@{...}'> to signal
 that the resulting event array should be flattened.  This only makes a
 difference if an array reference is used as the handler target.
 Consider this example:
 
    $p->handler(text => [], 'text');
    $p->handler(text => [], '@{text}']);
 
 With two text events; C<"foo">, C<"bar">; then the first example will end
 up with [["foo"], ["bar"]] and the second with ["foo", "bar"] in
 the handler target array.
 
 
 =head2 Events
 
 Handlers for the following events can be registered:
 
 =over
 
 =item C<comment>
 
 This event is triggered when a markup comment is recognized.
 
 Example:
 
   <!-- This is a comment -- -- So is this -->
 
 =item C<declaration>
 
 This event is triggered when a I<markup declaration> is recognized.
 
 For typical HTML documents, the only declaration you are
 likely to find is <!DOCTYPE ...>.
 
 Example:
 
   <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
       "http://www.w3.org/TR/html4/strict.dtd">
 
 DTDs inside <!DOCTYPE ...> will confuse HTML::Parser.
 
 =item C<default>
 
 This event is triggered for events that do not have a specific
 handler.  You can set up a handler for this event to catch stuff you
 did not want to catch explicitly.
 
 =item C<end>
 
 This event is triggered when an end tag is recognized.
 
 Example:
 
   </A>
 
 =item C<end_document>
 
 This event is triggered when $p->eof is called and after any remaining
 text is flushed.  There is no document text associated with this event.
 
 =item C<process>
 
 This event is triggered when a processing instructions markup is
 recognized.
 
 The format and content of processing instructions are system and
 application dependent.
 
 Examples:
 
   <? HTML processing instructions >
   <? XML processing instructions ?>
 
 =item C<start>
 
 This event is triggered when a start tag is recognized.
 
 Example:
 
   <A HREF="http://www.perl.com/">
 
 =item C<start_document>
 
 This event is triggered before any other events for a new document.  A
 handler for it can be used to initialize stuff.  There is no document
 text associated with this event.
 
 =item C<text>
 
 This event is triggered when plain text (characters) is recognized.
 The text may contain multiple lines.  A sequence of text may be broken
 between several text events unless $p->unbroken_text is enabled.
 
 The parser will make sure that it does not break a word or a sequence
 of whitespace between two text events.
 
 =back
 
 =head2 Unicode
 
 C<HTML::Parser> can parse Unicode strings when running under
 perl-5.8 or better.  If Unicode is passed to $p->parse() then chunks
 of Unicode will be reported to the handlers.  The offset and length
 argspecs will also report their position in terms of characters.
 
 It is safe to parse raw undecoded UTF-8 if you either avoid decoding
 entities and make sure to not use I<argspecs> that do, or enable the
 C<utf8_mode> for the parser.  Parsing of undecoded UTF-8 might be
 useful when parsing from a file where you need the reported offsets
 and lengths to match the byte offsets in the file.
 
 If a filename is passed to $p->parse_file() then the file will be read
 in binary mode.  This will be fine if the file contains only ASCII or
 Latin-1 characters.  If the file contains UTF-8 encoded text then care
 must be taken when decoding entities as described in the previous
 paragraph, but better is to open the file with the UTF-8 layer so that
 it is decoded properly:
 
    open(my $fh, "<:utf8", "index.html") || die "...: $!";
    $p->parse_file($fh);
 
 If the file contains text encoded in a charset besides ASCII, Latin-1
 or UTF-8 then decoding will always be needed.
 
 =head1 VERSION 2 COMPATIBILITY
 
 When an C<HTML::Parser> object is constructed with no arguments, a set
 of handlers is automatically provided that is compatible with the old
 HTML::Parser version 2 callback methods.
 
 This is equivalent to the following method calls:
 
    $p->handler(start   => "start",   "self, tagname, attr, attrseq, text");
    $p->handler(end     => "end",     "self, tagname, text");
    $p->handler(text    => "text",    "self, text, is_cdata");
    $p->handler(process => "process", "self, token0, text");
    $p->handler(comment =>
              sub {
 		 my($self, $tokens) = @_;
 		 for (@$tokens) {$self->comment($_);}},
              "self, tokens");
    $p->handler(declaration =>
              sub {
 		 my $self = shift;
 		 $self->declaration(substr($_[0], 2, -1));},
              "self, text");
 
 Setting up these handlers can also be requested with the "api_version =>
 2" constructor option.
 
 =head1 SUBCLASSING
 
 The C<HTML::Parser> class is subclassable.  Parser objects are plain
 hashes and C<HTML::Parser> reserves only hash keys that start with
 "_hparser".  The parser state can be set up by invoking the init()
 method, which takes the same arguments as new().
 
 =head1 EXAMPLES
 
 The first simple example shows how you might strip out comments from
 an HTML document.  We achieve this by setting up a comment handler that
 does nothing and a default handler that will print out anything else:
 
   use HTML::Parser;
   HTML::Parser->new(default_h => [sub { print shift }, 'text'],
                     comment_h => [""],
                    )->parse_file(shift || die) || die $!;
 
 An alternative implementation is:
 
   use HTML::Parser;
   HTML::Parser->new(end_document_h => [sub { print shift },
                                        'skipped_text'],
                     comment_h      => [""],
                    )->parse_file(shift || die) || die $!;
 
 This will in most cases be much more efficient since only a single
 callback will be made.
 
 The next example prints out the text that is inside the <title>
 element of an HTML document.  Here we start by setting up a start
 handler.  When it sees the title start tag it enables a text handler
 that prints any text found and an end handler that will terminate
 parsing as soon as the title end tag is seen:
 
   use HTML::Parser ();
 
   sub start_handler
   {
     return if shift ne "title";
     my $self = shift;
     $self->handler(text => sub { print shift }, "dtext");
     $self->handler(end  => sub { shift->eof if shift eq "title"; },
 		           "tagname,self");
   }
 
   my $p = HTML::Parser->new(api_version => 3);
   $p->handler( start => \&start_handler, "tagname,self");
   $p->parse_file(shift || die) || die $!;
   print "\n";
 
 More examples are found in the F<eg/> directory of the C<HTML-Parser>
 distribution: the program C<hrefsub> shows how you can edit all links
 found in a document; the program C<htextsub> shows how to edit the text only; the
 program C<hstrip> shows how you can strip out certain tags/elements
 and/or attributes; and the program C<htext> show how to obtain the
 plain text, but not any script/style content.
 
 You can browse the F<eg/> directory online from the I<[Browse]> link on
 the http://search.cpan.org/~gaas/HTML-Parser/ page.
 
 =head1 BUGS
 
 The <style> and <script> sections do not end with the first "</", but
 need the complete corresponding end tag.  The standard behaviour is
 not really practical.
 
 When the I<strict_comment> option is enabled, we still recognize
 comments where there is something other than whitespace between even
 and odd "--" markers.
 
 Once $p->boolean_attribute_value has been set, there is no way to
 restore the default behaviour.
 
 There is currently no way to get both quote characters
 into the same literal argspec.
 
 Empty tags, e.g. "<>" and "</>", are not recognized.  SGML allows them
 to repeat the previous start tag or close the previous start tag
 respectively.
 
 NET tags, e.g. "code/.../" are not recognized.  This is SGML
 shorthand for "<code>...</code>".
 
 Unclosed start or end tags, e.g. "<tt<b>...</b</tt>" are not
 recognized.
 
 =head1 DIAGNOSTICS
 
 The following messages may be produced by HTML::Parser.  The notation
 in this listing is the same as used in L<perldiag>:
 
 =over
 
 =item Not a reference to a hash
 
 (F) The object blessed into or subclassed from HTML::Parser is not a
 hash as required by the HTML::Parser methods.
 
 =item Bad signature in parser state object at %p
 
 (F) The _hparser_xs_state element does not refer to a valid state structure.
 Something must have changed the internal value
 stored in this hash element, or the memory has been overwritten.
 
 =item _hparser_xs_state element is not a reference
 
 (F) The _hparser_xs_state element has been destroyed.
 
 =item Can't find '_hparser_xs_state' element in HTML::Parser hash
 
 (F) The _hparser_xs_state element is missing from the parser hash.
 It was either deleted, or not created when the object was created.
 
 =item API version %s not supported by HTML::Parser %s
 
 (F) The constructor option 'api_version' with an argument greater than
 or equal to 4 is reserved for future extensions.
 
 =item Bad constructor option '%s'
 
 (F) An unknown constructor option key was passed to the new() or
 init() methods.
 
 =item Parse loop not allowed
 
 (F) A handler invoked the parse() or parse_file() method.
 This is not permitted.
 
 =item marked sections not supported
 
 (F) The $p->marked_sections() method was invoked in a HTML::Parser
 module that was compiled without support for marked sections.
 
 =item Unknown boolean attribute (%d)
 
 (F) Something is wrong with the internal logic that set up aliases for
 boolean attributes.
 
 =item Only code or array references allowed as handler
 
 (F) The second argument for $p->handler must be either a subroutine
 reference, then name of a subroutine or method, or a reference to an
 array.
 
 =item No handler for %s events
 
 (F) The first argument to $p->handler must be a valid event name; i.e. one
 of "start", "end", "text", "process", "declaration" or "comment".
 
 =item Unrecognized identifier %s in argspec
 
 (F) The identifier is not a known argspec name.
 Use one of the names mentioned in the argspec section above.
 
 =item Literal string is longer than 255 chars in argspec
 
 (F) The current implementation limits the length of literals in
 an argspec to 255 characters.  Make the literal shorter.
 
 =item Backslash reserved for literal string in argspec
 
 (F) The backslash character "\" is not allowed in argspec literals.
 It is reserved to permit quoting inside a literal in a later version.
 
 =item Unterminated literal string in argspec
 
 (F) The terminating quote character for a literal was not found.
 
 =item Bad argspec (%s)
 
 (F) Only identifier names, literals, spaces and commas
 are allowed in argspecs.
 
 =item Missing comma separator in argspec
 
 (F) Identifiers in an argspec must be separated with ",".
 
 =item Parsing of undecoded UTF-8 will give garbage when decoding entities
 
 (W) The first chunk parsed appears to contain undecoded UTF-8 and one
 or more argspecs that decode entities are used for the callback
 handlers.
 
 The result of decoding will be a mix of encoded and decoded characters
 for any entities that expand to characters with code above 127.  This
 is not a good thing.
 
 The recommened solution is to apply Encode::decode_utf8() on the data before
 feeding it to the $p->parse().  For $p->parse_file() pass a file that has been
 opened in ":utf8" mode.
 
 The alternative solution is to enable the C<utf8_mode> and not decode before
 passing strings to $p->parse().  The parser can process raw undecoded UTF-8
 sanely if the C<utf8_mode> is enabled, or if the "attr", "@attr" or "dtext"
 argspecs are avoided.
 
 =item Parsing string decoded with wrong endianness
 
 (W) The first character in the document is U+FFFE.  This is not a
 legal Unicode character but a byte swapped BOM.  The result of parsing
 will likely be garbage.
 
 =item Parsing of undecoded UTF-32
 
 (W) The parser found the Unicode UTF-32 BOM signature at the start
 of the document.  The result of parsing will likely be garbage.
 
 =item Parsing of undecoded UTF-16
 
 (W) The parser found the Unicode UTF-16 BOM signature at the start of
 the document.  The result of parsing will likely be garbage.
 
 =back
 
 =head1 SEE ALSO
 
 L<HTML::Entities>, L<HTML::PullParser>, L<HTML::TokeParser>, L<HTML::HeadParser>,
 L<HTML::LinkExtor>, L<HTML::Form>
 
 L<HTML::TreeBuilder> (part of the I<HTML-Tree> distribution)
 
 L<http://www.w3.org/TR/html4/>
 
 More information about marked sections and processing instructions may
 be found at L<http://www.is-thought.co.uk/book/sgml-8.htm>.
 
 =head1 COPYRIGHT
 
  Copyright 1996-2008 Gisle Aas. All rights reserved.
  Copyright 1999-2000 Michael A. Chase.  All rights reserved.
 
 This library is free software; you can redistribute it and/or
 modify it under the same terms as Perl itself.
 
 =cut
### HTML/PullParser.pm ###
 package HTML::PullParser;
 
 require HTML::Parser;
 @ISA=qw(HTML::Parser);
 $VERSION = "3.57";
 
 use strict;
 use Carp ();
 
 sub new
 {
     my($class, %cnf) = @_;
 
     # Construct argspecs for the various events
     my %argspec;
     for (qw(start end text declaration comment process default)) {
 	my $tmp = delete $cnf{$_};
 	next unless defined $tmp;
 	$argspec{$_} = $tmp;
     }
     Carp::croak("Info not collected for any events")
 	  unless %argspec;
 
     my $file = delete $cnf{file};
     my $doc  = delete $cnf{doc};
     Carp::croak("Can't parse from both 'doc' and 'file' at the same time")
 	  if defined($file) && defined($doc);
     Carp::croak("No 'doc' or 'file' given to parse from")
 	  unless defined($file) || defined($doc);
 
     # Create object
     $cnf{api_version} = 3;
     my $self = $class->SUPER::new(%cnf);
 
     my $accum = $self->{pullparser_accum} = [];
     while (my($event, $argspec) = each %argspec) {
 	$self->SUPER::handler($event => $accum, $argspec);
     }
 
     if (defined $doc) {
 	$self->{pullparser_str_ref} = ref($doc) ? $doc : \$doc;
 	$self->{pullparser_str_pos} = 0;
     }
     else {
 	if (!ref($file) && ref(\$file) ne "GLOB") {
 	    require IO::File;
 	    $file = IO::File->new($file, "r") || return;
 	}
 
 	$self->{pullparser_file} = $file;
     }
     $self;
 }
 
 
 sub handler
 {
     Carp::croak("Can't set handlers for HTML::PullParser");
 }
 
 
 sub get_token
 {
     my $self = shift;
     while (!@{$self->{pullparser_accum}} && !$self->{pullparser_eof}) {
 	if (my $f = $self->{pullparser_file}) {
 	    # must try to parse more from the file
 	    my $buf;
 	    if (read($f, $buf, 512)) {
 		$self->parse($buf);
 	    } else {
 		$self->eof;
 		$self->{pullparser_eof}++;
 		delete $self->{pullparser_file};
 	    }
 	}
 	elsif (my $sref = $self->{pullparser_str_ref}) {
 	    # must try to parse more from the scalar
 	    my $pos = $self->{pullparser_str_pos};
 	    my $chunk = substr($$sref, $pos, 512);
 	    $self->parse($chunk);
 	    $pos += length($chunk);
 	    if ($pos < length($$sref)) {
 		$self->{pullparser_str_pos} = $pos;
 	    }
 	    else {
 		$self->eof;
 		$self->{pullparser_eof}++;
 		delete $self->{pullparser_str_ref};
 		delete $self->{pullparser_str_pos};
 	    }
 	}
 	else {
 	    die;
 	}
     }
     shift @{$self->{pullparser_accum}};
 }
 
 
 sub unget_token
 {
     my $self = shift;
     unshift @{$self->{pullparser_accum}}, @_;
     $self;
 }
 
 1;
 
 
 __END__
 
 =head1 NAME
 
 HTML::PullParser - Alternative HTML::Parser interface
 
 =head1 SYNOPSIS
 
  use HTML::PullParser;
 
  $p = HTML::PullParser->new(file => "index.html",
                             start => 'event, tagname, @attr',
                             end   => 'event, tagname',
                             ignore_elements => [qw(script style)],
                            ) || die "Can't open: $!";
  while (my $token = $p->get_token) {
      #...do something with $token
  }
 
 =head1 DESCRIPTION
 
 The HTML::PullParser is an alternative interface to the HTML::Parser class.
 It basically turns the HTML::Parser inside out.  You associate a file
 (or any IO::Handle object or string) with the parser at construction time and
 then repeatedly call $parser->get_token to obtain the tags and text
 found in the parsed document.
 
 The following methods are provided:
 
 =over 4
 
 =item $p = HTML::PullParser->new( file => $file, %options )
 
 =item $p = HTML::PullParser->new( doc => \$doc, %options )
 
 A C<HTML::PullParser> can be made to parse from either a file or a
 literal document based on whether the C<file> or C<doc> option is
 passed to the parser's constructor.
 
 The C<file> passed in can either be a file name or a file handle
 object.  If a file name is passed, and it can't be opened for reading,
 then the constructor will return an undefined value and $!  will tell
 you why it failed.  Otherwise the argument is taken to be some object
 that the C<HTML::PullParser> can read() from when it needs more data.
 The stream will be read() until EOF, but not closed.
 
 A C<doc> can be passed plain or as a reference
 to a scalar.  If a reference is passed then the value of this scalar
 should not be changed before all tokens have been extracted.
 
 Next the information to be returned for the different token types must
 be set up.  This is done by simply associating an argspec (as defined
 in L<HTML::Parser>) with the events you have an interest in.  For
 instance, if you want C<start> tokens to be reported as the string
 C<'S'> followed by the tagname and the attributes you might pass an
 C<start>-option like this:
 
    $p = HTML::PullParser->new(
           doc   => $document_to_parse,
           start => '"S", tagname, @attr',
           end   => '"E", tagname',
         );
 
 At last other C<HTML::Parser> options, like C<ignore_tags>, and
 C<unbroken_text>, can be passed in.  Note that you should not use the
 I<event>_h options to set up parser handlers.  That would confuse the
 inner logic of C<HTML::PullParser>.
 
 =item $token = $p->get_token
 
 This method will return the next I<token> found in the HTML document,
 or C<undef> at the end of the document.  The token is returned as an
 array reference.  The content of this array match the argspec set up
 during C<HTML::PullParser> construction.
 
 =item $p->unget_token( @tokens )
 
 If you find out you have read too many tokens you can push them back,
 so that they are returned again the next time $p->get_token is called.
 
 =back
 
 =head1 EXAMPLES
 
 The 'eg/hform' script shows how we might parse the form section of
 HTML::Documents using HTML::PullParser.
 
 =head1 SEE ALSO
 
 L<HTML::Parser>, L<HTML::TokeParser>
 
 =head1 COPYRIGHT
 
 Copyright 1998-2001 Gisle Aas.
 
 This library is free software; you can redistribute it and/or
 modify it under the same terms as Perl itself.
 
 =cut
### HTML/Tagset.pm ###
 package HTML::Tagset;
 
 use strict;
 
 =head1 NAME
 
 HTML::Tagset - data tables useful in parsing HTML
 
 =head1 VERSION
 
 Version 3.20
 
 =cut
 
 use vars qw( $VERSION );
 
 $VERSION = '3.20';
 
 =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.)
 
 =cut
 
 use vars qw(
     $VERSION
     %emptyElement %optionalEndTag %linkElements %boolean_attr
     %isHeadElement %isBodyElement %isPhraseMarkup
     %is_Possible_Strict_P_Content
     %isHeadOrBodyElement
     %isList %isTableElement %isFormElement
     %isKnown %canTighten
     @p_closure_barriers
     %isCDATA_Parent
 );
 
 =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
 
 %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
 
 %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
 
 %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
 
 %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
 
 %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 
   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
 
 %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
 
 %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
 
 %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
 
 %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
 
 %isFormElement  = map {; $_ => 1 }
  qw(input select option optgroup textarea button label);
 
 =head2 hashset %HTML::Tagset::isBodyMarkup
 
 This hashset contains all elements that are to be found only in/under
 the "body" element of an HTML document.
 
 =cut
 
 %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
 
 %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
 
 %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
 
 %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
 
 @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
 
 %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-2008 Andy Lester.
 
 This program is free software; you can redistribute it and/or modify it
 under the same terms as Perl itself.
 
 =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;
### HTML/TokeParser.pm ###
 package HTML::TokeParser;
 
 require HTML::PullParser;
 @ISA=qw(HTML::PullParser);
 $VERSION = "3.69";
 
 use strict;
 use Carp ();
 use HTML::Entities qw(decode_entities);
 use HTML::Tagset ();
 
 my %ARGS =
 (
  start       => "'S',tagname,attr,attrseq,text",
  end         => "'E',tagname,text",
  text        => "'T',text,is_cdata",
  process     => "'PI',token0,text",
  comment     => "'C',text",
  declaration => "'D',text",
 
  # options that default on
  unbroken_text => 1,
 );
 
 
 sub new
 {
     my $class = shift;
     my %cnf;
 
     if (@_ == 1) {
 	my $type = (ref($_[0]) eq "SCALAR") ? "doc" : "file";
 	%cnf = ($type => $_[0]);
     }
     else {
 	unshift @_, (ref($_[0]) eq "SCALAR") ? "doc" : "file" if(scalar(@_) % 2 == 1);
 	%cnf = @_;
     }
 
     my $textify = delete $cnf{textify} || {img => "alt", applet => "alt"};
 
     my $self = $class->SUPER::new(%ARGS, %cnf) || return undef;
 
     $self->{textify} = $textify;
     $self;
 }
 
 
 sub get_tag
 {
     my $self = shift;
     my $token;
     while (1) {
 	$token = $self->get_token || return undef;
 	my $type = shift @$token;
 	next unless $type eq "S" || $type eq "E";
 	substr($token->[0], 0, 0) = "/" if $type eq "E";
 	return $token unless @_;
 	for (@_) {
 	    return $token if $token->[0] eq $_;
 	}
     }
 }
 
 
 sub _textify {
     my($self, $token) = @_;
     my $tag = $token->[1];
     return undef unless exists $self->{textify}{$tag};
 
     my $alt = $self->{textify}{$tag};
     my $text;
     if (ref($alt)) {
 	$text = &$alt(@$token);
     } else {
 	$text = $token->[2]{$alt || "alt"};
 	$text = "[\U$tag]" unless defined $text;
     }
     return $text;
 }
 
 
 sub get_text
 {
     my $self = shift;
     my @text;
     while (my $token = $self->get_token) {
 	my $type = $token->[0];
 	if ($type eq "T") {
 	    my $text = $token->[1];
 	    decode_entities($text) unless $token->[2];
 	    push(@text, $text);
 	} elsif ($type =~ /^[SE]$/) {
 	    my $tag = $token->[1];
 	    if ($type eq "S") {
 		if (defined(my $text = _textify($self, $token))) {
 		    push(@text, $text);
 		    next;
 		}
 	    } else {
 		$tag = "/$tag";
 	    }
 	    if (!@_ || grep $_ eq $tag, @_) {
 		 $self->unget_token($token);
 		 last;
 	    }
 	    push(@text, " ")
 		if $tag eq "br" || !$HTML::Tagset::isPhraseMarkup{$token->[1]};
 	}
     }
     join("", @text);
 }
 
 
 sub get_trimmed_text
 {
     my $self = shift;
     my $text = $self->get_text(@_);
     $text =~ s/^\s+//; $text =~ s/\s+$//; $text =~ s/\s+/ /g;
     $text;
 }
 
 sub get_phrase {
     my $self = shift;
     my @text;
     while (my $token = $self->get_token) {
 	my $type = $token->[0];
 	if ($type eq "T") {
 	    my $text = $token->[1];
 	    decode_entities($text) unless $token->[2];
 	    push(@text, $text);
 	} elsif ($type =~ /^[SE]$/) {
 	    my $tag = $token->[1];
 	    if ($type eq "S") {
 		if (defined(my $text = _textify($self, $token))) {
 		    push(@text, $text);
 		    next;
 		}
 	    }
 	    if (!$HTML::Tagset::isPhraseMarkup{$tag}) {
 		$self->unget_token($token);
 		last;
 	    }
 	    push(@text, " ") if $tag eq "br";
 	}
     }
     my $text = join("", @text);
     $text =~ s/^\s+//; $text =~ s/\s+$//; $text =~ s/\s+/ /g;
     $text;
 }
 
 1;
 
 
 __END__
 
 =head1 NAME
 
 HTML::TokeParser - Alternative HTML::Parser interface
 
 =head1 SYNOPSIS
 
  require HTML::TokeParser;
  $p = HTML::TokeParser->new("index.html") ||
       die "Can't open: $!";
  $p->empty_element_tags(1);  # configure its behaviour
 
  while (my $token = $p->get_token) {
      #...
  }
 
 =head1 DESCRIPTION
 
 The C<HTML::TokeParser> is an alternative interface to the
 C<HTML::Parser> class.  It is an C<HTML::PullParser> subclass with a
 predeclared set of token types.  If you wish the tokens to be reported
 differently you probably want to use the C<HTML::PullParser> directly.
 
 The following methods are available:
 
 =over 4
 
 =item $p = HTML::TokeParser->new( $filename, %opt );
 
 =item $p = HTML::TokeParser->new( $filehandle, %opt );
 
 =item $p = HTML::TokeParser->new( \$document, %opt );
 
 The object constructor argument is either a file name, a file handle
 object, or the complete document to be parsed.  Extra options can be
 provided as key/value pairs and are processed as documented by the base
 classes.
 
 If the argument is a plain scalar, then it is taken as the name of a
 file to be opened and parsed.  If the file can't be opened for
 reading, then the constructor will return C<undef> and $! will tell
 you why it failed.
 
 If the argument is a reference to a plain scalar, then this scalar is
 taken to be the literal document to parse.  The value of this
 scalar should not be changed before all tokens have been extracted.
 
 Otherwise the argument is taken to be some object that the
 C<HTML::TokeParser> can read() from when it needs more data.  Typically
 it will be a filehandle of some kind.  The stream will be read() until
 EOF, but not closed.
 
 A newly constructed C<HTML::TokeParser> differ from its base classes
 by having the C<unbroken_text> attribute enabled by default. See
 L<HTML::Parser> for a description of this and other attributes that
 influence how the document is parsed. It is often a good idea to enable
 C<empty_element_tags> behaviour.
 
 Note that the parsing result will likely not be valid if raw undecoded
 UTF-8 is used as a source.  When parsing UTF-8 encoded files turn
 on UTF-8 decoding:
 
    open(my $fh, "<:utf8", "index.html") || die "Can't open 'index.html': $!";
    my $p = HTML::TokeParser->new( $fh );
    # ...
 
 If a $filename is passed to the constructor the file will be opened in
 raw mode and the parsing result will only be valid if its content is
 Latin-1 or pure ASCII.
 
 If parsing from an UTF-8 encoded string buffer decode it first:
 
    utf8::decode($document);
    my $p = HTML::TokeParser->new( \$document );
    # ...
 
 =item $p->get_token
 
 This method will return the next I<token> found in the HTML document,
 or C<undef> at the end of the document.  The token is returned as an
 array reference.  The first element of the array will be a string
 denoting the type of this token: "S" for start tag, "E" for end tag,
 "T" for text, "C" for comment, "D" for declaration, and "PI" for
 process instructions.  The rest of the token array depend on the type
 like this:
 
   ["S",  $tag, $attr, $attrseq, $text]
   ["E",  $tag, $text]
   ["T",  $text, $is_data]
   ["C",  $text]
   ["D",  $text]
   ["PI", $token0, $text]
 
 where $attr is a hash reference, $attrseq is an array reference and
 the rest are plain scalars.  The L<HTML::Parser/Argspec> explains the
 details.
 
 =item $p->unget_token( @tokens )
 
 If you find you have read too many tokens you can push them back,
 so that they are returned the next time $p->get_token is called.
 
 =item $p->get_tag
 
 =item $p->get_tag( @tags )
 
 This method returns the next start or end tag (skipping any other
 tokens), or C<undef> if there are no more tags in the document.  If
 one or more arguments are given, then we skip tokens until one of the
 specified tag types is found.  For example:
 
    $p->get_tag("font", "/font");
 
 will find the next start or end tag for a font-element.
 
 The tag information is returned as an array reference in the same form
 as for $p->get_token above, but the type code (first element) is
 missing. A start tag will be returned like this:
 
   [$tag, $attr, $attrseq, $text]
 
 The tagname of end tags are prefixed with "/", i.e. end tag is
 returned like this:
 
   ["/$tag", $text]
 
 =item $p->get_text
 
 =item $p->get_text( @endtags )
 
 This method returns all text found at the current position. It will
 return a zero length string if the next token is not text. Any
 entities will be converted to their corresponding character.
 
 If one or more arguments are given, then we return all text occurring
 before the first of the specified tags found. For example:
 
    $p->get_text("p", "br");
 
 will return the text up to either a paragraph of linebreak element.
 
 The text might span tags that should be I<textified>.  This is
 controlled by the $p->{textify} attribute, which is a hash that
 defines how certain tags can be treated as text.  If the name of a
 start tag matches a key in this hash then this tag is converted to
 text.  The hash value is used to specify which tag attribute to obtain
 the text from.  If this tag attribute is missing, then the upper case
 name of the tag enclosed in brackets is returned, e.g. "[IMG]".  The
 hash value can also be a subroutine reference.  In this case the
 routine is called with the start tag token content as its argument and
 the return value is treated as the text.
 
 The default $p->{textify} value is:
 
   {img => "alt", applet => "alt"}
 
 This means that <IMG> and <APPLET> tags are treated as text, and that
 the text to substitute can be found in the ALT attribute.
 
 =item $p->get_trimmed_text
 
 =item $p->get_trimmed_text( @endtags )
 
 Same as $p->get_text above, but will collapse any sequences of white
 space to a single space character.  Leading and trailing white space is
 removed.
 
 =item $p->get_phrase
 
 This will return all text found at the current position ignoring any
 phrasal-level tags.  Text is extracted until the first non
 phrasal-level tag.  Textification of tags is the same as for
 get_text().  This method will collapse white space in the same way as
 get_trimmed_text() does.
 
 The definition of <i>phrasal-level tags</i> is obtained from the
 HTML::Tagset module.
 
 =back
 
 =head1 EXAMPLES
 
 This example extracts all links from a document.  It will print one
 line for each link, containing the URL and the textual description
 between the <A>...</A> tags:
 
   use HTML::TokeParser;
   $p = HTML::TokeParser->new(shift||"index.html");
 
   while (my $token = $p->get_tag("a")) {
       my $url = $token->[1]{href} || "-";
       my $text = $p->get_trimmed_text("/a");
       print "$url\t$text\n";
   }
 
 This example extract the <TITLE> from the document:
 
   use HTML::TokeParser;
   $p = HTML::TokeParser->new(shift||"index.html");
   if ($p->get_tag("title")) {
       my $title = $p->get_trimmed_text;
       print "Title: $title\n";
   }
 
 =head1 SEE ALSO
 
 L<HTML::PullParser>, L<HTML::Parser>
 
 =head1 COPYRIGHT
 
 Copyright 1998-2005 Gisle Aas.
 
 This library is free software; you can redistribute it and/or
 modify it under the same terms as Perl itself.
 
 =cut
### HTTP/Tiny.pm ###
 # 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.054';
 
 use Carp ();
 
 #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> —
 #pod     A user-agent string (defaults to 'HTTP-Tiny/$VERSION'). If C<agent> — ends in a space character, the default user-agent string is appended.
 #pod * C<cookie_jar> —
 #pod     An instance of L<HTTP::CookieJar> — or equivalent class that supports the C<add> and C<cookie_header> methods
 #pod * C<default_headers> —
 #pod     A hashref of default headers to apply to requests
 #pod * C<local_address> —
 #pod     The local IP address to bind to
 #pod * C<keep_alive> —
 #pod     Whether to reuse the last connection (if for the same scheme, host and port) (defaults to 1)
 #pod * C<max_redirect> —
 #pod     Maximum number of redirects allowed (defaults to 5)
 #pod * C<max_size> —
 #pod     Maximum response size (only when not using a data callback).  If defined, responses larger than this will return an exception.
 #pod * C<http_proxy> —
 #pod     URL of a proxy server to use for HTTP connections (default is C<$ENV{http_proxy}> — if set)
 #pod * C<https_proxy> —
 #pod     URL of a proxy server to use for HTTPS connections (default is C<$ENV{https_proxy}> — if set)
 #pod * C<proxy> —
 #pod     URL of a generic proxy server for both HTTP and HTTPS connections (default is C<$ENV{all_proxy}> — if set)
 #pod * C<no_proxy> —
 #pod     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}> —)
 #pod * C<timeout> —
 #pod     Request timeout in seconds (default is 60)
 #pod * C<verify_SSL> —
 #pod     A boolean that indicates whether to validate the SSL certificate of an C<https> —
 #pod     connection (default is false)
 #pod * C<SSL_options> —
 #pod     A hashref of C<SSL_*> — options to pass through to L<IO::Socket::SSL>
 #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 Exceptions from C<max_size>, C<timeout> or other errors will result in a
 #pod pseudo-HTTP status code of 599 and a reason of "Internal Exception". The
 #pod content field in the response will contain the text of the exception.
 #pod
 #pod The C<keep_alive> parameter enables a persistent connection, but only to a
 #pod single destination scheme, host and port.  Also, if any connection-relevant
 #pod attributes are modified, or if the process ID or thread ID change, the
 #pod persistent connection will be dropped.  If you want persistent connections
 #pod across multiple destinations, use multiple HTTP::Tiny objects.
 #pod
 #pod See L</SSL SUPPORT> for more on the C<verify_SSL> and C<SSL_options> 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 timeout
         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 new {
     my($class, %args) = @_;
 
     my $self = {
         max_redirect => 5,
         timeout      => 60,
         keep_alive   => 1,
         verify_SSL   => $args{verify_SSL} || $args{verify_ssl} || 0, # no verification by 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 _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} 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|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 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 Carp::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 on key and value 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 Carp::croak(q/Usage: $http->post_form(URL, DATAREF, [HASHREF])/ . "\n");
 
     my $headers = {};
     while ( my ($key, $value) = each %{$args->{headers} || {}} ) {
         $headers->{lc $key} = $value;
     }
     delete $args->{headers};
 
     return $self->request('POST', $url, {
             %$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 Carp::croak(q/Usage: $http->mirror(URL, FILE, [HASHREF])/ . "\n");
     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 Carp::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 Carp::croak(qq/Error: Caught error closing temporary file $tempfile: $!\n/);
 
     if ( $response->{success} ) {
         rename $tempfile, $file
             or Carp::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 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
 #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 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
 #pod On an exception 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 exception.
 #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 Carp::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)};
     }
 
     if (my $e = $@) {
         # maybe we got a response hash thrown from somewhere deep
         if ( ref $e eq 'HASH' && exists $e->{status} ) {
             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,
             }
         };
     }
     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 Carp::croak(q/Usage: $http->www_form_urlencode(DATAREF)/ . "\n");
     (ref $data eq 'HASH' || ref $data eq 'ARRAY')
         or Carp::croak("form data must be a hash or array reference\n");
 
     my @params = ref $data eq 'HASH' ? %$data : @$data;
     @params % 2 == 0
         or Carp::croak("form data reference must have an even number of terms\n");
 
     my @terms;
     while( @params ) {
         my ($key, $value) = splice(@params, 0, 2);
         if ( ref $value eq 'ARRAY' ) {
             unshift @params, map { $key => $_ } @$value;
         }
         else {
             push @terms, join("=", map { $self->_uri_escape($_) } $key, $value);
         }
     }
 
     return join("&", (ref $data eq 'ARRAY') ? (@terms) : (sort @terms) );
 }
 
 #--------------------------------------------------------------------------#
 # private methods
 #--------------------------------------------------------------------------#
 
 my %DefaultPort = (
     http => 80,
     https => 443,
 );
 
 sub _agent {
     my $class = ref($_[0]) || $_[0];
     (my $default_agent = $class) =~ s{::}{-}g;
     return $default_agent . "/" . $class->VERSION;
 }
 
 sub _request {
     my ($self, $method, $url, $args) = @_;
 
     my ($scheme, $host, $port, $path_query, $auth) = $self->_split_url($url);
 
     my $request = {
         method    => $method,
         scheme    => $scheme,
         host      => $host,
         port      => $port,
         host_port => ($port == $DefaultPort{$scheme} ? $host : "$host:$port"),
         uri       => $path_query,
         headers   => {},
     };
 
     # 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 ) ) {
             $handle->close;
             undef $handle;
         }
     }
     $handle ||= $self->_open_handle( $request, $scheme, $host, $port );
 
     $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};
 
     if ( my @redir_args = $self->_maybe_redirect($request, $response, $args) ) {
         $handle->close;
         return $self->_request(@redir_args, $args);
     }
 
     my $known_message_length;
     if ($method eq 'HEAD' || $response->{status} =~ /^[23]04/) {
         # response has no message body
         $known_message_length = 1;
     }
     else {
         my $data_cb = $self->_prepare_data_cb($response, $args);
         $known_message_length = $handle->read_body($data_cb, $response);
     }
 
     if ( $self->{keep_alive}
         && $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;
     return $response;
 }
 
 sub _open_handle {
     my ($self, $request, $scheme, $host, $port) = @_;
 
     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);
     }
 }
 
 sub _proxy_connect {
     my ($self, $request, $handle) = @_;
 
     my @proxy_vars;
     if ( $request->{scheme} eq 'https' ) {
         Carp::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' ) {
             Carp::croak(qq{Can't proxy https over https: $request->{uri} via $self->{https_proxy}});
         }
     }
     else {
         Carp::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);
 
     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 '/'
     ) {
         Carp::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;
         }
     }
 
     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};
 
     if ( defined $args->{content} ) {
         if (ref $args->{content} eq 'CODE') {
             $request->{headers}{'content-type'} ||= "application/octet-stream";
             $request->{headers}{'transfer-encoding'} = 'chunked'
               unless $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/ ) {
         Carp::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});
     if (($status eq '303' or ($status =~ /^30[127]/ && $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) = @_;
     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}/ge;
     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];
 
 # 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.25) } ? '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]/;
 
 sub new {
     my ($class, %args) = @_;
     return bless {
         rbuf             => '',
         timeout          => 60,
         max_line_size    => 16384,
         max_header_lines => 64,
         verify_SSL       => 0,
         SSL_options      => {},
         %args
     }, $class;
 }
 
 sub connect {
     @_ == 4 || die(q/Usage: $handle->connect(scheme, host, port)/ . "\n");
     my ($self, $scheme, $host, $port) = @_;
 
     if ( $scheme eq 'https' ) {
         $self->_assert_ssl;
     }
     elsif ( $scheme ne 'http' ) {
       die(qq/Unsupported URL scheme '$scheme'\n/);
     }
     $self->{fh} = $SOCKET_CLASS->new(
         PeerHost  => $host,
         PeerPort  => $port,
         $self->{local_address} ?
             ( LocalAddr => $self->{local_address} ) : (),
         Proto     => 'tcp',
         Type      => SOCK_STREAM,
         Timeout   => $self->{timeout},
         KeepAlive => !!$self->{keep_alive}
     ) or die(qq/Could not connect to '$host:$port': $@\n/);
 
     binmode($self->{fh})
       or die(qq/Could not binmode() socket: '$!'\n/);
 
     $self->start_ssl($host) if $scheme eq 'https';
 
     $self->{scheme} = $scheme;
     $self->{host} = $host;
     $self->{port} = $port;
     $self->{pid} = $$;
     $self->{tid} = _get_tid();
 
     return $self;
 }
 
 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;
     }
 
     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/});
     $self->write_body($request) if $request->{cb};
     return;
 }
 
 my %HeaderCase = (
     'content-md5'      => 'Content-MD5',
     'etag'             => 'ETag',
     'te'               => 'TE',
     'www-authenticate' => 'WWW-Authenticate',
     'x-xss-protection' => 'X-XSS-Protection',
 );
 
 # 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 || @_ == 3 && ref $_[1] eq 'HASH') || die(q/Usage: $handle->write_header_lines(headers[,prefix])/ . "\n");
     my($self, $headers, $prefix_data) = @_;
 
     my $buf = (defined $prefix_data ? $prefix_data : '');
     while (my ($k, $v) = each %$headers) {
         my $field_name = lc $k;
         if (exists $HeaderCase{$field_name}) {
             $field_name = $HeaderCase{$field_name};
         }
         else {
             $field_name =~ /\A $Token+ \z/xo
               or die(q/Invalid HTTP header field name: / . $Printable->($field_name) . "\n");
             $field_name =~ s/\b(\w)/\u$1/g;
             $HeaderCase{lc $field_name} = $field_name;
         }
         for (ref $v eq 'ARRAY' ? @$v : $v) {
             $_ = '' 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 ($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");
     $self->write_header_lines($request->{trailer_cb}->())
         if ref $request->{trailer_cb} eq 'CODE';
     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);
 
     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 {
     @_ == 4 || die(q/Usage: $handle->write_request_header(method, request_uri, headers)/ . "\n");
     my ($self, $method, $request_uri, $headers) = @_;
 
     return $self->write_header_lines($headers, "$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 {
     # Need IO::Socket::SSL 1.42 for SSL_create_ctx_callback
     die(qq/IO::Socket::SSL 1.42 must be installed for https support\n/)
         unless eval {require IO::Socket::SSL; IO::Socket::SSL->VERSION(1.42)};
     # Need Net::SSLeay 1.49 for MODE_AUTO_RETRY
     die(qq/Net::SSLeay 1.49 must be installed for https support\n/)
         unless eval {require Net::SSLeay; Net::SSLeay->VERSION(1.49)};
 }
 
 sub can_reuse {
     my ($self,$scheme,$host,$port) = @_;
     return 0 if
         $self->{pid} != $$
         || $self->{tid} != _get_tid()
         || length($self->{rbuf})
         || $scheme ne $self->{scheme}
         || $host ne $self->{host}
         || $port ne $self->{port}
         || eval { $self->can_read(0) }
         || $@ ;
         return 1;
 }
 
 # Try to find a CA bundle to validate the SSL cert,
 # prefer Mozilla::CA or fallback to a system file
 sub _find_CA_file {
     my $self = shift();
 
     return $self->{SSL_options}->{SSL_ca_file}
         if $self->{SSL_options}->{SSL_ca_file} and -e $self->{SSL_options}->{SSL_ca_file};
 
     return Mozilla::CA::SSL_ca_file()
         if eval { require Mozilla::CA };
 
     # 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 $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 Mozilla::CA from CPAN\n/;
 }
 
 # 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_ca_file}          = $self->_find_CA_file;
     }
     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.054
 
 =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 (only when not using a data callback).  If defined, responses larger than this will return an exception.
 
 =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)
 
 =item *
 
 C<verify_SSL> — A boolean that indicates whether to validate the SSL certificate of an C<https> — connection (default is false)
 
 =item *
 
 C<SSL_options> — A hashref of C<SSL_*> — options to pass through to L<IO::Socket::SSL>
 
 =back
 
 Passing an explicit C<undef> for C<proxy>, C<http_proxy> or C<https_proxy> will
 prevent getting the corresponding proxies from the environment.
 
 Exceptions from C<max_size>, C<timeout> or other errors 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 exception.
 
 The C<keep_alive> parameter enables a persistent connection, but only to a
 single destination scheme, host and port.  Also, if any connection-relevant
 attributes are modified, 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</SSL SUPPORT> for more on the C<verify_SSL> and C<SSL_options> attributes.
 
 =head2 get|head|put|post|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 on key and value 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.
 
 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.
 
 =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.)
 
 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
 
 =back
 
 On an exception during the execution of the request, the C<status> field will
 contain 599, and the C<content> field will contain the text of the exception.
 
 =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.
 
 =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 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 exception will be
 thrown if new enough versions of these modules are not installed or if the SSL
 encryption fails. 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.
 
 SSL provides two distinct capabilities:
 
 =over 4
 
 =item *
 
 Encrypted communication channel
 
 =item *
 
 Verification of server identity
 
 =back
 
 B<By default, HTTP::Tiny does not verify server identity>.
 
 Server identity verification is controversial and potentially tricky because it
 depends on a (usually paid) third-party Certificate Authority (CA) trust model
 to validate a certificate as legitimate.  This discriminates against servers
 with self-signed certificates or certificates signed by free, community-driven
 CA's such as L<CAcert.org|http://cacert.org>.
 
 By default, HTTP::Tiny does not make any assumptions about your trust model,
 threat level or risk tolerance.  It just aims to give you an encrypted channel
 when you need one.
 
 Setting the C<verify_SSL> attribute to a true value will make HTTP::Tiny verify
 that an SSL connection has a valid SSL certificate corresponding to the host
 name of the connection and that the SSL certificate has been verified by a CA.
 Assuming you trust the CA, this will protect against a L<man-in-the-middle
 attack|http://en.wikipedia.org/wiki/Man-in-the-middle_attack>.  If you are
 concerned about security, you should enable this option.
 
 Certificate verification requires a file containing trusted CA certificates.
 If the L<Mozilla::CA> module is installed, HTTP::Tiny will use the CA file
 included with it as a source of trusted CA's.  (This means you trust Mozilla,
 the author of Mozilla::CA, the CPAN mirror where you got Mozilla::CA, the
 toolchain used to install it, and your operating system security, right?)
 
 If that module is not available, then HTTP::Tiny will search several
 system-specific default locations for a CA certificate file:
 
 =over 4
 
 =item *
 
 /etc/ssl/certs/ca-certificates.crt
 
 =item *
 
 /etc/pki/tls/certs/ca-bundle.crt
 
 =item *
 
 /etc/ssl/ca-bundle.pem
 
 =back
 
 An exception will be raised if C<verify_SSL> is true and no CA certificate file
 is available.
 
 If you desire complete control over 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 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.
 
 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.)
 
 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 and 307 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.
 
 =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<Mozilla::CA> - Required if you want to validate SSL certificates
 
 =item *
 
 L<Net::SSLeay> - Required for SSL support
 
 =back
 
 =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/chansen/p5-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/chansen/p5-http-tiny>
 
   git clone https://github.com/chansen/p5-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 Brad Gilbert Chris Nehren Weyl Claes Jakobsson Clinton Gormley Craig Berry David Mitchell Dean Pearce Edward Zborowski James Raspass Jess Robinson Lukas Eklund Martin J. Evans Martin-Louis Bright Mike Doherty Olaf Alders Petr Písař Serguei Trouchelle Sören Kornetzki Syohei YOSHIDA Tom Hukins Tony Cook
 
 =over 4
 
 =item *
 
 Alan Gardner <gardner@pythian.com>
 
 =item *
 
 Alessandro Ghedini <al3xbio@gmail.com>
 
 =item *
 
 Brad Gilbert <bgills@cpan.org>
 
 =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 Berry <cberry@cpan.org>
 
 =item *
 
 David Mitchell <davem@iabyn.com>
 
 =item *
 
 Dean Pearce <pearce@pythian.com>
 
 =item *
 
 Edward Zborowski <ed@rubensteintech.com>
 
 =item *
 
 James Raspass <jraspass@gmail.com>
 
 =item *
 
 Jess Robinson <castaway@desert-island.me.uk>
 
 =item *
 
 Lukas Eklund <leklund@gmail.com>
 
 =item *
 
 Martin J. Evans <mjegh@ntlworld.com>
 
 =item *
 
 Martin-Louis Bright <mlbright@gmail.com>
 
 =item *
 
 Mike Doherty <doherty@cpan.org>
 
 =item *
 
 Olaf Alders <olaf@wundersolutions.com>
 
 =item *
 
 Petr Písař <ppisar@redhat.com>
 
 =item *
 
 Serguei Trouchelle <stro@cpan.org>
 
 =item *
 
 Sören Kornetzki <soeren.kornetzki@delti.com>
 
 =item *
 
 Syohei YOSHIDA <syohex@gmail.com>
 
 =item *
 
 Tom Hukins <tom@eborcom.com>
 
 =item *
 
 Tony Cook <tony@develop-help.com>
 
 =back
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 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
### HTTP/Tiny/UNIX.pm ###
 package HTTP::Tiny::UNIX;
 
 use 5.010001;
 use strict;
 use warnings;
 
 our $DATE = '2014-07-04'; # DATE
 our $VERSION = '0.04'; # VERSION
 
 # issue: port must be numeric to avoid warning
 # put everything in path_query
 
 use parent qw(HTTP::Tiny);
 
 use IO::Socket::UNIX;
 
 sub _split_url {
     my ($self, $url) = @_;
 
     if ($url =~ m<\A[^:/?#]+://>) {
         $self->{_unix} = 0;
         return $self->SUPER::_split_url($url);
     }
 
     my ($scheme, $sock_path, $path_query) =
         $url =~ m<\A(\w+):(.+?)/(/[^#]*)>
             or die "Cannot parse HTTP-over-Unix URL: '$url'\n";
 
     # a hack
     $self->{_unix} = 1;
     $self->{_path_query} = $path_query;
 
     $scheme = lc $scheme;
     die "Only http scheme is supported\n" unless $scheme eq 'http';
 
     #return ($scheme, $host,      $port, $path_query, $auth);
     return  ($scheme, $sock_path, -1,    $path_query, '');
 }
 
 sub _open_handle {
     my ($self, $request, $scheme, $host, $port) = @_;
 
     return $self->SUPER::_open_handle($request, $scheme, $host, $port)
         unless $self->{_unix};
 
     my $handle = HTTP::Tiny::Handle::UNIX->new(
         timeout => $self->{timeout},
     );
 
     $handle->connect($scheme, $host, $port, $self);
 }
 
 package
     HTTP::Tiny::Handle::UNIX;
 
 use parent -norequire, 'HTTP::Tiny::Handle';
 
 use IO::Socket;
 
 sub connect {
     my ($self, $scheme, $host, $port, $tiny) = @_;
 
     # on Unix, we use $host for path and leave port at -1 (unused)
     my $path = $host;
 
     local($^W) = 0;
     my $sock = IO::Socket::UNIX->new(
         Peer    => $path,
         Type    => SOCK_STREAM,
         Timeout => $self->{timeout},
         Host    => 'localhost',
     );
 
     unless ($sock) {
         $@ =~ s/^.*?: //;
         die "Can't open Unix socket $path\: $@";
     }
 
     eval { $sock->blocking(0); };
 
     $self->{fh} = $sock;
 
     $self->{scheme} = $scheme;
     $self->{host} = $host;
     $self->{port} = $port;
     $self->{_unix} = 1;
     # this is a hack, we inject this so we can get HTTP::Tiny::UNIX object from
     # HTTP::Tiny::Handle::UNIX, to get path
     $self->{_tiny} = $tiny;
     $self;
 }
 
 sub write_request_header {
     my ($self, $method, $request_uri, $headers) = @_;
 
     return $self->write_request_header($method, $request_uri, $headers)
         unless $self->{_unix};
 
     return $self->write_header_lines($headers, "$method $self->{_tiny}{_path_query} HTTP/1.1\x0D\x0A");
 }
 
 1;
 # ABSTRACT: A subclass of HTTP::Tiny to connect to HTTP server over Unix socket
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 HTTP::Tiny::UNIX - A subclass of HTTP::Tiny to connect to HTTP server over Unix socket
 
 =head1 VERSION
 
 This document describes version 0.04 of HTTP::Tiny::UNIX (from Perl distribution HTTP-Tiny-UNIX), released on 2014-07-04.
 
 =head1 SYNOPSIS
 
  use HTTP::Tiny::UNIX;
 
  my $response = HTTP::Tiny::UNIX->new->get('http:/path/to/unix.sock//uri/path');
 
  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 subclass of L<HTTP::Tiny> to connect to HTTP server over Unix socket.
 URL syntax is C<"http:"> + I<path to unix socket> + C<"/"> + I<uri path>. For
 example: C<http:/var/run/apid.sock//api/v1/matches>. URL not matching this
 pattern will be passed to HTTP::Tiny.
 
 Proxy is currently not supported.
 
 =head1 SEE ALSO
 
 L<HTTP::Tiny>
 
 To use L<LWP> to connect over Unix sockets, see
 L<LWP::protocol::http::SocketUnixAlt>.
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/HTTP-Tiny-UNIX>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-HTTP-Tiny-UNIX>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=HTTP-Tiny-UNIX>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 Steven Haryanto <stevenharyanto@gmail.com>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2014 by Steven Haryanto.
 
 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
### IO/Event.pm ###
 
 our $debug = 0;
 our $edebug = 0;
 our $sdebug = 0;
 
 {
 package IO::Event;
 
 our $VERSION = 0.813;
 
 use strict;
 no strict 'refs';
 use warnings;
 use Carp qw(confess);
 
 our $base;
 our @ISA;
 
 sub idle
 {
 	IO::Event->import('no_emulate_Event') unless $base;
 	&{$base . "::idle"}(@_);
 }
 
 sub loop
 {
 	IO::Event->import('no_emulate_Event') unless $base;
 	&{$base . "::loop"}(@_);
 }
 
 sub unloop
 {
 	&{$base . "::unloop"}(@_);
 }
 
 sub unloop_all
 {
 	&{$base . "::unloop_all"}(@_);
 }
 
 sub timer
 {
 	shift;
 	IO::Event->import('no_emulate_Event') unless $base;
 	$base->timer(@_);
 }
 
 sub new
 {
 	IO::Event->import('no_emulate_Event') unless $base;
 	&{$base . "::new"}(@_);
 }
 
 sub import
 {
 	my ($pkg, @stuff) = @_;
 	for my $s (@stuff) {
 		if ($s eq 'emulate_Event') {
 			$base = 'IO::Event::Emulate';
 			require IO::Event::Emulate;
 		} elsif ($s eq 'no_emulate_Event') {
 			require Event;
 			require IO::Event::Event;
 			$base = 'IO::Event::Event';
 		} elsif ($s eq 'AnyEvent') {
 			require AnyEvent;
 			require IO::Event::AnyEvent;
 			$base = 'IO::Event::AnyEvent';
 		} else {
 			die "unknown import: $s";
 		}
 		@ISA = $base;
 	}
 	return 1;
 }
 
 sub AUTOLOAD
 {
 	my $self = shift;
 	our $AUTOLOAD;
 	my $a = $AUTOLOAD;
 	$a =~ s/.*:://;
 	
 	# for whatever reason, UNIVERSAL::can() 
 	# doesn't seem to work on some filehandles
 
 	my $r;
 	my @r;
 	my $fh = ${*$self}{ie_fh};
 	if ($fh) {
 		if (wantarray) {
 			eval { @r = $fh->$a(@_) };
 		} else {
 			eval { $r = $fh->$a(@_) };
 		}
 		if ($@ && $@ =~ /Can't locate object method "(.*?)" via package/) {
 			my $event = ${*$self}{ie_event};
 			if ($1 ne $a) {
 				# nothing to do
 			} elsif ($event && $event->can($a)) {
 				if (wantarray) {
 					eval { @r = $event->$a(@_) };
 				} else {
 					eval { $r = $event->$a(@_) };
 				}
 			} else {
 				confess qq{Can't locate object method "$a" via "@{[ ref($self) ]}", "@{[ ref($fh)||'IO::Handle' ]}", or "@{[ ref($event) ]}"};
 			}
 		}
 	} else {
 		my $event = ${*$self}{ie_event};
 		if ($event && $event->can($a)) {
 			if (wantarray) {
 				eval { @r = $event->$a(@_) };
 			} else {
 				eval { $r = $event->$a(@_) };
 			}
 		} else {
 			confess qq{Can't locate object method "$a" via "@{[ ref($self) ]}" or "@{[ ref($event) ]}"};
 		}
 	}
 	confess $@ if $@;
 	return @r if wantarray;
 	return $r;
 }
 
 }{package IO::Event::Common;
 
 use strict;
 use warnings;
 use Symbol;
 use Carp;
 require IO::Handle;
 use POSIX qw(BUFSIZ EAGAIN EBADF EINVAL ETIMEDOUT);
 use Socket;
 use Scalar::Util qw(weaken reftype);
 use Time::HiRes qw(time);
 
 our $in_callback = 0;
 
 my %fh_table;
 my %rxcache;
 
 my @pending_callbacks;
 
 sub display_bits
 {
 	print STDERR unpack("b*", $_[0]);
 }
 
 sub count_bits 
 { 
 	scalar(grep { $_ } split(//, unpack("b*", $_[0])));
 }
 
 sub display_want
 {
 	my ($name, $vec, %hash) = @_;
 	my ($pkg, $file, $line) = caller;
 	print STDERR "\n\nAT $file: $line\n";
 	print STDERR "$name\n";
 	for my $ioe (values %hash) {
 		printf STDERR "%03d-", fileno(${*$ioe}{ie_fh});
 		# display_bits(${*$ioe}{ie_vec});
 		print STDERR "\n";
 	}
 	print STDERR "----------";
 	display_bits($vec);
 	printf STDERR " - %d\n", count_bits($vec);
 	print STDERR scalar(keys(%hash));
 	print STDERR "\n";
 	exit 1;
 }
 
 my $counter = 1;
 
 sub new
 {
 	my ($pkg, $fh, $handler, $options) = @_;
 
 	# stolen from IO::Handle
 	my $self = bless gensym(), $pkg;
 
 	$handler = (caller(2))[0]
 		unless $handler;
 
 	confess unless ref $fh;
 
 	unless (ref $options) {
 		$options = {
 			description => $options,
 		};
 	}
 
 	# some bits stolen from IO::Socket
 	${*$self}{ie_fh} = $fh;
 	${*$self}{ie_handler} = $handler;
 	${*$self}{ie_ibuf} = '';
 	${*$self}{ie_obuf} = '';
 	${*$self}{ie_obufsize} = BUFSIZ*4;
 	${*$self}{ie_autoread} = 1;
 	${*$self}{ie_pending} = {};
 	${*$self}{ie_desc} = $options->{description} || "wrapper for $fh";
 	${*$self}{ie_writeclosed} = EINVAL if $options->{read_only};
 	${*$self}{ie_readclosed} = EINVAL if $options->{write_only};
 
 	$self->ie_register();
 	$fh->blocking(0);
 	print "New IO::Event: ${*$self}{ie_desc} - now nonblocking\n" if $debug;
 	
 	# stolen from IO::Multiplex
 	tie(*$self, $pkg, $self);
 	return $self;
 }
 
 sub reset
 {
 	my $self = shift;
 	delete ${*$self}{ie_writeclosed};
 	delete ${*$self}{ie_readclosed};
 	delete ${*$self}{ie_eofinvoked};
 	delete ${*$self}{ie_overflowinvoked};
 }
 
 # mark as listener
 sub listener
 {
 	my ($self, $listener) = @_;
 	$listener = 1 unless defined $listener;
 	my $o = ${*$self}{ie_listener};
 	${*$self}{ie_listener} = $listener;
 	return $o;
 }
 
 # call out
 sub ie_invoke
 {
 	my ($self, $required, $method, @args) = @_;
 
 	if ($in_callback && ! ${*$self}->{ie_reentrant}) {
 		# we'll do this later
 		push(@pending_callbacks, [ $self, $required, $method, @args ])
 			unless exists ${*$self}{ie_pending}{$method};
 		${*$self}{ie_pending}{$method} = 1; # prevent double invocation.  needed?
 		print STDERR "Delaying invocation of $method on ${*$self}{ie_desc} because we're already in a callback\n" if $debug;
 		return;
 	}
 
 	local($in_callback) = 1;
 
 	$self->ie_do_invoke($required, $method, @args);
 
 	while (@pending_callbacks) {
 		my ($ie, $req, $meth, @a) = @{shift @pending_callbacks};
 		delete ${*$ie}{ie_pending}{$meth}; 
 		print STDERR "Processing delayed invocation of $meth on ${*$ie}{ie_desc}\n" if $debug;
 		$ie->ie_do_invoke($req, $meth, @a);
 	}
 	return;
 }
 
 sub ie_do_invoke
 {
 	my ($self, $required, $method, @args) = @_;
 
 	print STDERR "invoking ${*$self}{ie_fileno} ${*$self}{ie_handler}->$method\n"
 		if $debug;
 
 	return if ! $required && ! ${*$self}{ie_handler}->can($method);
 	if ($debug) {
 		my ($pkg, $line, $func) = caller();
 		print "DISPATCHING $method on ${*$self}{ie_desc} from $func at line $line\n";
 	}
 	eval {
 		${*$self}{ie_handler}->$method($self, @args);
 	};
 
 	print STDERR "return from ${*$self}{ie_fileno} ${*$self}{ie_handler}->$method handler: $@\n" if $debug;
 
 	return unless $@;
 	if (${*$self}{ie_handler}->can('ie_died')) {
 		${*$self}{ie_handler}->ie_died($self, $method, $@);
 	} else {
 		confess $@;
 		exit 1;
 	}
 
 }
 
 #
 # we use a single event handler so that the AUTOLOAD
 # function can try a single $event object when looking for
 # methods
 #
 sub ie_dispatch
 {
 	print STDERR "D" if $sdebug;
 	my ($self, $ievent) = @_;
 	my $fh = ${*$self}{ie_fh};
 	my $got = $ievent->got;
 	{
 		if ($got & Event::Watcher::R()) {
 			last if $self->ie_dispatch_read($fh);
 		}
 		if ($got & Event::Watcher::W()) {
 			last if $self->ie_dispatch_write($fh);
 		}
 		if ($got & Event::Watcher::E()) {
 			$self->ie_dispatch_exception($fh);
 		}
 		if ($got & Event::Watcher::T()) {
 			$self->ie_dispatch_timer();
 		}
 	}
 }
 
 
 sub ie_dispatch_read
 {
 	my ($self, $fh) = @_;
 	printf STDERR "R%d", $self->fileno if $sdebug;
 	if (${*$self}{ie_listener}) {
 		$self->ie_invoke(1, 'ie_connection');
 	} elsif (${*$self}{ie_autoread}) {
 		$self->ie_input();
 	} else {
 		$self->ie_invoke(1, 'ie_read_ready', $fh);
 	}
 	return 1 if ${*$self}{ie_writeclosed} && ${*$self}{ie_readclosed};
 	return 0;
 }
 
 sub ie_dispatch_write
 {
 	my ($self, $fh) = @_;
 	printf STDERR "W%d", $self->fileno if $sdebug;
 	if (${*$self}{ie_connecting}) {
 		$self->writeevents(0);
 		delete ${*$self}{ie_connecting};
 		delete ${*$self}{ie_connect_timeout};
 		$self->ie_invoke(0, 'ie_connected');
 	} else {
 		my $obuf = \${*$self}{ie_obuf};
 		my $rv;
 		if (length($$obuf)) {
 			$rv = syswrite($fh, $$obuf);
 			if (defined $rv) {
 				substr($$obuf, 0, $rv) = '';
 			} elsif ($! == EAGAIN) {
 				# this shouldn't happen, but
 				# it's not that big a deal
 			} else {
 				# the file descriptor is toast
 				${*$self}{ie_writeclosed} = $!;
 				$self->ie_invoke(0, 'ie_werror', $obuf);
 			}
 		}
 		if (${*$self}{ie_closerequested}) {
 			if (! length($$obuf)) {
 				$self->ie_deregister();
 				${*$self}{ie_fh}->close();
 				delete ${*$self}{ie_closerequested};
 			}
 		} elsif (${*$self}{ie_shutdownrequested}) {
 			if (! length($$obuf)) {
 				shutdown(${*$self}{ie_fh}, 1);
 				${*$self}{ie_writeclosed} = 1;
 				delete ${*$self}{ie_shutdownrequested};
 				$self->ie_invoke(0, 'ie_outputdone', $obuf, 0);
 			}
 		} else {
 			$self->ie_invoke(0, 'ie_output', $obuf, $rv);
 			return 1 if ${*$self}{ie_writeclosed} 
 				&& ${*$self}{ie_readclosed};
 			if (! length($$obuf)) {
 				$self->ie_invoke(0, 'ie_outputdone', $obuf, 1);
 				return 1 if ${*$self}{ie_writeclosed} 
 					&& ${*$self}{ie_readclosed};
 				if (! length($$obuf)) {
 					$self->writeevents(0);
 				}
 			}
 			if (length($$obuf) > ${*$self}{ie_obufsize}) {
 				${*$self}{ie_overflowinvoked} = 1;
 				$self->ie_invoke(0, 'ie_outputoverflow', 1, $obuf);
 			} elsif (${*$self}{ie_overflowinvoked}) {
 				${*$self}{ie_overflowinvoked} = 0;
 				$self->ie_invoke(0, 'ie_outputoverflow', 0, $obuf);
 			}
 		}
 	}
 	return 1 if ${*$self}{ie_writeclosed} && ${*$self}{ie_readclosed};
 	return 0;
 }
 
 sub ie_dispatch_exception
 {
 	my ($self, $fh) = @_;
 	printf STDERR "E%d", fileno(${*$self}{ie_fh}) if $sdebug;
 	if (${*$self}{ie_closerequested}) {
 		$self->forceclose;
 	} elsif (${*$self}{ie_writeclosed} && ${*$self}{ie_readclosed}) {
 		$self->forceclose;
 	} elsif ($fh->eof) {
 		if (length(${*$self}{ie_ibuf})) {
 			$self->ie_invoke(0, 'ie_input', \${*$self}{ie_ibuf});
 		} 
 		if (${*$self}{ie_eofinvoked}++) {
 			warn "EOF repeat";
 		} else {
 			${*$self}{ie_closecalled} = 0;
 			$self->ie_invoke(0, 'ie_eof', \${*$self}{ie_ibuf});
 			unless (${*$self}{ie_closecalled}) {
 				$self->close;
 			}
 		}
 	} else {
 		# print STDERR "!?!";
 		$self->ie_invoke(0, 'ie_exception');
 	}
 }
 
 
 sub ie_dispatch_timer
 {
 	my ($self) = @_;
 	printf STDERR "T%d", fileno(${*$self}{ie_fh}) if $sdebug;
 	if (${*$self}{ie_connecting} 
 		&& ${*$self}{ie_connect_timeout}
 		&& time >= ${*$self}{ie_connect_timeout})
 	{
 		delete ${*$self}{ie_connect_timeout};
 		$self->ie_invoke(0, 'ie_connect_failed', ETIMEDOUT)
 			or $self->ie_invoke(0, 'ie_timer');
 	} else {
 		$self->ie_invoke(0, 'ie_timer');
 	}
 }
 
 
 # same name as handler since we want to intercept invocations
 # when processing pending callbacks.  Why?
 sub ie_input
 {
 	my $self = shift;
 	my $ibuf = \${*$self}{ie_ibuf};
 
 	# 
 	# We'll loop just to make sure we don't miss an event
 	# 
 	for (;;) {
 		my $ol = length($$ibuf);
 		my $rv = ${*$self}{ie_fh}->sysread($$ibuf, BUFSIZ, $ol);
 
 #		my $x = defined($rv) ? $rv : "$!";			# LOST EVENTS
 #		print STDERR "<INPUT ${*$self}{ie_desc}=$x>";		# LOST EVENTS
 
 		if ($rv) {
 			delete ${*$self}{ie_readclosed};
 		} elsif (defined($rv)) {
 			# must be 0 and closed!
 			${*$self}{ie_readclosed} = 1;
 			last;
 		} elsif ($! == EAGAIN) {
 			# readclosed = 0?
 			last;
 		} else {
 			# errors other than EAGAIN aren't recoverable
 			${*$self}{ie_readclosed} = $!;
 			last;
 		}
 
 		$self->ie_invoke(1, 'ie_input', $ibuf);
 		last if ${*$self}{ie_readclosed};
 	}
 
 	if (${*$self}{ie_readclosed}) {
 		$self->ie_invoke(1, 'ie_input', $ibuf)
 			if length($$ibuf);
 		if (${*$self}{ie_connecting}) {
 			${*$self}{ie_writeclosed} = $!;
 			$self->writeevents(0);
 			delete ${*$self}{ie_connecting};
 			delete ${*$self}{ie_connect_timeout};
 			$self->ie_invoke(0, 'ie_connect_failed', $!);
 		} else {
 			$self->ie_invoke(0, 'ie_eof', $ibuf)
 				unless ${*$self}{ie_eofinvoked}++;
 		}
 		$self->readevents(0);
 	}
 }
 
 sub reentrant
 {
 	my $self = shift;
 	my $old = ${*$self}{ie_reentrant};
 	if (@_) {
 		${*$self}{ie_reentrant} = $_[0];
 	}
 	return $old;
 }
 	
 sub output_bufsize
 {
 	my $self = shift;
 	my $old = ${*$self}{ie_obufsize};
 	if (@_) {
 		${*$self}{ie_obufsize} = $_[0];
 		if (length(${*$self}{ie_obuf}) > ${*$self}{ie_obufsize}) {
 			$self->ie_invoke(0, 'ie_outputoverflow', 1, ${*$self}{ie_obuf});
 			${*$self}{ie_overflowinvoked} = 1;
 		} elsif (${*$self}{ie_overflowinvoked}) {
 			$self->ie_invoke(0, 'ie_outputoverflow', 0, ${*$self}{ie_obuf});
 			${*$self}{ie_overflowinvoked} = 0;
 		}
 		# while this should trigger callbacks, we don't want to assume
 		# that our caller's code is re-enterant.
 	}
 	return $old;
 }
 
 # get/set autoread
 sub autoread
 {
 	my $self = shift;
 	my $old = ${*$self}{ie_autoread};
 	if (@_) {
 		${*$self}{ie_autoread} = $_[0];
 		if (${*$self}{ie_readclosed}) {
 			delete ${*$self}{ie_readclosed};
 			$self->readevents(1);
 		}
 	}
 	return $old;
 }
 
 sub writeevents
 {
 	my $self = shift;
 	my $old = ${*$self}{ie_want_write_events};
 	return !! $old unless @_;
 	my $new = !! shift;
 	return $old if defined($old) && $old eq $new;
 	${*$self}{ie_want_write_events} = $new;
 	$self->set_write_polling($new);
 	return $old;
 }
 
 sub readevents
 {
 	my $self = shift;
 	my $old = ${*$self}{ie_want_read_events};
 	return !! $old unless @_;
 	my $new = !! shift;
 #	print STDERR "<READEVENTS ${*$self}{ie_desc} = $new>"; 		# LOST EVENTS
 	return $old if defined($old) && $old eq $new;
 	${*$self}{ie_want_read_events} = $new;
 	$self->set_read_polling($new);
 	return $old;
 }
 
 sub drain
 {
 	my $self = shift;
 	$self->writeevents(1);
 }
 
 # register with Event
 sub ie_register
 {
 	my ($self) = @_;
 	my $fh = ${*$self}{ie_fh};
 	$fh->blocking(0);
 	$fh->autoflush(1);
 
 	my $fileno = ${*$self}{ie_fileno} = $fh->fileno;
 	return ($fh, $fileno);
 }
 
 # deregister with Event
 sub ie_deregister
 {
 	my ($self) = @_;
 	my $fh = ${*$self}{ie_fh};
 	delete $fh_table{$fh};
 	$self->readevents(0);
 	$self->writeevents(0);
 }
 
 # the standard max() function
 sub ie_max
 {
 	my ($max, @stuff) = @_;
 	for my $t (@stuff) {
 		$max = $t if $t > $max;
 	}
 	return $max;
 }
 
 # get the Filehandle
 sub filehandle
 {
 	my ($self) = @_;
 	return ${*$self}{ie_fh};
 }
 
 # get the Event
 sub event
 {
 	my ($self) = @_;
 	return ${*$self}{ie_event};
 }
 
 # set the handler
 sub handler
 {
 	my $self = shift;
 	my $old = ${*$self}{ie_handler};
 	${*$self}{ie_handler} = $_[0]
 		if @_;
 	return $old;
 }
 
 # is there enough?
 sub can_read
 {
 	my ($self, $length) = @_;
 	my $l = length(${*$self}{ie_ibuf});
 	return $l if $l && $l >= $length;
 	return "0 but true" if $length <= 0;
 	return 0;
 }
 
 # reads N characters or returns undef if it can't 
 sub getsome
 {
 	my ($self, $length) = @_;
 	return undef unless ${*$self}{ie_autoread};
 	my $ibuf = \${*$self}{ie_ibuf};
 	$length = length($$ibuf)
 		unless defined $length;
 	my $tmp = substr($$ibuf, 0, $length);
 	substr($$ibuf, 0, $length) = '';
 	return undef if ! length($tmp) && ! $self->eof2;
 	return $tmp;
 }
 
 # from base perl
 # will this work right for SOCK_DGRAM?
 sub connect
 {
 	my $self = shift;
 	my $fh = ${*$self}{ie_fh};
 	my $rv = $fh->connect(@_);
 	$self->reset;
 	$self->readevents(1);
 	unless($fh->connected()) {
 		${*$self}{ie_connecting} = 1;
 		$self->writeevents(1);
 		${*$self}{ie_connect_timeout} = time 
 			+ ${*$self}{ie_socket_timeout}
 			if ${*$self}{ie_socket_timeout};
 	}
 	return $rv;
 }
 
 # from IO::Socket
 sub listen
 {
 	my $self = shift;
 	my $fh = ${*$self}{ie_fh};
 	my $rv = $fh->listen();
 	$self->listener(1);
 	return $rv;
 }
 
 # from IO::Socket
 sub accept
 {
 	my ($self, $handler) = @_;
 	my $fh = ${*$self}{ie_fh};
 	my $newfh = $fh->accept();
 	return undef unless $newfh;
 
 	# it appears that sockdomain isn't set on accept()ed sockets
 	my $sd = $fh->sockdomain;
 
 	my $desc;
 	if ($sd == &AF_INET) {
 		$desc = sprintf "Accepted socket from %s:%s to %s:%s",
 			$newfh->peerhost, $newfh->peerport,
 			$newfh->sockhost, $newfh->sockport;
 	} elsif ($sd == &AF_UNIX) {
 		# Unset peerpath crashes on FreeBSD 9
 		my $pp = eval { $newfh->peerpath };
 		if ($pp) {
 			$desc = sprintf "Accepted socket from %s to %s",
 				$pp, $newfh->hostpath;
 		} else {
 			$desc = sprintf "Accepted socket from to %s",
 				$newfh->hostpath;
 		}
 	} else {
 		$desc = "Accept for ${*$self}{ie_desc}";
 	}
 	$handler = ${*$self}{ie_handler} 
 		unless defined $handler;
 	my $new = IO::Event->new($newfh, $handler, $desc);
 	${*$new}{ie_obufsize} = ${*$self}{ie_obufsize};
 	${*$new}{ie_reentrant} = ${*$self}{ie_reentrant};
 	return $new;
 }
 
 # not the same as IO::Handle
 sub input_record_separator
 {
 	my $self = shift;
 	my $old = ${*$self}{ie_irs};
 	${*$self}{ie_irs} = $_[0]
 		if @_;
 	if ($debug) {
 		my $fn = $self->fileno;
 		my $x = ${*$self}{ie_irs};
 		$x =~ s/\n/\\n/g;
 		print "input_record_separator($fn) = '$x'\n";
 	}
 	return $old;
 }
 
 # 0 = read
 # 1 = write
 # 2 = both
 sub shutdown
 {
 	my ($self, $what) = @_;
 	my $r;
 	if ($what == 1 || $what == 2) {
 		if (length(${*$self}{ie_obuf})) {
 			${*$self}{ie_shutdownrequested} = $what;
 			if ($what == 2) {
 				$r = shutdown(${*$self}{ie_fh}, 0) 
 			}
 		} else {
 			$r = shutdown(${*$self}{ie_fh}, $what);
 			${*$self}{ie_writeclosed} = 1;
 		}
 	} elsif ($what == 0) {
 		$r = shutdown(${*$self}{ie_fh}, 0);
 	} else {
 		die;
 	}
 	if ($what == 0 || $what == 2) {
 		${*$self}{ie_readclosed} = 1;
 	}
 	return 1 unless defined($r);
 	return $r;
 }
 
 # from IO::Handle
 sub close
 {
 	my ($self) = @_;
 	my $obuf = \${*$self}{ie_obuf};
 	${*$self}{ie_closecalled} = 1;
 	if (length($$obuf)) {
 		${*$self}{ie_closerequested} = 1;
 		${*$self}{ie_writeclosed} = 1;
 		${*$self}{ie_readclosed} = 1;
 	} else {
 		return $self->forceclose;
 	}
 }
 
 sub forceclose
 {
 	my ($self) = @_;
 	$self->ie_deregister();
 	my $ret = ${*$self}{ie_fh}->close();
 	${*$self}{ie_writeclosed} = 1;
 	${*$self}{ie_readclosed} = 1;
 	${*$self}{ie_totallyclosed} = 1;
 	print STDERR "forceclose(${*$self}{ie_desc})\n" if $debug;
 	return $ret;
 }
 
 # from IO::Handle
 sub open 
 { 
 	my $self = shift;
 	my $fh = ${*$self}{ie_fh};
 	$self->ie_deregister();
 	$self->close()
 		if $fh->opened;
 	$self->reset;
 	my $r;
 	if (@_ == 1) {
 		$r = CORE::open($fh, $_[0]);
 	} elsif (@_ == 2) {
 		$r = CORE::open($fh, $_[0], $_[1]);
 	} elsif (@_ == 3) {
 		$r = CORE::open($fh, $_[0], $_[1], $_[4]);
 	} elsif (@_ > 3) {
 		$r = CORE::open($fh, $_[0], $_[1], $_[4], @_);
 	} else {
 		confess("open w/o enoug args");
 	}
 	return undef unless defined $r;
 	$self->ie_register();
 	return $r;
 }
 
 
 # from IO::Handle		VAR LENGTH [OFFSET]
 #
 # this returns nothing unless there is enough to fill
 # the request or it's at eof
 #
 sub sysread 
 {
 	my $self = shift;
 
 	unless (${*$self}{ie_autoread}) {
 		my $buf = shift;
 		my $length = shift;
 		my $rv = ${*$self}{ie_fh}->sysread($buf, $length, @_);
 
 		if ($rv) {
 			delete ${*$self}{ie_readclosed};
 		} elsif (defined($rv)) {
 			# must be 0 and closed!
 			${*$self}{ie_readclosed} = 1;
 		} elsif ($! == EAGAIN) {
 			# nothing there
 		} else {
 			# errors other than EAGAIN aren't recoverable
 			${*$self}{ie_readclosed} = $!;
 		}
 		return $rv;
 	}
 
 	my $ibuf = \${*$self}{ie_ibuf};
 	my $length = length($$ibuf);
 
 	return undef unless $length >= $_[1] || $self->eof2;
 
 	(defined $_[2] ? 
 		substr ($_[0], $_[2], length($_[0]))
 		: $_[0]) 
 			= substr($$ibuf, 0, $_[1]);
 
 	substr($$ibuf, 0, $_[1]) = '';
 	return ($length-length($$ibuf));
 }
 
 # from IO::Handle
 sub syswrite
 {
 	my ($self, $data, $length, $offset) = @_;
 	if (defined $offset or defined $length) {
 		return $self->print(substr($data, $offset, $length));
 	} else {
 		return $self->print($data);
 	}
 }
 
 # like Data::LineBuffer
 sub get
 {
 	my $self = shift;
 	return undef unless ${*$self}{ie_autoread};
 	my $ibuf = \${*$self}{ie_ibuf};
 	my $irs = "\n";
 	my $index = index($$ibuf, $irs);
 	if ($index < 0) {
 		return undef unless $self->eof2;
 		my $l = $$ibuf;
 		$$ibuf = '';
 		return undef unless length($l);
 		return $l;
 	}
 	my $line = substr($$ibuf, 0, $index - length($irs) + 1);
 	substr($$ibuf, 0, $index + 1) = '';
 	return $line;
 }
 
 # like Data::LineBuffer
 # input_record_separator is always "\n".
 sub unget
 {
 	my $self = shift;
 	my $irs = "\n";
 	no warnings;
 	substr(${*$self}{ie_ibuf}, 0, 0) 
 		= join($irs, @_, undef);
 }
 
 # from IO::Handle
 sub getline 
 { 
 	my $self = shift;
 	return undef unless ${*$self}{ie_autoread};
 	my $ibuf = \${*$self}{ie_ibuf};
 	my $fh = ${*$self}{ie_fh};
 	my $irs = exists ${*$self}{ie_irs} ? ${*$self}{ie_irs} : $/;
 	my $line;
 
 
 	# perl's handling if input record separators is 
 	# not completely simple.  
 	$irs = $$irs if ref $irs;
 	my $index;
 	if ($irs =~ /^\d/ && int($irs)) {
 		if ($irs > 0 && length($$ibuf) >= $irs) {
 			$line = substr($$ibuf, 0, $irs);
 		} elsif ($self->eof2) {
 			$line = $$ibuf;
 		} 
 	} elsif (! defined $irs) {
 		if ($self->eof2) {
 			$line = $$ibuf;
 		} 
 	} elsif ($irs eq '') {
 		# paragraph mode
 		$$ibuf =~ s/^\n+//;
 		$irs = "\n\n";
 		$index = index($$ibuf, "\n\n");
 	} else {
 		# multi-character (or just \n)
 		$index = index($$ibuf, $irs);
 	}
 	if (defined $index) {
 		$line = $index > -1
 			? substr($$ibuf, 0, $index+length($irs))
 			: ($self->eof2 ? $$ibuf : undef);
 	}
 	if ($debug) {
 		no warnings;
 		my $x = $$ibuf;
 		substr($x, 0, length($line)) = '';
 		$x =~ s/\n/\\n/g;
 		my $y = $irs;
 		$y =~ s/\n/\\n/g;
 		print "looked for '$y', returning undef, keeping '$x'\n" unless defined $line;
 		my $z = $line;
 		$z =~ s/\n/\\n/g;
 		print "looked for '$y', returning '$z', keeping '$x'\n" if defined $line;
 	}
 	return undef unless defined($line) && length($line);
 	substr($$ibuf, 0, length($line)) = '';
 	return $line;
 }
 
 # is the following a good idea?
 #sub tell
 #{
 #	my ($self) = @_;
 #	return ${*$self}{ie_fh}->tell() + length(${*$self}{ie_obuf});
 #}
 
 # from IO::Handle
 sub getlines
 {
 	my $self = shift;
 	return undef unless ${*$self}{ie_autoread};
 	my $ibuf = \${*$self}{ie_ibuf};
 	#my $ol = length($$ibuf);
 	my $irs = exists ${*$self}{ie_irs} ? ${*$self}{ie_irs} : $/;
 	my @lines;
 	if ($debug) {
 		my $x = $irs;
 		$x =~ s/\n/\\n/g;
 		my $fn = $self->fileno;
 		print "getlines($fn, '$x')\n";
 	}
 	if ($irs =~ /^\d/ && int($irs)) {
 		if ($irs > 0) {
 			@lines = unpack("(a$irs)*", $$ibuf);
 			$$ibuf = '';
 			$$ibuf = pop(@lines)
 				if length($lines[$#lines]) != $irs && ! $self->eof2;
 		} else {
 			return undef unless $self->eof2;
 			@lines = $$ibuf;
 			$$ibuf = '';
 		}
 	} elsif (! defined $irs) {
 		return undef unless $self->eof2;
 		@lines = $$ibuf;
 		$$ibuf = '';
 	} elsif ($irs eq '') {
 		# paragraphish mode.
 		$$ibuf =~ s/^\n+//;
 		@lines = grep($_ ne '', split(/(.*?\n\n)\n*/s, $$ibuf));
 		$$ibuf = '';
 		$$ibuf = pop(@lines)
 			if @lines && substr($lines[$#lines], -2) ne "\n\n" && ! $self->eof2;
 		if ($debug) {
 			my $x = join('|', @lines);
 			$x =~ s/\n/\\n/g;
 			my $y = $$ibuf;
 			$y =~ s/\n/\\n/g;
 			print "getlines returns '$x' but holds onto '$y'\n";
 		}
 	} else {
 		# multicharacter
 		$rxcache{$irs} = qr/(.*?\Q$irs\E)/s
 			unless exists $rxcache{$irs};
 		my $irsrx = $rxcache{$irs};
 		@lines = grep($_ ne '', split(/$rxcache{$irs}/, $$ibuf));
 		return undef
 			unless @lines;
 		$$ibuf = '';
 		$$ibuf = pop(@lines)
 			if substr($lines[$#lines], 0-length($irs)) ne $irs && ! $self->eof2;
 	}
 	return @lines;
 }
 
 # from IO::Handle
 sub ungetc
 {
 	my ($self, $ord) = @_;
 	my $ibuf = \${*$self}{ie_ibuf};
 	substr($$ibuf, 0, 0) = chr($ord);
 }
 
 # from FileHandle::Unget & original
 sub ungets
 {
 	my $self = shift;
 	substr(${*$self}{ie_ibuf}, 0, 0) 
 		= join('', @_);
 }
 
 *xungetc = \&ungets;
 *ungetline = \&ungets;
 
 # from IO::Handle
 sub getc
 {
 	my ($self) = @_;
 	$self->getsome(1);
 }
 
 # from IO::Handle
 sub print
 {
 	my ($self, @data) = @_;
 	$! = ${*$self}{ie_writeclosed} && return undef
 		if ${*$self}{ie_writeclosed};
 	my $ol;
 	my $rv;
 	my $er;
 	my $obuf = \${*$self}{ie_obuf};
 	if ($ol = length($$obuf)) {
 		$$obuf .= join('', @data);
 		$rv = length($$obuf) - $ol;
 	} else {
 		my $fh = ${*$self}{ie_fh};
 		my $data = join('', @data);
 		$rv = CORE::syswrite($fh, $data);
 		if (defined($rv) && $rv < length($data)) {
 			$$obuf = substr($data, $rv, length($data)-$rv);
 			$self->writeevents(1);
 			$rv = 1;
 		} elsif ((! defined $rv) && $! == EAGAIN) {
 			$$obuf = $data;
 			$self->writeevents(1);
 			$rv = 1;
 		} else {
 			$er = 0+$!;
 		}
 	}
 	if (length($$obuf) > ${*$self}{ie_obufsize}) {
 		$self->ie_invoke(0, 'ie_outputoverflow', 1, $obuf);
 		${*$self}{ie_overflowinvoked} = 1;
 	} elsif (${*$self}{ie_overflowinvoked}) {
 		$self->ie_invoke(0, 'ie_outputoverflow', 0, $obuf);
 		${*$self}{ie_overflowinvoked} = 0;
 	}
 	$! = $er;
 	return $rv;
 }
 
 # from IO::Handle
 sub eof
 {
 	my ($self) = @_;
 	return 0 if length(${*$self}{ie_ibuf});
 	return 1 if ${*$self}{ie_readclosed};
 	return 0;
 	# return ${*$self}{ie_fh}->eof;
 }
 
 # internal use only.
 # just like eof, but we assume the input buffer is empty
 sub eof2
 {
 	my ($self) = @_;
 	if ($debug) {
 		my $fn = $self->fileno;
 		print "eof2($fn)...";
 		print " readclosed" if ${*$self}{ie_readclosed};
 		#print " EOF" if ${*$self}{ie_fh}->eof;
 		my $x = 0;
 		$x = 1 if ${*$self}{ie_readclosed};
 		# $x = ${*$self}{ie_fh}->eof unless defined $x;
 		print " =$x\n";
 	}
 	return 1 if ${*$self}{ie_readclosed};
 	return 0;
 	# return ${*$self}{ie_fh}->eof;
 }
 
 sub fileno
 {
 	my $self = shift;
 	return undef unless $self && ref($self) && reftype($self) eq 'GLOB';
 	return ${*$self}{ie_fileno}
 		if defined ${*$self}{ie_fileno};
 	return undef unless ${*$self}{ie_fh} && reftype(${*$self}{ie_fh}) eq 'GLOB';
 	return ${*$self}{ie_fh}->fileno();
 }
 
 sub DESTROY
 {
 	my $self = shift;
 	my $no = $self->fileno;
 	$no = '?' unless defined $no;
 	print "DESTROY $no...\n" if $debug;
 	return undef unless $self && ref($self) && reftype($self) eq 'GLOB';
 	${*$self}{ie_event}->cancel
 		if ${*$self}{ie_event};
 }
 
 
 sub TIEHANDLE
 {
 	my ($pkg, $self) = @_;
 	return $self;
 }
 
 sub PRINTF
 {
 	my $self = shift;
 	$self->print(sprintf(shift, @_));
 }
 
 sub READLINE 
 {
 	my $self = shift;
 	wantarray ? $self->getlines : $self->getline;
 }
 
 sub ie_desc
 {
 	my ($self, $new) = @_;
 	my $r = ${*$self}{ie_desc} || "no description";
 	${*$self}{ie_desc} = $new if defined $new;
 	return $r;
 }
 
 no warnings;
 
 *PRINT = \&print;
 
 *READ = \&sysread;
 
 # from IO::Handle
 *read = \&sysread;
 
 *WRITE = \&syswrite;
 
 *CLOSE = \&close;
 
 *EOF = \&eof;
 
 *TELL = \&tell;
 
 *FILENO = \&fileno;
 
 *SEEK = \&seek;
 
 *BINMODE = \&binmode;
 
 *OPEN = \&open;
 
 *GETC = \&getc;
 
 use warnings;
 
 }{package IO::Event::Socket::INET;
 
 # XXX version 1.26 required for IO::Socket::INET
 
 use strict;
 use warnings;
 use List::MoreUtils qw(any);
 
 our @ISA = qw(IO::Event);
 
 sub new
 {
 	my ($pkg, $a, $b, %sock) = @_;
 
 	# emulate behavior in the IO::Socket::INET API
 	if (! %sock && ! $b) {
 		$sock{PeerAddr} = $a;
 	} else {
 		$sock{$a} = $b;
 	}
 
 	my $handler = $sock{Handler} || (caller)[0];
 	delete $sock{Handler};
 
 	my $timeout;
 	if ($sock{Timeout}) {
 		$timeout = $sock{Timeout};
 		delete $sock{Timeout};
 	}
 
 	$sock{Blocking} = 0;
 
 	my (%ds) = %sock;
 
 	delete $sock{Description};
 
 	require IO::Socket::INET;
 	my $fh = new IO::Socket::INET(%sock);
 	return undef unless defined $fh;
 
 	my $peer = any { /Peer/ } keys %sock;
 	if ($peer) {
 		$ds{LocalPort} = $fh->sockport
 			unless defined $ds{LocalPort};
 		$ds{LocalHost} = $fh->sockhost
 			unless defined $ds{LocalHost};
 	}
 
 	my $desc = $ds{Description} 
 		|| join(" ", 
 			map { 
 				defined $ds{$_} 
 					? "$_=$ds{$_}" 
 					: $_
 			} sort keys %ds);
 
 	return undef unless $fh;
 	my $self = $pkg->SUPER::new($fh, $handler, $desc);
 	bless $self, $pkg;
 	$self->listener(1)
 		if $sock{Listen};
 	$fh->blocking(0); # XXX may be redundant
 	if ($peer) {
 		if ($fh->connected()) {
 			$self->ie_invoke(0, 'ie_connected');
 		} else {
 			${*$self}{ie_connecting} = 1;
 			$self->writeevents(1);
 			${*$self}{ie_connect_timeout} = $timeout + time
 				if $timeout;
 		}
 	}
 	${*$self}{ie_socket_timeout} = $timeout
 		if $timeout;
 
 	return $self;
 }
 
 }{
 package IO::Event::Socket::UNIX;
 
 use strict;
 use warnings;
 
 our @ISA = qw(IO::Event);
 
 sub new
 {
 	my ($pkg, $a, $b, %sock) = @_;
 
 	# emulate behavior in the IO::Socket::INET API
 	if (! %sock && ! $b) {
 		$sock{Peer} = $a;
 	} else {
 		$sock{$a} = $b;
 	}
 
 	my $handler = $sock{Handler} || (caller)[0];
 	delete $sock{Handler};
 
 	my $desc = $sock{Description} 
 		|| join(" ", map { "$_=$sock{$_}" } sort keys %sock);
 	delete $sock{Description};
 
 	require IO::Socket::UNIX;
 	my $fh = new IO::Socket::UNIX(%sock);
 
 	return undef unless $fh;
 	my $self = $pkg->SUPER::new($fh, $handler, $desc);
 	bless $self, $pkg;
 	$self->listener(1)
 		if $sock{Listen};
 	$fh->blocking(0); 
 	if ($sock{Peer}) {
 		if ($fh->connected()) {
 			$self->ie_invoke(0, 'ie_connected');
 		} else {
 			${*$self}{ie_connecting} = 1;
 			$self->writeevents(1);
 		}
 	}
 
 	return $self;
 }
 
 }#end package
 1;
 
### IO/Event/AnyEvent.pm ###
 
 #
 # Use AnyEvent for the IO::Event's event handler
 #
 
 my $debug = 0;
 my $debug_timer;
 my $lost_event_timer;
 
 {
 package IO::Event::AnyEvent;
 
 our $lost_event_hack = 2;
 
 require IO::Event;
 use strict;
 use warnings;
 use Scalar::Util qw(refaddr);
 
 our @ISA = qw(IO::Event::Common);
 
 my %selves;
 my $condvar;
 
 sub import
 {
 	require IO::Event;
 	IO::Event->import('AnyEvent');
 }
 
 sub new
 {
 	my ($pkg, @stuff) = @_;
 	my $self = $pkg->SUPER::new(@stuff);
 	return $self;
 }
 
 sub loop
 {
 	$condvar = AnyEvent->condvar;
 
 	if ($debug) {
 		$debug_timer = AnyEvent->timer(after => 0.1, interval => 0.1, cb => sub {
 			print STDERR "WATCHING:\n";
 			for my $ie (values %selves) {
 				print STDERR "\t";
 				print STDERR "R" if ${*$ie}{ie_anyevent_read};
 				print STDERR "W" if ${*$ie}{ie_anyevent_read};
 				print STDERR " ${*$ie}{ie_desc}\n";
 			}
 		});
 	}
 	if ($lost_event_hack) {
 		$lost_event_timer = AnyEvent->timer(
 			after => $lost_event_hack,
 			interval => $lost_event_hack,
 			cb => sub {
 				for my $ie (values %selves) {
 					next unless ${*$ie}{ie_anyevent_read};
 					next if ${*$ie}{ie_listener};  # no spurious connections!
 #					print STDERR "DISPATCHING FOR READ for ${*$ie}{ie_desc}\n";  # LOST EVENTS
 					$ie->ie_dispatch_read();
 				}
 			},
 		);
 	}
 	$condvar->recv;
 }
 
 sub timer
 {
 	IO::Event::AnyEvent::Wrapper->new('Timer', @_);
 }
 
 sub unloop
 {
 	$condvar->send(@_) if $condvar;
 }
 
 sub unloop_all
 {
 	$condvar->send(@_) if $condvar;
 }
 
 sub idle
 {
 	IO::Event::AnyEvent::Wrapper->new('Idle', @_);
 }
 
 sub set_write_polling
 {
 	my ($self, $new) = @_;
 	my $event = ${*$self}{ie_write};
 	if ($new) {
 		${*$self}{ie_anyevent_write} = AnyEvent->io(
 			fh	=> ${*$self}{ie_fh},
 			cb	=> sub {
 #				print STDERR "<Write ${*$self}{ie_desc}>";	# LOST EVENTS
 				$self->ie_dispatch_write();
 			},
 			poll	=> 'w',
 		);
 	} else {
 		delete ${*$self}{ie_anyevent_write};
 	}
 }
 
 sub set_read_polling
 {
 	my ($self, $new) = @_;
 	my $event = ${*$self}{ie_event};
 	if ($new) {
 		${*$self}{ie_anyevent_read} = AnyEvent->io(
 			fh	=> ${*$self}{ie_fh},
 			cb	=> sub {
 #				print STDERR "<READ ${*$self}{ie_desc}>";	# LOST EVENTS
 				$self->ie_dispatch_read();
 			},
 			poll	=> 'r',
 		);
 	} else {
 		delete ${*$self}{ie_anyevent_read};
 	}
 }
 
 sub ie_register
 {
 	my ($self) = @_;
 	my ($fh, $fileno) = $self->SUPER::ie_register();
 	$self->set_read_polling(${*$self}{ie_want_read_events} = ! ${*$self}{ie_readclosed});
 	${*$self}{ie_want_write_events} = '';
 	$selves{refaddr($self)} = $self;
 	print STDERR "registered ${*$self}{ie_fileno}:${*$self}{ie_desc} $self $fh ${*$self}{ie_event}\n"
 		if $debug;
 }
 
 sub ie_deregister
 {
 	my ($self) = @_;
 	$self->SUPER::ie_deregister();
 	delete ${*$self}{ie_anyevent_write};
 	delete ${*$self}{ie_anyevent_read};
 	delete $selves{refaddr($self)};
 }
 
 }{package IO::Event::AnyEvent::Wrapper;
 
 use strict;
 use warnings;
 use Scalar::Util qw(refaddr);
 
 my %handlers;
 
 sub new
 {
 	my ($pkg, $type, $req_pkg, %param) = @_;
 	my ($cpkg, $file, $line, $sub) = caller;
 	my $desc;
 	{ 
 		no warnings;
 		$desc = $param{desc} || "\u$type\E event  defined in ${cpkg}::${sub} at $file:$line";
 	}
 	if (ref($param{cb}) eq 'ARRAY') {
 		my ($obj, $meth) = @{$param{cb}};
 		$param{cb} = sub {
 			$obj->$meth();
 		};
 	}
 	$param{after} ||= $param{interval};
 	my $self = bless {
 		type	=> lc($type),
 		desc	=> $desc,
 		param	=> \%param,
 	}, $pkg;
 
 	$self->start();
 
 	return $self;
 }
 
 sub start
 {
 	my ($self) = @_;
 	$handlers{refaddr($self)} = $self;
 	my $type = $self->{type};
 	$self->{handler} = AnyEvent->$type(%{$self->{param}});
 }
 
 sub again
 {
 	my ($self) = @_;
 	$self->start;
 }
 
 sub now
 {
 	my ($self) = @_;
 	$self->{param}{cb}->($self);
 }
 
 sub stop
 {
 	my ($self) = @_;
 	delete $self->{handler};
 }
 
 sub cancel
 {
 	my ($self) = @_;
 	$self->stop();
 	delete $handlers{refaddr($self)};
 }
 
 sub is_cancelled
 {
 	my ($self) = @_;
 	return ! $handlers{refaddr($self)}; 
 }
 
 sub is_active
 {
 	my ($self) = @_;
 	return ! ! $self->{handler};
 }
 
 sub is_running
 {
 	return;
 }
 
 sub pending
 {
 	return;
 }
 
 
 }#end package
 1;
### IO/Event/Callback.pm ###
 
 package IO::Event::Callback;
 
 use strict;
 use warnings;
 
 use IO::Event;
 
 our @handlers;
 BEGIN {
 	@handlers = qw(input connection read_ready werror eof output 
 		outputdone connected connect_failed died timer exception
 		outputoverflow);
 }
 
 sub new
 {
 	my ($pkg, $filehandle, %h) = @_;
 
 	my $ro = $h{read_only};
 	my $wo = $h{write_only};
 	delete $h{read_only};
 	delete $h{write_only};
 
 	my $self = handler($pkg, %h);
 
 	return IO::Event->new($filehandle, $self, read_only => $ro, write_only => $wo);
 }
 
 sub ie_input		{ $_[0]->{'ie_input'}->(@_)		};
 sub ie_connection	{ $_[0]->{'ie_connection'}->(@_)	};
 sub ie_read_ready	{ $_[0]->{'ie_read_ready'}->(@_)	};
 sub ie_werror		{ $_[0]->{'ie_werror'}->(@_)		};
 sub ie_eof		{ $_[0]->{'ie_eof'}->(@_)		};
 sub ie_output		{ $_[0]->{'ie_output'}->(@_)		};
 sub ie_outputdone	{ $_[0]->{'ie_outputdone'}->(@_)	};
 sub ie_connected	{ $_[0]->{'ie_connected'}->(@_)		};
 sub ie_connect_failed	{ $_[0]->{'ie_connect_failed'}->(@_)	};
 sub ie_died		{ $_[0]->{'ie_died'}->(@_)		};
 sub ie_timer		{ $_[0]->{'ie_timer'}->(@_)		};
 sub ie_exception	{ $_[0]->{'ie_exception'}->(@_)		};
 sub ie_outputoverflow	{ $_[0]->{'ie_outputoverflow'}->(@_)	};
 
 sub handler
 {
 	my ($pkg, %h) = @_;
 
 	my $self = bless {}, $pkg;
 
 	for my $h (@handlers) {
 		my $key = 
 			exists($h{$h})		? $h		: 
 			exists($h{"ie_$h"})	? "ie_$h"	: undef;
 		if ($key) {
 			$self->{"ie_$h"} = $h{$key};
 			delete $h{$key};
 		} else {
 			$self->{"ie_$h"} = sub {};
 		}
 	}
 	my @k = keys %h;
 	die "unexpected parameters: @k" if @k;
 	return $self;
 }
 
 sub sock2handler
 {
 	my ($pkg, $sref) = @_;
 	my %h;
 	for my $h (@handlers) {
 		next unless exists $sref->{$h};
 		my $key = 
 			exists($sref->{$h})		? $h		: 
 			exists($sref->{"ie_$h"})	? "ie_$h"	: next;
 		$h{$h} = $sref->{$key};
 		delete $sref->{$key};
 	}
 	my $handler = handler($pkg,%h);
 }
 
 package IO::Event::INET::Callback;
 
 use strict;
 use warnings;
 
 sub new
 {
 	my ($pkg, %sock) = @_;
 	my $handler = IO::Event::Callback->sock2handler(\%sock);
 	return IO::Event::INET->new(%sock, Handler => $handler);
 }
 
 package IO::Event::UNIX::Callback;
 
 use strict;
 use warnings;
 
 sub new
 {
 	my ($pkg, %sock) = @_;
 	my $handler = IO::Event::Callback->sock2handler(\%sock);
 	return IO::Event::UNIX->new(%sock, Handler => $handler);
 }
 
 1;
 
 __END__
 
 
 =head1 NAME
 
  IO::Event::Callback - A closure based API for IO::Event
 
 =head1 SYNOPSIS
 
  use IO::Event::Callback;
 
  IO::Event::Callback->new($filehanle, %callbacks);
 
  use IO::Event::INET::Callback;
 
  IO::Event::INET::Callback->new(%socket_info, %callbacks);
 
  use IO::Event::UNIX::Callback;
 
  IO::Event::UNIX::Callback->new(%socket_info, %callbacks);
 
 =head1 DESCRIPTION
 
 IO::Event::Callback is a wrapper around L<IO::Event>.  It 
 provides an alternative interface to using L<IO::Event>.
 
 Instead of defining a class with methods like "ie_input", you
 provide the callbacks as code references when you create
 the object.
 
 The keys for the callbacks are the same as the callbacks 
 for L<IO::Event> with the C<ie_> prefix removed.
 
 =head1 EXAMPLE
 
  use IO::Event::Callback;
 
  my $remote = IO::Event::Callback::INET->new(
 	peeraddr	=> '10.20.10.3',
 	peerport	=> '23',
 	input		=> sub { 
 		# handle input
 	},
 	werror		=> sub {
 		# handdle error
 	},
 	eof		=> sub {
 		# handle end-of-file
 	},
  );
 
 =head1 SEE ALSO
 
 See the source for L<RPC::ToWorker> for an exmaple use of IO::Event::Callback.
 
### IO/Event/Emulate.pm ###
 
 #
 # Use a pure-perl event handler that kinda emulates's Event 
 # for IO::Event's event handler.
 #
 
 my $sdebug = 0;
 
 {
 package IO::Event::Emulate;
 
 use strict;
 use warnings;
 
 our @ISA = qw(IO::Event::Common);
 
 my %want_read;
 my %want_write;
 my %want_exception;
 my %active;
 
 my $rin = '';
 my $win = '';
 my $ein = '';
 
 my $unloop;
 
 sub import
 {
 	require IO::Event;
 	IO::Event->import('emulate_Event');
 }
 
 sub new
 {
 	my ($pkg, @stuff) = @_;
 	$pkg->SUPER::new(@stuff);
 }
 
 # a replacement for Event::loop
 sub ie_loop
 {
 	$unloop = 0;
 	my ($rout, $wout, $eout);
 	for(;;) {
 		print STDERR "EMULATE LOOP-TOP\n" if $sdebug;
 		last if $unloop;
 
 		my $timer_timeout = IO::Event::Emulate::Timer->get_time_to_timer;
 
 		my $timeout = $timer_timeout || IO::Event::Emulate::Idle->get_time_to_idle;
 
 		if ($sdebug > 3) {
 			print STDERR "Readers:\n";
 			for my $ioe (values %want_read) {
 				print STDERR "\t${*$ioe}{ie_desc}\n";
 			}
 			print STDERR "Writers:\n";
 			for my $ioe (values %want_write) {
 				print STDERR "\t${*$ioe}{ie_desc}\n";
 			}
 			print STDERR "Exceptions:\n";
 			for my $ioe (values %want_exception) {
 				print STDERR "\t${*$ioe}{ie_desc}\n";
 			}
 		}
 		my ($nfound, $timeleft) = select($rout=$rin, $wout=$win, $eout=$ein, $timeout);
 		print STDERR "SELECT: N$nfound\n" if $sdebug;
 		if ($nfound) {
 			EVENT:
 			{
 				if ($rout) {
 					for my $ioe (values %want_read) {
 						next unless vec($rout, ${*$ioe}{ie_fileno}, 1);
 						my $ret = $ioe->ie_dispatch_read(${*$ioe}{ie_fh});
 						if ($ret && vec($wout, ${*$ioe}{ie_fileno}, 1)) {
 							vec($wout, ${*$ioe}{ie_fileno}, 1) = 0;
 							$nfound--;
 						}
 						if ($ret && vec($eout, ${*$ioe}{ie_fileno}, 1)) {
 							vec($eout, ${*$ioe}{ie_fileno}, 1) = 0;
 							$nfound--;
 						}
 						$nfound--;
 						last EVENT unless $nfound > 0;
 					}
 				}
 				if ($wout) {
 					for my $ioe (values %want_write) {
 						next unless vec($wout, ${*$ioe}{ie_fileno}, 1);
 						my $ret = $ioe->ie_dispatch_write(${*$ioe}{ie_fh});
 						if ($ret && vec($eout, ${*$ioe}{ie_fileno}, 1)) {
 							vec($eout, ${*$ioe}{ie_fileno}, 1) = 0;
 							$nfound--;
 						}
 						$nfound--;
 						last EVENT unless $nfound > 0;
 					}
 				}
 				if ($eout) {
 					for my $ioe (values %want_exception) {
 						next unless vec($eout, ${*$ioe}{ie_fileno}, 1);
 						$ioe->ie_dispatch_exception(${*$ioe}{ie_fh});
 						$nfound--;
 						last EVENT unless $nfound > 0;
 					}
 				}
 			}
 		}
 		IO::Event::Emulate::Timer->invoke_timers if $timer_timeout;
 		IO::Event::Emulate::Idle->invoke_idlers($nfound == 0);
 	}
 	die unless ref($unloop);
 	my @r = @$unloop;
 	shift(@r);
 	return $r[0] if @r == 1;
 	return @r;
 }
 
 sub loop
 {
 	ie_loop(@_);
 }
 
 sub timer
 {
 	shift;
 	IO::Event::Emulate::Timer->new(@_);
 }
 
 sub idle
 {
 	shift;
 	IO::Event::Emulate::Idle->new(@_);
 }
 
 sub unloop_all
 {
 	$unloop = [1, @_];
 }
 
 sub set_write_polling
 {
 	my ($self, $new) = @_;
 	my $fileno = ${*$self}{ie_fileno};
 	if ($new) {
 		vec($win, $fileno, 1) = 1;
 		$want_write{$fileno} = $want_exception{$fileno} = $self;
 	} else {
 		vec($win, $fileno, 1) = 0;
 		delete $want_write{$fileno};
 		delete $want_exception{$fileno}
 			unless $want_read{$fileno};
 	}
 	$ein = $rin | $win;
 }
 
 sub set_read_polling
 {
 	my ($self, $new) = @_;
 	my $fileno = ${*$self}{ie_fileno};
 	if ($new) {
 		vec($rin, $fileno, 1) = 1;
 		$want_read{$fileno} = $want_exception{$fileno} = $self;
 	} else {
 		if (defined $fileno) {
 			vec($rin, $fileno, 1) = 0;
 			delete $want_read{$fileno};
 			delete $want_exception{$fileno}
 				unless $want_write{$fileno}
 		}
 	}
 	$ein = $rin | $win;
 }
 
 sub ie_register
 {
 	my ($self) = @_;
 	my ($fh, $fileno) = $self->SUPER::ie_register();
 	$active{$fileno} = $self;
 	$self->readevents(! ${*$self}{ie_readclosed}); 
 	$self->writeevents(0);
 }
 
 sub ie_deregister
 {
 	my ($self) = @_;
 	$self->SUPER::ie_deregister();
 	delete $active{${*$self}{ie_fileno}};
 }
 
 }{package IO::Event::Emulate::Timer;
 
 use warnings;
 use strict;
 use Time::HiRes qw(time);
 use Carp qw(confess);
 use Scalar::Util qw(reftype);
 
 our @ISA = qw(IO::Event);
 our %timers = ();
 our %levels = ();
 our %next = ();
 
 BEGIN {
 	for $a (qw(at after interval hard cb desc prio repeat timeout)) {
 		my $attrib = $a;
 		no strict 'refs';
 		*{"IO::Event::Emulate::Timer::$a"} = sub {
 			my $self = shift;
 			return $self->{$attrib} unless @_;
 			my $val = shift;
 			$self->{$attrib} = $val;
 			return $val;
 		};
 	}
 }
 
 my $tcount = 1;
 
 my @timers;
 
 sub get_time_to_timer
 {
 	@timers = sort { $a <=> $b } keys %next;
 	my $t = time;
 	if (@timers) {
 		if ($timers[0] > $t) {
 			my $timeout = $timers[0] - $t;
 			$timeout = 0.01 if $timeout < 0.01;
 			return $timeout;
 		} else {
 			return 0.01;
 		}
 	}
 	return undef;
 }
 
 sub invoke_timers
 {
 	while (@timers && $timers[0] < time) {
 		print STDERR "Ti" if $sdebug;
 		my $t = shift(@timers);
 		my $te = delete $next{$t};
 		for my $tnum (keys %$te) {
 			my $timer = $te->{$tnum};
 			next unless $timer->{next};
 			next unless $timer->{next} eq $t;
 			$timer->now();
 		}
 	}
 }
 
 sub new
 {
 	my ($pkg, %param) = @_;
 	confess unless $param{cb};
 	die if $param{after} && $param{at};
 	my $timer = bless {
 		tcount		=> $tcount,
 		last_time	=> time,
 		%param
 	}, __PACKAGE__;
 	$timers{$tcount++} = $timer;
 	$timer->schedule;
 	return $timer;
 }
 
 sub schedule
 {
 	my ($self) = @_;
 	my $next;
 	if ($self->{invoked}) {
 		if ($self->{interval}) {
 			$next = $self->{last_time} + $self->{interval};
 			if ($self->{hard} && $self->{next}) {
 				$next = $self->{next} + $self->{interval};
 			}
 		} else {
 			$next = undef;
 		}
 	} elsif ($self->{at}) {
 		$next = $self->{at};
 	} elsif ($self->{after}) {
 		$next = $self->{after} + time;
 	} elsif ($self->{interval}) {
 		$next = $self->{interval} + time;
 	} else {
 		die;
 	}
 	if ($next) {
 		$next{$next}{$self->{tcount}} = $self;
 		$self->{next} = $next;
 	} else {
 		$self->{next} = 0;
 		$self->stop();
 	}
 }
 
 sub start
 {
 	my ($self) = @_;
 	$timers{$self->{tcount}} = $self;
 	delete $self->{stopped};
 	$self->schedule;
 }
 
 sub again
 {
 	my ($self) = @_;
 	$self->{last_time} = time;
 	$self->start;
 }
 
 sub now
 {
 	my ($self) = @_;
 	$self->{last_time} = time;
 	local($levels{$self->{tcount}}) = ($levels{$self->{tcount}} || 0)+1;
 	$self->{invoked}++;
 	if (reftype($self->{cb}) eq 'CODE') {
 		$self->{cb}->($self);
 	} elsif (reftype($self->{cb}) eq 'ARRAY') {
 		my ($o, $m) = @{$self->{cb}};
 		$o->$m($self);
 	} else {
 		die;
 	}
 	$self->schedule;
 }
 
 
 sub stop
 {
 	my ($self) = @_;
 	delete $timers{$self->{tcount}};
 	$self->{stopped} = time;
 }
 
 sub cancel
 {
 	my ($self) = @_;
 	$self->{cancelled} = time;
 	delete $timers{$self->{tcount}};
 }
 
 sub is_cancelled
 {
 	my ($self) = @_;
 	return $self->{cancelled};
 }
 
 sub is_active
 {
 	my ($self) = @_;
 	return exists $timers{$self->{tcount}};
 }
 
 sub is_running
 {
 	my ($self) = @_;
 	return $levels{$self->{tcount}};
 }
 
 sub is_suspended
 {
 	my ($self) = @_;
 	return 0;
 }
 
 sub pending
 {
 	return;
 }
 
 
 }{package IO::Event::Emulate::Idle;
 
 use warnings;
 use strict;
 use Carp qw(confess);
 use Scalar::Util qw(reftype);
 use Time::HiRes qw(time);
 
 our @ISA = qw(IO::Event);
 our %timers = ();
 our %levels = ();
 our %next = ();
 
 my $icount = 0;
 my %idlers;
 
 our $time_to_idle_timeout = 1;
 
 sub new
 {
 	my ($pkg, %param) = @_;
 	confess unless $param{cb};
 	die if $param{after} && $param{at};
 	my $idler = bless {
 		icount		=> $icount,
 		last_time	=> time,
 		%param
 	}, __PACKAGE__;
 	$idlers{$icount++} = $idler;
 	return $idler;
 }
 
 sub get_time_to_idle
 {
 	return undef unless %idlers;
 	return $time_to_idle_timeout;
 }
 
 sub start
 {
 	my ($self) = @_;
 	$idlers{$self->{icount}} = $self;
 	delete $self->{stopped};
 	$self->schedule;
 }
 
 sub again
 {
 	my ($self) = @_;
 	$self->{last_time} = time;
 	$self->start;
 }
 
 sub invoke_idlers
 {
 	my ($pkg, $is_idle) = @_;
 	for my $idler (values %idlers) {
 		if ($idler->{min} && (time - $idler->{last_time}) < $idler->{min}) {
 			next;
 		}
 		unless ($is_idle) {
 			next unless $idler->{max};
 			next unless (time - $idler->{last_time}) > $idler->{max};
 		}
 		$idler->now;
 	}
 }
 
 sub now
 {
 	my ($self) = @_;
 	$self->{last_time} = time;
 	local($levels{$self->{icount}}) = ($levels{$self->{icount}} || 0)+1;
 	if (defined($self->{reentrant}) && ! $self->{reentrant} && $self->{icount}) {
 		return;
 	}
 	$self->{invoked}++;
 	if (defined($self->{repeat}) && ! $self->{repeat}) {
 		$self->cancel;
 	}
 	if (reftype($self->{cb}) eq 'CODE') {
 		$self->{cb}->($self);
 	} elsif (reftype($self->{cb}) eq 'ARRAY') {
 		my ($o, $m) = @{$self->{cb}};
 		$o->$m($self);
 	} else {
 		die;
 	}
 	$self->{last_time} = time;
 }
 
 
 sub stop
 {
 	my ($self) = @_;
 	delete $idlers{$self->{icount}};
 	$self->{stopped} = time;
 }
 
 sub cancel
 {
 	my ($self) = @_;
 	$self->{cancelled} = time;
 	delete $idlers{$self->{icount}};
 }
 
 sub is_cancelled
 {
 	my ($self) = @_;
 	return $self->{cancelled};
 }
 
 sub is_active
 {
 	my ($self) = @_;
 	return exists $idlers{$self->{icount}};
 }
 
 sub is_running
 {
 	my ($self) = @_;
 	return $levels{$self->{icount}};
 }
 
 sub is_suspended
 {
 	my ($self) = @_;
 	return 0;
 }
 
 sub pending
 {
 	return;
 }
 
 
 }#end package
 1;
### IO/Event/Event.pm ###
 
 #
 # Use Event for the IO::Event event handler
 #
 
 my $debug = $IO::Event::debug;
 my $edebug = $IO::Event::edebug;
 my $sdebug = $IO::Event::sdebug;
 
 package IO::Event::Event;
 
 require IO::Event;
 use strict;
 use warnings;
 
 our @ISA = qw(IO::Event::Common);
 
 sub import
 {
 	require IO::Event;
 	IO::Event->import('no_emulate_Event');
 }
 
 sub new
 {
 	my ($pkg, @stuff) = @_;
 	require Event;
 	require Event::Watcher;
 	$pkg->SUPER::new(@stuff);
 }
 
 sub loop
 {
 	require Event;
 	Event::loop(@_);
 }
 
 sub unloop_all
 {
 	require Event;
 	Event::unloop_all(@_);
 }
 
 sub timer
 {
 	require Event;
 	shift;
 	Event->timer(hard => 1, @_);
 }
 
 sub idle
 {
 	require Event;
 	shift;
 	Event->idle(@_);
 }
 
 sub set_write_polling
 {
 	my ($self, $new) = @_;
 	my $event = ${*$self}{ie_event};
 	if ($new) {
 		$event->poll($event->poll | Event::Watcher::W());
 	} else {
 		$event->poll($event->poll & ~Event::Watcher::W());
 	}
 }
 
 sub set_read_polling
 {
 	my ($self, $new) = @_;
 	my $event = ${*$self}{ie_event};
 	if ($new) {
 		$event->poll($event->poll | Event::Watcher::R());
 	} else {
 		if ($event) {
 			$event->poll($event->poll & ~Event::Watcher::R());
 		}
 	}
 }
 
 sub ie_register
 {
 	my ($self) = @_;
 	my ($fh, $fileno) = $self->SUPER::ie_register();
 	my $R = ${*$self}{ie_readclosed}
 		? 0
 		: Event::Watcher::R();
 	${*$self}{ie_want_read_events} = ! ${*$self}{ie_readclosed};
 	${*$self}{ie_want_write_events} = '';
 	${*$self}{ie_event} = Event->io(
 		fd	=> $fileno,
 		poll	=> Event::Watcher::E()|Event::Watcher::T()|$R,
 		cb	=> [ $self, 'ie_dispatch' ],
 		desc	=> ${*$self}{ie_desc},
 		edebug	=> $edebug,
 	);
 	print STDERR "registered ${*$self}{ie_fileno}:${*$self}{ie_desc} $self $fh ${*$self}{ie_event}\n"
 		if $debug;
 }
 
 sub ie_deregister
 {
 	my ($self) = @_;
 	$self->SUPER::ie_deregister();
 	${*$self}{ie_event}->cancel
 		if ${*$self}{ie_event};
 	delete ${*$self}{ie_event};
 }
 
 1;
### IO/Socket/UNIX/Util.pm ###
 package IO::Socket::UNIX::Util;
 
 our $DATE = '2014-12-05'; # DATE
 our $VERSION = '0.05'; # VERSION
 
 use 5.010001;
 use strict;
 use warnings;
 
 use IO::Socket::UNIX;
 use POSIX qw(locale_h);
 
 use Exporter;
 our @ISA = qw(Exporter);
 our @EXPORT_OK = qw(
                        create_unix_socket
                        create_unix_stream_socket
                        create_unix_datagram_socket
                );
 
 sub create_unix_socket {
     my ($path, $mode, $opts) = @_;
 
     $opts //= {};
 
     my $old_locale = setlocale(LC_ALL);
 
     my $sock;
 
     setlocale(LC_ALL, "C"); # so that error messages are in English
     # probe the Unix socket first, delete if stale
     {
         $sock = IO::Socket::UNIX->new(
             Type => SOCK_STREAM,
             Peer => $path,
             %$opts,
         );
         my $err = $@ unless $sock;
         if ($sock) {
             die "Some process is already listening on $path, aborting";
         } elsif ($err =~ /^connect: permission denied/i) {
             die "Cannot access $path, aborting";
         } elsif (1) { #$err =~ /^connect: connection refused/i) {
             unlink $path;
         } elsif ($err !~ /^connect: no such file/i) {
             die "Cannot bind to $path: $err";
         }
     }
     setlocale(LC_ALL, $old_locale);
 
     # XXX this is a race condition
 
     # create listening socket now
     $sock = IO::Socket::UNIX->new(
         Type   => SOCK_STREAM,
         Local  => $path,
         Listen => 1,
         %$opts,
     );
     die "Can't create listening Unix socket: $@" unless $sock;
 
     if (defined $mode) {
         warn "Can't chmod $path: $!" unless chmod($mode, $path);
     }
 
     $sock;
 }
 
 sub create_unix_stream_socket {
     my ($path, $mode, $opts) = @_;
     $opts //= {};
     create_unix_socket($path, $mode, {Type=>SOCK_STREAM, %$opts});
 }
 
 sub create_unix_datagram_socket {
     my ($path, $mode, $opts) = @_;
     $opts //= {};
     create_unix_socket($path, $mode, {Type=>SOCK_DGRAM, %$opts});
 }
 
 1;
 # ABSTRACT: Unix domain socket utilities
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 IO::Socket::UNIX::Util - Unix domain socket utilities
 
 =head1 VERSION
 
 This document describes version 0.05 of IO::Socket::UNIX::Util (from Perl distribution IO-Socket-UNIX-Util), released on 2014-12-05.
 
 =head1 FUNCTIONS
 
 =head2 create_unix_socket($path[, $mode, \%opts]) => SOCKET
 
 Create a listening Unix socket (by default with Type SOCK_STREAM) using
 L<IO::SOcket::UNIX>. C<%opts> will be passed to L<IO::Socket::UNIX>.
 
 Die on failure.
 
 This function creates Unix domain socket with the usual way of using
 L<IO::Socket::UNIX> with some extra stuffs: remove stale socket first, show more
 detailed/precise error message, chmod with $mode.
 
 =head2 create_unix_stream_socket($path[, $mode, \%opts]) => SOCKET
 
 Shortcut for:
 
  create_unix_socket($path, $mode, {Type=>SOCK_STREAM, %opts});
 
 which is the default anyway.
 
 =head2 create_unix_datagram_socket($path[, $mode, \%opts]) => SOCKET
 
 Shortcut for:
 
  create_unix_socket($path, $mode, {Type=>SOCK_DGRAM, %opts});
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/IO-Socket-UNIX-Util>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-SHARYANTO-IO-Socket-Utils>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=IO-Socket-UNIX-Util>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2014 by perlancar@cpan.org.
 
 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
### JSON.pm ###
 package JSON;
 
 
 use strict;
 use Carp ();
 use base qw(Exporter);
 @JSON::EXPORT = qw(from_json to_json jsonToObj objToJson encode_json decode_json);
 
 BEGIN {
     $JSON::VERSION = '2.90';
     $JSON::DEBUG   = 0 unless (defined $JSON::DEBUG);
     $JSON::DEBUG   = $ENV{ PERL_JSON_DEBUG } if exists $ENV{ PERL_JSON_DEBUG };
 }
 
 my $Module_XS  = 'JSON::XS';
 my $Module_PP  = 'JSON::PP';
 my $Module_bp  = 'JSON::backportPP'; # included in JSON distribution
 my $PP_Version = '2.27203';
 my $XS_Version = '2.34';
 
 
 # XS and PP common methods
 
 my @PublicMethods = qw/
     ascii latin1 utf8 pretty indent space_before space_after relaxed canonical allow_nonref 
     allow_blessed convert_blessed filter_json_object filter_json_single_key_object 
     shrink max_depth max_size encode decode decode_prefix allow_unknown
 /;
 
 my @Properties = qw/
     ascii latin1 utf8 indent space_before space_after relaxed canonical allow_nonref
     allow_blessed convert_blessed shrink max_depth max_size allow_unknown
 /;
 
 my @XSOnlyMethods = qw/allow_tags/; # Currently nothing
 
 my @PPOnlyMethods = qw/
     indent_length sort_by
     allow_singlequote allow_bignum loose allow_barekey escape_slash as_nonblessed
 /; # JSON::PP specific
 
 
 # used in _load_xs and _load_pp ($INSTALL_ONLY is not used currently)
 my $_INSTALL_DONT_DIE  = 1; # When _load_xs fails to load XS, don't die.
 my $_INSTALL_ONLY      = 2; # Don't call _set_methods()
 my $_ALLOW_UNSUPPORTED = 0;
 my $_UNIV_CONV_BLESSED = 0;
 my $_USSING_bpPP       = 0;
 
 
 # Check the environment variable to decide worker module. 
 
 unless ($JSON::Backend) {
     $JSON::DEBUG and  Carp::carp("Check used worker module...");
 
     my $backend = exists $ENV{PERL_JSON_BACKEND} ? $ENV{PERL_JSON_BACKEND} : 1;
 
     if ($backend eq '1' or $backend =~ /JSON::XS\s*,\s*JSON::PP/) {
         _load_xs($_INSTALL_DONT_DIE) or _load_pp();
     }
     elsif ($backend eq '0' or $backend eq 'JSON::PP') {
         _load_pp();
     }
     elsif ($backend eq '2' or $backend eq 'JSON::XS') {
         _load_xs();
     }
     elsif ($backend eq 'JSON::backportPP') {
         $_USSING_bpPP = 1;
         _load_pp();
     }
     else {
         Carp::croak "The value of environmental variable 'PERL_JSON_BACKEND' is invalid.";
     }
 }
 
 
 sub import {
     my $pkg = shift;
     my @what_to_export;
     my $no_export;
 
     for my $tag (@_) {
         if ($tag eq '-support_by_pp') {
             if (!$_ALLOW_UNSUPPORTED++) {
                 JSON::Backend::XS
                     ->support_by_pp(@PPOnlyMethods) if ($JSON::Backend eq $Module_XS);
             }
             next;
         }
         elsif ($tag eq '-no_export') {
             $no_export++, next;
         }
         elsif ( $tag eq '-convert_blessed_universally' ) {
             eval q|
                 require B;
                 *UNIVERSAL::TO_JSON = sub {
                     my $b_obj = B::svref_2object( $_[0] );
                     return    $b_obj->isa('B::HV') ? { %{ $_[0] } }
                             : $b_obj->isa('B::AV') ? [ @{ $_[0] } ]
                             : undef
                             ;
                 }
             | if ( !$_UNIV_CONV_BLESSED++ );
             next;
         }
         push @what_to_export, $tag;
     }
 
     return if ($no_export);
 
     __PACKAGE__->export_to_level(1, $pkg, @what_to_export);
 }
 
 
 # OBSOLETED
 
 sub jsonToObj {
     my $alternative = 'from_json';
     if (defined $_[0] and UNIVERSAL::isa($_[0], 'JSON')) {
         shift @_; $alternative = 'decode';
     }
     Carp::carp "'jsonToObj' will be obsoleted. Please use '$alternative' instead.";
     return JSON::from_json(@_);
 };
 
 sub objToJson {
     my $alternative = 'to_json';
     if (defined $_[0] and UNIVERSAL::isa($_[0], 'JSON')) {
         shift @_; $alternative = 'encode';
     }
     Carp::carp "'objToJson' will be obsoleted. Please use '$alternative' instead.";
     JSON::to_json(@_);
 };
 
 
 # INTERFACES
 
 sub to_json ($@) {
     if (
         ref($_[0]) eq 'JSON'
         or (@_ > 2 and $_[0] eq 'JSON')
     ) {
         Carp::croak "to_json should not be called as a method.";
     }
     my $json = JSON->new;
 
     if (@_ == 2 and ref $_[1] eq 'HASH') {
         my $opt  = $_[1];
         for my $method (keys %$opt) {
             $json->$method( $opt->{$method} );
         }
     }
 
     $json->encode($_[0]);
 }
 
 
 sub from_json ($@) {
     if ( ref($_[0]) eq 'JSON' or $_[0] eq 'JSON' ) {
         Carp::croak "from_json should not be called as a method.";
     }
     my $json = JSON->new;
 
     if (@_ == 2 and ref $_[1] eq 'HASH') {
         my $opt  = $_[1];
         for my $method (keys %$opt) {
             $json->$method( $opt->{$method} );
         }
     }
 
     return $json->decode( $_[0] );
 }
 
 
 
 sub true  { $JSON::true  }
 
 sub false { $JSON::false }
 
 sub null  { undef; }
 
 
 sub require_xs_version { $XS_Version; }
 
 sub backend {
     my $proto = shift;
     $JSON::Backend;
 }
 
 #*module = *backend;
 
 
 sub is_xs {
     return $_[0]->backend eq $Module_XS;
 }
 
 
 sub is_pp {
     return not $_[0]->is_xs;
 }
 
 
 sub pureperl_only_methods { @PPOnlyMethods; }
 
 
 sub property {
     my ($self, $name, $value) = @_;
 
     if (@_ == 1) {
         my %props;
         for $name (@Properties) {
             my $method = 'get_' . $name;
             if ($name eq 'max_size') {
                 my $value = $self->$method();
                 $props{$name} = $value == 1 ? 0 : $value;
                 next;
             }
             $props{$name} = $self->$method();
         }
         return \%props;
     }
     elsif (@_ > 3) {
         Carp::croak('property() can take only the option within 2 arguments.');
     }
     elsif (@_ == 2) {
         if ( my $method = $self->can('get_' . $name) ) {
             if ($name eq 'max_size') {
                 my $value = $self->$method();
                 return $value == 1 ? 0 : $value;
             }
             $self->$method();
         }
     }
     else {
         $self->$name($value);
     }
 
 }
 
 
 
 # INTERNAL
 
 sub _load_xs {
     my $opt = shift;
 
     $JSON::DEBUG and Carp::carp "Load $Module_XS.";
 
     # if called after install module, overload is disable.... why?
     JSON::Boolean::_overrride_overload($Module_XS);
     JSON::Boolean::_overrride_overload($Module_PP);
 
     eval qq|
         use $Module_XS $XS_Version ();
     |;
 
     if ($@) {
         if (defined $opt and $opt & $_INSTALL_DONT_DIE) {
             $JSON::DEBUG and Carp::carp "Can't load $Module_XS...($@)";
             return 0;
         }
         Carp::croak $@;
     }
 
     unless (defined $opt and $opt & $_INSTALL_ONLY) {
         _set_module( $JSON::Backend = $Module_XS );
         my $data = join("", <DATA>); # this code is from Jcode 2.xx.
         close(DATA);
         eval $data;
         JSON::Backend::XS->init;
     }
 
     return 1;
 };
 
 
 sub _load_pp {
     my $opt = shift;
     my $backend = $_USSING_bpPP ? $Module_bp : $Module_PP;
 
     $JSON::DEBUG and Carp::carp "Load $backend.";
 
     # if called after install module, overload is disable.... why?
     JSON::Boolean::_overrride_overload($Module_XS);
     JSON::Boolean::_overrride_overload($backend);
 
     if ( $_USSING_bpPP ) {
         eval qq| require $backend |;
     }
     else {
         eval qq| use $backend $PP_Version () |;
     }
 
     if ($@) {
         if ( $backend eq $Module_PP ) {
             $JSON::DEBUG and Carp::carp "Can't load $Module_PP ($@), so try to load $Module_bp";
             $_USSING_bpPP++;
             $backend = $Module_bp;
             JSON::Boolean::_overrride_overload($backend);
             local $^W; # if PP installed but invalid version, backportPP redefines methods.
             eval qq| require $Module_bp |;
         }
         Carp::croak $@ if $@;
     }
 
     unless (defined $opt and $opt & $_INSTALL_ONLY) {
         _set_module( $JSON::Backend = $Module_PP ); # even if backportPP, set $Backend with 'JSON::PP'
         JSON::Backend::PP->init;
     }
 };
 
 
 sub _set_module {
     return if defined $JSON::true;
 
     my $module = shift;
 
     local $^W;
     no strict qw(refs);
 
     $JSON::true  = ${"$module\::true"};
     $JSON::false = ${"$module\::false"};
 
     push @JSON::ISA, $module;
     if ( JSON->is_xs and JSON->backend->VERSION < 3 ) {
         eval 'package JSON::PP::Boolean';
         push @{"$module\::Boolean::ISA"}, qw(JSON::PP::Boolean);
     }
 
     *{"JSON::is_bool"} = \&{"$module\::is_bool"};
 
     for my $method ($module eq $Module_XS ? @PPOnlyMethods : @XSOnlyMethods) {
         *{"JSON::$method"} = sub {
             Carp::carp("$method is not supported in $module.");
             $_[0];
         };
     }
 
     return 1;
 }
 
 
 
 #
 # JSON Boolean
 #
 
 package JSON::Boolean;
 
 my %Installed;
 
 sub _overrride_overload {
     return; # this function is currently disable.
     return if ($Installed{ $_[0] }++);
 
     my $boolean = $_[0] . '::Boolean';
 
     eval sprintf(q|
         package %s;
         use overload (
             '""' => sub { ${$_[0]} == 1 ? 'true' : 'false' },
             'eq' => sub {
                 my ($obj, $op) = ref ($_[0]) ? ($_[0], $_[1]) : ($_[1], $_[0]);
                 if ($op eq 'true' or $op eq 'false') {
                     return "$obj" eq 'true' ? 'true' eq $op : 'false' eq $op;
                 }
                 else {
                     return $obj ? 1 == $op : 0 == $op;
                 }
             },
         );
     |, $boolean);
 
     if ($@) { Carp::croak $@; }
 
     if ( exists $INC{'JSON/XS.pm'} and $boolean eq 'JSON::XS::Boolean' ) {
         local $^W;
         my $true  = do { bless \(my $dummy = 1), $boolean };
         my $false = do { bless \(my $dummy = 0), $boolean };
         *JSON::XS::true  = sub () { $true };
         *JSON::XS::false = sub () { $false };
     }
     elsif ( exists $INC{'JSON/PP.pm'} and $boolean eq 'JSON::PP::Boolean' ) {
         local $^W;
         my $true  = do { bless \(my $dummy = 1), $boolean };
         my $false = do { bless \(my $dummy = 0), $boolean };
         *JSON::PP::true  = sub { $true };
         *JSON::PP::false = sub { $false };
     }
 
     return 1;
 }
 
 
 #
 # Helper classes for Backend Module (PP)
 #
 
 package JSON::Backend::PP;
 
 sub init {
     local $^W;
     no strict qw(refs); # this routine may be called after JSON::Backend::XS init was called.
     *{"JSON::decode_json"} = \&{"JSON::PP::decode_json"};
     *{"JSON::encode_json"} = \&{"JSON::PP::encode_json"};
     *{"JSON::PP::is_xs"}  = sub { 0 };
     *{"JSON::PP::is_pp"}  = sub { 1 };
     return 1;
 }
 
 #
 # To save memory, the below lines are read only when XS backend is used.
 #
 
 package JSON;
 
 1;
 __DATA__
 
 
 #
 # Helper classes for Backend Module (XS)
 #
 
 package JSON::Backend::XS;
 
 use constant INDENT_LENGTH_FLAG => 15 << 12;
 
 use constant UNSUPPORTED_ENCODE_FLAG => {
     ESCAPE_SLASH      => 0x00000010,
     ALLOW_BIGNUM      => 0x00000020,
     AS_NONBLESSED     => 0x00000040,
     EXPANDED          => 0x10000000, # for developer's
 };
 
 use constant UNSUPPORTED_DECODE_FLAG => {
     LOOSE             => 0x00000001,
     ALLOW_BIGNUM      => 0x00000002,
     ALLOW_BAREKEY     => 0x00000004,
     ALLOW_SINGLEQUOTE => 0x00000008,
     EXPANDED          => 0x20000000, # for developer's
 };
 
 
 sub init {
     local $^W;
     no strict qw(refs);
     *{"JSON::decode_json"} = \&{"JSON::XS::decode_json"};
     *{"JSON::encode_json"} = \&{"JSON::XS::encode_json"};
     *{"JSON::XS::is_xs"}  = sub { 1 };
     *{"JSON::XS::is_pp"}  = sub { 0 };
     return 1;
 }
 
 
 sub support_by_pp {
     my ($class, @methods) = @_;
 
     local $^W;
     no strict qw(refs);
 
     my $JSON_XS_encode_orignal     = \&JSON::XS::encode;
     my $JSON_XS_decode_orignal     = \&JSON::XS::decode;
     my $JSON_XS_incr_parse_orignal = \&JSON::XS::incr_parse;
 
     *JSON::XS::decode     = \&JSON::Backend::XS::Supportable::_decode;
     *JSON::XS::encode     = \&JSON::Backend::XS::Supportable::_encode;
     *JSON::XS::incr_parse = \&JSON::Backend::XS::Supportable::_incr_parse;
 
     *{JSON::XS::_original_decode}     = $JSON_XS_decode_orignal;
     *{JSON::XS::_original_encode}     = $JSON_XS_encode_orignal;
     *{JSON::XS::_original_incr_parse} = $JSON_XS_incr_parse_orignal;
 
     push @JSON::Backend::XS::Supportable::ISA, 'JSON';
 
     my $pkg = 'JSON::Backend::XS::Supportable';
 
     *{JSON::new} = sub {
         my $proto = JSON::XS->new; $$proto = 0;
         bless  $proto, $pkg;
     };
 
 
     for my $method (@methods) {
         my $flag = uc($method);
         my $type |= (UNSUPPORTED_ENCODE_FLAG->{$flag} || 0);
            $type |= (UNSUPPORTED_DECODE_FLAG->{$flag} || 0);
 
         next unless($type);
 
         $pkg->_make_unsupported_method($method => $type);
     }
 
 #    push @{"JSON::XS::Boolean::ISA"}, qw(JSON::PP::Boolean);
 #    push @{"JSON::PP::Boolean::ISA"}, qw(JSON::Boolean);
 
     $JSON::DEBUG and Carp::carp("set -support_by_pp mode.");
 
     return 1;
 }
 
 
 
 
 #
 # Helper classes for XS
 #
 
 package JSON::Backend::XS::Supportable;
 
 $Carp::Internal{'JSON::Backend::XS::Supportable'} = 1;
 
 sub _make_unsupported_method {
     my ($pkg, $method, $type) = @_;
 
     local $^W;
     no strict qw(refs);
 
     *{"$pkg\::$method"} = sub {
         local $^W;
         if (defined $_[1] ? $_[1] : 1) {
             ${$_[0]} |= $type;
         }
         else {
             ${$_[0]} &= ~$type;
         }
         $_[0];
     };
 
     *{"$pkg\::get_$method"} = sub {
         ${$_[0]} & $type ? 1 : '';
     };
 
 }
 
 
 sub _set_for_pp {
     JSON::_load_pp( $_INSTALL_ONLY );
 
     my $type  = shift;
     my $pp    = JSON::PP->new;
     my $prop = $_[0]->property;
 
     for my $name (keys %$prop) {
         $pp->$name( $prop->{$name} ? $prop->{$name} : 0 );
     }
 
     my $unsupported = $type eq 'encode' ? JSON::Backend::XS::UNSUPPORTED_ENCODE_FLAG
                                         : JSON::Backend::XS::UNSUPPORTED_DECODE_FLAG;
     my $flags       = ${$_[0]} || 0;
 
     for my $name (keys %$unsupported) {
         next if ($name eq 'EXPANDED'); # for developer's
         my $enable = ($flags & $unsupported->{$name}) ? 1 : 0;
         my $method = lc $name;
         $pp->$method($enable);
     }
 
     $pp->indent_length( $_[0]->get_indent_length );
 
     return $pp;
 }
 
 sub _encode { # using with PP encode
     if (${$_[0]}) {
         _set_for_pp('encode' => @_)->encode($_[1]);
     }
     else {
         $_[0]->_original_encode( $_[1] );
     }
 }
 
 
 sub _decode { # if unsupported-flag is set, use PP
     if (${$_[0]}) {
         _set_for_pp('decode' => @_)->decode($_[1]);
     }
     else {
         $_[0]->_original_decode( $_[1] );
     }
 }
 
 
 sub decode_prefix { # if unsupported-flag is set, use PP
     _set_for_pp('decode' => @_)->decode_prefix($_[1]);
 }
 
 
 sub _incr_parse {
     if (${$_[0]}) {
         _set_for_pp('decode' => @_)->incr_parse($_[1]);
     }
     else {
         $_[0]->_original_incr_parse( $_[1] );
     }
 }
 
 
 sub get_indent_length {
     ${$_[0]} << 4 >> 16;
 }
 
 
 sub indent_length {
     my $length = $_[1];
 
     if (!defined $length or $length > 15 or $length < 0) {
         Carp::carp "The acceptable range of indent_length() is 0 to 15.";
     }
     else {
         local $^W;
         $length <<= 12;
         ${$_[0]} &= ~ JSON::Backend::XS::INDENT_LENGTH_FLAG;
         ${$_[0]} |= $length;
         *JSON::XS::encode = \&JSON::Backend::XS::Supportable::_encode;
     }
 
     $_[0];
 }
 
 
 1;
 __END__
 
 =head1 NAME
 
 JSON - JSON (JavaScript Object Notation) encoder/decoder
 
 =head1 SYNOPSIS
 
  use JSON; # imports encode_json, decode_json, to_json and from_json.
  
  # simple and fast interfaces (expect/generate UTF-8)
  
  $utf8_encoded_json_text = encode_json $perl_hash_or_arrayref;
  $perl_hash_or_arrayref  = decode_json $utf8_encoded_json_text;
  
  # OO-interface
  
  $json = JSON->new->allow_nonref;
  
  $json_text   = $json->encode( $perl_scalar );
  $perl_scalar = $json->decode( $json_text );
  
  $pretty_printed = $json->pretty->encode( $perl_scalar ); # pretty-printing
  
  # If you want to use PP only support features, call with '-support_by_pp'
  # When XS unsupported feature is enable, using PP (de|en)code instead of XS ones.
  
  use JSON -support_by_pp;
  
  # option-acceptable interfaces (expect/generate UNICODE by default)
  
  $json_text   = to_json( $perl_scalar, { ascii => 1, pretty => 1 } );
  $perl_scalar = from_json( $json_text, { utf8  => 1 } );
  
  # Between (en|de)code_json and (to|from)_json, if you want to write
  # a code which communicates to an outer world (encoded in UTF-8),
  # recommend to use (en|de)code_json.
  
 =head1 VERSION
 
     2.90
 
 This version is compatible with JSON::XS B<2.34> and later.
 (Not yet compatble to JSON::XS B<3.0x>.)
 
 
 =head1 NOTE
 
 JSON::PP was earlier included in the C<JSON> distribution, but
 has since Perl 5.14 been a core module. For this reason,
 L<JSON::PP> was removed from the JSON distribution and can now
 be found also in the Perl5 repository at
 
 =over
 
 =item * L<http://perl5.git.perl.org/perl.git>
 
 =back
 
 (The newest JSON::PP version still exists in CPAN.)
 
 Instead, the C<JSON> distribution will include JSON::backportPP
 for backwards computability. JSON.pm should thus work as it did
 before.
 
 =head1 DESCRIPTION
 
  *************************** CAUTION **************************************
  *                                                                        *
  * INCOMPATIBLE CHANGE (JSON::XS version 2.90)                            *
  *                                                                        *
  * JSON.pm had patched JSON::XS::Boolean and JSON::PP::Boolean internally *
  * on loading time for making these modules inherit JSON::Boolean.        *
  * But since JSON::XS v3.0 it use Types::Serialiser as boolean class.     *
  * Then now JSON.pm breaks boolean classe overload features and           *
  * -support_by_pp if JSON::XS v3.0 or later is installed.                 *
  *                                                                        *
  * JSON::true and JSON::false returned JSON::Boolean objects.             *
  * For workaround, they return JSON::PP::Boolean objects in this version. *
  *                                                                        *
  *     isa_ok(JSON::true, 'JSON::PP::Boolean');                           *
  *                                                                        *
  * And it discards a feature:                                             *
  *                                                                        *
  *     ok(JSON::true eq 'true');                                          *
  *                                                                        *
  * In other word, JSON::PP::Boolean overload numeric only.                *
  *                                                                        *
  *     ok( JSON::true == 1 );                                             *
  *                                                                        *
  **************************************************************************
 
  ************************** CAUTION ********************************
  * This is 'JSON module version 2' and there are many differences  *
  * to version 1.xx                                                 *
  * Please check your applications using old version.              *
  *   See to 'INCOMPATIBLE CHANGES TO OLD VERSION'                  *
  *******************************************************************
 
 JSON (JavaScript Object Notation) is a simple data format.
 See to L<http://www.json.org/> and C<RFC4627>(L<http://www.ietf.org/rfc/rfc4627.txt>).
 
 This module converts Perl data structures to JSON and vice versa using either
 L<JSON::XS> or L<JSON::PP>.
 
 JSON::XS is the fastest and most proper JSON module on CPAN which must be
 compiled and installed in your environment.
 JSON::PP is a pure-Perl module which is bundled in this distribution and
 has a strong compatibility to JSON::XS.
 
 This module try to use JSON::XS by default and fail to it, use JSON::PP instead.
 So its features completely depend on JSON::XS or JSON::PP.
 
 See to L<BACKEND MODULE DECISION>.
 
 To distinguish the module name 'JSON' and the format type JSON,
 the former is quoted by CE<lt>E<gt> (its results vary with your using media),
 and the latter is left just as it is.
 
 Module name : C<JSON>
 
 Format type : JSON
 
 =head2 FEATURES
 
 =over
 
 =item * correct unicode handling
 
 This module (i.e. backend modules) knows how to handle Unicode, documents
 how and when it does so, and even documents what "correct" means.
 
 Even though there are limitations, this feature is available since Perl version 5.6.
 
 JSON::XS requires Perl 5.8.2 (but works correctly in 5.8.8 or later), so in older versions
 C<JSON> should call JSON::PP as the backend which can be used since Perl 5.005.
 
 With Perl 5.8.x JSON::PP works, but from 5.8.0 to 5.8.2, because of a Perl side problem,
 JSON::PP works slower in the versions. And in 5.005, the Unicode handling is not available.
 See to L<JSON::PP/UNICODE HANDLING ON PERLS> for more information.
 
 See also to L<JSON::XS/A FEW NOTES ON UNICODE AND PERL>
 and L<JSON::XS/ENCODING/CODESET_FLAG_NOTES>.
 
 
 =item * round-trip integrity
 
 When you serialise a perl data structure using only data types supported
 by JSON and Perl, the deserialised data structure is identical on the Perl
 level. (e.g. the string "2.0" doesn't suddenly become "2" just because
 it looks like a number). There I<are> minor exceptions to this, read the
 L</MAPPING> section below to learn about those.
 
 
 =item * strict checking of JSON correctness
 
 There is no guessing, no generating of illegal JSON texts by default,
 and only JSON is accepted as input by default (the latter is a security
 feature).
 
 See to L<JSON::XS/FEATURES> and L<JSON::PP/FEATURES>.
 
 =item * fast
 
 This module returns a JSON::XS object itself if available.
 Compared to other JSON modules and other serialisers such as Storable,
 JSON::XS usually compares favorably in terms of speed, too.
 
 If not available, C<JSON> returns a JSON::PP object instead of JSON::XS and
 it is very slow as pure-Perl.
 
 =item * simple to use
 
 This module has both a simple functional interface as well as an
 object oriented interface interface.
 
 =item * reasonably versatile output formats
 
 You can choose between the most compact guaranteed-single-line format possible
 (nice for simple line-based protocols), a pure-ASCII format (for when your transport
 is not 8-bit clean, still supports the whole Unicode range), or a pretty-printed
 format (for when you want to read that stuff). Or you can combine those features
 in whatever way you like.
 
 =back
 
 =head1 FUNCTIONAL INTERFACE
 
 Some documents are copied and modified from L<JSON::XS/FUNCTIONAL INTERFACE>.
 C<to_json> and C<from_json> are additional functions.
 
 =head2 encode_json
 
     $json_text = encode_json $perl_scalar
 
 Converts the given Perl data structure to a UTF-8 encoded, binary string.
 
 This function call is functionally identical to:
 
     $json_text = JSON->new->utf8->encode($perl_scalar)
 
 =head2 decode_json
 
     $perl_scalar = decode_json $json_text
 
 The opposite of C<encode_json>: expects an UTF-8 (binary) string and tries
 to parse that as an UTF-8 encoded JSON text, returning the resulting
 reference.
 
 This function call is functionally identical to:
 
     $perl_scalar = JSON->new->utf8->decode($json_text)
 
 
 =head2 to_json
 
    $json_text = to_json($perl_scalar)
 
 Converts the given Perl data structure to a json string.
 
 This function call is functionally identical to:
 
    $json_text = JSON->new->encode($perl_scalar)
 
 Takes a hash reference as the second.
 
    $json_text = to_json($perl_scalar, $flag_hashref)
 
 So,
 
    $json_text = to_json($perl_scalar, {utf8 => 1, pretty => 1})
 
 equivalent to:
 
    $json_text = JSON->new->utf8(1)->pretty(1)->encode($perl_scalar)
 
 If you want to write a modern perl code which communicates to outer world,
 you should use C<encode_json> (supposed that JSON data are encoded in UTF-8).
 
 =head2 from_json
 
    $perl_scalar = from_json($json_text)
 
 The opposite of C<to_json>: expects a json string and tries
 to parse it, returning the resulting reference.
 
 This function call is functionally identical to:
 
     $perl_scalar = JSON->decode($json_text)
 
 Takes a hash reference as the second.
 
     $perl_scalar = from_json($json_text, $flag_hashref)
 
 So,
 
     $perl_scalar = from_json($json_text, {utf8 => 1})
 
 equivalent to:
 
     $perl_scalar = JSON->new->utf8(1)->decode($json_text)
 
 If you want to write a modern perl code which communicates to outer world,
 you should use C<decode_json> (supposed that JSON data are encoded in UTF-8).
 
 =head2 JSON::is_bool
 
     $is_boolean = JSON::is_bool($scalar)
 
 Returns true if the passed scalar represents either JSON::true or
 JSON::false, two constants that act like C<1> and C<0> respectively
 and are also used to represent JSON C<true> and C<false> in Perl strings.
 
 =head2 JSON::true
 
 Returns JSON true value which is blessed object.
 It C<isa> JSON::Boolean object.
 
 =head2 JSON::false
 
 Returns JSON false value which is blessed object.
 It C<isa> JSON::Boolean object.
 
 =head2 JSON::null
 
 Returns C<undef>.
 
 See L<MAPPING>, below, for more information on how JSON values are mapped to
 Perl.
 
 =head1 HOW DO I DECODE A DATA FROM OUTER AND ENCODE TO OUTER
 
 This section supposes that your perl version is 5.8 or later.
 
 If you know a JSON text from an outer world - a network, a file content, and so on,
 is encoded in UTF-8, you should use C<decode_json> or C<JSON> module object
 with C<utf8> enable. And the decoded result will contain UNICODE characters.
 
   # from network
   my $json        = JSON->new->utf8;
   my $json_text   = CGI->new->param( 'json_data' );
   my $perl_scalar = $json->decode( $json_text );
   
   # from file content
   local $/;
   open( my $fh, '<', 'json.data' );
   $json_text   = <$fh>;
   $perl_scalar = decode_json( $json_text );
 
 If an outer data is not encoded in UTF-8, firstly you should C<decode> it.
 
   use Encode;
   local $/;
   open( my $fh, '<', 'json.data' );
   my $encoding = 'cp932';
   my $unicode_json_text = decode( $encoding, <$fh> ); # UNICODE
   
   # or you can write the below code.
   #
   # open( my $fh, "<:encoding($encoding)", 'json.data' );
   # $unicode_json_text = <$fh>;
 
 In this case, C<$unicode_json_text> is of course UNICODE string.
 So you B<cannot> use C<decode_json> nor C<JSON> module object with C<utf8> enable.
 Instead of them, you use C<JSON> module object with C<utf8> disable or C<from_json>.
 
   $perl_scalar = $json->utf8(0)->decode( $unicode_json_text );
   # or
   $perl_scalar = from_json( $unicode_json_text );
 
 Or C<encode 'utf8'> and C<decode_json>:
 
   $perl_scalar = decode_json( encode( 'utf8', $unicode_json_text ) );
   # this way is not efficient.
 
 And now, you want to convert your C<$perl_scalar> into JSON data and
 send it to an outer world - a network or a file content, and so on.
 
 Your data usually contains UNICODE strings and you want the converted data to be encoded
 in UTF-8, you should use C<encode_json> or C<JSON> module object with C<utf8> enable.
 
   print encode_json( $perl_scalar ); # to a network? file? or display?
   # or
   print $json->utf8->encode( $perl_scalar );
 
 If C<$perl_scalar> does not contain UNICODE but C<$encoding>-encoded strings
 for some reason, then its characters are regarded as B<latin1> for perl
 (because it does not concern with your $encoding).
 You B<cannot> use C<encode_json> nor C<JSON> module object with C<utf8> enable.
 Instead of them, you use C<JSON> module object with C<utf8> disable or C<to_json>.
 Note that the resulted text is a UNICODE string but no problem to print it.
 
   # $perl_scalar contains $encoding encoded string values
   $unicode_json_text = $json->utf8(0)->encode( $perl_scalar );
   # or 
   $unicode_json_text = to_json( $perl_scalar );
   # $unicode_json_text consists of characters less than 0x100
   print $unicode_json_text;
 
 Or C<decode $encoding> all string values and C<encode_json>:
 
   $perl_scalar->{ foo } = decode( $encoding, $perl_scalar->{ foo } );
   # ... do it to each string values, then encode_json
   $json_text = encode_json( $perl_scalar );
 
 This method is a proper way but probably not efficient.
 
 See to L<Encode>, L<perluniintro>.
 
 
 =head1 COMMON OBJECT-ORIENTED INTERFACE
 
 =head2 new
 
     $json = JSON->new
 
 Returns a new C<JSON> object inherited from either JSON::XS or JSON::PP
 that can be used to de/encode JSON strings.
 
 All boolean flags described below are by default I<disabled>.
 
 The mutators for flags all return the JSON object again and thus calls can
 be chained:
 
    my $json = JSON->new->utf8->space_after->encode({a => [1,2]})
    => {"a": [1, 2]}
 
 =head2 ascii
 
     $json = $json->ascii([$enable])
     
     $enabled = $json->get_ascii
 
 If $enable is true (or missing), then the encode method will not generate characters outside
 the code range 0..127. Any Unicode characters outside that range will be escaped using either
 a single \uXXXX or a double \uHHHH\uLLLLL escape sequence, as per RFC4627.
 
 If $enable is false, then the encode method will not escape Unicode characters unless
 required by the JSON syntax or other flags. This results in a faster and more compact format.
 
 This feature depends on the used Perl version and environment.
 
 See to L<JSON::PP/UNICODE HANDLING ON PERLS> if the backend is PP.
 
   JSON->new->ascii(1)->encode([chr 0x10401])
   => ["\ud801\udc01"]
 
 =head2 latin1
 
     $json = $json->latin1([$enable])
     
     $enabled = $json->get_latin1
 
 If $enable is true (or missing), then the encode method will encode the resulting JSON
 text as latin1 (or iso-8859-1), escaping any characters outside the code range 0..255.
 
 If $enable is false, then the encode method will not escape Unicode characters
 unless required by the JSON syntax or other flags.
 
   JSON->new->latin1->encode (["\x{89}\x{abc}"]
   => ["\x{89}\\u0abc"]    # (perl syntax, U+abc escaped, U+89 not)
 
 =head2 utf8
 
     $json = $json->utf8([$enable])
     
     $enabled = $json->get_utf8
 
 If $enable is true (or missing), then the encode method will encode the JSON result
 into UTF-8, as required by many protocols, while the decode method expects to be handled
 an UTF-8-encoded string. Please note that UTF-8-encoded strings do not contain any
 characters outside the range 0..255, they are thus useful for bytewise/binary I/O.
 
 In future versions, enabling this option might enable autodetection of the UTF-16 and UTF-32
 encoding families, as described in RFC4627.
 
 If $enable is false, then the encode method will return the JSON string as a (non-encoded)
 Unicode string, while decode expects thus a Unicode string. Any decoding or encoding
 (e.g. to UTF-8 or UTF-16) needs to be done yourself, e.g. using the Encode module.
 
 
 Example, output UTF-16BE-encoded JSON:
 
   use Encode;
   $jsontext = encode "UTF-16BE", JSON::XS->new->encode ($object);
 
 Example, decode UTF-32LE-encoded JSON:
 
   use Encode;
   $object = JSON::XS->new->decode (decode "UTF-32LE", $jsontext);
 
 See to L<JSON::PP/UNICODE HANDLING ON PERLS> if the backend is PP.
 
 
 =head2 pretty
 
     $json = $json->pretty([$enable])
 
 This enables (or disables) all of the C<indent>, C<space_before> and
 C<space_after> (and in the future possibly more) flags in one call to
 generate the most readable (or most compact) form possible.
 
 Equivalent to:
 
    $json->indent->space_before->space_after
 
 The indent space length is three and JSON::XS cannot change the indent
 space length.
 
 =head2 indent
 
     $json = $json->indent([$enable])
     
     $enabled = $json->get_indent
 
 If C<$enable> is true (or missing), then the C<encode> method will use a multiline
 format as output, putting every array member or object/hash key-value pair
 into its own line, identifying them properly.
 
 If C<$enable> is false, no newlines or indenting will be produced, and the
 resulting JSON text is guaranteed not to contain any C<newlines>.
 
 This setting has no effect when decoding JSON texts.
 
 The indent space length is three.
 With JSON::PP, you can also access C<indent_length> to change indent space length.
 
 
 =head2 space_before
 
     $json = $json->space_before([$enable])
     
     $enabled = $json->get_space_before
 
 If C<$enable> is true (or missing), then the C<encode> method will add an extra
 optional space before the C<:> separating keys from values in JSON objects.
 
 If C<$enable> is false, then the C<encode> method will not add any extra
 space at those places.
 
 This setting has no effect when decoding JSON texts.
 
 Example, space_before enabled, space_after and indent disabled:
 
    {"key" :"value"}
 
 
 =head2 space_after
 
     $json = $json->space_after([$enable])
     
     $enabled = $json->get_space_after
 
 If C<$enable> is true (or missing), then the C<encode> method will add an extra
 optional space after the C<:> separating keys from values in JSON objects
 and extra whitespace after the C<,> separating key-value pairs and array
 members.
 
 If C<$enable> is false, then the C<encode> method will not add any extra
 space at those places.
 
 This setting has no effect when decoding JSON texts.
 
 Example, space_before and indent disabled, space_after enabled:
 
    {"key": "value"}
 
 
 =head2 relaxed
 
     $json = $json->relaxed([$enable])
     
     $enabled = $json->get_relaxed
 
 If C<$enable> is true (or missing), then C<decode> will accept some
 extensions to normal JSON syntax (see below). C<encode> will not be
 affected in anyway. I<Be aware that this option makes you accept invalid
 JSON texts as if they were valid!>. I suggest only to use this option to
 parse application-specific files written by humans (configuration files,
 resource files etc.)
 
 If C<$enable> is false (the default), then C<decode> will only accept
 valid JSON texts.
 
 Currently accepted extensions are:
 
 =over 4
 
 =item * list items can have an end-comma
 
 JSON I<separates> array elements and key-value pairs with commas. This
 can be annoying if you write JSON texts manually and want to be able to
 quickly append elements, so this extension accepts comma at the end of
 such items not just between them:
 
    [
       1,
       2, <- this comma not normally allowed
    ]
    {
       "k1": "v1",
       "k2": "v2", <- this comma not normally allowed
    }
 
 =item * shell-style '#'-comments
 
 Whenever JSON allows whitespace, shell-style comments are additionally
 allowed. They are terminated by the first carriage-return or line-feed
 character, after which more white-space and comments are allowed.
 
   [
      1, # this comment not allowed in JSON
         # neither this one...
   ]
 
 =back
 
 
 =head2 canonical
 
     $json = $json->canonical([$enable])
     
     $enabled = $json->get_canonical
 
 If C<$enable> is true (or missing), then the C<encode> method will output JSON objects
 by sorting their keys. This is adding a comparatively high overhead.
 
 If C<$enable> is false, then the C<encode> method will output key-value
 pairs in the order Perl stores them (which will likely change between runs
 of the same script).
 
 This option is useful if you want the same data structure to be encoded as
 the same JSON text (given the same overall settings). If it is disabled,
 the same hash might be encoded differently even if contains the same data,
 as key-value pairs have no inherent ordering in Perl.
 
 This setting has no effect when decoding JSON texts.
 
 =head2 allow_nonref
 
     $json = $json->allow_nonref([$enable])
     
     $enabled = $json->get_allow_nonref
 
 If C<$enable> is true (or missing), then the C<encode> method can convert a
 non-reference into its corresponding string, number or null JSON value,
 which is an extension to RFC4627. Likewise, C<decode> will accept those JSON
 values instead of croaking.
 
 If C<$enable> is false, then the C<encode> method will croak if it isn't
 passed an arrayref or hashref, as JSON texts must either be an object
 or array. Likewise, C<decode> will croak if given something that is not a
 JSON object or array.
 
    JSON->new->allow_nonref->encode ("Hello, World!")
    => "Hello, World!"
 
 =head2 allow_unknown
 
     $json = $json->allow_unknown ([$enable])
     
     $enabled = $json->get_allow_unknown
 
 If $enable is true (or missing), then "encode" will *not* throw an
 exception when it encounters values it cannot represent in JSON (for
 example, filehandles) but instead will encode a JSON "null" value.
 Note that blessed objects are not included here and are handled
 separately by c<allow_nonref>.
 
 If $enable is false (the default), then "encode" will throw an
 exception when it encounters anything it cannot encode as JSON.
 
 This option does not affect "decode" in any way, and it is
 recommended to leave it off unless you know your communications
 partner.
 
 =head2 allow_blessed
 
     $json = $json->allow_blessed([$enable])
     
     $enabled = $json->get_allow_blessed
 
 If C<$enable> is true (or missing), then the C<encode> method will not
 barf when it encounters a blessed reference. Instead, the value of the
 B<convert_blessed> option will decide whether C<null> (C<convert_blessed>
 disabled or no C<TO_JSON> method found) or a representation of the
 object (C<convert_blessed> enabled and C<TO_JSON> method found) is being
 encoded. Has no effect on C<decode>.
 
 If C<$enable> is false (the default), then C<encode> will throw an
 exception when it encounters a blessed object.
 
 
 =head2 convert_blessed
 
     $json = $json->convert_blessed([$enable])
     
     $enabled = $json->get_convert_blessed
 
 If C<$enable> is true (or missing), then C<encode>, upon encountering a
 blessed object, will check for the availability of the C<TO_JSON> method
 on the object's class. If found, it will be called in scalar context
 and the resulting scalar will be encoded instead of the object. If no
 C<TO_JSON> method is found, the value of C<allow_blessed> will decide what
 to do.
 
 The C<TO_JSON> method may safely call die if it wants. If C<TO_JSON>
 returns other blessed objects, those will be handled in the same
 way. C<TO_JSON> must take care of not causing an endless recursion cycle
 (== crash) in this case. The name of C<TO_JSON> was chosen because other
 methods called by the Perl core (== not by the user of the object) are
 usually in upper case letters and to avoid collisions with the C<to_json>
 function or method.
 
 This setting does not yet influence C<decode> in any way.
 
 If C<$enable> is false, then the C<allow_blessed> setting will decide what
 to do when a blessed object is found.
 
 =over
 
 =item convert_blessed_universally mode
 
 If use C<JSON> with C<-convert_blessed_universally>, the C<UNIVERSAL::TO_JSON>
 subroutine is defined as the below code:
 
    *UNIVERSAL::TO_JSON = sub {
        my $b_obj = B::svref_2object( $_[0] );
        return    $b_obj->isa('B::HV') ? { %{ $_[0] } }
                : $b_obj->isa('B::AV') ? [ @{ $_[0] } ]
                : undef
                ;
    }
 
 This will cause that C<encode> method converts simple blessed objects into
 JSON objects as non-blessed object.
 
    JSON -convert_blessed_universally;
    $json->allow_blessed->convert_blessed->encode( $blessed_object )
 
 This feature is experimental and may be removed in the future.
 
 =back
 
 =head2 filter_json_object
 
     $json = $json->filter_json_object([$coderef])
 
 When C<$coderef> is specified, it will be called from C<decode> each
 time it decodes a JSON object. The only argument passed to the coderef
 is a reference to the newly-created hash. If the code references returns
 a single scalar (which need not be a reference), this value
 (i.e. a copy of that scalar to avoid aliasing) is inserted into the
 deserialised data structure. If it returns an empty list
 (NOTE: I<not> C<undef>, which is a valid scalar), the original deserialised
 hash will be inserted. This setting can slow down decoding considerably.
 
 When C<$coderef> is omitted or undefined, any existing callback will
 be removed and C<decode> will not change the deserialised hash in any
 way.
 
 Example, convert all JSON objects into the integer 5:
 
    my $js = JSON->new->filter_json_object (sub { 5 });
    # returns [5]
    $js->decode ('[{}]'); # the given subroutine takes a hash reference.
    # throw an exception because allow_nonref is not enabled
    # so a lone 5 is not allowed.
    $js->decode ('{"a":1, "b":2}');
 
 
 =head2 filter_json_single_key_object
 
     $json = $json->filter_json_single_key_object($key [=> $coderef])
 
 Works remotely similar to C<filter_json_object>, but is only called for
 JSON objects having a single key named C<$key>.
 
 This C<$coderef> is called before the one specified via
 C<filter_json_object>, if any. It gets passed the single value in the JSON
 object. If it returns a single value, it will be inserted into the data
 structure. If it returns nothing (not even C<undef> but the empty list),
 the callback from C<filter_json_object> will be called next, as if no
 single-key callback were specified.
 
 If C<$coderef> is omitted or undefined, the corresponding callback will be
 disabled. There can only ever be one callback for a given key.
 
 As this callback gets called less often then the C<filter_json_object>
 one, decoding speed will not usually suffer as much. Therefore, single-key
 objects make excellent targets to serialise Perl objects into, especially
 as single-key JSON objects are as close to the type-tagged value concept
 as JSON gets (it's basically an ID/VALUE tuple). Of course, JSON does not
 support this in any way, so you need to make sure your data never looks
 like a serialised Perl hash.
 
 Typical names for the single object key are C<__class_whatever__>, or
 C<$__dollars_are_rarely_used__$> or C<}ugly_brace_placement>, or even
 things like C<__class_md5sum(classname)__>, to reduce the risk of clashing
 with real hashes.
 
 Example, decode JSON objects of the form C<< { "__widget__" => <id> } >>
 into the corresponding C<< $WIDGET{<id>} >> object:
 
    # return whatever is in $WIDGET{5}:
    JSON
       ->new
       ->filter_json_single_key_object (__widget__ => sub {
             $WIDGET{ $_[0] }
          })
       ->decode ('{"__widget__": 5')
 
    # this can be used with a TO_JSON method in some "widget" class
    # for serialisation to json:
    sub WidgetBase::TO_JSON {
       my ($self) = @_;
 
       unless ($self->{id}) {
          $self->{id} = ..get..some..id..;
          $WIDGET{$self->{id}} = $self;
       }
 
       { __widget__ => $self->{id} }
    }
 
 
 =head2 shrink
 
     $json = $json->shrink([$enable])
     
     $enabled = $json->get_shrink
 
 With JSON::XS, this flag resizes strings generated by either
 C<encode> or C<decode> to their minimum size possible. This can save
 memory when your JSON texts are either very very long or you have many
 short strings. It will also try to downgrade any strings to octet-form
 if possible: perl stores strings internally either in an encoding called
 UTF-X or in octet-form. The latter cannot store everything but uses less
 space in general (and some buggy Perl or C code might even rely on that
 internal representation being used).
 
 With JSON::PP, it is noop about resizing strings but tries
 C<utf8::downgrade> to the returned string by C<encode>. See to L<utf8>.
 
 See to L<JSON::XS/OBJECT-ORIENTED INTERFACE> and L<JSON::PP/METHODS>.
 
 =head2 max_depth
 
     $json = $json->max_depth([$maximum_nesting_depth])
     
     $max_depth = $json->get_max_depth
 
 Sets the maximum nesting level (default C<512>) accepted while encoding
 or decoding. If a higher nesting level is detected in JSON text or a Perl
 data structure, then the encoder and decoder will stop and croak at that
 point.
 
 Nesting level is defined by number of hash- or arrayrefs that the encoder
 needs to traverse to reach a given point or the number of C<{> or C<[>
 characters without their matching closing parenthesis crossed to reach a
 given character in a string.
 
 If no argument is given, the highest possible setting will be used, which
 is rarely useful.
 
 Note that nesting is implemented by recursion in C. The default value has
 been chosen to be as large as typical operating systems allow without
 crashing. (JSON::XS)
 
 With JSON::PP as the backend, when a large value (100 or more) was set and
 it de/encodes a deep nested object/text, it may raise a warning
 'Deep recursion on subroutine' at the perl runtime phase.
 
 See L<JSON::XS/SECURITY CONSIDERATIONS> for more info on why this is useful.
 
 =head2 max_size
 
     $json = $json->max_size([$maximum_string_size])
     
     $max_size = $json->get_max_size
 
 Set the maximum length a JSON text may have (in bytes) where decoding is
 being attempted. The default is C<0>, meaning no limit. When C<decode>
 is called on a string that is longer then this many bytes, it will not
 attempt to decode the string but throw an exception. This setting has no
 effect on C<encode> (yet).
 
 If no argument is given, the limit check will be deactivated (same as when
 C<0> is specified).
 
 See L<JSON::XS/SECURITY CONSIDERATIONS>, below, for more info on why this is useful.
 
 =head2 encode
 
     $json_text = $json->encode($perl_scalar)
 
 Converts the given Perl data structure (a simple scalar or a reference
 to a hash or array) to its JSON representation. Simple scalars will be
 converted into JSON string or number sequences, while references to arrays
 become JSON arrays and references to hashes become JSON objects. Undefined
 Perl values (e.g. C<undef>) become JSON C<null> values.
 References to the integers C<0> and C<1> are converted into C<true> and C<false>.
 
 =head2 decode
 
     $perl_scalar = $json->decode($json_text)
 
 The opposite of C<encode>: expects a JSON text and tries to parse it,
 returning the resulting simple scalar or reference. Croaks on error.
 
 JSON numbers and strings become simple Perl scalars. JSON arrays become
 Perl arrayrefs and JSON objects become Perl hashrefs. C<true> becomes
 C<1> (C<JSON::true>), C<false> becomes C<0> (C<JSON::false>) and
 C<null> becomes C<undef>.
 
 =head2 decode_prefix
 
     ($perl_scalar, $characters) = $json->decode_prefix($json_text)
 
 This works like the C<decode> method, but instead of raising an exception
 when there is trailing garbage after the first JSON object, it will
 silently stop parsing there and return the number of characters consumed
 so far.
 
    JSON->new->decode_prefix ("[1] the tail")
    => ([], 3)
 
 See to L<JSON::XS/OBJECT-ORIENTED INTERFACE>
 
 =head2 property
 
     $boolean = $json->property($property_name)
 
 Returns a boolean value about above some properties.
 
 The available properties are C<ascii>, C<latin1>, C<utf8>,
 C<indent>,C<space_before>, C<space_after>, C<relaxed>, C<canonical>,
 C<allow_nonref>, C<allow_unknown>, C<allow_blessed>, C<convert_blessed>,
 C<shrink>, C<max_depth> and C<max_size>.
 
    $boolean = $json->property('utf8');
     => 0
    $json->utf8;
    $boolean = $json->property('utf8');
     => 1
 
 Sets the property with a given boolean value.
 
     $json = $json->property($property_name => $boolean);
 
 With no argument, it returns all the above properties as a hash reference.
 
     $flag_hashref = $json->property();
 
 =head1 INCREMENTAL PARSING
 
 Most of this section are copied and modified from L<JSON::XS/INCREMENTAL PARSING>.
 
 In some cases, there is the need for incremental parsing of JSON texts.
 This module does allow you to parse a JSON stream incrementally.
 It does so by accumulating text until it has a full JSON object, which
 it then can decode. This process is similar to using C<decode_prefix>
 to see if a full JSON object is available, but is much more efficient
 (and can be implemented with a minimum of method calls).
 
 The backend module will only attempt to parse the JSON text once it is sure it
 has enough text to get a decisive result, using a very simple but
 truly incremental parser. This means that it sometimes won't stop as
 early as the full parser, for example, it doesn't detect parenthesis
 mismatches. The only thing it guarantees is that it starts decoding as
 soon as a syntactically valid JSON text has been seen. This means you need
 to set resource limits (e.g. C<max_size>) to ensure the parser will stop
 parsing in the presence if syntax errors.
 
 The following methods implement this incremental parser.
 
 =head2 incr_parse
 
     $json->incr_parse( [$string] ) # void context
     
     $obj_or_undef = $json->incr_parse( [$string] ) # scalar context
     
     @obj_or_empty = $json->incr_parse( [$string] ) # list context
 
 This is the central parsing function. It can both append new text and
 extract objects from the stream accumulated so far (both of these
 functions are optional).
 
 If C<$string> is given, then this string is appended to the already
 existing JSON fragment stored in the C<$json> object.
 
 After that, if the function is called in void context, it will simply
 return without doing anything further. This can be used to add more text
 in as many chunks as you want.
 
 If the method is called in scalar context, then it will try to extract
 exactly I<one> JSON object. If that is successful, it will return this
 object, otherwise it will return C<undef>. If there is a parse error,
 this method will croak just as C<decode> would do (one can then use
 C<incr_skip> to skip the erroneous part). This is the most common way of
 using the method.
 
 And finally, in list context, it will try to extract as many objects
 from the stream as it can find and return them, or the empty list
 otherwise. For this to work, there must be no separators between the JSON
 objects or arrays, instead they must be concatenated back-to-back. If
 an error occurs, an exception will be raised as in the scalar context
 case. Note that in this case, any previously-parsed JSON texts will be
 lost.
 
 Example: Parse some JSON arrays/objects in a given string and return them.
 
     my @objs = JSON->new->incr_parse ("[5][7][1,2]");
 
 =head2 incr_text
 
     $lvalue_string = $json->incr_text
 
 This method returns the currently stored JSON fragment as an lvalue, that
 is, you can manipulate it. This I<only> works when a preceding call to
 C<incr_parse> in I<scalar context> successfully returned an object. Under
 all other circumstances you must not call this function (I mean it.
 although in simple tests it might actually work, it I<will> fail under
 real world conditions). As a special exception, you can also call this
 method before having parsed anything.
 
 This function is useful in two cases: a) finding the trailing text after a
 JSON object or b) parsing multiple JSON objects separated by non-JSON text
 (such as commas).
 
     $json->incr_text =~ s/\s*,\s*//;
 
 In Perl 5.005, C<lvalue> attribute is not available.
 You must write codes like the below:
 
     $string = $json->incr_text;
     $string =~ s/\s*,\s*//;
     $json->incr_text( $string );
 
 =head2 incr_skip
 
     $json->incr_skip
 
 This will reset the state of the incremental parser and will remove the
 parsed text from the input buffer. This is useful after C<incr_parse>
 died, in which case the input buffer and incremental parser state is left
 unchanged, to skip the text parsed so far and to reset the parse state.
 
 =head2 incr_reset
 
     $json->incr_reset
 
 This completely resets the incremental parser, that is, after this call,
 it will be as if the parser had never parsed anything.
 
 This is useful if you want to repeatedly parse JSON objects and want to
 ignore any trailing data, which means you have to reset the parser after
 each successful decode.
 
 See to L<JSON::XS/INCREMENTAL PARSING> for examples.
 
 
 =head1 JSON::PP SUPPORT METHODS
 
 The below methods are JSON::PP own methods, so when C<JSON> works
 with JSON::PP (i.e. the created object is a JSON::PP object), available.
 See to L<JSON::PP/JSON::PP OWN METHODS> in detail.
 
 If you use C<JSON> with additional C<-support_by_pp>, some methods
 are available even with JSON::XS. See to L<USE PP FEATURES EVEN THOUGH XS BACKEND>.
 
    BEING { $ENV{PERL_JSON_BACKEND} = 'JSON::XS' }
    
    use JSON -support_by_pp;
    
    my $json = JSON->new;
    $json->allow_nonref->escape_slash->encode("/");
 
    # functional interfaces too.
    print to_json(["/"], {escape_slash => 1});
    print from_json('["foo"]', {utf8 => 1});
 
 If you do not want to all functions but C<-support_by_pp>,
 use C<-no_export>.
 
    use JSON -support_by_pp, -no_export;
    # functional interfaces are not exported.
 
 =head2 allow_singlequote
 
     $json = $json->allow_singlequote([$enable])
 
 If C<$enable> is true (or missing), then C<decode> will accept
 any JSON strings quoted by single quotations that are invalid JSON
 format.
 
     $json->allow_singlequote->decode({"foo":'bar'});
     $json->allow_singlequote->decode({'foo':"bar"});
     $json->allow_singlequote->decode({'foo':'bar'});
 
 As same as the C<relaxed> option, this option may be used to parse
 application-specific files written by humans.
 
 =head2 allow_barekey
 
     $json = $json->allow_barekey([$enable])
 
 If C<$enable> is true (or missing), then C<decode> will accept
 bare keys of JSON object that are invalid JSON format.
 
 As same as the C<relaxed> option, this option may be used to parse
 application-specific files written by humans.
 
     $json->allow_barekey->decode('{foo:"bar"}');
 
 =head2 allow_bignum
 
     $json = $json->allow_bignum([$enable])
 
 If C<$enable> is true (or missing), then C<decode> will convert
 the big integer Perl cannot handle as integer into a L<Math::BigInt>
 object and convert a floating number (any) into a L<Math::BigFloat>.
 
 On the contrary, C<encode> converts C<Math::BigInt> objects and C<Math::BigFloat>
 objects into JSON numbers with C<allow_blessed> enable.
 
    $json->allow_nonref->allow_blessed->allow_bignum;
    $bigfloat = $json->decode('2.000000000000000000000000001');
    print $json->encode($bigfloat);
    # => 2.000000000000000000000000001
 
 See to L<MAPPING> about the conversion of JSON number.
 
 =head2 loose
 
     $json = $json->loose([$enable])
 
 The unescaped [\x00-\x1f\x22\x2f\x5c] strings are invalid in JSON strings
 and the module doesn't allow to C<decode> to these (except for \x2f).
 If C<$enable> is true (or missing), then C<decode>  will accept these
 unescaped strings.
 
     $json->loose->decode(qq|["abc
                                    def"]|);
 
 See to L<JSON::PP/JSON::PP OWN METHODS>.
 
 =head2 escape_slash
 
     $json = $json->escape_slash([$enable])
 
 According to JSON Grammar, I<slash> (U+002F) is escaped. But by default
 JSON backend modules encode strings without escaping slash.
 
 If C<$enable> is true (or missing), then C<encode> will escape slashes.
 
 =head2 indent_length
 
     $json = $json->indent_length($length)
 
 With JSON::XS, The indent space length is 3 and cannot be changed.
 With JSON::PP, it sets the indent space length with the given $length.
 The default is 3. The acceptable range is 0 to 15.
 
 =head2 sort_by
 
     $json = $json->sort_by($function_name)
     $json = $json->sort_by($subroutine_ref)
 
 If $function_name or $subroutine_ref are set, its sort routine are used.
 
    $js = $pc->sort_by(sub { $JSON::PP::a cmp $JSON::PP::b })->encode($obj);
    # is($js, q|{"a":1,"b":2,"c":3,"d":4,"e":5,"f":6,"g":7,"h":8,"i":9}|);
 
    $js = $pc->sort_by('own_sort')->encode($obj);
    # is($js, q|{"a":1,"b":2,"c":3,"d":4,"e":5,"f":6,"g":7,"h":8,"i":9}|);
 
    sub JSON::PP::own_sort { $JSON::PP::a cmp $JSON::PP::b }
 
 As the sorting routine runs in the JSON::PP scope, the given
 subroutine name and the special variables C<$a>, C<$b> will begin
 with 'JSON::PP::'.
 
 If $integer is set, then the effect is same as C<canonical> on.
 
 See to L<JSON::PP/JSON::PP OWN METHODS>.
 
 =head1 MAPPING
 
 This section is copied from JSON::XS and modified to C<JSON>.
 JSON::XS and JSON::PP mapping mechanisms are almost equivalent.
 
 See to L<JSON::XS/MAPPING>.
 
 =head2 JSON -> PERL
 
 =over 4
 
 =item object
 
 A JSON object becomes a reference to a hash in Perl. No ordering of object
 keys is preserved (JSON does not preserver object key ordering itself).
 
 =item array
 
 A JSON array becomes a reference to an array in Perl.
 
 =item string
 
 A JSON string becomes a string scalar in Perl - Unicode codepoints in JSON
 are represented by the same codepoints in the Perl string, so no manual
 decoding is necessary.
 
 =item number
 
 A JSON number becomes either an integer, numeric (floating point) or
 string scalar in perl, depending on its range and any fractional parts. On
 the Perl level, there is no difference between those as Perl handles all
 the conversion details, but an integer may take slightly less memory and
 might represent more values exactly than floating point numbers.
 
 If the number consists of digits only, C<JSON> will try to represent
 it as an integer value. If that fails, it will try to represent it as
 a numeric (floating point) value if that is possible without loss of
 precision. Otherwise it will preserve the number as a string value (in
 which case you lose roundtripping ability, as the JSON number will be
 re-encoded to a JSON string).
 
 Numbers containing a fractional or exponential part will always be
 represented as numeric (floating point) values, possibly at a loss of
 precision (in which case you might lose perfect roundtripping ability, but
 the JSON number will still be re-encoded as a JSON number).
 
 Note that precision is not accuracy - binary floating point values cannot
 represent most decimal fractions exactly, and when converting from and to
 floating point, C<JSON> only guarantees precision up to but not including
 the least significant bit.
 
 If the backend is JSON::PP and C<allow_bignum> is enable, the big integers 
 and the numeric can be optionally converted into L<Math::BigInt> and
 L<Math::BigFloat> objects.
 
 =item true, false
 
 These JSON atoms become C<JSON::true> and C<JSON::false>,
 respectively. They are overloaded to act almost exactly like the numbers
 C<1> and C<0>. You can check whether a scalar is a JSON boolean by using
 the C<JSON::is_bool> function.
 
    print JSON::true + 1;
     => 1
 
    ok(JSON::true eq  '1');
    ok(JSON::true == 1);
 
 C<JSON> will install these missing overloading features to the backend modules.
 
 
 =item null
 
 A JSON null atom becomes C<undef> in Perl.
 
 C<JSON::null> returns C<undef>.
 
 =back
 
 
 =head2 PERL -> JSON
 
 The mapping from Perl to JSON is slightly more difficult, as Perl is a
 truly typeless language, so we can only guess which JSON type is meant by
 a Perl value.
 
 =over 4
 
 =item hash references
 
 Perl hash references become JSON objects. As there is no inherent ordering
 in hash keys (or JSON objects), they will usually be encoded in a
 pseudo-random order that can change between runs of the same program but
 stays generally the same within a single run of a program. C<JSON>
 optionally sort the hash keys (determined by the I<canonical> flag), so
 the same data structure will serialise to the same JSON text (given same
 settings and version of JSON::XS), but this incurs a runtime overhead
 and is only rarely useful, e.g. when you want to compare some JSON text
 against another for equality.
 
 In future, the ordered object feature will be added to JSON::PP using C<tie> mechanism.
 
 
 =item array references
 
 Perl array references become JSON arrays.
 
 =item other references
 
 Other unblessed references are generally not allowed and will cause an
 exception to be thrown, except for references to the integers C<0> and
 C<1>, which get turned into C<false> and C<true> atoms in JSON. You can
 also use C<JSON::false> and C<JSON::true> to improve readability.
 
    to_json [\0,JSON::true]      # yields [false,true]
 
 =item JSON::true, JSON::false, JSON::null
 
 These special values become JSON true and JSON false values,
 respectively. You can also use C<\1> and C<\0> directly if you want.
 
 JSON::null returns C<undef>.
 
 =item blessed objects
 
 Blessed objects are not directly representable in JSON. See the
 C<allow_blessed> and C<convert_blessed> methods on various options on
 how to deal with this: basically, you can choose between throwing an
 exception, encoding the reference as if it weren't blessed, or provide
 your own serialiser method.
 
 With C<convert_blessed_universally> mode,  C<encode> converts blessed
 hash references or blessed array references (contains other blessed references)
 into JSON members and arrays.
 
    use JSON -convert_blessed_universally;
    JSON->new->allow_blessed->convert_blessed->encode( $blessed_object );
 
 See to L<convert_blessed>.
 
 =item simple scalars
 
 Simple Perl scalars (any scalar that is not a reference) are the most
 difficult objects to encode: JSON::XS and JSON::PP will encode undefined scalars as
 JSON C<null> values, scalars that have last been used in a string context
 before encoding as JSON strings, and anything else as number value:
 
    # dump as number
    encode_json [2]                      # yields [2]
    encode_json [-3.0e17]                # yields [-3e+17]
    my $value = 5; encode_json [$value]  # yields [5]
 
    # used as string, so dump as string
    print $value;
    encode_json [$value]                 # yields ["5"]
 
    # undef becomes null
    encode_json [undef]                  # yields [null]
 
 You can force the type to be a string by stringifying it:
 
    my $x = 3.1; # some variable containing a number
    "$x";        # stringified
    $x .= "";    # another, more awkward way to stringify
    print $x;    # perl does it for you, too, quite often
 
 You can force the type to be a number by numifying it:
 
    my $x = "3"; # some variable containing a string
    $x += 0;     # numify it, ensuring it will be dumped as a number
    $x *= 1;     # same thing, the choice is yours.
 
 You can not currently force the type in other, less obscure, ways.
 
 Note that numerical precision has the same meaning as under Perl (so
 binary to decimal conversion follows the same rules as in Perl, which
 can differ to other languages). Also, your perl interpreter might expose
 extensions to the floating point numbers of your platform, such as
 infinities or NaN's - these cannot be represented in JSON, and it is an
 error to pass those in.
 
 =item Big Number
 
 If the backend is JSON::PP and C<allow_bignum> is enable, 
 C<encode> converts C<Math::BigInt> objects and C<Math::BigFloat>
 objects into JSON numbers.
 
 
 =back
 
 =head1 JSON and ECMAscript
 
 See to L<JSON::XS/JSON and ECMAscript>.
 
 =head1 JSON and YAML
 
 JSON is not a subset of YAML.
 See to L<JSON::XS/JSON and YAML>.
 
 
 =head1 BACKEND MODULE DECISION
 
 When you use C<JSON>, C<JSON> tries to C<use> JSON::XS. If this call failed, it will
 C<uses> JSON::PP. The required JSON::XS version is I<2.2> or later.
 
 The C<JSON> constructor method returns an object inherited from the backend module,
 and JSON::XS object is a blessed scalar reference while JSON::PP is a blessed hash
 reference.
 
 So, your program should not depend on the backend module, especially
 returned objects should not be modified.
 
  my $json = JSON->new; # XS or PP?
  $json->{stash} = 'this is xs object'; # this code may raise an error!
 
 To check the backend module, there are some methods - C<backend>, C<is_pp> and C<is_xs>.
 
   JSON->backend; # 'JSON::XS' or 'JSON::PP'
   
   JSON->backend->is_pp: # 0 or 1
   
   JSON->backend->is_xs: # 1 or 0
   
   $json->is_xs; # 1 or 0
   
   $json->is_pp; # 0 or 1
 
 
 If you set an environment variable C<PERL_JSON_BACKEND>, the calling action will be changed.
 
 =over
 
 =item PERL_JSON_BACKEND = 0 or PERL_JSON_BACKEND = 'JSON::PP'
 
 Always use JSON::PP
 
 =item PERL_JSON_BACKEND == 1 or PERL_JSON_BACKEND = 'JSON::XS,JSON::PP'
 
 (The default) Use compiled JSON::XS if it is properly compiled & installed,
 otherwise use JSON::PP.
 
 =item PERL_JSON_BACKEND == 2 or PERL_JSON_BACKEND = 'JSON::XS'
 
 Always use compiled JSON::XS, die if it isn't properly compiled & installed.
 
 =item PERL_JSON_BACKEND = 'JSON::backportPP'
 
 Always use JSON::backportPP.
 JSON::backportPP is JSON::PP back port module.
 C<JSON> includes JSON::backportPP instead of JSON::PP.
 
 =back
 
 These ideas come from L<DBI::PurePerl> mechanism.
 
 example:
 
  BEGIN { $ENV{PERL_JSON_BACKEND} = 'JSON::PP' }
  use JSON; # always uses JSON::PP
 
 In future, it may be able to specify another module.
 
 =head1 USE PP FEATURES EVEN THOUGH XS BACKEND
 
 Many methods are available with either JSON::XS or JSON::PP and
 when the backend module is JSON::XS, if any JSON::PP specific (i.e. JSON::XS unsupported)
 method is called, it will C<warn> and be noop.
 
 But If you C<use> C<JSON> passing the optional string C<-support_by_pp>,
 it makes a part of those unsupported methods available.
 This feature is achieved by using JSON::PP in C<de/encode>.
 
    BEGIN { $ENV{PERL_JSON_BACKEND} = 2 } # with JSON::XS
    use JSON -support_by_pp;
    my $json = JSON->new;
    $json->allow_nonref->escape_slash->encode("/");
 
 At this time, the returned object is a C<JSON::Backend::XS::Supportable>
 object (re-blessed XS object), and  by checking JSON::XS unsupported flags
 in de/encoding, can support some unsupported methods - C<loose>, C<allow_bignum>,
 C<allow_barekey>, C<allow_singlequote>, C<escape_slash> and C<indent_length>.
 
 When any unsupported methods are not enable, C<XS de/encode> will be
 used as is. The switch is achieved by changing the symbolic tables.
 
 C<-support_by_pp> is effective only when the backend module is JSON::XS
 and it makes the de/encoding speed down a bit.
 
 See to L<JSON::PP SUPPORT METHODS>.
 
 =head1 INCOMPATIBLE CHANGES TO OLD VERSION
 
 There are big incompatibility between new version (2.00) and old (1.xx).
 If you use old C<JSON> 1.xx in your code, please check it.
 
 See to L<Transition ways from 1.xx to 2.xx.>
 
 =over
 
 =item jsonToObj and objToJson are obsoleted.
 
 Non Perl-style name C<jsonToObj> and C<objToJson> are obsoleted
 (but not yet deleted from the source).
 If you use these functions in your code, please replace them
 with C<from_json> and C<to_json>.
 
 
 =item Global variables are no longer available.
 
 C<JSON> class variables - C<$JSON::AUTOCONVERT>, C<$JSON::BareKey>, etc...
 - are not available any longer.
 Instead, various features can be used through object methods.
 
 
 =item Package JSON::Converter and JSON::Parser are deleted.
 
 Now C<JSON> bundles with JSON::PP which can handle JSON more properly than them.
 
 =item Package JSON::NotString is deleted.
 
 There was C<JSON::NotString> class which represents JSON value C<true>, C<false>, C<null>
 and numbers. It was deleted and replaced by C<JSON::Boolean>.
 
 C<JSON::Boolean> represents C<true> and C<false>.
 
 C<JSON::Boolean> does not represent C<null>.
 
 C<JSON::null> returns C<undef>.
 
 C<JSON> makes L<JSON::XS::Boolean> and L<JSON::PP::Boolean> is-a relation
 to L<JSON::Boolean>.
 
 =item function JSON::Number is obsoleted.
 
 C<JSON::Number> is now needless because JSON::XS and JSON::PP have
 round-trip integrity.
 
 =item JSONRPC modules are deleted.
 
 Perl implementation of JSON-RPC protocol - C<JSONRPC >, C<JSONRPC::Transport::HTTP>
 and C<Apache::JSONRPC > are deleted in this distribution.
 Instead of them, there is L<JSON::RPC> which supports JSON-RPC protocol version 1.1.
 
 =back
 
 =head2 Transition ways from 1.xx to 2.xx.
 
 You should set C<suport_by_pp> mode firstly, because
 it is always successful for the below codes even with JSON::XS.
 
     use JSON -support_by_pp;
 
 =over
 
 =item Exported jsonToObj (simple)
 
   from_json($json_text);
 
 =item Exported objToJson (simple)
 
   to_json($perl_scalar);
 
 =item Exported jsonToObj (advanced)
 
   $flags = {allow_barekey => 1, allow_singlequote => 1};
   from_json($json_text, $flags);
 
 equivalent to:
 
   $JSON::BareKey = 1;
   $JSON::QuotApos = 1;
   jsonToObj($json_text);
 
 =item Exported objToJson (advanced)
 
   $flags = {allow_blessed => 1, allow_barekey => 1};
   to_json($perl_scalar, $flags);
 
 equivalent to:
 
   $JSON::BareKey = 1;
   objToJson($perl_scalar);
 
 =item jsonToObj as object method
 
   $json->decode($json_text);
 
 =item objToJson as object method
 
   $json->encode($perl_scalar);
 
 =item new method with parameters
 
 The C<new> method in 2.x takes any parameters no longer.
 You can set parameters instead;
 
    $json = JSON->new->pretty;
 
 =item $JSON::Pretty, $JSON::Indent, $JSON::Delimiter
 
 If C<indent> is enable, that means C<$JSON::Pretty> flag set. And
 C<$JSON::Delimiter> was substituted by C<space_before> and C<space_after>.
 In conclusion:
 
    $json->indent->space_before->space_after;
 
 Equivalent to:
 
   $json->pretty;
 
 To change indent length, use C<indent_length>.
 
 (Only with JSON::PP, if C<-support_by_pp> is not used.)
 
   $json->pretty->indent_length(2)->encode($perl_scalar);
 
 =item $JSON::BareKey
 
 (Only with JSON::PP, if C<-support_by_pp> is not used.)
 
   $json->allow_barekey->decode($json_text)
 
 =item $JSON::ConvBlessed
 
 use C<-convert_blessed_universally>. See to L<convert_blessed>.
 
 =item $JSON::QuotApos
 
 (Only with JSON::PP, if C<-support_by_pp> is not used.)
 
   $json->allow_singlequote->decode($json_text)
 
 =item $JSON::SingleQuote
 
 Disable. C<JSON> does not make such a invalid JSON string any longer.
 
 =item $JSON::KeySort
 
   $json->canonical->encode($perl_scalar)
 
 This is the ascii sort.
 
 If you want to use with your own sort routine, check the C<sort_by> method.
 
 (Only with JSON::PP, even if C<-support_by_pp> is used currently.)
 
   $json->sort_by($sort_routine_ref)->encode($perl_scalar)
  
   $json->sort_by(sub { $JSON::PP::a <=> $JSON::PP::b })->encode($perl_scalar)
 
 Can't access C<$a> and C<$b> but C<$JSON::PP::a> and C<$JSON::PP::b>.
 
 =item $JSON::SkipInvalid
 
   $json->allow_unknown
 
 =item $JSON::AUTOCONVERT
 
 Needless. C<JSON> backend modules have the round-trip integrity.
 
 =item $JSON::UTF8
 
 Needless because C<JSON> (JSON::XS/JSON::PP) sets
 the UTF8 flag on properly.
 
     # With UTF8-flagged strings
 
     $json->allow_nonref;
     $str = chr(1000); # UTF8-flagged
 
     $json_text  = $json->utf8(0)->encode($str);
     utf8::is_utf8($json_text);
     # true
     $json_text  = $json->utf8(1)->encode($str);
     utf8::is_utf8($json_text);
     # false
 
     $str = '"' . chr(1000) . '"'; # UTF8-flagged
 
     $perl_scalar  = $json->utf8(0)->decode($str);
     utf8::is_utf8($perl_scalar);
     # true
     $perl_scalar  = $json->utf8(1)->decode($str);
     # died because of 'Wide character in subroutine'
 
 See to L<JSON::XS/A FEW NOTES ON UNICODE AND PERL>.
 
 =item $JSON::UnMapping
 
 Disable. See to L<MAPPING>.
 
 =item $JSON::SelfConvert
 
 This option was deleted.
 Instead of it, if a given blessed object has the C<TO_JSON> method,
 C<TO_JSON> will be executed with C<convert_blessed>.
 
   $json->convert_blessed->encode($blessed_hashref_or_arrayref)
   # if need, call allow_blessed
 
 Note that it was C<toJson> in old version, but now not C<toJson> but C<TO_JSON>.
 
 =back
 
 =head1 TODO
 
 =over
 
 =item example programs
 
 =back
 
 =head1 THREADS
 
 No test with JSON::PP. If with JSON::XS, See to L<JSON::XS/THREADS>.
 
 
 =head1 BUGS
 
 Please report bugs relevant to C<JSON> to E<lt>makamaka[at]cpan.orgE<gt>.
 
 
 =head1 SEE ALSO
 
 Most of the document is copied and modified from JSON::XS doc.
 
 L<JSON::XS>, L<JSON::PP>
 
 C<RFC4627>(L<http://www.ietf.org/rfc/rfc4627.txt>)
 
 =head1 AUTHOR
 
 Makamaka Hannyaharamitu, E<lt>makamaka[at]cpan.orgE<gt>
 
 JSON::XS was written by  Marc Lehmann <schmorp[at]schmorp.de>
 
 The release of this new version owes to the courtesy of Marc Lehmann.
 
 
 =head1 COPYRIGHT AND LICENSE
 
 Copyright 2005-2013 by Makamaka Hannyaharamitu
 
 This library is free software; you can redistribute it and/or modify
 it under the same terms as Perl itself. 
 
 =cut
 
### JSON/Color.pm ###
 package JSON::Color;
 
 use 5.010001;
 use strict;
 use warnings;
 
 our $sul_available = eval { require Scalar::Util::LooksLikeNumber; 1 } ? 1:0;
 use Term::ANSIColor qw(:constants);
 
 # PUSHCOLOR and LOCALCOLOR cannot be used, they are functions, not escape codes
 
 require Exporter;
 our @ISA       = qw(Exporter);
 our @EXPORT_OK = qw(encode_json);
 
 our $VERSION = '0.08'; # VERSION
 
 our %theme = (
     start_quote         => BOLD . BRIGHT_GREEN,
     end_quote           => RESET,
     start_string        => GREEN,
     end_string          => RESET,
     start_string_escape => BOLD,
     end_string_escape   => RESET . GREEN, # back to string
     start_number        => BOLD . BRIGHT_MAGENTA,
     end_number          => RESET,
     start_bool          => CYAN,
     end_bool            => RESET,
     start_null          => CYAN,
     end_null            => RESET,
     start_object_key    => MAGENTA,
     end_object_key      => RESET,
     start_object_key_escape => BOLD,
     end_object_key_escape   => RESET . MAGENTA, # back to object key
     start_linum         => REVERSE . WHITE,
     end_linum           => RESET,
 );
 
 my %esc = (
     "\n" => '\n',
     "\r" => '\r',
     "\t" => '\t',
     "\f" => '\f',
     "\b" => '\b',
     "\"" => '\"',
     "\\" => '\\\\',
     "\'" => '\\\'',
 );
 sub _string {
     my ($value, $opts) = @_;
 
     my ($sq, $eq, $ss, $es, $sse, $ese);
     if ($opts->{obj_key}) {
         $sq  = $theme{start_object_key};
         $eq  = $theme{end_object_key};
         $ss  = $theme{start_object_key};
         $es  = $theme{end_object_key};
         $sse = $theme{start_object_key_escape};
         $ese = $theme{end_object_key_escape};
     } else {
         $sq  = $theme{start_quote};
         $eq  = $theme{end_quote};
         $ss  = $theme{start_string};
         $es  = $theme{end_string};
         $sse = $theme{start_string_escape};
         $ese = $theme{end_string_escape};
     }
 
     $value =~ s/([\x22\x5c\n\r\t\f\b])|([\x00-\x08\x0b\x0e-\x1f])/
         join("",
              $sse,
              $1 ? $esc{$1} : '\\u00' . unpack('H2', $2),
              $ese,
          )
             /eg;
 
     return join(
         "",
         $sq, '"', $eq,
         $ss, $value, $es,
         $sq, '"', $eq,
     );
 }
 
 sub _number {
     my ($value, $opts) = @_;
 
     return join(
         "",
         $theme{start_number}, $value, $theme{end_number},
     );
 }
 
 sub _null {
     my ($value, $opts) = @_;
 
     return join(
         "",
         $theme{start_null}, "null", $theme{end_null},
     );
 }
 
 sub _bool {
     my ($value, $opts) = @_;
 
     return join(
         "",
         $theme{start_bool}, "$value", $theme{end_bool},
     );
 }
 
 sub _array {
     my ($value, $opts) = @_;
 
     return "[]" unless @$value;
     my $indent  = $opts->{pretty} ? "   " x  $opts->{_indent}    : "";
     my $indent2 = $opts->{pretty} ? "   " x ($opts->{_indent}+1) : "";
     my $nl      = $opts->{pretty} ? "\n" : "";
     local $opts->{_indent} = $opts->{_indent}+1;
     return join(
         "",
         "[$nl",
         (map {
             $indent2,
             _encode($value->[$_], $opts),
             $_ == @$value-1 ? $nl : ",$nl",
         } 0..@$value-1),
         $indent, "]",
     );
 }
 
 sub _hash {
     my ($value, $opts) = @_;
 
     return "{}" unless keys %$value;
     my $indent  = $opts->{pretty} ? "   " x  $opts->{_indent}    : "";
     my $indent2 = $opts->{pretty} ? "   " x ($opts->{_indent}+1) : "";
     my $nl      = $opts->{pretty} ? "\n" : "";
     my $colon   = $opts->{pretty} ? ": " : ":";
     my @res;
 
     push @res, "{$nl";
     my @k = sort keys(%$value);
     local $opts->{_indent} = $opts->{_indent}+1;
     for (0..@k-1) {
         my $k = $k[$_];
         push @res, (
             $indent2,
             _string($k, {obj_key=>1}),
             $colon,
             _encode($value->{$k}, $opts),
             $_ == @k-1 ? $nl : ",$nl",
         );
     }
     push @res, $indent, "}";
     join "", @res;
 }
 
 sub _encode {
     my ($data, $opts) = @_;
 
     my $ref = ref($data);
 
     if (!defined($data)) {
         return _null($data, $opts);
     } elsif ($ref eq 'ARRAY') {
         return _array($data, $opts);
     } elsif ($ref eq 'HASH') {
         return _hash($data, $opts);
     } elsif ($ref eq 'JSON::XS::Boolean' || $ref eq 'JSON::PP::Boolean') {
         return _bool($data, $opts);
     } elsif (!$ref) {
         if ($sul_available &&
                 Scalar::Util::LooksLikeNumber::looks_like_number($data) =~
                   /^(4|12|4352|8704)$/o) {
             return _number($data, $opts);
         } else {
             return _string($data, $opts);
         }
     } else {
         die "Can't encode $data";
     }
 }
 
 sub encode_json {
     my ($value, $opts) = @_;
     $opts //= {};
     $opts->{_indent} //= 0;
     my $res = _encode($value , $opts);
 
     if ($opts->{linum}) {
         my $lines = 0;
         $lines++ while $res =~ /^/mog;
         my $fmt = "%".length($lines)."d";
         my $i = 0;
         $res =~ s/^/
             $theme{start_linum} . sprintf($fmt, ++$i) . $theme{end_linum}
                 /meg;
     }
     $res;
 }
 
 1;
 # ABSTRACT: Encode to colored JSON
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 JSON::Color - Encode to colored JSON
 
 =head1 VERSION
 
 This document describes version 0.08 of JSON::Color (from Perl distribution JSON-Color), released on 2015-10-20.
 
 =head1 SYNOPSIS
 
  use JSON::Color qw(encode_json);
  say encode_json([1, "two", {three => 4}]);
 
 =head1 DESCRIPTION
 
 This module generates JSON, colorized with ANSI escape sequences.
 
 To change the color, see the C<%theme> in the source code. In theory you can
 also modify it to colorize using HTML.
 
 =head1 FUNCTIONS
 
 =head2 encode_json($data, \%opts) => STR
 
 Encode to JSON. Will die on error (e.g. when encountering non-encodeable data
 like Regexp or file handle).
 
 Known options:
 
 =over
 
 =item * pretty => BOOL (default: 0)
 
 Pretty-print.
 
 =item * linum => BOOL (default: 0)
 
 Show line number.
 
 =back
 
 =head1 FAQ
 
 =head2 What about loading?
 
 Use L<JSON>.
 
 =head2 How to handle non-encodeable data?
 
 Use L<Data::Clean::JSON>.
 
 =head1 SEE ALSO
 
 To colorize with HTML, you can try L<Syntax::Highlight::JSON>.
 
 L<Syntax::SourceHighlight> can also colorize JSON/JavaScript to HTML or ANSI
 escape. It requires the GNU Source-highlight library.
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/JSON-Color>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-JSON-Color>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=JSON-Color>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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
### JSON/PP.pm ###
 package JSON::PP;
 
 # JSON-2.0
 
 use 5.005;
 use strict;
 use base qw(Exporter);
 use overload ();
 
 use Carp ();
 use B ();
 #use Devel::Peek;
 
 $JSON::PP::VERSION = '2.27300';
 
 @JSON::PP::EXPORT = qw(encode_json decode_json from_json to_json);
 
 # instead of hash-access, i tried index-access for speed.
 # but this method is not faster than what i expected. so it will be changed.
 
 use constant P_ASCII                => 0;
 use constant P_LATIN1               => 1;
 use constant P_UTF8                 => 2;
 use constant P_INDENT               => 3;
 use constant P_CANONICAL            => 4;
 use constant P_SPACE_BEFORE         => 5;
 use constant P_SPACE_AFTER          => 6;
 use constant P_ALLOW_NONREF         => 7;
 use constant P_SHRINK               => 8;
 use constant P_ALLOW_BLESSED        => 9;
 use constant P_CONVERT_BLESSED      => 10;
 use constant P_RELAXED              => 11;
 
 use constant P_LOOSE                => 12;
 use constant P_ALLOW_BIGNUM         => 13;
 use constant P_ALLOW_BAREKEY        => 14;
 use constant P_ALLOW_SINGLEQUOTE    => 15;
 use constant P_ESCAPE_SLASH         => 16;
 use constant P_AS_NONBLESSED        => 17;
 
 use constant P_ALLOW_UNKNOWN        => 18;
 
 use constant OLD_PERL => $] < 5.008 ? 1 : 0;
 
 BEGIN {
     my @xs_compati_bit_properties = qw(
             latin1 ascii utf8 indent canonical space_before space_after allow_nonref shrink
             allow_blessed convert_blessed relaxed allow_unknown
     );
     my @pp_bit_properties = qw(
             allow_singlequote allow_bignum loose
             allow_barekey escape_slash as_nonblessed
     );
 
     # Perl version check, Unicode handling is enable?
     # Helper module sets @JSON::PP::_properties.
     if ($] < 5.008 ) {
         my $helper = $] >= 5.006 ? 'JSON::PP::Compat5006' : 'JSON::PP::Compat5005';
         eval qq| require $helper |;
         if ($@) { Carp::croak $@; }
     }
 
     for my $name (@xs_compati_bit_properties, @pp_bit_properties) {
         my $flag_name = 'P_' . uc($name);
 
         eval qq/
             sub $name {
                 my \$enable = defined \$_[1] ? \$_[1] : 1;
 
                 if (\$enable) {
                     \$_[0]->{PROPS}->[$flag_name] = 1;
                 }
                 else {
                     \$_[0]->{PROPS}->[$flag_name] = 0;
                 }
 
                 \$_[0];
             }
 
             sub get_$name {
                 \$_[0]->{PROPS}->[$flag_name] ? 1 : '';
             }
         /;
     }
 
 }
 
 
 
 # Functions
 
 my %encode_allow_method
      = map {($_ => 1)} qw/utf8 pretty allow_nonref latin1 self_encode escape_slash
                           allow_blessed convert_blessed indent indent_length allow_bignum
                           as_nonblessed
                         /;
 my %decode_allow_method
      = map {($_ => 1)} qw/utf8 allow_nonref loose allow_singlequote allow_bignum
                           allow_barekey max_size relaxed/;
 
 
 my $JSON; # cache
 
 sub encode_json ($) { # encode
     ($JSON ||= __PACKAGE__->new->utf8)->encode(@_);
 }
 
 
 sub decode_json { # decode
     ($JSON ||= __PACKAGE__->new->utf8)->decode(@_);
 }
 
 # Obsoleted
 
 sub to_json($) {
    Carp::croak ("JSON::PP::to_json has been renamed to encode_json.");
 }
 
 
 sub from_json($) {
    Carp::croak ("JSON::PP::from_json has been renamed to decode_json.");
 }
 
 
 # Methods
 
 sub new {
     my $class = shift;
     my $self  = {
         max_depth   => 512,
         max_size    => 0,
         indent      => 0,
         FLAGS       => 0,
         fallback      => sub { encode_error('Invalid value. JSON can only reference.') },
         indent_length => 3,
     };
 
     bless $self, $class;
 }
 
 
 sub encode {
     return $_[0]->PP_encode_json($_[1]);
 }
 
 
 sub decode {
     return $_[0]->PP_decode_json($_[1], 0x00000000);
 }
 
 
 sub decode_prefix {
     return $_[0]->PP_decode_json($_[1], 0x00000001);
 }
 
 
 # accessor
 
 
 # pretty printing
 
 sub pretty {
     my ($self, $v) = @_;
     my $enable = defined $v ? $v : 1;
 
     if ($enable) { # indent_length(3) for JSON::XS compatibility
         $self->indent(1)->indent_length(3)->space_before(1)->space_after(1);
     }
     else {
         $self->indent(0)->space_before(0)->space_after(0);
     }
 
     $self;
 }
 
 # etc
 
 sub max_depth {
     my $max  = defined $_[1] ? $_[1] : 0x80000000;
     $_[0]->{max_depth} = $max;
     $_[0];
 }
 
 
 sub get_max_depth { $_[0]->{max_depth}; }
 
 
 sub max_size {
     my $max  = defined $_[1] ? $_[1] : 0;
     $_[0]->{max_size} = $max;
     $_[0];
 }
 
 
 sub get_max_size { $_[0]->{max_size}; }
 
 
 sub filter_json_object {
     $_[0]->{cb_object} = defined $_[1] ? $_[1] : 0;
     $_[0]->{F_HOOK} = ($_[0]->{cb_object} or $_[0]->{cb_sk_object}) ? 1 : 0;
     $_[0];
 }
 
 sub filter_json_single_key_object {
     if (@_ > 1) {
         $_[0]->{cb_sk_object}->{$_[1]} = $_[2];
     }
     $_[0]->{F_HOOK} = ($_[0]->{cb_object} or $_[0]->{cb_sk_object}) ? 1 : 0;
     $_[0];
 }
 
 sub indent_length {
     if (!defined $_[1] or $_[1] > 15 or $_[1] < 0) {
         Carp::carp "The acceptable range of indent_length() is 0 to 15.";
     }
     else {
         $_[0]->{indent_length} = $_[1];
     }
     $_[0];
 }
 
 sub get_indent_length {
     $_[0]->{indent_length};
 }
 
 sub sort_by {
     $_[0]->{sort_by} = defined $_[1] ? $_[1] : 1;
     $_[0];
 }
 
 sub allow_bigint {
     Carp::carp("allow_bigint() is obsoleted. use allow_bignum() insted.");
 }
 
 ###############################
 
 ###
 ### Perl => JSON
 ###
 
 
 { # Convert
 
     my $max_depth;
     my $indent;
     my $ascii;
     my $latin1;
     my $utf8;
     my $space_before;
     my $space_after;
     my $canonical;
     my $allow_blessed;
     my $convert_blessed;
 
     my $indent_length;
     my $escape_slash;
     my $bignum;
     my $as_nonblessed;
 
     my $depth;
     my $indent_count;
     my $keysort;
 
 
     sub PP_encode_json {
         my $self = shift;
         my $obj  = shift;
 
         $indent_count = 0;
         $depth        = 0;
 
         my $idx = $self->{PROPS};
 
         ($ascii, $latin1, $utf8, $indent, $canonical, $space_before, $space_after, $allow_blessed,
             $convert_blessed, $escape_slash, $bignum, $as_nonblessed)
          = @{$idx}[P_ASCII .. P_SPACE_AFTER, P_ALLOW_BLESSED, P_CONVERT_BLESSED,
                     P_ESCAPE_SLASH, P_ALLOW_BIGNUM, P_AS_NONBLESSED];
 
         ($max_depth, $indent_length) = @{$self}{qw/max_depth indent_length/};
 
         $keysort = $canonical ? sub { $a cmp $b } : undef;
 
         if ($self->{sort_by}) {
             $keysort = ref($self->{sort_by}) eq 'CODE' ? $self->{sort_by}
                      : $self->{sort_by} =~ /\D+/       ? $self->{sort_by}
                      : sub { $a cmp $b };
         }
 
         encode_error("hash- or arrayref expected (not a simple scalar, use allow_nonref to allow this)")
              if(!ref $obj and !$idx->[ P_ALLOW_NONREF ]);
 
         my $str  = $self->object_to_json($obj);
 
         $str .= "\n" if ( $indent ); # JSON::XS 2.26 compatible
 
         unless ($ascii or $latin1 or $utf8) {
             utf8::upgrade($str);
         }
 
         if ($idx->[ P_SHRINK ]) {
             utf8::downgrade($str, 1);
         }
 
         return $str;
     }
 
 
     sub object_to_json {
         my ($self, $obj) = @_;
         my $type = ref($obj);
 
         if($type eq 'HASH'){
             return $self->hash_to_json($obj);
         }
         elsif($type eq 'ARRAY'){
             return $self->array_to_json($obj);
         }
         elsif ($type) { # blessed object?
             if (blessed($obj)) {
 
                 return $self->value_to_json($obj) if ( $obj->isa('JSON::PP::Boolean') );
 
                 if ( $convert_blessed and $obj->can('TO_JSON') ) {
                     my $result = $obj->TO_JSON();
                     if ( defined $result and ref( $result ) ) {
                         if ( refaddr( $obj ) eq refaddr( $result ) ) {
                             encode_error( sprintf(
                                 "%s::TO_JSON method returned same object as was passed instead of a new one",
                                 ref $obj
                             ) );
                         }
                     }
 
                     return $self->object_to_json( $result );
                 }
 
                 return "$obj" if ( $bignum and _is_bignum($obj) );
                 return $self->blessed_to_json($obj) if ($allow_blessed and $as_nonblessed); # will be removed.
 
                 encode_error( sprintf("encountered object '%s', but neither allow_blessed "
                     . "nor convert_blessed settings are enabled", $obj)
                 ) unless ($allow_blessed);
 
                 return 'null';
             }
             else {
                 return $self->value_to_json($obj);
             }
         }
         else{
             return $self->value_to_json($obj);
         }
     }
 
 
     sub hash_to_json {
         my ($self, $obj) = @_;
         my @res;
 
         encode_error("json text or perl structure exceeds maximum nesting level (max_depth set too low?)")
                                          if (++$depth > $max_depth);
 
         my ($pre, $post) = $indent ? $self->_up_indent() : ('', '');
         my $del = ($space_before ? ' ' : '') . ':' . ($space_after ? ' ' : '');
 
         for my $k ( _sort( $obj ) ) {
             if ( OLD_PERL ) { utf8::decode($k) } # key for Perl 5.6 / be optimized
             push @res, string_to_json( $self, $k )
                           .  $del
                           . ( $self->object_to_json( $obj->{$k} ) || $self->value_to_json( $obj->{$k} ) );
         }
 
         --$depth;
         $self->_down_indent() if ($indent);
 
         return   '{' . ( @res ? $pre : '' ) . ( @res ? join( ",$pre", @res ) . $post : '' )  . '}';
     }
 
 
     sub array_to_json {
         my ($self, $obj) = @_;
         my @res;
 
         encode_error("json text or perl structure exceeds maximum nesting level (max_depth set too low?)")
                                          if (++$depth > $max_depth);
 
         my ($pre, $post) = $indent ? $self->_up_indent() : ('', '');
 
         for my $v (@$obj){
             push @res, $self->object_to_json($v) || $self->value_to_json($v);
         }
 
         --$depth;
         $self->_down_indent() if ($indent);
 
         return '[' . ( @res ? $pre : '' ) . ( @res ? join( ",$pre", @res ) . $post : '' ) . ']';
     }
 
 
     sub value_to_json {
         my ($self, $value) = @_;
 
         return 'null' if(!defined $value);
 
         my $b_obj = B::svref_2object(\$value);  # for round trip problem
         my $flags = $b_obj->FLAGS;
 
         return $value # as is 
             if $flags & ( B::SVp_IOK | B::SVp_NOK ) and !( $flags & B::SVp_POK ); # SvTYPE is IV or NV?
 
         my $type = ref($value);
 
         if(!$type){
             return string_to_json($self, $value);
         }
         elsif( blessed($value) and  $value->isa('JSON::PP::Boolean') ){
             return $$value == 1 ? 'true' : 'false';
         }
         elsif ($type) {
             if ((overload::StrVal($value) =~ /=(\w+)/)[0]) {
                 return $self->value_to_json("$value");
             }
 
             if ($type eq 'SCALAR' and defined $$value) {
                 return   $$value eq '1' ? 'true'
                        : $$value eq '0' ? 'false'
                        : $self->{PROPS}->[ P_ALLOW_UNKNOWN ] ? 'null'
                        : encode_error("cannot encode reference to scalar");
             }
 
              if ( $self->{PROPS}->[ P_ALLOW_UNKNOWN ] ) {
                  return 'null';
              }
              else {
                  if ( $type eq 'SCALAR' or $type eq 'REF' ) {
                     encode_error("cannot encode reference to scalar");
                  }
                  else {
                     encode_error("encountered $value, but JSON can only represent references to arrays or hashes");
                  }
              }
 
         }
         else {
             return $self->{fallback}->($value)
                  if ($self->{fallback} and ref($self->{fallback}) eq 'CODE');
             return 'null';
         }
 
     }
 
 
     my %esc = (
         "\n" => '\n',
         "\r" => '\r',
         "\t" => '\t',
         "\f" => '\f',
         "\b" => '\b',
         "\"" => '\"',
         "\\" => '\\\\',
         "\'" => '\\\'',
     );
 
 
     sub string_to_json {
         my ($self, $arg) = @_;
 
         $arg =~ s/([\x22\x5c\n\r\t\f\b])/$esc{$1}/g;
         $arg =~ s/\//\\\//g if ($escape_slash);
         $arg =~ s/([\x00-\x08\x0b\x0e-\x1f])/'\\u00' . unpack('H2', $1)/eg;
 
         if ($ascii) {
             $arg = JSON_PP_encode_ascii($arg);
         }
 
         if ($latin1) {
             $arg = JSON_PP_encode_latin1($arg);
         }
 
         if ($utf8) {
             utf8::encode($arg);
         }
 
         return '"' . $arg . '"';
     }
 
 
     sub blessed_to_json {
         my $reftype = reftype($_[1]) || '';
         if ($reftype eq 'HASH') {
             return $_[0]->hash_to_json($_[1]);
         }
         elsif ($reftype eq 'ARRAY') {
             return $_[0]->array_to_json($_[1]);
         }
         else {
             return 'null';
         }
     }
 
 
     sub encode_error {
         my $error  = shift;
         Carp::croak "$error";
     }
 
 
     sub _sort {
         defined $keysort ? (sort $keysort (keys %{$_[0]})) : keys %{$_[0]};
     }
 
 
     sub _up_indent {
         my $self  = shift;
         my $space = ' ' x $indent_length;
 
         my ($pre,$post) = ('','');
 
         $post = "\n" . $space x $indent_count;
 
         $indent_count++;
 
         $pre = "\n" . $space x $indent_count;
 
         return ($pre,$post);
     }
 
 
     sub _down_indent { $indent_count--; }
 
 
     sub PP_encode_box {
         {
             depth        => $depth,
             indent_count => $indent_count,
         };
     }
 
 } # Convert
 
 
 sub _encode_ascii {
     join('',
         map {
             $_ <= 127 ?
                 chr($_) :
             $_ <= 65535 ?
                 sprintf('\u%04x', $_) : sprintf('\u%x\u%x', _encode_surrogates($_));
         } unpack('U*', $_[0])
     );
 }
 
 
 sub _encode_latin1 {
     join('',
         map {
             $_ <= 255 ?
                 chr($_) :
             $_ <= 65535 ?
                 sprintf('\u%04x', $_) : sprintf('\u%x\u%x', _encode_surrogates($_));
         } unpack('U*', $_[0])
     );
 }
 
 
 sub _encode_surrogates { # from perlunicode
     my $uni = $_[0] - 0x10000;
     return ($uni / 0x400 + 0xD800, $uni % 0x400 + 0xDC00);
 }
 
 
 sub _is_bignum {
     $_[0]->isa('Math::BigInt') or $_[0]->isa('Math::BigFloat');
 }
 
 
 
 #
 # JSON => Perl
 #
 
 my $max_intsize;
 
 BEGIN {
     my $checkint = 1111;
     for my $d (5..64) {
         $checkint .= 1;
         my $int   = eval qq| $checkint |;
         if ($int =~ /[eE]/) {
             $max_intsize = $d - 1;
             last;
         }
     }
 }
 
 { # PARSE 
 
     my %escapes = ( #  by Jeremy Muhlich <jmuhlich [at] bitflood.org>
         b    => "\x8",
         t    => "\x9",
         n    => "\xA",
         f    => "\xC",
         r    => "\xD",
         '\\' => '\\',
         '"'  => '"',
         '/'  => '/',
     );
 
     my $text; # json data
     my $at;   # offset
     my $ch;   # 1chracter
     my $len;  # text length (changed according to UTF8 or NON UTF8)
     # INTERNAL
     my $depth;          # nest counter
     my $encoding;       # json text encoding
     my $is_valid_utf8;  # temp variable
     my $utf8_len;       # utf8 byte length
     # FLAGS
     my $utf8;           # must be utf8
     my $max_depth;      # max nest nubmer of objects and arrays
     my $max_size;
     my $relaxed;
     my $cb_object;
     my $cb_sk_object;
 
     my $F_HOOK;
 
     my $allow_bigint;   # using Math::BigInt
     my $singlequote;    # loosely quoting
     my $loose;          # 
     my $allow_barekey;  # bareKey
 
     # $opt flag
     # 0x00000001 .... decode_prefix
     # 0x10000000 .... incr_parse
 
     sub PP_decode_json {
         my ($self, $opt); # $opt is an effective flag during this decode_json.
 
         ($self, $text, $opt) = @_;
 
         ($at, $ch, $depth) = (0, '', 0);
 
         if ( !defined $text or ref $text ) {
             decode_error("malformed JSON string, neither array, object, number, string or atom");
         }
 
         my $idx = $self->{PROPS};
 
         ($utf8, $relaxed, $loose, $allow_bigint, $allow_barekey, $singlequote)
             = @{$idx}[P_UTF8, P_RELAXED, P_LOOSE .. P_ALLOW_SINGLEQUOTE];
 
         if ( $utf8 ) {
             utf8::downgrade( $text, 1 ) or Carp::croak("Wide character in subroutine entry");
         }
         else {
             utf8::upgrade( $text );
             utf8::encode( $text );
         }
 
         $len = length $text;
 
         ($max_depth, $max_size, $cb_object, $cb_sk_object, $F_HOOK)
              = @{$self}{qw/max_depth  max_size cb_object cb_sk_object F_HOOK/};
 
         if ($max_size > 1) {
             use bytes;
             my $bytes = length $text;
             decode_error(
                 sprintf("attempted decode of JSON text of %s bytes size, but max_size is set to %s"
                     , $bytes, $max_size), 1
             ) if ($bytes > $max_size);
         }
 
         # Currently no effect
         # should use regexp
         my @octets = unpack('C4', $text);
         $encoding =   ( $octets[0] and  $octets[1]) ? 'UTF-8'
                     : (!$octets[0] and  $octets[1]) ? 'UTF-16BE'
                     : (!$octets[0] and !$octets[1]) ? 'UTF-32BE'
                     : ( $octets[2]                ) ? 'UTF-16LE'
                     : (!$octets[2]                ) ? 'UTF-32LE'
                     : 'unknown';
 
         white(); # remove head white space
 
         my $valid_start = defined $ch; # Is there a first character for JSON structure?
 
         my $result = value();
 
         return undef if ( !$result && ( $opt & 0x10000000 ) ); # for incr_parse
 
         decode_error("malformed JSON string, neither array, object, number, string or atom") unless $valid_start;
 
         if ( !$idx->[ P_ALLOW_NONREF ] and !ref $result ) {
                 decode_error(
                 'JSON text must be an object or array (but found number, string, true, false or null,'
                        . ' use allow_nonref to allow this)', 1);
         }
 
         Carp::croak('something wrong.') if $len < $at; # we won't arrive here.
 
         my $consumed = defined $ch ? $at - 1 : $at; # consumed JSON text length
 
         white(); # remove tail white space
 
         if ( $ch ) {
             return ( $result, $consumed ) if ($opt & 0x00000001); # all right if decode_prefix
             decode_error("garbage after JSON object");
         }
 
         ( $opt & 0x00000001 ) ? ( $result, $consumed ) : $result;
     }
 
 
     sub next_chr {
         return $ch = undef if($at >= $len);
         $ch = substr($text, $at++, 1);
     }
 
 
     sub value {
         white();
         return          if(!defined $ch);
         return object() if($ch eq '{');
         return array()  if($ch eq '[');
         return string() if($ch eq '"' or ($singlequote and $ch eq "'"));
         return number() if($ch =~ /[0-9]/ or $ch eq '-');
         return word();
     }
 
     sub string {
         my ($i, $s, $t, $u);
         my $utf16;
         my $is_utf8;
 
         ($is_valid_utf8, $utf8_len) = ('', 0);
 
         $s = ''; # basically UTF8 flag on
 
         if($ch eq '"' or ($singlequote and $ch eq "'")){
             my $boundChar = $ch;
 
             OUTER: while( defined(next_chr()) ){
 
                 if($ch eq $boundChar){
                     next_chr();
 
                     if ($utf16) {
                         decode_error("missing low surrogate character in surrogate pair");
                     }
 
                     utf8::decode($s) if($is_utf8);
 
                     return $s;
                 }
                 elsif($ch eq '\\'){
                     next_chr();
                     if(exists $escapes{$ch}){
                         $s .= $escapes{$ch};
                     }
                     elsif($ch eq 'u'){ # UNICODE handling
                         my $u = '';
 
                         for(1..4){
                             $ch = next_chr();
                             last OUTER if($ch !~ /[0-9a-fA-F]/);
                             $u .= $ch;
                         }
 
                         # U+D800 - U+DBFF
                         if ($u =~ /^[dD][89abAB][0-9a-fA-F]{2}/) { # UTF-16 high surrogate?
                             $utf16 = $u;
                         }
                         # U+DC00 - U+DFFF
                         elsif ($u =~ /^[dD][c-fC-F][0-9a-fA-F]{2}/) { # UTF-16 low surrogate?
                             unless (defined $utf16) {
                                 decode_error("missing high surrogate character in surrogate pair");
                             }
                             $is_utf8 = 1;
                             $s .= JSON_PP_decode_surrogates($utf16, $u) || next;
                             $utf16 = undef;
                         }
                         else {
                             if (defined $utf16) {
                                 decode_error("surrogate pair expected");
                             }
 
                             if ( ( my $hex = hex( $u ) ) > 127 ) {
                                 $is_utf8 = 1;
                                 $s .= JSON_PP_decode_unicode($u) || next;
                             }
                             else {
                                 $s .= chr $hex;
                             }
                         }
 
                     }
                     else{
                         unless ($loose) {
                             $at -= 2;
                             decode_error('illegal backslash escape sequence in string');
                         }
                         $s .= $ch;
                     }
                 }
                 else{
 
                     if ( ord $ch  > 127 ) {
                         unless( $ch = is_valid_utf8($ch) ) {
                             $at -= 1;
                             decode_error("malformed UTF-8 character in JSON string");
                         }
                         else {
                             $at += $utf8_len - 1;
                         }
 
                         $is_utf8 = 1;
                     }
 
                     if (!$loose) {
                         if ($ch =~ /[\x00-\x1f\x22\x5c]/)  { # '/' ok
                             $at--;
                             decode_error('invalid character encountered while parsing JSON string');
                         }
                     }
 
                     $s .= $ch;
                 }
             }
         }
 
         decode_error("unexpected end of string while parsing JSON string");
     }
 
 
     sub white {
         while( defined $ch  ){
             if($ch le ' '){
                 next_chr();
             }
             elsif($ch eq '/'){
                 next_chr();
                 if(defined $ch and $ch eq '/'){
                     1 while(defined(next_chr()) and $ch ne "\n" and $ch ne "\r");
                 }
                 elsif(defined $ch and $ch eq '*'){
                     next_chr();
                     while(1){
                         if(defined $ch){
                             if($ch eq '*'){
                                 if(defined(next_chr()) and $ch eq '/'){
                                     next_chr();
                                     last;
                                 }
                             }
                             else{
                                 next_chr();
                             }
                         }
                         else{
                             decode_error("Unterminated comment");
                         }
                     }
                     next;
                 }
                 else{
                     $at--;
                     decode_error("malformed JSON string, neither array, object, number, string or atom");
                 }
             }
             else{
                 if ($relaxed and $ch eq '#') { # correctly?
                     pos($text) = $at;
                     $text =~ /\G([^\n]*(?:\r\n|\r|\n|$))/g;
                     $at = pos($text);
                     next_chr;
                     next;
                 }
 
                 last;
             }
         }
     }
 
 
     sub array {
         my $a  = $_[0] || []; # you can use this code to use another array ref object.
 
         decode_error('json text or perl structure exceeds maximum nesting level (max_depth set too low?)')
                                                     if (++$depth > $max_depth);
 
         next_chr();
         white();
 
         if(defined $ch and $ch eq ']'){
             --$depth;
             next_chr();
             return $a;
         }
         else {
             while(defined($ch)){
                 push @$a, value();
 
                 white();
 
                 if (!defined $ch) {
                     last;
                 }
 
                 if($ch eq ']'){
                     --$depth;
                     next_chr();
                     return $a;
                 }
 
                 if($ch ne ','){
                     last;
                 }
 
                 next_chr();
                 white();
 
                 if ($relaxed and $ch eq ']') {
                     --$depth;
                     next_chr();
                     return $a;
                 }
 
             }
         }
 
         decode_error(", or ] expected while parsing array");
     }
 
 
     sub object {
         my $o = $_[0] || {}; # you can use this code to use another hash ref object.
         my $k;
 
         decode_error('json text or perl structure exceeds maximum nesting level (max_depth set too low?)')
                                                 if (++$depth > $max_depth);
         next_chr();
         white();
 
         if(defined $ch and $ch eq '}'){
             --$depth;
             next_chr();
             if ($F_HOOK) {
                 return _json_object_hook($o);
             }
             return $o;
         }
         else {
             while (defined $ch) {
                 $k = ($allow_barekey and $ch ne '"' and $ch ne "'") ? bareKey() : string();
                 white();
 
                 if(!defined $ch or $ch ne ':'){
                     $at--;
                     decode_error("':' expected");
                 }
 
                 next_chr();
                 $o->{$k} = value();
                 white();
 
                 last if (!defined $ch);
 
                 if($ch eq '}'){
                     --$depth;
                     next_chr();
                     if ($F_HOOK) {
                         return _json_object_hook($o);
                     }
                     return $o;
                 }
 
                 if($ch ne ','){
                     last;
                 }
 
                 next_chr();
                 white();
 
                 if ($relaxed and $ch eq '}') {
                     --$depth;
                     next_chr();
                     if ($F_HOOK) {
                         return _json_object_hook($o);
                     }
                     return $o;
                 }
 
             }
 
         }
 
         $at--;
         decode_error(", or } expected while parsing object/hash");
     }
 
 
     sub bareKey { # doesn't strictly follow Standard ECMA-262 3rd Edition
         my $key;
         while($ch =~ /[^\x00-\x23\x25-\x2F\x3A-\x40\x5B-\x5E\x60\x7B-\x7F]/){
             $key .= $ch;
             next_chr();
         }
         return $key;
     }
 
 
     sub word {
         my $word =  substr($text,$at-1,4);
 
         if($word eq 'true'){
             $at += 3;
             next_chr;
             return $JSON::PP::true;
         }
         elsif($word eq 'null'){
             $at += 3;
             next_chr;
             return undef;
         }
         elsif($word eq 'fals'){
             $at += 3;
             if(substr($text,$at,1) eq 'e'){
                 $at++;
                 next_chr;
                 return $JSON::PP::false;
             }
         }
 
         $at--; # for decode_error report
 
         decode_error("'null' expected")  if ($word =~ /^n/);
         decode_error("'true' expected")  if ($word =~ /^t/);
         decode_error("'false' expected") if ($word =~ /^f/);
         decode_error("malformed JSON string, neither array, object, number, string or atom");
     }
 
 
     sub number {
         my $n    = '';
         my $v;
 
         # According to RFC4627, hex or oct digts are invalid.
         if($ch eq '0'){
             my $peek = substr($text,$at,1);
             my $hex  = $peek =~ /[xX]/; # 0 or 1
 
             if($hex){
                 decode_error("malformed number (leading zero must not be followed by another digit)");
                 ($n) = ( substr($text, $at+1) =~ /^([0-9a-fA-F]+)/);
             }
             else{ # oct
                 ($n) = ( substr($text, $at) =~ /^([0-7]+)/);
                 if (defined $n and length $n > 1) {
                     decode_error("malformed number (leading zero must not be followed by another digit)");
                 }
             }
 
             if(defined $n and length($n)){
                 if (!$hex and length($n) == 1) {
                    decode_error("malformed number (leading zero must not be followed by another digit)");
                 }
                 $at += length($n) + $hex;
                 next_chr;
                 return $hex ? hex($n) : oct($n);
             }
         }
 
         if($ch eq '-'){
             $n = '-';
             next_chr;
             if (!defined $ch or $ch !~ /\d/) {
                 decode_error("malformed number (no digits after initial minus)");
             }
         }
 
         while(defined $ch and $ch =~ /\d/){
             $n .= $ch;
             next_chr;
         }
 
         if(defined $ch and $ch eq '.'){
             $n .= '.';
 
             next_chr;
             if (!defined $ch or $ch !~ /\d/) {
                 decode_error("malformed number (no digits after decimal point)");
             }
             else {
                 $n .= $ch;
             }
 
             while(defined(next_chr) and $ch =~ /\d/){
                 $n .= $ch;
             }
         }
 
         if(defined $ch and ($ch eq 'e' or $ch eq 'E')){
             $n .= $ch;
             next_chr;
 
             if(defined($ch) and ($ch eq '+' or $ch eq '-')){
                 $n .= $ch;
                 next_chr;
                 if (!defined $ch or $ch =~ /\D/) {
                     decode_error("malformed number (no digits after exp sign)");
                 }
                 $n .= $ch;
             }
             elsif(defined($ch) and $ch =~ /\d/){
                 $n .= $ch;
             }
             else {
                 decode_error("malformed number (no digits after exp sign)");
             }
 
             while(defined(next_chr) and $ch =~ /\d/){
                 $n .= $ch;
             }
 
         }
 
         $v .= $n;
 
         if ($v !~ /[.eE]/ and length $v > $max_intsize) {
             if ($allow_bigint) { # from Adam Sussman
                 require Math::BigInt;
                 return Math::BigInt->new($v);
             }
             else {
                 return "$v";
             }
         }
         elsif ($allow_bigint) {
             require Math::BigFloat;
             return Math::BigFloat->new($v);
         }
 
         return 0+$v;
     }
 
 
     sub is_valid_utf8 {
 
         $utf8_len = $_[0] =~ /[\x00-\x7F]/  ? 1
                   : $_[0] =~ /[\xC2-\xDF]/  ? 2
                   : $_[0] =~ /[\xE0-\xEF]/  ? 3
                   : $_[0] =~ /[\xF0-\xF4]/  ? 4
                   : 0
                   ;
 
         return unless $utf8_len;
 
         my $is_valid_utf8 = substr($text, $at - 1, $utf8_len);
 
         return ( $is_valid_utf8 =~ /^(?:
              [\x00-\x7F]
             |[\xC2-\xDF][\x80-\xBF]
             |[\xE0][\xA0-\xBF][\x80-\xBF]
             |[\xE1-\xEC][\x80-\xBF][\x80-\xBF]
             |[\xED][\x80-\x9F][\x80-\xBF]
             |[\xEE-\xEF][\x80-\xBF][\x80-\xBF]
             |[\xF0][\x90-\xBF][\x80-\xBF][\x80-\xBF]
             |[\xF1-\xF3][\x80-\xBF][\x80-\xBF][\x80-\xBF]
             |[\xF4][\x80-\x8F][\x80-\xBF][\x80-\xBF]
         )$/x )  ? $is_valid_utf8 : '';
     }
 
 
     sub decode_error {
         my $error  = shift;
         my $no_rep = shift;
         my $str    = defined $text ? substr($text, $at) : '';
         my $mess   = '';
         my $type   = $] >= 5.008           ? 'U*'
                    : $] <  5.006           ? 'C*'
                    : utf8::is_utf8( $str ) ? 'U*' # 5.6
                    : 'C*'
                    ;
 
         for my $c ( unpack( $type, $str ) ) { # emulate pv_uni_display() ?
             $mess .=  $c == 0x07 ? '\a'
                     : $c == 0x09 ? '\t'
                     : $c == 0x0a ? '\n'
                     : $c == 0x0d ? '\r'
                     : $c == 0x0c ? '\f'
                     : $c <  0x20 ? sprintf('\x{%x}', $c)
                     : $c == 0x5c ? '\\\\'
                     : $c <  0x80 ? chr($c)
                     : sprintf('\x{%x}', $c)
                     ;
             if ( length $mess >= 20 ) {
                 $mess .= '...';
                 last;
             }
         }
 
         unless ( length $mess ) {
             $mess = '(end of string)';
         }
 
         Carp::croak (
             $no_rep ? "$error" : "$error, at character offset $at (before \"$mess\")"
         );
 
     }
 
 
     sub _json_object_hook {
         my $o    = $_[0];
         my @ks = keys %{$o};
 
         if ( $cb_sk_object and @ks == 1 and exists $cb_sk_object->{ $ks[0] } and ref $cb_sk_object->{ $ks[0] } ) {
             my @val = $cb_sk_object->{ $ks[0] }->( $o->{$ks[0]} );
             if (@val == 1) {
                 return $val[0];
             }
         }
 
         my @val = $cb_object->($o) if ($cb_object);
         if (@val == 0 or @val > 1) {
             return $o;
         }
         else {
             return $val[0];
         }
     }
 
 
     sub PP_decode_box {
         {
             text    => $text,
             at      => $at,
             ch      => $ch,
             len     => $len,
             depth   => $depth,
             encoding      => $encoding,
             is_valid_utf8 => $is_valid_utf8,
         };
     }
 
 } # PARSE
 
 
 sub _decode_surrogates { # from perlunicode
     my $uni = 0x10000 + (hex($_[0]) - 0xD800) * 0x400 + (hex($_[1]) - 0xDC00);
     my $un  = pack('U*', $uni);
     utf8::encode( $un );
     return $un;
 }
 
 
 sub _decode_unicode {
     my $un = pack('U', hex shift);
     utf8::encode( $un );
     return $un;
 }
 
 #
 # Setup for various Perl versions (the code from JSON::PP58)
 #
 
 BEGIN {
 
     unless ( defined &utf8::is_utf8 ) {
        require Encode;
        *utf8::is_utf8 = *Encode::is_utf8;
     }
 
     if ( $] >= 5.008 ) {
         *JSON::PP::JSON_PP_encode_ascii      = \&_encode_ascii;
         *JSON::PP::JSON_PP_encode_latin1     = \&_encode_latin1;
         *JSON::PP::JSON_PP_decode_surrogates = \&_decode_surrogates;
         *JSON::PP::JSON_PP_decode_unicode    = \&_decode_unicode;
     }
 
     if ($] >= 5.008 and $] < 5.008003) { # join() in 5.8.0 - 5.8.2 is broken.
         package JSON::PP;
         require subs;
         subs->import('join');
         eval q|
             sub join {
                 return '' if (@_ < 2);
                 my $j   = shift;
                 my $str = shift;
                 for (@_) { $str .= $j . $_; }
                 return $str;
             }
         |;
     }
 
 
     sub JSON::PP::incr_parse {
         local $Carp::CarpLevel = 1;
         ( $_[0]->{_incr_parser} ||= JSON::PP::IncrParser->new )->incr_parse( @_ );
     }
 
 
     sub JSON::PP::incr_skip {
         ( $_[0]->{_incr_parser} ||= JSON::PP::IncrParser->new )->incr_skip;
     }
 
 
     sub JSON::PP::incr_reset {
         ( $_[0]->{_incr_parser} ||= JSON::PP::IncrParser->new )->incr_reset;
     }
 
     eval q{
         sub JSON::PP::incr_text : lvalue {
             $_[0]->{_incr_parser} ||= JSON::PP::IncrParser->new;
 
             if ( $_[0]->{_incr_parser}->{incr_parsing} ) {
                 Carp::croak("incr_text can not be called when the incremental parser already started parsing");
             }
             $_[0]->{_incr_parser}->{incr_text};
         }
     } if ( $] >= 5.006 );
 
 } # Setup for various Perl versions (the code from JSON::PP58)
 
 
 ###############################
 # Utilities
 #
 
 BEGIN {
     eval 'require Scalar::Util';
     unless($@){
         *JSON::PP::blessed = \&Scalar::Util::blessed;
         *JSON::PP::reftype = \&Scalar::Util::reftype;
         *JSON::PP::refaddr = \&Scalar::Util::refaddr;
     }
     else{ # This code is from Sclar::Util.
         # warn $@;
         eval 'sub UNIVERSAL::a_sub_not_likely_to_be_here { ref($_[0]) }';
         *JSON::PP::blessed = sub {
             local($@, $SIG{__DIE__}, $SIG{__WARN__});
             ref($_[0]) ? eval { $_[0]->a_sub_not_likely_to_be_here } : undef;
         };
         my %tmap = qw(
             B::NULL   SCALAR
             B::HV     HASH
             B::AV     ARRAY
             B::CV     CODE
             B::IO     IO
             B::GV     GLOB
             B::REGEXP REGEXP
         );
         *JSON::PP::reftype = sub {
             my $r = shift;
 
             return undef unless length(ref($r));
 
             my $t = ref(B::svref_2object($r));
 
             return
                 exists $tmap{$t} ? $tmap{$t}
               : length(ref($$r)) ? 'REF'
               :                    'SCALAR';
         };
         *JSON::PP::refaddr = sub {
           return undef unless length(ref($_[0]));
 
           my $addr;
           if(defined(my $pkg = blessed($_[0]))) {
             $addr .= bless $_[0], 'Scalar::Util::Fake';
             bless $_[0], $pkg;
           }
           else {
             $addr .= $_[0]
           }
 
           $addr =~ /0x(\w+)/;
           local $^W;
           #no warnings 'portable';
           hex($1);
         }
     }
 }
 
 
 # shamely copied and modified from JSON::XS code.
 
 $JSON::PP::true  = do { bless \(my $dummy = 1), "JSON::PP::Boolean" };
 $JSON::PP::false = do { bless \(my $dummy = 0), "JSON::PP::Boolean" };
 
 sub is_bool { defined $_[0] and UNIVERSAL::isa($_[0], "JSON::PP::Boolean"); }
 
 sub true  { $JSON::PP::true  }
 sub false { $JSON::PP::false }
 sub null  { undef; }
 
 ###############################
 
 package JSON::PP::Boolean;
 
 use overload (
    "0+"     => sub { ${$_[0]} },
    "++"     => sub { $_[0] = ${$_[0]} + 1 },
    "--"     => sub { $_[0] = ${$_[0]} - 1 },
    fallback => 1,
 );
 
 
 ###############################
 
 package JSON::PP::IncrParser;
 
 use strict;
 
 use constant INCR_M_WS   => 0; # initial whitespace skipping
 use constant INCR_M_STR  => 1; # inside string
 use constant INCR_M_BS   => 2; # inside backslash
 use constant INCR_M_JSON => 3; # outside anything, count nesting
 use constant INCR_M_C0   => 4;
 use constant INCR_M_C1   => 5;
 
 $JSON::PP::IncrParser::VERSION = '1.01';
 
 my $unpack_format = $] < 5.006 ? 'C*' : 'U*';
 
 sub new {
     my ( $class ) = @_;
 
     bless {
         incr_nest    => 0,
         incr_text    => undef,
         incr_parsing => 0,
         incr_p       => 0,
     }, $class;
 }
 
 
 sub incr_parse {
     my ( $self, $coder, $text ) = @_;
 
     $self->{incr_text} = '' unless ( defined $self->{incr_text} );
 
     if ( defined $text ) {
         if ( utf8::is_utf8( $text ) and !utf8::is_utf8( $self->{incr_text} ) ) {
             utf8::upgrade( $self->{incr_text} ) ;
             utf8::decode( $self->{incr_text} ) ;
         }
         $self->{incr_text} .= $text;
     }
 
 
     my $max_size = $coder->get_max_size;
 
     if ( defined wantarray ) {
 
         $self->{incr_mode} = INCR_M_WS unless defined $self->{incr_mode};
 
         if ( wantarray ) {
             my @ret;
 
             $self->{incr_parsing} = 1;
 
             do {
                 push @ret, $self->_incr_parse( $coder, $self->{incr_text} );
 
                 unless ( !$self->{incr_nest} and $self->{incr_mode} == INCR_M_JSON ) {
                     $self->{incr_mode} = INCR_M_WS if $self->{incr_mode} != INCR_M_STR;
                 }
 
             } until ( length $self->{incr_text} >= $self->{incr_p} );
 
             $self->{incr_parsing} = 0;
 
             return @ret;
         }
         else { # in scalar context
             $self->{incr_parsing} = 1;
             my $obj = $self->_incr_parse( $coder, $self->{incr_text} );
             $self->{incr_parsing} = 0 if defined $obj; # pointed by Martin J. Evans
             return $obj ? $obj : undef; # $obj is an empty string, parsing was completed.
         }
 
     }
 
 }
 
 
 sub _incr_parse {
     my ( $self, $coder, $text, $skip ) = @_;
     my $p = $self->{incr_p};
     my $restore = $p;
 
     my @obj;
     my $len = length $text;
 
     if ( $self->{incr_mode} == INCR_M_WS ) {
         while ( $len > $p ) {
             my $s = substr( $text, $p, 1 );
             $p++ and next if ( 0x20 >= unpack($unpack_format, $s) );
             $self->{incr_mode} = INCR_M_JSON;
             last;
        }
     }
 
     while ( $len > $p ) {
         my $s = substr( $text, $p++, 1 );
 
         if ( $s eq '"' ) {
             if (substr( $text, $p - 2, 1 ) eq '\\' ) {
                 next;
             }
 
             if ( $self->{incr_mode} != INCR_M_STR  ) {
                 $self->{incr_mode} = INCR_M_STR;
             }
             else {
                 $self->{incr_mode} = INCR_M_JSON;
                 unless ( $self->{incr_nest} ) {
                     last;
                 }
             }
         }
 
         if ( $self->{incr_mode} == INCR_M_JSON ) {
 
             if ( $s eq '[' or $s eq '{' ) {
                 if ( ++$self->{incr_nest} > $coder->get_max_depth ) {
                     Carp::croak('json text or perl structure exceeds maximum nesting level (max_depth set too low?)');
                 }
             }
             elsif ( $s eq ']' or $s eq '}' ) {
                 last if ( --$self->{incr_nest} <= 0 );
             }
             elsif ( $s eq '#' ) {
                 while ( $len > $p ) {
                     last if substr( $text, $p++, 1 ) eq "\n";
                 }
             }
 
         }
 
     }
 
     $self->{incr_p} = $p;
 
     return if ( $self->{incr_mode} == INCR_M_STR and not $self->{incr_nest} );
     return if ( $self->{incr_mode} == INCR_M_JSON and $self->{incr_nest} > 0 );
 
     return '' unless ( length substr( $self->{incr_text}, 0, $p ) );
 
     local $Carp::CarpLevel = 2;
 
     $self->{incr_p} = $restore;
     $self->{incr_c} = $p;
 
     my ( $obj, $tail ) = $coder->PP_decode_json( substr( $self->{incr_text}, 0, $p ), 0x10000001 );
 
     $self->{incr_text} = substr( $self->{incr_text}, $p );
     $self->{incr_p} = 0;
 
     return $obj || '';
 }
 
 
 sub incr_text {
     if ( $_[0]->{incr_parsing} ) {
         Carp::croak("incr_text can not be called when the incremental parser already started parsing");
     }
     $_[0]->{incr_text};
 }
 
 
 sub incr_skip {
     my $self  = shift;
     $self->{incr_text} = substr( $self->{incr_text}, $self->{incr_c} );
     $self->{incr_p} = 0;
 }
 
 
 sub incr_reset {
     my $self = shift;
     $self->{incr_text}    = undef;
     $self->{incr_p}       = 0;
     $self->{incr_mode}    = 0;
     $self->{incr_nest}    = 0;
     $self->{incr_parsing} = 0;
 }
 
 ###############################
 
 
 1;
 __END__
 =pod
 
 =head1 NAME
 
 JSON::PP - JSON::XS compatible pure-Perl module.
 
 =head1 SYNOPSIS
 
  use JSON::PP;
 
  # exported functions, they croak on error
  # and expect/generate UTF-8
 
  $utf8_encoded_json_text = encode_json $perl_hash_or_arrayref;
  $perl_hash_or_arrayref  = decode_json $utf8_encoded_json_text;
 
  # OO-interface
 
  $coder = JSON::PP->new->ascii->pretty->allow_nonref;
  
  $json_text   = $json->encode( $perl_scalar );
  $perl_scalar = $json->decode( $json_text );
  
  $pretty_printed = $json->pretty->encode( $perl_scalar ); # pretty-printing
  
  # Note that JSON version 2.0 and above will automatically use
  # JSON::XS or JSON::PP, so you should be able to just:
  
  use JSON;
 
 
 =head1 VERSION
 
     2.27300
 
 L<JSON::XS> 2.27 (~2.30) compatible.
 
 =head1 NOTE
 
 JSON::PP had been inculded in JSON distribution (CPAN module).
 It was a perl core module in Perl 5.14.
 
 =head1 DESCRIPTION
 
 This module is L<JSON::XS> compatible pure Perl module.
 (Perl 5.8 or later is recommended)
 
 JSON::XS is the fastest and most proper JSON module on CPAN.
 It is written by Marc Lehmann in C, so must be compiled and
 installed in the used environment.
 
 JSON::PP is a pure-Perl module and has compatibility to JSON::XS.
 
 
 =head2 FEATURES
 
 =over
 
 =item * correct unicode handling
 
 This module knows how to handle Unicode (depending on Perl version).
 
 See to L<JSON::XS/A FEW NOTES ON UNICODE AND PERL> and L<UNICODE HANDLING ON PERLS>.
 
 
 =item * round-trip integrity
 
 When you serialise a perl data structure using only data types supported
 by JSON and Perl, the deserialised data structure is identical on the Perl
 level. (e.g. the string "2.0" doesn't suddenly become "2" just because
 it looks like a number). There I<are> minor exceptions to this, read the
 MAPPING section below to learn about those.
 
 
 =item * strict checking of JSON correctness
 
 There is no guessing, no generating of illegal JSON texts by default,
 and only JSON is accepted as input by default (the latter is a security feature).
 But when some options are set, loose chcking features are available.
 
 =back
 
 =head1 FUNCTIONAL INTERFACE
 
 Some documents are copied and modified from L<JSON::XS/FUNCTIONAL INTERFACE>.
 
 =head2 encode_json
 
     $json_text = encode_json $perl_scalar
 
 Converts the given Perl data structure to a UTF-8 encoded, binary string.
 
 This function call is functionally identical to:
 
     $json_text = JSON::PP->new->utf8->encode($perl_scalar)
 
 =head2 decode_json
 
     $perl_scalar = decode_json $json_text
 
 The opposite of C<encode_json>: expects an UTF-8 (binary) string and tries
 to parse that as an UTF-8 encoded JSON text, returning the resulting
 reference.
 
 This function call is functionally identical to:
 
     $perl_scalar = JSON::PP->new->utf8->decode($json_text)
 
 =head2 JSON::PP::is_bool
 
     $is_boolean = JSON::PP::is_bool($scalar)
 
 Returns true if the passed scalar represents either JSON::PP::true or
 JSON::PP::false, two constants that act like C<1> and C<0> respectively
 and are also used to represent JSON C<true> and C<false> in Perl strings.
 
 =head2 JSON::PP::true
 
 Returns JSON true value which is blessed object.
 It C<isa> JSON::PP::Boolean object.
 
 =head2 JSON::PP::false
 
 Returns JSON false value which is blessed object.
 It C<isa> JSON::PP::Boolean object.
 
 =head2 JSON::PP::null
 
 Returns C<undef>.
 
 See L<MAPPING>, below, for more information on how JSON values are mapped to
 Perl.
 
 
 =head1 HOW DO I DECODE A DATA FROM OUTER AND ENCODE TO OUTER
 
 This section supposes that your perl vresion is 5.8 or later.
 
 If you know a JSON text from an outer world - a network, a file content, and so on,
 is encoded in UTF-8, you should use C<decode_json> or C<JSON> module object
 with C<utf8> enable. And the decoded result will contain UNICODE characters.
 
   # from network
   my $json        = JSON::PP->new->utf8;
   my $json_text   = CGI->new->param( 'json_data' );
   my $perl_scalar = $json->decode( $json_text );
   
   # from file content
   local $/;
   open( my $fh, '<', 'json.data' );
   $json_text   = <$fh>;
   $perl_scalar = decode_json( $json_text );
 
 If an outer data is not encoded in UTF-8, firstly you should C<decode> it.
 
   use Encode;
   local $/;
   open( my $fh, '<', 'json.data' );
   my $encoding = 'cp932';
   my $unicode_json_text = decode( $encoding, <$fh> ); # UNICODE
   
   # or you can write the below code.
   #
   # open( my $fh, "<:encoding($encoding)", 'json.data' );
   # $unicode_json_text = <$fh>;
 
 In this case, C<$unicode_json_text> is of course UNICODE string.
 So you B<cannot> use C<decode_json> nor C<JSON> module object with C<utf8> enable.
 Instead of them, you use C<JSON> module object with C<utf8> disable.
 
   $perl_scalar = $json->utf8(0)->decode( $unicode_json_text );
 
 Or C<encode 'utf8'> and C<decode_json>:
 
   $perl_scalar = decode_json( encode( 'utf8', $unicode_json_text ) );
   # this way is not efficient.
 
 And now, you want to convert your C<$perl_scalar> into JSON data and
 send it to an outer world - a network or a file content, and so on.
 
 Your data usually contains UNICODE strings and you want the converted data to be encoded
 in UTF-8, you should use C<encode_json> or C<JSON> module object with C<utf8> enable.
 
   print encode_json( $perl_scalar ); # to a network? file? or display?
   # or
   print $json->utf8->encode( $perl_scalar );
 
 If C<$perl_scalar> does not contain UNICODE but C<$encoding>-encoded strings
 for some reason, then its characters are regarded as B<latin1> for perl
 (because it does not concern with your $encoding).
 You B<cannot> use C<encode_json> nor C<JSON> module object with C<utf8> enable.
 Instead of them, you use C<JSON> module object with C<utf8> disable.
 Note that the resulted text is a UNICODE string but no problem to print it.
 
   # $perl_scalar contains $encoding encoded string values
   $unicode_json_text = $json->utf8(0)->encode( $perl_scalar );
   # $unicode_json_text consists of characters less than 0x100
   print $unicode_json_text;
 
 Or C<decode $encoding> all string values and C<encode_json>:
 
   $perl_scalar->{ foo } = decode( $encoding, $perl_scalar->{ foo } );
   # ... do it to each string values, then encode_json
   $json_text = encode_json( $perl_scalar );
 
 This method is a proper way but probably not efficient.
 
 See to L<Encode>, L<perluniintro>.
 
 
 =head1 METHODS
 
 Basically, check to L<JSON> or L<JSON::XS>.
 
 =head2 new
 
     $json = JSON::PP->new
 
 Rturns a new JSON::PP object that can be used to de/encode JSON
 strings.
 
 All boolean flags described below are by default I<disabled>.
 
 The mutators for flags all return the JSON object again and thus calls can
 be chained:
 
    my $json = JSON::PP->new->utf8->space_after->encode({a => [1,2]})
    => {"a": [1, 2]}
 
 =head2 ascii
 
     $json = $json->ascii([$enable])
     
     $enabled = $json->get_ascii
 
 If $enable is true (or missing), then the encode method will not generate characters outside
 the code range 0..127. Any Unicode characters outside that range will be escaped using either
 a single \uXXXX or a double \uHHHH\uLLLLL escape sequence, as per RFC4627.
 (See to L<JSON::XS/OBJECT-ORIENTED INTERFACE>).
 
 In Perl 5.005, there is no character having high value (more than 255).
 See to L<UNICODE HANDLING ON PERLS>.
 
 If $enable is false, then the encode method will not escape Unicode characters unless
 required by the JSON syntax or other flags. This results in a faster and more compact format.
 
   JSON::PP->new->ascii(1)->encode([chr 0x10401])
   => ["\ud801\udc01"]
 
 =head2 latin1
 
     $json = $json->latin1([$enable])
     
     $enabled = $json->get_latin1
 
 If $enable is true (or missing), then the encode method will encode the resulting JSON
 text as latin1 (or iso-8859-1), escaping any characters outside the code range 0..255.
 
 If $enable is false, then the encode method will not escape Unicode characters
 unless required by the JSON syntax or other flags.
 
   JSON::XS->new->latin1->encode (["\x{89}\x{abc}"]
   => ["\x{89}\\u0abc"]    # (perl syntax, U+abc escaped, U+89 not)
 
 See to L<UNICODE HANDLING ON PERLS>.
 
 =head2 utf8
 
     $json = $json->utf8([$enable])
     
     $enabled = $json->get_utf8
 
 If $enable is true (or missing), then the encode method will encode the JSON result
 into UTF-8, as required by many protocols, while the decode method expects to be handled
 an UTF-8-encoded string. Please note that UTF-8-encoded strings do not contain any
 characters outside the range 0..255, they are thus useful for bytewise/binary I/O.
 
 (In Perl 5.005, any character outside the range 0..255 does not exist.
 See to L<UNICODE HANDLING ON PERLS>.)
 
 In future versions, enabling this option might enable autodetection of the UTF-16 and UTF-32
 encoding families, as described in RFC4627.
 
 If $enable is false, then the encode method will return the JSON string as a (non-encoded)
 Unicode string, while decode expects thus a Unicode string. Any decoding or encoding
 (e.g. to UTF-8 or UTF-16) needs to be done yourself, e.g. using the Encode module.
 
 Example, output UTF-16BE-encoded JSON:
 
   use Encode;
   $jsontext = encode "UTF-16BE", JSON::PP->new->encode ($object);
 
 Example, decode UTF-32LE-encoded JSON:
 
   use Encode;
   $object = JSON::PP->new->decode (decode "UTF-32LE", $jsontext);
 
 
 =head2 pretty
 
     $json = $json->pretty([$enable])
 
 This enables (or disables) all of the C<indent>, C<space_before> and
 C<space_after> flags in one call to generate the most readable
 (or most compact) form possible.
 
 Equivalent to:
 
    $json->indent->space_before->space_after
 
 =head2 indent
 
     $json = $json->indent([$enable])
     
     $enabled = $json->get_indent
 
 The default indent space length is three.
 You can use C<indent_length> to change the length.
 
 =head2 space_before
 
     $json = $json->space_before([$enable])
     
     $enabled = $json->get_space_before
 
 If C<$enable> is true (or missing), then the C<encode> method will add an extra
 optional space before the C<:> separating keys from values in JSON objects.
 
 If C<$enable> is false, then the C<encode> method will not add any extra
 space at those places.
 
 This setting has no effect when decoding JSON texts.
 
 Example, space_before enabled, space_after and indent disabled:
 
    {"key" :"value"}
 
 =head2 space_after
 
     $json = $json->space_after([$enable])
     
     $enabled = $json->get_space_after
 
 If C<$enable> is true (or missing), then the C<encode> method will add an extra
 optional space after the C<:> separating keys from values in JSON objects
 and extra whitespace after the C<,> separating key-value pairs and array
 members.
 
 If C<$enable> is false, then the C<encode> method will not add any extra
 space at those places.
 
 This setting has no effect when decoding JSON texts.
 
 Example, space_before and indent disabled, space_after enabled:
 
    {"key": "value"}
 
 =head2 relaxed
 
     $json = $json->relaxed([$enable])
     
     $enabled = $json->get_relaxed
 
 If C<$enable> is true (or missing), then C<decode> will accept some
 extensions to normal JSON syntax (see below). C<encode> will not be
 affected in anyway. I<Be aware that this option makes you accept invalid
 JSON texts as if they were valid!>. I suggest only to use this option to
 parse application-specific files written by humans (configuration files,
 resource files etc.)
 
 If C<$enable> is false (the default), then C<decode> will only accept
 valid JSON texts.
 
 Currently accepted extensions are:
 
 =over 4
 
 =item * list items can have an end-comma
 
 JSON I<separates> array elements and key-value pairs with commas. This
 can be annoying if you write JSON texts manually and want to be able to
 quickly append elements, so this extension accepts comma at the end of
 such items not just between them:
 
    [
       1,
       2, <- this comma not normally allowed
    ]
    {
       "k1": "v1",
       "k2": "v2", <- this comma not normally allowed
    }
 
 =item * shell-style '#'-comments
 
 Whenever JSON allows whitespace, shell-style comments are additionally
 allowed. They are terminated by the first carriage-return or line-feed
 character, after which more white-space and comments are allowed.
 
   [
      1, # this comment not allowed in JSON
         # neither this one...
   ]
 
 =back
 
 =head2 canonical
 
     $json = $json->canonical([$enable])
     
     $enabled = $json->get_canonical
 
 If C<$enable> is true (or missing), then the C<encode> method will output JSON objects
 by sorting their keys. This is adding a comparatively high overhead.
 
 If C<$enable> is false, then the C<encode> method will output key-value
 pairs in the order Perl stores them (which will likely change between runs
 of the same script).
 
 This option is useful if you want the same data structure to be encoded as
 the same JSON text (given the same overall settings). If it is disabled,
 the same hash might be encoded differently even if contains the same data,
 as key-value pairs have no inherent ordering in Perl.
 
 This setting has no effect when decoding JSON texts.
 
 If you want your own sorting routine, you can give a code referece
 or a subroutine name to C<sort_by>. See to C<JSON::PP OWN METHODS>.
 
 =head2 allow_nonref
 
     $json = $json->allow_nonref([$enable])
     
     $enabled = $json->get_allow_nonref
 
 If C<$enable> is true (or missing), then the C<encode> method can convert a
 non-reference into its corresponding string, number or null JSON value,
 which is an extension to RFC4627. Likewise, C<decode> will accept those JSON
 values instead of croaking.
 
 If C<$enable> is false, then the C<encode> method will croak if it isn't
 passed an arrayref or hashref, as JSON texts must either be an object
 or array. Likewise, C<decode> will croak if given something that is not a
 JSON object or array.
 
    JSON::PP->new->allow_nonref->encode ("Hello, World!")
    => "Hello, World!"
 
 =head2 allow_unknown
 
     $json = $json->allow_unknown ([$enable])
     
     $enabled = $json->get_allow_unknown
 
 If $enable is true (or missing), then "encode" will *not* throw an
 exception when it encounters values it cannot represent in JSON (for
 example, filehandles) but instead will encode a JSON "null" value.
 Note that blessed objects are not included here and are handled
 separately by c<allow_nonref>.
 
 If $enable is false (the default), then "encode" will throw an
 exception when it encounters anything it cannot encode as JSON.
 
 This option does not affect "decode" in any way, and it is
 recommended to leave it off unless you know your communications
 partner.
 
 =head2 allow_blessed
 
     $json = $json->allow_blessed([$enable])
     
     $enabled = $json->get_allow_blessed
 
 If C<$enable> is true (or missing), then the C<encode> method will not
 barf when it encounters a blessed reference. Instead, the value of the
 B<convert_blessed> option will decide whether C<null> (C<convert_blessed>
 disabled or no C<TO_JSON> method found) or a representation of the
 object (C<convert_blessed> enabled and C<TO_JSON> method found) is being
 encoded. Has no effect on C<decode>.
 
 If C<$enable> is false (the default), then C<encode> will throw an
 exception when it encounters a blessed object.
 
 =head2 convert_blessed
 
     $json = $json->convert_blessed([$enable])
     
     $enabled = $json->get_convert_blessed
 
 If C<$enable> is true (or missing), then C<encode>, upon encountering a
 blessed object, will check for the availability of the C<TO_JSON> method
 on the object's class. If found, it will be called in scalar context
 and the resulting scalar will be encoded instead of the object. If no
 C<TO_JSON> method is found, the value of C<allow_blessed> will decide what
 to do.
 
 The C<TO_JSON> method may safely call die if it wants. If C<TO_JSON>
 returns other blessed objects, those will be handled in the same
 way. C<TO_JSON> must take care of not causing an endless recursion cycle
 (== crash) in this case. The name of C<TO_JSON> was chosen because other
 methods called by the Perl core (== not by the user of the object) are
 usually in upper case letters and to avoid collisions with the C<to_json>
 function or method.
 
 This setting does not yet influence C<decode> in any way.
 
 If C<$enable> is false, then the C<allow_blessed> setting will decide what
 to do when a blessed object is found.
 
 =head2 filter_json_object
 
     $json = $json->filter_json_object([$coderef])
 
 When C<$coderef> is specified, it will be called from C<decode> each
 time it decodes a JSON object. The only argument passed to the coderef
 is a reference to the newly-created hash. If the code references returns
 a single scalar (which need not be a reference), this value
 (i.e. a copy of that scalar to avoid aliasing) is inserted into the
 deserialised data structure. If it returns an empty list
 (NOTE: I<not> C<undef>, which is a valid scalar), the original deserialised
 hash will be inserted. This setting can slow down decoding considerably.
 
 When C<$coderef> is omitted or undefined, any existing callback will
 be removed and C<decode> will not change the deserialised hash in any
 way.
 
 Example, convert all JSON objects into the integer 5:
 
    my $js = JSON::PP->new->filter_json_object (sub { 5 });
    # returns [5]
    $js->decode ('[{}]'); # the given subroutine takes a hash reference.
    # throw an exception because allow_nonref is not enabled
    # so a lone 5 is not allowed.
    $js->decode ('{"a":1, "b":2}');
 
 =head2 filter_json_single_key_object
 
     $json = $json->filter_json_single_key_object($key [=> $coderef])
 
 Works remotely similar to C<filter_json_object>, but is only called for
 JSON objects having a single key named C<$key>.
 
 This C<$coderef> is called before the one specified via
 C<filter_json_object>, if any. It gets passed the single value in the JSON
 object. If it returns a single value, it will be inserted into the data
 structure. If it returns nothing (not even C<undef> but the empty list),
 the callback from C<filter_json_object> will be called next, as if no
 single-key callback were specified.
 
 If C<$coderef> is omitted or undefined, the corresponding callback will be
 disabled. There can only ever be one callback for a given key.
 
 As this callback gets called less often then the C<filter_json_object>
 one, decoding speed will not usually suffer as much. Therefore, single-key
 objects make excellent targets to serialise Perl objects into, especially
 as single-key JSON objects are as close to the type-tagged value concept
 as JSON gets (it's basically an ID/VALUE tuple). Of course, JSON does not
 support this in any way, so you need to make sure your data never looks
 like a serialised Perl hash.
 
 Typical names for the single object key are C<__class_whatever__>, or
 C<$__dollars_are_rarely_used__$> or C<}ugly_brace_placement>, or even
 things like C<__class_md5sum(classname)__>, to reduce the risk of clashing
 with real hashes.
 
 Example, decode JSON objects of the form C<< { "__widget__" => <id> } >>
 into the corresponding C<< $WIDGET{<id>} >> object:
 
    # return whatever is in $WIDGET{5}:
    JSON::PP
       ->new
       ->filter_json_single_key_object (__widget__ => sub {
             $WIDGET{ $_[0] }
          })
       ->decode ('{"__widget__": 5')
 
    # this can be used with a TO_JSON method in some "widget" class
    # for serialisation to json:
    sub WidgetBase::TO_JSON {
       my ($self) = @_;
 
       unless ($self->{id}) {
          $self->{id} = ..get..some..id..;
          $WIDGET{$self->{id}} = $self;
       }
 
       { __widget__ => $self->{id} }
    }
 
 =head2 shrink
 
     $json = $json->shrink([$enable])
     
     $enabled = $json->get_shrink
 
 In JSON::XS, this flag resizes strings generated by either
 C<encode> or C<decode> to their minimum size possible.
 It will also try to downgrade any strings to octet-form if possible.
 
 In JSON::PP, it is noop about resizing strings but tries
 C<utf8::downgrade> to the returned string by C<encode>.
 See to L<utf8>.
 
 See to L<JSON::XS/OBJECT-ORIENTED INTERFACE>
 
 =head2 max_depth
 
     $json = $json->max_depth([$maximum_nesting_depth])
     
     $max_depth = $json->get_max_depth
 
 Sets the maximum nesting level (default C<512>) accepted while encoding
 or decoding. If a higher nesting level is detected in JSON text or a Perl
 data structure, then the encoder and decoder will stop and croak at that
 point.
 
 Nesting level is defined by number of hash- or arrayrefs that the encoder
 needs to traverse to reach a given point or the number of C<{> or C<[>
 characters without their matching closing parenthesis crossed to reach a
 given character in a string.
 
 If no argument is given, the highest possible setting will be used, which
 is rarely useful.
 
 See L<JSON::XS/SSECURITY CONSIDERATIONS> for more info on why this is useful.
 
 When a large value (100 or more) was set and it de/encodes a deep nested object/text,
 it may raise a warning 'Deep recursion on subroutin' at the perl runtime phase.
 
 =head2 max_size
 
     $json = $json->max_size([$maximum_string_size])
     
     $max_size = $json->get_max_size
 
 Set the maximum length a JSON text may have (in bytes) where decoding is
 being attempted. The default is C<0>, meaning no limit. When C<decode>
 is called on a string that is longer then this many bytes, it will not
 attempt to decode the string but throw an exception. This setting has no
 effect on C<encode> (yet).
 
 If no argument is given, the limit check will be deactivated (same as when
 C<0> is specified).
 
 See L<JSON::XS/SSECURITY CONSIDERATIONS> for more info on why this is useful.
 
 =head2 encode
 
     $json_text = $json->encode($perl_scalar)
 
 Converts the given Perl data structure (a simple scalar or a reference
 to a hash or array) to its JSON representation. Simple scalars will be
 converted into JSON string or number sequences, while references to arrays
 become JSON arrays and references to hashes become JSON objects. Undefined
 Perl values (e.g. C<undef>) become JSON C<null> values.
 References to the integers C<0> and C<1> are converted into C<true> and C<false>.
 
 =head2 decode
 
     $perl_scalar = $json->decode($json_text)
 
 The opposite of C<encode>: expects a JSON text and tries to parse it,
 returning the resulting simple scalar or reference. Croaks on error.
 
 JSON numbers and strings become simple Perl scalars. JSON arrays become
 Perl arrayrefs and JSON objects become Perl hashrefs. C<true> becomes
 C<1> (C<JSON::true>), C<false> becomes C<0> (C<JSON::false>) and
 C<null> becomes C<undef>.
 
 =head2 decode_prefix
 
     ($perl_scalar, $characters) = $json->decode_prefix($json_text)
 
 This works like the C<decode> method, but instead of raising an exception
 when there is trailing garbage after the first JSON object, it will
 silently stop parsing there and return the number of characters consumed
 so far.
 
    JSON->new->decode_prefix ("[1] the tail")
    => ([], 3)
 
 =head1 INCREMENTAL PARSING
 
 Most of this section are copied and modified from L<JSON::XS/INCREMENTAL PARSING>.
 
 In some cases, there is the need for incremental parsing of JSON texts.
 This module does allow you to parse a JSON stream incrementally.
 It does so by accumulating text until it has a full JSON object, which
 it then can decode. This process is similar to using C<decode_prefix>
 to see if a full JSON object is available, but is much more efficient
 (and can be implemented with a minimum of method calls).
 
 This module will only attempt to parse the JSON text once it is sure it
 has enough text to get a decisive result, using a very simple but
 truly incremental parser. This means that it sometimes won't stop as
 early as the full parser, for example, it doesn't detect parenthese
 mismatches. The only thing it guarantees is that it starts decoding as
 soon as a syntactically valid JSON text has been seen. This means you need
 to set resource limits (e.g. C<max_size>) to ensure the parser will stop
 parsing in the presence if syntax errors.
 
 The following methods implement this incremental parser.
 
 =head2 incr_parse
 
     $json->incr_parse( [$string] ) # void context
     
     $obj_or_undef = $json->incr_parse( [$string] ) # scalar context
     
     @obj_or_empty = $json->incr_parse( [$string] ) # list context
 
 This is the central parsing function. It can both append new text and
 extract objects from the stream accumulated so far (both of these
 functions are optional).
 
 If C<$string> is given, then this string is appended to the already
 existing JSON fragment stored in the C<$json> object.
 
 After that, if the function is called in void context, it will simply
 return without doing anything further. This can be used to add more text
 in as many chunks as you want.
 
 If the method is called in scalar context, then it will try to extract
 exactly I<one> JSON object. If that is successful, it will return this
 object, otherwise it will return C<undef>. If there is a parse error,
 this method will croak just as C<decode> would do (one can then use
 C<incr_skip> to skip the errornous part). This is the most common way of
 using the method.
 
 And finally, in list context, it will try to extract as many objects
 from the stream as it can find and return them, or the empty list
 otherwise. For this to work, there must be no separators between the JSON
 objects or arrays, instead they must be concatenated back-to-back. If
 an error occurs, an exception will be raised as in the scalar context
 case. Note that in this case, any previously-parsed JSON texts will be
 lost.
 
 Example: Parse some JSON arrays/objects in a given string and return them.
 
     my @objs = JSON->new->incr_parse ("[5][7][1,2]");
 
 =head2 incr_text
 
     $lvalue_string = $json->incr_text
 
 This method returns the currently stored JSON fragment as an lvalue, that
 is, you can manipulate it. This I<only> works when a preceding call to
 C<incr_parse> in I<scalar context> successfully returned an object. Under
 all other circumstances you must not call this function (I mean it.
 although in simple tests it might actually work, it I<will> fail under
 real world conditions). As a special exception, you can also call this
 method before having parsed anything.
 
 This function is useful in two cases: a) finding the trailing text after a
 JSON object or b) parsing multiple JSON objects separated by non-JSON text
 (such as commas).
 
     $json->incr_text =~ s/\s*,\s*//;
 
 In Perl 5.005, C<lvalue> attribute is not available.
 You must write codes like the below:
 
     $string = $json->incr_text;
     $string =~ s/\s*,\s*//;
     $json->incr_text( $string );
 
 =head2 incr_skip
 
     $json->incr_skip
 
 This will reset the state of the incremental parser and will remove the
 parsed text from the input buffer. This is useful after C<incr_parse>
 died, in which case the input buffer and incremental parser state is left
 unchanged, to skip the text parsed so far and to reset the parse state.
 
 =head2 incr_reset
 
     $json->incr_reset
 
 This completely resets the incremental parser, that is, after this call,
 it will be as if the parser had never parsed anything.
 
 This is useful if you want ot repeatedly parse JSON objects and want to
 ignore any trailing data, which means you have to reset the parser after
 each successful decode.
 
 See to L<JSON::XS/INCREMENTAL PARSING> for examples.
 
 
 =head1 JSON::PP OWN METHODS
 
 =head2 allow_singlequote
 
     $json = $json->allow_singlequote([$enable])
 
 If C<$enable> is true (or missing), then C<decode> will accept
 JSON strings quoted by single quotations that are invalid JSON
 format.
 
     $json->allow_singlequote->decode({"foo":'bar'});
     $json->allow_singlequote->decode({'foo':"bar"});
     $json->allow_singlequote->decode({'foo':'bar'});
 
 As same as the C<relaxed> option, this option may be used to parse
 application-specific files written by humans.
 
 
 =head2 allow_barekey
 
     $json = $json->allow_barekey([$enable])
 
 If C<$enable> is true (or missing), then C<decode> will accept
 bare keys of JSON object that are invalid JSON format.
 
 As same as the C<relaxed> option, this option may be used to parse
 application-specific files written by humans.
 
     $json->allow_barekey->decode('{foo:"bar"}');
 
 =head2 allow_bignum
 
     $json = $json->allow_bignum([$enable])
 
 If C<$enable> is true (or missing), then C<decode> will convert
 the big integer Perl cannot handle as integer into a L<Math::BigInt>
 object and convert a floating number (any) into a L<Math::BigFloat>.
 
 On the contary, C<encode> converts C<Math::BigInt> objects and C<Math::BigFloat>
 objects into JSON numbers with C<allow_blessed> enable.
 
    $json->allow_nonref->allow_blessed->allow_bignum;
    $bigfloat = $json->decode('2.000000000000000000000000001');
    print $json->encode($bigfloat);
    # => 2.000000000000000000000000001
 
 See to L<JSON::XS/MAPPING> aboout the normal conversion of JSON number.
 
 =head2 loose
 
     $json = $json->loose([$enable])
 
 The unescaped [\x00-\x1f\x22\x2f\x5c] strings are invalid in JSON strings
 and the module doesn't allow to C<decode> to these (except for \x2f).
 If C<$enable> is true (or missing), then C<decode>  will accept these
 unescaped strings.
 
     $json->loose->decode(qq|["abc
                                    def"]|);
 
 See L<JSON::XS/SSECURITY CONSIDERATIONS>.
 
 =head2 escape_slash
 
     $json = $json->escape_slash([$enable])
 
 According to JSON Grammar, I<slash> (U+002F) is escaped. But default
 JSON::PP (as same as JSON::XS) encodes strings without escaping slash.
 
 If C<$enable> is true (or missing), then C<encode> will escape slashes.
 
 =head2 indent_length
 
     $json = $json->indent_length($length)
 
 JSON::XS indent space length is 3 and cannot be changed.
 JSON::PP set the indent space length with the given $length.
 The default is 3. The acceptable range is 0 to 15.
 
 =head2 sort_by
 
     $json = $json->sort_by($function_name)
     $json = $json->sort_by($subroutine_ref)
 
 If $function_name or $subroutine_ref are set, its sort routine are used
 in encoding JSON objects.
 
    $js = $pc->sort_by(sub { $JSON::PP::a cmp $JSON::PP::b })->encode($obj);
    # is($js, q|{"a":1,"b":2,"c":3,"d":4,"e":5,"f":6,"g":7,"h":8,"i":9}|);
 
    $js = $pc->sort_by('own_sort')->encode($obj);
    # is($js, q|{"a":1,"b":2,"c":3,"d":4,"e":5,"f":6,"g":7,"h":8,"i":9}|);
 
    sub JSON::PP::own_sort { $JSON::PP::a cmp $JSON::PP::b }
 
 As the sorting routine runs in the JSON::PP scope, the given
 subroutine name and the special variables C<$a>, C<$b> will begin
 'JSON::PP::'.
 
 If $integer is set, then the effect is same as C<canonical> on.
 
 =head1 INTERNAL
 
 For developers.
 
 =over
 
 =item PP_encode_box
 
 Returns
 
         {
             depth        => $depth,
             indent_count => $indent_count,
         }
 
 
 =item PP_decode_box
 
 Returns
 
         {
             text    => $text,
             at      => $at,
             ch      => $ch,
             len     => $len,
             depth   => $depth,
             encoding      => $encoding,
             is_valid_utf8 => $is_valid_utf8,
         };
 
 =back
 
 =head1 MAPPING
 
 This section is copied from JSON::XS and modified to C<JSON::PP>.
 JSON::XS and JSON::PP mapping mechanisms are almost equivalent.
 
 See to L<JSON::XS/MAPPING>.
 
 =head2 JSON -> PERL
 
 =over 4
 
 =item object
 
 A JSON object becomes a reference to a hash in Perl. No ordering of object
 keys is preserved (JSON does not preserver object key ordering itself).
 
 =item array
 
 A JSON array becomes a reference to an array in Perl.
 
 =item string
 
 A JSON string becomes a string scalar in Perl - Unicode codepoints in JSON
 are represented by the same codepoints in the Perl string, so no manual
 decoding is necessary.
 
 =item number
 
 A JSON number becomes either an integer, numeric (floating point) or
 string scalar in perl, depending on its range and any fractional parts. On
 the Perl level, there is no difference between those as Perl handles all
 the conversion details, but an integer may take slightly less memory and
 might represent more values exactly than floating point numbers.
 
 If the number consists of digits only, C<JSON> will try to represent
 it as an integer value. If that fails, it will try to represent it as
 a numeric (floating point) value if that is possible without loss of
 precision. Otherwise it will preserve the number as a string value (in
 which case you lose roundtripping ability, as the JSON number will be
 re-encoded toa JSON string).
 
 Numbers containing a fractional or exponential part will always be
 represented as numeric (floating point) values, possibly at a loss of
 precision (in which case you might lose perfect roundtripping ability, but
 the JSON number will still be re-encoded as a JSON number).
 
 Note that precision is not accuracy - binary floating point values cannot
 represent most decimal fractions exactly, and when converting from and to
 floating point, C<JSON> only guarantees precision up to but not including
 the leats significant bit.
 
 When C<allow_bignum> is enable, the big integers 
 and the numeric can be optionally converted into L<Math::BigInt> and
 L<Math::BigFloat> objects.
 
 =item true, false
 
 These JSON atoms become C<JSON::PP::true> and C<JSON::PP::false>,
 respectively. They are overloaded to act almost exactly like the numbers
 C<1> and C<0>. You can check wether a scalar is a JSON boolean by using
 the C<JSON::is_bool> function.
 
    print JSON::PP::true . "\n";
     => true
    print JSON::PP::true + 1;
     => 1
 
    ok(JSON::true eq  '1');
    ok(JSON::true == 1);
 
 C<JSON> will install these missing overloading features to the backend modules.
 
 
 =item null
 
 A JSON null atom becomes C<undef> in Perl.
 
 C<JSON::PP::null> returns C<unddef>.
 
 =back
 
 
 =head2 PERL -> JSON
 
 The mapping from Perl to JSON is slightly more difficult, as Perl is a
 truly typeless language, so we can only guess which JSON type is meant by
 a Perl value.
 
 =over 4
 
 =item hash references
 
 Perl hash references become JSON objects. As there is no inherent ordering
 in hash keys (or JSON objects), they will usually be encoded in a
 pseudo-random order that can change between runs of the same program but
 stays generally the same within a single run of a program. C<JSON>
 optionally sort the hash keys (determined by the I<canonical> flag), so
 the same datastructure will serialise to the same JSON text (given same
 settings and version of JSON::XS), but this incurs a runtime overhead
 and is only rarely useful, e.g. when you want to compare some JSON text
 against another for equality.
 
 
 =item array references
 
 Perl array references become JSON arrays.
 
 =item other references
 
 Other unblessed references are generally not allowed and will cause an
 exception to be thrown, except for references to the integers C<0> and
 C<1>, which get turned into C<false> and C<true> atoms in JSON. You can
 also use C<JSON::false> and C<JSON::true> to improve readability.
 
    to_json [\0,JSON::PP::true]      # yields [false,true]
 
 =item JSON::PP::true, JSON::PP::false, JSON::PP::null
 
 These special values become JSON true and JSON false values,
 respectively. You can also use C<\1> and C<\0> directly if you want.
 
 JSON::PP::null returns C<undef>.
 
 =item blessed objects
 
 Blessed objects are not directly representable in JSON. See the
 C<allow_blessed> and C<convert_blessed> methods on various options on
 how to deal with this: basically, you can choose between throwing an
 exception, encoding the reference as if it weren't blessed, or provide
 your own serialiser method.
 
 See to L<convert_blessed>.
 
 =item simple scalars
 
 Simple Perl scalars (any scalar that is not a reference) are the most
 difficult objects to encode: JSON::XS and JSON::PP will encode undefined scalars as
 JSON C<null> values, scalars that have last been used in a string context
 before encoding as JSON strings, and anything else as number value:
 
    # dump as number
    encode_json [2]                      # yields [2]
    encode_json [-3.0e17]                # yields [-3e+17]
    my $value = 5; encode_json [$value]  # yields [5]
 
    # used as string, so dump as string
    print $value;
    encode_json [$value]                 # yields ["5"]
 
    # undef becomes null
    encode_json [undef]                  # yields [null]
 
 You can force the type to be a string by stringifying it:
 
    my $x = 3.1; # some variable containing a number
    "$x";        # stringified
    $x .= "";    # another, more awkward way to stringify
    print $x;    # perl does it for you, too, quite often
 
 You can force the type to be a number by numifying it:
 
    my $x = "3"; # some variable containing a string
    $x += 0;     # numify it, ensuring it will be dumped as a number
    $x *= 1;     # same thing, the choise is yours.
 
 You can not currently force the type in other, less obscure, ways.
 
 Note that numerical precision has the same meaning as under Perl (so
 binary to decimal conversion follows the same rules as in Perl, which
 can differ to other languages). Also, your perl interpreter might expose
 extensions to the floating point numbers of your platform, such as
 infinities or NaN's - these cannot be represented in JSON, and it is an
 error to pass those in.
 
 =item Big Number
 
 When C<allow_bignum> is enable, 
 C<encode> converts C<Math::BigInt> objects and C<Math::BigFloat>
 objects into JSON numbers.
 
 
 =back
 
 =head1 UNICODE HANDLING ON PERLS
 
 If you do not know about Unicode on Perl well,
 please check L<JSON::XS/A FEW NOTES ON UNICODE AND PERL>.
 
 =head2 Perl 5.8 and later
 
 Perl can handle Unicode and the JSON::PP de/encode methods also work properly.
 
     $json->allow_nonref->encode(chr hex 3042);
     $json->allow_nonref->encode(chr hex 12345);
 
 Reuturns C<"\u3042"> and C<"\ud808\udf45"> respectively.
 
     $json->allow_nonref->decode('"\u3042"');
     $json->allow_nonref->decode('"\ud808\udf45"');
 
 Returns UTF-8 encoded strings with UTF8 flag, regarded as C<U+3042> and C<U+12345>.
 
 Note that the versions from Perl 5.8.0 to 5.8.2, Perl built-in C<join> was broken,
 so JSON::PP wraps the C<join> with a subroutine. Thus JSON::PP works slow in the versions.
 
 
 =head2 Perl 5.6
 
 Perl can handle Unicode and the JSON::PP de/encode methods also work.
 
 =head2 Perl 5.005
 
 Perl 5.005 is a byte sementics world -- all strings are sequences of bytes.
 That means the unicode handling is not available.
 
 In encoding,
 
     $json->allow_nonref->encode(chr hex 3042);  # hex 3042 is 12354.
     $json->allow_nonref->encode(chr hex 12345); # hex 12345 is 74565.
 
 Returns C<B> and C<E>, as C<chr> takes a value more than 255, it treats
 as C<$value % 256>, so the above codes are equivalent to :
 
     $json->allow_nonref->encode(chr 66);
     $json->allow_nonref->encode(chr 69);
 
 In decoding,
 
     $json->decode('"\u00e3\u0081\u0082"');
 
 The returned is a byte sequence C<0xE3 0x81 0x82> for UTF-8 encoded
 japanese character (C<HIRAGANA LETTER A>).
 And if it is represented in Unicode code point, C<U+3042>.
 
 Next, 
 
     $json->decode('"\u3042"');
 
 We ordinary expect the returned value is a Unicode character C<U+3042>.
 But here is 5.005 world. This is C<0xE3 0x81 0x82>.
 
     $json->decode('"\ud808\udf45"');
 
 This is not a character C<U+12345> but bytes - C<0xf0 0x92 0x8d 0x85>.
 
 
 =head1 TODO
 
 =over
 
 =item speed
 
 =item memory saving
 
 =back
 
 
 =head1 SEE ALSO
 
 Most of the document are copied and modified from JSON::XS doc.
 
 L<JSON::XS>
 
 RFC4627 (L<http://www.ietf.org/rfc/rfc4627.txt>)
 
 =head1 AUTHOR
 
 Makamaka Hannyaharamitu, E<lt>makamaka[at]cpan.orgE<gt>
 
 
 =head1 COPYRIGHT AND LICENSE
 
 Copyright 2007-2014 by Makamaka Hannyaharamitu
 
 This library is free software; you can redistribute it and/or modify
 it under the same terms as Perl itself. 
 
 =cut
### JSON/PP/Boolean.pm ###
 =head1 NAME
 
 JSON::PP::Boolean - dummy module providing JSON::PP::Boolean
 
 =head1 SYNOPSIS
 
  # do not "use" yourself
 
 =head1 DESCRIPTION
 
 This module exists only to provide overload resolution for Storable and similar modules. See
 L<JSON::PP> for more info about this class.
 
 =cut
 
 use JSON::PP ();
 use strict;
 
 1;
 
 =head1 AUTHOR
 
 This idea is from L<JSON::XS::Boolean> written by Marc Lehmann <schmorp[at]schmorp.de>
 
 =cut
 
### LWP.pm ###
 package LWP;
 
 $VERSION = "6.13";
 sub Version { $VERSION; }
 
 require 5.008;
 require LWP::UserAgent;  # this should load everything you need
 
 1;
 
 __END__
 
 =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 http, https, gopher, ftp, news,
 file, and 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
 <URL: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 C<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 C<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 C<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 C<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 C<HTTP::Request> object as
 argument and (eventually) returns a C<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 E<lt>head> section of HTML documents.
 
 =item *
 
 B<proxy> and B<no_proxy> specify if and when to go through
 a proxy server. <URL: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
 C<LWP::UserAgent>.  The library includes a
 sub-class, C<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 $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 $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 a "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 C<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 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 the 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 C<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 C<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 C<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 C<URI>.
 You might want to set it to C<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 GuentherDaniel 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
### LWP/Authen/Basic.pm ###
 package LWP::Authen::Basic;
 use strict;
 
 require MIME::Base64;
 
 sub auth_header {
     my($class, $user, $pass) = @_;
     return "Basic " . MIME::Base64::encode("$user:$pass", "");
 }
 
 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;
 
     if (!$proxy && !$request->header($auth_header) && $ua->credentials($host_port, $realm)) {
 	# we can make sure this handler applies and retry
         add_path($h, $url->path);
         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;
### LWP/Authen/Digest.pm ###
 package LWP::Authen::Digest;
 
 use strict;
 use base 'LWP::Authen::Basic';
 
 require Digest::MD5;
 
 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);
     if($request->method =~ /^(?:POST|PUT)$/) {
 	$md5->add($request->content);
 	my $content = $md5->hexdigest;
 	$md5->reset;
 	$md5->add(join(":", @digest[0..1], $content));
 	$md5->reset;
 	$resp{"message-digest"} = $md5->hexdigest;
 	push(@order, "message-digest");
     }
     push(@order, "opaque");
     my @pairs;
     for (@order) {
 	next unless defined $resp{$_};
 
 	# RFC2617 sais 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;
### LWP/Authen/Ntlm.pm ###
 package LWP::Authen::Ntlm;
 
 use strict;
 use vars qw/$VERSION/;
 
 $VERSION = "6.13";
 
 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;
 
 
 =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
 
 C<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 Mime::Base64, which Bush's Authen::NTLM makes use of.  Therefore, it is 
 necessary to ensure that your Mime::Base64 module supports exporting of the 
 encode_base64 and 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 "keep_alive=>1" option to the 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 HTTP::Request object's authorization_basic() method to set 
 the credentials.  Note, too, that the '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>.
### LWP/ConnCache.pm ###
 package LWP::ConnCache;
 
 use strict;
 use vars qw($VERSION $DEBUG);
 
 $VERSION = "6.13";
 
 
 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__
 
 =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 LWP::UserAgent.
 
 The following basic methods are provided:
 
 =over
 
 =item $cache = LWP::ConnCache->new( %options )
 
 This method constructs a new C<LWP::ConnCache> object.  The only
 option currently accepted is 'total_capacity'.  If specified it
 initialize the total_capacity option.  It defaults to the value 1.
 
 =item $cache->total_capacity( [$num_connections] )
 
 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.
 
 =item $cache->capacity($type, [$num_connections] )
 
 Get/set a limit for the number of connections of the specified type
 that can be cached.  The $type will typically be a short string like
 "http" or "ftp".
 
 =item $cache->drop( [$checker, [$reason]] )
 
 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 ($conn, $type, $key, $deposit_time) as arguments.
 
 Shortcuts: If the $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 $reason argument is passed on to the dropped() method.
 
 =item $cache->prune
 
 Calling this method will drop all connections that are dead.  This is
 tested by calling the ping() method on the connections.  If the ping()
 method exists and returns a FALSE value, then the connection is
 dropped.
 
 =item $cache->get_types
 
 This returns all the 'type' fields used for the currently cached
 connections.
 
 =item $cache->get_connections( [$type] )
 
 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.
 
 =back
 
 
 The following methods are called by low-level protocol modules to
 try to save away connections and to get them back.
 
 =over
 
 =item $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 added.
 
 =item $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.
 
 =back
 
 The following methods are called internally.  Subclasses might want to
 override them.
 
 =over
 
 =item $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.
 
 =item $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
 $LWP::ConnCache::DEBUG variable is set and nothing more.
 
 =back
 
 =head1 SUBCLASSING
 
 For specialized cache policy it makes sense to subclass
 C<LWP::ConnCache> and perhaps override the deposit(), enforce_limits()
 and 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.
### LWP/Debug.pm ###
 package LWP::Debug;  # legacy
 
 require Exporter;
 @ISA = qw(Exporter);
 @EXPORT_OK = qw(level trace debug conns);
 
 use Carp ();
 
 my @levels = qw(trace debug conns);
 %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__
 
 =head1 NAME
 
 LWP::Debug - deprecated
 
 =head1 DESCRIPTION
 
 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 Wireshark program
 (L<http://www.wireshark.org/>) 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::UserAgent>
### LWP/DebugFile.pm ###
 package LWP::DebugFile;
 
 # legacy stub
 
 1;
### LWP/MemberMixin.pm ###
 package LWP::MemberMixin;
 
 sub _elem
 {
     my $self = shift;
     my $elem = shift;
     my $old = $self->{$elem};
     $self->{$elem} = shift if @_;
     return $old;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 LWP::MemberMixin - Member access mixin class
 
 =head1 SYNOPSIS
 
  package Foo;
  require LWP::MemberMixin;
  @ISA=qw(LWP::MemberMixin);
 
 =head1 DESCRIPTION
 
 A mixin class to get methods that provide easy access to member
 variables in the %$self.
 Ideally there should be better Perl language support for this.
 
 There is only one method provided:
 
 =over 4
 
 =item _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.
 
 =back
### LWP/Protocol.pm ###
 package LWP::Protocol;
 
 require LWP::MemberMixin;
 @ISA = qw(LWP::MemberMixin);
 $VERSION = "6.13";
 
 use strict;
 use Carp ();
 use HTTP::Status ();
 use HTTP::Response;
 
 my %ImplementedBy = (); # scheme => classname
 
 
 
 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};
     return $ic if $ic;
 
     return '' unless $scheme =~ /^([.+\-\w]+)$/;  # check valid URL schemes
     $scheme = $1; # untaint
     $scheme =~ s/[.+\-]/_/g;  # make it a legal module name
 
     # scheme not yet known, look for a 'use'd implementation
     $ic = "LWP::Protocol::$scheme";  # 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
 	eval "require $ic";
 	if ($@) {
 	    if ($@ =~ /Can't locate/) { #' #emacs get confused by '
 		$ic = '';
 	    }
 	    else {
 		die "$@\n";
 	    }
 	}
     }
     $ImplementedBy{$scheme} = $ic if $ic;
     $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)};
 
     eval {
 	local $\; # protect the print below from surprises
         if (!defined($arg) || !$response->is_success) {
             $response->{default_add_content} = 1;
         }
         elsif (!ref($arg) && length($arg)) {
             open(my $fh, ">", $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 {
 		    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;
             }
         }
     };
     my $err = $@;
     delete $response->{handlers}{response_data};
     delete $response->{handlers} unless %{$response->{handlers}};
     if ($err) {
         chomp($err);
         $response->push_header('X-Died' => $err);
         $response->push_header("Client-Aborted", "die");
         return $response;
     }
 
     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__
 
 =head1 NAME
 
 LWP::Protocol - Base class for LWP protocols
 
 =head1 SYNOPSIS
 
  package LWP::Protocol::foo;
  require LWP::Protocol;
  @ISA=qw(LWP::Protocol);
 
 =head1 DESCRIPTION
 
 This class is used a 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
 LWP::Protocol::create() function calls the constructor for one of its
 subclasses.
 
 All derived LWP::Protocol classes need to override the request()
 method which is used to service a request. The overridden method can
 make use of the collect() function to collect together chunks of data
 as it is received.
 
 The following methods and functions are provided:
 
 =over 4
 
 =item $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.
 
 =item $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.
 
 =item $class = LWP::Protocol::implementor($scheme, [$class])
 
 Get and/or set implementor class for a scheme.  Returns '' if the
 specified scheme is not supported.
 
 =item $prot->request(...)
 
  $response = $protocol->request($request, $proxy, undef);
  $response = $protocol->request($request, $proxy, '/tmp/sss');
  $response = $protocol->request($request, $proxy, \&callback, 1024);
 
 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.
 
 =item $prot->collect($arg, $response, $collector)
 
 Called to collect the content of a request, and process it
 appropriately into a scalar, file, or by calling a callback.  If $arg
 is undefined, then the content is stored within the $response.  If
 $arg is a simple scalar, then $arg is interpreted as a file name and
 the content is written to this file.  If $arg is a reference to a
 routine, then content is passed to this routine.
 
 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 $collector signals EOF by returning a reference to an
 empty string.
 
 The return value from collect() is the $response object reference.
 
 B<Note:> We will only use the callback or file argument if
 $response->is_success().  This avoids sending content data for
 redirects and authentication responses to the callback which would be
 confusing.
 
 =item $prot->collect_once($arg, $response, $content)
 
 Can be called when the whole response content is available as
 $content.  This will invoke collect() with a collector callback that
 returns a reference to $content the first time and an empty string the
 next.
 
 =back
 
 =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.
### LWP/Protocol/GHTTP.pm ###
 package LWP::Protocol::GHTTP;
 
 # You can tell LWP to use this module for 'http' requests by running
 # code like this before you make requests:
 #
 #    require LWP::Protocol::GHTTP;
 #    LWP::Protocol::implementor('http', 'LWP::Protocol::GHTTP');
 #
 
 use strict;
 use vars qw(@ISA);
 
 require LWP::Protocol;
 @ISA=qw(LWP::Protocol);
 
 require HTTP::Response;
 require HTTP::Status;
 
 use HTTP::GHTTP qw(METHOD_GET METHOD_HEAD METHOD_POST);
 
 my %METHOD =
 (
  GET  => METHOD_GET,
  HEAD => METHOD_HEAD,
  POST => METHOD_POST,
 );
 
 sub request
 {
     my($self, $request, $proxy, $arg, $size, $timeout) = @_;
 
     my $method = $request->method;
     unless (exists $METHOD{$method}) {
 	return HTTP::Response->new(&HTTP::Status::RC_BAD_REQUEST,
 				   "Bad method '$method'");
     }
 
     my $r = HTTP::GHTTP->new($request->uri);
 
     # XXX what headers for repeated headers here?
     $request->headers->scan(sub { $r->set_header(@_)});
 
     $r->set_type($METHOD{$method});
 
     # XXX should also deal with subroutine content.
     my $cref = $request->content_ref;
     $r->set_body($$cref) if length($$cref);
 
     # XXX is this right
     $r->set_proxy($proxy->as_string) if $proxy;
 
     $r->process_request;
 
     my $response = HTTP::Response->new($r->get_status);
 
     # XXX How can get the headers out of $r??  This way is too stupid.
     my @headers;
     eval {
 	# Wrapped in eval because this method is not always available
 	@headers = $r->get_headers;
     };
     @headers = qw(Date Connection Server Content-type
                   Accept-Ranges Server
                   Content-Length Last-Modified ETag) if $@;
     for (@headers) {
 	my $v = $r->get_header($_);
 	$response->header($_ => $v) if defined $v;
     }
 
     return $self->collect_once($arg, $response, $r->get_body);
 }
 
 1;
### LWP/Protocol/cpan.pm ###
 package LWP::Protocol::cpan;
 
 use strict;
 use vars qw(@ISA);
 
 require LWP::Protocol;
 @ISA = qw(LWP::Protocol);
 
 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;
### LWP/Protocol/data.pm ###
 package LWP::Protocol::data;
 
 # Implements access to data:-URLs as specified in RFC 2397
 
 use strict;
 use vars qw(@ISA);
 
 require HTTP::Response;
 require HTTP::Status;
 
 require LWP::Protocol;
 @ISA = 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;
### LWP/Protocol/file.pm ###
 package LWP::Protocol::file;
 
 require LWP::Protocol;
 @ISA = qw(LWP::Protocol);
 
 use strict;
 
 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(F, $path) or return new
 	    HTTP::Response(&HTTP::Status::RC_INTERNAL_SERVER_ERROR,
 			   "Cannot read file '$path': $!");
 	binmode(F);
 	$response =  $self->collect($arg, $response, sub {
 	    my $content = "";
 	    my $bytes = sysread(F, $content, $size);
 	    return \$content if $bytes > 0;
 	    return \ "";
 	});
 	close(F);
     }
 
     $response;
 }
 
 1;
### LWP/Protocol/ftp.pm ###
 package LWP::Protocol::ftp;
 
 # Implementation of the ftp protocol (RFC 959). We let the Net::FTP
 # package do all the dirty work.
 
 use Carp ();
 
 use HTTP::Status ();
 use HTTP::Negotiate ();
 use HTTP::Response ();
 use LWP::MediaTypes ();
 use File::Listing ();
 
 require LWP::Protocol;
 @ISA = qw(LWP::Protocol);
 
 use strict;
 eval {
     package LWP::Protocol::MyFTP;
 
     require Net::FTP;
     Net::FTP->require_version(2.00);
 
     use vars qw(@ISA);
     @ISA=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;
     }
 
 };
 my $init_failed = $@;
 
 
 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");
     }
 
     if ($init_failed) {
 	return HTTP::Response->new(&HTTP::Status::RC_INTERNAL_SERVER_ERROR,
 				   $init_failed);
     }
 
     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.
### LWP/Protocol/gopher.pm ###
 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;
 use vars qw(@ISA);
 
 require HTTP::Response;
 require HTTP::Status;
 require IO::Socket;
 require IO::Select;
 
 require LWP::Protocol;
 @ISA = 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 =~ s/\015//g;  # 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;
### LWP/Protocol/http.pm ###
 package LWP::Protocol::http;
 
 use strict;
 
 require HTTP::Response;
 require HTTP::Status;
 require Net::HTTP;
 
 use vars qw(@ISA @EXTRA_SOCK_OPTS);
 
 require LWP::Protocol;
 @ISA = qw(LWP::Protocol);
 
 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    => 1,
 					$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(certificate verify failed)\b/ ||
 	    $@ =~ /\b(Crypt-SSLeay can't verify hostnames)\b/
 	) {
 	    $status .= " ($1)";
 	}
 	die "$status\n\n$@";
     }
 
     # perl 5.005's IO::Socket does not have the blocking method.
     eval { $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.":".$url->port;
 
     my ($host,$port) = $proxy
 	? ($proxy->host,$proxy->port)
 	: ($url->host,$url->port);
     my $fullpath =
 	$method eq 'CONNECT' ? $url->host . ":" . $url->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 immediatly 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
 	}
     }
 
     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 =~ s/\n/ /g;
 			       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 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 LWP::Protocol::http::Socket;
 use vars qw(@ISA);
 @ISA = qw(LWP::Protocol::http::SocketMethods Net::HTTP);
 
 1;
### LWP/Protocol/http/SocketUnixAlt.pm ###
 package LWP::Protocol::http::SocketUnixAlt;
 
 use 5.010001;
 use strict;
 use warnings;
 use vars qw( @ISA $VERSION );
 use IO::Socket;
 use LWP::Protocol::http;
 
 @ISA = qw( LWP::Protocol::http );
 
 our $VERSION = '0.0204'; # VERSION
 
 sub _new_socket {
 	my ($self, $path, $timeout) = @_;
 
 	local($^W) = 0;
 	my $sock = $self->socket_class->new(
 			Peer	=> $path,
 			Type	=> SOCK_STREAM,
 			Timeout	=> $timeout,
 			Host    => 'localhost',
 	);
 
 	unless($sock) {
 		$@ =~ s/^.*?: //;
 		die "Can't open socket $path\: $@";
 	}
 
 	eval { $sock->blocking(0); };
 
 	$sock;
 }
 
 sub request {
     my($self, $request, undef, $arg, $size, $timeout) = @_;
     #LWP::Debug::trace('()');
 
     $size ||= 4096;
 
     # check method
     my $method = $request->method;
     unless ($method =~ /^[A-Za-z0-9_!\#\$%&\'*+\-.^\`|~]+$/) {  # HTTP token
 		return new HTTP::Response &HTTP::Status::RC_BAD_REQUEST,
 				  'Library does not allow method ' .
 				  "$method for 'http:' URLs";
     }
 
     my $url = $request->url;
 	my $path = $url->path_query;
 	my $fullpath;
 	if ($path =~ s!/(/.+)!!) {
 		$fullpath = $1;
 	} else {
 		$fullpath = "/";
 	}
 
     # connect to remote site
     my $socket = $self->_new_socket($path, $timeout);
     $self->_check_sock($request, $socket);
 
     my @h;
     my $request_headers = $request->headers->clone;
     $self->_fixup_header($request_headers, $url);
 
     $request_headers->scan(sub {
 			       my($k, $v) = @_;
 			       $v =~ s/\n/ /g;
 			       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++;
 			if (!defined($clen) || $clen ne length($$content_ref)) {
 				if (defined $clen) {
 					warn "Content-Length header value was wrong, fixed";
 					hlist_remove(\@h, 'Content-Length');
 				}
 				push(@h, 'Content-Length' => length($$content_ref));
 			}
 		} elsif ($clen) {
 			warn "Content-Length set when there is not content, fixed";
 			hlist_remove(\@h, 'Content-Length');
 		}
     }
 
     my $req_buf = $socket->format_request($method, $fullpath, @h);
     #print "------\n$req_buf\n------\n";
 
     # XXX need to watch out for write timeouts
     {
 		my $n = $socket->syswrite($req_buf, length($req_buf));
 		die $! unless defined($n);
 		die "short write" unless $n == length($req_buf);
 		#LWP::Debug::conns($req_buf);
     }
 
     my($code, $mess, @junk);
 
     if ($has_content) {
 		my $write_wait = 0;
 		$write_wait = 2
 			if ($request_headers->header("Expect") || "") =~ /100-continue/;
 
 		my $eof;
 		my $wbuf;
 		my $woffset = 0;
 		if (ref($content_ref) eq 'CODE') {
 			my $buf = &$content_ref();
 			$buf = "" unless defined($buf);
 			$buf = sprintf "%x%s%s%s", length($buf), $LWP::Protocol::http::CRLF,
 				$buf, $LWP::Protocol::http::CRLF if $chunked;
 			$wbuf = \$buf;
 		} else {
 			$wbuf = $content_ref;
 			$eof = 1;
 		}
 
 		my $fbits = '';
 		vec($fbits, fileno($socket), 1) = 1;
 
 		while ($woffset < length($$wbuf)) {
 
 			my $time_before;
 			my $sel_timeout = $timeout;
 			if ($write_wait) {
 				$time_before = time;
 				$sel_timeout = $write_wait if $write_wait < $sel_timeout;
 			}
 
 			my $rbits = $fbits;
 			my $wbits = $write_wait ? undef : $fbits;
 			my $nfound = select($rbits, $wbits, undef, $sel_timeout);
 			unless (defined $nfound) {
 				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 ($n) {
 					die "EOF";
 				}
 				$socket->_rbuf($buf);
 				if ($buf =~ /\015?\012\015?\012/) {
 					# a whole response present
 					($code, $mess, @h) = $socket->read_response_headers(laxed => 1,
 											junk_out => \@junk,
 											   );
 					if ($code eq "100") {
 						$write_wait = 0;
 						undef($code);
 					} else {
 						last;
 						# 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 ($n) {
 					die "syswrite: $!" unless defined $n;
 					die "syswrite: 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), $LWP::Protocol::http::CRLF,
 						$buf, $LWP::Protocol::http::CRLF if $chunked;
 					$wbuf = \$buf;
 					$woffset = 0;
 				}
 			}
 		}
     }
 
     ($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");
     while (@h) {
 		my($k, $v) = splice(@h, 0, 2);
 		$response->push_header($k, $v);
     }
     $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', $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);
 			die "Can't read entity body: $!" unless defined $n;
 			redo READ if $n == -1;
 		}
 		$complete++ if !$n;
 			return \$buf;
     } );
 
     @h = $socket->get_trailers;
     while (@h) {
 		my($k, $v) = splice(@h, 0, 2);
 		$response->push_header($k, $v);
     }
 
     $response;
 }
 
 package LWP::Protocol::http::SocketUnixAlt::Socket;
 
 use strict;
 use warnings;
 use vars qw( @ISA );
 
 @ISA =qw(	LWP::Protocol::http::SocketMethods
 			Net::HTTP::Methods
 			IO::Socket::UNIX
 		);
 
 sub configure {
 	my ($self, $cnf) = @_;
 	$self->http_configure($cnf);
 }
 
 sub http_connect {
 	my ($self, $cnf) = @_;
 	$self->SUPER::configure($cnf);
 }
 
 # Just to avoid some errors. We don't really need this.
 sub peerport { }
 sub peerhost { }
 
 1;
 # ABSTRACT: Speak HTTP through Unix sockets
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 LWP::Protocol::http::SocketUnixAlt - Speak HTTP through Unix sockets
 
 =head1 VERSION
 
 version 0.0204
 
 =head1 SYNOPSIS
 
   use LWP::Protocol::http::SocketUnixAlt;
   LWP::Protocol::implementor( http => 'LWP::Protocol::http::SocketUnixAlt' );
   ...
 
 =head1 DESCRIPTION
 
 LWP::Protocol::http::UnixSocketAlt is a fork of Florian Ragwitz's
 L<LWP::Protocol::http::SocketUnix> 0.02. It fixes a few issues including:
 
 =over 4
 
 =item * remedy 'No Host options provided' error
 
 As suggested in https://rt.cpan.org/Public/Bug/Display.html?id=65670
 
 =item * allow specifying URI path
 
 Currently using "//" as separator, e.g.: "http:path/to/unix.socket//uri/path"
 
 =back
 
 =head1 SEE ALSO
 
 L<LWP>, L<LWP::Protocol>
 
 L<HTTP::Daemon::UNIX>
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/LWP-Protocol-http-SocketUnixAlt>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-LWP-Protocol-http-SocketUnixAlt>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=LWP-Protocol-http-SocketUnixAlt>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 Steven Haryanto <stevenharyanto@gmail.com>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2014 by Steven Haryanto.
 
 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
### LWP/Protocol/loopback.pm ###
 package LWP::Protocol::loopback;
 
 use strict;
 use vars qw(@ISA);
 require HTTP::Response;
 
 require LWP::Protocol;
 @ISA = 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;
### LWP/Protocol/mailto.pm ###
 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 LWP::Protocol;
 require HTTP::Request;
 require HTTP::Response;
 require HTTP::Status;
 
 use Carp;
 use strict;
 use vars qw(@ISA $SENDMAIL);
 
 @ISA = qw(LWP::Protocol);
 
 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;
### LWP/Protocol/nntp.pm ###
 package LWP::Protocol::nntp;
 
 # Implementation of the Network News Transfer Protocol (RFC 977)
 
 require LWP::Protocol;
 @ISA = qw(LWP::Protocol);
 
 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; $nntp = undef;
 	$response->code(&HTTP::Status::RC_NOT_FOUND);
 	$response->message($nntp->message);
 	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;
### LWP/Protocol/nogo.pm ###
 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;
 use vars qw(@ISA);
 require HTTP::Response;
 require HTTP::Status;
 require LWP::Protocol;
 @ISA = 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;
### LWP/RobotUA.pm ###
 package LWP::RobotUA;
 
 require LWP::UserAgent;
 @ISA = qw(LWP::UserAgent);
 $VERSION = "6.13";
 
 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__
 
 =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
 <URL: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 LWP::UserAgent and implements the
 same methods. In addition the following methods are provided:
 
 =over 4
 
 =item $ua = LWP::RobotUA->new( %options )
 
 =item $ua = LWP::RobotUA->new( $agent, $from )
 
 =item $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
 C<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.
 
 =item $ua->delay
 
 =item $ua->delay( $minutes )
 
 Get/set the minimum delay between requests to the same server, in
 I<minutes>.  The default is 1 minute.  Note that this number doesn't
 have to be an integer; for example, this sets the delay to 10 seconds:
 
     $ua->delay(10/60);
 
 =item $ua->use_sleep
 
 =item $ua->use_sleep( $boolean )
 
 Get/set a value indicating whether the UA should sleep() if requests
 arrive too fast, defined as $ua->delay minutes not passed since
 last request to the given server.  The default is TRUE.  If this value is
 FALSE then an internal SERVICE_UNAVAILABLE response will be generated.
 It will have a Retry-After header that indicates when it is OK to
 send another request to this server.
 
 =item $ua->rules
 
 =item $ua->rules( $rules )
 
 Set/get which I<WWW::RobotRules> object to use.
 
 =item $ua->no_visits( $netloc )
 
 Returns the number of documents fetched from this server host. Yeah I
 know, this method should probably have been named num_visits() or
 something like that. :-(
 
 =item $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.
 
 =item $ua->as_string
 
 Returns a string that describes the state of the UA.
 Mainly useful for debugging.
 
 =back
 
 =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.
### LWP/Simple.pm ###
 package LWP::Simple;
 
 use strict;
 use vars qw($ua %loop_check $FULL_LWP @EXPORT @EXPORT_OK $VERSION);
 
 require Exporter;
 
 @EXPORT = qw(get head getprint getstore mirror);
 @EXPORT_OK = qw($ua);
 
 # I really hate this.  I 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);
 
 $VERSION = "6.13";
 
 sub import
 {
     my $pkg = shift;
     my $callpkg = caller;
     Exporter::export($pkg, $callpkg, @_);
 }
 
 use LWP::UserAgent ();
 use HTTP::Status ();
 use HTTP::Date ();
 $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__
 
 =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 C<LWP::UserAgent> module.
 
 The following functions are provided (and exported) by this module:
 
 =over 3
 
 =item 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 $url argument can
 be either a string or a reference to a URI object.
 
 You will not be able to examine the response code or response headers
 (like '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>).
 
 =item 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.
 
 =item 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.
 
 =item getstore($url, $file)
 
 Gets a document identified by a URL and stores it in the file. The
 return value is the HTTP response code.
 
 =item 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.
 
 =back
 
 This module also exports the HTTP::Status constants and procedures.
 You can use them when you check the response code from getprint(),
 getstore() or 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
 
 The HTTP::Status classification functions are:
 
 =over 3
 
 =item is_success($rc)
 
 True if response code indicated a successful request.
 
 =item is_error($rc)
 
 True if response code indicated that an error occurred.
 
 =back
 
 The module will also export the LWP::UserAgent object as C<$ua> if you
 ask for it explicitly.
 
 The user agent created by this module will identify itself as
 "LWP::Simple/#.##"
 and will initialize its proxy defaults from the environment (by
 calling $ua->env_proxy).
 
 =head1 CAVEAT
 
 Note that if you are using both LWP::Simple and the very popular CGI.pm
 module, you may be importing a C<head> function from each module,
 producing a warning like "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>
### LWP/UserAgent.pm ###
 package LWP::UserAgent;
 
 use strict;
 use vars qw(@ISA $VERSION);
 
 require LWP::MemberMixin;
 @ISA = qw(LWP::MemberMixin);
 $VERSION = "6.13";
 
 use HTTP::Request ();
 use HTTP::Response ();
 use HTTP::Date ();
 
 use LWP ();
 use LWP::Protocol ();
 
 use Carp ();
 
 
 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 $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 $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;
 
     # 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,
                       proxy        => {},
 		      no_proxy     => [],
                       protocols_allowed     => $protocols_allowed,
                       protocols_forbidden   => $protocols_forbidden,
                       requests_redirectable => $requests_redirectable,
 		     }, $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;
 
     $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) {
             $protocol = eval { LWP::Protocol::create($scheme, $self) };
             if ($@) {
                 $@ =~ s/ at .* line \d+.*//s;  # remove file/line number
                 $response =  _new_response($request, &HTTP::Status::RC_NOT_IMPLEMENTED, $@);
                 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
             eval {
                 $response = $protocol->request($request, $proxy, $arg, $size, $self->{timeout}) ||
 		    die "No response returned by $protocol";
             };
             if ($@) {
                 if (UNIVERSAL::isa($@, "HTTP::Response")) {
                     $response = $@;
                     $response->request($request);
                 }
                 else {
                     my $full = $@;
                     (my $status = $@) =~ 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");
     }
 
     eval {
 	$request = $self->prepare_request($request);
     };
     if ($@) {
 	$@ =~ s/ at .* line \d+.*//s;  # remove file/line number
 	return _new_response($request, &HTTP::Status::RC_BAD_REQUEST, $@);
     }
     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}) {
         $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)
     {
 	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 @challenge = $response->header($ch_header);
 	unless (@challenge) {
 	    $response->header("Client-Warning" => 
 			      "Missing Authenticate header");
 	    return $response;
 	}
 
 	require HTTP::Headers::Util;
 	CHALLENGE: for my $challenge (@challenge) {
 	    $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 =~ s/-/_/g;
 
 	    no strict 'refs';
 	    unless (%{"$class\::"}) {
 		# try to load it
 		eval "require $class";
 		if ($@) {
 		    if ($@ =~ /^Can\'t locate/) {
 			$response->header("Client-Warning" =>
 					  "Unsupported authentication scheme '$scheme'");
 		    }
 		    else {
 			$response->header("Client-Warning" => $@);
 		    }
 		    next CHALLENGE;
 		}
 	    }
 	    unless ($class->can("authenticate")) {
 		$response->header("Client-Warning" =>
 				  "Unsupported authentication scheme '$scheme'");
 		next CHALLENGE;
 	    }
 	    return $class->authenticate($self, $proxy, $challenge, $response,
 					$request, $arg, $size);
 	}
 	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 post {
     require HTTP::Request::Common;
     my($self, @parameters) = @_;
     my @suff = $self->_process_colonic_headers(\@parameters, (ref($parameters[1]) ? 2 : 1));
     return $self->request( HTTP::Request::Common::POST( @parameters ), @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 put {
     require HTTP::Request::Common;
     my($self, @parameters) = @_;
     my @suff = $self->_process_colonic_headers(\@parameters, (ref($parameters[1]) ? 2 : 1));
     return $self->request( HTTP::Request::Common::PUT( @parameters ), @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;
 	    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 an 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      { shift->_elem('timeout',      @_); }
 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 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;
     }
 
     return keys %{$self->{ssl_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 $] >= 5.008 && $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};
     if (@_) {
 	my $jar = shift;
 	if (ref($jar) eq "HASH") {
 	    require HTTP::Cookies;
 	    $jar = HTTP::Cookies->new(%$jar);
 	}
 	$self->{cookie_jar} = $jar;
         $self->set_my_handler("request_prepare",
             $jar ? sub { $jar->add_cookie_header($_[0]); } : undef,
         );
         $self->set_my_handler("response_done",
             $jar ? sub { $jar->extract_cookies($_[0]); } : undef,
         );
     }
     $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/$LWP::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);
 	}
 	$self->{conn_cache} = $cache;
     }
     $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") {
             while (my($k, $v) = each %$init) {
                 $spec{$k} = $v;
             }
         }
         $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) = @_;
     if (defined(wantarray)) {
         for my $h ($self->handlers($phase, $o)) {
             my $ret = $h->{callback}->($o, $self, $h);
             return $ret if $ret;
         }
         return undef;
     }
 
     for my $h ($self->handlers($phase, $o)) {
         $h->{callback}->($o, $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) = @_;
 
     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) );
         }
     }
     my $tmpfile = "$file-$$";
 
     my $response = $self->request($request, $tmpfile);
     if ( $response->header('X-Died') ) {
 	die $response->header('X-Died');
     }
 
     # Only fetching a fresh copy of the 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
             if ( -e $file ) {
                 # Some DOSish systems fail to rename if the target exists
                 chmod 0777, $file;
                 unlink $file;
             }
             rename( $tmpfile, $file )
                 or die "Cannot rename '$tmpfile' to '$file': $!\n";
 
             # make sure the file has the same last modification time
             if ( my $lm = $response->last_modified ) {
                 utime $lm, $lm, $file;
             }
         }
     }
     # 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}}) {
                 if ($host =~ /\Q$domain\E$/) {
                     return;
                 }
             }
         }
     }
     $req->{proxy} = $HTTP::URI_CLASS->new($proxy);
 }
 
 
 sub proxy
 {
     my $self = shift;
     my $key  = shift;
     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($k,$v);
     while(($k, $v) = each %ENV) {
 	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);
 	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__
 
 =head1 NAME
 
 LWP::UserAgent - Web user agent class
 
 =head1 SYNOPSIS
 
  require LWP::UserAgent;
  
  my $ua = LWP::UserAgent->new;
  $ua->timeout(10);
  $ua->env_proxy;
  
  my $response = $ua->get('http://search.cpan.org/');
  
  if ($response->is_success) {
      print $response->decoded_content;  # or whatever
  }
  else {
      die $response->status_line;
  }
 
 =head1 DESCRIPTION
 
 The C<LWP::UserAgent> is a class implementing a web user agent.
 C<LWP::UserAgent> objects can be used to dispatch web requests.
 
 In normal use the application creates an C<LWP::UserAgent> object, and
 then configures it with values for timeouts, proxies, name, etc. It
 then creates an instance of C<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 C<HTTP::Response> object.  There are
 convenience methods for sending the most common request types: get(),
 head(), post(), put() and delete().  When using these methods then 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
 C<HTTP::Request> objects and receive C<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, gopher menus and
 file directories are converted to HTML documents.
 
 =head1 CONSTRUCTOR METHODS
 
 The following constructor methods are available:
 
 =over 4
 
 =item $ua = LWP::UserAgent->new( %options )
 
 This method constructs a new C<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/#.###"
    from                    undef
    conn_cache              undef
    cookie_jar              undef
    default_headers         HTTP::Headers->new
    local_address           undef
    ssl_opts		   { verify_hostname => 1 }
    max_size                undef
    max_redirect            7
    parse_head              1
    protocols_allowed       undef
    protocols_forbidden     undef
    requests_redirectable   ['GET', 'HEAD']
    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 env_proxy() method below).  If C<env_proxy> isn't provided the
 C<PERL_LWP_ENV_PROXY> environment variable controls if env_proxy() is called
 during initialization.  If the C<keep_alive> option is passed in, then a
 C<LWP::ConnCache> is set up (see conn_cache() method below).  The C<keep_alive>
 value is passed on as the C<total_capacity> for the connection cache.
 
 =item $ua->clone
 
 Returns a copy of the LWP::UserAgent object.
 
 =back
 
 =head1 ATTRIBUTES
 
 The settings of the configuration attributes modify the behaviour of the
 C<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.
 
 =over
 
 =item $ua->agent
 
 =item $ua->agent( $product_id )
 
 Get/set the product token that is used to identify the user agent on
 the network.  The agent value is sent as the "User-Agent" header in
 the requests.  The default is the string returned by the _agent()
 method (see below).
 
 If the $product_id ends with space then the _agent() 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 "/" character.
 Examples are:
 
   $ua->agent('Checkbot/0.4 ' . $ua->_agent);
   $ua->agent('Checkbot/0.4 ');    # same as above
   $ua->agent('Mozilla/5.0');
   $ua->agent("");                 # don't identify
 
 =item $ua->_agent
 
 Returns the default agent identifier.  This is a string of the form
 "libwww-perl/#.###", where "#.###" is substituted with the version number
 of this library.
 
 =item $ua->from
 
 =item $ua->from( $email_address )
 
 Get/set the e-mail address for the human user who controls
 the requesting user agent.  The address should be machine-usable, as
 defined in RFC 822.  The C<from> value is send as the "From" header in
 the requests.  Example:
 
   $ua->from('gaas@cpan.org');
 
 The default is to not send a "From" header.  See the default_headers()
 method for the more general interface that allow any header to be defaulted.
 
 =item $ua->cookie_jar
 
 =item $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 extract_cookies($response) and
 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 C<HTTP::Cookies> object or some
 subclass.
 
 The default is to have no cookie_jar, i.e. never automatically add
 "Cookie" headers to the requests.
 
 Shortcut: If a reference to a plain hash is passed in as the
 $cookie_jar_object, then it is replaced with an instance of
 C<HTTP::Cookies> that is initialized based on the hash.  This form also
 automatically loads the C<HTTP::Cookies> module.  It means that:
 
   $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"));
 
 =item $ua->default_headers
 
 =item $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 C<HTTP::Headers>
 object.
 
 =item $ua->default_header( $field )
 
 =item $ua->default_header( $field => $value )
 
 This is just a short-cut for $ua->default_headers->header( $field =>
 $value ). Example:
 
   $ua->default_header('Accept-Encoding' => scalar HTTP::Message::decodable());
   $ua->default_header('Accept-Language' => "no, en");
 
 =item $ua->conn_cache
 
 =item $ua->conn_cache( $cache_obj )
 
 Get/set the C<LWP::ConnCache> object to use.  See L<LWP::ConnCache>
 for details.
 
 =item $ua->credentials( $netloc, $realm )
 
 =item $ua->credentials( $netloc, $realm, $uname, $pass )
 
 Get/set the user name and password to be used for a realm.
 
 The $netloc is a string of the form "<host>:<port>".  The username and
 password will only be passed to this server.  Example:
 
   $ua->credentials("www.example.com:80", "Some Realm", "foo", "secret");
 
 =item $ua->local_address
 
 =item $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>.
 
 =item $ua->max_size
 
 =item $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
 "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 "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) >>.
 
 =item $ua->max_redirect
 
 =item $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 7. This means that if you call request()
 method 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.
 
 =item $ua->parse_head
 
 =item $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.  Do not turn this off, unless you know what you are doing.
 
 =item $ua->protocols_allowed
 
 =item $ua->protocols_allowed( \@protocols )
 
 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-E<gt>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 "ftp://...") will result in a 500 error.
 
 To delete the list, call: C<$ua-E<gt>protocols_allowed(undef)>
 
 By default, an object has neither a C<protocols_allowed> list, nor a
 C<protocols_forbidden> list.
 
 Note that having a C<protocols_allowed> list causes any
 C<protocols_forbidden> list to be ignored.
 
 =item $ua->protocols_forbidden
 
 =item $ua->protocols_forbidden( \@protocols )
 
 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-E<gt>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.
 
 To delete the list, call: C<$ua-E<gt>protocols_forbidden(undef)>
 
 =item $ua->requests_redirectable
 
 =item $ua->requests_redirectable( \@requests )
 
 This reads or sets the object's list of request names that
 C<$ua-E<gt>redirect_ok(...)> will allow redirection for.  By
 default, this is C<['GET', 'HEAD']>, as per RFC 2616.  To
 change to include 'POST', consider:
 
    push @{ $ua->requests_redirectable }, 'POST';
 
 =item $ua->show_progress
 
 =item $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.
 
 =item $ua->timeout
 
 =item $ua->timeout( $secs )
 
 Get/set the timeout value in seconds. The default timeout() value is
 180 seconds, i.e. 3 minutes.
 
 The requests 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 request() method to actually
 return might be longer.
 
 =item $ua->ssl_opts
 
 =item $ua->ssl_opts( $key )
 
 =item $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 L<PERL_LWP_SSL_VERIFY_HOSTNAME> environment
 variable.  If this environment variable isn't set; then C<verify_hostname>
 defaults to 1.
 
 =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.
 
 =back
 
 =head2 Proxy attributes
 
 The following methods set up when requests should be passed via a
 proxy server.
 
 =over
 
 =item $ua->proxy(\@schemes, $proxy_url)
 
 =item $ua->proxy($scheme, $proxy_url)
 
 Set/retrieve proxy URL for a scheme:
 
  $ua->proxy(['http', 'ftp'], 'http://proxy.sn.no:8001/');
  $ua->proxy('gopher', 'http://proxy.sn.no:8001/');
 
 The first form specifies that the URL is to be used for proxying of
 access methods listed in the list in the first method argument,
 i.e. 'http' and 'ftp'.
 
 The second form shows a shorthand form for specifying
 proxy URL for a single access scheme.
 
 =item $ua->no_proxy( $domain, ... )
 
 Do not proxy requests to the given domains.  Calling no_proxy without
 any domains clears the list of domains. Eg:
 
  $ua->no_proxy('localhost', 'example.com');
 
 =item $ua->env_proxy
 
 Load proxy settings from *_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 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.
 
 =back
 
 =head2 Handlers
 
 Handlers are code that injected at various phases during the
 processing of requests.  The following methods are provided to manage
 the active handlers:
 
 =over
 
 =item $ua->add_handler( $phase => \&cb, %matchspec )
 
 Add handler to be invoked in the given processing phase.  For how to
 specify %matchspec see L<HTTP::Config/"Matching">.
 
 The possible values $phase and the corresponding callback signatures are:
 
 =over
 
 =item request_preprepare => sub { my($request, $ua, $h) = @_; ... }
 
 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, $h) = @_; ... }
 
 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 $_[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, $h) = @_; ... }
 
 This handler gets a chance of handling requests before they're sent to the
 protocol handlers.  It should return an 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, $h) = @_; ... }
 
 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 $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 $ua->request() method
 was called with a $content_file or $content_cb argument; otherwise true.
 
 =item response_data => sub { my($response, $ua, $h, $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, $h) = @_; ... }
 
 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, $h) = @_; ... }
 
 The handler is called in $ua->request after C<response_done>.  If the
 handler returns an HTTP::Request object we'll start over with processing
 this request instead.
 
 =back
 
 =item $ua->remove_handler( undef, %matchspec )
 
 =item $ua->remove_handler( $phase, %matchspec )
 
 Remove handlers that match the given %matchspec.  If $phase is not
 provided remove handlers from all phases.
 
 Be careful as calling this function with %matchspec that is not
 specific enough can remove handlers not owned by you.  It's probably
 better to use the set_my_handler() method instead.
 
 The removed handlers are returned.
 
 =item $ua->set_my_handler( $phase, $cb, %matchspec )
 
 Set handlers private to the executing subroutine.  Works by defaulting
 an C<owner> field to the %matchspec that holds the name of the called
 subroutine.  You might pass an explicit C<owner> to override this.
 
 If $cb is passed as C<undef>, remove the handler.
 
 =item $ua->get_my_handler( $phase, %matchspec )
 
 =item $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 $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
 $init is a hash reference, merge the hashes.
 
 =item $ua->handlers( $phase, $request )
 
 =item $ua->handlers( $phase, $response )
 
 Returns the handlers that apply to the given request or response at
 the given processing phase.
 
 =back
 
 =head1 REQUEST METHODS
 
 The methods described in this section are used to dispatch requests
 via the user agent.  The following request methods are provided:
 
 =over
 
 =item $ua->get( $url )
 
 =item $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
     :content_cb     => \&callback
     :read_size_hint => $bytes
 
 If a $filename is provided with the C<:content_file> option, then the
 response content will be saved here instead of in the response
 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.
 
 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 die().  The
 exception message will show up as the "X-Died" header field in the
 response returned by the get() function.
 
 =item $ua->head( $url )
 
 =item $ua->head( $url , $field_name => $value, ... )
 
 This method will dispatch a C<HEAD> request on the given $url.
 Otherwise it works like the get() method described above.
 
 =item $ua->post( $url, \%form )
 
 =item $ua->post( $url, \@form )
 
 =item $ua->post( $url, \%form, $field_name => $value, ... )
 
 =item $ua->post( $url, $field_name => $value,... Content => \%form )
 
 =item $ua->post( $url, $field_name => $value,... Content => \@form )
 
 =item $ua->post( $url, $field_name => $value,... Content => $content )
 
 This method will dispatch a C<POST> request on the given $url, with
 %form or @form providing the key/value pairs for the fill-in form
 content. Additional headers and content options are the same as for
 the get() method.
 
 This method will use the POST() function from C<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.
 
 =item $ua->put( $url, \%form )
 
 =item $ua->put( $url, \@form )
 
 =item $ua->put( $url, \%form, $field_name => $value, ... )
 
 =item $ua->put( $url, $field_name => $value,... Content => \%form )
 
 =item $ua->put( $url, $field_name => $value,... Content => \@form )
 
 =item $ua->put( $url, $field_name => $value,... Content => $content )
 
 This method will dispatch a C<PUT> request on the given $url, with
 %form or @form providing the key/value pairs for the fill-in form
 content. Additional headers and content options are the same as for
 the get() method.
 
 This method will use the PUT() function from C<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.
 
 =item $ua->delete( $url )
 
 =item $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 get() method.
 
 This method will use the DELETE() function from C<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.
 
 =item $ua->mirror( $url, $filename )
 
 This method will get the document identified by $url and store it in
 file called $filename.  If the file already exists, then the request
 will contain an "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.
 
 The return value is the response object.
 
 =item $ua->request( $request )
 
 =item $ua->request( $request, $content_file )
 
 =item $ua->request( $request, $content_cb )
 
 =item $ua->request( $request, $content_cb, $read_size_hint )
 
 This method will dispatch the given $request object.  Normally this
 will be an instance of the C<HTTP::Request> class, but any object with
 a similar interface will do.  The return value is a response object.
 See L<HTTP::Request> and L<HTTP::Response> for a description of the
 interface provided by these classes.
 
 The request() method will process redirects and authentication
 responses transparently.  This means that it may actually send several
 simple requests via the simple_request() method described below.
 
 The request methods described above; get(), head(), post() and
 mirror(), will all dispatch the request they build via this method.
 They are convenience methods that simply hides the creation of the
 request object for you.
 
 The $content_file, $content_cb and $read_size_hint all correspond to
 options described with the get() method above.
 
 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.
 
 =item $ua->simple_request( $request )
 
 =item $ua->simple_request( $request, $content_file )
 
 =item $ua->simple_request( $request, $content_cb )
 
 =item $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 request() described above.
 
 The difference from request() is that simple_request() will not try to
 handle redirects or authentication responses.  The request() method
 will in fact invoke this method for each simple request it sends.
 
 =item $ua->is_online
 
 Tries to determine if you have access to the Internet.  Returns
 TRUE if the built-in heuristics determine that the user agent is
 able to access the Internet (over HTTP).  See also L<LWP::Online>.
 
 =item $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 'http' or
 'ftp') or it might be an 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.
 
 =back
 
 =head2 Callback methods
 
 The following methods will be invoked as requests are processed. These
 methods are documented here because subclasses of C<LWP::UserAgent>
 might want to override their behaviour.
 
 =over
 
 =item $ua->prepare_request( $request )
 
 This method is invoked by simple_request().  Its task is to modify the
 given $request object by setting up various headers based on the
 attributes of the user agent. The return value should normally be the
 $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; "User-Agent",
 "From", "Range" and "Cookie".
 
 =item $ua->redirect_ok( $prospective_request, $response )
 
 This method is called by request() before it tries to follow a
 redirection to the request in $response.  This should return a TRUE
 value if this redirection is permissible.  The $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 "file://..."
 URL, and TRUE otherwise.
 
 =item $ua->get_basic_credentials( $realm, $uri, $isproxy )
 
 This is called by request() to retrieve credentials for documents
 protected by Basic or Digest Authentication.  The arguments passed in
 is the $realm provided by the server, the $uri requested and a 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 credentials() method.
 
 =item $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 $status
 "begin" at the start of processing the request and with $state "end"
 before the request method returns.  In between these $status will be
 the fraction of the response currently received or the string "tick"
 if the fraction can't be calculated.
 
 When $status is "begin" the second argument is the request object,
 otherwise it is the response object.
 
 =back
 
 =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 C<LWP::UserAgent>.
 
 =head1 COPYRIGHT
 
 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.
### Lingua/EN/Numbers/Ordinate.pm ###
 package Lingua::EN::Numbers::Ordinate;
 $Lingua::EN::Numbers::Ordinate::VERSION = '1.04';
 # ABSTRACT: go from cardinal number (3) to ordinal ("3rd")
 
 use 5.006;
 use strict;
 use warnings;
 require Exporter;
 
 our @ISA        = qw/ Exporter  /;
 our @EXPORT     = qw/ ordinate  /;
 our @EXPORT_OK  = qw/ ordsuf th /;
 
 ###########################################################################
 
 =head1 NAME
 
 Lingua::EN::Numbers::Ordinate -- go from cardinal number (3) to ordinal ("3rd")
 
 =head1 SYNOPSIS
 
   use Lingua::EN::Numbers::Ordinate;
   print ordinate(4), "\n";
    # prints 4th
   print ordinate(-342), "\n";
    # prints -342nd
 
   # Example of actual use:
   ...
   for(my $i = 0; $i < @records; $i++) {
     unless(is_valid($record[$i]) {
       warn "The ", ordinate($i), " record is invalid!\n"; 
       next;
     }
     ...
   }
 
 =head1 DESCRIPTION
 
 There are two kinds of numbers in English -- cardinals (1, 2, 3...), and
 ordinals (1st, 2nd, 3rd...).  This library provides functions for giving
 the ordinal form of a number, given its cardinal value.
 
 =head1 FUNCTIONS
 
 =over
 
 =item ordinate(SCALAR)
 
 Returns a string consisting of that scalar's string form, plus the
 appropriate ordinal suffix.  Example: C<ordinate(23)> returns "23rd".
 
 As a special case, C<ordinate(undef)> and C<ordinate("")> return "0th",
 not "th".
 
 This function is exported by default.
 
 =item th(SCALAR)
 
 Merely an alias for C<ordinate>, but not exported by default.
 
 =item ordsuf(SCALAR)
 
 Returns just the appropriate ordinal suffix for the given scalar
 numeric value.  This is what C<ordinate> uses to actually do its
 work.  For example, C<ordsuf(3)> is "rd". 
 
 Not exported by default.
 
 =back
 
 The above functions are all prototyped to take a scalar value,
 so C<ordinate(@stuff)> is the same as C<ordinate(scalar @stuff)>.
 
 =head1 CAVEATS
 
 * Note that this library knows only about numbers, not number-words.
 C<ordinate('seven')> might just as well be C<ordinate('superglue')>
 or C<ordinate("\x1E\x9A")> -- you'll get the fallthru case of the input
 string plus "th".
 
 * As is unavoidable, C<ordinate(0256)> returns "174th" (because ordinate
 sees the value 174). Similarly, C<ordinate(1E12)> returns
 "1000000000000th".  Returning "trillionth" would be nice, but that's an
 awfully atypical case.
 
 * Note that this library's algorithm (as well as the basic concept
 and implementation of ordinal numbers) is totally language specific.
 
 To pick a trivial example, consider that in French, 1 ordinates
 as "1ier", whereas 41 ordinates as "41ieme".
 
 =head1 STILL NOT SATISFIED?
 
 Bored of this...?
 
   use Lingua::EN::Numbers::Ordinate qw(ordinate th);
   ...
   print th($n), " entry processed...\n";
   ...
 
 Try this bit of lunacy:
 
   {
     my $th_object;
     sub _th () { $th_object }
 
     package Lingua::EN::Numbers::Ordinate::Overloader;
     my $x; # Gotta have something to bless.
     $th_object = bless \$x; # Define the object now, which _th returns
     use Carp ();
     use Lingua::EN::Numbers::Ordinate ();
     sub overordinate {
       Carp::croak "_th should be used only as postfix!" unless $_[2];
       Lingua::EN::Numbers::Ordinate::ordinate($_[1]);
     }
     use overload '&' => \&overordinate;
   }
 
 Then you get to do:
 
   print 3 & _th, "\n";
     # prints "3rd"
   
   print 1 + 2 & _th, "\n";
     # prints "3rd" too!
     # Because of the precedence of & !
   
   print _th & 3, "\n";
     # dies with: "th should be used only as postfix!"
 
 Kooky, isn't it?  For more delightful deleria like this, see
 Damian Conway's I<Object Oriented Perl> from Manning Press.
 
 Kinda makes you like C<th(3)>, doesn't it?
 
 =head1 SEE ALSO
 
 L<Lingua::EN::Inflect> provides an C<ORD> function,
 which returns the ordinal form of a cardinal number.
 
 L<Lingua::EN::Number::IsOrdinal> provides an C<is_ordinal>
 function, which returns true if passed an ordinal number.
 
 =head1 REPOSITORY
 
 L<https://github.com/neilbowers/Lingua-EN-Numbers-Ordinate>
 
 =head1 COPYRIGHT
 
 Copyright (c) 2000 Sean M. Burke.  All rights reserved.
 
 This library is free software; you can redistribute it and/or
 modify it under the same terms as Perl itself.
 
 =head1 AUTHOR
 
 Sean M. Burke C<sburke@cpan.org>
 
 =cut
 
 ###########################################################################
 
 sub ordsuf ($) {
   return 'th' if not(defined($_[0])) or not( 0 + $_[0] );
    # 'th' for undef, 0, or anything non-number.
   my $n = abs($_[0]);  # Throw away the sign.
   return 'th' unless $n == int($n); # Best possible, I guess.
   $n %= 100;
   return 'th' if $n == 11 or $n == 12 or $n == 13;
   $n %= 10;
   return 'st' if $n == 1; 
   return 'nd' if $n == 2;
   return 'rd' if $n == 3;
   return 'th';
 }
 
 sub ordinate ($) {
   my $i = $_[0] || 0;
   return $i . ordsuf($i);
 }
 
 no warnings 'all';
 *th = \&ordinate; # correctly copies the prototype, too.
 
 ###########################################################################
 1;
 
 __END__
### Lingua/EN/PluralToSingular.pm ###
 package Lingua::EN::PluralToSingular;
 require Exporter;
 @ISA = qw(Exporter);
 @EXPORT_OK = qw/to_singular is_plural/;
 use warnings;
 use strict;
 our $VERSION = '0.16';
 
 # Irregular plurals.
 
 # References:
 # http://www.macmillandictionary.com/thesaurus-category/british/Irregular-plurals
 # http://web2.uvcs.uvic.ca/elc/studyzone/330/grammar/irrplu.htm
 # http://www.scribd.com/doc/3271143/List-of-100-Irregular-Plural-Nouns-in-English
 
 # This mixes latin/greek plurals and anglo-saxon together. It may be
 # desirable to split things like corpora and genera from "feet" and
 # "geese" at some point.
 
 my %irregular = (qw/
     analyses analysis
     children child
     corpora corpus
     craftsmen craftsman
     crises crisis
     criteria criterion
     curricula curriculum
     feet foot
     fungi fungus
     geese goose
     genera genus
     indices index
     lice louse
     matrices matrix
     memoranda memorandum
     men man
     mice mouse
     monies money
     neuroses neurosis
     nuclei nucleus
     oases oasis
     pence penny
     people person
     phenomena phenomenon
     quanta quantum
     strata stratum
     teeth tooth
     testes testis
     these this
     theses thesis
     those that
     women woman
 /);
 
 # Words ending in ves need care, since the ves may become "f" or "fe".
 
 # References:
 # http://www.macmillandictionary.com/thesaurus-category/british/Irregular-plurals
 
 my %ves = (qw/
     calves calf
     dwarves dwarf
     elves elf
     halves half
     knives knife
     leaves leaf
     lives life
     loaves loaf
     scarves scarf
     sheaves sheaf
     shelves shelf
     wharves wharf 
     wives wife
     wolves wolf
 /);
 
 # A dictionary of plurals.
 
 my %plural = (
     # Words ending in "us" which are plural, in contrast to words like
     # "citrus" or "bogus".
     'menus' => 'menu',
     'buses' => 'bus',
     %ves,
     %irregular,
 );
 
 # A store of words which are the same in both singular and plural.
 
 my @no_change = qw/
                       clothes
                       deer
                       ides
                       fish
                       means
                       offspring
                       series
                       sheep
                       species
                   /;
 
 @plural{@no_change} = @no_change;
 
 # A store of words which look like plurals but are not.
 
 # References:
 
 # http://wiki.answers.com/Q/What_are_some_examples_of_singular_nouns_ending_in_S
 # http://virtuallinguist.typepad.com/the_virtual_linguist/2009/10/singular-nouns-ending-in-s.html
 
 my @not_plural = (qw/
 			Charles
 			Gonzales 
 			Hades 
 			Hercules 
 			Hermes 
 			Holmes 
 			Hughes 
 			Ives 
 			Jacques 
 			James 
 			Keyes 
 			Mercedes 
 			Naples 
 			Oates 
 			Raines 
 			Texas
 			athletics
 			bogus
 			bus
 			cactus
 			cannabis
 			chaos
 			citrus
 			corps
 			corpus
 			devious
 			dias
 			famous
 			hippopotamus
 			homunculus
 			iris
 			lens
 			mathematics
 			metaphysics
 			metropolis
 			mews
 			minus
 			miscellaneous
 			molasses
 			mrs
 			narcissus
 			news
 			octopus
 			ourselves
 			papyrus
 			perhaps
 			physics
 			platypus
 			plus
 			previous
 			pus
 			sometimes
 			stylus
 			themselves
 			this
 			thus
 			various
 			yes
 		    /);
 
 my %not_plural;
 
 @not_plural{@not_plural} = (1) x @not_plural;
 
 # A store of words which end in "oe" and whose plural ends in "oes".
 
 # References
 # http://www.scrabblefinder.com/ends-with/oe/
 
 # Also used
 
 # perl -n -e 'print if /oe$/' < /usr/share/dict/words
 
 my @oes = (qw/
 		 canoes
 		 does
 		 foes
 		 gumshoes
 		 horseshoes
 		 oboes
 		 shoes
 		 snowshoes
 		 throes
                  hoes
                  toes
              /);
 
 my %oes;
 
 @oes{@oes} = (1) x @oes;
 
 # A store of words which end in "ie" and whose plural ends in "ies".
 
 # References:
 # http://www.scrabblefinder.com/ends-with/ie/
 # (most of the words are invalid, the above list was manually searched
 # for useful words).
 
 # Also get a good list using
 
 # perl -n -e 'print if /ie$/' < /usr/share/dict/words 
 
 # There are too many obscure words there though.
 
 # Also, I'm deliberately not including "Bernie" and "Bessie" since the
 # plurals are rare I think. 
 
 my @ies = (qw/
 Aussies
 Valkryies
 aunties
 bogie
 brownies
 calories
 charlies
 coolies
 coteries
 curies
 cuties
 dies
 genies
 goalie
 kilocalories
 lies
 magpies
 menagerie
 movies
 neckties
 pies
 porkpies
 prairies
 quickies
 reveries
 rookies
 sorties
 stogies
 talkies
 ties
 zombies
 /);
 
 my %ies;
 
 @ies{@ies} = (1) x @ies;
 
 # Words which end in -se, so that we want the singular to change from
 # -ses to -se.
 
 my @ses = (qw/
 horses
 tenses
 /);
 
 my %ses;
 @ses{@ses} = (1) x @ses;
 
 # A regular expression which matches the end of words like "dishes"
 # and "sandwiches". $1 is a capture which contains the part of the
 # word which should be kept in a substitution.
 
 my $es_re = qr/([^aeiou]s|ch|sh)es$/;
 
 # See documentation below.
 
 sub to_singular
 {
     my ($word) = @_;
     # The return value.
     my $singular = $word;
     if (! $not_plural{$word}) {
         # The word is not in the list of exceptions.
         if ($plural{$word}) {
             # The word has an irregular plural, like "children", or
             # "geese", so look up the singular in the table.
             $singular = $plural{$word};
         }
         elsif ($word =~ /s$/) {
             # The word ends in "s".
 	    if ($word =~ /'s$/) {
 		# report's, etc.
 		;
 	    }
 	    elsif (length ($word) <= 2) {
 		# is, as, letter s, etc.
 		;
 	    }
 	    elsif ($word =~ /ss$/) {
 		# useless, etc.
 		;
 	    }
 	    elsif ($word =~ /sis$/) {
 		# basis, dialysis etc.
 		;
 	    }
             elsif ($word =~ /ies$/) {
                 # The word ends in "ies".
                 if ($ies{$word}) {
                     # Lies -> lie
                     $singular =~ s/ies$/ie/;
                 }
                 else {
                     # Fries -> fry
                     $singular =~ s/ies$/y/;
                 }
             }
             elsif ($word =~ /oes$/) {
                 # The word ends in "oes".
                 if ($oes{$word}) {
                     # Toes -> toe
                     $singular =~ s/oes$/oe/;
                 }
                 else {
                     # Potatoes -> potato
                     $singular =~ s/oes$/o/;
                 }
             }
             elsif ($word =~ /xes$/) {
                 # The word ends in "xes".
 		$singular =~ s/xes$/x/;
             }
 	    elsif ($word =~ /ses$/) {
 		if ($ses{$word}) {
 		    $singular =~ s/ses$/se/;
 		}
 		else {
 		    $singular =~ s/ses$/s/;
 		}
 	    }
             elsif ($word =~ $es_re) {
                 # Sandwiches -> sandwich
                 # Dishes -> dish
                 $singular =~ s/$es_re/$1/;
             }
             else {
                 # Now the program has checked for every exception it
                 # can think of, so it assumes that it is OK to remove
                 # the "s" from the end of the word.
                 $singular =~ s/s$//;
             }
         }
     }            
     return $singular;
 }
 
 sub is_plural
 {
     my ($word) = @_;
     my $singular = to_singular ($word);
     my $is_plural;
     if ($singular ne $word) {
 	$is_plural = 1;
     }
     elsif ($plural{$singular} && $plural{$singular} eq $singular) {
 	$is_plural = 1;
     }
     else {
 	$is_plural = 0;
     }
     return $is_plural;
 }
 
 1;
 
### Locale/Messages.pm ###
 #! /bin/false
 
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::Messages;
 
 use strict;
 
 use vars qw ($package @EXPORT_OK %EXPORT_TAGS @ISA $VERSION);
 
 $VERSION = '1.24';
 
 # Try to load the C version first.
 $package = 'gettext_xs';
 eval <<'EOF';
 require Locale::gettext_xs; 
 my $version = Locale::gettext_xs::__gettext_xs_version();
 die "Version: version mismatch ($VERSION vs. $version)" unless $version eq $VERSION;
 EOF
 my $no_xs = $@;
 
 # There are systems where setlocale() and the LC_ constants are not
 # defined at all, see https://rt.cpan.org/Ticket/Display.html?id=98109
 #
 # On such systems, we always fall back to gettext_dumb.
 if ($no_xs) {
     eval {
         require POSIX;
         # void
         POSIX::setlocale(POSIX::LC_ALL());
     };
     if ($@) {
         $package = 'gettext_dumb';
         require Locale::gettext_dumb;
     } else {
         $package = 'gettext_pp';
         require Locale::gettext_pp;
     }
 }
 		
 require Exporter;
 @ISA = qw (Exporter);
 %EXPORT_TAGS = (locale_h => [ qw (gettext
 				  dgettext
 				  dcgettext
 				  ngettext
 				  dngettext
 				  dcngettext
 				  pgettext
 				  dpgettext
 				  dcpgettext
 				  npgettext
 				  dnpgettext
 				  dcnpgettext
 				  textdomain
 				  bindtextdomain
 				  bind_textdomain_codeset
 				  )
 			       ],
 		 libintl_h => [ qw (LC_CTYPE
 				    LC_NUMERIC
 				    LC_TIME
 				    LC_COLLATE
 				    LC_MONETARY
 				    LC_MESSAGES
 				    LC_ALL)
 				],
 		 );
 
 @EXPORT_OK = qw (select_package
 				 turn_utf_8_on
 				 turn_utf_8_off
 				 gettext
 				 dgettext
 				 dcgettext
 				 ngettext
 				 dngettext
 				 dcngettext
 				 pgettext
 				 dpgettext
 				 dcpgettext
 				 npgettext
 				 dnpgettext
 				 dcnpgettext
 				 textdomain
 				 bindtextdomain
 				 bind_textdomain_codeset
 				 bind_textdomain_filter
                  nl_putenv
                  setlocale
 				 LC_CTYPE
 				 LC_NUMERIC
 				 LC_TIME
 				 LC_COLLATE
 				 LC_MONETARY
 				 LC_MESSAGES
 				 LC_ALL);
 
 BEGIN {
 	my ($has_encode, $has_bytes);
 	
 	if ($] >= 5.006) {
 		unless (defined $has_encode) {
 			eval "require Encode";
 			$has_encode = !$@;
 		}
 
 		unless ($has_encode || defined $has_bytes) {
 			eval "use bytes";
 			$has_bytes = !$@;
 		}
 	}
 
 	# Turn the UTF-8 flag on or off unconditionally.  The prototypes
 	# allow an optional second parameter, so that you can use the
 	# functions as callbacks to bind_textdomain_filter.
 	if ($has_encode) {
 		eval <<'EOF';
 sub turn_utf_8_on($;$)
 {
 	Encode::_utf8_on ($_[0]);
 	return $_[0];
 }
 
 sub turn_utf_8_off($;$)
 {
 	Encode::_utf8_off ($_[0]);
 	return $_[0];
 }
 
 EOF
 	} elsif ($has_bytes) {
 		eval <<'EOF';
 sub turn_utf_8_on($;$)
 {
 	$_[0] = pack "U0C*", unpack "C*", $_[0];
 }
 
 sub turn_utf_8_off($;$)
 {
 	use bytes;
 	$_[0] = join "", split //, $_[0];
 }
 
 EOF
 	} else {
 		eval <<'EOF';
 sub turn_utf_8_on($;$)
 {
 	return $_[0];
 }
 
 sub turn_utf_8_off($;$)
 {
 	return $_[0];
 }
 
 EOF
 	}
 }
 
 # The textdomain could be undef.  We avoid a warning by specifying
 # a filter for the undefined textdomain.
 my %filters = (undef => \&turn_utf_8_off);
 
 sub select_package {
     my ($pkg, $compatibility) = @_;
 
     # Compatibility quirk for a bug pre 1.17:
     if (__PACKAGE__ eq $pkg && defined $compatibility) {
         $pkg = $compatibility;
     }
 
     if ($no_xs && 'gettext_xs' eq $pkg) {
         $pkg = 'gettext_pp';
     }
 
     if (defined $pkg && 'gettext_pp' eq $pkg) {
         # This branch is not unnecessary.  The next (elsif) branch does
         # essentially the same but catches compilation errors.
         require Locale::gettext_pp;
         $package = 'gettext_pp';
     } elsif (defined $pkg) {
         my $filename = "Locale::$pkg";
         $filename =~ s{::|\'}{/};
 	$filename .= '.pm';
         eval { require $filename };
 	$package = $pkg unless $@;   
     } else {
         eval "require Locale::gettext_xs";
         $package = 'gettext_xs' unless $@;
     }
 
     return $package;
 }
 
 sub bind_textdomain_filter ($;$$) {
 	my ($textdomain, $coderef, $data) = @_;
 
 	$filters{$textdomain} = [ $coderef, $data ];
 
 	return 1;
 }
 
 sub textdomain (;$) {
     my $function = "Locale::${package}::textdomain";
     
     no strict 'refs';
     &$function;
 }
 
 sub bindtextdomain ($;$) {
     my $function = "Locale::${package}::bindtextdomain";
 
     no strict 'refs';
     &$function;
 }
 
 sub bind_textdomain_codeset ($;$) {
     my $function = "Locale::${package}::bind_textdomain_codeset";
 
     no strict 'refs';    
     &$function;
 }
 
 sub gettext ($) {
     my $textdomain = textdomain;
     $filters{$textdomain} ||= [ \&turn_utf_8_off ];
     my $cb = $filters{$textdomain};
 
     my $function = "Locale::${package}::gettext";
     
     no strict 'refs';
     $cb->[0] (&$function, $cb->[1]);
 }
 
 sub dgettext($$) {
     my $cb = $filters{$_[0]} ||= [ \&turn_utf_8_off ];
 
     my $function = "Locale::${package}::dgettext";
     
     no strict 'refs';
     $cb->[0] (&$function, $cb->[1]);
 }
 
 sub dcgettext($$$) {
     my $cb = $filters{$_[0]} ||= [ \&turn_utf_8_off ];
 
     my $function = "Locale::${package}::dcgettext";
     
     no strict 'refs';
     $cb->[0] (&$function, $cb->[1]);
 }
 
 sub ngettext($$$) {
     my $textdomain = textdomain;
     $filters{$textdomain} ||= [ \&turn_utf_8_off ];
     my $cb = $filters{$textdomain};
 
     my $function = "Locale::${package}::ngettext";
     
     no strict 'refs';
     $cb->[0] (&$function, $cb->[1]);
 }
 
 sub dngettext($$$$) {
     my $cb = $filters{$_[0]} ||= [ \&turn_utf_8_off ];
 
     my $function = "Locale::${package}::dngettext";
     
     no strict 'refs';
     $cb->[0] (&$function, $cb->[1]);
 }
 
 sub dcngettext($$$$$) {
     my $cb = $filters{$_[0]} ||= [ \&turn_utf_8_off ];
 
     my $function = "Locale::${package}::dcngettext";
     
     no strict 'refs';
     $cb->[0] (&$function, $cb->[1]);
 }
 
 sub pgettext($$) {
     my $textdomain = textdomain;
     $filters{$textdomain} ||= [ \&turn_utf_8_off ];
     my $cb = $filters{$textdomain};
 
     my $function = "Locale::${package}::pgettext";
     
     no strict 'refs';
     $cb->[0] (&$function, $cb->[1]);
 }
 
 sub dpgettext($$$) {
     my $cb = $filters{$_[0]} ||= [ \&turn_utf_8_off ];
 
     my $function = "Locale::${package}::dpgettext";
     
     no strict 'refs';
     $cb->[0] (&$function, $cb->[1]);
 }
 
 sub dcpgettext($$$$) {
     my $cb = $filters{$_[0]} ||= [ \&turn_utf_8_off ];
 
     my $function = "Locale::${package}::dcpgettext";
     
     no strict 'refs';
     $cb->[0] (&$function, $cb->[1]);
 }
 
 sub npgettext($$$$) {
     my $cb = $filters{$_[0]} ||= [ \&turn_utf_8_off ];
 
     my $function = "Locale::${package}::npgettext";
     
     no strict 'refs';
     $cb->[0] (&$function, $cb->[1]);
 }
 
 sub dnpgettext($$$$$) {
     my $cb = $filters{$_[0]} ||= [ \&turn_utf_8_off ];
 
     my $function = "Locale::${package}::dnpgettext";
     
     no strict 'refs';
     $cb->[0] (&$function, $cb->[1]);
 }
 
 sub dcnpgettext($$$$$$) {
     my $cb = $filters{$_[0]} ||= [ \&turn_utf_8_off ];
 
     my $function = "Locale::${package}::dcnpgettext";
     
     no strict 'refs';
     $cb->[0] (&$function, $cb->[1]);
 }
 
 sub setlocale($;$) {
     my $function = "Locale::${package}::setlocale";
     
     no strict 'refs';
     &$function;
 }
 
 sub nl_putenv($) {
     my $function = "Locale::${package}::nl_putenv";
     
     no strict 'refs';
     &$function;
 }
 
 sub LC_NUMERIC {
     my $function = "Locale::${package}::LC_NUMERIC";
     
     no strict 'refs';
     &$function;
 }
 
 sub LC_CTYPE {
     my $function = "Locale::${package}::LC_CTYPE";
     
     no strict 'refs';
     &$function;
 }
 
 sub LC_TIME {
     my $function = "Locale::${package}::LC_TIME";
     
     no strict 'refs';
     &$function;
 }
 
 sub LC_COLLATE {
     my $function = "Locale::${package}::LC_COLLATE";
     
     no strict 'refs';
     &$function;
 }
 
 sub LC_MONETARY {
     my $function = "Locale::${package}::LC_MONETARY";
     
     no strict 'refs';
     &$function;
 }
 
 sub LC_MESSAGES {
     my $function = "Locale::${package}::LC_MESSAGES";
     
     no strict 'refs';
     &$function;
 }
 
 sub LC_ALL {
     my $function = "Locale::${package}::LC_ALL";
     
     no strict 'refs';
     &$function;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::Messages - Gettext Like Message Retrieval
 
 =head1 SYNOPSIS
 
  use Locale::Messages (:locale_h :libintl_h);
 
  gettext $msgid;
  dgettext $textdomain, $msgid;
  dcgettext $textdomain, $msgid, LC_MESSAGES;
  ngettext $msgid, $msgid_plural, $count;
  dngettext $textdomain, $msgid, $msgid_plural, $count;
  dcngettext $textdomain, $msgid, $msgid_plural, $count, LC_MESSAGES;
  pgettext $msgctxt, $msgid;
  dpgettext $textdomain, $msgctxt, $msgid;
  dcpgettext $textdomain, $msgctxt, $msgid, LC_MESSAGES;
  npgettext $msgctxt, $msgid, $msgid_plural, $count;
  dnpgettext $textdomain, $msgctxt, $msgid, $msgid_plural, $count;
  dcnpgettext $textdomain, $msgctxt, $msgid, $msgid_plural, $count, LC_MESSAGES;
  textdomain $textdomain;
  bindtextdomain $textdomain, $directory;
  bind_textdomain_codeset $textdomain, $encoding;
  bind_textdomain_filter $textdomain, \&filter, $data;
  turn_utf_8_on ($variable);
  turn_utf_8_off ($variable);
  nl_putenv ('OUTPUT_CHARSET=koi8-r');
  my $category = LC_CTYPE;
  my $category = LC_NUMERIC;
  my $category = LC_TIME;
  my $category = LC_COLLATE;
  my $category = LC_MONETARY;
  my $category = LC_MESSAGES;
  my $category = LC_ALL;
 
 =head1 DESCRIPTION
 
 The module B<Locale::Messages> is a wrapper around the interface to
 message translation according to the Uniforum approach that is
 for example used in GNU gettext and Sun's Solaris.  It is intended
 to allow Locale::Messages(3) to switch between different implementations
 of the lower level libraries but this is not yet implemented.
 
 Normally you should not use this module directly, but the high
 level interface Locale::TextDomain(3) that provides a much simpler
 interface.  This description is therefore deliberately kept
 brief.  Please refer to the GNU gettext documentation available at
 L<http://www.gnu.org/manual/gettext/> for in-depth and background 
 information on the topic.
 
 The lower level module Locale::gettext_pp(3) provides the Perl
 implementation of gettext() and related functions.
 
 =head1 FUNCTIONS
 
 The module exports by default nothing.  Every function has to be
 imported explicitely or via an export tag (L</"EXPORT TAGS">).
 
 =over 4
 
 =item B<gettext MSGID>
 
 Returns the translation for B<MSGID>.  Example:
 
     print gettext "Hello World!\n";
 
 If no translation can be found, the unmodified B<MSGID> is returned,
 i. e. the function can I<never> fail, and will I<never> mess up your
 original message.
 
 Note for Perl 5.6 and later: The returned string will I<always> have
 the UTF-8 flag off by default.  See the documentation for function
 bind_textdomain_filter() for a way to change this behavior.
 
 One common mistake is this:
 
     print gettext "Hello $name!";
 
 Perl will interpolate the variable C<$name> I<before> the function
 will see the string.  Unless the corresponding message catalog 
 contains a message "Hello Tom!", "Hello Dick!" or "Hello Harry!",
 no translation will be found.
 
 Using printf() and friends has its own problems:
 
     print sprintf (gettext ("This is the %s %s."), $color, $thing);
 
 (The example is stupid because neither color nor thing will get
 translated here ...).
 
 In English the adjective (the color) will precede the noun, many
 other languages (for example French or Italian) differ here.  The 
 translator of the message may therefore have a hard time to find
 a translation that will still work and not sound stupid in the 
 target language.  Many C implementations of printf() allow to 
 change the order of the arguments, and a French translator could
 then say:
 
     "C'est le %2$s %1$s."
 
 Perl printf() implements this feature as of version 5.8 or better.
 Consequently you can only use it, if you are sure that your software
 will run with Perl 5.8 or a later version.
 
 Another disadvantage of using printf() is its cryptic syntax (maybe
 not for you but translators of your software may have their own
 opinion).
 
 See the description of the function C<__x()> in Locale::TextDomain(3)
 for a much better way to get around this problem.
 
 Non-ASCII message ids ...
 
 You should note that the function (and all other similar functions
 in this module) does a bytewise comparison of the B<MSGID> for the
 lookup in the translation catalog, no matter whether obscure utf-8
 flags are set on it, whether the string looks like utf-8, whether
 the utf8(3pm) pragma is used, or whatever other weird method past
 or future perl(1) versions invent for guessing character sets of
 strings.
 
 Using other than us-ascii characters in Perl source code is a call
 for trouble, a compatibility nightmare.  Furthermore, GNU gettext
 only lately introduced support for non-ascii character sets in sources,
 and support for this feature may not be available everywhere.  If
 you absolutely want to use B<MSGID>s in non-ascii character sets,
 it is wise to choose utf-8.  This will minimize the risk that perl(1)
 itself will mess with the strings, and it will also be a guaranty
 that you can later translate your project into arbitrary target
 languages.
 
 Other character sets can theoretically work.  Yet, using another
 character set in the Perl source code than the one used in your
 message catalogs will B<never> work, since the lookup is done bytewise,
 and all strings with non-ascii characters will not be found.
 
 Even if you have solved all these problems, there is still one show
 stopper left: The gettext runtime API lacks a possibility to specify 
 the character set of the source code (including the original strings).
 Consequently - in absence of a hint for the input encoding - strings 
 without a translation are not subject to output character set conversion.
 In other words: If the (non-determinable) output character set differs
 from the character set used in the source code, output can be a
 mixture of two character sets.  There is no point in trying to address
 this problem in the pure Perl version of the gettext functions.  because
 breaking compatibilty between the Perl and the C version is a price too
 high to pay.
 
 This all boils down to: Only use ASCII characters in your translatable
 strings!
 
 =item B<dgettext TEXTDOMAIN, MSGID>
 
 Like gettext(), but retrieves the message for the specified 
 B<TEXTDOMAIN> instead of the default domain.  In case you wonder what
 a textdomain is, you should really read on with Locale::TextDomain(3).
 
 =item B<dcgettext TEXTDOMAIN, MSGID, CATEGORY>
 
 Like dgettext() but retrieves the message from the specified B<CATEGORY>
 instead of the default category C<LC_MESSAGES>.
 
 =item B<ngettext MSGID, MSGID_PLURAL, COUNT>
 
 Retrieves the correct translation for B<COUNT> items.  In legacy software
 you will often find something like:
 
     print "$count file(s) deleted.\n";
 
 or
 
     printf "$count file%s deleted.\n", $count == 1 ? '' : 's';
 
 The first example looks awkward, the second will only work in English
 and languages with similar plural rules.  Before ngettext() was introduced,
 the best practice for internationalized programs was:
 
     if ($count == 1) {
         print gettext "One file deleted.\n";
     } else {
         printf gettext "%d files deleted.\n";
     }
 
 This is a nuisance for the programmer and often still not sufficient
 for an adequate translation.  Many languages have completely different
 ideas on numerals.  Some (French, Italian, ...) treat 0 and 1 alike,
 others make no distinction at all (Japanese, Korean, Chinese, ...),
 others have two or more plural forms (Russian, Latvian, Czech,
 Polish, ...).  The solution is:
 
     printf (ngettext ("One file deleted.\n",
                      "%d files deleted.\n",
                      $count), # argument to ngettext!
             $count);          # argument to printf!
 
 In English, or if no translation can be found, the first argument
 (B<MSGID>) is picked if C<$count> is one, the second one otherwise.
 For other languages, the correct plural form (of 1, 2, 3, 4, ...)
 is automatically picked, too.  You don't have to know anything about
 the plural rules in the target language, ngettext() will take care
 of that.
 
 This is most of the time sufficient but you will have to prove your
 creativity in cases like
 
     printf "%d file(s) deleted, and %d file(s) created.\n";
 
 =item B<dngettext TEXTDOMAIN, MSGID, MSGID_PLURAL, COUNT>
 
 Like ngettext() but retrieves the translation from the specified
 textdomain instead of the default domain.
 
 =item B<dcngettext TEXTDOMAIN, MSGID, MSGID_PLURAL, COUNT, CATEGORY>
 
 Like dngettext() but retrieves the translation from the specified
 category, instead of the default category C<LC_MESSAGES>.
 
 =item B<pgettext MSGCTXT, MSGID>
 
 Returns the translation of MSGID, given the context of MSGCTXT.
 
 Both items are used as a unique key into the message catalog.
 
 This allows the translator to have two entries for words that may
 translate to different foreign words based on their context. For
 example, the word "View" may be a noun or a verb, which may be
 used in a menu as File->View or View->Source.
 
     pgettext "Verb: To View", "View\n";
     pgettext "Noun: A View", "View\n";
 
 The above will both lookup different entries in the message catalog.
 
 A typical usage are GUI programs.  Imagine a program with a main
 menu and the notorious "Open" entry in the "File" menu.  Now imagine,
 there is another menu entry Preferences->Advanced->Policy where you have 
 a choice between the alternatives "Open" and "Closed".  In English, "Open"
 is the adequate text at both places.  In other languages, it is very
 likely that you need two different translations.  Therefore, you would
 now write:
 
     pgettext "File|", "Open";
     pgettext "Preferences|Advanced|Policy", "Open";
 
 In English, or if no translation can be found, the second argument
 (MSGID) is returned.
 
 The function was introduced with libintl-perl version 1.17.
 
 =item B<dpgettext TEXTDOMAIN, MSGCTXT, MSGID>
 
 Like pgettext(), but retrieves the message for the specified 
 B<TEXTDOMAIN> instead of the default domain.
 
 The function was introduced with libintl-perl version 1.17.
 
 =item B<dcpgettext TEXTDOMAIN, MSGCTXT, MSGID, CATEGORY>
 
 Like dpgettext() but retrieves the message from the specified B<CATEGORY>
 instead of the default category C<LC_MESSAGES>.
 
 The function was introduced with libintl-perl version 1.17.
 
 =item B<npgettext MSGCTXT, MSGID, MSGID_PLURAL, COUNT>
 
 Like ngettext() with the addition of context as in pgettext().
 
 In English, or if no translation can be found, the second argument
 (MSGID) is picked if $count is one, the third one otherwise.
 
 The function was introduced with libintl-perl version 1.17.
 
 =item B<dnpgettext TEXTDOMAIN, MSGCTXT, MSGID, MSGID_PLURAL, COUNT>
 
 Like npgettext() but retrieves the translation from the specified
 textdomain instead of the default domain.
 
 The function was introduced with libintl-perl version 1.17.
 
 =item B<dcnpgettext TEXTDOMAIN, MSGCTXT, MSGID, MSGID_PLURAL, COUNT, CATEGORY>
 
 Like dnpgettext() but retrieves the translation from the specified
 category, instead of the default category C<LC_MESSAGES>.
 
 The function was introduced with libintl-perl version 1.17.
 
 =item B<textdomain TEXTDOMAIN>
 
 Sets the default textdomain (initially 'messages').
 
 =item B<bindtextdomain TEXTDOMAIN, DIRECTORY>
 
 Binds B<TEXTDOMAIN> to B<DIRECTORY>.  Huh? An example:
 
     bindtextdomain "my-package", "./mylocale";
 
 Say, the selected locale (actually the selected locale for category
 C<LC_MESSAGES>) of the program is 'fr_CH', then the message catalog
 will be expected in F<./mylocale/fr_CH/LC_MESSAGES/my-package.mo>.
 
 =item B<bind_textdomain_codeset TEXTDOMAIN, ENCODING>
 
 Sets the output encoding for B<TEXTDOMAIN> to B<ENCODING>.  
 
 =item B<bind_textdomain_filter TEXTDOMAN, CODEREF, DATA>
 
 =item B<bind_textdomain_filter TEXTDOMAN, CODEREF>
 
 By default, Locale::Messages will turn the utf-8 flag of all returned
 messages off.  If you want to change this behavior, you can pass
 a reference to a subroutine that does different things - for example
 turn the utf-8 flag on, or leave it untouched.  The callback function 
 will be called with B<DATA> as the first, and the possibly 
 translated string as the second argument.  It should return the
 possibly modified string.
 
 If you want an object method to be called, pass the object itself
 in the data parameter and write a wrapper function.  Example:
 
     sub wrapper { 
         my ($string, $obj) = @_;
  
         $obj->filterMethod ($string);
     }
     my $obj = MyPackage->new;
 
     bind_textdomain_filter ('mydomain', \&wrapper, $obj);
 
 The function cannot fail and always returns a true value.
 
 B<Attention:> If you use the function for setting the utf-8 flag,
 it is B<your> responsability to ensure that the output is really
 utf-8.  You should only use it, if you have set the environment
 variable B<OUTPUT_CHARSET> to "utf-8".  Additionally you should
 call bind_textdomain_codeset() with "utf-8" as the second
 argument.
 
 Steven Haryanto has written a module Locale::TextDomain::UTF8(3pm)
 that addresses the same problem.
 
 This function has been introduced in libintl-perl 1.16 and it is
 B<not> part of the standard gettext API.
 
 =item B<turn_utf_8_on VARIABLE>
 
 Returns VARIABLE but with the UTF-8 flag (only known in Perl >=5.6)
 guaranteed to be turned on.  This function does not really fit into
 the module, but it is often handy nevertheless.
 
 The flag does B<not> mean that the string is in fact valid utf-8!
 
 The function was introduced with libintl-perl version 1.16.
 
 =item B<turn_utf_8_off VARIABLE>
 
 Returns VARIABLE but with the UTF-8 flag (only known in Perl >=5.6)
 guaranteed to be turned off.  This function does not really fit into
 the module, but it is often handy nevertheless.
 
 The function was introduced with libintl-perl version 1.07.
 
 =item B<select_package PACKAGE>
 
 By default, B<Locale::Messages> will try to load the XS version of
 the gettext implementation, i. e. Locale::gettext_xs(3) and will fall
 back to the pure Perl implementation Locale::gettext_pp(3).  You can
 override this behavior by passing the string "gettext_pp" or
 "gettext_xs" to the function select_package().  Passing "gettext_pp"
 here, will prefer the pure Perl implementation.
 
 You will normally want to use that in a BEGIN block of your main
 script.
 
 The function was introduced with libintl-perl version 1.03 and is not
 part of the standard gettext API.
 
 Beginning with version 1.22 you can pass other package names than "gettext_pp"
 or "gettext_xs" and use a completely different backend.  It is the caller's
 responsability to make sure that the selected package offers the same
 interface as the two standard packages.
 
 One package that offers that functionality is Locale::gettext_dumb(3pm).
 
 =item B<nl_putenv ENVSPEC>
 
 Resembles the ANSI C putenv(3) function.  The sole purpose of this 
 function is to work around some ideosyncrasies in the environment
 processing of Windows systems.  If you want to portably set or
 unset environment variables, use this function instead of directly
 manipulating C<%ENV>.
 
 The argument B<ENVSPEC> may have three different forms.
 
 =over 8
 
 =item B<LANGUAGE=fr_CH>
 
 This would set the environment variable C<LANGUAGE> to "fr_CH".
 
 =item B<LANGUAGE=>
 
 Normally, this will set the environment variable C<LANGUAGE> to an
 empty string.  Under Windows, however, the environment variable will
 be deleted instead (and is no longer present in C<%ENV>).  Since
 within libintl-perl empty environment variables are useless, consider
 this usage as deprecated.
 
 =item B<LANGUAGE>
 
 This will delete the environment variable B<LANGUAGE>.  If you are
 familiar with the brain-damaged implementation of putenv(3) (resp.
 _putenv()) in the so-called standard C library of MS-Windows, you
 may suspect that this is an invalid argument.  This is not the case!
 Passing a variable name not followed by an equal sign will always
 delete the variable, no matter which operating system you use.
 
 =back
 
 The function returns true for success, and false for failure.  Possible
 reasons for failure are an invalid syntax or - only under Windows -
 failure to allocate space for the new environment entry ($! will be
 set accordingly in this case).
 
 Why all this hassle?  The 32-bit versions of MS-DOS (currently
 Windows 95/98/ME/NT/2000/XP/CE/.NET) maintain two distinct blocks
 of environment variables per process.  Which block is considered
 the "correct" environment is a compile-time option of the Perl
 interpreter.  Unfortunately, if you have build the XS version 
 Locale::gettext_xs(3) under Windows, the underlying library may use 
 a different environment block, and changes you make to C<%ENV> may
 not be visible to the library.
 
 The function nl_putenv() is mostly a funny way of saying
 
     LANGUAGE=some_value
     
 but it does its best, to pass this information to the gettext 
 library.  Under other operating systems than Windows, it only
 operates on C<%ENV>, under Windows it will call the C library
 function _putenv() (after doing some cleanup to its arguments),
 before manipulating C<%ENV>.
 
 Please note, that your C<%ENV> is updated by nl_putenv() automatically.
 
 The function has been introduced in libintl-perl version 1.10.
 
 =item setlocale
 
 Modifies and queries program's locale, see the documentation for setlocale()
 in POSIX(3pm) instead.
 
 On some systems, when using GNU gettext, a call from C to setlocale() is
 - with the help of the C preprocessor - really a call to libintl_setlocale(),
 which is in turn a wrapper around the system setlocale(3).  Failure to call
 libintl_setlocale() may lead to certain malfunctions.  On such systems,
 B<Locale::Messages::setlocale()> will call the wrapper libintl_setlocale().
 If you want to avoid problems, you should therefore always call
 the setlocale() implementation in Locale::Messages(3pm).
 
 See L<https://rt.cpan.org/Public/Bug/Display.html?id=83980> or
 L<https://savannah.gnu.org/bugs/?38162>, and 
 L<https://savannah.gnu.org/bugs/?func=detailitem&item_id=44645> for a discussion
 of the problem.
 
 The function has been introduced in libintl-perl version 1.24.
 
 =back
 
 =head1 CONSTANTS
 
 You can (maybe) get the same constants from POSIX(3); see there for
 a detailed description
 
 =over 4
 
 =item B<LC_CTYPE>
 
 =item B<LC_NUMERIC>
 
 =item B<LC_TIME>
 
 =item B<LC_COLLATE>
 
 =item B<LC_MONETARY>
 
 =item B<LC_MESSAGES>
 
 This locale category was the reason that these constants from POSIX(3)
 were included here.  Even if it was present in your systems C include
 file F<locale.h>, it was not provided by POSIX(3).  Perl 5.8 and later
 seems to export the constant if available, although it is not documented
 in POSIX(3).
 
 Locale::Messages(3) makes an attempt to guess the value of this category for
 all systems, and assumes the arbitrary value 1729 otherwise.
 
 =item B<LC_ALL>
 
 If you specify the category B<LC_ALL> as the first argument to
 POSIX::setlocale(), I<all> locale categories will be affected at once.
 
 =back
 
 =head1 EXPORT TAGS
 
 The module does not export anything unless explicitely requested.
 You can import groups of functions via two tags:
 
 =over 4
 
 =item B<use Locale::Messages (':locale_h')>
 
 Imports the functions that are normally defined in the C include
 file F<locale.h>:
 
 =over 8
 
 =item B<gettext()>
 
 =item B<dgettext()>
 
 =item B<dcgettext()>
 
 =item B<ngettext()>
 
 =item B<dngettext()>
 
 =item B<dcngettext()>
 
 =item B<pgettext()>
 
 =item B<dpgettext()>
 
 =item B<dcpgettext()>
 
 =item B<npgettext()>
 
 =item B<dnpgettext()>
 
 =item B<dcnpgettext()>
 
 =item B<textdomain()>
 
 =item B<bindtextdomain()>
 
 =item B<bind_textdomain_codeset()>
 
 =back
 
 =item B<use Locale::Messages (':libintl_h')>
 
 Imports the locale category constants:
 
 =over 8
 
 =item B<LC_CTYPE>
 
 =item B<LC_NUMERIC>
 
 =item B<LC_TIME>
 
 =item B<LC_COLLATE>
 
 =item B<LC_MONETARY>
 
 =item B<LC_MESSAGES>
 
 =item B<LC_ALL>
 
 =back
 
 =back
 
 =head1 OTHER EXPORTS
 
 =item B<select_package PACKAGE>
 
 =head1 USAGE
 
 A complete example:
 
     1: use Locale::Messages qw (:locale_h :libintl_h);
     2: use POSIX qw (setlocale);
     3: setlocale (LC_MESSAGES, '');
     4: textdomain ('my-package');
     5: bindtextdomain ('my-package' => '/usr/local/share/locale');
     6:
     7: print gettext ("Hello world!\n");
 
 Step by step: Line 1 imports the necessary functions and constants.
 In line 3 we set the locale for category LC_MESSAGES to the default
 user settings.  For C programs you will often read that LC_ALL
 is the best category here but this will also change the locale for
 LC_NUMERIC and many programs will not work reliably after changing
 that category in Perl; choose your own poison!
 
 In line 4 we say that all messages (translations) without an explicit
 domain specification should be retrieved from the message catalog
 for the domain 'my-package'.  Line 5 has the effect that the message
 catalog will be searched under the directory F</usr/local/share/locale>.
 
 If the user has selected the locale 'fr_CH', and if the file 
 F</usr/local/share/locale/fr_CH/LC_MESSAGES/my-package.mo>
 exists, and if it contains a GNU message object file with a translation
 for the string "Hello world!\n", then line 7 will print the French
 translation (for Switzerland CH) to STDOUT.
 
 The documentation for GNU gettext explains how to extract translatable
 strings from your Perl files and how to create message catalogs.
 
 Another less portable example: If your system uses the GNU libc you
 should be able to find various files with the name F<libc.mo>, the
 message catalog for the library itself.  If you have found these
 files under F</usr/share/locale>, then you can try the following:
 
     use Locale::Messages qw (:locale_h :libintl_h);
     use POSIX qw (setlocale);
 
     setlocale LC_MESSAGES, "";
     textdomain "libc";
 
     # The following is actually not needed, since this is
     # one of the default search directories.
     bindtextdomain libc => '/usr/share/locale';
     bind_textdomain_codeset libc => 'iso-8859-1';
 
     print gettext ("No such file or directory");
 
 See Locale::TextDomain(3) for much simpler ways.
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::TextDomain(3pm), Locale::gettext_pp(3pm), Encode(3pm),
 Locale::TextDomain::UTF8(3pm), perllocale(3pm), POSIX(3pm), perl(1), 
 gettext(1), gettext(3)
 
 =cut
 
 __END__
 
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
### Locale/Recode.pm ###
 #! /bin/false
 
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Portable character conversion for Perl.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::Recode;
 
 use strict;
 
 require Locale::Recode::_Conversions;
 
 my $loaded = {};
 my $has_encode;
 
 sub new
 {
     my $class = ref($_[0]) || $_[0];
     shift;
     my %args = @_;
 
     my $self = bless {}, $class;
 
     my ($from_codeset, $to_codeset) = @args{qw (from to)};
     
     unless ($from_codeset && $to_codeset) {
 		require Carp;
         Carp::croak (<<EOF);
 	Usage: $class->new (from => FROM_CODESET, to => TO_CODESET);
 EOF
     }
 
     # Find a conversion path.
 	my $path = Locale::Recode::_Conversions->findPath ($from_codeset, 
 													   $to_codeset);
 	unless ($path) {
 		$self->{__error} = 'EINVAL';
 		return $self;
 	}
 
 	my @conversions = ();
 	foreach (@$path) {
 		my ($module, $from, $to) = @$_;
 		
 		unless ($loaded->{$module}) {
 			eval "require Locale::RecodeData::$module";
 			if ($@) {
 				$self->{__error} = $@;
 				return $self;
 			}
 			
 			$loaded->{$module} = 1;
 		}
 		
 		my $module_name = "Locale::RecodeData::$module";
 		my $method = 'new';
 		my $object = $module_name->$method (from => $from,
 											to => $to);
 		
 		push @conversions, $object;
 	}
 
 	$self->{__conversions} = \@conversions;
 		
     return $self;
 }
 
 sub resolveAlias
 {
 	my ($class, $alias) = @_;
 
 	return Locale::Recode::_Conversions->resolveAlias ($alias);
 }
 
 sub getSupported
 {
 	return [ Locale::Recode::_Conversions->listSupported ];
 }
 
 sub getCharsets
 {
 	my $self = shift;
 	my %all = map { $_ => 1 } @{&getSupported};
 
 	require Locale::Recode::_Aliases;
 
 	my $conversions = Locale::Recode::_Conversions->listSupported;
 	foreach my $charset (keys %{Locale::Recode::_Aliases::ALIASES()}) {
 		my $mime_name = $self->resolveAlias ($charset);
 		next unless exists $all{$mime_name};
 		$all{$charset} = 1;
 	}
 	
 	return [ keys %all ];
 }
 
 sub recode
 {
     my $self = $_[0];
 
     return if $self->{__error};
 
     return 1 unless defined $_[1];
 
     my $chain = $self->{__conversions};
     
     foreach my $module (@$chain) {
 		my $success = $module->_recode ($_[1]);
 		
 		unless ($success) {
 			$self->{__error} = $module->_getError;
 			return;
 		}
     }
 
     return 1;
 }
 
 sub getError
 {
     my $self = shift;
     my $error = $self->{__error} or return;
 
     if ('EINVAL' eq $error) {
 		return 'Invalid conversion';
     } else {
 		return $error;
     }
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::Recode - Object-Oriented Portable Charset Conversion
 
 =head1 SYNOPSIS
 
   use Locale::Recode;
 
   $cd = Locale::Recode->new (from => 'UTF-8',
                              to   => 'ISO-8859-1');
 
   die $cd->getError if $cd->getError;
 
   $cd->recode ($text) or die $cd->getError;
 
   $mime_name = Locale::Recode->resolveAlias ('latin-1');
 
   $supported = Locale::Recode->getSupported;
 
   $complete = Locale::Recode->getCharsets;
 
 =head1 DESCRIPTION
 
 This module provides routines that convert textual data from one
 codeset to another in a portable way.  The module has been started
 before Encode(3) was written.  It's main purpose today is to provide
 charset conversion even when Encode(3) is not available on the system.
 It should also work for older Perl versions without Unicode support.
 
 Internally Locale::Recode(3) will use Encode(3) whenever possible,
 to allow for a faster conversion and for a wider range of supported
 charsets, and will only fall back to the Perl implementation when
 Encode(3) is not available or does not support a particular charset
 that Locale::Recode(3) does.
 
 Locale::Recode(3) is part of libintl-perl, and it's main purpose is
 actually to implement a portable charset conversion framework for
 the message translation facilities described in Locale::TextDomain(3).
 
 =head1 CONSTRUCTOR
 
 The constructor C<new()> requires two named arguments:
 
 =over 4
 
 =item B<from>
 
 The encoding of the original data.  Case doesn't matter, aliases
 are resolved.
 
 =item B<to>
 
 The target encoding.  Again, case doesn't matter, and aliases
 are resolved.
 
 =back
 
 The constructor will never fail.  In case of an error, the object's
 internal state is set to bad and it will refuse to do any conversions.
 You can inquire the reason for the failure with the method
 getError().
 
 =head1 OBJECT METHODS
 
 The following object methods are available.
 
 =over 4
 
 =item B<recode (STRING)>
 
 Converts B<STRING> from the source encoding into the destination
 encoding.  In case of success, a truth value is returned, false
 otherwise.  You can inquire the reason for the failure with the
 method getError().
 
 =item B<getError>
 
 Returns either false if the object is not in an error state or
 an error message.
 
 =back
 
 =head1 CLASS METHODS
 
 The object provides some additional class methods:
 
 =over 4
 
 =item B<getSupported>
 
 Returns a reference to a list of all supported charsets.  This
 may implicitely load additional Encode(3) conversions like 
 Encode::HanExtra(3) which may produce considerable load on your
 system.
 
 The method is therefore not intended for regular use but rather
 for getting resp. displaying I<once> a list of available encodings.
 
 The members of the list are all converted to uppercase!
 
 =item B<getCharsets>
 
 Like getSupported() but also returns all available aliases.
 
 =back
 
 =head1 SUPPORTED CHARSETS
 
 The range of supported charsets is system-dependent.  The following
 somewhat special charsets are always available:
 
 =over 4
 
 =item B<UTF-8>
 
 UTF-8 is available independently of your Perl version.  For Perl 5.6
 or better or in the presence of Encode(3), conversions are not done
 in Perl but with the interfaces provided by these facilities which
 are written in C, hence much faster.
 
 Encoding data I<into> UTF-8 is fast, even if it is done in Perl.
 Decoding it in Perl may become quite slow.  If you frequently have
 to decode UTF-8 with B<Locale::Recode> you will probably want to
 make sure that you do that with Perl 5.6 or beter, or install Encode(3) to
 speed up things.
 
 =item B<INTERNAL>
 
 UTF-8 is fast to write but hard to read for applications.  It is 
 therefore not the worst for internal string representation but not
 far from that.  Locale::Recode(3) stores strings internally as a
 reference to an array of integer values like most programming languages
 (Perl is an exception) do, trading memory for performance.
 
 The integer values are the UCS-4 codes of the characters in host
 byte order.
 
 The encoding B<INTERNAL> is directly availabe via Locale::Recode(3)
 but of course you should not really use it for data exchange, unless
 you know what you are doing.
 
 =back
 
 Locale::Recode(3) has native support for a plethora of other encodings,
 most of them 8 bit encodings that are fast to decode, including most
 encodings used on popular micros like the ISO-8859-* series of encodings,
 most Windows-* encodings (also known as CP*), Macintosh, Atari, etc.
 
 =head1 NAMES AND ALIASES
 
 Each charset resp. encoding is available internally under a unique
 name.  Whenever the information was available, the preferred MIME name
 (see L<http://www.iana.org/assignments/character-sets/>) was chosen as 
 the internal name.
 
 Alias handling is quite strict.  The module does not make wild guesses
 at what you mean ("What's the meaning of the acronym JIS" is a valid
 alias for "7bit-jis" in Encode(3) ....) but aims at providing common
 aliases only.  The same applies to so-called aliases that are really 
 mistakes, like "utf8" for UTF-8.
 
 The module knows all aliases that are listed with the IANA character
 set registry (L<http://www.iana.org/assignments/character-sets/>), plus
 those known to libiconv version 1.8, and a bunch of additional ones.
 
 =head1 CONVERSION TABLES
 
 The conversion tables have either been taken from official sources
 like the IANA or the Unicode Consortium, from Bruno Haible's libiconv,
 or from the sources of the GNU libc and the regression tests for 
 libintl-perl will check for conformance here.  For some encodings this data
 differs from Encode(3)'s data which would cause these tests to fail.  
 In these cases, the module will not invoke the Encode(3) methods, but
 will fall back to the internal implementation for the sake of 
 consistency.
 
 The few encodings that are affected are so simple that you will not
 experience any real performance penalty unless you convert large chunks
 of data.  But the package is not really intended for such use anyway, and
 since Encode(3) is relatively new, I rather think that the differences
 are bugs in Encode which will be fixed soon.
 
 =head1 BUGS
 
 The module should provide fall back conversions for other Unicode
 encoding schemes like UCS-2, UCS-4 (big- and little-endian).
 
 The pure Perl UTF-8 decoder will not always handle corrupt UTF-8
 correctly, especially at the end and at the beginning of the string.
 This is not likely to be fixed, since the module's intention is not
 to be a consistency checker for UTF-8 data.
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Encode(3), iconv(3), iconv(1), recode(1), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/Recode/_Aliases.pm ###
 #! /bin/false
 
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Internally known aliases for charsets.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::Recode::_Aliases;
 
 use constant ALIASES => {
 	'1047' => 'IBM1047',
     '437' => 'IBM437',
     '850' => 'IBM850',
     '851' => 'IBM851',
     '852' => 'IBM852',
     '855' => 'IBM855',
     '857' => 'IBM857',
     '860' => 'IBM860',
     '861' => 'IBM861',
     '862' => 'IBM862',
     '863' => 'IBM863',
     '865' => 'IBM865',
     '866' => 'IBM866',
     '869' => 'IBM869',
     '904' => 'IBM904',
     'ANSI_X3.4-1968' => 'US-ASCII',
     'ANSI_X3.4-1986' => 'US-ASCII',
     'ARABIC' => 'ISO-8859-6',
     'ARABIC7' => 'ASMO_449',
     'ASCII' => 'US-ASCII',
     'ASMO-708' => 'ISO-8859-6',
 	'ATARIST' => 'ATARI-ST',
 	'ATARIST-EURO' => 'ATARI-ST-EURO',
 	'BIG-5' => 'BIG5',
 	'BIG-FIVE' => 'BIG5',
 	'BIG5-ETEN' => 'BIG5',
 	'BIG5HKSCS' => 'BIG5-HKSCS',
 	'BIGFIVE' => 'BIG5',
     'CA' => 'CSA_Z243.4-1985-1',
     'CCSID00924' => 'IBM00924',
     'CCSID01140' => 'IBM01140',
     'CCSID01141' => 'IBM01141',
     'CCSID01142' => 'IBM01142',
     'CCSID01143' => 'IBM01143',
     'CCSID01144' => 'IBM01144',
     'CCSID01145' => 'IBM01145',
     'CCSID01146' => 'IBM01146',
     'CCSID01147' => 'IBM01147',
     'CCSID01148' => 'IBM01148',
     'CCSID01149' => 'IBM01149',
     'CHINESE' => 'GB_2312-80',
     'CN' => 'GB_1988-80',
 	'CN-BIG5' => 'BIG5',
     'CP-AR' => 'IBM868',
     'CP-GR' => 'IBM869',
 	'CP-HU' => 'CWI',
     'CP-IS' => 'IBM861',
     'CP00924' => 'IBM00924',
     'CP01140' => 'IBM01140',
     'CP01141' => 'IBM01141',
     'CP01142' => 'IBM01142',
     'CP01143' => 'IBM01143',
     'CP01144' => 'IBM01144',
     'CP01145' => 'IBM01145',
     'CP01146' => 'IBM01146',
     'CP01147' => 'IBM01147',
     'CP01148' => 'IBM01148',
     'CP01149' => 'IBM01149',
     'CP037' => 'IBM037',
     'CP038' => 'IBM038',
 	'CP1004' => 'IBM1004',
     'CP1026' => 'IBM1026',
 	'CP1047' => 'IBM1047',
 	'CP1250' => 'WINDOWS-1250',
 	'CP1251' => 'WINDOWS-1251',
 	'CP1252' => 'WINDOWS-1252',
 	'CP1253' => 'WINDOWS-1253',
 	'CP1254' => 'WINDOWS-1254',
 	'CP1255' => 'WINDOWS-1255',
 	'CP1256' => 'WINDOWS-1256',
 	'CP1257' => 'WINDOWS-1257',
 	'CP1258' => 'WINDOWS-1258',
     'CP154' => 'PTCP154',
     'CP273' => 'IBM273',
     'CP274' => 'IBM274',
     'CP275' => 'IBM275',
     'CP278' => 'IBM278',
     'CP280' => 'IBM280',
     'CP281' => 'IBM281',
     'CP284' => 'IBM284',
     'CP285' => 'IBM285',
     'CP290' => 'IBM290',
     'CP297' => 'IBM297',
     'CP367' => 'US-ASCII',
     'CP420' => 'IBM420',
     'CP423' => 'IBM423',
     'CP424' => 'IBM424',
     'CP437' => 'IBM437',
     'CP500' => 'IBM500',
     'CP775' => 'IBM775',
     'CP819' => 'ISO-8859-1',
     'CP850' => 'IBM850',
     'CP851' => 'IBM851',
     'CP852' => 'IBM852',
     'CP855' => 'IBM855',
     'CP857' => 'IBM857',
     'CP860' => 'IBM860',
     'CP861' => 'IBM861',
     'CP862' => 'IBM862',
     'CP863' => 'IBM863',
     'CP864' => 'IBM864',
     'CP865' => 'IBM865',
     'CP866' => 'IBM866',
     'CP868' => 'IBM868',
     'CP869' => 'IBM869',
     'CP870' => 'IBM870',
     'CP871' => 'IBM871',
 	'CP874' => 'IBM874',
 	'CP875' => 'IBM875',
     'CP880' => 'IBM880',
     'CP891' => 'IBM891',
     'CP903' => 'IBM903',
     'CP904' => 'IBM904',
     'CP905' => 'IBM905',
     'CP918' => 'IBM918',
     'CP936' => 'GBK',
     'CSA7-1' => 'CSA_Z243.4-1985-1',
     'CSA7-2' => 'CSA_Z243.4-1985-2',
     'CSADOBESTANDARDENCODING' => 'ADOBE-STANDARD-ENCODING',
     'CSASCII' => 'US-ASCII',
     'CSA_T500-1983' => 'ANSI_X3.110-1983',
     'CSBIG5' => 'BIG5',
     'CSBOCU-1' => 'BOCU-1',
     'CSCESU-8' => 'CESU-8',
     'CSDECMCS' => 'DEC-MCS',
     'CSDKUS' => 'DK-US',
     'CSEBCDICATDEA' => 'EBCDIC-AT-DE-A',
     'CSEBCDICCAFR' => 'EBCDIC-CA-FR',
     'CSEBCDICDKNO' => 'EBCDIC-DK-NO',
     'CSEBCDICDKNOA' => 'EBCDIC-DK-NO-A',
     'CSEBCDICES' => 'EBCDIC-ES',
     'CSEBCDICESA' => 'EBCDIC-ES-A',
     'CSEBCDICESS' => 'EBCDIC-ES-S',
     'CSEBCDICFISE' => 'EBCDIC-FI-SE',
     'CSEBCDICFISEA' => 'EBCDIC-FI-SE-A',
     'CSEBCDICFR' => 'EBCDIC-FR',
     'CSEBCDICIT' => 'EBCDIC-IT',
     'CSEBCDICPT' => 'EBCDIC-PT',
     'CSEBCDICUK' => 'EBCDIC-UK',
     'CSEBCDICUS' => 'EBCDIC-US',
     'CSEUCFIXWIDJAPANESE' => 'EXTENDED_UNIX_CODE_FIXED_WIDTH_FOR_JAPANESE',
     'CSEUCKR' => 'EUC-KR',
     'CSEUCPKDFMTJAPANESE' => 'EUC-JP',
     'CSEUCTW' => 'EUC-TW',
     'CSGB2312' => 'GB2312',
     'CSHALFWIDTHKATAKANA' => 'JIS_X0201',
     'CSHPDESKTOP' => 'HP-DESKTOP',
     'CSHPLEGAL' => 'HP-LEGAL',
     'CSHPMATH8' => 'HP-MATH8',
     'CSHPPIFONT' => 'HP-PI-FONT',
     'CSHPPSMATH' => 'ADOBE-SYMBOL-ENCODING',
     'CSHPROMAN8' => 'HP-ROMAN8',
     'CSIBBM904' => 'IBM904',
     'CSIBM037' => 'IBM037',
     'CSIBM038' => 'IBM038',
     'CSIBM1026' => 'IBM1026',
     'CSIBM273' => 'IBM273',
     'CSIBM274' => 'IBM274',
     'CSIBM275' => 'IBM275',
     'CSIBM277' => 'IBM277',
     'CSIBM278' => 'IBM278',
     'CSIBM280' => 'IBM280',
     'CSIBM281' => 'IBM281',
     'CSIBM284' => 'IBM284',
     'CSIBM285' => 'IBM285',
     'CSIBM290' => 'IBM290',
     'CSIBM297' => 'IBM297',
     'CSIBM420' => 'IBM420',
     'CSIBM423' => 'IBM423',
     'CSIBM424' => 'IBM424',
     'CSIBM500' => 'IBM500',
     'CSIBM851' => 'IBM851',
     'CSIBM855' => 'IBM855',
     'CSIBM857' => 'IBM857',
     'CSIBM860' => 'IBM860',
     'CSIBM861' => 'IBM861',
     'CSIBM863' => 'IBM863',
     'CSIBM864' => 'IBM864',
     'CSIBM865' => 'IBM865',
     'CSIBM866' => 'IBM866',
     'CSIBM868' => 'IBM868',
     'CSIBM869' => 'IBM869',
     'CSIBM870' => 'IBM870',
     'CSIBM871' => 'IBM871',
     'CSIBM880' => 'IBM880',
     'CSIBM891' => 'IBM891',
     'CSIBM903' => 'IBM903',
     'CSIBM905' => 'IBM905',
     'CSIBM918' => 'IBM918',
     'CSIBMEBCDICATDE' => 'EBCDIC-AT-DE',
     'CSIBMSYMBOLS' => 'IBM-SYMBOLS',
     'CSIBMTHAI' => 'IBM-THAI',
     'CSINVARIANT' => 'INVARIANT',
     'CSISO102T617BIT' => 'T.61-7BIT',
     'CSISO10367BOX' => 'ISO_10367-BOX',
     'CSISO10646UTF1' => 'ISO-10646-UTF-1',
     'CSISO10SWEDISH' => 'SEN_850200_B',
     'CSISO111ECMACYRILLIC' => 'ECMA-CYRILLIC',
     'CSISO11SWEDISHFORNAMES' => 'SEN_850200_C',
     'CSISO121CANADIAN1' => 'CSA_Z243.4-1985-1',
     'CSISO122CANADIAN2' => 'CSA_Z243.4-1985-2',
     'CSISO123CSAZ24341985GR' => 'CSA_Z243.4-1985-GR',
     'CSISO128T101G2' => 'T.101-G2',
     'CSISO139CSN369103' => 'CSN_369103',
     'CSISO13JISC6220JP' => 'JIS_C6220-1969-JP',
     'CSISO141JUSIB1002' => 'JUS_I.B1.002',
     'CSISO143IECP271' => 'IEC_P27-1',
     'CSISO146SERBIAN' => 'JUS_I.B1.003-SERB',
     'CSISO147MACEDONIAN' => 'JUS_I.B1.003-MAC',
     'CSISO14JISC6220RO' => 'JIS_C6220-1969-RO',
     'CSISO150' => 'GREEK-CCITT',
     'CSISO150GREEKCCITT' => 'GREEK-CCITT',
     'CSISO151CUBA' => 'NC_NC00-10:81',
     'CSISO153GOST1976874' => 'GOST_19768-74',
     'CSISO158LAP' => 'LATIN-LAP',
     'CSISO159JISX02121990' => 'JIS_X0212-1990',
     'CSISO15ITALIAN' => 'IT',
     'CSISO16PORTUGUESE' => 'PT',
     'CSISO17SPANISH' => 'ES',
     'CSISO18GREEK7OLD' => 'GREEK7-OLD',
     'CSISO19LATINGREEK' => 'LATIN-GREEK',
     'CSISO2022JP' => 'ISO-2022-JP',
     'CSISO2022JP2' => 'ISO-2022-JP-2',
     'CSISO2022KR' => 'ISO-2022-KR',
     'CSISO2033' => 'ISO_2033-1983',
     'CSISO21GERMAN' => 'DIN_66003',
     'CSISO25FRENCH' => 'NF_Z_62-010_(1973)',
     'CSISO27LATINGREEK1' => 'LATIN-GREEK-1',
     'CSISO2INTLREFVERSION' => 'ISO_646.IRV:1983',
     'CSISO42JISC62261978' => 'JIS_C6226-1978',
     'CSISO47BSVIEWDATA' => 'BS_VIEWDATA',
     'CSISO49INIS' => 'INIS',
     'CSISO4UNITEDKINGDOM' => 'BS_4730',
     'CSISO50INIS8' => 'INIS-8',
     'CSISO51INISCYRILLIC' => 'INIS-CYRILLIC',
     'CSISO5427CYRILLIC' => 'ISO_5427',
     'CSISO5428GREEK' => 'ISO_5428:1980',
     'CSISO57GB1988' => 'GB_1988-80',
     'CSISO58GB231280' => 'GB_2312-80',
     'CSISO60DANISHNORWEGIAN' => 'NS_4551-1',
     'CSISO60NORWEGIAN1' => 'NS_4551-1',
     'CSISO61NORWEGIAN2' => 'NS_4551-2',
     'CSISO646BASIC1983' => 'ISO_646.BASIC:1983',
     'CSISO646DANISH' => 'DS_2089',
     'CSISO6937ADD' => 'ISO_6937-2-25',
     'CSISO69FRENCH' => 'NF_Z_62-010',
     'CSISO70VIDEOTEXSUPP1' => 'VIDEOTEX-SUPPL',
     'CSISO84PORTUGUESE2' => 'PT2',
     'CSISO85SPANISH2' => 'ES2',
     'CSISO86HUNGARIAN' => 'MSZ_7795.3',
     'CSISO87JISX0208' => 'JIS_C6226-1983',
     'CSISO88596E' => 'ISO-8859-6-E',
     'CSISO88596I' => 'ISO-8859-6-I',
     'CSISO88598E' => 'ISO-8859-8-E',
     'CSISO88598I' => 'ISO-8859-8-I',
     'CSISO8859SUPP' => 'ISO_8859-SUPP',
     'CSISO88GREEK7' => 'GREEK7',
     'CSISO89ASMO449' => 'ASMO_449',
     'CSISO90' => 'ISO-IR-90',
     'CSISO91JISC62291984A' => 'JIS_C6229-1984-A',
     'CSISO92JISC62991984B' => 'JIS_C6229-1984-B',
     'CSISO93JIS62291984BADD' => 'JIS_C6229-1984-B-ADD',
     'CSISO94JIS62291984HAND' => 'JIS_C6229-1984-HAND',
     'CSISO95JIS62291984HANDADD' => 'JIS_C6229-1984-HAND-ADD',
     'CSISO96JISC62291984KANA' => 'JIS_C6229-1984-KANA',
     'CSISO99NAPLPS' => 'ANSI_X3.110-1983',
     'CSISOLATIN1' => 'ISO-8859-1',
     'CSISOLATIN2' => 'ISO-8859-2',
     'CSISOLATIN3' => 'ISO-8859-3',
     'CSISOLATIN4' => 'ISO-8859-4',
     'CSISOLATIN5' => 'ISO-8859-9',
     'CSISOLATIN6' => 'ISO-8859-10',
     'CSISOLATINARABIC' => 'ISO-8859-6',
     'CSISOLATINCYRILLIC' => 'ISO-8859-5',
     'CSISOLATINGREEK' => 'ISO-8859-7',
     'CSISOLATINHEBREW' => 'ISO-8859-8',
     'CSISOTEXTCOMM' => 'ISO_6937-2-ADD',
     'CSJISENCODING' => 'JIS_ENCODING',
     'CSKOI8R' => 'KOI8-R',
     'CSKSC56011987' => 'KS_C_5601-1987',
     'CSKSC5636' => 'KSC5636',
     'CSMACINTOSH' => 'MACINTOSH',
     'CSMICROSOFTPUBLISHING' => 'MICROSOFT-PUBLISHING',
     'CSMNEM' => 'MNEM',
     'CSMNEMONIC' => 'MNEMONIC',
     'CSNATSDANO' => 'NATS-DANO',
     'CSNATSDANOADD' => 'NATS-DANO-ADD',
     'CSNATSSEFI' => 'NATS-SEFI',
     'CSNATSSEFIADD' => 'NATS-SEFI-ADD',
     'CSPC775BALTIC' => 'IBM775',
     'CSPC850MULTILINGUAL' => 'IBM850',
     'CSPC862LATINHEBREW' => 'IBM862',
     'CSPC8CODEPAGE437' => 'IBM437',
     'CSPC8DANISHNORWEGIAN' => 'PC8-DANISH-NORWEGIAN',
     'CSPC8TURKISH' => 'PC8-TURKISH',
     'CSPCP852' => 'IBM852',
     'CSPTCP154' => 'PTCP154',
     'CSSHIFTJIS' => 'SHIFT_JIS',
     'CSUCS4' => 'ISO-10646-UCS-4',
     'CSUNICODE' => 'ISO-10646-UCS-2',
     'CSUNICODE11' => 'UNICODE-1-1',
     'CSUNICODE11UTF7' => 'UNICODE-1-1-UTF-7',
     'CSUNICODEASCII' => 'ISO-10646-UCS-BASIC',
     'CSUNICODEIBM1264' => 'ISO-UNICODE-IBM-1264',
     'CSUNICODEIBM1265' => 'ISO-UNICODE-IBM-1265',
     'CSUNICODEIBM1268' => 'ISO-UNICODE-IBM-1268',
     'CSUNICODEIBM1276' => 'ISO-UNICODE-IBM-1276',
     'CSUNICODELATIN1' => 'ISO-10646-UNICODE-LATIN1',
     'CSUNKNOWN8BIT' => 'UNKNOWN-8BIT',
     'CSUSDK' => 'US-DK',
     'CSVENTURAINTERNATIONAL' => 'VENTURA-INTERNATIONAL',
     'CSVENTURAMATH' => 'VENTURA-MATH',
     'CSVENTURAUS' => 'VENTURA-US',
     'CSVIQR' => 'VIQR',
     'CSVISCII' => 'VISCII',
     'CSWINDOWS30LATIN1' => 'ISO-8859-1-WINDOWS-3.0-LATIN-1',
     'CSWINDOWS31J' => 'WINDOWS-31J',
     'CSWINDOWS31LATIN1' => 'ISO-8859-1-WINDOWS-3.1-LATIN-1',
     'CSWINDOWS31LATIN2' => 'ISO-8859-2-WINDOWS-LATIN-2',
     'CSWINDOWS31LATIN5' => 'ISO-8859-9-WINDOWS-LATIN-5',
     'CUBA' => 'NC_NC00-10:81',
 	'CWI-2' => 'CWI',
     'CYRILLIC' => 'ISO-8859-5',
     'CYRILLIC-ASIAN' => 'PTCP154',
     'DE' => 'DIN_66003',
     'DEC' => 'DEC-MCS',
     'DK' => 'DS_2089',
     'DS2089' => 'DS_2089',
     'E13B' => 'ISO_2033-1983',
     'EBCDIC-BE' => 'IBM274',
     'EBCDIC-BR' => 'IBM275',
     'EBCDIC-CP-AR1' => 'IBM420',
     'EBCDIC-CP-AR2' => 'IBM918',
     'EBCDIC-CP-BE' => 'IBM500',
     'EBCDIC-CP-CA' => 'IBM037',
     'EBCDIC-CP-CH' => 'IBM500',
     'EBCDIC-CP-DK' => 'IBM277',
     'EBCDIC-CP-ES' => 'IBM284',
     'EBCDIC-CP-FI' => 'IBM278',
     'EBCDIC-CP-FR' => 'IBM297',
     'EBCDIC-CP-GB' => 'IBM285',
     'EBCDIC-CP-GR' => 'IBM423',
     'EBCDIC-CP-HE' => 'IBM424',
     'EBCDIC-CP-IS' => 'IBM871',
     'EBCDIC-CP-IT' => 'IBM280',
     'EBCDIC-CP-NL' => 'IBM037',
     'EBCDIC-CP-NO' => 'IBM277',
     'EBCDIC-CP-ROECE' => 'IBM870',
     'EBCDIC-CP-SE' => 'IBM278',
     'EBCDIC-CP-TR' => 'IBM905',
     'EBCDIC-CP-US' => 'IBM037',
     'EBCDIC-CP-WT' => 'IBM037',
     'EBCDIC-CP-YU' => 'IBM870',
     'EBCDIC-CYRILLIC' => 'IBM880',
     'EBCDIC-DE-273+EURO' => 'IBM01141',
     'EBCDIC-DK-277+EURO' => 'IBM01142',
     'EBCDIC-ES-284+EURO' => 'IBM01145',
     'EBCDIC-FI-278+EURO' => 'IBM01143',
     'EBCDIC-FR-297+EURO' => 'IBM01147',
     'EBCDIC-GB-285+EURO' => 'IBM01146',
 	'EBCDIC-GREEK' => 'IBM875',
     'EBCDIC-INT' => 'IBM038',
 	'EBCDIC-INT1' => 'IBM256',
     'EBCDIC-INTERNATIONAL-500+EURO' => 'IBM01148',
     'EBCDIC-IS-871+EURO' => 'IBM01149',
     'EBCDIC-IT-280+EURO' => 'IBM01144',
     'EBCDIC-JP-E' => 'IBM281',
     'EBCDIC-JP-KANA' => 'IBM290',
     'EBCDIC-LATIN9--EURO' => 'IBM00924',
     'EBCDIC-NO-277+EURO' => 'IBM01142',
     'EBCDIC-SE-278+EURO' => 'IBM01143',
     'EBCDIC-US-37+EURO' => 'IBM01140',
     'ECMA-114' => 'ISO-8859-6',
     'ECMA-118' => 'ISO-8859-7',
     'ELOT_928' => 'ISO-8859-7',
 	'EUC-CN' => 'CN-GB',
 	'EUCCN' => 'CN-GB',
 	'EUCJP' => 'EUC-JP',
 	'EUCKR' => 'EUC-KR',
 	'EUCTW' => 'EUC-TW',
     'EXTENDED_UNIX_CODE_PACKED_FORMAT_FOR_JAPANESE' => 'EUC-JP',
     'FI' => 'SEN_850200_B',
     'FR' => 'NF_Z_62-010',
 	'FRISS' => 'EBCDIC-IS-FRISS',
     'GB' => 'BS_4730',
     'GB2312' => 'CN-GB',
 	'GBK' => 'CP936',
     'GREEK' => 'ISO-8859-7',
     'GREEK8' => 'ISO-8859-7',
     'HEBREW' => 'ISO-8859-8',
     'HU' => 'MSZ_7795.3',
 	'HZ-GB-2312' => 'HZ',
     'IBM367' => 'US-ASCII',
 	'IBM775' => 'CP775',
     'IBM819' => 'ISO-8859-1',
     'IRV' => 'ISO_646.IRV:1983',
     'ISO-10646' => 'ISO-10646-UNICODE-LATIN1',
     'ISO-CELTIC' => 'ISO-8859-14',
     'ISO-IR-10' => 'SEN_850200_B',
     'ISO-IR-100' => 'ISO-8859-1',
     'ISO-IR-101' => 'ISO-8859-2',
     'ISO-IR-102' => 'T.61-7BIT',
     'ISO-IR-109' => 'ISO-8859-3',
     'ISO-IR-11' => 'SEN_850200_C',
     'ISO-IR-110' => 'ISO-8859-4',
     'ISO-IR-111' => 'ECMA-CYRILLIC',
     'ISO-IR-121' => 'CSA_Z243.4-1985-1',
     'ISO-IR-122' => 'CSA_Z243.4-1985-2',
     'ISO-IR-123' => 'CSA_Z243.4-1985-GR',
     'ISO-IR-126' => 'ISO-8859-7',
     'ISO-IR-127' => 'ISO-8859-6',
     'ISO-IR-128' => 'T.101-G2',
     'ISO-IR-13' => 'JIS_C6220-1969-JP',
     'ISO-IR-138' => 'ISO-8859-8',
     'ISO-IR-139' => 'CSN_369103',
     'ISO-IR-14' => 'JIS_C6220-1969-RO',
     'ISO-IR-141' => 'JUS_I.B1.002',
     'ISO-IR-142' => 'ISO_6937-2-ADD',
     'ISO-IR-143' => 'IEC_P27-1',
     'ISO-IR-144' => 'ISO-8859-5',
     'ISO-IR-146' => 'JUS_I.B1.003-SERB',
     'ISO-IR-147' => 'JUS_I.B1.003-MAC',
     'ISO-IR-148' => 'ISO-8859-9',
     'ISO-IR-149' => 'KS_C_5601-1987',
     'ISO-IR-15' => 'IT',
     'ISO-IR-150' => 'GREEK-CCITT',
     'ISO-IR-151' => 'NC_NC00-10:81',
     'ISO-IR-152' => 'ISO_6937-2-25',
     'ISO-IR-153' => 'GOST_19768-74',
     'ISO-IR-154' => 'ISO_8859-SUPP',
     'ISO-IR-155' => 'ISO_10367-BOX',
     'ISO-IR-157' => 'ISO-8859-10',
     'ISO-IR-158' => 'LATIN-LAP',
     'ISO-IR-159' => 'JIS_X0212-1990',
     'ISO-IR-16' => 'PT',
 	'ISO-IR-166' => 'TIS-620',
     'ISO-IR-17' => 'ES',
 	'ISO-IR-179' => 'ISO-8859-13',
     'ISO-IR-18' => 'GREEK7-OLD',
     'ISO-IR-19' => 'LATIN-GREEK',
     'ISO-IR-199' => 'ISO-8859-14',
     'ISO-IR-2' => 'ISO_646.IRV:1983',
     'ISO-IR-203' => 'ISO-8859-15',
     'ISO-IR-21' => 'DIN_66003',
     'ISO-IR-226' => 'ISO-8859-16',
     'ISO-IR-25' => 'NF_Z_62-010_(1973)',
     'ISO-IR-27' => 'LATIN-GREEK-1',
     'ISO-IR-37' => 'ISO_5427',
     'ISO-IR-4' => 'BS_4730',
     'ISO-IR-42' => 'JIS_C6226-1978',
     'ISO-IR-47' => 'BS_VIEWDATA',
     'ISO-IR-49' => 'INIS',
     'ISO-IR-50' => 'INIS-8',
     'ISO-IR-51' => 'INIS-CYRILLIC',
     'ISO-IR-54' => 'ISO_5427-EXT',
     'ISO-IR-55' => 'ISO_5428',
     'ISO-IR-57' => 'GB_1988-80',
     'ISO-IR-58' => 'GB_2312-80',
     'ISO-IR-6' => 'US-ASCII',
     'ISO-IR-60' => 'NS_4551-1',
     'ISO-IR-61' => 'NS_4551-2',
     'ISO-IR-69' => 'NF_Z_62-010',
     'ISO-IR-70' => 'VIDEOTEX-SUPPL',
     'ISO-IR-79' => 'ISO-8859-13',
     'ISO-IR-8-1' => 'NATS-SEFI',
     'ISO-IR-8-2' => 'NATS-SEFI-ADD',
     'ISO-IR-84' => 'PT2',
     'ISO-IR-85' => 'ES2',
     'ISO-IR-86' => 'MSZ_7795.3',
     'ISO-IR-87' => 'JIS_C6226-1983',
     'ISO-IR-88' => 'GREEK7',
     'ISO-IR-89' => 'ASMO_449',
     'ISO-IR-9-1' => 'NATS-DANO',
     'ISO-IR-9-2' => 'NATS-DANO-ADD',
     'ISO-IR-91' => 'JIS_C6229-1984-A',
     'ISO-IR-92' => 'JIS_C6229-1984-B',
     'ISO-IR-93' => 'JIS_C6229-1984-B-ADD',
     'ISO-IR-94' => 'JIS_C6229-1984-HAND',
     'ISO-IR-95' => 'JIS_C6229-1984-HAND-ADD',
     'ISO-IR-96' => 'JIS_C6229-1984-KANA',
     'ISO-IR-98' => 'ISO_2033-1983',
     'ISO-IR-99' => 'ANSI_X3.110-1983',
     'ISO5427CYRILLIC1981' => 'ISO_5427:1981',
     'ISO646-CA' => 'CSA_Z243.4-1985-1',
     'ISO646-CA2' => 'CSA_Z243.4-1985-2',
     'ISO646-CN' => 'GB_1988-80',
     'ISO646-CU' => 'NC_NC00-10:81',
     'ISO646-DE' => 'DIN_66003',
     'ISO646-DK' => 'DS_2089',
     'ISO646-ES' => 'ES',
     'ISO646-ES2' => 'ES2',
     'ISO646-FI' => 'SEN_850200_B',
     'ISO646-FR' => 'NF_Z_62-010',
     'ISO646-FR1' => 'NF_Z_62-010_(1973)',
     'ISO646-GB' => 'BS_4730',
     'ISO646-HU' => 'MSZ_7795.3',
     'ISO646-IT' => 'IT',
     'ISO646-JP' => 'JIS_C6220-1969-RO',
     'ISO646-JP-OCR-B' => 'JIS_C6229-1984-B',
     'ISO646-KR' => 'KSC5636',
     'ISO646-NO' => 'NS_4551-1',
     'ISO646-NO2' => 'NS_4551-2',
     'ISO646-PT' => 'PT',
     'ISO646-PT2' => 'PT2',
     'ISO646-SE' => 'SEN_850200_B',
     'ISO646-SE2' => 'SEN_850200_C',
     'ISO646-US' => 'US-ASCII',
     'ISO646-YU' => 'JUS_I.B1.002',
 	'ISO_5427:1981' => 'ISO_5427-EXT',
     'ISO_5428:1980' => 'ISO_5428',
     'ISO_646.IRV:1991' => 'US-ASCII',
     'ISO_8859-1' => 'ISO-8859-1',
     'ISO_8859-1:1987' => 'ISO-8859-1',
     'ISO_8859-10' => 'ISO-8859-10',
     'ISO_8859-10:1992' => 'ISO-8859-10',
     'ISO_8859-13' => 'ISO-8859-13',
     'ISO_8859-14' => 'ISO-8859-14',
     'ISO_8859-14:1998' => 'ISO-8859-14',
     'ISO_8859-15' => 'ISO-8859-15',
     'ISO_8859-15:1998' => 'ISO-8859-15',
     'ISO_8859-16' => 'ISO-8859-16',
     'ISO_8859-16:2001' => 'ISO-8859-16',
     'ISO_8859-1:1987' => 'ISO-8859-1',
     'ISO_8859-2' => 'ISO-8859-2',
     'ISO_8859-2:1987' => 'ISO-8859-2',
     'ISO_8859-3' => 'ISO-8859-3',
     'ISO_8859-3:1988' => 'ISO-8859-3',
     'ISO_8859-4' => 'ISO-8859-4',
     'ISO_8859-4:1988' => 'ISO-8859-4',
     'ISO_8859-5' => 'ISO-8859-5',
     'ISO_8859-5:1988' => 'ISO-8859-5',
     'ISO_8859-6' => 'ISO-8859-6',
     'ISO_8859-6-E' => 'ISO-8859-6-E',
     'ISO_8859-6-I' => 'ISO-8859-6-I',
     'ISO_8859-6:1987' => 'ISO-8859-6',
     'ISO_8859-7' => 'ISO-8859-7',
     'ISO_8859-7:1987' => 'ISO-8859-7',
     'ISO_8859-8' => 'ISO-8859-8',
     'ISO_8859-8-E' => 'ISO-8859-8-E',
     'ISO_8859-8-I' => 'ISO-8859-8-I',
     'ISO_8859-8:1988' => 'ISO-8859-8',
     'ISO_8859-9' => 'ISO-8859-9',
     'ISO_8859-9:1989' => 'ISO-8859-9',
     'ISO_9036' => 'ASMO_449',
     'JIS_C6220-1969' => 'JIS_C6220-1969-JP',
     'JIS_X0208-1983' => 'JIS_C6226-1983',
     'JP' => 'JIS_C6220-1969-RO',
     'JP-OCR-A' => 'JIS_C6229-1984-A',
     'JP-OCR-B' => 'JIS_C6229-1984-B',
     'JP-OCR-B-ADD' => 'JIS_C6229-1984-B-ADD',
     'JP-OCR-HAND' => 'JIS_C6229-1984-HAND',
     'JP-OCR-HAND-ADD' => 'JIS_C6229-1984-HAND-ADD',
     'JS' => 'JUS_I.B1.002',
     'KATAKANA' => 'JIS_C6220-1969-JP',
     'KOREAN' => 'KS_C_5601-1987',
     'KSC_5601' => 'KS_C_5601-1987',
     'KS_C_5601-1989' => 'KS_C_5601-1987',
     'L1' => 'ISO-8859-1',
     'L10' => 'ISO-8859-16',
     'L2' => 'ISO-8859-2',
     'L3' => 'ISO-8859-3',
     'L4' => 'ISO-8859-4',
     'L5' => 'ISO-8859-9',
     'L6' => 'ISO-8859-10',
 	'L7' => 'ISO-8859-13',
     'L8' => 'ISO-8859-14',
     'LAP' => 'LATIN-LAP',
     'LATIN-9' => 'ISO-8859-15',
     'LATIN1' => 'ISO-8859-1',
     'LATIN1-2-5' => 'ISO_8859-SUPP',
     'LATIN10' => 'ISO-8859-16',
     'LATIN2' => 'ISO-8859-2',
     'LATIN3' => 'ISO-8859-3',
     'LATIN4' => 'ISO-8859-4',
     'LATIN5' => 'ISO-8859-9',
     'LATIN6' => 'ISO-8859-10',
 	'LATIN7' => 'ISO-8859-13',
     'LATIN8' => 'ISO-8859-14',
     'MAC' => 'MACINTOSH',
 	'MAC-ARABIC' => 'MACARABIC',
 	'MAC-CENTRALEUROPE' => 'MACCENTRALEUROPE',
 	'MAC-CROATIAN' => 'MACCROATIAN',
 	'MAC-CYRILLIC' => 'MACCYRILLIC',
 	'MAC-GREEK' => 'MACGREEK',
 	'MAC-HEBREW' => 'MACHEBREW',
 	'MAC-ICELAND' => 'MACICELAND',
 	'MAC-ROMANIA' => 'MACROMANIA',
 	'MAC-THAI' => 'MACTHAI',
 	'MAC-TURKISH' => 'MACTURKISH',
 	'MAC-UKRAINE' => 'MACUKRAINE',
     'MACEDONIAN' => 'JUS_I.B1.003-MAC',
 	'MS-ARAB' => 'WINDOWS-1256',
 	'MS-ANSI' => 'WINDOWS-1252',
 	'MS-EE' => 'WINDOWS-1250',
 	'MS-CYRL' => 'WINDOWS-1251',
 	'MS-GREEK' => 'WINDOWS-1253',
 	'MS-HEBR' => 'WINDOWS-1255',
 	'MS-TURK' => 'WINDOWS-1254',
     'MS936' => 'GBK',
     'MS_KANJI' => 'SHIFT_JIS',
     'NAPLPS' => 'ANSI_X3.110-1983',
     'NO' => 'NS_4551-1',
     'NO2' => 'NS_4551-2',
 	'OS2LATIN1' => 'IBM1004',
     'PT154' => 'PTCP154',
     'R8' => 'HP-ROMAN8',
     'REF' => 'ISO_646.BASIC:1983',
     'ROMAN8' => 'HP-ROMAN8',
     'SE' => 'SEN_850200_B',
     'SE2' => 'SEN_850200_C',
     'SERBIAN' => 'JUS_I.B1.003-SERB',
     'ST_SEV_358-88' => 'GOST_19768-74',
     'T.61' => 'T.61-8BIT',
 	'TIS620' => 'TIS-620',
 	'TIS620-0' => 'TIS-620',
 	'TIS620.2529-1' => 'TIS-620',
 	'TIS620.2533-0' => 'TIS-620',
 	'TIS620.2533-1' => 'TIS-620',
 	'UHC' => 'CP949',
     'UK' => 'BS_4730',
     'US' => 'US-ASCII',
 	'VISCII1.1-1' => 'VISCII',
 	'WINBALTRIM' => 'WINDOWS-1257',
 	'WINDOWS-874' => 'CP874',
     'WINDOWS-936' => 'GBK',
 	'WINDOWS-SAMI2' => 'WIN-SAMI-2',
 	'WS2' => 'WIN-SAMI-2',
     'X0201' => 'JIS_X0201',
     'X0201-7' => 'JIS_C6220-1969-JP',
     'X0208' => 'JIS_C6226-1983',
     'X0212' => 'JIS_X0212-1990',
     'YU' => 'JUS_I.B1.002',
 	'X-ATARI-ST' => 'ATARI-ST',
 	'X-ATARIST' => 'ATARI-ST',
 	'X-ATARI-ST-EURO' => 'ATARI-ST-EURO',
 	'X-ATARIST-EURO' => 'ATARI-ST-EURO',
 	'X-MAC-ARABIC' => 'MACARABIC',
 	'X-MAC-CENTRALEUROPE' => 'MACCENTRALEUROPE',
 	'X-MAC-CROATIAN' => 'MACCROATIAN',
 	'X-MAC-CYRILLIC' => 'MACCYRILLIC',
 	'X-MAC-GREEK' => 'MACGREEK',
 	'X-MAC-HEBREW' => 'MACHEBREW',
 	'X-MAC-ICELAND' => 'MACICELAND',
 	'X-MAC-ROMANIA' => 'MACROMANIA',
 	'X-MAC-THAI' => 'MACTHAI',
 	'X-MAC-TURKISH' => 'MACTURKISH',
 	'X-MAC-UKRAINE' => 'MACUKRAINE',
 	'X-MACARABIC' => 'MACARABIC',
 	'X-MACCENTRALEUROPE' => 'MACCENTRALEUROPE',
 	'X-MACCROATIAN' => 'MACCROATIAN',
 	'X-MACCYRILLIC' => 'MACCYRILLIC',
 	'X-MACGREEK' => 'MACGREEK',
 	'X-MACHEBREW' => 'MACHEBREW',
 	'X-MACICELAND' => 'MACICELAND',
 	'X-MACROMANIA' => 'MACROMANIA',
 	'X-MACTHAI' => 'MACTHAI',
 	'X-MACTURKISH' => 'MACTURKISH',
 	'X-MACUKRAINE' => 'MACUKRAINE',
 };
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::Recode::_Aliases - Internal Charset Alias Database for libintl-perl
 
 =head1 SYNOPSIS
 
 use Locale::Recode::_Aliases
 
 die "This module is internal to libintl.  Do not use it directly!\n";
 
 =head1 DESCRIPTION
 
 Contains a list of codeset aliases that are known internally to
 libintl.
 
 =head1 CONSTANTS
 
 =over 4
 
 =item ALIASES
 
 The constant B<Locale::Recode::_Aliases::ALIASES> contains a hash reference
 the keys of which are internally known charset alias names all in 
 uppercase.  The corresponding value is the canonical name of the charset.
 
 =back
 
 =head1 BUGS
 
 The format of the lookup table will most probably change, do not rely
 on the current format!
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/Recode/_Conversions.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # List of internally known conversions.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::Recode::_Conversions;
 
 use strict;
 use integer;
 
 use vars qw ($conversions $optional_conversions);
 
 # These are the canonical names of the encodings always available.
 $conversions = {
 	'ASMO_449' => 'ASMO_449',
 	'ATARI-ST-EURO' => 'ATARI_ST_EURO',
 	'ATARI-ST' => 'ATARI_ST',
 	'CP10007' => 'CP10007',
 	'CSN_369103' => 'CSN_369103',
 	'CWI' => 'CWI',
 	'DEC-MCS' => 'DEC_MCS',
 	'EBCDIC-AT-DE-A' => 'EBCDIC_AT_DE_A',
 	'EBCDIC-AT-DE' => 'EBCDIC_AT_DE',
 	'EBCDIC-CA-FR' => 'EBCDIC_CA_FR',
 	'EBCDIC-DK-NO-A' => 'EBCDIC_DK_NO_A',
 	'EBCDIC-DK-NO' => 'EBCDIC_DK_NO',
 	'EBCDIC-ES-A' => 'EBCDIC_ES_A',
 	'EBCDIC-ES-S' => 'EBCDIC_ES_S',
 	'EBCDIC-ES' => 'EBCDIC_ES',
 	'EBCDIC-FI-SE-A' => 'EBCDIC_FI_SE_A',
 	'EBCDIC-FI-SE' => 'EBCDIC_FI_SE',
 	'EBCDIC-FR' => 'EBCDIC_FR',
 	'EBCDIC-IS-FRISS' => 'EBCDIC_IS_FRISS',
 	'EBCDIC-IT' => 'EBCDIC_IT',
 	'EBCDIC-PT' => 'EBCDIC_PT',
 	'EBCDIC-UK' => 'EBCDIC_UK',
 	'EBCDIC-US' => 'EBCDIC_US',
 	'ECMA-CYRILLIC' => 'ECMA_CYRILLIC',
 	'GEORGIAN-ACADEMY' => 'GEORGIAN_ACADEMY',
 	'GEORGIAN-PS' => 'GEORGIAN_PS',
 	'GOST_19768-74' => 'GOST_19768_74',
 	'GREEK-CCITT' => 'GREEK_CCITT',
 	'GREEK7-OLD' => 'GREEK7_OLD',
 	'GREEK7' => 'GREEK7',
 	'HP-ROMAN8' => 'HP_ROMAN8',
 	'IBM037' => 'IBM037',
 	'IBM038' => 'IBM038',
 	'IBM1004' => 'IBM1004',
 	'IBM1026' => 'IBM1026',
 	'IBM1047' => 'IBM1047',
 	'IBM256' => 'IBM256',
 	'IBM273' => 'IBM273',
 	'IBM274' => 'IBM274',
 	'IBM275' => 'IBM275',
 	'IBM277' => 'IBM277',
 	'IBM278' => 'IBM278',
 	'IBM280' => 'IBM280',
 	'IBM281' => 'IBM281',
 	'IBM284' => 'IBM284',
 	'IBM285' => 'IBM285',
 	'IBM290' => 'IBM290',
 	'IBM297' => 'IBM297',
 	'IBM420' => 'IBM420',
 	'IBM423' => 'IBM423',
 	'IBM424' => 'IBM424',
 	'IBM437' => 'IBM437',
 	'IBM500' => 'IBM500',
 	'IBM850' => 'IBM850',
 	'IBM851' => 'IBM851',
 	'IBM852' => 'IBM852',
 	'IBM855' => 'IBM855',
 	'IBM857' => 'IBM857',
 	'IBM860' => 'IBM860',
 	'IBM861' => 'IBM861',
 	'IBM862' => 'IBM862',
 	'IBM863' => 'IBM863',
 	'IBM864' => 'IBM864',
 	'IBM865' => 'IBM865',
 	'IBM866' => 'IBM866',
 	'IBM868' => 'IBM868',
 	'IBM869' => 'IBM869',
 	'IBM870' => 'IBM870',
 	'IBM871' => 'IBM871',
 	'IBM874' => 'IBM874',
 	'IBM875' => 'IBM875',
 	'IBM880' => 'IBM880',
 	'IBM891' => 'IBM891',
 	'IBM903' => 'IBM903',
 	'IBM904' => 'IBM904',
 	'IBM905' => 'IBM905',
 	'IBM918' => 'IBM918',
 	'IEC_P27-1' => 'IEC_P27_1',
 	'INIS-8' => 'INIS_8',
 	'INIS-CYRILLIC' => 'INIS_CYRILLIC',
 	'INIS' => 'INIS',
 	'ISO-8859-1' => 'ISO_8859_1',
 	'ISO-8859-10' => 'ISO_8859_10',
 	'ISO-8859-11' => 'ISO_8859_11',
 	'ISO-8859-13' => 'ISO_8859_13',
 	'ISO-8859-14' => 'ISO_8859_14',
 	'ISO-8859-15' => 'ISO_8859_15',
 	'ISO-8859-16' => 'ISO_8859_16',
 	'ISO-8859-2' => 'ISO_8859_2',
 	'ISO-8859-3' => 'ISO_8859_3',
 	'ISO-8859-4' => 'ISO_8859_4',
 	'ISO-8859-5' => 'ISO_8859_5',
 	'ISO-8859-6' => 'ISO_8859_6',
 	'ISO-8859-7' => 'ISO_8859_7',
 	'ISO-8859-8' => 'ISO_8859_8',
 	'ISO-8859-9' => 'ISO_8859_9',
 	'ISO_10367-BOX' => 'ISO_10367_BOX',
 	'ISO_2033-1983' => 'ISO_2033_1983',
 	'ISO_5427-EXT' => 'ISO_5427_EXT',
 	'ISO_5427' => 'ISO_5427',
 	'ISO_5428' => 'ISO_5428',
 	'KOI-8' => 'KOI_8',
 	'KOI8-R' => 'KOI8_R',
 	'KOI8-RU' => 'KOI8_RU',
 	'KOI8-T' => 'KOI8_T',
 	'KOI8-U' => 'KOI8_U',
 	'LATIN-GREEK-1' => 'LATIN_GREEK_1',
 	'LATIN-GREEK' => 'LATIN_GREEK',
 	'MACINTOSH' => 'MACINTOSH',
 	'MACARABIC' => 'MACARABIC',
 	'MACCYRILLIC' => 'MACCYRILLIC',
 	'MACCROATIAN' => 'MACCROATIAN',
 	'MACGREEK' => 'MACGREEK',
 	'MACHEBREW' => 'MACHEBREW',
 	'MACICELAND' => 'MACICELAND',
 	'MACROMANIA' => 'MACROMANIA',
 	'MACTHAI' => 'MACTHAI',
 	'MACTURKISH' => 'MACTURKISH',
 	'MACUKRAINE' => 'MACUKRAINE',
 	'MAC-IS' => 'MAC_IS',
 	'MAC-SAMI' => 'MAC_SAMI',
 	'MAC-UK' => 'MAC_UK',
 	'NATS-DANO' => 'NATS_DANO',
 	'NATS-SEFI' => 'NATS_SEFI',
 	'NEXTSTEP' => 'NEXTSTEP',
 	'TIS-620' => 'TIS_620',
 	'UTF-8' => 'UTF_8',
 	'VISCII' => 'VISCII',
 	'WIN-SAMI-2' => 'SAMI_WS2',
 	'WINDOWS-1250' => 'CP1250',
 	'WINDOWS-1251' => 'CP1251',
 	'WINDOWS-1252' => 'CP1252',
 	'WINDOWS-1253' => 'CP1253',
 	'WINDOWS-1254' => 'CP1254',
 	'WINDOWS-1256' => 'CP1256',
 	'WINDOWS-1257' => 'CP1257',
 	'US-ASCII' => 'US_ASCII',
 };
 
 # These encodings are maybe available via Encode(3pm).
 $optional_conversions = {
 	'BIG5' => undef,
 	'BIG5-HKSCS' => undef,
 	'CN-GB' => undef,
 	'CN-GB-ISOIR165' => undef,
 	'CP1006' => undef,
 	'CP1026' => undef,
 	'CP1047' => undef,
 	'CP1361' => undef,
 	'CP949' => undef,
     'CP37' => undef,
     'CP424' => undef,
     'CP500' => undef,
     'CP737' => undef,
     'CP775' => undef,
     'CP856' => undef,
     'CP874' => undef,
     'CP875' => undef,
     'CP932' => undef,
     'CP936' => undef,
     'CP950' => undef,
 	'EUC-JP' => undef,
 	'EUC-KR' => undef,
 	'EUC-TW' => undef,
     # mapping from 0xef to 0xff missing.
 	# 'HP-ROMAN8' => undef,
 	'GB18030' => undef,
 	'HZ' => undef,
 	'IBM437' => undef,
 	'IBM850' => undef,
 	'IBM852' => undef,
 	'IBM855' => undef,
 	'IBM857' => undef,
 	'IBM860' => undef,
 	'IBM861' => undef,
 	'IBM862' => undef,
 	'IBM863' => undef,
 	'IBM864' => undef,
 	'IBM865' => undef,
 	'IBM866' => undef,
 	'IBM869' => undef,
 	'ISO-10646-UCS-2' => undef,
 	'ISO-10646-UCS-4' => undef,
 	'ISO-2022-JP' => undef,
 	'ISO-2022-JP-1' => undef,
 	'ISO-2022-KR' => undef,
 	'ISO-8859-1' => undef,
 	'ISO-8859-10' => undef,
 	# This is broken in some versions of Encode.
 	# 'ISO-8859-11' => undef,
 	'ISO-8859-13' => undef,
 	'ISO-8859-14' => undef,
 	'ISO-8859-15' => undef,
     # Errors at 0xa5 and 0xab.
 	# 'ISO-8859-16' => undef,
 	'ISO-8859-2' => undef,
 	'ISO-8859-3' => undef,
 	'ISO-8859-4' => undef,
 	'ISO-8859-5' => undef,
     # Uses arabic digits in ascii range?!
 	# 'ISO-8859-6' => undef,
     # 0xa1 and 0xa2 are incorrectly encoded.
 	# 'ISO-8859-7' => undef,
     # 0xfd and 0xfe are missing.
 	# 'ISO-8859-8' => undef,
 	'ISO-8859-9' => undef,
 	'ISO-IR-149' => undef,
 	'KOI8-R' => undef,
     # 0x95 is BULLET, not BULLET OPERATOR.
 	# 'KOI8-U' => undef,
     # Seems to be messed up in certain Encode versions.
 	# 'MACINTOSH' => undef,
 	# TODO: Check other Mac encodings for correctness.
 	# Nextstep is completely broken in my version of Encode.
 	# 'NEXTSTEP' => undef,
 	'SHIFT_JIS' => undef,
 	'UCS-2BE' => undef,
 	'UCS-2LE' => undef,
 	'UCS-4BE' => undef,
 	'UCS-4LE' => undef,
 	'US-ASCII' => undef,
 	'UTF-16' => undef,
 	'UTF-16BE' => undef,
 	'UTF-16LE' => undef,
 	'UTF-32' => undef,
 	'UTF-32BE' => undef,
 	'UTF-32LE' => undef,
 	'UTF-8' => undef,
     # 0x86 is missing, 0xa6 is incorrectly encoded.
 	# 'VISCII' => undef,
 	'WINDOWS-1250' => undef,
 	'WINDOWS-1251' => undef,
 	'WINDOWS-1252' => undef,
 	'WINDOWS-1253' => undef,
 	'WINDOWS-1254' => undef,
 	'WINDOWS-1255' => undef,
 	'WINDOWS-1256' => undef,
 	'WINDOWS-1257' => undef,
 	'WINDOWS-1258' => undef,
 };
 
 my $has_encode;
 
 sub resolveAlias
 {
 	my (undef, $encoding) = @_;
 
 	$encoding = uc $encoding;
 	
 	return $encoding if exists $conversions->{$encoding};
 	return $encoding if exists $optional_conversions->{$encoding};
 
 	require Locale::Recode::_Aliases;
 
 	my $resolved = Locale::Recode::_Aliases::ALIASES()->{$encoding};
 	
 	return $resolved if $resolved;
 
 	return;
 }
 
 sub isSupported
 {
 	my ($class, $encoding) = @_;
 
 	return unless defined $encoding && length $encoding;
 
 	$encoding = uc $encoding;
 	my $mimename = $class->resolveAlias ($encoding);
 
 	return unless $mimename;
 	
 	# Determine the correct module.
 	if (exists $optional_conversions->{$mimename}) {
 		unless (defined $has_encode) {
 			eval "require Encode";
 			$has_encode = !$@;
 
 			if ($has_encode) {
 				require Encode::Alias;
 
 				# Add missing real names.
 				Encode::Alias::define_alias (MS_KANJI => 'ShiftJIS');
 				Encode::Alias::define_alias ('CN-GB' => 'EUC-CN');
 			}
 		}
 
 		if ($has_encode) {
 			# Now check whether Encode really supports that encoding.
 			eval "Encode::encode ('$mimename', 'x')";
 		
 			unless ($@) {
 				$conversions->{$mimename} = '_Encode';
 			}
 			delete $optional_conversions->{$mimename};
 		}
 	}
 
 	return $conversions->{$mimename} if exists $conversions->{$mimename};
 
 	return;
 }
 
 sub listSupported
 {
 	my ($class) = @_;
 
 	foreach my $opt (keys %$optional_conversions) {
 		$class->isSupported ($opt);
 	}
 
 	my @list = keys %$conversions;
 	return @list;
 }
 
 # Find a conversion path.
 sub findPath
 {
 	my ($class, $from, $to) = @_;
 
 	$from = 'INTERNAL' eq uc $from ? 'INTERNAL' : $class->resolveAlias ($from);
 	$to = 'INTERNAL' eq uc $to ? 'INTERNAL' : $class->resolveAlias ($to);
 	
 	return unless $from && $to;
 	
 	return [] if $from eq $to;
 
 	my $from_module = $class->isSupported ($from);
 	my $to_module = $class->isSupported ($to);
 
 	if (!$from_module) {
 		if ('INTERNAL' eq $from) {
 			$from_module = $to_module or return;
 		} else {
 			return;
 		}
 	}
 
 	if (!$to_module) {
 		if ('INTERNAL' eq $to) {
 			$to_module = $from_module or return;
 		} else {
 			return;
 		}
 	}
 
 	if ($from_module eq $to_module
 		|| $to eq 'INTERNAL'
 		|| $to eq 'UTF-8') {
 		return [[ $from_module, $from, $to ]];
 	} elsif ($from eq 'INTERNAL') {
 		return [[ $to_module, $from, $to ]];
 	} else {
 		return [[ $from_module, $from, 'INTERNAL' ],
 				[ $to_module, 'INTERNAL', $to ]];
 	}
 }
 
 # TODO: check for
 # 7bit-jis
 # AdobeStandardEncoding
 # AdobeSymbol
 # AdobeZdingbat
 # ascii-ctrl
 # big5ext
 # big5plus
 # cccii
 # cns11643-1
 # cns11643-2
 # cns11643-3
 # cns11643-4
 # cns11643-5
 # cns11643-6
 # cns11643-7
 # cns11643-f
 # dingbats
 # gb12345-raw
 # gb2312-raw
 # gsm0338
 # jis0201-raw
 # jis0208-raw
 # jis0212-raw
 # koi8-f
 # MIME-B
 # MIME-Header
 # MIME-Q
 # posix-bc
 # symbol
 # unisys
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::Recode::_Conversions - Internal Table of Known Conversions
 
 =head1 SYNOPSIS
 
 use Locale::Recode::_Conversions
 
 This module is internal to libintl.  Do not use it directly!
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData.pm ###
 #! /bin/false
 
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Virtual base class for Locale::Recode converters.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData;
 
 use strict;
 
 sub new
 {
     my ($class, %args) = @_;
 
     bless {
 		_from => $args{from},
 		_to => $args{to},
     }, $class;
 }
 
 sub _getError
 {
 	shift->{_error};
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData - Abstract Base Class for Charset Converters
 
 =head1 SYNOPSIS
 
     # For compatibility with Perl 5.005 and earlier, you must
     # *use* the module before inheriting from it!
     use qw (Locale::RecodeData);
     use base qw (Locale::RecodeData);
 
 =head1 DESCRIPTION
 
 The module B<Locale::RecodeData> serves as an abstract base class to
 all converters used by Locale::Recode(3).
 
 Adding new conversion modules is currently not straightforward, and 
 you will have to edit the sources of some modules for that purpose.
 
 First, you have to add your new converter class to the list found
 in Locale::_Conversions(3), so that Locale::Recode(3) knows about
 its presence.  If there are valid aliases for the codeset of your
 converter, you will also have to edit Locale::_Aliases(3).
 
 Finally, you have to implement the (protected) conversion routine
 _recode().  See below (L<"INTERFACE")> for details.
 
 =head1 CONSTRUCTOR
 
 =over 4
 
 =item B<new (from =E<gt> FROM_CODESET, to =E<gt> TO_CODESET)>
 
 The constructor takes two (named) arguments:
 
 =over 8
 
 =item B<from>
 
 The canonical name of the source codeset.  Aliases have already been
 resolved and the name is converted to uppercase.
 
 =item B<to>
 
 The canonical name of the destination codeset.  Aliases have already been
 resolved and the name is converted to uppercase.
 
 =back
 
 You normally don't have to implement the constructor.  The default constructor
 implemented here will store the source and destination codesets in the
 protected members C<_from> and C<_to>.
 
 =back
 
 =head1 METHODS
 
 The class implements one method:
 
 =over 4
 
 =item B<_getError>
 
 Returns the (protected) member C<_error>.
 
 =back
 
 =head1 INTERFACE
 
 New conversion classes must provide the following interface:
 
 =over 4
 
 =item B<new (from =E<gt> FROM_CODESET, to =E<gt> TO_CODESET)>
 
 The constructor takes two (named) arguments:
 
 =over 8
 
 =item B<from>
 
 The canonical name of the source codeset.  Aliases have already been
 resolved and the name is converted to uppercase.
 
 =item B<to>
 
 The canonical name of the destination codeset.  Aliases have already been
 resolved and the name is converted to uppercase.
 
 =back
 
 =item B<_getError>
 
 Should return the last error (as a string) or false if there was no error.
 
 This method is implemented in the base class already.
 
 =item B<_recode STRINGREF>
 
 Should convert the argument C<STRINGREF> in-place.  In case of failure,
 return false, and make provisions that the method C<_getError()> returns
 an informative error message.
 
 =back
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::Recode::_Aliases(3pm), Locale::Recode::_Conversions(3pm),
 Locale::Recode(3pm), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/ASMO_449.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for ASMO_449.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::ASMO_449;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x0004,
     0x0005,
     0x0006,
     0x0007,
     0x0008,
     0x0009,
     0x000a,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x0014,
     0x0015,
     0x0016,
     0x0017,
     0x0018,
     0x0019,
     0x001a,
     0x001b,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0020,
     0x0021,
     0x0022,
     0x0023,
     0x00a4,
     0x0025,
     0x0026,
     0x0027,
     0x0028,
     0x0029,
     0x002a,
     0x002b,
     0x060c,
     0x002d,
     0x002e,
     0x002f,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x003a,
     0x061b,
     0x003c,
     0x003d,
     0x003e,
     0x061f,
     0x0040,
     0x0621,
     0x0622,
     0x0623,
     0x0624,
     0x0625,
     0x0626,
     0x0627,
     0x0628,
     0x0629,
     0x062a,
     0x062b,
     0x062c,
     0x062d,
     0x062e,
     0x062f,
     0x0630,
     0x0631,
     0x0632,
     0x0633,
     0x0634,
     0x0635,
     0x0636,
     0x0637,
     0x0638,
     0x0639,
     0x063a,
     0x005b,
     0x005c,
     0x005d,
     0x005e,
     0x005f,
     0x0640,
     0x0641,
     0x0642,
     0x0643,
     0x0644,
     0x0645,
     0x0646,
     0x0647,
     0x0648,
     0x0649,
     0x064a,
     0x064b,
     0x064c,
     0x064d,
     0x064e,
     0x064f,
     0x0650,
     0x0651,
     0x0652,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x007b,
     0x007c,
     0x007d,
     0x203e,
     0x007f,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\x04",
     "\x05",
     "\x06",
     "\x07",
     "\x08",
     "\x09",
     "\x0a",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\x14",
     "\x15",
     "\x16",
     "\x17",
     "\x18",
     "\x19",
     "\x1a",
     "\x1b",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\x20",
     "\x21",
     "\x22",
     "\x23",
     "\xc2\xa4",
     "\x25",
     "\x26",
     "\x27",
     "\x28",
     "\x29",
     "\x2a",
     "\x2b",
     "\xd8\x8c",
     "\x2d",
     "\x2e",
     "\x2f",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\x3a",
     "\xd8\x9b",
     "\x3c",
     "\x3d",
     "\x3e",
     "\xd8\x9f",
     "\x40",
     "\xd8\xa1",
     "\xd8\xa2",
     "\xd8\xa3",
     "\xd8\xa4",
     "\xd8\xa5",
     "\xd8\xa6",
     "\xd8\xa7",
     "\xd8\xa8",
     "\xd8\xa9",
     "\xd8\xaa",
     "\xd8\xab",
     "\xd8\xac",
     "\xd8\xad",
     "\xd8\xae",
     "\xd8\xaf",
     "\xd8\xb0",
     "\xd8\xb1",
     "\xd8\xb2",
     "\xd8\xb3",
     "\xd8\xb4",
     "\xd8\xb5",
     "\xd8\xb6",
     "\xd8\xb7",
     "\xd8\xb8",
     "\xd8\xb9",
     "\xd8\xba",
     "\x5b",
     "\x5c",
     "\x5d",
     "\x5e",
     "\x5f",
     "\xd9\x80",
     "\xd9\x81",
     "\xd9\x82",
     "\xd9\x83",
     "\xd9\x84",
     "\xd9\x85",
     "\xd9\x86",
     "\xd9\x87",
     "\xd9\x88",
     "\xd9\x89",
     "\xd9\x8a",
     "\xd9\x8b",
     "\xd9\x8c",
     "\xd9\x8d",
     "\xd9\x8e",
     "\xd9\x8f",
     "\xd9\x90",
     "\xd9\x91",
     "\xd9\x92",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x7b",
     "\x7c",
     "\x7d",
     "\xe2\x80\xbe",
     "\x7f",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x04",
     0x00000005 => "\x05",
     0x00000006 => "\x06",
     0x00000007 => "\x07",
     0x00000008 => "\x08",
     0x00000009 => "\x09",
     0x0000000a => "\x0a",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x14",
     0x00000015 => "\x15",
     0x00000016 => "\x16",
     0x00000017 => "\x17",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x1a",
     0x0000001b => "\x1b",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x20",
     0x00000021 => "\x21",
     0x00000022 => "\x22",
     0x00000023 => "\x23",
     0x00000025 => "\x25",
     0x00000026 => "\x26",
     0x00000027 => "\x27",
     0x00000028 => "\x28",
     0x00000029 => "\x29",
     0x0000002a => "\x2a",
     0x0000002b => "\x2b",
     0x0000002d => "\x2d",
     0x0000002e => "\x2e",
     0x0000002f => "\x2f",
     0x00000030 => "\x30",
     0x00000031 => "\x31",
     0x00000032 => "\x32",
     0x00000033 => "\x33",
     0x00000034 => "\x34",
     0x00000035 => "\x35",
     0x00000036 => "\x36",
     0x00000037 => "\x37",
     0x00000038 => "\x38",
     0x00000039 => "\x39",
     0x0000003a => "\x3a",
     0x0000003c => "\x3c",
     0x0000003d => "\x3d",
     0x0000003e => "\x3e",
     0x00000040 => "\x40",
     0x0000005b => "\x5b",
     0x0000005c => "\x5c",
     0x0000005d => "\x5d",
     0x0000005e => "\x5e",
     0x0000005f => "\x5f",
     0x0000007b => "\x7b",
     0x0000007c => "\x7c",
     0x0000007d => "\x7d",
     0x0000007f => "\x7f",
     0x000000a4 => "\x24",
     0x0000060c => "\x2c",
     0x0000061b => "\x3b",
     0x0000061f => "\x3f",
     0x00000621 => "\x41",
     0x00000622 => "\x42",
     0x00000623 => "\x43",
     0x00000624 => "\x44",
     0x00000625 => "\x45",
     0x00000626 => "\x46",
     0x00000627 => "\x47",
     0x00000628 => "\x48",
     0x00000629 => "\x49",
     0x0000062a => "\x4a",
     0x0000062b => "\x4b",
     0x0000062c => "\x4c",
     0x0000062d => "\x4d",
     0x0000062e => "\x4e",
     0x0000062f => "\x4f",
     0x00000630 => "\x50",
     0x00000631 => "\x51",
     0x00000632 => "\x52",
     0x00000633 => "\x53",
     0x00000634 => "\x54",
     0x00000635 => "\x55",
     0x00000636 => "\x56",
     0x00000637 => "\x57",
     0x00000638 => "\x58",
     0x00000639 => "\x59",
     0x0000063a => "\x5a",
     0x00000640 => "\x60",
     0x00000641 => "\x61",
     0x00000642 => "\x62",
     0x00000643 => "\x63",
     0x00000644 => "\x64",
     0x00000645 => "\x65",
     0x00000646 => "\x66",
     0x00000647 => "\x67",
     0x00000648 => "\x68",
     0x00000649 => "\x69",
     0x0000064a => "\x6a",
     0x0000064b => "\x6b",
     0x0000064c => "\x6c",
     0x0000064d => "\x6d",
     0x0000064e => "\x6e",
     0x0000064f => "\x6f",
     0x00000650 => "\x70",
     0x00000651 => "\x71",
     0x00000652 => "\x72",
     0x0000203e => "\x7e",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::ASMO_449 - Conversion routines for ASMO_449
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for ASMO_449.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
   source: ECMA registry
  alias ISO_9036
  alias ARABIC7
  alias ISO-IR-89
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  00000004 | END OF TRANSMISSION (EOT)
     05 |  00000005 | ENQUIRY (ENQ)
     06 |  00000006 | ACKNOWLEDGE (ACK)
     07 |  00000007 | BELL (BEL)
     08 |  00000008 | BACKSPACE (BS)
     09 |  00000009 | CHARACTER TABULATION (HT)
     0A |  0000000A | LINE FEED (LF)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  00000014 | DEVICE CONTROL FOUR (DC4)
     15 |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     16 |  00000016 | SYNCHRONOUS IDLE (SYN)
     17 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  0000001A | SUBSTITUTE (SUB)
     1B |  0000001B | ESCAPE (ESC)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000020 | SPACE
     21 |  00000021 | EXCLAMATION MARK
     22 |  00000022 | QUOTATION MARK
     23 |  00000023 | NUMBER SIGN
     24 |  000000A4 | CURRENCY SIGN
     25 |  00000025 | PERCENT SIGN
     26 |  00000026 | AMPERSAND
     27 |  00000027 | APOSTROPHE
     28 |  00000028 | LEFT PARENTHESIS
     29 |  00000029 | RIGHT PARENTHESIS
     2A |  0000002A | ASTERISK
     2B |  0000002B | PLUS SIGN
     2C |  0000060C | ARABIC COMMA
     2D |  0000002D | HYPHEN-MINUS
     2E |  0000002E | FULL STOP
     2F |  0000002F | SOLIDUS
     30 |  00000030 | DIGIT ZERO
     31 |  00000031 | DIGIT ONE
     32 |  00000032 | DIGIT TWO
     33 |  00000033 | DIGIT THREE
     34 |  00000034 | DIGIT FOUR
     35 |  00000035 | DIGIT FIVE
     36 |  00000036 | DIGIT SIX
     37 |  00000037 | DIGIT SEVEN
     38 |  00000038 | DIGIT EIGHT
     39 |  00000039 | DIGIT NINE
     3A |  0000003A | COLON
     3B |  0000061B | ARABIC SEMICOLON
     3C |  0000003C | LESS-THAN SIGN
     3D |  0000003D | EQUALS SIGN
     3E |  0000003E | GREATER-THAN SIGN
     3F |  0000061F | ARABIC QUESTION MARK
     40 |  00000040 | COMMERCIAL AT
     41 |  00000621 | ARABIC LETTER HAMZA
     42 |  00000622 | ARABIC LETTER ALEF WITH MADDA ABOVE
     43 |  00000623 | ARABIC LETTER ALEF WITH HAMZA ABOVE
     44 |  00000624 | ARABIC LETTER WAW WITH HAMZA ABOVE
     45 |  00000625 | ARABIC LETTER ALEF WITH HAMZA BELOW
     46 |  00000626 | ARABIC LETTER YEH WITH HAMZA ABOVE
     47 |  00000627 | ARABIC LETTER ALEF
     48 |  00000628 | ARABIC LETTER BEH
     49 |  00000629 | ARABIC LETTER TEH MARBUTA
     4A |  0000062A | ARABIC LETTER TEH
     4B |  0000062B | ARABIC LETTER THEH
     4C |  0000062C | ARABIC LETTER JEEM
     4D |  0000062D | ARABIC LETTER HAH
     4E |  0000062E | ARABIC LETTER KHAH
     4F |  0000062F | ARABIC LETTER DAL
     50 |  00000630 | ARABIC LETTER THAL
     51 |  00000631 | ARABIC LETTER REH
     52 |  00000632 | ARABIC LETTER ZAIN
     53 |  00000633 | ARABIC LETTER SEEN
     54 |  00000634 | ARABIC LETTER SHEEN
     55 |  00000635 | ARABIC LETTER SAD
     56 |  00000636 | ARABIC LETTER DAD
     57 |  00000637 | ARABIC LETTER TAH
     58 |  00000638 | ARABIC LETTER ZAH
     59 |  00000639 | ARABIC LETTER AIN
     5A |  0000063A | ARABIC LETTER GHAIN
     5B |  0000005B | LEFT SQUARE BRACKET
     5C |  0000005C | REVERSE SOLIDUS
     5D |  0000005D | RIGHT SQUARE BRACKET
     5E |  0000005E | CIRCUMFLEX ACCENT
     5F |  0000005F | LOW LINE
     60 |  00000640 | ARABIC TATWEEL
     61 |  00000641 | ARABIC LETTER FEH
     62 |  00000642 | ARABIC LETTER QAF
     63 |  00000643 | ARABIC LETTER KAF
     64 |  00000644 | ARABIC LETTER LAM
     65 |  00000645 | ARABIC LETTER MEEM
     66 |  00000646 | ARABIC LETTER NOON
     67 |  00000647 | ARABIC LETTER HEH
     68 |  00000648 | ARABIC LETTER WAW
     69 |  00000649 | ARABIC LETTER ALEF MAKSURA
     6A |  0000064A | ARABIC LETTER YEH
     6B |  0000064B | ARABIC FATHATAN
     6C |  0000064C | ARABIC DAMMATAN
     6D |  0000064D | ARABIC KASRATAN
     6E |  0000064E | ARABIC FATHA
     6F |  0000064F | ARABIC DAMMA
     70 |  00000650 | ARABIC KASRA
     71 |  00000651 | ARABIC SHADDA
     72 |  00000652 | ARABIC SUKUN
     7B |  0000007B | LEFT CURLY BRACKET
     7C |  0000007C | VERTICAL LINE
     7D |  0000007D | RIGHT CURLY BRACKET
     7E |  0000203E | OVERLINE
     7F |  0000007F | DELETE (DEL)
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/ATARI_ST.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for ATARI-ST.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::ATARI_ST;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x0004,
     0x0005,
     0x0006,
     0x0007,
     0x0008,
     0x0009,
     0x000a,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x0014,
     0x0015,
     0x0016,
     0x0017,
     0x0018,
     0x0019,
     0x001a,
     0x001b,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0020,
     0x0021,
     0x0022,
     0x0023,
     0x0024,
     0x0025,
     0x0026,
     0x0027,
     0x0028,
     0x0029,
     0x002a,
     0x002b,
     0x002c,
     0x002d,
     0x002e,
     0x002f,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x003a,
     0x003b,
     0x003c,
     0x003d,
     0x003e,
     0x003f,
     0x0040,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x005b,
     0x005c,
     0x005d,
     0x005e,
     0x005f,
     0x0060,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x007b,
     0x007c,
     0x007d,
     0x007e,
     0x007f,
     0x00c7,
     0x00fc,
     0x00e9,
     0x00e2,
     0x00e4,
     0x00e0,
     0x00e5,
     0x00e7,
     0x00ea,
     0x00eb,
     0x00e8,
     0x00ef,
     0x00ee,
     0x00ec,
     0x00c4,
     0x00c5,
     0x00c9,
     0x00e6,
     0x00c6,
     0x00f4,
     0x00f6,
     0x00f2,
     0x00fb,
     0x00f9,
     0x00ff,
     0x00d6,
     0x00dc,
     0x00a2,
     0x00a3,
     0x00a5,
     0x00df,
     0x0192,
     0x00e1,
     0x00ed,
     0x00f3,
     0x00fa,
     0x00f1,
     0x00d1,
     0x00aa,
     0x00ba,
     0x00bf,
     0x2310,
     0x00ac,
     0x00bd,
     0x00bc,
     0x00a1,
     0x00ab,
     0x00bb,
     0x00e3,
     0x00f5,
     0x00d8,
     0x00f8,
     0x0153,
     0x0152,
     0x00c0,
     0x00c3,
     0x00d5,
     0x00a8,
     0x00b4,
     0x2020,
     0x00b6,
     0x00a9,
     0x00ae,
     0x2122,
     0x0133,
     0x0132,
     0x05d0,
     0x05d1,
     0x05d2,
     0x05d3,
     0x05d4,
     0x05d5,
     0x05d6,
     0x05d7,
     0x05d8,
     0x05d9,
     0x05db,
     0x05dc,
     0x05de,
     0x05e0,
     0x05e1,
     0x05e2,
     0x05e4,
     0x05e6,
     0x05e7,
     0x05e8,
     0x05e9,
     0x05ea,
     0x05df,
     0x05da,
     0x05dd,
     0x05e3,
     0x05e5,
     0x00a7,
     0x2038,
     0x221e,
     0x03b1,
     0x03b2,
     0x0393,
     0x03c0,
     0x03a3,
     0x03c3,
     0x00b5,
     0x03c4,
     0x03a6,
     0x03b8,
     0x03a9,
     0x03b4,
     0x222e,
     0x03c6,
     0x2208,
     0x220f,
     0x2261,
     0x00b1,
     0x2265,
     0x2264,
     0x2320,
     0x2321,
     0x00f7,
     0x2248,
     0x00b0,
     0x2022,
     0x00b7,
     0x221a,
     0x207f,
     0x00b2,
     0x00b3,
     0x00af,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\x04",
     "\x05",
     "\x06",
     "\x07",
     "\x08",
     "\x09",
     "\x0a",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\x14",
     "\x15",
     "\x16",
     "\x17",
     "\x18",
     "\x19",
     "\x1a",
     "\x1b",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\x20",
     "\x21",
     "\x22",
     "\x23",
     "\x24",
     "\x25",
     "\x26",
     "\x27",
     "\x28",
     "\x29",
     "\x2a",
     "\x2b",
     "\x2c",
     "\x2d",
     "\x2e",
     "\x2f",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\x3a",
     "\x3b",
     "\x3c",
     "\x3d",
     "\x3e",
     "\x3f",
     "\x40",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\x5b",
     "\x5c",
     "\x5d",
     "\x5e",
     "\x5f",
     "\x60",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\x7b",
     "\x7c",
     "\x7d",
     "\x7e",
     "\x7f",
     "\xc3\x87",
     "\xc3\xbc",
     "\xc3\xa9",
     "\xc3\xa2",
     "\xc3\xa4",
     "\xc3\xa0",
     "\xc3\xa5",
     "\xc3\xa7",
     "\xc3\xaa",
     "\xc3\xab",
     "\xc3\xa8",
     "\xc3\xaf",
     "\xc3\xae",
     "\xc3\xac",
     "\xc3\x84",
     "\xc3\x85",
     "\xc3\x89",
     "\xc3\xa6",
     "\xc3\x86",
     "\xc3\xb4",
     "\xc3\xb6",
     "\xc3\xb2",
     "\xc3\xbb",
     "\xc3\xb9",
     "\xc3\xbf",
     "\xc3\x96",
     "\xc3\x9c",
     "\xc2\xa2",
     "\xc2\xa3",
     "\xc2\xa5",
     "\xc3\x9f",
     "\xc6\x92",
     "\xc3\xa1",
     "\xc3\xad",
     "\xc3\xb3",
     "\xc3\xba",
     "\xc3\xb1",
     "\xc3\x91",
     "\xc2\xaa",
     "\xc2\xba",
     "\xc2\xbf",
     "\xe2\x8c\x90",
     "\xc2\xac",
     "\xc2\xbd",
     "\xc2\xbc",
     "\xc2\xa1",
     "\xc2\xab",
     "\xc2\xbb",
     "\xc3\xa3",
     "\xc3\xb5",
     "\xc3\x98",
     "\xc3\xb8",
     "\xc5\x93",
     "\xc5\x92",
     "\xc3\x80",
     "\xc3\x83",
     "\xc3\x95",
     "\xc2\xa8",
     "\xc2\xb4",
     "\xe2\x80\xa0",
     "\xc2\xb6",
     "\xc2\xa9",
     "\xc2\xae",
     "\xe2\x84\xa2",
     "\xc4\xb3",
     "\xc4\xb2",
     "\xd7\x90",
     "\xd7\x91",
     "\xd7\x92",
     "\xd7\x93",
     "\xd7\x94",
     "\xd7\x95",
     "\xd7\x96",
     "\xd7\x97",
     "\xd7\x98",
     "\xd7\x99",
     "\xd7\x9b",
     "\xd7\x9c",
     "\xd7\x9e",
     "\xd7\xa0",
     "\xd7\xa1",
     "\xd7\xa2",
     "\xd7\xa4",
     "\xd7\xa6",
     "\xd7\xa7",
     "\xd7\xa8",
     "\xd7\xa9",
     "\xd7\xaa",
     "\xd7\x9f",
     "\xd7\x9a",
     "\xd7\x9d",
     "\xd7\xa3",
     "\xd7\xa5",
     "\xc2\xa7",
     "\xe2\x80\xb8",
     "\xe2\x88\x9e",
     "\xce\xb1",
     "\xce\xb2",
     "\xce\x93",
     "\xcf\x80",
     "\xce\xa3",
     "\xcf\x83",
     "\xc2\xb5",
     "\xcf\x84",
     "\xce\xa6",
     "\xce\xb8",
     "\xce\xa9",
     "\xce\xb4",
     "\xe2\x88\xae",
     "\xcf\x86",
     "\xe2\x88\x88",
     "\xe2\x88\x8f",
     "\xe2\x89\xa1",
     "\xc2\xb1",
     "\xe2\x89\xa5",
     "\xe2\x89\xa4",
     "\xe2\x8c\xa0",
     "\xe2\x8c\xa1",
     "\xc3\xb7",
     "\xe2\x89\x88",
     "\xc2\xb0",
     "\xe2\x80\xa2",
     "\xc2\xb7",
     "\xe2\x88\x9a",
     "\xe2\x81\xbf",
     "\xc2\xb2",
     "\xc2\xb3",
     "\xc2\xaf",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x04",
     0x00000005 => "\x05",
     0x00000006 => "\x06",
     0x00000007 => "\x07",
     0x00000008 => "\x08",
     0x00000009 => "\x09",
     0x0000000a => "\x0a",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x14",
     0x00000015 => "\x15",
     0x00000016 => "\x16",
     0x00000017 => "\x17",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x1a",
     0x0000001b => "\x1b",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x20",
     0x00000021 => "\x21",
     0x00000022 => "\x22",
     0x00000023 => "\x23",
     0x00000024 => "\x24",
     0x00000025 => "\x25",
     0x00000026 => "\x26",
     0x00000027 => "\x27",
     0x00000028 => "\x28",
     0x00000029 => "\x29",
     0x0000002a => "\x2a",
     0x0000002b => "\x2b",
     0x0000002c => "\x2c",
     0x0000002d => "\x2d",
     0x0000002e => "\x2e",
     0x0000002f => "\x2f",
     0x00000030 => "\x30",
     0x00000031 => "\x31",
     0x00000032 => "\x32",
     0x00000033 => "\x33",
     0x00000034 => "\x34",
     0x00000035 => "\x35",
     0x00000036 => "\x36",
     0x00000037 => "\x37",
     0x00000038 => "\x38",
     0x00000039 => "\x39",
     0x0000003a => "\x3a",
     0x0000003b => "\x3b",
     0x0000003c => "\x3c",
     0x0000003d => "\x3d",
     0x0000003e => "\x3e",
     0x0000003f => "\x3f",
     0x00000040 => "\x40",
     0x00000041 => "\x41",
     0x00000042 => "\x42",
     0x00000043 => "\x43",
     0x00000044 => "\x44",
     0x00000045 => "\x45",
     0x00000046 => "\x46",
     0x00000047 => "\x47",
     0x00000048 => "\x48",
     0x00000049 => "\x49",
     0x0000004a => "\x4a",
     0x0000004b => "\x4b",
     0x0000004c => "\x4c",
     0x0000004d => "\x4d",
     0x0000004e => "\x4e",
     0x0000004f => "\x4f",
     0x00000050 => "\x50",
     0x00000051 => "\x51",
     0x00000052 => "\x52",
     0x00000053 => "\x53",
     0x00000054 => "\x54",
     0x00000055 => "\x55",
     0x00000056 => "\x56",
     0x00000057 => "\x57",
     0x00000058 => "\x58",
     0x00000059 => "\x59",
     0x0000005a => "\x5a",
     0x0000005b => "\x5b",
     0x0000005c => "\x5c",
     0x0000005d => "\x5d",
     0x0000005e => "\x5e",
     0x0000005f => "\x5f",
     0x00000060 => "\x60",
     0x00000061 => "\x61",
     0x00000062 => "\x62",
     0x00000063 => "\x63",
     0x00000064 => "\x64",
     0x00000065 => "\x65",
     0x00000066 => "\x66",
     0x00000067 => "\x67",
     0x00000068 => "\x68",
     0x00000069 => "\x69",
     0x0000006a => "\x6a",
     0x0000006b => "\x6b",
     0x0000006c => "\x6c",
     0x0000006d => "\x6d",
     0x0000006e => "\x6e",
     0x0000006f => "\x6f",
     0x00000070 => "\x70",
     0x00000071 => "\x71",
     0x00000072 => "\x72",
     0x00000073 => "\x73",
     0x00000074 => "\x74",
     0x00000075 => "\x75",
     0x00000076 => "\x76",
     0x00000077 => "\x77",
     0x00000078 => "\x78",
     0x00000079 => "\x79",
     0x0000007a => "\x7a",
     0x0000007b => "\x7b",
     0x0000007c => "\x7c",
     0x0000007d => "\x7d",
     0x0000007e => "\x7e",
     0x0000007f => "\x7f",
     0x000000a1 => "\xad",
     0x000000a2 => "\x9b",
     0x000000a3 => "\x9c",
     0x000000a5 => "\x9d",
     0x000000a7 => "\xdd",
     0x000000a8 => "\xb9",
     0x000000a9 => "\xbd",
     0x000000aa => "\xa6",
     0x000000ab => "\xae",
     0x000000ac => "\xaa",
     0x000000ae => "\xbe",
     0x000000af => "\xff",
     0x000000b0 => "\xf8",
     0x000000b1 => "\xf1",
     0x000000b2 => "\xfd",
     0x000000b3 => "\xfe",
     0x000000b4 => "\xba",
     0x000000b5 => "\xe6",
     0x000000b6 => "\xbc",
     0x000000b7 => "\xfa",
     0x000000ba => "\xa7",
     0x000000bb => "\xaf",
     0x000000bc => "\xac",
     0x000000bd => "\xab",
     0x000000bf => "\xa8",
     0x000000c0 => "\xb6",
     0x000000c3 => "\xb7",
     0x000000c4 => "\x8e",
     0x000000c5 => "\x8f",
     0x000000c6 => "\x92",
     0x000000c7 => "\x80",
     0x000000c9 => "\x90",
     0x000000d1 => "\xa5",
     0x000000d5 => "\xb8",
     0x000000d6 => "\x99",
     0x000000d8 => "\xb2",
     0x000000dc => "\x9a",
     0x000000df => "\x9e",
     0x000000e0 => "\x85",
     0x000000e1 => "\xa0",
     0x000000e2 => "\x83",
     0x000000e3 => "\xb0",
     0x000000e4 => "\x84",
     0x000000e5 => "\x86",
     0x000000e6 => "\x91",
     0x000000e7 => "\x87",
     0x000000e8 => "\x8a",
     0x000000e9 => "\x82",
     0x000000ea => "\x88",
     0x000000eb => "\x89",
     0x000000ec => "\x8d",
     0x000000ed => "\xa1",
     0x000000ee => "\x8c",
     0x000000ef => "\x8b",
     0x000000f1 => "\xa4",
     0x000000f2 => "\x95",
     0x000000f3 => "\xa2",
     0x000000f4 => "\x93",
     0x000000f5 => "\xb1",
     0x000000f6 => "\x94",
     0x000000f7 => "\xf6",
     0x000000f8 => "\xb3",
     0x000000f9 => "\x97",
     0x000000fa => "\xa3",
     0x000000fb => "\x96",
     0x000000fc => "\x81",
     0x000000ff => "\x98",
     0x00000132 => "\xc1",
     0x00000133 => "\xc0",
     0x00000152 => "\xb5",
     0x00000153 => "\xb4",
     0x00000192 => "\x9f",
     0x00000393 => "\xe2",
     0x000003a3 => "\xe4",
     0x000003a6 => "\xe8",
     0x000003a9 => "\xea",
     0x000003b1 => "\xe0",
     0x000003b2 => "\xe1",
     0x000003b4 => "\xeb",
     0x000003b8 => "\xe9",
     0x000003c0 => "\xe3",
     0x000003c3 => "\xe5",
     0x000003c4 => "\xe7",
     0x000003c6 => "\xed",
     0x000005d0 => "\xc2",
     0x000005d1 => "\xc3",
     0x000005d2 => "\xc4",
     0x000005d3 => "\xc5",
     0x000005d4 => "\xc6",
     0x000005d5 => "\xc7",
     0x000005d6 => "\xc8",
     0x000005d7 => "\xc9",
     0x000005d8 => "\xca",
     0x000005d9 => "\xcb",
     0x000005da => "\xd9",
     0x000005db => "\xcc",
     0x000005dc => "\xcd",
     0x000005dd => "\xda",
     0x000005de => "\xce",
     0x000005df => "\xd8",
     0x000005e0 => "\xcf",
     0x000005e1 => "\xd0",
     0x000005e2 => "\xd1",
     0x000005e3 => "\xdb",
     0x000005e4 => "\xd2",
     0x000005e5 => "\xdc",
     0x000005e6 => "\xd3",
     0x000005e7 => "\xd4",
     0x000005e8 => "\xd5",
     0x000005e9 => "\xd6",
     0x000005ea => "\xd7",
     0x00002020 => "\xbb",
     0x00002022 => "\xf9",
     0x00002038 => "\xde",
     0x0000207f => "\xfc",
     0x00002122 => "\xbf",
     0x00002208 => "\xee",
     0x0000220f => "\xef",
     0x0000221a => "\xfb",
     0x0000221e => "\xdf",
     0x0000222e => "\xec",
     0x00002248 => "\xf7",
     0x00002261 => "\xf0",
     0x00002264 => "\xf3",
     0x00002265 => "\xf2",
     0x00002310 => "\xa9",
     0x00002320 => "\xf4",
     0x00002321 => "\xf5",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::ATARI_ST - Conversion routines for ATARI-ST
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for ATARI-ST.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.1
   source: Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>
  alias ATARIST
  alias X-ATARIST
  alias X-ATARI-ST
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  00000004 | END OF TRANSMISSION (EOT)
     05 |  00000005 | ENQUIRY (ENQ)
     06 |  00000006 | ACKNOWLEDGE (ACK)
     07 |  00000007 | BELL (BEL)
     08 |  00000008 | BACKSPACE (BS)
     09 |  00000009 | CHARACTER TABULATION (HT)
     0A |  0000000A | LINE FEED (LF)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  00000014 | DEVICE CONTROL FOUR (DC4)
     15 |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     16 |  00000016 | SYNCHRONOUS IDLE (SYN)
     17 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  0000001A | SUBSTITUTE (SUB)
     1B |  0000001B | ESCAPE (ESC)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000020 | SPACE
     21 |  00000021 | EXCLAMATION MARK
     22 |  00000022 | QUOTATION MARK
     23 |  00000023 | NUMBER SIGN
     24 |  00000024 | DOLLAR SIGN
     25 |  00000025 | PERCENT SIGN
     26 |  00000026 | AMPERSAND
     27 |  00000027 | APOSTROPHE
     28 |  00000028 | LEFT PARENTHESIS
     29 |  00000029 | RIGHT PARENTHESIS
     2A |  0000002A | ASTERISK
     2B |  0000002B | PLUS SIGN
     2C |  0000002C | COMMA
     2D |  0000002D | HYPHEN-MINUS
     2E |  0000002E | FULL STOP
     2F |  0000002F | SOLIDUS
     30 |  00000030 | DIGIT ZERO
     31 |  00000031 | DIGIT ONE
     32 |  00000032 | DIGIT TWO
     33 |  00000033 | DIGIT THREE
     34 |  00000034 | DIGIT FOUR
     35 |  00000035 | DIGIT FIVE
     36 |  00000036 | DIGIT SIX
     37 |  00000037 | DIGIT SEVEN
     38 |  00000038 | DIGIT EIGHT
     39 |  00000039 | DIGIT NINE
     3A |  0000003A | COLON
     3B |  0000003B | SEMICOLON
     3C |  0000003C | LESS-THAN SIGN
     3D |  0000003D | EQUALS SIGN
     3E |  0000003E | GREATER-THAN SIGN
     3F |  0000003F | QUESTION MARK
     40 |  00000040 | COMMERCIAL AT
     41 |  00000041 | LATIN CAPITAL LETTER A
     42 |  00000042 | LATIN CAPITAL LETTER B
     43 |  00000043 | LATIN CAPITAL LETTER C
     44 |  00000044 | LATIN CAPITAL LETTER D
     45 |  00000045 | LATIN CAPITAL LETTER E
     46 |  00000046 | LATIN CAPITAL LETTER F
     47 |  00000047 | LATIN CAPITAL LETTER G
     48 |  00000048 | LATIN CAPITAL LETTER H
     49 |  00000049 | LATIN CAPITAL LETTER I
     4A |  0000004A | LATIN CAPITAL LETTER J
     4B |  0000004B | LATIN CAPITAL LETTER K
     4C |  0000004C | LATIN CAPITAL LETTER L
     4D |  0000004D | LATIN CAPITAL LETTER M
     4E |  0000004E | LATIN CAPITAL LETTER N
     4F |  0000004F | LATIN CAPITAL LETTER O
     50 |  00000050 | LATIN CAPITAL LETTER P
     51 |  00000051 | LATIN CAPITAL LETTER Q
     52 |  00000052 | LATIN CAPITAL LETTER R
     53 |  00000053 | LATIN CAPITAL LETTER S
     54 |  00000054 | LATIN CAPITAL LETTER T
     55 |  00000055 | LATIN CAPITAL LETTER U
     56 |  00000056 | LATIN CAPITAL LETTER V
     57 |  00000057 | LATIN CAPITAL LETTER W
     58 |  00000058 | LATIN CAPITAL LETTER X
     59 |  00000059 | LATIN CAPITAL LETTER Y
     5A |  0000005A | LATIN CAPITAL LETTER Z
     5B |  0000005B | LEFT SQUARE BRACKET
     5C |  0000005C | REVERSE SOLIDUS
     5D |  0000005D | RIGHT SQUARE BRACKET
     5E |  0000005E | CIRCUMFLEX ACCENT
     5F |  0000005F | LOW LINE
     60 |  00000060 | GRAVE ACCENT
     61 |  00000061 | LATIN SMALL LETTER A
     62 |  00000062 | LATIN SMALL LETTER B
     63 |  00000063 | LATIN SMALL LETTER C
     64 |  00000064 | LATIN SMALL LETTER D
     65 |  00000065 | LATIN SMALL LETTER E
     66 |  00000066 | LATIN SMALL LETTER F
     67 |  00000067 | LATIN SMALL LETTER G
     68 |  00000068 | LATIN SMALL LETTER H
     69 |  00000069 | LATIN SMALL LETTER I
     6A |  0000006A | LATIN SMALL LETTER J
     6B |  0000006B | LATIN SMALL LETTER K
     6C |  0000006C | LATIN SMALL LETTER L
     6D |  0000006D | LATIN SMALL LETTER M
     6E |  0000006E | LATIN SMALL LETTER N
     6F |  0000006F | LATIN SMALL LETTER O
     70 |  00000070 | LATIN SMALL LETTER P
     71 |  00000071 | LATIN SMALL LETTER Q
     72 |  00000072 | LATIN SMALL LETTER R
     73 |  00000073 | LATIN SMALL LETTER S
     74 |  00000074 | LATIN SMALL LETTER T
     75 |  00000075 | LATIN SMALL LETTER U
     76 |  00000076 | LATIN SMALL LETTER V
     77 |  00000077 | LATIN SMALL LETTER W
     78 |  00000078 | LATIN SMALL LETTER X
     79 |  00000079 | LATIN SMALL LETTER Y
     7A |  0000007A | LATIN SMALL LETTER Z
     7B |  0000007B | LEFT CURLY BRACKET
     7C |  0000007C | VERTICAL LINE
     7D |  0000007D | RIGHT CURLY BRACKET
     7E |  0000007E | TILDE
     7F |  0000007F | DELETE
     80 |  000000C7 | LATIN CAPITAL LETTER C WITH CEDILLA
     81 |  000000FC | LATIN SMALL LETTER U WITH DIAERESIS
     82 |  000000E9 | LATIN SMALL LETTER E WITH ACUTE
     83 |  000000E2 | LATIN SMALL LETTER A WITH CIRCUMFLEX
     84 |  000000E4 | LATIN SMALL LETTER A WITH DIAERESIS
     85 |  000000E0 | LATIN SMALL LETTER A WITH GRAVE
     86 |  000000E5 | LATIN SMALL LETTER A WITH RING ABOVE
     87 |  000000E7 | LATIN SMALL LETTER C WITH CEDILLA
     88 |  000000EA | LATIN SMALL LETTER E WITH CIRCUMFLEX
     89 |  000000EB | LATIN SMALL LETTER E WITH DIAERESIS
     8A |  000000E8 | LATIN SMALL LETTER E WITH GRAVE
     8B |  000000EF | LATIN SMALL LETTER I WITH DIAERESIS
     8C |  000000EE | LATIN SMALL LETTER I WITH CIRCUMFLEX
     8D |  000000EC | LATIN SMALL LETTER I WITH GRAVE
     8E |  000000C4 | LATIN CAPITAL LETTER A WITH DIAERESIS
     8F |  000000C5 | LATIN CAPITAL LETTER A WITH RING ABOVE
     90 |  000000C9 | LATIN CAPITAL LETTER E WITH ACUTE
     91 |  000000E6 | LATIN SMALL LETTER AE
     92 |  000000C6 | LATIN CAPITAL LETTER AE
     93 |  000000F4 | LATIN SMALL LETTER O WITH CIRCUMFLEX
     94 |  000000F6 | LATIN SMALL LETTER O WITH DIAERESIS
     95 |  000000F2 | LATIN SMALL LETTER O WITH GRAVE
     96 |  000000FB | LATIN SMALL LETTER U WITH CIRCUMFLEX
     97 |  000000F9 | LATIN SMALL LETTER U WITH GRAVE
     98 |  000000FF | LATIN SMALL LETTER Y WITH DIAERESIS
     99 |  000000D6 | LATIN CAPITAL LETTER O WITH DIAERESIS
     9A |  000000DC | LATIN CAPITAL LETTER U WITH DIAERESIS
     9B |  000000A2 | CENT SIGN
     9C |  000000A3 | POUND SIGN
     9D |  000000A5 | YEN SIGN
     9E |  000000DF | LATIN SMALL LETTER SHARP S
     9F |  00000192 | LATIN SMALL LETTER F WITH HOOK
     A0 |  000000E1 | LATIN SMALL LETTER A WITH ACUTE
     A1 |  000000ED | LATIN SMALL LETTER I WITH ACUTE
     A2 |  000000F3 | LATIN SMALL LETTER O WITH ACUTE
     A3 |  000000FA | LATIN SMALL LETTER U WITH ACUTE
     A4 |  000000F1 | LATIN SMALL LETTER N WITH TILDE
     A5 |  000000D1 | LATIN CAPITAL LETTER N WITH TILDE
     A6 |  000000AA | FEMININE ORDINAL INDICATOR
     A7 |  000000BA | MASCULINE ORDINAL INDICATOR
     A8 |  000000BF | INVERTED QUESTION MARK
     A9 |  00002310 | REVERSED NOT SIGN
     AA |  000000AC | NOT SIGN
     AB |  000000BD | VULGAR FRACTION ONE HALF
     AC |  000000BC | VULGAR FRACTION ONE QUARTER
     AD |  000000A1 | INVERTED EXCLAMATION MARK
     AE |  000000AB | LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
     AF |  000000BB | RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
     B0 |  000000E3 | LATIN SMALL LETTER A WITH TILDE
     B1 |  000000F5 | LATIN SMALL LETTER O WITH TILDE
     B2 |  000000D8 | LATIN CAPITAL LETTER O WITH STROKE
     B3 |  000000F8 | LATIN SMALL LETTER O WITH STROKE
     B4 |  00000153 | LATIN SMALL LIGATURE OE
     B5 |  00000152 | LATIN CAPITAL LIGATURE OE
     B6 |  000000C0 | LATIN CAPITAL LETTER A WITH GRAVE
     B7 |  000000C3 | LATIN CAPITAL LETTER A WITH TILDE
     B8 |  000000D5 | LATIN CAPITAL LETTER O WITH TILDE
     B9 |  000000A8 | DIAERESIS
     BA |  000000B4 | ACUTE ACCENT
     BB |  00002020 | DAGGER
     BC |  000000B6 | PILCROW SIGN
     BD |  000000A9 | COPYRIGHT SIGN
     BE |  000000AE | REGISTERED SIGN
     BF |  00002122 | TRADE MARK SIGN
     C0 |  00000133 | LATIN SMALL LIGATURE IJ
     C1 |  00000132 | LATIN CAPITAL LIGATURE IJ
     C2 |  000005D0 | HEBREW LETTER ALEF
     C3 |  000005D1 | HEBREW LETTER BET
     C4 |  000005D2 | HEBREW LETTER GIMEL
     C5 |  000005D3 | HEBREW LETTER DALET
     C6 |  000005D4 | HEBREW LETTER HE
     C7 |  000005D5 | HEBREW LETTER VAV
     C8 |  000005D6 | HEBREW LETTER ZAYIN
     C9 |  000005D7 | HEBREW LETTER HET
     CA |  000005D8 | HEBREW LETTER TET
     CB |  000005D9 | HEBREW LETTER YOD
     CC |  000005DB | HEBREW LETTER KAF
     CD |  000005DC | HEBREW LETTER LAMED
     CE |  000005DE | HEBREW LETTER MEM
     CF |  000005E0 | HEBREW LETTER NUN
     D0 |  000005E1 | HEBREW LETTER SAMEKH
     D1 |  000005E2 | HEBREW LETTER AYIN
     D2 |  000005E4 | HEBREW LETTER PE
     D3 |  000005E6 | HEBREW LETTER TSADI
     D4 |  000005E7 | HEBREW LETTER QOF
     D5 |  000005E8 | HEBREW LETTER RESH
     D6 |  000005E9 | HEBREW LETTER SHIN
     D7 |  000005EA | HEBREW LETTER TAV
     D8 |  000005DF | HEBREW LETTER FINAL NUN
     D9 |  000005DA | HEBREW LETTER FINAL KAF
     DA |  000005DD | HEBREW LETTER FINAL MEM
     DB |  000005E3 | HEBREW LETTER FINAL PE
     DC |  000005E5 | HEBREW LETTER FINAL TSADI
     DD |  000000A7 | SECTION SIGN
     DE |  00002038 | CARET
     DF |  0000221E | INFINITY
     E0 |  000003B1 | GREEK SMALL LETTER ALPHA
     E1 |  000003B2 | GREEK SMALL LETTER BETA
     E2 |  00000393 | GREEK CAPITAL LETTER GAMMA
     E3 |  000003C0 | GREEK SMALL LETTER PI
     E4 |  000003A3 | GREEK CAPITAL LETTER SIGMA
     E5 |  000003C3 | GREEK SMALL LETTER SIGMA
     E6 |  000000B5 | MICRO SIGN
     E7 |  000003C4 | GREEK SMALL LETTER TAU
     E8 |  000003A6 | GREEK CAPITAL LETTER PHI
     E9 |  000003B8 | GREEK SMALL LETTER THETA
     EA |  000003A9 | GREEK CAPITAL LETTER OMEGA
     EB |  000003B4 | GREEK SMALL LETTER DELTA
     EC |  0000222E | CONTOUR INTEGRAL
     ED |  000003C6 | GREEK SMALL LETTER PHI
     EE |  00002208 | ELEMENT OF
     EF |  0000220F | N-ARY PRODUCT
     F0 |  00002261 | IDENTICAL TO
     F1 |  000000B1 | PLUS-MINUS SIGN
     F2 |  00002265 | GREATER-THAN OR EQUAL TO
     F3 |  00002264 | LESS-THAN OR EQUAL TO
     F4 |  00002320 | TOP HALF INTEGRAL
     F5 |  00002321 | BOTTOM HALF INTEGRAL
     F6 |  000000F7 | DIVISION SIGN
     F7 |  00002248 | ALMOST EQUAL TO
     F8 |  000000B0 | DEGREE SIGN
     F9 |  00002022 | BULLET
     FA |  000000B7 | MIDDLE DOT
     FB |  0000221A | SQUARE ROOT
     FC |  0000207F | SUPERSCRIPT LATIN SMALL LETTER N
     FD |  000000B2 | SUPERSCRIPT TWO
     FE |  000000B3 | SUPERSCRIPT THREE
     FF |  000000AF | MACRON
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/ATARI_ST_EURO.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for ATARI-ST-EURO.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::ATARI_ST_EURO;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x0004,
     0x0005,
     0x0006,
     0x0007,
     0x0008,
     0x0009,
     0x000a,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x0014,
     0x0015,
     0x0016,
     0x0017,
     0x0018,
     0x0019,
     0x001a,
     0x001b,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0020,
     0x0021,
     0x0022,
     0x0023,
     0x0024,
     0x0025,
     0x0026,
     0x0027,
     0x0028,
     0x0029,
     0x002a,
     0x002b,
     0x002c,
     0x002d,
     0x002e,
     0x002f,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x003a,
     0x003b,
     0x003c,
     0x003d,
     0x003e,
     0x003f,
     0x0040,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x005b,
     0x005c,
     0x005d,
     0x005e,
     0x005f,
     0x0060,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x007b,
     0x007c,
     0x007d,
     0x007e,
     0x007f,
     0x00c7,
     0x00fc,
     0x00e9,
     0x00e2,
     0x00e4,
     0x00e0,
     0x00e5,
     0x00e7,
     0x00ea,
     0x00eb,
     0x00e8,
     0x00ef,
     0x00ee,
     0x00ec,
     0x00c4,
     0x00c5,
     0x00c9,
     0x00e6,
     0x00c6,
     0x00f4,
     0x00f6,
     0x00f2,
     0x00fb,
     0x00f9,
     0x00ff,
     0x00d6,
     0x00dc,
     0x00a2,
     0x00a3,
     0x00a5,
     0x00df,
     0x0192,
     0x00e1,
     0x00ed,
     0x00f3,
     0x00fa,
     0x00f1,
     0x00d1,
     0x00aa,
     0x00ba,
     0x00bf,
     0x2310,
     0x00ac,
     0x00bd,
     0x00bc,
     0x00a1,
     0x00ab,
     0x00bb,
     0x00e3,
     0x00f5,
     0x00d8,
     0x00f8,
     0x0153,
     0x0152,
     0x00c0,
     0x00c3,
     0x00d5,
     0x00a8,
     0x00b4,
     0x2020,
     0x00b6,
     0x00a9,
     0x00ae,
     0x2122,
     0x0133,
     0x0132,
     0x05d0,
     0x05d1,
     0x05d2,
     0x05d3,
     0x05d4,
     0x05d5,
     0x05d6,
     0x05d7,
     0x05d8,
     0x05d9,
     0x05db,
     0x05dc,
     0x05de,
     0x05e0,
     0x05e1,
     0x05e2,
     0x05e4,
     0x05e6,
     0x05e7,
     0x05e8,
     0x05e9,
     0x05ea,
     0x05df,
     0x05da,
     0x05dd,
     0x05e3,
     0x05e5,
     0x00a7,
     0x20ac,
     0x221e,
     0x03b1,
     0x03b2,
     0x0393,
     0x03c0,
     0x03a3,
     0x03c3,
     0x00b5,
     0x03c4,
     0x03a6,
     0x03b8,
     0x03a9,
     0x03b4,
     0x222e,
     0x03c6,
     0x2208,
     0x220f,
     0x2261,
     0x00b1,
     0x2265,
     0x2264,
     0x2320,
     0x2321,
     0x00f7,
     0x2248,
     0x00b0,
     0x2022,
     0x00b7,
     0x221a,
     0x207f,
     0x00b2,
     0x00b3,
     0x00af,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\x04",
     "\x05",
     "\x06",
     "\x07",
     "\x08",
     "\x09",
     "\x0a",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\x14",
     "\x15",
     "\x16",
     "\x17",
     "\x18",
     "\x19",
     "\x1a",
     "\x1b",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\x20",
     "\x21",
     "\x22",
     "\x23",
     "\x24",
     "\x25",
     "\x26",
     "\x27",
     "\x28",
     "\x29",
     "\x2a",
     "\x2b",
     "\x2c",
     "\x2d",
     "\x2e",
     "\x2f",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\x3a",
     "\x3b",
     "\x3c",
     "\x3d",
     "\x3e",
     "\x3f",
     "\x40",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\x5b",
     "\x5c",
     "\x5d",
     "\x5e",
     "\x5f",
     "\x60",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\x7b",
     "\x7c",
     "\x7d",
     "\x7e",
     "\x7f",
     "\xc3\x87",
     "\xc3\xbc",
     "\xc3\xa9",
     "\xc3\xa2",
     "\xc3\xa4",
     "\xc3\xa0",
     "\xc3\xa5",
     "\xc3\xa7",
     "\xc3\xaa",
     "\xc3\xab",
     "\xc3\xa8",
     "\xc3\xaf",
     "\xc3\xae",
     "\xc3\xac",
     "\xc3\x84",
     "\xc3\x85",
     "\xc3\x89",
     "\xc3\xa6",
     "\xc3\x86",
     "\xc3\xb4",
     "\xc3\xb6",
     "\xc3\xb2",
     "\xc3\xbb",
     "\xc3\xb9",
     "\xc3\xbf",
     "\xc3\x96",
     "\xc3\x9c",
     "\xc2\xa2",
     "\xc2\xa3",
     "\xc2\xa5",
     "\xc3\x9f",
     "\xc6\x92",
     "\xc3\xa1",
     "\xc3\xad",
     "\xc3\xb3",
     "\xc3\xba",
     "\xc3\xb1",
     "\xc3\x91",
     "\xc2\xaa",
     "\xc2\xba",
     "\xc2\xbf",
     "\xe2\x8c\x90",
     "\xc2\xac",
     "\xc2\xbd",
     "\xc2\xbc",
     "\xc2\xa1",
     "\xc2\xab",
     "\xc2\xbb",
     "\xc3\xa3",
     "\xc3\xb5",
     "\xc3\x98",
     "\xc3\xb8",
     "\xc5\x93",
     "\xc5\x92",
     "\xc3\x80",
     "\xc3\x83",
     "\xc3\x95",
     "\xc2\xa8",
     "\xc2\xb4",
     "\xe2\x80\xa0",
     "\xc2\xb6",
     "\xc2\xa9",
     "\xc2\xae",
     "\xe2\x84\xa2",
     "\xc4\xb3",
     "\xc4\xb2",
     "\xd7\x90",
     "\xd7\x91",
     "\xd7\x92",
     "\xd7\x93",
     "\xd7\x94",
     "\xd7\x95",
     "\xd7\x96",
     "\xd7\x97",
     "\xd7\x98",
     "\xd7\x99",
     "\xd7\x9b",
     "\xd7\x9c",
     "\xd7\x9e",
     "\xd7\xa0",
     "\xd7\xa1",
     "\xd7\xa2",
     "\xd7\xa4",
     "\xd7\xa6",
     "\xd7\xa7",
     "\xd7\xa8",
     "\xd7\xa9",
     "\xd7\xaa",
     "\xd7\x9f",
     "\xd7\x9a",
     "\xd7\x9d",
     "\xd7\xa3",
     "\xd7\xa5",
     "\xc2\xa7",
     "\xe2\x82\xac",
     "\xe2\x88\x9e",
     "\xce\xb1",
     "\xce\xb2",
     "\xce\x93",
     "\xcf\x80",
     "\xce\xa3",
     "\xcf\x83",
     "\xc2\xb5",
     "\xcf\x84",
     "\xce\xa6",
     "\xce\xb8",
     "\xce\xa9",
     "\xce\xb4",
     "\xe2\x88\xae",
     "\xcf\x86",
     "\xe2\x88\x88",
     "\xe2\x88\x8f",
     "\xe2\x89\xa1",
     "\xc2\xb1",
     "\xe2\x89\xa5",
     "\xe2\x89\xa4",
     "\xe2\x8c\xa0",
     "\xe2\x8c\xa1",
     "\xc3\xb7",
     "\xe2\x89\x88",
     "\xc2\xb0",
     "\xe2\x80\xa2",
     "\xc2\xb7",
     "\xe2\x88\x9a",
     "\xe2\x81\xbf",
     "\xc2\xb2",
     "\xc2\xb3",
     "\xc2\xaf",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x04",
     0x00000005 => "\x05",
     0x00000006 => "\x06",
     0x00000007 => "\x07",
     0x00000008 => "\x08",
     0x00000009 => "\x09",
     0x0000000a => "\x0a",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x14",
     0x00000015 => "\x15",
     0x00000016 => "\x16",
     0x00000017 => "\x17",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x1a",
     0x0000001b => "\x1b",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x20",
     0x00000021 => "\x21",
     0x00000022 => "\x22",
     0x00000023 => "\x23",
     0x00000024 => "\x24",
     0x00000025 => "\x25",
     0x00000026 => "\x26",
     0x00000027 => "\x27",
     0x00000028 => "\x28",
     0x00000029 => "\x29",
     0x0000002a => "\x2a",
     0x0000002b => "\x2b",
     0x0000002c => "\x2c",
     0x0000002d => "\x2d",
     0x0000002e => "\x2e",
     0x0000002f => "\x2f",
     0x00000030 => "\x30",
     0x00000031 => "\x31",
     0x00000032 => "\x32",
     0x00000033 => "\x33",
     0x00000034 => "\x34",
     0x00000035 => "\x35",
     0x00000036 => "\x36",
     0x00000037 => "\x37",
     0x00000038 => "\x38",
     0x00000039 => "\x39",
     0x0000003a => "\x3a",
     0x0000003b => "\x3b",
     0x0000003c => "\x3c",
     0x0000003d => "\x3d",
     0x0000003e => "\x3e",
     0x0000003f => "\x3f",
     0x00000040 => "\x40",
     0x00000041 => "\x41",
     0x00000042 => "\x42",
     0x00000043 => "\x43",
     0x00000044 => "\x44",
     0x00000045 => "\x45",
     0x00000046 => "\x46",
     0x00000047 => "\x47",
     0x00000048 => "\x48",
     0x00000049 => "\x49",
     0x0000004a => "\x4a",
     0x0000004b => "\x4b",
     0x0000004c => "\x4c",
     0x0000004d => "\x4d",
     0x0000004e => "\x4e",
     0x0000004f => "\x4f",
     0x00000050 => "\x50",
     0x00000051 => "\x51",
     0x00000052 => "\x52",
     0x00000053 => "\x53",
     0x00000054 => "\x54",
     0x00000055 => "\x55",
     0x00000056 => "\x56",
     0x00000057 => "\x57",
     0x00000058 => "\x58",
     0x00000059 => "\x59",
     0x0000005a => "\x5a",
     0x0000005b => "\x5b",
     0x0000005c => "\x5c",
     0x0000005d => "\x5d",
     0x0000005e => "\x5e",
     0x0000005f => "\x5f",
     0x00000060 => "\x60",
     0x00000061 => "\x61",
     0x00000062 => "\x62",
     0x00000063 => "\x63",
     0x00000064 => "\x64",
     0x00000065 => "\x65",
     0x00000066 => "\x66",
     0x00000067 => "\x67",
     0x00000068 => "\x68",
     0x00000069 => "\x69",
     0x0000006a => "\x6a",
     0x0000006b => "\x6b",
     0x0000006c => "\x6c",
     0x0000006d => "\x6d",
     0x0000006e => "\x6e",
     0x0000006f => "\x6f",
     0x00000070 => "\x70",
     0x00000071 => "\x71",
     0x00000072 => "\x72",
     0x00000073 => "\x73",
     0x00000074 => "\x74",
     0x00000075 => "\x75",
     0x00000076 => "\x76",
     0x00000077 => "\x77",
     0x00000078 => "\x78",
     0x00000079 => "\x79",
     0x0000007a => "\x7a",
     0x0000007b => "\x7b",
     0x0000007c => "\x7c",
     0x0000007d => "\x7d",
     0x0000007e => "\x7e",
     0x0000007f => "\x7f",
     0x000000a1 => "\xad",
     0x000000a2 => "\x9b",
     0x000000a3 => "\x9c",
     0x000000a5 => "\x9d",
     0x000000a7 => "\xdd",
     0x000000a8 => "\xb9",
     0x000000a9 => "\xbd",
     0x000000aa => "\xa6",
     0x000000ab => "\xae",
     0x000000ac => "\xaa",
     0x000000ae => "\xbe",
     0x000000af => "\xff",
     0x000000b0 => "\xf8",
     0x000000b1 => "\xf1",
     0x000000b2 => "\xfd",
     0x000000b3 => "\xfe",
     0x000000b4 => "\xba",
     0x000000b5 => "\xe6",
     0x000000b6 => "\xbc",
     0x000000b7 => "\xfa",
     0x000000ba => "\xa7",
     0x000000bb => "\xaf",
     0x000000bc => "\xac",
     0x000000bd => "\xab",
     0x000000bf => "\xa8",
     0x000000c0 => "\xb6",
     0x000000c3 => "\xb7",
     0x000000c4 => "\x8e",
     0x000000c5 => "\x8f",
     0x000000c6 => "\x92",
     0x000000c7 => "\x80",
     0x000000c9 => "\x90",
     0x000000d1 => "\xa5",
     0x000000d5 => "\xb8",
     0x000000d6 => "\x99",
     0x000000d8 => "\xb2",
     0x000000dc => "\x9a",
     0x000000df => "\x9e",
     0x000000e0 => "\x85",
     0x000000e1 => "\xa0",
     0x000000e2 => "\x83",
     0x000000e3 => "\xb0",
     0x000000e4 => "\x84",
     0x000000e5 => "\x86",
     0x000000e6 => "\x91",
     0x000000e7 => "\x87",
     0x000000e8 => "\x8a",
     0x000000e9 => "\x82",
     0x000000ea => "\x88",
     0x000000eb => "\x89",
     0x000000ec => "\x8d",
     0x000000ed => "\xa1",
     0x000000ee => "\x8c",
     0x000000ef => "\x8b",
     0x000000f1 => "\xa4",
     0x000000f2 => "\x95",
     0x000000f3 => "\xa2",
     0x000000f4 => "\x93",
     0x000000f5 => "\xb1",
     0x000000f6 => "\x94",
     0x000000f7 => "\xf6",
     0x000000f8 => "\xb3",
     0x000000f9 => "\x97",
     0x000000fa => "\xa3",
     0x000000fb => "\x96",
     0x000000fc => "\x81",
     0x000000ff => "\x98",
     0x00000132 => "\xc1",
     0x00000133 => "\xc0",
     0x00000152 => "\xb5",
     0x00000153 => "\xb4",
     0x00000192 => "\x9f",
     0x00000393 => "\xe2",
     0x000003a3 => "\xe4",
     0x000003a6 => "\xe8",
     0x000003a9 => "\xea",
     0x000003b1 => "\xe0",
     0x000003b2 => "\xe1",
     0x000003b4 => "\xeb",
     0x000003b8 => "\xe9",
     0x000003c0 => "\xe3",
     0x000003c3 => "\xe5",
     0x000003c4 => "\xe7",
     0x000003c6 => "\xed",
     0x000005d0 => "\xc2",
     0x000005d1 => "\xc3",
     0x000005d2 => "\xc4",
     0x000005d3 => "\xc5",
     0x000005d4 => "\xc6",
     0x000005d5 => "\xc7",
     0x000005d6 => "\xc8",
     0x000005d7 => "\xc9",
     0x000005d8 => "\xca",
     0x000005d9 => "\xcb",
     0x000005da => "\xd9",
     0x000005db => "\xcc",
     0x000005dc => "\xcd",
     0x000005dd => "\xda",
     0x000005de => "\xce",
     0x000005df => "\xd8",
     0x000005e0 => "\xcf",
     0x000005e1 => "\xd0",
     0x000005e2 => "\xd1",
     0x000005e3 => "\xdb",
     0x000005e4 => "\xd2",
     0x000005e5 => "\xdc",
     0x000005e6 => "\xd3",
     0x000005e7 => "\xd4",
     0x000005e8 => "\xd5",
     0x000005e9 => "\xd6",
     0x000005ea => "\xd7",
     0x00002020 => "\xbb",
     0x00002022 => "\xf9",
     0x0000207f => "\xfc",
     0x000020ac => "\xde",
     0x00002122 => "\xbf",
     0x00002208 => "\xee",
     0x0000220f => "\xef",
     0x0000221a => "\xfb",
     0x0000221e => "\xdf",
     0x0000222e => "\xec",
     0x00002248 => "\xf7",
     0x00002261 => "\xf0",
     0x00002264 => "\xf3",
     0x00002265 => "\xf2",
     0x00002310 => "\xa9",
     0x00002320 => "\xf4",
     0x00002321 => "\xf5",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::ATARI_ST_EURO - Conversion routines for ATARI-ST-EURO
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for ATARI-ST-EURO.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.1
   source: Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>
  alias ATARIST-EURO
  alias X-ATARIST-EURO
  alias X-ATARI-ST-EURO
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  00000004 | END OF TRANSMISSION (EOT)
     05 |  00000005 | ENQUIRY (ENQ)
     06 |  00000006 | ACKNOWLEDGE (ACK)
     07 |  00000007 | BELL (BEL)
     08 |  00000008 | BACKSPACE (BS)
     09 |  00000009 | CHARACTER TABULATION (HT)
     0A |  0000000A | LINE FEED (LF)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  00000014 | DEVICE CONTROL FOUR (DC4)
     15 |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     16 |  00000016 | SYNCHRONOUS IDLE (SYN)
     17 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  0000001A | SUBSTITUTE (SUB)
     1B |  0000001B | ESCAPE (ESC)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000020 | SPACE
     21 |  00000021 | EXCLAMATION MARK
     22 |  00000022 | QUOTATION MARK
     23 |  00000023 | NUMBER SIGN
     24 |  00000024 | DOLLAR SIGN
     25 |  00000025 | PERCENT SIGN
     26 |  00000026 | AMPERSAND
     27 |  00000027 | APOSTROPHE
     28 |  00000028 | LEFT PARENTHESIS
     29 |  00000029 | RIGHT PARENTHESIS
     2A |  0000002A | ASTERISK
     2B |  0000002B | PLUS SIGN
     2C |  0000002C | COMMA
     2D |  0000002D | HYPHEN-MINUS
     2E |  0000002E | FULL STOP
     2F |  0000002F | SOLIDUS
     30 |  00000030 | DIGIT ZERO
     31 |  00000031 | DIGIT ONE
     32 |  00000032 | DIGIT TWO
     33 |  00000033 | DIGIT THREE
     34 |  00000034 | DIGIT FOUR
     35 |  00000035 | DIGIT FIVE
     36 |  00000036 | DIGIT SIX
     37 |  00000037 | DIGIT SEVEN
     38 |  00000038 | DIGIT EIGHT
     39 |  00000039 | DIGIT NINE
     3A |  0000003A | COLON
     3B |  0000003B | SEMICOLON
     3C |  0000003C | LESS-THAN SIGN
     3D |  0000003D | EQUALS SIGN
     3E |  0000003E | GREATER-THAN SIGN
     3F |  0000003F | QUESTION MARK
     40 |  00000040 | COMMERCIAL AT
     41 |  00000041 | LATIN CAPITAL LETTER A
     42 |  00000042 | LATIN CAPITAL LETTER B
     43 |  00000043 | LATIN CAPITAL LETTER C
     44 |  00000044 | LATIN CAPITAL LETTER D
     45 |  00000045 | LATIN CAPITAL LETTER E
     46 |  00000046 | LATIN CAPITAL LETTER F
     47 |  00000047 | LATIN CAPITAL LETTER G
     48 |  00000048 | LATIN CAPITAL LETTER H
     49 |  00000049 | LATIN CAPITAL LETTER I
     4A |  0000004A | LATIN CAPITAL LETTER J
     4B |  0000004B | LATIN CAPITAL LETTER K
     4C |  0000004C | LATIN CAPITAL LETTER L
     4D |  0000004D | LATIN CAPITAL LETTER M
     4E |  0000004E | LATIN CAPITAL LETTER N
     4F |  0000004F | LATIN CAPITAL LETTER O
     50 |  00000050 | LATIN CAPITAL LETTER P
     51 |  00000051 | LATIN CAPITAL LETTER Q
     52 |  00000052 | LATIN CAPITAL LETTER R
     53 |  00000053 | LATIN CAPITAL LETTER S
     54 |  00000054 | LATIN CAPITAL LETTER T
     55 |  00000055 | LATIN CAPITAL LETTER U
     56 |  00000056 | LATIN CAPITAL LETTER V
     57 |  00000057 | LATIN CAPITAL LETTER W
     58 |  00000058 | LATIN CAPITAL LETTER X
     59 |  00000059 | LATIN CAPITAL LETTER Y
     5A |  0000005A | LATIN CAPITAL LETTER Z
     5B |  0000005B | LEFT SQUARE BRACKET
     5C |  0000005C | REVERSE SOLIDUS
     5D |  0000005D | RIGHT SQUARE BRACKET
     5E |  0000005E | CIRCUMFLEX ACCENT
     5F |  0000005F | LOW LINE
     60 |  00000060 | GRAVE ACCENT
     61 |  00000061 | LATIN SMALL LETTER A
     62 |  00000062 | LATIN SMALL LETTER B
     63 |  00000063 | LATIN SMALL LETTER C
     64 |  00000064 | LATIN SMALL LETTER D
     65 |  00000065 | LATIN SMALL LETTER E
     66 |  00000066 | LATIN SMALL LETTER F
     67 |  00000067 | LATIN SMALL LETTER G
     68 |  00000068 | LATIN SMALL LETTER H
     69 |  00000069 | LATIN SMALL LETTER I
     6A |  0000006A | LATIN SMALL LETTER J
     6B |  0000006B | LATIN SMALL LETTER K
     6C |  0000006C | LATIN SMALL LETTER L
     6D |  0000006D | LATIN SMALL LETTER M
     6E |  0000006E | LATIN SMALL LETTER N
     6F |  0000006F | LATIN SMALL LETTER O
     70 |  00000070 | LATIN SMALL LETTER P
     71 |  00000071 | LATIN SMALL LETTER Q
     72 |  00000072 | LATIN SMALL LETTER R
     73 |  00000073 | LATIN SMALL LETTER S
     74 |  00000074 | LATIN SMALL LETTER T
     75 |  00000075 | LATIN SMALL LETTER U
     76 |  00000076 | LATIN SMALL LETTER V
     77 |  00000077 | LATIN SMALL LETTER W
     78 |  00000078 | LATIN SMALL LETTER X
     79 |  00000079 | LATIN SMALL LETTER Y
     7A |  0000007A | LATIN SMALL LETTER Z
     7B |  0000007B | LEFT CURLY BRACKET
     7C |  0000007C | VERTICAL LINE
     7D |  0000007D | RIGHT CURLY BRACKET
     7E |  0000007E | TILDE
     7F |  0000007F | DELETE
     80 |  000000C7 | LATIN CAPITAL LETTER C WITH CEDILLA
     81 |  000000FC | LATIN SMALL LETTER U WITH DIAERESIS
     82 |  000000E9 | LATIN SMALL LETTER E WITH ACUTE
     83 |  000000E2 | LATIN SMALL LETTER A WITH CIRCUMFLEX
     84 |  000000E4 | LATIN SMALL LETTER A WITH DIAERESIS
     85 |  000000E0 | LATIN SMALL LETTER A WITH GRAVE
     86 |  000000E5 | LATIN SMALL LETTER A WITH RING ABOVE
     87 |  000000E7 | LATIN SMALL LETTER C WITH CEDILLA
     88 |  000000EA | LATIN SMALL LETTER E WITH CIRCUMFLEX
     89 |  000000EB | LATIN SMALL LETTER E WITH DIAERESIS
     8A |  000000E8 | LATIN SMALL LETTER E WITH GRAVE
     8B |  000000EF | LATIN SMALL LETTER I WITH DIAERESIS
     8C |  000000EE | LATIN SMALL LETTER I WITH CIRCUMFLEX
     8D |  000000EC | LATIN SMALL LETTER I WITH GRAVE
     8E |  000000C4 | LATIN CAPITAL LETTER A WITH DIAERESIS
     8F |  000000C5 | LATIN CAPITAL LETTER A WITH RING ABOVE
     90 |  000000C9 | LATIN CAPITAL LETTER E WITH ACUTE
     91 |  000000E6 | LATIN SMALL LETTER AE
     92 |  000000C6 | LATIN CAPITAL LETTER AE
     93 |  000000F4 | LATIN SMALL LETTER O WITH CIRCUMFLEX
     94 |  000000F6 | LATIN SMALL LETTER O WITH DIAERESIS
     95 |  000000F2 | LATIN SMALL LETTER O WITH GRAVE
     96 |  000000FB | LATIN SMALL LETTER U WITH CIRCUMFLEX
     97 |  000000F9 | LATIN SMALL LETTER U WITH GRAVE
     98 |  000000FF | LATIN SMALL LETTER Y WITH DIAERESIS
     99 |  000000D6 | LATIN CAPITAL LETTER O WITH DIAERESIS
     9A |  000000DC | LATIN CAPITAL LETTER U WITH DIAERESIS
     9B |  000000A2 | CENT SIGN
     9C |  000000A3 | POUND SIGN
     9D |  000000A5 | YEN SIGN
     9E |  000000DF | LATIN SMALL LETTER SHARP S
     9F |  00000192 | LATIN SMALL LETTER F WITH HOOK
     A0 |  000000E1 | LATIN SMALL LETTER A WITH ACUTE
     A1 |  000000ED | LATIN SMALL LETTER I WITH ACUTE
     A2 |  000000F3 | LATIN SMALL LETTER O WITH ACUTE
     A3 |  000000FA | LATIN SMALL LETTER U WITH ACUTE
     A4 |  000000F1 | LATIN SMALL LETTER N WITH TILDE
     A5 |  000000D1 | LATIN CAPITAL LETTER N WITH TILDE
     A6 |  000000AA | FEMININE ORDINAL INDICATOR
     A7 |  000000BA | MASCULINE ORDINAL INDICATOR
     A8 |  000000BF | INVERTED QUESTION MARK
     A9 |  00002310 | REVERSED NOT SIGN
     AA |  000000AC | NOT SIGN
     AB |  000000BD | VULGAR FRACTION ONE HALF
     AC |  000000BC | VULGAR FRACTION ONE QUARTER
     AD |  000000A1 | INVERTED EXCLAMATION MARK
     AE |  000000AB | LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
     AF |  000000BB | RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
     B0 |  000000E3 | LATIN SMALL LETTER A WITH TILDE
     B1 |  000000F5 | LATIN SMALL LETTER O WITH TILDE
     B2 |  000000D8 | LATIN CAPITAL LETTER O WITH STROKE
     B3 |  000000F8 | LATIN SMALL LETTER O WITH STROKE
     B4 |  00000153 | LATIN SMALL LIGATURE OE
     B5 |  00000152 | LATIN CAPITAL LIGATURE OE
     B6 |  000000C0 | LATIN CAPITAL LETTER A WITH GRAVE
     B7 |  000000C3 | LATIN CAPITAL LETTER A WITH TILDE
     B8 |  000000D5 | LATIN CAPITAL LETTER O WITH TILDE
     B9 |  000000A8 | DIAERESIS
     BA |  000000B4 | ACUTE ACCENT
     BB |  00002020 | DAGGER
     BC |  000000B6 | PILCROW SIGN
     BD |  000000A9 | COPYRIGHT SIGN
     BE |  000000AE | REGISTERED SIGN
     BF |  00002122 | TRADE MARK SIGN
     C0 |  00000133 | LATIN SMALL LIGATURE IJ
     C1 |  00000132 | LATIN CAPITAL LIGATURE IJ
     C2 |  000005D0 | HEBREW LETTER ALEF
     C3 |  000005D1 | HEBREW LETTER BET
     C4 |  000005D2 | HEBREW LETTER GIMEL
     C5 |  000005D3 | HEBREW LETTER DALET
     C6 |  000005D4 | HEBREW LETTER HE
     C7 |  000005D5 | HEBREW LETTER VAV
     C8 |  000005D6 | HEBREW LETTER ZAYIN
     C9 |  000005D7 | HEBREW LETTER HET
     CA |  000005D8 | HEBREW LETTER TET
     CB |  000005D9 | HEBREW LETTER YOD
     CC |  000005DB | HEBREW LETTER KAF
     CD |  000005DC | HEBREW LETTER LAMED
     CE |  000005DE | HEBREW LETTER MEM
     CF |  000005E0 | HEBREW LETTER NUN
     D0 |  000005E1 | HEBREW LETTER SAMEKH
     D1 |  000005E2 | HEBREW LETTER AYIN
     D2 |  000005E4 | HEBREW LETTER PE
     D3 |  000005E6 | HEBREW LETTER TSADI
     D4 |  000005E7 | HEBREW LETTER QOF
     D5 |  000005E8 | HEBREW LETTER RESH
     D6 |  000005E9 | HEBREW LETTER SHIN
     D7 |  000005EA | HEBREW LETTER TAV
     D8 |  000005DF | HEBREW LETTER FINAL NUN
     D9 |  000005DA | HEBREW LETTER FINAL KAF
     DA |  000005DD | HEBREW LETTER FINAL MEM
     DB |  000005E3 | HEBREW LETTER FINAL PE
     DC |  000005E5 | HEBREW LETTER FINAL TSADI
     DD |  000000A7 | SECTION SIGN
     DE |  000020AC | EURO SIGN
     DF |  0000221E | INFINITY
     E0 |  000003B1 | GREEK SMALL LETTER ALPHA
     E1 |  000003B2 | GREEK SMALL LETTER BETA
     E2 |  00000393 | GREEK CAPITAL LETTER GAMMA
     E3 |  000003C0 | GREEK SMALL LETTER PI
     E4 |  000003A3 | GREEK CAPITAL LETTER SIGMA
     E5 |  000003C3 | GREEK SMALL LETTER SIGMA
     E6 |  000000B5 | MICRO SIGN
     E7 |  000003C4 | GREEK SMALL LETTER TAU
     E8 |  000003A6 | GREEK CAPITAL LETTER PHI
     E9 |  000003B8 | GREEK SMALL LETTER THETA
     EA |  000003A9 | GREEK CAPITAL LETTER OMEGA
     EB |  000003B4 | GREEK SMALL LETTER DELTA
     EC |  0000222E | CONTOUR INTEGRAL
     ED |  000003C6 | GREEK SMALL LETTER PHI
     EE |  00002208 | ELEMENT OF
     EF |  0000220F | N-ARY PRODUCT
     F0 |  00002261 | IDENTICAL TO
     F1 |  000000B1 | PLUS-MINUS SIGN
     F2 |  00002265 | GREATER-THAN OR EQUAL TO
     F3 |  00002264 | LESS-THAN OR EQUAL TO
     F4 |  00002320 | TOP HALF INTEGRAL
     F5 |  00002321 | BOTTOM HALF INTEGRAL
     F6 |  000000F7 | DIVISION SIGN
     F7 |  00002248 | ALMOST EQUAL TO
     F8 |  000000B0 | DEGREE SIGN
     F9 |  00002022 | BULLET
     FA |  000000B7 | MIDDLE DOT
     FB |  0000221A | SQUARE ROOT
     FC |  0000207F | SUPERSCRIPT LATIN SMALL LETTER N
     FD |  000000B2 | SUPERSCRIPT TWO
     FE |  000000B3 | SUPERSCRIPT THREE
     FF |  000000AF | MACRON
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/CP10007.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for CP10007.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::CP10007;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x0004,
     0x0005,
     0x0006,
     0x0007,
     0x0008,
     0x0009,
     0x000a,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x0014,
     0x0015,
     0x0016,
     0x0017,
     0x0018,
     0x0019,
     0x001a,
     0x001b,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0020,
     0x0021,
     0x0022,
     0x0023,
     0x0024,
     0x0025,
     0x0026,
     0x0027,
     0x0028,
     0x0029,
     0x002a,
     0x002b,
     0x002c,
     0x002d,
     0x002e,
     0x002f,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x003a,
     0x003b,
     0x003c,
     0x003d,
     0x003e,
     0x003f,
     0x0040,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x005b,
     0x005c,
     0x005d,
     0x005e,
     0x005f,
     0x0060,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x007b,
     0x007c,
     0x007d,
     0x007e,
     0x007f,
     0x0410,
     0x0411,
     0x0412,
     0x0413,
     0x0414,
     0x0415,
     0x0416,
     0x0417,
     0x0418,
     0x0419,
     0x041a,
     0x041b,
     0x041c,
     0x041d,
     0x041e,
     0x041f,
     0x0420,
     0x0421,
     0x0422,
     0x0423,
     0x0424,
     0x0425,
     0x0426,
     0x0427,
     0x0428,
     0x0429,
     0x042a,
     0x042b,
     0x042c,
     0x042d,
     0x042e,
     0x042f,
     0x2020,
     0x00b0,
     0x00a2,
     0x00a3,
     0x00a7,
     0x2022,
     0x00b6,
     0x0406,
     0x00ae,
     0x00a9,
     0x2122,
     0x0402,
     0x0452,
     0x2260,
     0x0403,
     0x0453,
     0x221e,
     0x00b1,
     0x2264,
     0x2265,
     0x0456,
     0x00b5,
     0x0491,
     0x0408,
     0x0404,
     0x0454,
     0x0407,
     0x0457,
     0x0409,
     0x0459,
     0x040a,
     0x045a,
     0x0458,
     0x0405,
     0x00ac,
     0x221a,
     0x0192,
     0x2248,
     0x2206,
     0x00ab,
     0x00bb,
     0x2026,
     0x00a0,
     0x040b,
     0x045b,
     0x040c,
     0x045c,
     0x0455,
     0x2013,
     0x2014,
     0x201c,
     0x201d,
     0x2018,
     0x2019,
     0x00f7,
     0x201e,
     0x040e,
     0x045e,
     0x040f,
     0x045f,
     0x2116,
     0x0401,
     0x0451,
     0x044f,
     0x0430,
     0x0431,
     0x0432,
     0x0433,
     0x0434,
     0x0435,
     0x0436,
     0x0437,
     0x0438,
     0x0439,
     0x043a,
     0x043b,
     0x043c,
     0x043d,
     0x043e,
     0x043f,
     0x0440,
     0x0441,
     0x0442,
     0x0443,
     0x0444,
     0x0445,
     0x0446,
     0x0447,
     0x0448,
     0x0449,
     0x044a,
     0x044b,
     0x044c,
     0x044d,
     0x044e,
     0x00a4,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\x04",
     "\x05",
     "\x06",
     "\x07",
     "\x08",
     "\x09",
     "\x0a",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\x14",
     "\x15",
     "\x16",
     "\x17",
     "\x18",
     "\x19",
     "\x1a",
     "\x1b",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\x20",
     "\x21",
     "\x22",
     "\x23",
     "\x24",
     "\x25",
     "\x26",
     "\x27",
     "\x28",
     "\x29",
     "\x2a",
     "\x2b",
     "\x2c",
     "\x2d",
     "\x2e",
     "\x2f",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\x3a",
     "\x3b",
     "\x3c",
     "\x3d",
     "\x3e",
     "\x3f",
     "\x40",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\x5b",
     "\x5c",
     "\x5d",
     "\x5e",
     "\x5f",
     "\x60",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\x7b",
     "\x7c",
     "\x7d",
     "\x7e",
     "\x7f",
     "\xd0\x90",
     "\xd0\x91",
     "\xd0\x92",
     "\xd0\x93",
     "\xd0\x94",
     "\xd0\x95",
     "\xd0\x96",
     "\xd0\x97",
     "\xd0\x98",
     "\xd0\x99",
     "\xd0\x9a",
     "\xd0\x9b",
     "\xd0\x9c",
     "\xd0\x9d",
     "\xd0\x9e",
     "\xd0\x9f",
     "\xd0\xa0",
     "\xd0\xa1",
     "\xd0\xa2",
     "\xd0\xa3",
     "\xd0\xa4",
     "\xd0\xa5",
     "\xd0\xa6",
     "\xd0\xa7",
     "\xd0\xa8",
     "\xd0\xa9",
     "\xd0\xaa",
     "\xd0\xab",
     "\xd0\xac",
     "\xd0\xad",
     "\xd0\xae",
     "\xd0\xaf",
     "\xe2\x80\xa0",
     "\xc2\xb0",
     "\xc2\xa2",
     "\xc2\xa3",
     "\xc2\xa7",
     "\xe2\x80\xa2",
     "\xc2\xb6",
     "\xd0\x86",
     "\xc2\xae",
     "\xc2\xa9",
     "\xe2\x84\xa2",
     "\xd0\x82",
     "\xd1\x92",
     "\xe2\x89\xa0",
     "\xd0\x83",
     "\xd1\x93",
     "\xe2\x88\x9e",
     "\xc2\xb1",
     "\xe2\x89\xa4",
     "\xe2\x89\xa5",
     "\xd1\x96",
     "\xc2\xb5",
     "\xd2\x91",
     "\xd0\x88",
     "\xd0\x84",
     "\xd1\x94",
     "\xd0\x87",
     "\xd1\x97",
     "\xd0\x89",
     "\xd1\x99",
     "\xd0\x8a",
     "\xd1\x9a",
     "\xd1\x98",
     "\xd0\x85",
     "\xc2\xac",
     "\xe2\x88\x9a",
     "\xc6\x92",
     "\xe2\x89\x88",
     "\xe2\x88\x86",
     "\xc2\xab",
     "\xc2\xbb",
     "\xe2\x80\xa6",
     "\xc2\xa0",
     "\xd0\x8b",
     "\xd1\x9b",
     "\xd0\x8c",
     "\xd1\x9c",
     "\xd1\x95",
     "\xe2\x80\x93",
     "\xe2\x80\x94",
     "\xe2\x80\x9c",
     "\xe2\x80\x9d",
     "\xe2\x80\x98",
     "\xe2\x80\x99",
     "\xc3\xb7",
     "\xe2\x80\x9e",
     "\xd0\x8e",
     "\xd1\x9e",
     "\xd0\x8f",
     "\xd1\x9f",
     "\xe2\x84\x96",
     "\xd0\x81",
     "\xd1\x91",
     "\xd1\x8f",
     "\xd0\xb0",
     "\xd0\xb1",
     "\xd0\xb2",
     "\xd0\xb3",
     "\xd0\xb4",
     "\xd0\xb5",
     "\xd0\xb6",
     "\xd0\xb7",
     "\xd0\xb8",
     "\xd0\xb9",
     "\xd0\xba",
     "\xd0\xbb",
     "\xd0\xbc",
     "\xd0\xbd",
     "\xd0\xbe",
     "\xd0\xbf",
     "\xd1\x80",
     "\xd1\x81",
     "\xd1\x82",
     "\xd1\x83",
     "\xd1\x84",
     "\xd1\x85",
     "\xd1\x86",
     "\xd1\x87",
     "\xd1\x88",
     "\xd1\x89",
     "\xd1\x8a",
     "\xd1\x8b",
     "\xd1\x8c",
     "\xd1\x8d",
     "\xd1\x8e",
     "\xc2\xa4",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x04",
     0x00000005 => "\x05",
     0x00000006 => "\x06",
     0x00000007 => "\x07",
     0x00000008 => "\x08",
     0x00000009 => "\x09",
     0x0000000a => "\x0a",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x14",
     0x00000015 => "\x15",
     0x00000016 => "\x16",
     0x00000017 => "\x17",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x1a",
     0x0000001b => "\x1b",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x20",
     0x00000021 => "\x21",
     0x00000022 => "\x22",
     0x00000023 => "\x23",
     0x00000024 => "\x24",
     0x00000025 => "\x25",
     0x00000026 => "\x26",
     0x00000027 => "\x27",
     0x00000028 => "\x28",
     0x00000029 => "\x29",
     0x0000002a => "\x2a",
     0x0000002b => "\x2b",
     0x0000002c => "\x2c",
     0x0000002d => "\x2d",
     0x0000002e => "\x2e",
     0x0000002f => "\x2f",
     0x00000030 => "\x30",
     0x00000031 => "\x31",
     0x00000032 => "\x32",
     0x00000033 => "\x33",
     0x00000034 => "\x34",
     0x00000035 => "\x35",
     0x00000036 => "\x36",
     0x00000037 => "\x37",
     0x00000038 => "\x38",
     0x00000039 => "\x39",
     0x0000003a => "\x3a",
     0x0000003b => "\x3b",
     0x0000003c => "\x3c",
     0x0000003d => "\x3d",
     0x0000003e => "\x3e",
     0x0000003f => "\x3f",
     0x00000040 => "\x40",
     0x00000041 => "\x41",
     0x00000042 => "\x42",
     0x00000043 => "\x43",
     0x00000044 => "\x44",
     0x00000045 => "\x45",
     0x00000046 => "\x46",
     0x00000047 => "\x47",
     0x00000048 => "\x48",
     0x00000049 => "\x49",
     0x0000004a => "\x4a",
     0x0000004b => "\x4b",
     0x0000004c => "\x4c",
     0x0000004d => "\x4d",
     0x0000004e => "\x4e",
     0x0000004f => "\x4f",
     0x00000050 => "\x50",
     0x00000051 => "\x51",
     0x00000052 => "\x52",
     0x00000053 => "\x53",
     0x00000054 => "\x54",
     0x00000055 => "\x55",
     0x00000056 => "\x56",
     0x00000057 => "\x57",
     0x00000058 => "\x58",
     0x00000059 => "\x59",
     0x0000005a => "\x5a",
     0x0000005b => "\x5b",
     0x0000005c => "\x5c",
     0x0000005d => "\x5d",
     0x0000005e => "\x5e",
     0x0000005f => "\x5f",
     0x00000060 => "\x60",
     0x00000061 => "\x61",
     0x00000062 => "\x62",
     0x00000063 => "\x63",
     0x00000064 => "\x64",
     0x00000065 => "\x65",
     0x00000066 => "\x66",
     0x00000067 => "\x67",
     0x00000068 => "\x68",
     0x00000069 => "\x69",
     0x0000006a => "\x6a",
     0x0000006b => "\x6b",
     0x0000006c => "\x6c",
     0x0000006d => "\x6d",
     0x0000006e => "\x6e",
     0x0000006f => "\x6f",
     0x00000070 => "\x70",
     0x00000071 => "\x71",
     0x00000072 => "\x72",
     0x00000073 => "\x73",
     0x00000074 => "\x74",
     0x00000075 => "\x75",
     0x00000076 => "\x76",
     0x00000077 => "\x77",
     0x00000078 => "\x78",
     0x00000079 => "\x79",
     0x0000007a => "\x7a",
     0x0000007b => "\x7b",
     0x0000007c => "\x7c",
     0x0000007d => "\x7d",
     0x0000007e => "\x7e",
     0x0000007f => "\x7f",
     0x000000a0 => "\xca",
     0x000000a2 => "\xa2",
     0x000000a3 => "\xa3",
     0x000000a4 => "\xff",
     0x000000a7 => "\xa4",
     0x000000a9 => "\xa9",
     0x000000ab => "\xc7",
     0x000000ac => "\xc2",
     0x000000ae => "\xa8",
     0x000000b0 => "\xa1",
     0x000000b1 => "\xb1",
     0x000000b5 => "\xb5",
     0x000000b6 => "\xa6",
     0x000000bb => "\xc8",
     0x000000f7 => "\xd6",
     0x00000192 => "\xc4",
     0x00000401 => "\xdd",
     0x00000402 => "\xab",
     0x00000403 => "\xae",
     0x00000404 => "\xb8",
     0x00000405 => "\xc1",
     0x00000406 => "\xa7",
     0x00000407 => "\xba",
     0x00000408 => "\xb7",
     0x00000409 => "\xbc",
     0x0000040a => "\xbe",
     0x0000040b => "\xcb",
     0x0000040c => "\xcd",
     0x0000040e => "\xd8",
     0x0000040f => "\xda",
     0x00000410 => "\x80",
     0x00000411 => "\x81",
     0x00000412 => "\x82",
     0x00000413 => "\x83",
     0x00000414 => "\x84",
     0x00000415 => "\x85",
     0x00000416 => "\x86",
     0x00000417 => "\x87",
     0x00000418 => "\x88",
     0x00000419 => "\x89",
     0x0000041a => "\x8a",
     0x0000041b => "\x8b",
     0x0000041c => "\x8c",
     0x0000041d => "\x8d",
     0x0000041e => "\x8e",
     0x0000041f => "\x8f",
     0x00000420 => "\x90",
     0x00000421 => "\x91",
     0x00000422 => "\x92",
     0x00000423 => "\x93",
     0x00000424 => "\x94",
     0x00000425 => "\x95",
     0x00000426 => "\x96",
     0x00000427 => "\x97",
     0x00000428 => "\x98",
     0x00000429 => "\x99",
     0x0000042a => "\x9a",
     0x0000042b => "\x9b",
     0x0000042c => "\x9c",
     0x0000042d => "\x9d",
     0x0000042e => "\x9e",
     0x0000042f => "\x9f",
     0x00000430 => "\xe0",
     0x00000431 => "\xe1",
     0x00000432 => "\xe2",
     0x00000433 => "\xe3",
     0x00000434 => "\xe4",
     0x00000435 => "\xe5",
     0x00000436 => "\xe6",
     0x00000437 => "\xe7",
     0x00000438 => "\xe8",
     0x00000439 => "\xe9",
     0x0000043a => "\xea",
     0x0000043b => "\xeb",
     0x0000043c => "\xec",
     0x0000043d => "\xed",
     0x0000043e => "\xee",
     0x0000043f => "\xef",
     0x00000440 => "\xf0",
     0x00000441 => "\xf1",
     0x00000442 => "\xf2",
     0x00000443 => "\xf3",
     0x00000444 => "\xf4",
     0x00000445 => "\xf5",
     0x00000446 => "\xf6",
     0x00000447 => "\xf7",
     0x00000448 => "\xf8",
     0x00000449 => "\xf9",
     0x0000044a => "\xfa",
     0x0000044b => "\xfb",
     0x0000044c => "\xfc",
     0x0000044d => "\xfd",
     0x0000044e => "\xfe",
     0x0000044f => "\xdf",
     0x00000451 => "\xde",
     0x00000452 => "\xac",
     0x00000453 => "\xaf",
     0x00000454 => "\xb9",
     0x00000455 => "\xcf",
     0x00000456 => "\xb4",
     0x00000457 => "\xbb",
     0x00000458 => "\xc0",
     0x00000459 => "\xbd",
     0x0000045a => "\xbf",
     0x0000045b => "\xcc",
     0x0000045c => "\xce",
     0x0000045e => "\xd9",
     0x0000045f => "\xdb",
     0x00000491 => "\xb6",
     0x00002013 => "\xd0",
     0x00002014 => "\xd1",
     0x00002018 => "\xd4",
     0x00002019 => "\xd5",
     0x0000201c => "\xd2",
     0x0000201d => "\xd3",
     0x0000201e => "\xd7",
     0x00002020 => "\xa0",
     0x00002022 => "\xa5",
     0x00002026 => "\xc9",
     0x00002116 => "\xdc",
     0x00002122 => "\xaa",
     0x00002206 => "\xc6",
     0x0000221a => "\xc3",
     0x0000221e => "\xb0",
     0x00002248 => "\xc5",
     0x00002260 => "\xad",
     0x00002264 => "\xb2",
     0x00002265 => "\xb3",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::CP10007 - Conversion routines for CP10007
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for CP10007.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  This is the old MacCyrillic which M$ keeps around as CP10007.
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL
     01 |  00000001 | START OF HEADING
     02 |  00000002 | START OF TEXT
     03 |  00000003 | END OF TEXT
     04 |  00000004 | END OF TRANSMISSION
     05 |  00000005 | ENQUIRY
     06 |  00000006 | ACKNOWLEDGE
     07 |  00000007 | BELL
     08 |  00000008 | BACKSPACE
     09 |  00000009 | HORIZONTAL TABULATION
     0A |  0000000A | LINE FEED
     0B |  0000000B | VERTICAL TABULATION
     0C |  0000000C | FORM FEED
     0D |  0000000D | CARRIAGE RETURN
     0E |  0000000E | SHIFT OUT
     0F |  0000000F | SHIFT IN
     10 |  00000010 | DATA LINK ESCAPE
     11 |  00000011 | DEVICE CONTROL ONE
     12 |  00000012 | DEVICE CONTROL TWO
     13 |  00000013 | DEVICE CONTROL THREE
     14 |  00000014 | DEVICE CONTROL FOUR
     15 |  00000015 | NEGATIVE ACKNOWLEDGE
     16 |  00000016 | SYNCHRONOUS IDLE
     17 |  00000017 | END OF TRANSMISSION BLOCK
     18 |  00000018 | CANCEL
     19 |  00000019 | END OF MEDIUM
     1A |  0000001A | SUBSTITUTE
     1B |  0000001B | ESCAPE
     1C |  0000001C | FILE SEPARATOR
     1D |  0000001D | GROUP SEPARATOR
     1E |  0000001E | RECORD SEPARATOR
     1F |  0000001F | UNIT SEPARATOR
     20 |  00000020 | SPACE
     21 |  00000021 | EXCLAMATION MARK
     22 |  00000022 | QUOTATION MARK
     23 |  00000023 | NUMBER SIGN
     24 |  00000024 | DOLLAR SIGN
     25 |  00000025 | PERCENT SIGN
     26 |  00000026 | AMPERSAND
     27 |  00000027 | APOSTROPHE
     28 |  00000028 | LEFT PARENTHESIS
     29 |  00000029 | RIGHT PARENTHESIS
     2A |  0000002A | ASTERISK
     2B |  0000002B | PLUS SIGN
     2C |  0000002C | COMMA
     2D |  0000002D | HYPHEN-MINUS
     2E |  0000002E | FULL STOP
     2F |  0000002F | SOLIDUS
     30 |  00000030 | DIGIT ZERO
     31 |  00000031 | DIGIT ONE
     32 |  00000032 | DIGIT TWO
     33 |  00000033 | DIGIT THREE
     34 |  00000034 | DIGIT FOUR
     35 |  00000035 | DIGIT FIVE
     36 |  00000036 | DIGIT SIX
     37 |  00000037 | DIGIT SEVEN
     38 |  00000038 | DIGIT EIGHT
     39 |  00000039 | DIGIT NINE
     3A |  0000003A | COLON
     3B |  0000003B | SEMICOLON
     3C |  0000003C | LESS-THAN SIGN
     3D |  0000003D | EQUALS SIGN
     3E |  0000003E | GREATER-THAN SIGN
     3F |  0000003F | QUESTION MARK
     40 |  00000040 | COMMERCIAL AT
     41 |  00000041 | LATIN CAPITAL LETTER A
     42 |  00000042 | LATIN CAPITAL LETTER B
     43 |  00000043 | LATIN CAPITAL LETTER C
     44 |  00000044 | LATIN CAPITAL LETTER D
     45 |  00000045 | LATIN CAPITAL LETTER E
     46 |  00000046 | LATIN CAPITAL LETTER F
     47 |  00000047 | LATIN CAPITAL LETTER G
     48 |  00000048 | LATIN CAPITAL LETTER H
     49 |  00000049 | LATIN CAPITAL LETTER I
     4A |  0000004A | LATIN CAPITAL LETTER J
     4B |  0000004B | LATIN CAPITAL LETTER K
     4C |  0000004C | LATIN CAPITAL LETTER L
     4D |  0000004D | LATIN CAPITAL LETTER M
     4E |  0000004E | LATIN CAPITAL LETTER N
     4F |  0000004F | LATIN CAPITAL LETTER O
     50 |  00000050 | LATIN CAPITAL LETTER P
     51 |  00000051 | LATIN CAPITAL LETTER Q
     52 |  00000052 | LATIN CAPITAL LETTER R
     53 |  00000053 | LATIN CAPITAL LETTER S
     54 |  00000054 | LATIN CAPITAL LETTER T
     55 |  00000055 | LATIN CAPITAL LETTER U
     56 |  00000056 | LATIN CAPITAL LETTER V
     57 |  00000057 | LATIN CAPITAL LETTER W
     58 |  00000058 | LATIN CAPITAL LETTER X
     59 |  00000059 | LATIN CAPITAL LETTER Y
     5A |  0000005A | LATIN CAPITAL LETTER Z
     5B |  0000005B | LEFT SQUARE BRACKET
     5C |  0000005C | REVERSE SOLIDUS
     5D |  0000005D | RIGHT SQUARE BRACKET
     5E |  0000005E | CIRCUMFLEX ACCENT
     5F |  0000005F | LOW LINE
     60 |  00000060 | GRAVE ACCENT
     61 |  00000061 | LATIN SMALL LETTER A
     62 |  00000062 | LATIN SMALL LETTER B
     63 |  00000063 | LATIN SMALL LETTER C
     64 |  00000064 | LATIN SMALL LETTER D
     65 |  00000065 | LATIN SMALL LETTER E
     66 |  00000066 | LATIN SMALL LETTER F
     67 |  00000067 | LATIN SMALL LETTER G
     68 |  00000068 | LATIN SMALL LETTER H
     69 |  00000069 | LATIN SMALL LETTER I
     6A |  0000006A | LATIN SMALL LETTER J
     6B |  0000006B | LATIN SMALL LETTER K
     6C |  0000006C | LATIN SMALL LETTER L
     6D |  0000006D | LATIN SMALL LETTER M
     6E |  0000006E | LATIN SMALL LETTER N
     6F |  0000006F | LATIN SMALL LETTER O
     70 |  00000070 | LATIN SMALL LETTER P
     71 |  00000071 | LATIN SMALL LETTER Q
     72 |  00000072 | LATIN SMALL LETTER R
     73 |  00000073 | LATIN SMALL LETTER S
     74 |  00000074 | LATIN SMALL LETTER T
     75 |  00000075 | LATIN SMALL LETTER U
     76 |  00000076 | LATIN SMALL LETTER V
     77 |  00000077 | LATIN SMALL LETTER W
     78 |  00000078 | LATIN SMALL LETTER X
     79 |  00000079 | LATIN SMALL LETTER Y
     7A |  0000007A | LATIN SMALL LETTER Z
     7B |  0000007B | LEFT CURLY BRACKET
     7C |  0000007C | VERTICAL LINE
     7D |  0000007D | RIGHT CURLY BRACKET
     7E |  0000007E | TILDE
     7F |  0000007F | DELETE
     80 |  00000410 | CYRILLIC CAPITAL LETTER A
     81 |  00000411 | CYRILLIC CAPITAL LETTER BE
     82 |  00000412 | CYRILLIC CAPITAL LETTER VE
     83 |  00000413 | CYRILLIC CAPITAL LETTER GHE
     84 |  00000414 | CYRILLIC CAPITAL LETTER DE
     85 |  00000415 | CYRILLIC CAPITAL LETTER IE
     86 |  00000416 | CYRILLIC CAPITAL LETTER ZHE
     87 |  00000417 | CYRILLIC CAPITAL LETTER ZE
     88 |  00000418 | CYRILLIC CAPITAL LETTER I
     89 |  00000419 | CYRILLIC CAPITAL LETTER SHORT I
     8A |  0000041A | CYRILLIC CAPITAL LETTER KA
     8B |  0000041B | CYRILLIC CAPITAL LETTER EL
     8C |  0000041C | CYRILLIC CAPITAL LETTER EM
     8D |  0000041D | CYRILLIC CAPITAL LETTER EN
     8E |  0000041E | CYRILLIC CAPITAL LETTER O
     8F |  0000041F | CYRILLIC CAPITAL LETTER PE
     90 |  00000420 | CYRILLIC CAPITAL LETTER ER
     91 |  00000421 | CYRILLIC CAPITAL LETTER ES
     92 |  00000422 | CYRILLIC CAPITAL LETTER TE
     93 |  00000423 | CYRILLIC CAPITAL LETTER U
     94 |  00000424 | CYRILLIC CAPITAL LETTER EF
     95 |  00000425 | CYRILLIC CAPITAL LETTER HA
     96 |  00000426 | CYRILLIC CAPITAL LETTER TSE
     97 |  00000427 | CYRILLIC CAPITAL LETTER CHE
     98 |  00000428 | CYRILLIC CAPITAL LETTER SHA
     99 |  00000429 | CYRILLIC CAPITAL LETTER SHCHA
     9A |  0000042A | CYRILLIC CAPITAL LETTER HARD SIGN
     9B |  0000042B | CYRILLIC CAPITAL LETTER YERU
     9C |  0000042C | CYRILLIC CAPITAL LETTER SOFT SIGN
     9D |  0000042D | CYRILLIC CAPITAL LETTER E
     9E |  0000042E | CYRILLIC CAPITAL LETTER YU
     9F |  0000042F | CYRILLIC CAPITAL LETTER YA
     A0 |  00002020 | DAGGER
     A1 |  000000B0 | DEGREE SIGN
     A2 |  000000A2 | CENT SIGN
     A3 |  000000A3 | POUND SIGN
     A4 |  000000A7 | SECTION SIGN
     A5 |  00002022 | BULLET
     A6 |  000000B6 | PILCROW SIGN
     A7 |  00000406 | CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I
     A8 |  000000AE | REGISTERED SIGN
     A9 |  000000A9 | COPYRIGHT SIGN
     AA |  00002122 | TRADE MARK SIGN
     AB |  00000402 | CYRILLIC CAPITAL LETTER DJE
     AC |  00000452 | CYRILLIC SMALL LETTER DJE
     AD |  00002260 | NOT EQUAL TO
     AE |  00000403 | CYRILLIC CAPITAL LETTER GJE
     AF |  00000453 | CYRILLIC SMALL LETTER GJE
     B0 |  0000221E | INFINITY
     B1 |  000000B1 | PLUS-MINUS SIGN
     B2 |  00002264 | LESS-THAN OR EQUAL TO
     B3 |  00002265 | GREATER-THAN OR EQUAL TO
     B4 |  00000456 | CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I
     B5 |  000000B5 | MICRO SIGN
     B6 |  00000491 | CYRILLIC SMALL LETTER GHE WITH UPTURN
     B7 |  00000408 | CYRILLIC CAPITAL LETTER JE
     B8 |  00000404 | CYRILLIC CAPITAL LETTER UKRAINIAN IE
     B9 |  00000454 | CYRILLIC SMALL LETTER UKRAINIAN IE
     BA |  00000407 | CYRILLIC CAPITAL LETTER YI
     BB |  00000457 | CYRILLIC SMALL LETTER YI
     BC |  00000409 | CYRILLIC CAPITAL LETTER LJE
     BD |  00000459 | CYRILLIC SMALL LETTER LJE
     BE |  0000040A | CYRILLIC CAPITAL LETTER NJE
     BF |  0000045A | CYRILLIC SMALL LETTER NJE
     C0 |  00000458 | CYRILLIC SMALL LETTER JE
     C1 |  00000405 | CYRILLIC CAPITAL LETTER DZE
     C2 |  000000AC | NOT SIGN
     C3 |  0000221A | SQUARE ROOT
     C4 |  00000192 | LATIN SMALL LETTER F WITH HOOK
     C5 |  00002248 | ALMOST EQUAL TO
     C6 |  00002206 | INCREMENT
     C7 |  000000AB | LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
     C8 |  000000BB | RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
     C9 |  00002026 | HORIZONTAL ELLIPSIS
     CA |  000000A0 | NO-BREAK SPACE
     CB |  0000040B | CYRILLIC CAPITAL LETTER TSHE
     CC |  0000045B | CYRILLIC SMALL LETTER TSHE
     CD |  0000040C | CYRILLIC CAPITAL LETTER KJE
     CE |  0000045C | CYRILLIC SMALL LETTER KJE
     CF |  00000455 | CYRILLIC SMALL LETTER DZE
     D0 |  00002013 | EN DASH
     D1 |  00002014 | EM DASH
     D2 |  0000201C | LEFT DOUBLE QUOTATION MARK
     D3 |  0000201D | RIGHT DOUBLE QUOTATION MARK
     D4 |  00002018 | LEFT SINGLE QUOTATION MARK
     D5 |  00002019 | RIGHT SINGLE QUOTATION MARK
     D6 |  000000F7 | DIVISION SIGN
     D7 |  0000201E | DOUBLE LOW-9 QUOTATION MARK
     D8 |  0000040E | CYRILLIC CAPITAL LETTER SHORT U
     D9 |  0000045E | CYRILLIC SMALL LETTER SHORT U
     DA |  0000040F | CYRILLIC CAPITAL LETTER DZHE
     DB |  0000045F | CYRILLIC SMALL LETTER DZHE
     DC |  00002116 | NUMERO SIGN
     DD |  00000401 | CYRILLIC CAPITAL LETTER IO
     DE |  00000451 | CYRILLIC SMALL LETTER IO
     DF |  0000044F | CYRILLIC SMALL LETTER YA
     E0 |  00000430 | CYRILLIC SMALL LETTER A
     E1 |  00000431 | CYRILLIC SMALL LETTER BE
     E2 |  00000432 | CYRILLIC SMALL LETTER VE
     E3 |  00000433 | CYRILLIC SMALL LETTER GHE
     E4 |  00000434 | CYRILLIC SMALL LETTER DE
     E5 |  00000435 | CYRILLIC SMALL LETTER IE
     E6 |  00000436 | CYRILLIC SMALL LETTER ZHE
     E7 |  00000437 | CYRILLIC SMALL LETTER ZE
     E8 |  00000438 | CYRILLIC SMALL LETTER I
     E9 |  00000439 | CYRILLIC SMALL LETTER SHORT I
     EA |  0000043A | CYRILLIC SMALL LETTER KA
     EB |  0000043B | CYRILLIC SMALL LETTER EL
     EC |  0000043C | CYRILLIC SMALL LETTER EM
     ED |  0000043D | CYRILLIC SMALL LETTER EN
     EE |  0000043E | CYRILLIC SMALL LETTER O
     EF |  0000043F | CYRILLIC SMALL LETTER PE
     F0 |  00000440 | CYRILLIC SMALL LETTER ER
     F1 |  00000441 | CYRILLIC SMALL LETTER ES
     F2 |  00000442 | CYRILLIC SMALL LETTER TE
     F3 |  00000443 | CYRILLIC SMALL LETTER U
     F4 |  00000444 | CYRILLIC SMALL LETTER EF
     F5 |  00000445 | CYRILLIC SMALL LETTER HA
     F6 |  00000446 | CYRILLIC SMALL LETTER TSE
     F7 |  00000447 | CYRILLIC SMALL LETTER CHE
     F8 |  00000448 | CYRILLIC SMALL LETTER SHA
     F9 |  00000449 | CYRILLIC SMALL LETTER SHCHA
     FA |  0000044A | CYRILLIC SMALL LETTER HARD SIGN
     FB |  0000044B | CYRILLIC SMALL LETTER YERU
     FC |  0000044C | CYRILLIC SMALL LETTER SOFT SIGN
     FD |  0000044D | CYRILLIC SMALL LETTER E
     FE |  0000044E | CYRILLIC SMALL LETTER YU
     FF |  000000A4 | CURRENCY SIGN
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/CP1250.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for CP1250.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::CP1250;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x0004,
     0x0005,
     0x0006,
     0x0007,
     0x0008,
     0x0009,
     0x000a,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x0014,
     0x0015,
     0x0016,
     0x0017,
     0x0018,
     0x0019,
     0x001a,
     0x001b,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0020,
     0x0021,
     0x0022,
     0x0023,
     0x0024,
     0x0025,
     0x0026,
     0x0027,
     0x0028,
     0x0029,
     0x002a,
     0x002b,
     0x002c,
     0x002d,
     0x002e,
     0x002f,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x003a,
     0x003b,
     0x003c,
     0x003d,
     0x003e,
     0x003f,
     0x0040,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x005b,
     0x005c,
     0x005d,
     0x005e,
     0x005f,
     0x0060,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x007b,
     0x007c,
     0x007d,
     0x007e,
     0x007f,
     0x20ac,
     0xfffd,
     0x201a,
     0xfffd,
     0x201e,
     0x2026,
     0x2020,
     0x2021,
     0xfffd,
     0x2030,
     0x0160,
     0x2039,
     0x015a,
     0x0164,
     0x017d,
     0x0179,
     0xfffd,
     0x2018,
     0x2019,
     0x201c,
     0x201d,
     0x2022,
     0x2013,
     0x2014,
     0xfffd,
     0x2122,
     0x0161,
     0x203a,
     0x015b,
     0x0165,
     0x017e,
     0x017a,
     0x00a0,
     0x02c7,
     0x02d8,
     0x0141,
     0x00a4,
     0x0104,
     0x00a6,
     0x00a7,
     0x00a8,
     0x00a9,
     0x015e,
     0x00ab,
     0x00ac,
     0x00ad,
     0x00ae,
     0x017b,
     0x00b0,
     0x00b1,
     0x02db,
     0x0142,
     0x00b4,
     0x00b5,
     0x00b6,
     0x00b7,
     0x00b8,
     0x0105,
     0x015f,
     0x00bb,
     0x013d,
     0x02dd,
     0x013e,
     0x017c,
     0x0154,
     0x00c1,
     0x00c2,
     0x0102,
     0x00c4,
     0x0139,
     0x0106,
     0x00c7,
     0x010c,
     0x00c9,
     0x0118,
     0x00cb,
     0x011a,
     0x00cd,
     0x00ce,
     0x010e,
     0x0110,
     0x0143,
     0x0147,
     0x00d3,
     0x00d4,
     0x0150,
     0x00d6,
     0x00d7,
     0x0158,
     0x016e,
     0x00da,
     0x0170,
     0x00dc,
     0x00dd,
     0x0162,
     0x00df,
     0x0155,
     0x00e1,
     0x00e2,
     0x0103,
     0x00e4,
     0x013a,
     0x0107,
     0x00e7,
     0x010d,
     0x00e9,
     0x0119,
     0x00eb,
     0x011b,
     0x00ed,
     0x00ee,
     0x010f,
     0x0111,
     0x0144,
     0x0148,
     0x00f3,
     0x00f4,
     0x0151,
     0x00f6,
     0x00f7,
     0x0159,
     0x016f,
     0x00fa,
     0x0171,
     0x00fc,
     0x00fd,
     0x0163,
     0x02d9,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\x04",
     "\x05",
     "\x06",
     "\x07",
     "\x08",
     "\x09",
     "\x0a",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\x14",
     "\x15",
     "\x16",
     "\x17",
     "\x18",
     "\x19",
     "\x1a",
     "\x1b",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\x20",
     "\x21",
     "\x22",
     "\x23",
     "\x24",
     "\x25",
     "\x26",
     "\x27",
     "\x28",
     "\x29",
     "\x2a",
     "\x2b",
     "\x2c",
     "\x2d",
     "\x2e",
     "\x2f",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\x3a",
     "\x3b",
     "\x3c",
     "\x3d",
     "\x3e",
     "\x3f",
     "\x40",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\x5b",
     "\x5c",
     "\x5d",
     "\x5e",
     "\x5f",
     "\x60",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\x7b",
     "\x7c",
     "\x7d",
     "\x7e",
     "\x7f",
     "\xe2\x82\xac",
     "\xef\xbf\xbd",
     "\xe2\x80\x9a",
     "\xef\xbf\xbd",
     "\xe2\x80\x9e",
     "\xe2\x80\xa6",
     "\xe2\x80\xa0",
     "\xe2\x80\xa1",
     "\xef\xbf\xbd",
     "\xe2\x80\xb0",
     "\xc5\xa0",
     "\xe2\x80\xb9",
     "\xc5\x9a",
     "\xc5\xa4",
     "\xc5\xbd",
     "\xc5\xb9",
     "\xef\xbf\xbd",
     "\xe2\x80\x98",
     "\xe2\x80\x99",
     "\xe2\x80\x9c",
     "\xe2\x80\x9d",
     "\xe2\x80\xa2",
     "\xe2\x80\x93",
     "\xe2\x80\x94",
     "\xef\xbf\xbd",
     "\xe2\x84\xa2",
     "\xc5\xa1",
     "\xe2\x80\xba",
     "\xc5\x9b",
     "\xc5\xa5",
     "\xc5\xbe",
     "\xc5\xba",
     "\xc2\xa0",
     "\xcb\x87",
     "\xcb\x98",
     "\xc5\x81",
     "\xc2\xa4",
     "\xc4\x84",
     "\xc2\xa6",
     "\xc2\xa7",
     "\xc2\xa8",
     "\xc2\xa9",
     "\xc5\x9e",
     "\xc2\xab",
     "\xc2\xac",
     "\xc2\xad",
     "\xc2\xae",
     "\xc5\xbb",
     "\xc2\xb0",
     "\xc2\xb1",
     "\xcb\x9b",
     "\xc5\x82",
     "\xc2\xb4",
     "\xc2\xb5",
     "\xc2\xb6",
     "\xc2\xb7",
     "\xc2\xb8",
     "\xc4\x85",
     "\xc5\x9f",
     "\xc2\xbb",
     "\xc4\xbd",
     "\xcb\x9d",
     "\xc4\xbe",
     "\xc5\xbc",
     "\xc5\x94",
     "\xc3\x81",
     "\xc3\x82",
     "\xc4\x82",
     "\xc3\x84",
     "\xc4\xb9",
     "\xc4\x86",
     "\xc3\x87",
     "\xc4\x8c",
     "\xc3\x89",
     "\xc4\x98",
     "\xc3\x8b",
     "\xc4\x9a",
     "\xc3\x8d",
     "\xc3\x8e",
     "\xc4\x8e",
     "\xc4\x90",
     "\xc5\x83",
     "\xc5\x87",
     "\xc3\x93",
     "\xc3\x94",
     "\xc5\x90",
     "\xc3\x96",
     "\xc3\x97",
     "\xc5\x98",
     "\xc5\xae",
     "\xc3\x9a",
     "\xc5\xb0",
     "\xc3\x9c",
     "\xc3\x9d",
     "\xc5\xa2",
     "\xc3\x9f",
     "\xc5\x95",
     "\xc3\xa1",
     "\xc3\xa2",
     "\xc4\x83",
     "\xc3\xa4",
     "\xc4\xba",
     "\xc4\x87",
     "\xc3\xa7",
     "\xc4\x8d",
     "\xc3\xa9",
     "\xc4\x99",
     "\xc3\xab",
     "\xc4\x9b",
     "\xc3\xad",
     "\xc3\xae",
     "\xc4\x8f",
     "\xc4\x91",
     "\xc5\x84",
     "\xc5\x88",
     "\xc3\xb3",
     "\xc3\xb4",
     "\xc5\x91",
     "\xc3\xb6",
     "\xc3\xb7",
     "\xc5\x99",
     "\xc5\xaf",
     "\xc3\xba",
     "\xc5\xb1",
     "\xc3\xbc",
     "\xc3\xbd",
     "\xc5\xa3",
     "\xcb\x99",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x04",
     0x00000005 => "\x05",
     0x00000006 => "\x06",
     0x00000007 => "\x07",
     0x00000008 => "\x08",
     0x00000009 => "\x09",
     0x0000000a => "\x0a",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x14",
     0x00000015 => "\x15",
     0x00000016 => "\x16",
     0x00000017 => "\x17",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x1a",
     0x0000001b => "\x1b",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x20",
     0x00000021 => "\x21",
     0x00000022 => "\x22",
     0x00000023 => "\x23",
     0x00000024 => "\x24",
     0x00000025 => "\x25",
     0x00000026 => "\x26",
     0x00000027 => "\x27",
     0x00000028 => "\x28",
     0x00000029 => "\x29",
     0x0000002a => "\x2a",
     0x0000002b => "\x2b",
     0x0000002c => "\x2c",
     0x0000002d => "\x2d",
     0x0000002e => "\x2e",
     0x0000002f => "\x2f",
     0x00000030 => "\x30",
     0x00000031 => "\x31",
     0x00000032 => "\x32",
     0x00000033 => "\x33",
     0x00000034 => "\x34",
     0x00000035 => "\x35",
     0x00000036 => "\x36",
     0x00000037 => "\x37",
     0x00000038 => "\x38",
     0x00000039 => "\x39",
     0x0000003a => "\x3a",
     0x0000003b => "\x3b",
     0x0000003c => "\x3c",
     0x0000003d => "\x3d",
     0x0000003e => "\x3e",
     0x0000003f => "\x3f",
     0x00000040 => "\x40",
     0x00000041 => "\x41",
     0x00000042 => "\x42",
     0x00000043 => "\x43",
     0x00000044 => "\x44",
     0x00000045 => "\x45",
     0x00000046 => "\x46",
     0x00000047 => "\x47",
     0x00000048 => "\x48",
     0x00000049 => "\x49",
     0x0000004a => "\x4a",
     0x0000004b => "\x4b",
     0x0000004c => "\x4c",
     0x0000004d => "\x4d",
     0x0000004e => "\x4e",
     0x0000004f => "\x4f",
     0x00000050 => "\x50",
     0x00000051 => "\x51",
     0x00000052 => "\x52",
     0x00000053 => "\x53",
     0x00000054 => "\x54",
     0x00000055 => "\x55",
     0x00000056 => "\x56",
     0x00000057 => "\x57",
     0x00000058 => "\x58",
     0x00000059 => "\x59",
     0x0000005a => "\x5a",
     0x0000005b => "\x5b",
     0x0000005c => "\x5c",
     0x0000005d => "\x5d",
     0x0000005e => "\x5e",
     0x0000005f => "\x5f",
     0x00000060 => "\x60",
     0x00000061 => "\x61",
     0x00000062 => "\x62",
     0x00000063 => "\x63",
     0x00000064 => "\x64",
     0x00000065 => "\x65",
     0x00000066 => "\x66",
     0x00000067 => "\x67",
     0x00000068 => "\x68",
     0x00000069 => "\x69",
     0x0000006a => "\x6a",
     0x0000006b => "\x6b",
     0x0000006c => "\x6c",
     0x0000006d => "\x6d",
     0x0000006e => "\x6e",
     0x0000006f => "\x6f",
     0x00000070 => "\x70",
     0x00000071 => "\x71",
     0x00000072 => "\x72",
     0x00000073 => "\x73",
     0x00000074 => "\x74",
     0x00000075 => "\x75",
     0x00000076 => "\x76",
     0x00000077 => "\x77",
     0x00000078 => "\x78",
     0x00000079 => "\x79",
     0x0000007a => "\x7a",
     0x0000007b => "\x7b",
     0x0000007c => "\x7c",
     0x0000007d => "\x7d",
     0x0000007e => "\x7e",
     0x0000007f => "\x7f",
     0x000000a0 => "\xa0",
     0x000000a4 => "\xa4",
     0x000000a6 => "\xa6",
     0x000000a7 => "\xa7",
     0x000000a8 => "\xa8",
     0x000000a9 => "\xa9",
     0x000000ab => "\xab",
     0x000000ac => "\xac",
     0x000000ad => "\xad",
     0x000000ae => "\xae",
     0x000000b0 => "\xb0",
     0x000000b1 => "\xb1",
     0x000000b4 => "\xb4",
     0x000000b5 => "\xb5",
     0x000000b6 => "\xb6",
     0x000000b7 => "\xb7",
     0x000000b8 => "\xb8",
     0x000000bb => "\xbb",
     0x000000c1 => "\xc1",
     0x000000c2 => "\xc2",
     0x000000c4 => "\xc4",
     0x000000c7 => "\xc7",
     0x000000c9 => "\xc9",
     0x000000cb => "\xcb",
     0x000000cd => "\xcd",
     0x000000ce => "\xce",
     0x000000d3 => "\xd3",
     0x000000d4 => "\xd4",
     0x000000d6 => "\xd6",
     0x000000d7 => "\xd7",
     0x000000da => "\xda",
     0x000000dc => "\xdc",
     0x000000dd => "\xdd",
     0x000000df => "\xdf",
     0x000000e1 => "\xe1",
     0x000000e2 => "\xe2",
     0x000000e4 => "\xe4",
     0x000000e7 => "\xe7",
     0x000000e9 => "\xe9",
     0x000000eb => "\xeb",
     0x000000ed => "\xed",
     0x000000ee => "\xee",
     0x000000f3 => "\xf3",
     0x000000f4 => "\xf4",
     0x000000f6 => "\xf6",
     0x000000f7 => "\xf7",
     0x000000fa => "\xfa",
     0x000000fc => "\xfc",
     0x000000fd => "\xfd",
     0x00000102 => "\xc3",
     0x00000103 => "\xe3",
     0x00000104 => "\xa5",
     0x00000105 => "\xb9",
     0x00000106 => "\xc6",
     0x00000107 => "\xe6",
     0x0000010c => "\xc8",
     0x0000010d => "\xe8",
     0x0000010e => "\xcf",
     0x0000010f => "\xef",
     0x00000110 => "\xd0",
     0x00000111 => "\xf0",
     0x00000118 => "\xca",
     0x00000119 => "\xea",
     0x0000011a => "\xcc",
     0x0000011b => "\xec",
     0x00000139 => "\xc5",
     0x0000013a => "\xe5",
     0x0000013d => "\xbc",
     0x0000013e => "\xbe",
     0x00000141 => "\xa3",
     0x00000142 => "\xb3",
     0x00000143 => "\xd1",
     0x00000144 => "\xf1",
     0x00000147 => "\xd2",
     0x00000148 => "\xf2",
     0x00000150 => "\xd5",
     0x00000151 => "\xf5",
     0x00000154 => "\xc0",
     0x00000155 => "\xe0",
     0x00000158 => "\xd8",
     0x00000159 => "\xf8",
     0x0000015a => "\x8c",
     0x0000015b => "\x9c",
     0x0000015e => "\xaa",
     0x0000015f => "\xba",
     0x00000160 => "\x8a",
     0x00000161 => "\x9a",
     0x00000162 => "\xde",
     0x00000163 => "\xfe",
     0x00000164 => "\x8d",
     0x00000165 => "\x9d",
     0x0000016e => "\xd9",
     0x0000016f => "\xf9",
     0x00000170 => "\xdb",
     0x00000171 => "\xfb",
     0x00000179 => "\x8f",
     0x0000017a => "\x9f",
     0x0000017b => "\xaf",
     0x0000017c => "\xbf",
     0x0000017d => "\x8e",
     0x0000017e => "\x9e",
     0x000002c7 => "\xa1",
     0x000002d8 => "\xa2",
     0x000002d9 => "\xff",
     0x000002db => "\xb2",
     0x000002dd => "\xbd",
     0x00002013 => "\x96",
     0x00002014 => "\x97",
     0x00002018 => "\x91",
     0x00002019 => "\x92",
     0x0000201a => "\x82",
     0x0000201c => "\x93",
     0x0000201d => "\x94",
     0x0000201e => "\x84",
     0x00002020 => "\x86",
     0x00002021 => "\x87",
     0x00002022 => "\x95",
     0x00002026 => "\x85",
     0x00002030 => "\x89",
     0x00002039 => "\x8b",
     0x0000203a => "\x9b",
     0x000020ac => "\x80",
     0x00002122 => "\x99",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::CP1250 - Conversion routines for CP1250
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for CP1250.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
  repertoiremap: mnemonic,ds
   source: UNICODE 1.0
  alias MS-EE
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  00000004 | END OF TRANSMISSION (EOT)
     05 |  00000005 | ENQUIRY (ENQ)
     06 |  00000006 | ACKNOWLEDGE (ACK)
     07 |  00000007 | BELL (BEL)
     08 |  00000008 | BACKSPACE (BS)
     09 |  00000009 | CHARACTER TABULATION (HT)
     0A |  0000000A | LINE FEED (LF)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  00000014 | DEVICE CONTROL FOUR (DC4)
     15 |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     16 |  00000016 | SYNCHRONOUS IDLE (SYN)
     17 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  0000001A | SUBSTITUTE (SUB)
     1B |  0000001B | ESCAPE (ESC)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000020 | SPACE
     21 |  00000021 | EXCLAMATION MARK
     22 |  00000022 | QUOTATION MARK
     23 |  00000023 | NUMBER SIGN
     24 |  00000024 | DOLLAR SIGN
     25 |  00000025 | PERCENT SIGN
     26 |  00000026 | AMPERSAND
     27 |  00000027 | APOSTROPHE
     28 |  00000028 | LEFT PARENTHESIS
     29 |  00000029 | RIGHT PARENTHESIS
     2A |  0000002A | ASTERISK
     2B |  0000002B | PLUS SIGN
     2C |  0000002C | COMMA
     2D |  0000002D | HYPHEN-MINUS
     2E |  0000002E | FULL STOP
     2F |  0000002F | SOLIDUS
     30 |  00000030 | DIGIT ZERO
     31 |  00000031 | DIGIT ONE
     32 |  00000032 | DIGIT TWO
     33 |  00000033 | DIGIT THREE
     34 |  00000034 | DIGIT FOUR
     35 |  00000035 | DIGIT FIVE
     36 |  00000036 | DIGIT SIX
     37 |  00000037 | DIGIT SEVEN
     38 |  00000038 | DIGIT EIGHT
     39 |  00000039 | DIGIT NINE
     3A |  0000003A | COLON
     3B |  0000003B | SEMICOLON
     3C |  0000003C | LESS-THAN SIGN
     3D |  0000003D | EQUALS SIGN
     3E |  0000003E | GREATER-THAN SIGN
     3F |  0000003F | QUESTION MARK
     40 |  00000040 | COMMERCIAL AT
     41 |  00000041 | LATIN CAPITAL LETTER A
     42 |  00000042 | LATIN CAPITAL LETTER B
     43 |  00000043 | LATIN CAPITAL LETTER C
     44 |  00000044 | LATIN CAPITAL LETTER D
     45 |  00000045 | LATIN CAPITAL LETTER E
     46 |  00000046 | LATIN CAPITAL LETTER F
     47 |  00000047 | LATIN CAPITAL LETTER G
     48 |  00000048 | LATIN CAPITAL LETTER H
     49 |  00000049 | LATIN CAPITAL LETTER I
     4A |  0000004A | LATIN CAPITAL LETTER J
     4B |  0000004B | LATIN CAPITAL LETTER K
     4C |  0000004C | LATIN CAPITAL LETTER L
     4D |  0000004D | LATIN CAPITAL LETTER M
     4E |  0000004E | LATIN CAPITAL LETTER N
     4F |  0000004F | LATIN CAPITAL LETTER O
     50 |  00000050 | LATIN CAPITAL LETTER P
     51 |  00000051 | LATIN CAPITAL LETTER Q
     52 |  00000052 | LATIN CAPITAL LETTER R
     53 |  00000053 | LATIN CAPITAL LETTER S
     54 |  00000054 | LATIN CAPITAL LETTER T
     55 |  00000055 | LATIN CAPITAL LETTER U
     56 |  00000056 | LATIN CAPITAL LETTER V
     57 |  00000057 | LATIN CAPITAL LETTER W
     58 |  00000058 | LATIN CAPITAL LETTER X
     59 |  00000059 | LATIN CAPITAL LETTER Y
     5A |  0000005A | LATIN CAPITAL LETTER Z
     5B |  0000005B | LEFT SQUARE BRACKET
     5C |  0000005C | REVERSE SOLIDUS
     5D |  0000005D | RIGHT SQUARE BRACKET
     5E |  0000005E | CIRCUMFLEX ACCENT
     5F |  0000005F | LOW LINE
     60 |  00000060 | GRAVE ACCENT
     61 |  00000061 | LATIN SMALL LETTER A
     62 |  00000062 | LATIN SMALL LETTER B
     63 |  00000063 | LATIN SMALL LETTER C
     64 |  00000064 | LATIN SMALL LETTER D
     65 |  00000065 | LATIN SMALL LETTER E
     66 |  00000066 | LATIN SMALL LETTER F
     67 |  00000067 | LATIN SMALL LETTER G
     68 |  00000068 | LATIN SMALL LETTER H
     69 |  00000069 | LATIN SMALL LETTER I
     6A |  0000006A | LATIN SMALL LETTER J
     6B |  0000006B | LATIN SMALL LETTER K
     6C |  0000006C | LATIN SMALL LETTER L
     6D |  0000006D | LATIN SMALL LETTER M
     6E |  0000006E | LATIN SMALL LETTER N
     6F |  0000006F | LATIN SMALL LETTER O
     70 |  00000070 | LATIN SMALL LETTER P
     71 |  00000071 | LATIN SMALL LETTER Q
     72 |  00000072 | LATIN SMALL LETTER R
     73 |  00000073 | LATIN SMALL LETTER S
     74 |  00000074 | LATIN SMALL LETTER T
     75 |  00000075 | LATIN SMALL LETTER U
     76 |  00000076 | LATIN SMALL LETTER V
     77 |  00000077 | LATIN SMALL LETTER W
     78 |  00000078 | LATIN SMALL LETTER X
     79 |  00000079 | LATIN SMALL LETTER Y
     7A |  0000007A | LATIN SMALL LETTER Z
     7B |  0000007B | LEFT CURLY BRACKET
     7C |  0000007C | VERTICAL LINE
     7D |  0000007D | RIGHT CURLY BRACKET
     7E |  0000007E | TILDE
     7F |  0000007F | DELETE (DEL)
     80 |  000020AC | EURO SIGN
     82 |  0000201A | SINGLE LOW-9 QUOTATION MARK
     84 |  0000201E | DOUBLE LOW-9 QUOTATION MARK
     85 |  00002026 | HORIZONTAL ELLIPSIS
     86 |  00002020 | DAGGER
     87 |  00002021 | DOUBLE DAGGER
     89 |  00002030 | PER MILLE SIGN
     8A |  00000160 | LATIN CAPITAL LETTER S WITH CARON
     8B |  00002039 | SINGLE LEFT-POINTING ANGLE QUOTATION MARK
     8C |  0000015A | LATIN CAPITAL LETTER S WITH ACUTE
     8D |  00000164 | LATIN CAPITAL LETTER T WITH CARON
     8E |  0000017D | LATIN CAPITAL LETTER Z WITH CARON
     8F |  00000179 | LATIN CAPITAL LETTER Z WITH ACUTE
     91 |  00002018 | LEFT SINGLE QUOTATION MARK
     92 |  00002019 | RIGHT SINGLE QUOTATION MARK
     93 |  0000201C | LEFT DOUBLE QUOTATION MARK
     94 |  0000201D | RIGHT DOUBLE QUOTATION MARK
     95 |  00002022 | BULLET
     96 |  00002013 | EN DASH
     97 |  00002014 | EM DASH
     99 |  00002122 | TRADE MARK SIGN
     9A |  00000161 | LATIN SMALL LETTER S WITH CARON
     9B |  0000203A | SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
     9C |  0000015B | LATIN SMALL LETTER S WITH ACUTE
     9D |  00000165 | LATIN SMALL LETTER T WITH CARON
     9E |  0000017E | LATIN SMALL LETTER Z WITH CARON
     9F |  0000017A | LATIN SMALL LETTER Z WITH ACUTE
     A0 |  000000A0 | NO-BREAK SPACE
     A1 |  000002C7 | CARON (Mandarin Chinese third tone)
     A2 |  000002D8 | BREVE
     A3 |  00000141 | LATIN CAPITAL LETTER L WITH STROKE
     A4 |  000000A4 | CURRENCY SIGN
     A5 |  00000104 | LATIN CAPITAL LETTER A WITH OGONEK
     A6 |  000000A6 | BROKEN BAR
     A7 |  000000A7 | SECTION SIGN
     A8 |  000000A8 | DIAERESIS
     A9 |  000000A9 | COPYRIGHT SIGN
     AA |  0000015E | LATIN CAPITAL LETTER S WITH CEDILLA
     AB |  000000AB | LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
     AC |  000000AC | NOT SIGN
     AD |  000000AD | SOFT HYPHEN
     AE |  000000AE | REGISTERED SIGN
     AF |  0000017B | LATIN CAPITAL LETTER Z WITH DOT ABOVE
     B0 |  000000B0 | DEGREE SIGN
     B1 |  000000B1 | PLUS-MINUS SIGN
     B2 |  000002DB | OGONEK
     B3 |  00000142 | LATIN SMALL LETTER L WITH STROKE
     B4 |  000000B4 | ACUTE ACCENT
     B5 |  000000B5 | MICRO SIGN
     B6 |  000000B6 | PILCROW SIGN
     B7 |  000000B7 | MIDDLE DOT
     B8 |  000000B8 | CEDILLA
     B9 |  00000105 | LATIN SMALL LETTER A WITH OGONEK
     BA |  0000015F | LATIN SMALL LETTER S WITH CEDILLA
     BB |  000000BB | RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
     BC |  0000013D | LATIN CAPITAL LETTER L WITH CARON
     BD |  000002DD | DOUBLE ACUTE ACCENT
     BE |  0000013E | LATIN SMALL LETTER L WITH CARON
     BF |  0000017C | LATIN SMALL LETTER Z WITH DOT ABOVE
     C0 |  00000154 | LATIN CAPITAL LETTER R WITH ACUTE
     C1 |  000000C1 | LATIN CAPITAL LETTER A WITH ACUTE
     C2 |  000000C2 | LATIN CAPITAL LETTER A WITH CIRCUMFLEX
     C3 |  00000102 | LATIN CAPITAL LETTER A WITH BREVE
     C4 |  000000C4 | LATIN CAPITAL LETTER A WITH DIAERESIS
     C5 |  00000139 | LATIN CAPITAL LETTER L WITH ACUTE
     C6 |  00000106 | LATIN CAPITAL LETTER C WITH ACUTE
     C7 |  000000C7 | LATIN CAPITAL LETTER C WITH CEDILLA
     C8 |  0000010C | LATIN CAPITAL LETTER C WITH CARON
     C9 |  000000C9 | LATIN CAPITAL LETTER E WITH ACUTE
     CA |  00000118 | LATIN CAPITAL LETTER E WITH OGONEK
     CB |  000000CB | LATIN CAPITAL LETTER E WITH DIAERESIS
     CC |  0000011A | LATIN CAPITAL LETTER E WITH CARON
     CD |  000000CD | LATIN CAPITAL LETTER I WITH ACUTE
     CE |  000000CE | LATIN CAPITAL LETTER I WITH CIRCUMFLEX
     CF |  0000010E | LATIN CAPITAL LETTER D WITH CARON
     D0 |  00000110 | LATIN CAPITAL LETTER D WITH STROKE
     D1 |  00000143 | LATIN CAPITAL LETTER N WITH ACUTE
     D2 |  00000147 | LATIN CAPITAL LETTER N WITH CARON
     D3 |  000000D3 | LATIN CAPITAL LETTER O WITH ACUTE
     D4 |  000000D4 | LATIN CAPITAL LETTER O WITH CIRCUMFLEX
     D5 |  00000150 | LATIN CAPITAL LETTER O WITH DOUBLE ACUTE
     D6 |  000000D6 | LATIN CAPITAL LETTER O WITH DIAERESIS
     D7 |  000000D7 | MULTIPLICATION SIGN
     D8 |  00000158 | LATIN CAPITAL LETTER R WITH CARON
     D9 |  0000016E | LATIN CAPITAL LETTER U WITH RING ABOVE
     DA |  000000DA | LATIN CAPITAL LETTER U WITH ACUTE
     DB |  00000170 | LATIN CAPITAL LETTER U WITH DOUBLE ACUTE
     DC |  000000DC | LATIN CAPITAL LETTER U WITH DIAERESIS
     DD |  000000DD | LATIN CAPITAL LETTER Y WITH ACUTE
     DE |  00000162 | LATIN CAPITAL LETTER T WITH CEDILLA
     DF |  000000DF | LATIN SMALL LETTER SHARP S (German)
     E0 |  00000155 | LATIN SMALL LETTER R WITH ACUTE
     E1 |  000000E1 | LATIN SMALL LETTER A WITH ACUTE
     E2 |  000000E2 | LATIN SMALL LETTER A WITH CIRCUMFLEX
     E3 |  00000103 | LATIN SMALL LETTER A WITH BREVE
     E4 |  000000E4 | LATIN SMALL LETTER A WITH DIAERESIS
     E5 |  0000013A | LATIN SMALL LETTER L WITH ACUTE
     E6 |  00000107 | LATIN SMALL LETTER C WITH ACUTE
     E7 |  000000E7 | LATIN SMALL LETTER C WITH CEDILLA
     E8 |  0000010D | LATIN SMALL LETTER C WITH CARON
     E9 |  000000E9 | LATIN SMALL LETTER E WITH ACUTE
     EA |  00000119 | LATIN SMALL LETTER E WITH OGONEK
     EB |  000000EB | LATIN SMALL LETTER E WITH DIAERESIS
     EC |  0000011B | LATIN SMALL LETTER E WITH CARON
     ED |  000000ED | LATIN SMALL LETTER I WITH ACUTE
     EE |  000000EE | LATIN SMALL LETTER I WITH CIRCUMFLEX
     EF |  0000010F | LATIN SMALL LETTER D WITH CARON
     F0 |  00000111 | LATIN SMALL LETTER D WITH STROKE
     F1 |  00000144 | LATIN SMALL LETTER N WITH ACUTE
     F2 |  00000148 | LATIN SMALL LETTER N WITH CARON
     F3 |  000000F3 | LATIN SMALL LETTER O WITH ACUTE
     F4 |  000000F4 | LATIN SMALL LETTER O WITH CIRCUMFLEX
     F5 |  00000151 | LATIN SMALL LETTER O WITH DOUBLE ACUTE
     F6 |  000000F6 | LATIN SMALL LETTER O WITH DIAERESIS
     F7 |  000000F7 | DIVISION SIGN
     F8 |  00000159 | LATIN SMALL LETTER R WITH CARON
     F9 |  0000016F | LATIN SMALL LETTER U WITH RING ABOVE
     FA |  000000FA | LATIN SMALL LETTER U WITH ACUTE
     FB |  00000171 | LATIN SMALL LETTER U WITH DOUBLE ACUTE
     FC |  000000FC | LATIN SMALL LETTER U WITH DIAERESIS
     FD |  000000FD | LATIN SMALL LETTER Y WITH ACUTE
     FE |  00000163 | LATIN SMALL LETTER T WITH CEDILLA
     FF |  000002D9 | DOT ABOVE (Mandarin Chinese light tone)
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/CP1251.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for CP1251.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::CP1251;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x0004,
     0x0005,
     0x0006,
     0x0007,
     0x0008,
     0x0009,
     0x000a,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x0014,
     0x0015,
     0x0016,
     0x0017,
     0x0018,
     0x0019,
     0x001a,
     0x001b,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0020,
     0x0021,
     0x0022,
     0x0023,
     0x0024,
     0x0025,
     0x0026,
     0x0027,
     0x0028,
     0x0029,
     0x002a,
     0x002b,
     0x002c,
     0x002d,
     0x002e,
     0x002f,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x003a,
     0x003b,
     0x003c,
     0x003d,
     0x003e,
     0x003f,
     0x0040,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x005b,
     0x005c,
     0x005d,
     0x005e,
     0x005f,
     0x0060,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x007b,
     0x007c,
     0x007d,
     0x007e,
     0x007f,
     0x0402,
     0x0403,
     0x201a,
     0x0453,
     0x201e,
     0x2026,
     0x2020,
     0x2021,
     0x20ac,
     0x2030,
     0x0409,
     0x2039,
     0x040a,
     0x040c,
     0x040b,
     0x040f,
     0x0452,
     0x2018,
     0x2019,
     0x201c,
     0x201d,
     0x2022,
     0x2013,
     0x2014,
     0xfffd,
     0x2122,
     0x0459,
     0x203a,
     0x045a,
     0x045c,
     0x045b,
     0x045f,
     0x00a0,
     0x040e,
     0x045e,
     0x0408,
     0x00a4,
     0x0490,
     0x00a6,
     0x00a7,
     0x0401,
     0x00a9,
     0x0404,
     0x00ab,
     0x00ac,
     0x00ad,
     0x00ae,
     0x0407,
     0x00b0,
     0x00b1,
     0x0406,
     0x0456,
     0x0491,
     0x00b5,
     0x00b6,
     0x00b7,
     0x0451,
     0x2116,
     0x0454,
     0x00bb,
     0x0458,
     0x0405,
     0x0455,
     0x0457,
     0x0410,
     0x0411,
     0x0412,
     0x0413,
     0x0414,
     0x0415,
     0x0416,
     0x0417,
     0x0418,
     0x0419,
     0x041a,
     0x041b,
     0x041c,
     0x041d,
     0x041e,
     0x041f,
     0x0420,
     0x0421,
     0x0422,
     0x0423,
     0x0424,
     0x0425,
     0x0426,
     0x0427,
     0x0428,
     0x0429,
     0x042a,
     0x042b,
     0x042c,
     0x042d,
     0x042e,
     0x042f,
     0x0430,
     0x0431,
     0x0432,
     0x0433,
     0x0434,
     0x0435,
     0x0436,
     0x0437,
     0x0438,
     0x0439,
     0x043a,
     0x043b,
     0x043c,
     0x043d,
     0x043e,
     0x043f,
     0x0440,
     0x0441,
     0x0442,
     0x0443,
     0x0444,
     0x0445,
     0x0446,
     0x0447,
     0x0448,
     0x0449,
     0x044a,
     0x044b,
     0x044c,
     0x044d,
     0x044e,
     0x044f,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\x04",
     "\x05",
     "\x06",
     "\x07",
     "\x08",
     "\x09",
     "\x0a",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\x14",
     "\x15",
     "\x16",
     "\x17",
     "\x18",
     "\x19",
     "\x1a",
     "\x1b",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\x20",
     "\x21",
     "\x22",
     "\x23",
     "\x24",
     "\x25",
     "\x26",
     "\x27",
     "\x28",
     "\x29",
     "\x2a",
     "\x2b",
     "\x2c",
     "\x2d",
     "\x2e",
     "\x2f",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\x3a",
     "\x3b",
     "\x3c",
     "\x3d",
     "\x3e",
     "\x3f",
     "\x40",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\x5b",
     "\x5c",
     "\x5d",
     "\x5e",
     "\x5f",
     "\x60",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\x7b",
     "\x7c",
     "\x7d",
     "\x7e",
     "\x7f",
     "\xd0\x82",
     "\xd0\x83",
     "\xe2\x80\x9a",
     "\xd1\x93",
     "\xe2\x80\x9e",
     "\xe2\x80\xa6",
     "\xe2\x80\xa0",
     "\xe2\x80\xa1",
     "\xe2\x82\xac",
     "\xe2\x80\xb0",
     "\xd0\x89",
     "\xe2\x80\xb9",
     "\xd0\x8a",
     "\xd0\x8c",
     "\xd0\x8b",
     "\xd0\x8f",
     "\xd1\x92",
     "\xe2\x80\x98",
     "\xe2\x80\x99",
     "\xe2\x80\x9c",
     "\xe2\x80\x9d",
     "\xe2\x80\xa2",
     "\xe2\x80\x93",
     "\xe2\x80\x94",
     "\xef\xbf\xbd",
     "\xe2\x84\xa2",
     "\xd1\x99",
     "\xe2\x80\xba",
     "\xd1\x9a",
     "\xd1\x9c",
     "\xd1\x9b",
     "\xd1\x9f",
     "\xc2\xa0",
     "\xd0\x8e",
     "\xd1\x9e",
     "\xd0\x88",
     "\xc2\xa4",
     "\xd2\x90",
     "\xc2\xa6",
     "\xc2\xa7",
     "\xd0\x81",
     "\xc2\xa9",
     "\xd0\x84",
     "\xc2\xab",
     "\xc2\xac",
     "\xc2\xad",
     "\xc2\xae",
     "\xd0\x87",
     "\xc2\xb0",
     "\xc2\xb1",
     "\xd0\x86",
     "\xd1\x96",
     "\xd2\x91",
     "\xc2\xb5",
     "\xc2\xb6",
     "\xc2\xb7",
     "\xd1\x91",
     "\xe2\x84\x96",
     "\xd1\x94",
     "\xc2\xbb",
     "\xd1\x98",
     "\xd0\x85",
     "\xd1\x95",
     "\xd1\x97",
     "\xd0\x90",
     "\xd0\x91",
     "\xd0\x92",
     "\xd0\x93",
     "\xd0\x94",
     "\xd0\x95",
     "\xd0\x96",
     "\xd0\x97",
     "\xd0\x98",
     "\xd0\x99",
     "\xd0\x9a",
     "\xd0\x9b",
     "\xd0\x9c",
     "\xd0\x9d",
     "\xd0\x9e",
     "\xd0\x9f",
     "\xd0\xa0",
     "\xd0\xa1",
     "\xd0\xa2",
     "\xd0\xa3",
     "\xd0\xa4",
     "\xd0\xa5",
     "\xd0\xa6",
     "\xd0\xa7",
     "\xd0\xa8",
     "\xd0\xa9",
     "\xd0\xaa",
     "\xd0\xab",
     "\xd0\xac",
     "\xd0\xad",
     "\xd0\xae",
     "\xd0\xaf",
     "\xd0\xb0",
     "\xd0\xb1",
     "\xd0\xb2",
     "\xd0\xb3",
     "\xd0\xb4",
     "\xd0\xb5",
     "\xd0\xb6",
     "\xd0\xb7",
     "\xd0\xb8",
     "\xd0\xb9",
     "\xd0\xba",
     "\xd0\xbb",
     "\xd0\xbc",
     "\xd0\xbd",
     "\xd0\xbe",
     "\xd0\xbf",
     "\xd1\x80",
     "\xd1\x81",
     "\xd1\x82",
     "\xd1\x83",
     "\xd1\x84",
     "\xd1\x85",
     "\xd1\x86",
     "\xd1\x87",
     "\xd1\x88",
     "\xd1\x89",
     "\xd1\x8a",
     "\xd1\x8b",
     "\xd1\x8c",
     "\xd1\x8d",
     "\xd1\x8e",
     "\xd1\x8f",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x04",
     0x00000005 => "\x05",
     0x00000006 => "\x06",
     0x00000007 => "\x07",
     0x00000008 => "\x08",
     0x00000009 => "\x09",
     0x0000000a => "\x0a",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x14",
     0x00000015 => "\x15",
     0x00000016 => "\x16",
     0x00000017 => "\x17",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x1a",
     0x0000001b => "\x1b",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x20",
     0x00000021 => "\x21",
     0x00000022 => "\x22",
     0x00000023 => "\x23",
     0x00000024 => "\x24",
     0x00000025 => "\x25",
     0x00000026 => "\x26",
     0x00000027 => "\x27",
     0x00000028 => "\x28",
     0x00000029 => "\x29",
     0x0000002a => "\x2a",
     0x0000002b => "\x2b",
     0x0000002c => "\x2c",
     0x0000002d => "\x2d",
     0x0000002e => "\x2e",
     0x0000002f => "\x2f",
     0x00000030 => "\x30",
     0x00000031 => "\x31",
     0x00000032 => "\x32",
     0x00000033 => "\x33",
     0x00000034 => "\x34",
     0x00000035 => "\x35",
     0x00000036 => "\x36",
     0x00000037 => "\x37",
     0x00000038 => "\x38",
     0x00000039 => "\x39",
     0x0000003a => "\x3a",
     0x0000003b => "\x3b",
     0x0000003c => "\x3c",
     0x0000003d => "\x3d",
     0x0000003e => "\x3e",
     0x0000003f => "\x3f",
     0x00000040 => "\x40",
     0x00000041 => "\x41",
     0x00000042 => "\x42",
     0x00000043 => "\x43",
     0x00000044 => "\x44",
     0x00000045 => "\x45",
     0x00000046 => "\x46",
     0x00000047 => "\x47",
     0x00000048 => "\x48",
     0x00000049 => "\x49",
     0x0000004a => "\x4a",
     0x0000004b => "\x4b",
     0x0000004c => "\x4c",
     0x0000004d => "\x4d",
     0x0000004e => "\x4e",
     0x0000004f => "\x4f",
     0x00000050 => "\x50",
     0x00000051 => "\x51",
     0x00000052 => "\x52",
     0x00000053 => "\x53",
     0x00000054 => "\x54",
     0x00000055 => "\x55",
     0x00000056 => "\x56",
     0x00000057 => "\x57",
     0x00000058 => "\x58",
     0x00000059 => "\x59",
     0x0000005a => "\x5a",
     0x0000005b => "\x5b",
     0x0000005c => "\x5c",
     0x0000005d => "\x5d",
     0x0000005e => "\x5e",
     0x0000005f => "\x5f",
     0x00000060 => "\x60",
     0x00000061 => "\x61",
     0x00000062 => "\x62",
     0x00000063 => "\x63",
     0x00000064 => "\x64",
     0x00000065 => "\x65",
     0x00000066 => "\x66",
     0x00000067 => "\x67",
     0x00000068 => "\x68",
     0x00000069 => "\x69",
     0x0000006a => "\x6a",
     0x0000006b => "\x6b",
     0x0000006c => "\x6c",
     0x0000006d => "\x6d",
     0x0000006e => "\x6e",
     0x0000006f => "\x6f",
     0x00000070 => "\x70",
     0x00000071 => "\x71",
     0x00000072 => "\x72",
     0x00000073 => "\x73",
     0x00000074 => "\x74",
     0x00000075 => "\x75",
     0x00000076 => "\x76",
     0x00000077 => "\x77",
     0x00000078 => "\x78",
     0x00000079 => "\x79",
     0x0000007a => "\x7a",
     0x0000007b => "\x7b",
     0x0000007c => "\x7c",
     0x0000007d => "\x7d",
     0x0000007e => "\x7e",
     0x0000007f => "\x7f",
     0x000000a0 => "\xa0",
     0x000000a4 => "\xa4",
     0x000000a6 => "\xa6",
     0x000000a7 => "\xa7",
     0x000000a9 => "\xa9",
     0x000000ab => "\xab",
     0x000000ac => "\xac",
     0x000000ad => "\xad",
     0x000000ae => "\xae",
     0x000000b0 => "\xb0",
     0x000000b1 => "\xb1",
     0x000000b5 => "\xb5",
     0x000000b6 => "\xb6",
     0x000000b7 => "\xb7",
     0x000000bb => "\xbb",
     0x00000401 => "\xa8",
     0x00000402 => "\x80",
     0x00000403 => "\x81",
     0x00000404 => "\xaa",
     0x00000405 => "\xbd",
     0x00000406 => "\xb2",
     0x00000407 => "\xaf",
     0x00000408 => "\xa3",
     0x00000409 => "\x8a",
     0x0000040a => "\x8c",
     0x0000040b => "\x8e",
     0x0000040c => "\x8d",
     0x0000040e => "\xa1",
     0x0000040f => "\x8f",
     0x00000410 => "\xc0",
     0x00000411 => "\xc1",
     0x00000412 => "\xc2",
     0x00000413 => "\xc3",
     0x00000414 => "\xc4",
     0x00000415 => "\xc5",
     0x00000416 => "\xc6",
     0x00000417 => "\xc7",
     0x00000418 => "\xc8",
     0x00000419 => "\xc9",
     0x0000041a => "\xca",
     0x0000041b => "\xcb",
     0x0000041c => "\xcc",
     0x0000041d => "\xcd",
     0x0000041e => "\xce",
     0x0000041f => "\xcf",
     0x00000420 => "\xd0",
     0x00000421 => "\xd1",
     0x00000422 => "\xd2",
     0x00000423 => "\xd3",
     0x00000424 => "\xd4",
     0x00000425 => "\xd5",
     0x00000426 => "\xd6",
     0x00000427 => "\xd7",
     0x00000428 => "\xd8",
     0x00000429 => "\xd9",
     0x0000042a => "\xda",
     0x0000042b => "\xdb",
     0x0000042c => "\xdc",
     0x0000042d => "\xdd",
     0x0000042e => "\xde",
     0x0000042f => "\xdf",
     0x00000430 => "\xe0",
     0x00000431 => "\xe1",
     0x00000432 => "\xe2",
     0x00000433 => "\xe3",
     0x00000434 => "\xe4",
     0x00000435 => "\xe5",
     0x00000436 => "\xe6",
     0x00000437 => "\xe7",
     0x00000438 => "\xe8",
     0x00000439 => "\xe9",
     0x0000043a => "\xea",
     0x0000043b => "\xeb",
     0x0000043c => "\xec",
     0x0000043d => "\xed",
     0x0000043e => "\xee",
     0x0000043f => "\xef",
     0x00000440 => "\xf0",
     0x00000441 => "\xf1",
     0x00000442 => "\xf2",
     0x00000443 => "\xf3",
     0x00000444 => "\xf4",
     0x00000445 => "\xf5",
     0x00000446 => "\xf6",
     0x00000447 => "\xf7",
     0x00000448 => "\xf8",
     0x00000449 => "\xf9",
     0x0000044a => "\xfa",
     0x0000044b => "\xfb",
     0x0000044c => "\xfc",
     0x0000044d => "\xfd",
     0x0000044e => "\xfe",
     0x0000044f => "\xff",
     0x00000451 => "\xb8",
     0x00000452 => "\x90",
     0x00000453 => "\x83",
     0x00000454 => "\xba",
     0x00000455 => "\xbe",
     0x00000456 => "\xb3",
     0x00000457 => "\xbf",
     0x00000458 => "\xbc",
     0x00000459 => "\x9a",
     0x0000045a => "\x9c",
     0x0000045b => "\x9e",
     0x0000045c => "\x9d",
     0x0000045e => "\xa2",
     0x0000045f => "\x9f",
     0x00000490 => "\xa5",
     0x00000491 => "\xb4",
     0x00002013 => "\x96",
     0x00002014 => "\x97",
     0x00002018 => "\x91",
     0x00002019 => "\x92",
     0x0000201a => "\x82",
     0x0000201c => "\x93",
     0x0000201d => "\x94",
     0x0000201e => "\x84",
     0x00002020 => "\x86",
     0x00002021 => "\x87",
     0x00002022 => "\x95",
     0x00002026 => "\x85",
     0x00002030 => "\x89",
     0x00002039 => "\x8b",
     0x0000203a => "\x9b",
     0x000020ac => "\x88",
     0x00002116 => "\xb9",
     0x00002122 => "\x99",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::CP1251 - Conversion routines for CP1251
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for CP1251.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
  repertoiremap: mnemonic,ds
   source: UNICODE 1.0
  alias MS-CYRL
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  00000004 | END OF TRANSMISSION (EOT)
     05 |  00000005 | ENQUIRY (ENQ)
     06 |  00000006 | ACKNOWLEDGE (ACK)
     07 |  00000007 | BELL (BEL)
     08 |  00000008 | BACKSPACE (BS)
     09 |  00000009 | CHARACTER TABULATION (HT)
     0A |  0000000A | LINE FEED (LF)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  00000014 | DEVICE CONTROL FOUR (DC4)
     15 |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     16 |  00000016 | SYNCHRONOUS IDLE (SYN)
     17 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  0000001A | SUBSTITUTE (SUB)
     1B |  0000001B | ESCAPE (ESC)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000020 | SPACE
     21 |  00000021 | EXCLAMATION MARK
     22 |  00000022 | QUOTATION MARK
     23 |  00000023 | NUMBER SIGN
     24 |  00000024 | DOLLAR SIGN
     25 |  00000025 | PERCENT SIGN
     26 |  00000026 | AMPERSAND
     27 |  00000027 | APOSTROPHE
     28 |  00000028 | LEFT PARENTHESIS
     29 |  00000029 | RIGHT PARENTHESIS
     2A |  0000002A | ASTERISK
     2B |  0000002B | PLUS SIGN
     2C |  0000002C | COMMA
     2D |  0000002D | HYPHEN-MINUS
     2E |  0000002E | FULL STOP
     2F |  0000002F | SOLIDUS
     30 |  00000030 | DIGIT ZERO
     31 |  00000031 | DIGIT ONE
     32 |  00000032 | DIGIT TWO
     33 |  00000033 | DIGIT THREE
     34 |  00000034 | DIGIT FOUR
     35 |  00000035 | DIGIT FIVE
     36 |  00000036 | DIGIT SIX
     37 |  00000037 | DIGIT SEVEN
     38 |  00000038 | DIGIT EIGHT
     39 |  00000039 | DIGIT NINE
     3A |  0000003A | COLON
     3B |  0000003B | SEMICOLON
     3C |  0000003C | LESS-THAN SIGN
     3D |  0000003D | EQUALS SIGN
     3E |  0000003E | GREATER-THAN SIGN
     3F |  0000003F | QUESTION MARK
     40 |  00000040 | COMMERCIAL AT
     41 |  00000041 | LATIN CAPITAL LETTER A
     42 |  00000042 | LATIN CAPITAL LETTER B
     43 |  00000043 | LATIN CAPITAL LETTER C
     44 |  00000044 | LATIN CAPITAL LETTER D
     45 |  00000045 | LATIN CAPITAL LETTER E
     46 |  00000046 | LATIN CAPITAL LETTER F
     47 |  00000047 | LATIN CAPITAL LETTER G
     48 |  00000048 | LATIN CAPITAL LETTER H
     49 |  00000049 | LATIN CAPITAL LETTER I
     4A |  0000004A | LATIN CAPITAL LETTER J
     4B |  0000004B | LATIN CAPITAL LETTER K
     4C |  0000004C | LATIN CAPITAL LETTER L
     4D |  0000004D | LATIN CAPITAL LETTER M
     4E |  0000004E | LATIN CAPITAL LETTER N
     4F |  0000004F | LATIN CAPITAL LETTER O
     50 |  00000050 | LATIN CAPITAL LETTER P
     51 |  00000051 | LATIN CAPITAL LETTER Q
     52 |  00000052 | LATIN CAPITAL LETTER R
     53 |  00000053 | LATIN CAPITAL LETTER S
     54 |  00000054 | LATIN CAPITAL LETTER T
     55 |  00000055 | LATIN CAPITAL LETTER U
     56 |  00000056 | LATIN CAPITAL LETTER V
     57 |  00000057 | LATIN CAPITAL LETTER W
     58 |  00000058 | LATIN CAPITAL LETTER X
     59 |  00000059 | LATIN CAPITAL LETTER Y
     5A |  0000005A | LATIN CAPITAL LETTER Z
     5B |  0000005B | LEFT SQUARE BRACKET
     5C |  0000005C | REVERSE SOLIDUS
     5D |  0000005D | RIGHT SQUARE BRACKET
     5E |  0000005E | CIRCUMFLEX ACCENT
     5F |  0000005F | LOW LINE
     60 |  00000060 | GRAVE ACCENT
     61 |  00000061 | LATIN SMALL LETTER A
     62 |  00000062 | LATIN SMALL LETTER B
     63 |  00000063 | LATIN SMALL LETTER C
     64 |  00000064 | LATIN SMALL LETTER D
     65 |  00000065 | LATIN SMALL LETTER E
     66 |  00000066 | LATIN SMALL LETTER F
     67 |  00000067 | LATIN SMALL LETTER G
     68 |  00000068 | LATIN SMALL LETTER H
     69 |  00000069 | LATIN SMALL LETTER I
     6A |  0000006A | LATIN SMALL LETTER J
     6B |  0000006B | LATIN SMALL LETTER K
     6C |  0000006C | LATIN SMALL LETTER L
     6D |  0000006D | LATIN SMALL LETTER M
     6E |  0000006E | LATIN SMALL LETTER N
     6F |  0000006F | LATIN SMALL LETTER O
     70 |  00000070 | LATIN SMALL LETTER P
     71 |  00000071 | LATIN SMALL LETTER Q
     72 |  00000072 | LATIN SMALL LETTER R
     73 |  00000073 | LATIN SMALL LETTER S
     74 |  00000074 | LATIN SMALL LETTER T
     75 |  00000075 | LATIN SMALL LETTER U
     76 |  00000076 | LATIN SMALL LETTER V
     77 |  00000077 | LATIN SMALL LETTER W
     78 |  00000078 | LATIN SMALL LETTER X
     79 |  00000079 | LATIN SMALL LETTER Y
     7A |  0000007A | LATIN SMALL LETTER Z
     7B |  0000007B | LEFT CURLY BRACKET
     7C |  0000007C | VERTICAL LINE
     7D |  0000007D | RIGHT CURLY BRACKET
     7E |  0000007E | TILDE
     7F |  0000007F | DELETE (DEL)
     80 |  00000402 | CYRILLIC CAPITAL LETTER DJE (Serbocroatian)
     81 |  00000403 | CYRILLIC CAPITAL LETTER GJE
     82 |  0000201A | SINGLE LOW-9 QUOTATION MARK
     83 |  00000453 | CYRILLIC SMALL LETTER GJE
     84 |  0000201E | DOUBLE LOW-9 QUOTATION MARK
     85 |  00002026 | HORIZONTAL ELLIPSIS
     86 |  00002020 | DAGGER
     87 |  00002021 | DOUBLE DAGGER
     88 |  000020AC | EURO SIGN
     89 |  00002030 | PER MILLE SIGN
     8A |  00000409 | CYRILLIC CAPITAL LETTER LJE
     8B |  00002039 | SINGLE LEFT-POINTING ANGLE QUOTATION MARK
     8C |  0000040A | CYRILLIC CAPITAL LETTER NJE
     8D |  0000040C | CYRILLIC CAPITAL LETTER KJE
     8E |  0000040B | CYRILLIC CAPITAL LETTER TSHE (Serbocroatian)
     8F |  0000040F | CYRILLIC CAPITAL LETTER DZHE
     90 |  00000452 | CYRILLIC SMALL LETTER DJE (Serbocroatian)
     91 |  00002018 | LEFT SINGLE QUOTATION MARK
     92 |  00002019 | RIGHT SINGLE QUOTATION MARK
     93 |  0000201C | LEFT DOUBLE QUOTATION MARK
     94 |  0000201D | RIGHT DOUBLE QUOTATION MARK
     95 |  00002022 | BULLET
     96 |  00002013 | EN DASH
     97 |  00002014 | EM DASH
     99 |  00002122 | TRADE MARK SIGN
     9A |  00000459 | CYRILLIC SMALL LETTER LJE
     9B |  0000203A | SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
     9C |  0000045A | CYRILLIC SMALL LETTER NJE
     9D |  0000045C | CYRILLIC SMALL LETTER KJE
     9E |  0000045B | CYRILLIC SMALL LETTER TSHE (Serbocroatian)
     9F |  0000045F | CYRILLIC SMALL LETTER DZHE
     A0 |  000000A0 | NO-BREAK SPACE
     A1 |  0000040E | CYRILLIC CAPITAL LETTER SHORT U (Byelorussian)
     A2 |  0000045E | CYRILLIC SMALL LETTER SHORT U (Byelorussian)
     A3 |  00000408 | CYRILLIC CAPITAL LETTER JE
     A4 |  000000A4 | CURRENCY SIGN
     A5 |  00000490 | CYRILLIC CAPITAL LETTER GHE WITH UPTURN
     A6 |  000000A6 | BROKEN BAR
     A7 |  000000A7 | SECTION SIGN
     A8 |  00000401 | CYRILLIC CAPITAL LETTER IO
     A9 |  000000A9 | COPYRIGHT SIGN
     AA |  00000404 | CYRILLIC CAPITAL LETTER UKRAINIAN IE
     AB |  000000AB | LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
     AC |  000000AC | NOT SIGN
     AD |  000000AD | SOFT HYPHEN
     AE |  000000AE | REGISTERED SIGN
     AF |  00000407 | CYRILLIC CAPITAL LETTER YI (Ukrainian)
     B0 |  000000B0 | DEGREE SIGN
     B1 |  000000B1 | PLUS-MINUS SIGN
     B2 |  00000406 | CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I
     B3 |  00000456 | CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I
     B4 |  00000491 | CYRILLIC SMALL LETTER GHE WITH UPTURN
     B5 |  000000B5 | MICRO SIGN
     B6 |  000000B6 | PILCROW SIGN
     B7 |  000000B7 | MIDDLE DOT
     B8 |  00000451 | CYRILLIC SMALL LETTER IO
     B9 |  00002116 | NUMERO SIGN
     BA |  00000454 | CYRILLIC SMALL LETTER UKRAINIAN IE
     BB |  000000BB | RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
     BC |  00000458 | CYRILLIC SMALL LETTER JE
     BD |  00000405 | CYRILLIC CAPITAL LETTER DZE
     BE |  00000455 | CYRILLIC SMALL LETTER DZE
     BF |  00000457 | CYRILLIC SMALL LETTER YI (Ukrainian)
     C0 |  00000410 | CYRILLIC CAPITAL LETTER A
     C1 |  00000411 | CYRILLIC CAPITAL LETTER BE
     C2 |  00000412 | CYRILLIC CAPITAL LETTER VE
     C3 |  00000413 | CYRILLIC CAPITAL LETTER GHE
     C4 |  00000414 | CYRILLIC CAPITAL LETTER DE
     C5 |  00000415 | CYRILLIC CAPITAL LETTER IE
     C6 |  00000416 | CYRILLIC CAPITAL LETTER ZHE
     C7 |  00000417 | CYRILLIC CAPITAL LETTER ZE
     C8 |  00000418 | CYRILLIC CAPITAL LETTER I
     C9 |  00000419 | CYRILLIC CAPITAL LETTER SHORT I
     CA |  0000041A | CYRILLIC CAPITAL LETTER KA
     CB |  0000041B | CYRILLIC CAPITAL LETTER EL
     CC |  0000041C | CYRILLIC CAPITAL LETTER EM
     CD |  0000041D | CYRILLIC CAPITAL LETTER EN
     CE |  0000041E | CYRILLIC CAPITAL LETTER O
     CF |  0000041F | CYRILLIC CAPITAL LETTER PE
     D0 |  00000420 | CYRILLIC CAPITAL LETTER ER
     D1 |  00000421 | CYRILLIC CAPITAL LETTER ES
     D2 |  00000422 | CYRILLIC CAPITAL LETTER TE
     D3 |  00000423 | CYRILLIC CAPITAL LETTER U
     D4 |  00000424 | CYRILLIC CAPITAL LETTER EF
     D5 |  00000425 | CYRILLIC CAPITAL LETTER HA
     D6 |  00000426 | CYRILLIC CAPITAL LETTER TSE
     D7 |  00000427 | CYRILLIC CAPITAL LETTER CHE
     D8 |  00000428 | CYRILLIC CAPITAL LETTER SHA
     D9 |  00000429 | CYRILLIC CAPITAL LETTER SHCHA
     DA |  0000042A | CYRILLIC CAPITAL LETTER HARD SIGN
     DB |  0000042B | CYRILLIC CAPITAL LETTER YERU
     DC |  0000042C | CYRILLIC CAPITAL LETTER SOFT SIGN
     DD |  0000042D | CYRILLIC CAPITAL LETTER E
     DE |  0000042E | CYRILLIC CAPITAL LETTER YU
     DF |  0000042F | CYRILLIC CAPITAL LETTER YA
     E0 |  00000430 | CYRILLIC SMALL LETTER A
     E1 |  00000431 | CYRILLIC SMALL LETTER BE
     E2 |  00000432 | CYRILLIC SMALL LETTER VE
     E3 |  00000433 | CYRILLIC SMALL LETTER GHE
     E4 |  00000434 | CYRILLIC SMALL LETTER DE
     E5 |  00000435 | CYRILLIC SMALL LETTER IE
     E6 |  00000436 | CYRILLIC SMALL LETTER ZHE
     E7 |  00000437 | CYRILLIC SMALL LETTER ZE
     E8 |  00000438 | CYRILLIC SMALL LETTER I
     E9 |  00000439 | CYRILLIC SMALL LETTER SHORT I
     EA |  0000043A | CYRILLIC SMALL LETTER KA
     EB |  0000043B | CYRILLIC SMALL LETTER EL
     EC |  0000043C | CYRILLIC SMALL LETTER EM
     ED |  0000043D | CYRILLIC SMALL LETTER EN
     EE |  0000043E | CYRILLIC SMALL LETTER O
     EF |  0000043F | CYRILLIC SMALL LETTER PE
     F0 |  00000440 | CYRILLIC SMALL LETTER ER
     F1 |  00000441 | CYRILLIC SMALL LETTER ES
     F2 |  00000442 | CYRILLIC SMALL LETTER TE
     F3 |  00000443 | CYRILLIC SMALL LETTER U
     F4 |  00000444 | CYRILLIC SMALL LETTER EF
     F5 |  00000445 | CYRILLIC SMALL LETTER HA
     F6 |  00000446 | CYRILLIC SMALL LETTER TSE
     F7 |  00000447 | CYRILLIC SMALL LETTER CHE
     F8 |  00000448 | CYRILLIC SMALL LETTER SHA
     F9 |  00000449 | CYRILLIC SMALL LETTER SHCHA
     FA |  0000044A | CYRILLIC SMALL LETTER HARD SIGN
     FB |  0000044B | CYRILLIC SMALL LETTER YERU
     FC |  0000044C | CYRILLIC SMALL LETTER SOFT SIGN
     FD |  0000044D | CYRILLIC SMALL LETTER E
     FE |  0000044E | CYRILLIC SMALL LETTER YU
     FF |  0000044F | CYRILLIC SMALL LETTER YA
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/CP1252.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for CP1252.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::CP1252;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x0004,
     0x0005,
     0x0006,
     0x0007,
     0x0008,
     0x0009,
     0x000a,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x0014,
     0x0015,
     0x0016,
     0x0017,
     0x0018,
     0x0019,
     0x001a,
     0x001b,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0020,
     0x0021,
     0x0022,
     0x0023,
     0x0024,
     0x0025,
     0x0026,
     0x0027,
     0x0028,
     0x0029,
     0x002a,
     0x002b,
     0x002c,
     0x002d,
     0x002e,
     0x002f,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x003a,
     0x003b,
     0x003c,
     0x003d,
     0x003e,
     0x003f,
     0x0040,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x005b,
     0x005c,
     0x005d,
     0x005e,
     0x005f,
     0x0060,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x007b,
     0x007c,
     0x007d,
     0x007e,
     0x007f,
     0x20ac,
     0xfffd,
     0x201a,
     0x0192,
     0x201e,
     0x2026,
     0x2020,
     0x2021,
     0x02c6,
     0x2030,
     0x0160,
     0x2039,
     0x0152,
     0xfffd,
     0x017d,
     0xfffd,
     0xfffd,
     0x2018,
     0x2019,
     0x201c,
     0x201d,
     0x2022,
     0x2013,
     0x2014,
     0x02dc,
     0x2122,
     0x0161,
     0x203a,
     0x0153,
     0xfffd,
     0x017e,
     0x0178,
     0x00a0,
     0x00a1,
     0x00a2,
     0x00a3,
     0x00a4,
     0x00a5,
     0x00a6,
     0x00a7,
     0x00a8,
     0x00a9,
     0x00aa,
     0x00ab,
     0x00ac,
     0x00ad,
     0x00ae,
     0x00af,
     0x00b0,
     0x00b1,
     0x00b2,
     0x00b3,
     0x00b4,
     0x00b5,
     0x00b6,
     0x00b7,
     0x00b8,
     0x00b9,
     0x00ba,
     0x00bb,
     0x00bc,
     0x00bd,
     0x00be,
     0x00bf,
     0x00c0,
     0x00c1,
     0x00c2,
     0x00c3,
     0x00c4,
     0x00c5,
     0x00c6,
     0x00c7,
     0x00c8,
     0x00c9,
     0x00ca,
     0x00cb,
     0x00cc,
     0x00cd,
     0x00ce,
     0x00cf,
     0x00d0,
     0x00d1,
     0x00d2,
     0x00d3,
     0x00d4,
     0x00d5,
     0x00d6,
     0x00d7,
     0x00d8,
     0x00d9,
     0x00da,
     0x00db,
     0x00dc,
     0x00dd,
     0x00de,
     0x00df,
     0x00e0,
     0x00e1,
     0x00e2,
     0x00e3,
     0x00e4,
     0x00e5,
     0x00e6,
     0x00e7,
     0x00e8,
     0x00e9,
     0x00ea,
     0x00eb,
     0x00ec,
     0x00ed,
     0x00ee,
     0x00ef,
     0x00f0,
     0x00f1,
     0x00f2,
     0x00f3,
     0x00f4,
     0x00f5,
     0x00f6,
     0x00f7,
     0x00f8,
     0x00f9,
     0x00fa,
     0x00fb,
     0x00fc,
     0x00fd,
     0x00fe,
     0x00ff,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\x04",
     "\x05",
     "\x06",
     "\x07",
     "\x08",
     "\x09",
     "\x0a",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\x14",
     "\x15",
     "\x16",
     "\x17",
     "\x18",
     "\x19",
     "\x1a",
     "\x1b",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\x20",
     "\x21",
     "\x22",
     "\x23",
     "\x24",
     "\x25",
     "\x26",
     "\x27",
     "\x28",
     "\x29",
     "\x2a",
     "\x2b",
     "\x2c",
     "\x2d",
     "\x2e",
     "\x2f",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\x3a",
     "\x3b",
     "\x3c",
     "\x3d",
     "\x3e",
     "\x3f",
     "\x40",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\x5b",
     "\x5c",
     "\x5d",
     "\x5e",
     "\x5f",
     "\x60",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\x7b",
     "\x7c",
     "\x7d",
     "\x7e",
     "\x7f",
     "\xe2\x82\xac",
     "\xef\xbf\xbd",
     "\xe2\x80\x9a",
     "\xc6\x92",
     "\xe2\x80\x9e",
     "\xe2\x80\xa6",
     "\xe2\x80\xa0",
     "\xe2\x80\xa1",
     "\xcb\x86",
     "\xe2\x80\xb0",
     "\xc5\xa0",
     "\xe2\x80\xb9",
     "\xc5\x92",
     "\xef\xbf\xbd",
     "\xc5\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xe2\x80\x98",
     "\xe2\x80\x99",
     "\xe2\x80\x9c",
     "\xe2\x80\x9d",
     "\xe2\x80\xa2",
     "\xe2\x80\x93",
     "\xe2\x80\x94",
     "\xcb\x9c",
     "\xe2\x84\xa2",
     "\xc5\xa1",
     "\xe2\x80\xba",
     "\xc5\x93",
     "\xef\xbf\xbd",
     "\xc5\xbe",
     "\xc5\xb8",
     "\xc2\xa0",
     "\xc2\xa1",
     "\xc2\xa2",
     "\xc2\xa3",
     "\xc2\xa4",
     "\xc2\xa5",
     "\xc2\xa6",
     "\xc2\xa7",
     "\xc2\xa8",
     "\xc2\xa9",
     "\xc2\xaa",
     "\xc2\xab",
     "\xc2\xac",
     "\xc2\xad",
     "\xc2\xae",
     "\xc2\xaf",
     "\xc2\xb0",
     "\xc2\xb1",
     "\xc2\xb2",
     "\xc2\xb3",
     "\xc2\xb4",
     "\xc2\xb5",
     "\xc2\xb6",
     "\xc2\xb7",
     "\xc2\xb8",
     "\xc2\xb9",
     "\xc2\xba",
     "\xc2\xbb",
     "\xc2\xbc",
     "\xc2\xbd",
     "\xc2\xbe",
     "\xc2\xbf",
     "\xc3\x80",
     "\xc3\x81",
     "\xc3\x82",
     "\xc3\x83",
     "\xc3\x84",
     "\xc3\x85",
     "\xc3\x86",
     "\xc3\x87",
     "\xc3\x88",
     "\xc3\x89",
     "\xc3\x8a",
     "\xc3\x8b",
     "\xc3\x8c",
     "\xc3\x8d",
     "\xc3\x8e",
     "\xc3\x8f",
     "\xc3\x90",
     "\xc3\x91",
     "\xc3\x92",
     "\xc3\x93",
     "\xc3\x94",
     "\xc3\x95",
     "\xc3\x96",
     "\xc3\x97",
     "\xc3\x98",
     "\xc3\x99",
     "\xc3\x9a",
     "\xc3\x9b",
     "\xc3\x9c",
     "\xc3\x9d",
     "\xc3\x9e",
     "\xc3\x9f",
     "\xc3\xa0",
     "\xc3\xa1",
     "\xc3\xa2",
     "\xc3\xa3",
     "\xc3\xa4",
     "\xc3\xa5",
     "\xc3\xa6",
     "\xc3\xa7",
     "\xc3\xa8",
     "\xc3\xa9",
     "\xc3\xaa",
     "\xc3\xab",
     "\xc3\xac",
     "\xc3\xad",
     "\xc3\xae",
     "\xc3\xaf",
     "\xc3\xb0",
     "\xc3\xb1",
     "\xc3\xb2",
     "\xc3\xb3",
     "\xc3\xb4",
     "\xc3\xb5",
     "\xc3\xb6",
     "\xc3\xb7",
     "\xc3\xb8",
     "\xc3\xb9",
     "\xc3\xba",
     "\xc3\xbb",
     "\xc3\xbc",
     "\xc3\xbd",
     "\xc3\xbe",
     "\xc3\xbf",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x04",
     0x00000005 => "\x05",
     0x00000006 => "\x06",
     0x00000007 => "\x07",
     0x00000008 => "\x08",
     0x00000009 => "\x09",
     0x0000000a => "\x0a",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x14",
     0x00000015 => "\x15",
     0x00000016 => "\x16",
     0x00000017 => "\x17",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x1a",
     0x0000001b => "\x1b",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x20",
     0x00000021 => "\x21",
     0x00000022 => "\x22",
     0x00000023 => "\x23",
     0x00000024 => "\x24",
     0x00000025 => "\x25",
     0x00000026 => "\x26",
     0x00000027 => "\x27",
     0x00000028 => "\x28",
     0x00000029 => "\x29",
     0x0000002a => "\x2a",
     0x0000002b => "\x2b",
     0x0000002c => "\x2c",
     0x0000002d => "\x2d",
     0x0000002e => "\x2e",
     0x0000002f => "\x2f",
     0x00000030 => "\x30",
     0x00000031 => "\x31",
     0x00000032 => "\x32",
     0x00000033 => "\x33",
     0x00000034 => "\x34",
     0x00000035 => "\x35",
     0x00000036 => "\x36",
     0x00000037 => "\x37",
     0x00000038 => "\x38",
     0x00000039 => "\x39",
     0x0000003a => "\x3a",
     0x0000003b => "\x3b",
     0x0000003c => "\x3c",
     0x0000003d => "\x3d",
     0x0000003e => "\x3e",
     0x0000003f => "\x3f",
     0x00000040 => "\x40",
     0x00000041 => "\x41",
     0x00000042 => "\x42",
     0x00000043 => "\x43",
     0x00000044 => "\x44",
     0x00000045 => "\x45",
     0x00000046 => "\x46",
     0x00000047 => "\x47",
     0x00000048 => "\x48",
     0x00000049 => "\x49",
     0x0000004a => "\x4a",
     0x0000004b => "\x4b",
     0x0000004c => "\x4c",
     0x0000004d => "\x4d",
     0x0000004e => "\x4e",
     0x0000004f => "\x4f",
     0x00000050 => "\x50",
     0x00000051 => "\x51",
     0x00000052 => "\x52",
     0x00000053 => "\x53",
     0x00000054 => "\x54",
     0x00000055 => "\x55",
     0x00000056 => "\x56",
     0x00000057 => "\x57",
     0x00000058 => "\x58",
     0x00000059 => "\x59",
     0x0000005a => "\x5a",
     0x0000005b => "\x5b",
     0x0000005c => "\x5c",
     0x0000005d => "\x5d",
     0x0000005e => "\x5e",
     0x0000005f => "\x5f",
     0x00000060 => "\x60",
     0x00000061 => "\x61",
     0x00000062 => "\x62",
     0x00000063 => "\x63",
     0x00000064 => "\x64",
     0x00000065 => "\x65",
     0x00000066 => "\x66",
     0x00000067 => "\x67",
     0x00000068 => "\x68",
     0x00000069 => "\x69",
     0x0000006a => "\x6a",
     0x0000006b => "\x6b",
     0x0000006c => "\x6c",
     0x0000006d => "\x6d",
     0x0000006e => "\x6e",
     0x0000006f => "\x6f",
     0x00000070 => "\x70",
     0x00000071 => "\x71",
     0x00000072 => "\x72",
     0x00000073 => "\x73",
     0x00000074 => "\x74",
     0x00000075 => "\x75",
     0x00000076 => "\x76",
     0x00000077 => "\x77",
     0x00000078 => "\x78",
     0x00000079 => "\x79",
     0x0000007a => "\x7a",
     0x0000007b => "\x7b",
     0x0000007c => "\x7c",
     0x0000007d => "\x7d",
     0x0000007e => "\x7e",
     0x0000007f => "\x7f",
     0x000000a0 => "\xa0",
     0x000000a1 => "\xa1",
     0x000000a2 => "\xa2",
     0x000000a3 => "\xa3",
     0x000000a4 => "\xa4",
     0x000000a5 => "\xa5",
     0x000000a6 => "\xa6",
     0x000000a7 => "\xa7",
     0x000000a8 => "\xa8",
     0x000000a9 => "\xa9",
     0x000000aa => "\xaa",
     0x000000ab => "\xab",
     0x000000ac => "\xac",
     0x000000ad => "\xad",
     0x000000ae => "\xae",
     0x000000af => "\xaf",
     0x000000b0 => "\xb0",
     0x000000b1 => "\xb1",
     0x000000b2 => "\xb2",
     0x000000b3 => "\xb3",
     0x000000b4 => "\xb4",
     0x000000b5 => "\xb5",
     0x000000b6 => "\xb6",
     0x000000b7 => "\xb7",
     0x000000b8 => "\xb8",
     0x000000b9 => "\xb9",
     0x000000ba => "\xba",
     0x000000bb => "\xbb",
     0x000000bc => "\xbc",
     0x000000bd => "\xbd",
     0x000000be => "\xbe",
     0x000000bf => "\xbf",
     0x000000c0 => "\xc0",
     0x000000c1 => "\xc1",
     0x000000c2 => "\xc2",
     0x000000c3 => "\xc3",
     0x000000c4 => "\xc4",
     0x000000c5 => "\xc5",
     0x000000c6 => "\xc6",
     0x000000c7 => "\xc7",
     0x000000c8 => "\xc8",
     0x000000c9 => "\xc9",
     0x000000ca => "\xca",
     0x000000cb => "\xcb",
     0x000000cc => "\xcc",
     0x000000cd => "\xcd",
     0x000000ce => "\xce",
     0x000000cf => "\xcf",
     0x000000d0 => "\xd0",
     0x000000d1 => "\xd1",
     0x000000d2 => "\xd2",
     0x000000d3 => "\xd3",
     0x000000d4 => "\xd4",
     0x000000d5 => "\xd5",
     0x000000d6 => "\xd6",
     0x000000d7 => "\xd7",
     0x000000d8 => "\xd8",
     0x000000d9 => "\xd9",
     0x000000da => "\xda",
     0x000000db => "\xdb",
     0x000000dc => "\xdc",
     0x000000dd => "\xdd",
     0x000000de => "\xde",
     0x000000df => "\xdf",
     0x000000e0 => "\xe0",
     0x000000e1 => "\xe1",
     0x000000e2 => "\xe2",
     0x000000e3 => "\xe3",
     0x000000e4 => "\xe4",
     0x000000e5 => "\xe5",
     0x000000e6 => "\xe6",
     0x000000e7 => "\xe7",
     0x000000e8 => "\xe8",
     0x000000e9 => "\xe9",
     0x000000ea => "\xea",
     0x000000eb => "\xeb",
     0x000000ec => "\xec",
     0x000000ed => "\xed",
     0x000000ee => "\xee",
     0x000000ef => "\xef",
     0x000000f0 => "\xf0",
     0x000000f1 => "\xf1",
     0x000000f2 => "\xf2",
     0x000000f3 => "\xf3",
     0x000000f4 => "\xf4",
     0x000000f5 => "\xf5",
     0x000000f6 => "\xf6",
     0x000000f7 => "\xf7",
     0x000000f8 => "\xf8",
     0x000000f9 => "\xf9",
     0x000000fa => "\xfa",
     0x000000fb => "\xfb",
     0x000000fc => "\xfc",
     0x000000fd => "\xfd",
     0x000000fe => "\xfe",
     0x000000ff => "\xff",
     0x00000152 => "\x8c",
     0x00000153 => "\x9c",
     0x00000160 => "\x8a",
     0x00000161 => "\x9a",
     0x00000178 => "\x9f",
     0x0000017d => "\x8e",
     0x0000017e => "\x9e",
     0x00000192 => "\x83",
     0x000002c6 => "\x88",
     0x000002dc => "\x98",
     0x00002013 => "\x96",
     0x00002014 => "\x97",
     0x00002018 => "\x91",
     0x00002019 => "\x92",
     0x0000201a => "\x82",
     0x0000201c => "\x93",
     0x0000201d => "\x94",
     0x0000201e => "\x84",
     0x00002020 => "\x86",
     0x00002021 => "\x87",
     0x00002022 => "\x95",
     0x00002026 => "\x85",
     0x00002030 => "\x89",
     0x00002039 => "\x8b",
     0x0000203a => "\x9b",
     0x000020ac => "\x80",
     0x00002122 => "\x99",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::CP1252 - Conversion routines for CP1252
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for CP1252.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
  repertoiremap: mnemonic,ds
   source: UNICODE 1.0
  alias MS-ANSI
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  00000004 | END OF TRANSMISSION (EOT)
     05 |  00000005 | ENQUIRY (ENQ)
     06 |  00000006 | ACKNOWLEDGE (ACK)
     07 |  00000007 | BELL (BEL)
     08 |  00000008 | BACKSPACE (BS)
     09 |  00000009 | CHARACTER TABULATION (HT)
     0A |  0000000A | LINE FEED (LF)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  00000014 | DEVICE CONTROL FOUR (DC4)
     15 |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     16 |  00000016 | SYNCHRONOUS IDLE (SYN)
     17 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  0000001A | SUBSTITUTE (SUB)
     1B |  0000001B | ESCAPE (ESC)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000020 | SPACE
     21 |  00000021 | EXCLAMATION MARK
     22 |  00000022 | QUOTATION MARK
     23 |  00000023 | NUMBER SIGN
     24 |  00000024 | DOLLAR SIGN
     25 |  00000025 | PERCENT SIGN
     26 |  00000026 | AMPERSAND
     27 |  00000027 | APOSTROPHE
     28 |  00000028 | LEFT PARENTHESIS
     29 |  00000029 | RIGHT PARENTHESIS
     2A |  0000002A | ASTERISK
     2B |  0000002B | PLUS SIGN
     2C |  0000002C | COMMA
     2D |  0000002D | HYPHEN-MINUS
     2E |  0000002E | FULL STOP
     2F |  0000002F | SOLIDUS
     30 |  00000030 | DIGIT ZERO
     31 |  00000031 | DIGIT ONE
     32 |  00000032 | DIGIT TWO
     33 |  00000033 | DIGIT THREE
     34 |  00000034 | DIGIT FOUR
     35 |  00000035 | DIGIT FIVE
     36 |  00000036 | DIGIT SIX
     37 |  00000037 | DIGIT SEVEN
     38 |  00000038 | DIGIT EIGHT
     39 |  00000039 | DIGIT NINE
     3A |  0000003A | COLON
     3B |  0000003B | SEMICOLON
     3C |  0000003C | LESS-THAN SIGN
     3D |  0000003D | EQUALS SIGN
     3E |  0000003E | GREATER-THAN SIGN
     3F |  0000003F | QUESTION MARK
     40 |  00000040 | COMMERCIAL AT
     41 |  00000041 | LATIN CAPITAL LETTER A
     42 |  00000042 | LATIN CAPITAL LETTER B
     43 |  00000043 | LATIN CAPITAL LETTER C
     44 |  00000044 | LATIN CAPITAL LETTER D
     45 |  00000045 | LATIN CAPITAL LETTER E
     46 |  00000046 | LATIN CAPITAL LETTER F
     47 |  00000047 | LATIN CAPITAL LETTER G
     48 |  00000048 | LATIN CAPITAL LETTER H
     49 |  00000049 | LATIN CAPITAL LETTER I
     4A |  0000004A | LATIN CAPITAL LETTER J
     4B |  0000004B | LATIN CAPITAL LETTER K
     4C |  0000004C | LATIN CAPITAL LETTER L
     4D |  0000004D | LATIN CAPITAL LETTER M
     4E |  0000004E | LATIN CAPITAL LETTER N
     4F |  0000004F | LATIN CAPITAL LETTER O
     50 |  00000050 | LATIN CAPITAL LETTER P
     51 |  00000051 | LATIN CAPITAL LETTER Q
     52 |  00000052 | LATIN CAPITAL LETTER R
     53 |  00000053 | LATIN CAPITAL LETTER S
     54 |  00000054 | LATIN CAPITAL LETTER T
     55 |  00000055 | LATIN CAPITAL LETTER U
     56 |  00000056 | LATIN CAPITAL LETTER V
     57 |  00000057 | LATIN CAPITAL LETTER W
     58 |  00000058 | LATIN CAPITAL LETTER X
     59 |  00000059 | LATIN CAPITAL LETTER Y
     5A |  0000005A | LATIN CAPITAL LETTER Z
     5B |  0000005B | LEFT SQUARE BRACKET
     5C |  0000005C | REVERSE SOLIDUS
     5D |  0000005D | RIGHT SQUARE BRACKET
     5E |  0000005E | CIRCUMFLEX ACCENT
     5F |  0000005F | LOW LINE
     60 |  00000060 | GRAVE ACCENT
     61 |  00000061 | LATIN SMALL LETTER A
     62 |  00000062 | LATIN SMALL LETTER B
     63 |  00000063 | LATIN SMALL LETTER C
     64 |  00000064 | LATIN SMALL LETTER D
     65 |  00000065 | LATIN SMALL LETTER E
     66 |  00000066 | LATIN SMALL LETTER F
     67 |  00000067 | LATIN SMALL LETTER G
     68 |  00000068 | LATIN SMALL LETTER H
     69 |  00000069 | LATIN SMALL LETTER I
     6A |  0000006A | LATIN SMALL LETTER J
     6B |  0000006B | LATIN SMALL LETTER K
     6C |  0000006C | LATIN SMALL LETTER L
     6D |  0000006D | LATIN SMALL LETTER M
     6E |  0000006E | LATIN SMALL LETTER N
     6F |  0000006F | LATIN SMALL LETTER O
     70 |  00000070 | LATIN SMALL LETTER P
     71 |  00000071 | LATIN SMALL LETTER Q
     72 |  00000072 | LATIN SMALL LETTER R
     73 |  00000073 | LATIN SMALL LETTER S
     74 |  00000074 | LATIN SMALL LETTER T
     75 |  00000075 | LATIN SMALL LETTER U
     76 |  00000076 | LATIN SMALL LETTER V
     77 |  00000077 | LATIN SMALL LETTER W
     78 |  00000078 | LATIN SMALL LETTER X
     79 |  00000079 | LATIN SMALL LETTER Y
     7A |  0000007A | LATIN SMALL LETTER Z
     7B |  0000007B | LEFT CURLY BRACKET
     7C |  0000007C | VERTICAL LINE
     7D |  0000007D | RIGHT CURLY BRACKET
     7E |  0000007E | TILDE
     7F |  0000007F | DELETE (DEL)
     80 |  000020AC | EURO SIGN
     82 |  0000201A | SINGLE LOW-9 QUOTATION MARK
     83 |  00000192 | LATIN SMALL LETTER F WITH HOOK
     84 |  0000201E | DOUBLE LOW-9 QUOTATION MARK
     85 |  00002026 | HORIZONTAL ELLIPSIS
     86 |  00002020 | DAGGER
     87 |  00002021 | DOUBLE DAGGER
     88 |  000002C6 | MODIFIER LETTER CIRCUMFLEX ACCENT
     89 |  00002030 | PER MILLE SIGN
     8A |  00000160 | LATIN CAPITAL LETTER S WITH CARON
     8B |  00002039 | SINGLE LEFT-POINTING ANGLE QUOTATION MARK
     8C |  00000152 | LATIN CAPITAL LIGATURE OE
     8E |  0000017D | LATIN CAPITAL LETTER Z WITH CARON
     91 |  00002018 | LEFT SINGLE QUOTATION MARK
     92 |  00002019 | RIGHT SINGLE QUOTATION MARK
     93 |  0000201C | LEFT DOUBLE QUOTATION MARK
     94 |  0000201D | RIGHT DOUBLE QUOTATION MARK
     95 |  00002022 | BULLET
     96 |  00002013 | EN DASH
     97 |  00002014 | EM DASH
     98 |  000002DC | SMALL TILDE
     99 |  00002122 | TRADE MARK SIGN
     9A |  00000161 | LATIN SMALL LETTER S WITH CARON
     9B |  0000203A | SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
     9C |  00000153 | LATIN SMALL LIGATURE OE
     9E |  0000017E | LATIN SMALL LETTER Z WITH CARON
     9F |  00000178 | LATIN CAPITAL LETTER Y WITH DIAERESIS
     A0 |  000000A0 | NO-BREAK SPACE
     A1 |  000000A1 | INVERTED EXCLAMATION MARK
     A2 |  000000A2 | CENT SIGN
     A3 |  000000A3 | POUND SIGN
     A4 |  000000A4 | CURRENCY SIGN
     A5 |  000000A5 | YEN SIGN
     A6 |  000000A6 | BROKEN BAR
     A7 |  000000A7 | SECTION SIGN
     A8 |  000000A8 | DIAERESIS
     A9 |  000000A9 | COPYRIGHT SIGN
     AA |  000000AA | FEMININE ORDINAL INDICATOR
     AB |  000000AB | LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
     AC |  000000AC | NOT SIGN
     AD |  000000AD | SOFT HYPHEN
     AE |  000000AE | REGISTERED SIGN
     AF |  000000AF | MACRON
     B0 |  000000B0 | DEGREE SIGN
     B1 |  000000B1 | PLUS-MINUS SIGN
     B2 |  000000B2 | SUPERSCRIPT TWO
     B3 |  000000B3 | SUPERSCRIPT THREE
     B4 |  000000B4 | ACUTE ACCENT
     B5 |  000000B5 | MICRO SIGN
     B6 |  000000B6 | PILCROW SIGN
     B7 |  000000B7 | MIDDLE DOT
     B8 |  000000B8 | CEDILLA
     B9 |  000000B9 | SUPERSCRIPT ONE
     BA |  000000BA | MASCULINE ORDINAL INDICATOR
     BB |  000000BB | RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
     BC |  000000BC | VULGAR FRACTION ONE QUARTER
     BD |  000000BD | VULGAR FRACTION ONE HALF
     BE |  000000BE | VULGAR FRACTION THREE QUARTERS
     BF |  000000BF | INVERTED QUESTION MARK
     C0 |  000000C0 | LATIN CAPITAL LETTER A WITH GRAVE
     C1 |  000000C1 | LATIN CAPITAL LETTER A WITH ACUTE
     C2 |  000000C2 | LATIN CAPITAL LETTER A WITH CIRCUMFLEX
     C3 |  000000C3 | LATIN CAPITAL LETTER A WITH TILDE
     C4 |  000000C4 | LATIN CAPITAL LETTER A WITH DIAERESIS
     C5 |  000000C5 | LATIN CAPITAL LETTER A WITH RING ABOVE
     C6 |  000000C6 | LATIN CAPITAL LETTER AE
     C7 |  000000C7 | LATIN CAPITAL LETTER C WITH CEDILLA
     C8 |  000000C8 | LATIN CAPITAL LETTER E WITH GRAVE
     C9 |  000000C9 | LATIN CAPITAL LETTER E WITH ACUTE
     CA |  000000CA | LATIN CAPITAL LETTER E WITH CIRCUMFLEX
     CB |  000000CB | LATIN CAPITAL LETTER E WITH DIAERESIS
     CC |  000000CC | LATIN CAPITAL LETTER I WITH GRAVE
     CD |  000000CD | LATIN CAPITAL LETTER I WITH ACUTE
     CE |  000000CE | LATIN CAPITAL LETTER I WITH CIRCUMFLEX
     CF |  000000CF | LATIN CAPITAL LETTER I WITH DIAERESIS
     D0 |  000000D0 | LATIN CAPITAL LETTER ETH (Icelandic)
     D1 |  000000D1 | LATIN CAPITAL LETTER N WITH TILDE
     D2 |  000000D2 | LATIN CAPITAL LETTER O WITH GRAVE
     D3 |  000000D3 | LATIN CAPITAL LETTER O WITH ACUTE
     D4 |  000000D4 | LATIN CAPITAL LETTER O WITH CIRCUMFLEX
     D5 |  000000D5 | LATIN CAPITAL LETTER O WITH TILDE
     D6 |  000000D6 | LATIN CAPITAL LETTER O WITH DIAERESIS
     D7 |  000000D7 | MULTIPLICATION SIGN
     D8 |  000000D8 | LATIN CAPITAL LETTER O WITH STROKE
     D9 |  000000D9 | LATIN CAPITAL LETTER U WITH GRAVE
     DA |  000000DA | LATIN CAPITAL LETTER U WITH ACUTE
     DB |  000000DB | LATIN CAPITAL LETTER U WITH CIRCUMFLEX
     DC |  000000DC | LATIN CAPITAL LETTER U WITH DIAERESIS
     DD |  000000DD | LATIN CAPITAL LETTER Y WITH ACUTE
     DE |  000000DE | LATIN CAPITAL LETTER THORN (Icelandic)
     DF |  000000DF | LATIN SMALL LETTER SHARP S (German)
     E0 |  000000E0 | LATIN SMALL LETTER A WITH GRAVE
     E1 |  000000E1 | LATIN SMALL LETTER A WITH ACUTE
     E2 |  000000E2 | LATIN SMALL LETTER A WITH CIRCUMFLEX
     E3 |  000000E3 | LATIN SMALL LETTER A WITH TILDE
     E4 |  000000E4 | LATIN SMALL LETTER A WITH DIAERESIS
     E5 |  000000E5 | LATIN SMALL LETTER A WITH RING ABOVE
     E6 |  000000E6 | LATIN SMALL LETTER AE
     E7 |  000000E7 | LATIN SMALL LETTER C WITH CEDILLA
     E8 |  000000E8 | LATIN SMALL LETTER E WITH GRAVE
     E9 |  000000E9 | LATIN SMALL LETTER E WITH ACUTE
     EA |  000000EA | LATIN SMALL LETTER E WITH CIRCUMFLEX
     EB |  000000EB | LATIN SMALL LETTER E WITH DIAERESIS
     EC |  000000EC | LATIN SMALL LETTER I WITH GRAVE
     ED |  000000ED | LATIN SMALL LETTER I WITH ACUTE
     EE |  000000EE | LATIN SMALL LETTER I WITH CIRCUMFLEX
     EF |  000000EF | LATIN SMALL LETTER I WITH DIAERESIS
     F0 |  000000F0 | LATIN SMALL LETTER ETH (Icelandic)
     F1 |  000000F1 | LATIN SMALL LETTER N WITH TILDE
     F2 |  000000F2 | LATIN SMALL LETTER O WITH GRAVE
     F3 |  000000F3 | LATIN SMALL LETTER O WITH ACUTE
     F4 |  000000F4 | LATIN SMALL LETTER O WITH CIRCUMFLEX
     F5 |  000000F5 | LATIN SMALL LETTER O WITH TILDE
     F6 |  000000F6 | LATIN SMALL LETTER O WITH DIAERESIS
     F7 |  000000F7 | DIVISION SIGN
     F8 |  000000F8 | LATIN SMALL LETTER O WITH STROKE
     F9 |  000000F9 | LATIN SMALL LETTER U WITH GRAVE
     FA |  000000FA | LATIN SMALL LETTER U WITH ACUTE
     FB |  000000FB | LATIN SMALL LETTER U WITH CIRCUMFLEX
     FC |  000000FC | LATIN SMALL LETTER U WITH DIAERESIS
     FD |  000000FD | LATIN SMALL LETTER Y WITH ACUTE
     FE |  000000FE | LATIN SMALL LETTER THORN (Icelandic)
     FF |  000000FF | LATIN SMALL LETTER Y WITH DIAERESIS
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/CP1253.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for CP1253.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::CP1253;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x0004,
     0x0005,
     0x0006,
     0x0007,
     0x0008,
     0x0009,
     0x000a,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x0014,
     0x0015,
     0x0016,
     0x0017,
     0x0018,
     0x0019,
     0x001a,
     0x001b,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0020,
     0x0021,
     0x0022,
     0x0023,
     0x0024,
     0x0025,
     0x0026,
     0x0027,
     0x0028,
     0x0029,
     0x002a,
     0x002b,
     0x002c,
     0x002d,
     0x002e,
     0x002f,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x003a,
     0x003b,
     0x003c,
     0x003d,
     0x003e,
     0x003f,
     0x0040,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x005b,
     0x005c,
     0x005d,
     0x005e,
     0x005f,
     0x0060,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x007b,
     0x007c,
     0x007d,
     0x007e,
     0x007f,
     0x20ac,
     0xfffd,
     0x201a,
     0x0192,
     0x201e,
     0x2026,
     0x2020,
     0x2021,
     0xfffd,
     0x2030,
     0xfffd,
     0x2039,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x2018,
     0x2019,
     0x201c,
     0x201d,
     0x2022,
     0x2013,
     0x2014,
     0xfffd,
     0x2122,
     0xfffd,
     0x203a,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00a0,
     0x0385,
     0x0386,
     0x00a3,
     0x00a4,
     0x00a5,
     0x00a6,
     0x00a7,
     0x00a8,
     0x00a9,
     0xfffd,
     0x00ab,
     0x00ac,
     0x00ad,
     0x00ae,
     0x2015,
     0x00b0,
     0x00b1,
     0x00b2,
     0x00b3,
     0x0384,
     0x00b5,
     0x00b6,
     0x00b7,
     0x0388,
     0x0389,
     0x038a,
     0x00bb,
     0x038c,
     0x00bd,
     0x038e,
     0x038f,
     0x0390,
     0x0391,
     0x0392,
     0x0393,
     0x0394,
     0x0395,
     0x0396,
     0x0397,
     0x0398,
     0x0399,
     0x039a,
     0x039b,
     0x039c,
     0x039d,
     0x039e,
     0x039f,
     0x03a0,
     0x03a1,
     0xfffd,
     0x03a3,
     0x03a4,
     0x03a5,
     0x03a6,
     0x03a7,
     0x03a8,
     0x03a9,
     0x03aa,
     0x03ab,
     0x03ac,
     0x03ad,
     0x03ae,
     0x03af,
     0x03b0,
     0x03b1,
     0x03b2,
     0x03b3,
     0x03b4,
     0x03b5,
     0x03b6,
     0x03b7,
     0x03b8,
     0x03b9,
     0x03ba,
     0x03bb,
     0x03bc,
     0x03bd,
     0x03be,
     0x03bf,
     0x03c0,
     0x03c1,
     0x03c2,
     0x03c3,
     0x03c4,
     0x03c5,
     0x03c6,
     0x03c7,
     0x03c8,
     0x03c9,
     0x03ca,
     0x03cb,
     0x03cc,
     0x03cd,
     0x03ce,
     0xfffd,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\x04",
     "\x05",
     "\x06",
     "\x07",
     "\x08",
     "\x09",
     "\x0a",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\x14",
     "\x15",
     "\x16",
     "\x17",
     "\x18",
     "\x19",
     "\x1a",
     "\x1b",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\x20",
     "\x21",
     "\x22",
     "\x23",
     "\x24",
     "\x25",
     "\x26",
     "\x27",
     "\x28",
     "\x29",
     "\x2a",
     "\x2b",
     "\x2c",
     "\x2d",
     "\x2e",
     "\x2f",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\x3a",
     "\x3b",
     "\x3c",
     "\x3d",
     "\x3e",
     "\x3f",
     "\x40",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\x5b",
     "\x5c",
     "\x5d",
     "\x5e",
     "\x5f",
     "\x60",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\x7b",
     "\x7c",
     "\x7d",
     "\x7e",
     "\x7f",
     "\xe2\x82\xac",
     "\xef\xbf\xbd",
     "\xe2\x80\x9a",
     "\xc6\x92",
     "\xe2\x80\x9e",
     "\xe2\x80\xa6",
     "\xe2\x80\xa0",
     "\xe2\x80\xa1",
     "\xef\xbf\xbd",
     "\xe2\x80\xb0",
     "\xef\xbf\xbd",
     "\xe2\x80\xb9",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xe2\x80\x98",
     "\xe2\x80\x99",
     "\xe2\x80\x9c",
     "\xe2\x80\x9d",
     "\xe2\x80\xa2",
     "\xe2\x80\x93",
     "\xe2\x80\x94",
     "\xef\xbf\xbd",
     "\xe2\x84\xa2",
     "\xef\xbf\xbd",
     "\xe2\x80\xba",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc2\xa0",
     "\xce\x85",
     "\xce\x86",
     "\xc2\xa3",
     "\xc2\xa4",
     "\xc2\xa5",
     "\xc2\xa6",
     "\xc2\xa7",
     "\xc2\xa8",
     "\xc2\xa9",
     "\xef\xbf\xbd",
     "\xc2\xab",
     "\xc2\xac",
     "\xc2\xad",
     "\xc2\xae",
     "\xe2\x80\x95",
     "\xc2\xb0",
     "\xc2\xb1",
     "\xc2\xb2",
     "\xc2\xb3",
     "\xce\x84",
     "\xc2\xb5",
     "\xc2\xb6",
     "\xc2\xb7",
     "\xce\x88",
     "\xce\x89",
     "\xce\x8a",
     "\xc2\xbb",
     "\xce\x8c",
     "\xc2\xbd",
     "\xce\x8e",
     "\xce\x8f",
     "\xce\x90",
     "\xce\x91",
     "\xce\x92",
     "\xce\x93",
     "\xce\x94",
     "\xce\x95",
     "\xce\x96",
     "\xce\x97",
     "\xce\x98",
     "\xce\x99",
     "\xce\x9a",
     "\xce\x9b",
     "\xce\x9c",
     "\xce\x9d",
     "\xce\x9e",
     "\xce\x9f",
     "\xce\xa0",
     "\xce\xa1",
     "\xef\xbf\xbd",
     "\xce\xa3",
     "\xce\xa4",
     "\xce\xa5",
     "\xce\xa6",
     "\xce\xa7",
     "\xce\xa8",
     "\xce\xa9",
     "\xce\xaa",
     "\xce\xab",
     "\xce\xac",
     "\xce\xad",
     "\xce\xae",
     "\xce\xaf",
     "\xce\xb0",
     "\xce\xb1",
     "\xce\xb2",
     "\xce\xb3",
     "\xce\xb4",
     "\xce\xb5",
     "\xce\xb6",
     "\xce\xb7",
     "\xce\xb8",
     "\xce\xb9",
     "\xce\xba",
     "\xce\xbb",
     "\xce\xbc",
     "\xce\xbd",
     "\xce\xbe",
     "\xce\xbf",
     "\xcf\x80",
     "\xcf\x81",
     "\xcf\x82",
     "\xcf\x83",
     "\xcf\x84",
     "\xcf\x85",
     "\xcf\x86",
     "\xcf\x87",
     "\xcf\x88",
     "\xcf\x89",
     "\xcf\x8a",
     "\xcf\x8b",
     "\xcf\x8c",
     "\xcf\x8d",
     "\xcf\x8e",
     "\xef\xbf\xbd",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x04",
     0x00000005 => "\x05",
     0x00000006 => "\x06",
     0x00000007 => "\x07",
     0x00000008 => "\x08",
     0x00000009 => "\x09",
     0x0000000a => "\x0a",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x14",
     0x00000015 => "\x15",
     0x00000016 => "\x16",
     0x00000017 => "\x17",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x1a",
     0x0000001b => "\x1b",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x20",
     0x00000021 => "\x21",
     0x00000022 => "\x22",
     0x00000023 => "\x23",
     0x00000024 => "\x24",
     0x00000025 => "\x25",
     0x00000026 => "\x26",
     0x00000027 => "\x27",
     0x00000028 => "\x28",
     0x00000029 => "\x29",
     0x0000002a => "\x2a",
     0x0000002b => "\x2b",
     0x0000002c => "\x2c",
     0x0000002d => "\x2d",
     0x0000002e => "\x2e",
     0x0000002f => "\x2f",
     0x00000030 => "\x30",
     0x00000031 => "\x31",
     0x00000032 => "\x32",
     0x00000033 => "\x33",
     0x00000034 => "\x34",
     0x00000035 => "\x35",
     0x00000036 => "\x36",
     0x00000037 => "\x37",
     0x00000038 => "\x38",
     0x00000039 => "\x39",
     0x0000003a => "\x3a",
     0x0000003b => "\x3b",
     0x0000003c => "\x3c",
     0x0000003d => "\x3d",
     0x0000003e => "\x3e",
     0x0000003f => "\x3f",
     0x00000040 => "\x40",
     0x00000041 => "\x41",
     0x00000042 => "\x42",
     0x00000043 => "\x43",
     0x00000044 => "\x44",
     0x00000045 => "\x45",
     0x00000046 => "\x46",
     0x00000047 => "\x47",
     0x00000048 => "\x48",
     0x00000049 => "\x49",
     0x0000004a => "\x4a",
     0x0000004b => "\x4b",
     0x0000004c => "\x4c",
     0x0000004d => "\x4d",
     0x0000004e => "\x4e",
     0x0000004f => "\x4f",
     0x00000050 => "\x50",
     0x00000051 => "\x51",
     0x00000052 => "\x52",
     0x00000053 => "\x53",
     0x00000054 => "\x54",
     0x00000055 => "\x55",
     0x00000056 => "\x56",
     0x00000057 => "\x57",
     0x00000058 => "\x58",
     0x00000059 => "\x59",
     0x0000005a => "\x5a",
     0x0000005b => "\x5b",
     0x0000005c => "\x5c",
     0x0000005d => "\x5d",
     0x0000005e => "\x5e",
     0x0000005f => "\x5f",
     0x00000060 => "\x60",
     0x00000061 => "\x61",
     0x00000062 => "\x62",
     0x00000063 => "\x63",
     0x00000064 => "\x64",
     0x00000065 => "\x65",
     0x00000066 => "\x66",
     0x00000067 => "\x67",
     0x00000068 => "\x68",
     0x00000069 => "\x69",
     0x0000006a => "\x6a",
     0x0000006b => "\x6b",
     0x0000006c => "\x6c",
     0x0000006d => "\x6d",
     0x0000006e => "\x6e",
     0x0000006f => "\x6f",
     0x00000070 => "\x70",
     0x00000071 => "\x71",
     0x00000072 => "\x72",
     0x00000073 => "\x73",
     0x00000074 => "\x74",
     0x00000075 => "\x75",
     0x00000076 => "\x76",
     0x00000077 => "\x77",
     0x00000078 => "\x78",
     0x00000079 => "\x79",
     0x0000007a => "\x7a",
     0x0000007b => "\x7b",
     0x0000007c => "\x7c",
     0x0000007d => "\x7d",
     0x0000007e => "\x7e",
     0x0000007f => "\x7f",
     0x000000a0 => "\xa0",
     0x000000a3 => "\xa3",
     0x000000a4 => "\xa4",
     0x000000a5 => "\xa5",
     0x000000a6 => "\xa6",
     0x000000a7 => "\xa7",
     0x000000a8 => "\xa8",
     0x000000a9 => "\xa9",
     0x000000ab => "\xab",
     0x000000ac => "\xac",
     0x000000ad => "\xad",
     0x000000ae => "\xae",
     0x000000b0 => "\xb0",
     0x000000b1 => "\xb1",
     0x000000b2 => "\xb2",
     0x000000b3 => "\xb3",
     0x000000b5 => "\xb5",
     0x000000b6 => "\xb6",
     0x000000b7 => "\xb7",
     0x000000bb => "\xbb",
     0x000000bd => "\xbd",
     0x00000192 => "\x83",
     0x00000384 => "\xb4",
     0x00000385 => "\xa1",
     0x00000386 => "\xa2",
     0x00000388 => "\xb8",
     0x00000389 => "\xb9",
     0x0000038a => "\xba",
     0x0000038c => "\xbc",
     0x0000038e => "\xbe",
     0x0000038f => "\xbf",
     0x00000390 => "\xc0",
     0x00000391 => "\xc1",
     0x00000392 => "\xc2",
     0x00000393 => "\xc3",
     0x00000394 => "\xc4",
     0x00000395 => "\xc5",
     0x00000396 => "\xc6",
     0x00000397 => "\xc7",
     0x00000398 => "\xc8",
     0x00000399 => "\xc9",
     0x0000039a => "\xca",
     0x0000039b => "\xcb",
     0x0000039c => "\xcc",
     0x0000039d => "\xcd",
     0x0000039e => "\xce",
     0x0000039f => "\xcf",
     0x000003a0 => "\xd0",
     0x000003a1 => "\xd1",
     0x000003a3 => "\xd3",
     0x000003a4 => "\xd4",
     0x000003a5 => "\xd5",
     0x000003a6 => "\xd6",
     0x000003a7 => "\xd7",
     0x000003a8 => "\xd8",
     0x000003a9 => "\xd9",
     0x000003aa => "\xda",
     0x000003ab => "\xdb",
     0x000003ac => "\xdc",
     0x000003ad => "\xdd",
     0x000003ae => "\xde",
     0x000003af => "\xdf",
     0x000003b0 => "\xe0",
     0x000003b1 => "\xe1",
     0x000003b2 => "\xe2",
     0x000003b3 => "\xe3",
     0x000003b4 => "\xe4",
     0x000003b5 => "\xe5",
     0x000003b6 => "\xe6",
     0x000003b7 => "\xe7",
     0x000003b8 => "\xe8",
     0x000003b9 => "\xe9",
     0x000003ba => "\xea",
     0x000003bb => "\xeb",
     0x000003bc => "\xec",
     0x000003bd => "\xed",
     0x000003be => "\xee",
     0x000003bf => "\xef",
     0x000003c0 => "\xf0",
     0x000003c1 => "\xf1",
     0x000003c2 => "\xf2",
     0x000003c3 => "\xf3",
     0x000003c4 => "\xf4",
     0x000003c5 => "\xf5",
     0x000003c6 => "\xf6",
     0x000003c7 => "\xf7",
     0x000003c8 => "\xf8",
     0x000003c9 => "\xf9",
     0x000003ca => "\xfa",
     0x000003cb => "\xfb",
     0x000003cc => "\xfc",
     0x000003cd => "\xfd",
     0x000003ce => "\xfe",
     0x00002013 => "\x96",
     0x00002014 => "\x97",
     0x00002015 => "\xaf",
     0x00002018 => "\x91",
     0x00002019 => "\x92",
     0x0000201a => "\x82",
     0x0000201c => "\x93",
     0x0000201d => "\x94",
     0x0000201e => "\x84",
     0x00002020 => "\x86",
     0x00002021 => "\x87",
     0x00002022 => "\x95",
     0x00002026 => "\x85",
     0x00002030 => "\x89",
     0x00002039 => "\x8b",
     0x0000203a => "\x9b",
     0x000020ac => "\x80",
     0x00002122 => "\x99",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::CP1253 - Conversion routines for CP1253
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for CP1253.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
  repertoiremap: mnemonic,ds
   source: UNICODE 1.0
  alias MS-GREEK
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  00000004 | END OF TRANSMISSION (EOT)
     05 |  00000005 | ENQUIRY (ENQ)
     06 |  00000006 | ACKNOWLEDGE (ACK)
     07 |  00000007 | BELL (BEL)
     08 |  00000008 | BACKSPACE (BS)
     09 |  00000009 | CHARACTER TABULATION (HT)
     0A |  0000000A | LINE FEED (LF)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  00000014 | DEVICE CONTROL FOUR (DC4)
     15 |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     16 |  00000016 | SYNCHRONOUS IDLE (SYN)
     17 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  0000001A | SUBSTITUTE (SUB)
     1B |  0000001B | ESCAPE (ESC)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000020 | SPACE
     21 |  00000021 | EXCLAMATION MARK
     22 |  00000022 | QUOTATION MARK
     23 |  00000023 | NUMBER SIGN
     24 |  00000024 | DOLLAR SIGN
     25 |  00000025 | PERCENT SIGN
     26 |  00000026 | AMPERSAND
     27 |  00000027 | APOSTROPHE
     28 |  00000028 | LEFT PARENTHESIS
     29 |  00000029 | RIGHT PARENTHESIS
     2A |  0000002A | ASTERISK
     2B |  0000002B | PLUS SIGN
     2C |  0000002C | COMMA
     2D |  0000002D | HYPHEN-MINUS
     2E |  0000002E | FULL STOP
     2F |  0000002F | SOLIDUS
     30 |  00000030 | DIGIT ZERO
     31 |  00000031 | DIGIT ONE
     32 |  00000032 | DIGIT TWO
     33 |  00000033 | DIGIT THREE
     34 |  00000034 | DIGIT FOUR
     35 |  00000035 | DIGIT FIVE
     36 |  00000036 | DIGIT SIX
     37 |  00000037 | DIGIT SEVEN
     38 |  00000038 | DIGIT EIGHT
     39 |  00000039 | DIGIT NINE
     3A |  0000003A | COLON
     3B |  0000003B | SEMICOLON
     3C |  0000003C | LESS-THAN SIGN
     3D |  0000003D | EQUALS SIGN
     3E |  0000003E | GREATER-THAN SIGN
     3F |  0000003F | QUESTION MARK
     40 |  00000040 | COMMERCIAL AT
     41 |  00000041 | LATIN CAPITAL LETTER A
     42 |  00000042 | LATIN CAPITAL LETTER B
     43 |  00000043 | LATIN CAPITAL LETTER C
     44 |  00000044 | LATIN CAPITAL LETTER D
     45 |  00000045 | LATIN CAPITAL LETTER E
     46 |  00000046 | LATIN CAPITAL LETTER F
     47 |  00000047 | LATIN CAPITAL LETTER G
     48 |  00000048 | LATIN CAPITAL LETTER H
     49 |  00000049 | LATIN CAPITAL LETTER I
     4A |  0000004A | LATIN CAPITAL LETTER J
     4B |  0000004B | LATIN CAPITAL LETTER K
     4C |  0000004C | LATIN CAPITAL LETTER L
     4D |  0000004D | LATIN CAPITAL LETTER M
     4E |  0000004E | LATIN CAPITAL LETTER N
     4F |  0000004F | LATIN CAPITAL LETTER O
     50 |  00000050 | LATIN CAPITAL LETTER P
     51 |  00000051 | LATIN CAPITAL LETTER Q
     52 |  00000052 | LATIN CAPITAL LETTER R
     53 |  00000053 | LATIN CAPITAL LETTER S
     54 |  00000054 | LATIN CAPITAL LETTER T
     55 |  00000055 | LATIN CAPITAL LETTER U
     56 |  00000056 | LATIN CAPITAL LETTER V
     57 |  00000057 | LATIN CAPITAL LETTER W
     58 |  00000058 | LATIN CAPITAL LETTER X
     59 |  00000059 | LATIN CAPITAL LETTER Y
     5A |  0000005A | LATIN CAPITAL LETTER Z
     5B |  0000005B | LEFT SQUARE BRACKET
     5C |  0000005C | REVERSE SOLIDUS
     5D |  0000005D | RIGHT SQUARE BRACKET
     5E |  0000005E | CIRCUMFLEX ACCENT
     5F |  0000005F | LOW LINE
     60 |  00000060 | GRAVE ACCENT
     61 |  00000061 | LATIN SMALL LETTER A
     62 |  00000062 | LATIN SMALL LETTER B
     63 |  00000063 | LATIN SMALL LETTER C
     64 |  00000064 | LATIN SMALL LETTER D
     65 |  00000065 | LATIN SMALL LETTER E
     66 |  00000066 | LATIN SMALL LETTER F
     67 |  00000067 | LATIN SMALL LETTER G
     68 |  00000068 | LATIN SMALL LETTER H
     69 |  00000069 | LATIN SMALL LETTER I
     6A |  0000006A | LATIN SMALL LETTER J
     6B |  0000006B | LATIN SMALL LETTER K
     6C |  0000006C | LATIN SMALL LETTER L
     6D |  0000006D | LATIN SMALL LETTER M
     6E |  0000006E | LATIN SMALL LETTER N
     6F |  0000006F | LATIN SMALL LETTER O
     70 |  00000070 | LATIN SMALL LETTER P
     71 |  00000071 | LATIN SMALL LETTER Q
     72 |  00000072 | LATIN SMALL LETTER R
     73 |  00000073 | LATIN SMALL LETTER S
     74 |  00000074 | LATIN SMALL LETTER T
     75 |  00000075 | LATIN SMALL LETTER U
     76 |  00000076 | LATIN SMALL LETTER V
     77 |  00000077 | LATIN SMALL LETTER W
     78 |  00000078 | LATIN SMALL LETTER X
     79 |  00000079 | LATIN SMALL LETTER Y
     7A |  0000007A | LATIN SMALL LETTER Z
     7B |  0000007B | LEFT CURLY BRACKET
     7C |  0000007C | VERTICAL LINE
     7D |  0000007D | RIGHT CURLY BRACKET
     7E |  0000007E | TILDE
     7F |  0000007F | DELETE (DEL)
     80 |  000020AC | EURO SIGN
     82 |  0000201A | SINGLE LOW-9 QUOTATION MARK
     83 |  00000192 | LATIN SMALL LETTER F WITH HOOK
     84 |  0000201E | DOUBLE LOW-9 QUOTATION MARK
     85 |  00002026 | HORIZONTAL ELLIPSIS
     86 |  00002020 | DAGGER
     87 |  00002021 | DOUBLE DAGGER
     89 |  00002030 | PER MILLE SIGN
     8B |  00002039 | SINGLE LEFT-POINTING ANGLE QUOTATION MARK
     91 |  00002018 | LEFT SINGLE QUOTATION MARK
     92 |  00002019 | RIGHT SINGLE QUOTATION MARK
     93 |  0000201C | LEFT DOUBLE QUOTATION MARK
     94 |  0000201D | RIGHT DOUBLE QUOTATION MARK
     95 |  00002022 | BULLET
     96 |  00002013 | EN DASH
     97 |  00002014 | EM DASH
     99 |  00002122 | TRADE MARK SIGN
     9B |  0000203A | SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
     A0 |  000000A0 | NO-BREAK SPACE
     A1 |  00000385 | GREEK DIALYTIKA TONOS
     A2 |  00000386 | GREEK CAPITAL LETTER ALPHA WITH TONOS
     A3 |  000000A3 | POUND SIGN
     A4 |  000000A4 | CURRENCY SIGN
     A5 |  000000A5 | YEN SIGN
     A6 |  000000A6 | BROKEN BAR
     A7 |  000000A7 | SECTION SIGN
     A8 |  000000A8 | DIAERESIS
     A9 |  000000A9 | COPYRIGHT SIGN
     AB |  000000AB | LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
     AC |  000000AC | NOT SIGN
     AD |  000000AD | SOFT HYPHEN
     AE |  000000AE | REGISTERED SIGN
     AF |  00002015 | HORIZONTAL BAR
     B0 |  000000B0 | DEGREE SIGN
     B1 |  000000B1 | PLUS-MINUS SIGN
     B2 |  000000B2 | SUPERSCRIPT TWO
     B3 |  000000B3 | SUPERSCRIPT THREE
     B4 |  00000384 | GREEK TONOS
     B5 |  000000B5 | MICRO SIGN
     B6 |  000000B6 | PILCROW SIGN
     B7 |  000000B7 | MIDDLE DOT
     B8 |  00000388 | GREEK CAPITAL LETTER EPSILON WITH TONOS
     B9 |  00000389 | GREEK CAPITAL LETTER ETA WITH TONOS
     BA |  0000038A | GREEK CAPITAL LETTER IOTA WITH TONOS
     BB |  000000BB | RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
     BC |  0000038C | GREEK CAPITAL LETTER OMICRON WITH TONOS
     BD |  000000BD | VULGAR FRACTION ONE HALF
     BE |  0000038E | GREEK CAPITAL LETTER UPSILON WITH TONOS
     BF |  0000038F | GREEK CAPITAL LETTER OMEGA WITH TONOS
     C0 |  00000390 | GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS
     C1 |  00000391 | GREEK CAPITAL LETTER ALPHA
     C2 |  00000392 | GREEK CAPITAL LETTER BETA
     C3 |  00000393 | GREEK CAPITAL LETTER GAMMA
     C4 |  00000394 | GREEK CAPITAL LETTER DELTA
     C5 |  00000395 | GREEK CAPITAL LETTER EPSILON
     C6 |  00000396 | GREEK CAPITAL LETTER ZETA
     C7 |  00000397 | GREEK CAPITAL LETTER ETA
     C8 |  00000398 | GREEK CAPITAL LETTER THETA
     C9 |  00000399 | GREEK CAPITAL LETTER IOTA
     CA |  0000039A | GREEK CAPITAL LETTER KAPPA
     CB |  0000039B | GREEK CAPITAL LETTER LAMDA
     CC |  0000039C | GREEK CAPITAL LETTER MU
     CD |  0000039D | GREEK CAPITAL LETTER NU
     CE |  0000039E | GREEK CAPITAL LETTER XI
     CF |  0000039F | GREEK CAPITAL LETTER OMICRON
     D0 |  000003A0 | GREEK CAPITAL LETTER PI
     D1 |  000003A1 | GREEK CAPITAL LETTER RHO
     D3 |  000003A3 | GREEK CAPITAL LETTER SIGMA
     D4 |  000003A4 | GREEK CAPITAL LETTER TAU
     D5 |  000003A5 | GREEK CAPITAL LETTER UPSILON
     D6 |  000003A6 | GREEK CAPITAL LETTER PHI
     D7 |  000003A7 | GREEK CAPITAL LETTER CHI
     D8 |  000003A8 | GREEK CAPITAL LETTER PSI
     D9 |  000003A9 | GREEK CAPITAL LETTER OMEGA
     DA |  000003AA | GREEK CAPITAL LETTER IOTA WITH DIALYTIKA
     DB |  000003AB | GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA
     DC |  000003AC | GREEK SMALL LETTER ALPHA WITH TONOS
     DD |  000003AD | GREEK SMALL LETTER EPSILON WITH TONOS
     DE |  000003AE | GREEK SMALL LETTER ETA WITH TONOS
     DF |  000003AF | GREEK SMALL LETTER IOTA WITH TONOS
     E0 |  000003B0 | GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS
     E1 |  000003B1 | GREEK SMALL LETTER ALPHA
     E2 |  000003B2 | GREEK SMALL LETTER BETA
     E3 |  000003B3 | GREEK SMALL LETTER GAMMA
     E4 |  000003B4 | GREEK SMALL LETTER DELTA
     E5 |  000003B5 | GREEK SMALL LETTER EPSILON
     E6 |  000003B6 | GREEK SMALL LETTER ZETA
     E7 |  000003B7 | GREEK SMALL LETTER ETA
     E8 |  000003B8 | GREEK SMALL LETTER THETA
     E9 |  000003B9 | GREEK SMALL LETTER IOTA
     EA |  000003BA | GREEK SMALL LETTER KAPPA
     EB |  000003BB | GREEK SMALL LETTER LAMDA
     EC |  000003BC | GREEK SMALL LETTER MU
     ED |  000003BD | GREEK SMALL LETTER NU
     EE |  000003BE | GREEK SMALL LETTER XI
     EF |  000003BF | GREEK SMALL LETTER OMICRON
     F0 |  000003C0 | GREEK SMALL LETTER PI
     F1 |  000003C1 | GREEK SMALL LETTER RHO
     F2 |  000003C2 | GREEK SMALL LETTER FINAL SIGMA
     F3 |  000003C3 | GREEK SMALL LETTER SIGMA
     F4 |  000003C4 | GREEK SMALL LETTER TAU
     F5 |  000003C5 | GREEK SMALL LETTER UPSILON
     F6 |  000003C6 | GREEK SMALL LETTER PHI
     F7 |  000003C7 | GREEK SMALL LETTER CHI
     F8 |  000003C8 | GREEK SMALL LETTER PSI
     F9 |  000003C9 | GREEK SMALL LETTER OMEGA
     FA |  000003CA | GREEK SMALL LETTER IOTA WITH DIALYTIKA
     FB |  000003CB | GREEK SMALL LETTER UPSILON WITH DIALYTIKA
     FC |  000003CC | GREEK SMALL LETTER OMICRON WITH TONOS
     FD |  000003CD | GREEK SMALL LETTER UPSILON WITH TONOS
     FE |  000003CE | GREEK SMALL LETTER OMEGA WITH TONOS
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/CP1254.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for CP1254.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::CP1254;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x0004,
     0x0005,
     0x0006,
     0x0007,
     0x0008,
     0x0009,
     0x000a,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x0014,
     0x0015,
     0x0016,
     0x0017,
     0x0018,
     0x0019,
     0x001a,
     0x001b,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0020,
     0x0021,
     0x0022,
     0x0023,
     0x0024,
     0x0025,
     0x0026,
     0x0027,
     0x0028,
     0x0029,
     0x002a,
     0x002b,
     0x002c,
     0x002d,
     0x002e,
     0x002f,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x003a,
     0x003b,
     0x003c,
     0x003d,
     0x003e,
     0x003f,
     0x0040,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x005b,
     0x005c,
     0x005d,
     0x005e,
     0x005f,
     0x0060,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x007b,
     0x007c,
     0x007d,
     0x007e,
     0x007f,
     0x20ac,
     0xfffd,
     0x201a,
     0x0192,
     0x201e,
     0x2026,
     0x2020,
     0x2021,
     0x02c6,
     0x2030,
     0x0160,
     0x2039,
     0x0152,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x2018,
     0x2019,
     0x201c,
     0x201d,
     0x2022,
     0x2013,
     0x2014,
     0x02dc,
     0x2122,
     0x0161,
     0x203a,
     0x0153,
     0xfffd,
     0xfffd,
     0x0178,
     0x00a0,
     0x00a1,
     0x00a2,
     0x00a3,
     0x00a4,
     0x00a5,
     0x00a6,
     0x00a7,
     0x00a8,
     0x00a9,
     0x00aa,
     0x00ab,
     0x00ac,
     0x00ad,
     0x00ae,
     0x00af,
     0x00b0,
     0x00b1,
     0x00b2,
     0x00b3,
     0x00b4,
     0x00b5,
     0x00b6,
     0x00b7,
     0x00b8,
     0x00b9,
     0x00ba,
     0x00bb,
     0x00bc,
     0x00bd,
     0x00be,
     0x00bf,
     0x00c0,
     0x00c1,
     0x00c2,
     0x00c3,
     0x00c4,
     0x00c5,
     0x00c6,
     0x00c7,
     0x00c8,
     0x00c9,
     0x00ca,
     0x00cb,
     0x00cc,
     0x00cd,
     0x00ce,
     0x00cf,
     0x011e,
     0x00d1,
     0x00d2,
     0x00d3,
     0x00d4,
     0x00d5,
     0x00d6,
     0x00d7,
     0x00d8,
     0x00d9,
     0x00da,
     0x00db,
     0x00dc,
     0x0130,
     0x015e,
     0x00df,
     0x00e0,
     0x00e1,
     0x00e2,
     0x00e3,
     0x00e4,
     0x00e5,
     0x00e6,
     0x00e7,
     0x00e8,
     0x00e9,
     0x00ea,
     0x00eb,
     0x00ec,
     0x00ed,
     0x00ee,
     0x00ef,
     0x011f,
     0x00f1,
     0x00f2,
     0x00f3,
     0x00f4,
     0x00f5,
     0x00f6,
     0x00f7,
     0x00f8,
     0x00f9,
     0x00fa,
     0x00fb,
     0x00fc,
     0x0131,
     0x015f,
     0x00ff,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\x04",
     "\x05",
     "\x06",
     "\x07",
     "\x08",
     "\x09",
     "\x0a",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\x14",
     "\x15",
     "\x16",
     "\x17",
     "\x18",
     "\x19",
     "\x1a",
     "\x1b",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\x20",
     "\x21",
     "\x22",
     "\x23",
     "\x24",
     "\x25",
     "\x26",
     "\x27",
     "\x28",
     "\x29",
     "\x2a",
     "\x2b",
     "\x2c",
     "\x2d",
     "\x2e",
     "\x2f",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\x3a",
     "\x3b",
     "\x3c",
     "\x3d",
     "\x3e",
     "\x3f",
     "\x40",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\x5b",
     "\x5c",
     "\x5d",
     "\x5e",
     "\x5f",
     "\x60",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\x7b",
     "\x7c",
     "\x7d",
     "\x7e",
     "\x7f",
     "\xe2\x82\xac",
     "\xef\xbf\xbd",
     "\xe2\x80\x9a",
     "\xc6\x92",
     "\xe2\x80\x9e",
     "\xe2\x80\xa6",
     "\xe2\x80\xa0",
     "\xe2\x80\xa1",
     "\xcb\x86",
     "\xe2\x80\xb0",
     "\xc5\xa0",
     "\xe2\x80\xb9",
     "\xc5\x92",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xe2\x80\x98",
     "\xe2\x80\x99",
     "\xe2\x80\x9c",
     "\xe2\x80\x9d",
     "\xe2\x80\xa2",
     "\xe2\x80\x93",
     "\xe2\x80\x94",
     "\xcb\x9c",
     "\xe2\x84\xa2",
     "\xc5\xa1",
     "\xe2\x80\xba",
     "\xc5\x93",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc5\xb8",
     "\xc2\xa0",
     "\xc2\xa1",
     "\xc2\xa2",
     "\xc2\xa3",
     "\xc2\xa4",
     "\xc2\xa5",
     "\xc2\xa6",
     "\xc2\xa7",
     "\xc2\xa8",
     "\xc2\xa9",
     "\xc2\xaa",
     "\xc2\xab",
     "\xc2\xac",
     "\xc2\xad",
     "\xc2\xae",
     "\xc2\xaf",
     "\xc2\xb0",
     "\xc2\xb1",
     "\xc2\xb2",
     "\xc2\xb3",
     "\xc2\xb4",
     "\xc2\xb5",
     "\xc2\xb6",
     "\xc2\xb7",
     "\xc2\xb8",
     "\xc2\xb9",
     "\xc2\xba",
     "\xc2\xbb",
     "\xc2\xbc",
     "\xc2\xbd",
     "\xc2\xbe",
     "\xc2\xbf",
     "\xc3\x80",
     "\xc3\x81",
     "\xc3\x82",
     "\xc3\x83",
     "\xc3\x84",
     "\xc3\x85",
     "\xc3\x86",
     "\xc3\x87",
     "\xc3\x88",
     "\xc3\x89",
     "\xc3\x8a",
     "\xc3\x8b",
     "\xc3\x8c",
     "\xc3\x8d",
     "\xc3\x8e",
     "\xc3\x8f",
     "\xc4\x9e",
     "\xc3\x91",
     "\xc3\x92",
     "\xc3\x93",
     "\xc3\x94",
     "\xc3\x95",
     "\xc3\x96",
     "\xc3\x97",
     "\xc3\x98",
     "\xc3\x99",
     "\xc3\x9a",
     "\xc3\x9b",
     "\xc3\x9c",
     "\xc4\xb0",
     "\xc5\x9e",
     "\xc3\x9f",
     "\xc3\xa0",
     "\xc3\xa1",
     "\xc3\xa2",
     "\xc3\xa3",
     "\xc3\xa4",
     "\xc3\xa5",
     "\xc3\xa6",
     "\xc3\xa7",
     "\xc3\xa8",
     "\xc3\xa9",
     "\xc3\xaa",
     "\xc3\xab",
     "\xc3\xac",
     "\xc3\xad",
     "\xc3\xae",
     "\xc3\xaf",
     "\xc4\x9f",
     "\xc3\xb1",
     "\xc3\xb2",
     "\xc3\xb3",
     "\xc3\xb4",
     "\xc3\xb5",
     "\xc3\xb6",
     "\xc3\xb7",
     "\xc3\xb8",
     "\xc3\xb9",
     "\xc3\xba",
     "\xc3\xbb",
     "\xc3\xbc",
     "\xc4\xb1",
     "\xc5\x9f",
     "\xc3\xbf",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x04",
     0x00000005 => "\x05",
     0x00000006 => "\x06",
     0x00000007 => "\x07",
     0x00000008 => "\x08",
     0x00000009 => "\x09",
     0x0000000a => "\x0a",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x14",
     0x00000015 => "\x15",
     0x00000016 => "\x16",
     0x00000017 => "\x17",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x1a",
     0x0000001b => "\x1b",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x20",
     0x00000021 => "\x21",
     0x00000022 => "\x22",
     0x00000023 => "\x23",
     0x00000024 => "\x24",
     0x00000025 => "\x25",
     0x00000026 => "\x26",
     0x00000027 => "\x27",
     0x00000028 => "\x28",
     0x00000029 => "\x29",
     0x0000002a => "\x2a",
     0x0000002b => "\x2b",
     0x0000002c => "\x2c",
     0x0000002d => "\x2d",
     0x0000002e => "\x2e",
     0x0000002f => "\x2f",
     0x00000030 => "\x30",
     0x00000031 => "\x31",
     0x00000032 => "\x32",
     0x00000033 => "\x33",
     0x00000034 => "\x34",
     0x00000035 => "\x35",
     0x00000036 => "\x36",
     0x00000037 => "\x37",
     0x00000038 => "\x38",
     0x00000039 => "\x39",
     0x0000003a => "\x3a",
     0x0000003b => "\x3b",
     0x0000003c => "\x3c",
     0x0000003d => "\x3d",
     0x0000003e => "\x3e",
     0x0000003f => "\x3f",
     0x00000040 => "\x40",
     0x00000041 => "\x41",
     0x00000042 => "\x42",
     0x00000043 => "\x43",
     0x00000044 => "\x44",
     0x00000045 => "\x45",
     0x00000046 => "\x46",
     0x00000047 => "\x47",
     0x00000048 => "\x48",
     0x00000049 => "\x49",
     0x0000004a => "\x4a",
     0x0000004b => "\x4b",
     0x0000004c => "\x4c",
     0x0000004d => "\x4d",
     0x0000004e => "\x4e",
     0x0000004f => "\x4f",
     0x00000050 => "\x50",
     0x00000051 => "\x51",
     0x00000052 => "\x52",
     0x00000053 => "\x53",
     0x00000054 => "\x54",
     0x00000055 => "\x55",
     0x00000056 => "\x56",
     0x00000057 => "\x57",
     0x00000058 => "\x58",
     0x00000059 => "\x59",
     0x0000005a => "\x5a",
     0x0000005b => "\x5b",
     0x0000005c => "\x5c",
     0x0000005d => "\x5d",
     0x0000005e => "\x5e",
     0x0000005f => "\x5f",
     0x00000060 => "\x60",
     0x00000061 => "\x61",
     0x00000062 => "\x62",
     0x00000063 => "\x63",
     0x00000064 => "\x64",
     0x00000065 => "\x65",
     0x00000066 => "\x66",
     0x00000067 => "\x67",
     0x00000068 => "\x68",
     0x00000069 => "\x69",
     0x0000006a => "\x6a",
     0x0000006b => "\x6b",
     0x0000006c => "\x6c",
     0x0000006d => "\x6d",
     0x0000006e => "\x6e",
     0x0000006f => "\x6f",
     0x00000070 => "\x70",
     0x00000071 => "\x71",
     0x00000072 => "\x72",
     0x00000073 => "\x73",
     0x00000074 => "\x74",
     0x00000075 => "\x75",
     0x00000076 => "\x76",
     0x00000077 => "\x77",
     0x00000078 => "\x78",
     0x00000079 => "\x79",
     0x0000007a => "\x7a",
     0x0000007b => "\x7b",
     0x0000007c => "\x7c",
     0x0000007d => "\x7d",
     0x0000007e => "\x7e",
     0x0000007f => "\x7f",
     0x000000a0 => "\xa0",
     0x000000a1 => "\xa1",
     0x000000a2 => "\xa2",
     0x000000a3 => "\xa3",
     0x000000a4 => "\xa4",
     0x000000a5 => "\xa5",
     0x000000a6 => "\xa6",
     0x000000a7 => "\xa7",
     0x000000a8 => "\xa8",
     0x000000a9 => "\xa9",
     0x000000aa => "\xaa",
     0x000000ab => "\xab",
     0x000000ac => "\xac",
     0x000000ad => "\xad",
     0x000000ae => "\xae",
     0x000000af => "\xaf",
     0x000000b0 => "\xb0",
     0x000000b1 => "\xb1",
     0x000000b2 => "\xb2",
     0x000000b3 => "\xb3",
     0x000000b4 => "\xb4",
     0x000000b5 => "\xb5",
     0x000000b6 => "\xb6",
     0x000000b7 => "\xb7",
     0x000000b8 => "\xb8",
     0x000000b9 => "\xb9",
     0x000000ba => "\xba",
     0x000000bb => "\xbb",
     0x000000bc => "\xbc",
     0x000000bd => "\xbd",
     0x000000be => "\xbe",
     0x000000bf => "\xbf",
     0x000000c0 => "\xc0",
     0x000000c1 => "\xc1",
     0x000000c2 => "\xc2",
     0x000000c3 => "\xc3",
     0x000000c4 => "\xc4",
     0x000000c5 => "\xc5",
     0x000000c6 => "\xc6",
     0x000000c7 => "\xc7",
     0x000000c8 => "\xc8",
     0x000000c9 => "\xc9",
     0x000000ca => "\xca",
     0x000000cb => "\xcb",
     0x000000cc => "\xcc",
     0x000000cd => "\xcd",
     0x000000ce => "\xce",
     0x000000cf => "\xcf",
     0x000000d1 => "\xd1",
     0x000000d2 => "\xd2",
     0x000000d3 => "\xd3",
     0x000000d4 => "\xd4",
     0x000000d5 => "\xd5",
     0x000000d6 => "\xd6",
     0x000000d7 => "\xd7",
     0x000000d8 => "\xd8",
     0x000000d9 => "\xd9",
     0x000000da => "\xda",
     0x000000db => "\xdb",
     0x000000dc => "\xdc",
     0x000000df => "\xdf",
     0x000000e0 => "\xe0",
     0x000000e1 => "\xe1",
     0x000000e2 => "\xe2",
     0x000000e3 => "\xe3",
     0x000000e4 => "\xe4",
     0x000000e5 => "\xe5",
     0x000000e6 => "\xe6",
     0x000000e7 => "\xe7",
     0x000000e8 => "\xe8",
     0x000000e9 => "\xe9",
     0x000000ea => "\xea",
     0x000000eb => "\xeb",
     0x000000ec => "\xec",
     0x000000ed => "\xed",
     0x000000ee => "\xee",
     0x000000ef => "\xef",
     0x000000f1 => "\xf1",
     0x000000f2 => "\xf2",
     0x000000f3 => "\xf3",
     0x000000f4 => "\xf4",
     0x000000f5 => "\xf5",
     0x000000f6 => "\xf6",
     0x000000f7 => "\xf7",
     0x000000f8 => "\xf8",
     0x000000f9 => "\xf9",
     0x000000fa => "\xfa",
     0x000000fb => "\xfb",
     0x000000fc => "\xfc",
     0x000000ff => "\xff",
     0x0000011e => "\xd0",
     0x0000011f => "\xf0",
     0x00000130 => "\xdd",
     0x00000131 => "\xfd",
     0x00000152 => "\x8c",
     0x00000153 => "\x9c",
     0x0000015e => "\xde",
     0x0000015f => "\xfe",
     0x00000160 => "\x8a",
     0x00000161 => "\x9a",
     0x00000178 => "\x9f",
     0x00000192 => "\x83",
     0x000002c6 => "\x88",
     0x000002dc => "\x98",
     0x00002013 => "\x96",
     0x00002014 => "\x97",
     0x00002018 => "\x91",
     0x00002019 => "\x92",
     0x0000201a => "\x82",
     0x0000201c => "\x93",
     0x0000201d => "\x94",
     0x0000201e => "\x84",
     0x00002020 => "\x86",
     0x00002021 => "\x87",
     0x00002022 => "\x95",
     0x00002026 => "\x85",
     0x00002030 => "\x89",
     0x00002039 => "\x8b",
     0x0000203a => "\x9b",
     0x000020ac => "\x80",
     0x00002122 => "\x99",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::CP1254 - Conversion routines for CP1254
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for CP1254.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
  repertoiremap: mnemonic,ds
   source: UNICODE 1.0
  alias MS-TURK
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  00000004 | END OF TRANSMISSION (EOT)
     05 |  00000005 | ENQUIRY (ENQ)
     06 |  00000006 | ACKNOWLEDGE (ACK)
     07 |  00000007 | BELL (BEL)
     08 |  00000008 | BACKSPACE (BS)
     09 |  00000009 | CHARACTER TABULATION (HT)
     0A |  0000000A | LINE FEED (LF)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  00000014 | DEVICE CONTROL FOUR (DC4)
     15 |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     16 |  00000016 | SYNCHRONOUS IDLE (SYN)
     17 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  0000001A | SUBSTITUTE (SUB)
     1B |  0000001B | ESCAPE (ESC)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000020 | SPACE
     21 |  00000021 | EXCLAMATION MARK
     22 |  00000022 | QUOTATION MARK
     23 |  00000023 | NUMBER SIGN
     24 |  00000024 | DOLLAR SIGN
     25 |  00000025 | PERCENT SIGN
     26 |  00000026 | AMPERSAND
     27 |  00000027 | APOSTROPHE
     28 |  00000028 | LEFT PARENTHESIS
     29 |  00000029 | RIGHT PARENTHESIS
     2A |  0000002A | ASTERISK
     2B |  0000002B | PLUS SIGN
     2C |  0000002C | COMMA
     2D |  0000002D | HYPHEN-MINUS
     2E |  0000002E | FULL STOP
     2F |  0000002F | SOLIDUS
     30 |  00000030 | DIGIT ZERO
     31 |  00000031 | DIGIT ONE
     32 |  00000032 | DIGIT TWO
     33 |  00000033 | DIGIT THREE
     34 |  00000034 | DIGIT FOUR
     35 |  00000035 | DIGIT FIVE
     36 |  00000036 | DIGIT SIX
     37 |  00000037 | DIGIT SEVEN
     38 |  00000038 | DIGIT EIGHT
     39 |  00000039 | DIGIT NINE
     3A |  0000003A | COLON
     3B |  0000003B | SEMICOLON
     3C |  0000003C | LESS-THAN SIGN
     3D |  0000003D | EQUALS SIGN
     3E |  0000003E | GREATER-THAN SIGN
     3F |  0000003F | QUESTION MARK
     40 |  00000040 | COMMERCIAL AT
     41 |  00000041 | LATIN CAPITAL LETTER A
     42 |  00000042 | LATIN CAPITAL LETTER B
     43 |  00000043 | LATIN CAPITAL LETTER C
     44 |  00000044 | LATIN CAPITAL LETTER D
     45 |  00000045 | LATIN CAPITAL LETTER E
     46 |  00000046 | LATIN CAPITAL LETTER F
     47 |  00000047 | LATIN CAPITAL LETTER G
     48 |  00000048 | LATIN CAPITAL LETTER H
     49 |  00000049 | LATIN CAPITAL LETTER I
     4A |  0000004A | LATIN CAPITAL LETTER J
     4B |  0000004B | LATIN CAPITAL LETTER K
     4C |  0000004C | LATIN CAPITAL LETTER L
     4D |  0000004D | LATIN CAPITAL LETTER M
     4E |  0000004E | LATIN CAPITAL LETTER N
     4F |  0000004F | LATIN CAPITAL LETTER O
     50 |  00000050 | LATIN CAPITAL LETTER P
     51 |  00000051 | LATIN CAPITAL LETTER Q
     52 |  00000052 | LATIN CAPITAL LETTER R
     53 |  00000053 | LATIN CAPITAL LETTER S
     54 |  00000054 | LATIN CAPITAL LETTER T
     55 |  00000055 | LATIN CAPITAL LETTER U
     56 |  00000056 | LATIN CAPITAL LETTER V
     57 |  00000057 | LATIN CAPITAL LETTER W
     58 |  00000058 | LATIN CAPITAL LETTER X
     59 |  00000059 | LATIN CAPITAL LETTER Y
     5A |  0000005A | LATIN CAPITAL LETTER Z
     5B |  0000005B | LEFT SQUARE BRACKET
     5C |  0000005C | REVERSE SOLIDUS
     5D |  0000005D | RIGHT SQUARE BRACKET
     5E |  0000005E | CIRCUMFLEX ACCENT
     5F |  0000005F | LOW LINE
     60 |  00000060 | GRAVE ACCENT
     61 |  00000061 | LATIN SMALL LETTER A
     62 |  00000062 | LATIN SMALL LETTER B
     63 |  00000063 | LATIN SMALL LETTER C
     64 |  00000064 | LATIN SMALL LETTER D
     65 |  00000065 | LATIN SMALL LETTER E
     66 |  00000066 | LATIN SMALL LETTER F
     67 |  00000067 | LATIN SMALL LETTER G
     68 |  00000068 | LATIN SMALL LETTER H
     69 |  00000069 | LATIN SMALL LETTER I
     6A |  0000006A | LATIN SMALL LETTER J
     6B |  0000006B | LATIN SMALL LETTER K
     6C |  0000006C | LATIN SMALL LETTER L
     6D |  0000006D | LATIN SMALL LETTER M
     6E |  0000006E | LATIN SMALL LETTER N
     6F |  0000006F | LATIN SMALL LETTER O
     70 |  00000070 | LATIN SMALL LETTER P
     71 |  00000071 | LATIN SMALL LETTER Q
     72 |  00000072 | LATIN SMALL LETTER R
     73 |  00000073 | LATIN SMALL LETTER S
     74 |  00000074 | LATIN SMALL LETTER T
     75 |  00000075 | LATIN SMALL LETTER U
     76 |  00000076 | LATIN SMALL LETTER V
     77 |  00000077 | LATIN SMALL LETTER W
     78 |  00000078 | LATIN SMALL LETTER X
     79 |  00000079 | LATIN SMALL LETTER Y
     7A |  0000007A | LATIN SMALL LETTER Z
     7B |  0000007B | LEFT CURLY BRACKET
     7C |  0000007C | VERTICAL LINE
     7D |  0000007D | RIGHT CURLY BRACKET
     7E |  0000007E | TILDE
     7F |  0000007F | DELETE (DEL)
     80 |  000020AC | EURO SIGN
     82 |  0000201A | SINGLE LOW-9 QUOTATION MARK
     83 |  00000192 | LATIN SMALL LETTER F WITH HOOK
     84 |  0000201E | DOUBLE LOW-9 QUOTATION MARK
     85 |  00002026 | HORIZONTAL ELLIPSIS
     86 |  00002020 | DAGGER
     87 |  00002021 | DOUBLE DAGGER
     88 |  000002C6 | MODIFIER LETTER CIRCUMFLEX ACCENT
     89 |  00002030 | PER MILLE SIGN
     8A |  00000160 | LATIN CAPITAL LETTER S WITH CARON
     8B |  00002039 | SINGLE LEFT-POINTING ANGLE QUOTATION MARK
     8C |  00000152 | LATIN CAPITAL LIGATURE OE
     91 |  00002018 | LEFT SINGLE QUOTATION MARK
     92 |  00002019 | RIGHT SINGLE QUOTATION MARK
     93 |  0000201C | LEFT DOUBLE QUOTATION MARK
     94 |  0000201D | RIGHT DOUBLE QUOTATION MARK
     95 |  00002022 | BULLET
     96 |  00002013 | EN DASH
     97 |  00002014 | EM DASH
     98 |  000002DC | SMALL TILDE
     99 |  00002122 | TRADE MARK SIGN
     9A |  00000161 | LATIN SMALL LETTER S WITH CARON
     9B |  0000203A | SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
     9C |  00000153 | LATIN SMALL LIGATURE OE
     9F |  00000178 | LATIN CAPITAL LETTER Y WITH DIAERESIS
     A0 |  000000A0 | NO-BREAK SPACE
     A1 |  000000A1 | INVERTED EXCLAMATION MARK
     A2 |  000000A2 | CENT SIGN
     A3 |  000000A3 | POUND SIGN
     A4 |  000000A4 | CURRENCY SIGN
     A5 |  000000A5 | YEN SIGN
     A6 |  000000A6 | BROKEN BAR
     A7 |  000000A7 | SECTION SIGN
     A8 |  000000A8 | DIAERESIS
     A9 |  000000A9 | COPYRIGHT SIGN
     AA |  000000AA | FEMININE ORDINAL INDICATOR
     AB |  000000AB | LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
     AC |  000000AC | NOT SIGN
     AD |  000000AD | SOFT HYPHEN
     AE |  000000AE | REGISTERED SIGN
     AF |  000000AF | MACRON
     B0 |  000000B0 | DEGREE SIGN
     B1 |  000000B1 | PLUS-MINUS SIGN
     B2 |  000000B2 | SUPERSCRIPT TWO
     B3 |  000000B3 | SUPERSCRIPT THREE
     B4 |  000000B4 | ACUTE ACCENT
     B5 |  000000B5 | MICRO SIGN
     B6 |  000000B6 | PILCROW SIGN
     B7 |  000000B7 | MIDDLE DOT
     B8 |  000000B8 | CEDILLA
     B9 |  000000B9 | SUPERSCRIPT ONE
     BA |  000000BA | MASCULINE ORDINAL INDICATOR
     BB |  000000BB | RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
     BC |  000000BC | VULGAR FRACTION ONE QUARTER
     BD |  000000BD | VULGAR FRACTION ONE HALF
     BE |  000000BE | VULGAR FRACTION THREE QUARTERS
     BF |  000000BF | INVERTED QUESTION MARK
     C0 |  000000C0 | LATIN CAPITAL LETTER A WITH GRAVE
     C1 |  000000C1 | LATIN CAPITAL LETTER A WITH ACUTE
     C2 |  000000C2 | LATIN CAPITAL LETTER A WITH CIRCUMFLEX
     C3 |  000000C3 | LATIN CAPITAL LETTER A WITH TILDE
     C4 |  000000C4 | LATIN CAPITAL LETTER A WITH DIAERESIS
     C5 |  000000C5 | LATIN CAPITAL LETTER A WITH RING ABOVE
     C6 |  000000C6 | LATIN CAPITAL LETTER AE
     C7 |  000000C7 | LATIN CAPITAL LETTER C WITH CEDILLA
     C8 |  000000C8 | LATIN CAPITAL LETTER E WITH GRAVE
     C9 |  000000C9 | LATIN CAPITAL LETTER E WITH ACUTE
     CA |  000000CA | LATIN CAPITAL LETTER E WITH CIRCUMFLEX
     CB |  000000CB | LATIN CAPITAL LETTER E WITH DIAERESIS
     CC |  000000CC | LATIN CAPITAL LETTER I WITH GRAVE
     CD |  000000CD | LATIN CAPITAL LETTER I WITH ACUTE
     CE |  000000CE | LATIN CAPITAL LETTER I WITH CIRCUMFLEX
     CF |  000000CF | LATIN CAPITAL LETTER I WITH DIAERESIS
     D0 |  0000011E | LATIN CAPITAL LETTER G WITH BREVE
     D1 |  000000D1 | LATIN CAPITAL LETTER N WITH TILDE
     D2 |  000000D2 | LATIN CAPITAL LETTER O WITH GRAVE
     D3 |  000000D3 | LATIN CAPITAL LETTER O WITH ACUTE
     D4 |  000000D4 | LATIN CAPITAL LETTER O WITH CIRCUMFLEX
     D5 |  000000D5 | LATIN CAPITAL LETTER O WITH TILDE
     D6 |  000000D6 | LATIN CAPITAL LETTER O WITH DIAERESIS
     D7 |  000000D7 | MULTIPLICATION SIGN
     D8 |  000000D8 | LATIN CAPITAL LETTER O WITH STROKE
     D9 |  000000D9 | LATIN CAPITAL LETTER U WITH GRAVE
     DA |  000000DA | LATIN CAPITAL LETTER U WITH ACUTE
     DB |  000000DB | LATIN CAPITAL LETTER U WITH CIRCUMFLEX
     DC |  000000DC | LATIN CAPITAL LETTER U WITH DIAERESIS
     DD |  00000130 | LATIN CAPITAL LETTER I WITH DOT ABOVE
     DE |  0000015E | LATIN CAPITAL LETTER S WITH CEDILLA
     DF |  000000DF | LATIN SMALL LETTER SHARP S (German)
     E0 |  000000E0 | LATIN SMALL LETTER A WITH GRAVE
     E1 |  000000E1 | LATIN SMALL LETTER A WITH ACUTE
     E2 |  000000E2 | LATIN SMALL LETTER A WITH CIRCUMFLEX
     E3 |  000000E3 | LATIN SMALL LETTER A WITH TILDE
     E4 |  000000E4 | LATIN SMALL LETTER A WITH DIAERESIS
     E5 |  000000E5 | LATIN SMALL LETTER A WITH RING ABOVE
     E6 |  000000E6 | LATIN SMALL LETTER AE
     E7 |  000000E7 | LATIN SMALL LETTER C WITH CEDILLA
     E8 |  000000E8 | LATIN SMALL LETTER E WITH GRAVE
     E9 |  000000E9 | LATIN SMALL LETTER E WITH ACUTE
     EA |  000000EA | LATIN SMALL LETTER E WITH CIRCUMFLEX
     EB |  000000EB | LATIN SMALL LETTER E WITH DIAERESIS
     EC |  000000EC | LATIN SMALL LETTER E WITH GRAVE
     ED |  000000ED | LATIN SMALL LETTER I WITH ACUTE
     EE |  000000EE | LATIN SMALL LETTER I WITH CIRCUMFLEX
     EF |  000000EF | LATIN SMALL LETTER I WITH DIAERESIS
     F0 |  0000011F | LATIN SMALL LETTER G WITH BREVE
     F1 |  000000F1 | LATIN SMALL LETTER N WITH TILDE
     F2 |  000000F2 | LATIN SMALL LETTER O WITH GRAVE
     F3 |  000000F3 | LATIN SMALL LETTER O WITH ACUTE
     F4 |  000000F4 | LATIN SMALL LETTER O WITH CIRCUMFLEX
     F5 |  000000F5 | LATIN SMALL LETTER O WITH TILDE
     F6 |  000000F6 | LATIN SMALL LETTER O WITH DIAERESIS
     F7 |  000000F7 | DIVISION SIGN
     F8 |  000000F8 | LATIN SMALL LETTER O WITH STROKE
     F9 |  000000F9 | LATIN SMALL LETTER U WITH GRAVE
     FA |  000000FA | LATIN SMALL LETTER U WITH ACUTE
     FB |  000000FB | LATIN SMALL LETTER U WITH CIRCUMFLEX
     FC |  000000FC | LATIN SMALL LETTER U WITH DIAERESIS
     FD |  00000131 | LATIN SMALL LETTER DOTLESS I
     FE |  0000015F | LATIN SMALL LETTER S WITH CEDILLA
     FF |  000000FF | LATIN SMALL LETTER Y WITH DIAERESIS
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/CP1256.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for CP1256.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::CP1256;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x0004,
     0x0005,
     0x0006,
     0x0007,
     0x0008,
     0x0009,
     0x000a,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x0014,
     0x0015,
     0x0016,
     0x0017,
     0x0018,
     0x0019,
     0x001a,
     0x001b,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0020,
     0x0021,
     0x0022,
     0x0023,
     0x0024,
     0x0025,
     0x0026,
     0x0027,
     0x0028,
     0x0029,
     0x002a,
     0x002b,
     0x002c,
     0x002d,
     0x002e,
     0x002f,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x003a,
     0x003b,
     0x003c,
     0x003d,
     0x003e,
     0x003f,
     0x0040,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x005b,
     0x005c,
     0x005d,
     0x005e,
     0x005f,
     0x0060,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x007b,
     0x007c,
     0x007d,
     0x007e,
     0x007f,
     0x20ac,
     0x067e,
     0x201a,
     0x0192,
     0x201e,
     0x2026,
     0x2020,
     0x2021,
     0x02c6,
     0x2030,
     0x0679,
     0x2039,
     0x0152,
     0x0686,
     0x0698,
     0x0688,
     0x06af,
     0x2018,
     0x2019,
     0x201c,
     0x201d,
     0x2022,
     0x2013,
     0x2014,
     0x06a9,
     0x2122,
     0x0691,
     0x203a,
     0x0153,
     0x200c,
     0x200d,
     0x06ba,
     0x00a0,
     0x060c,
     0x00a2,
     0x00a3,
     0x00a4,
     0x00a5,
     0x00a6,
     0x00a7,
     0x00a8,
     0x00a9,
     0x06be,
     0x00ab,
     0x00ac,
     0x00ad,
     0x00ae,
     0x00af,
     0x00b0,
     0x00b1,
     0x00b2,
     0x00b3,
     0x00b4,
     0x00b5,
     0x00b6,
     0x00b7,
     0x00b8,
     0x00b9,
     0x061b,
     0x00bb,
     0x00bc,
     0x00bd,
     0x00be,
     0x061f,
     0x06c1,
     0x0621,
     0x0622,
     0x0623,
     0x0624,
     0x0625,
     0x0626,
     0x0627,
     0x0628,
     0x0629,
     0x062a,
     0x062b,
     0x062c,
     0x062d,
     0x062e,
     0x062f,
     0x0630,
     0x0631,
     0x0632,
     0x0633,
     0x0634,
     0x0635,
     0x0636,
     0x00d7,
     0x0637,
     0x0638,
     0x0639,
     0x063a,
     0x0640,
     0x0641,
     0x0642,
     0x0643,
     0x00e0,
     0x0644,
     0x00e2,
     0x0645,
     0x0646,
     0x0647,
     0x0648,
     0x00e7,
     0x00e8,
     0x00e9,
     0x00ea,
     0x00eb,
     0x0649,
     0x064a,
     0x00ee,
     0x00ef,
     0x064b,
     0x064c,
     0x064d,
     0x064e,
     0x00f4,
     0x064f,
     0x0650,
     0x00f7,
     0x0651,
     0x00f9,
     0x0652,
     0x00fb,
     0x00fc,
     0x200e,
     0x200f,
     0x06d2,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\x04",
     "\x05",
     "\x06",
     "\x07",
     "\x08",
     "\x09",
     "\x0a",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\x14",
     "\x15",
     "\x16",
     "\x17",
     "\x18",
     "\x19",
     "\x1a",
     "\x1b",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\x20",
     "\x21",
     "\x22",
     "\x23",
     "\x24",
     "\x25",
     "\x26",
     "\x27",
     "\x28",
     "\x29",
     "\x2a",
     "\x2b",
     "\x2c",
     "\x2d",
     "\x2e",
     "\x2f",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\x3a",
     "\x3b",
     "\x3c",
     "\x3d",
     "\x3e",
     "\x3f",
     "\x40",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\x5b",
     "\x5c",
     "\x5d",
     "\x5e",
     "\x5f",
     "\x60",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\x7b",
     "\x7c",
     "\x7d",
     "\x7e",
     "\x7f",
     "\xe2\x82\xac",
     "\xd9\xbe",
     "\xe2\x80\x9a",
     "\xc6\x92",
     "\xe2\x80\x9e",
     "\xe2\x80\xa6",
     "\xe2\x80\xa0",
     "\xe2\x80\xa1",
     "\xcb\x86",
     "\xe2\x80\xb0",
     "\xd9\xb9",
     "\xe2\x80\xb9",
     "\xc5\x92",
     "\xda\x86",
     "\xda\x98",
     "\xda\x88",
     "\xda\xaf",
     "\xe2\x80\x98",
     "\xe2\x80\x99",
     "\xe2\x80\x9c",
     "\xe2\x80\x9d",
     "\xe2\x80\xa2",
     "\xe2\x80\x93",
     "\xe2\x80\x94",
     "\xda\xa9",
     "\xe2\x84\xa2",
     "\xda\x91",
     "\xe2\x80\xba",
     "\xc5\x93",
     "\xe2\x80\x8c",
     "\xe2\x80\x8d",
     "\xda\xba",
     "\xc2\xa0",
     "\xd8\x8c",
     "\xc2\xa2",
     "\xc2\xa3",
     "\xc2\xa4",
     "\xc2\xa5",
     "\xc2\xa6",
     "\xc2\xa7",
     "\xc2\xa8",
     "\xc2\xa9",
     "\xda\xbe",
     "\xc2\xab",
     "\xc2\xac",
     "\xc2\xad",
     "\xc2\xae",
     "\xc2\xaf",
     "\xc2\xb0",
     "\xc2\xb1",
     "\xc2\xb2",
     "\xc2\xb3",
     "\xc2\xb4",
     "\xc2\xb5",
     "\xc2\xb6",
     "\xc2\xb7",
     "\xc2\xb8",
     "\xc2\xb9",
     "\xd8\x9b",
     "\xc2\xbb",
     "\xc2\xbc",
     "\xc2\xbd",
     "\xc2\xbe",
     "\xd8\x9f",
     "\xdb\x81",
     "\xd8\xa1",
     "\xd8\xa2",
     "\xd8\xa3",
     "\xd8\xa4",
     "\xd8\xa5",
     "\xd8\xa6",
     "\xd8\xa7",
     "\xd8\xa8",
     "\xd8\xa9",
     "\xd8\xaa",
     "\xd8\xab",
     "\xd8\xac",
     "\xd8\xad",
     "\xd8\xae",
     "\xd8\xaf",
     "\xd8\xb0",
     "\xd8\xb1",
     "\xd8\xb2",
     "\xd8\xb3",
     "\xd8\xb4",
     "\xd8\xb5",
     "\xd8\xb6",
     "\xc3\x97",
     "\xd8\xb7",
     "\xd8\xb8",
     "\xd8\xb9",
     "\xd8\xba",
     "\xd9\x80",
     "\xd9\x81",
     "\xd9\x82",
     "\xd9\x83",
     "\xc3\xa0",
     "\xd9\x84",
     "\xc3\xa2",
     "\xd9\x85",
     "\xd9\x86",
     "\xd9\x87",
     "\xd9\x88",
     "\xc3\xa7",
     "\xc3\xa8",
     "\xc3\xa9",
     "\xc3\xaa",
     "\xc3\xab",
     "\xd9\x89",
     "\xd9\x8a",
     "\xc3\xae",
     "\xc3\xaf",
     "\xd9\x8b",
     "\xd9\x8c",
     "\xd9\x8d",
     "\xd9\x8e",
     "\xc3\xb4",
     "\xd9\x8f",
     "\xd9\x90",
     "\xc3\xb7",
     "\xd9\x91",
     "\xc3\xb9",
     "\xd9\x92",
     "\xc3\xbb",
     "\xc3\xbc",
     "\xe2\x80\x8e",
     "\xe2\x80\x8f",
     "\xdb\x92",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x04",
     0x00000005 => "\x05",
     0x00000006 => "\x06",
     0x00000007 => "\x07",
     0x00000008 => "\x08",
     0x00000009 => "\x09",
     0x0000000a => "\x0a",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x14",
     0x00000015 => "\x15",
     0x00000016 => "\x16",
     0x00000017 => "\x17",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x1a",
     0x0000001b => "\x1b",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x20",
     0x00000021 => "\x21",
     0x00000022 => "\x22",
     0x00000023 => "\x23",
     0x00000024 => "\x24",
     0x00000025 => "\x25",
     0x00000026 => "\x26",
     0x00000027 => "\x27",
     0x00000028 => "\x28",
     0x00000029 => "\x29",
     0x0000002a => "\x2a",
     0x0000002b => "\x2b",
     0x0000002c => "\x2c",
     0x0000002d => "\x2d",
     0x0000002e => "\x2e",
     0x0000002f => "\x2f",
     0x00000030 => "\x30",
     0x00000031 => "\x31",
     0x00000032 => "\x32",
     0x00000033 => "\x33",
     0x00000034 => "\x34",
     0x00000035 => "\x35",
     0x00000036 => "\x36",
     0x00000037 => "\x37",
     0x00000038 => "\x38",
     0x00000039 => "\x39",
     0x0000003a => "\x3a",
     0x0000003b => "\x3b",
     0x0000003c => "\x3c",
     0x0000003d => "\x3d",
     0x0000003e => "\x3e",
     0x0000003f => "\x3f",
     0x00000040 => "\x40",
     0x00000041 => "\x41",
     0x00000042 => "\x42",
     0x00000043 => "\x43",
     0x00000044 => "\x44",
     0x00000045 => "\x45",
     0x00000046 => "\x46",
     0x00000047 => "\x47",
     0x00000048 => "\x48",
     0x00000049 => "\x49",
     0x0000004a => "\x4a",
     0x0000004b => "\x4b",
     0x0000004c => "\x4c",
     0x0000004d => "\x4d",
     0x0000004e => "\x4e",
     0x0000004f => "\x4f",
     0x00000050 => "\x50",
     0x00000051 => "\x51",
     0x00000052 => "\x52",
     0x00000053 => "\x53",
     0x00000054 => "\x54",
     0x00000055 => "\x55",
     0x00000056 => "\x56",
     0x00000057 => "\x57",
     0x00000058 => "\x58",
     0x00000059 => "\x59",
     0x0000005a => "\x5a",
     0x0000005b => "\x5b",
     0x0000005c => "\x5c",
     0x0000005d => "\x5d",
     0x0000005e => "\x5e",
     0x0000005f => "\x5f",
     0x00000060 => "\x60",
     0x00000061 => "\x61",
     0x00000062 => "\x62",
     0x00000063 => "\x63",
     0x00000064 => "\x64",
     0x00000065 => "\x65",
     0x00000066 => "\x66",
     0x00000067 => "\x67",
     0x00000068 => "\x68",
     0x00000069 => "\x69",
     0x0000006a => "\x6a",
     0x0000006b => "\x6b",
     0x0000006c => "\x6c",
     0x0000006d => "\x6d",
     0x0000006e => "\x6e",
     0x0000006f => "\x6f",
     0x00000070 => "\x70",
     0x00000071 => "\x71",
     0x00000072 => "\x72",
     0x00000073 => "\x73",
     0x00000074 => "\x74",
     0x00000075 => "\x75",
     0x00000076 => "\x76",
     0x00000077 => "\x77",
     0x00000078 => "\x78",
     0x00000079 => "\x79",
     0x0000007a => "\x7a",
     0x0000007b => "\x7b",
     0x0000007c => "\x7c",
     0x0000007d => "\x7d",
     0x0000007e => "\x7e",
     0x0000007f => "\x7f",
     0x000000a0 => "\xa0",
     0x000000a2 => "\xa2",
     0x000000a3 => "\xa3",
     0x000000a4 => "\xa4",
     0x000000a5 => "\xa5",
     0x000000a6 => "\xa6",
     0x000000a7 => "\xa7",
     0x000000a8 => "\xa8",
     0x000000a9 => "\xa9",
     0x000000ab => "\xab",
     0x000000ac => "\xac",
     0x000000ad => "\xad",
     0x000000ae => "\xae",
     0x000000af => "\xaf",
     0x000000b0 => "\xb0",
     0x000000b1 => "\xb1",
     0x000000b2 => "\xb2",
     0x000000b3 => "\xb3",
     0x000000b4 => "\xb4",
     0x000000b5 => "\xb5",
     0x000000b6 => "\xb6",
     0x000000b7 => "\xb7",
     0x000000b8 => "\xb8",
     0x000000b9 => "\xb9",
     0x000000bb => "\xbb",
     0x000000bc => "\xbc",
     0x000000bd => "\xbd",
     0x000000be => "\xbe",
     0x000000d7 => "\xd7",
     0x000000e0 => "\xe0",
     0x000000e2 => "\xe2",
     0x000000e7 => "\xe7",
     0x000000e8 => "\xe8",
     0x000000e9 => "\xe9",
     0x000000ea => "\xea",
     0x000000eb => "\xeb",
     0x000000ee => "\xee",
     0x000000ef => "\xef",
     0x000000f4 => "\xf4",
     0x000000f7 => "\xf7",
     0x000000f9 => "\xf9",
     0x000000fb => "\xfb",
     0x000000fc => "\xfc",
     0x00000152 => "\x8c",
     0x00000153 => "\x9c",
     0x00000192 => "\x83",
     0x000002c6 => "\x88",
     0x0000060c => "\xa1",
     0x0000061b => "\xba",
     0x0000061f => "\xbf",
     0x00000621 => "\xc1",
     0x00000622 => "\xc2",
     0x00000623 => "\xc3",
     0x00000624 => "\xc4",
     0x00000625 => "\xc5",
     0x00000626 => "\xc6",
     0x00000627 => "\xc7",
     0x00000628 => "\xc8",
     0x00000629 => "\xc9",
     0x0000062a => "\xca",
     0x0000062b => "\xcb",
     0x0000062c => "\xcc",
     0x0000062d => "\xcd",
     0x0000062e => "\xce",
     0x0000062f => "\xcf",
     0x00000630 => "\xd0",
     0x00000631 => "\xd1",
     0x00000632 => "\xd2",
     0x00000633 => "\xd3",
     0x00000634 => "\xd4",
     0x00000635 => "\xd5",
     0x00000636 => "\xd6",
     0x00000637 => "\xd8",
     0x00000638 => "\xd9",
     0x00000639 => "\xda",
     0x0000063a => "\xdb",
     0x00000640 => "\xdc",
     0x00000641 => "\xdd",
     0x00000642 => "\xde",
     0x00000643 => "\xdf",
     0x00000644 => "\xe1",
     0x00000645 => "\xe3",
     0x00000646 => "\xe4",
     0x00000647 => "\xe5",
     0x00000648 => "\xe6",
     0x00000649 => "\xec",
     0x0000064a => "\xed",
     0x0000064b => "\xf0",
     0x0000064c => "\xf1",
     0x0000064d => "\xf2",
     0x0000064e => "\xf3",
     0x0000064f => "\xf5",
     0x00000650 => "\xf6",
     0x00000651 => "\xf8",
     0x00000652 => "\xfa",
     0x00000679 => "\x8a",
     0x0000067e => "\x81",
     0x00000686 => "\x8d",
     0x00000688 => "\x8f",
     0x00000691 => "\x9a",
     0x00000698 => "\x8e",
     0x000006a9 => "\x98",
     0x000006af => "\x90",
     0x000006ba => "\x9f",
     0x000006be => "\xaa",
     0x000006c1 => "\xc0",
     0x000006d2 => "\xff",
     0x0000200c => "\x9d",
     0x0000200d => "\x9e",
     0x0000200e => "\xfd",
     0x0000200f => "\xfe",
     0x00002013 => "\x96",
     0x00002014 => "\x97",
     0x00002018 => "\x91",
     0x00002019 => "\x92",
     0x0000201a => "\x82",
     0x0000201c => "\x93",
     0x0000201d => "\x94",
     0x0000201e => "\x84",
     0x00002020 => "\x86",
     0x00002021 => "\x87",
     0x00002022 => "\x95",
     0x00002026 => "\x85",
     0x00002030 => "\x89",
     0x00002039 => "\x8b",
     0x0000203a => "\x9b",
     0x000020ac => "\x80",
     0x00002122 => "\x99",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::CP1256 - Conversion routines for CP1256
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for CP1256.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
  repertoiremap: mnemonic,ds
   source: UNICODE 1.0
  alias MS-ARAB
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  00000004 | END OF TRANSMISSION (EOT)
     05 |  00000005 | ENQUIRY (ENQ)
     06 |  00000006 | ACKNOWLEDGE (ACK)
     07 |  00000007 | BELL (BEL)
     08 |  00000008 | BACKSPACE (BS)
     09 |  00000009 | CHARACTER TABULATION (HT)
     0A |  0000000A | LINE FEED (LF)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  00000014 | DEVICE CONTROL FOUR (DC4)
     15 |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     16 |  00000016 | SYNCHRONOUS IDLE (SYN)
     17 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  0000001A | SUBSTITUTE (SUB)
     1B |  0000001B | ESCAPE (ESC)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000020 | SPACE
     21 |  00000021 | EXCLAMATION MARK
     22 |  00000022 | QUOTATION MARK
     23 |  00000023 | NUMBER SIGN
     24 |  00000024 | DOLLAR SIGN
     25 |  00000025 | PERCENT SIGN
     26 |  00000026 | AMPERSAND
     27 |  00000027 | APOSTROPHE
     28 |  00000028 | LEFT PARENTHESIS
     29 |  00000029 | RIGHT PARENTHESIS
     2A |  0000002A | ASTERISK
     2B |  0000002B | PLUS SIGN
     2C |  0000002C | COMMA
     2D |  0000002D | HYPHEN-MINUS
     2E |  0000002E | FULL STOP
     2F |  0000002F | SOLIDUS
     30 |  00000030 | DIGIT ZERO
     31 |  00000031 | DIGIT ONE
     32 |  00000032 | DIGIT TWO
     33 |  00000033 | DIGIT THREE
     34 |  00000034 | DIGIT FOUR
     35 |  00000035 | DIGIT FIVE
     36 |  00000036 | DIGIT SIX
     37 |  00000037 | DIGIT SEVEN
     38 |  00000038 | DIGIT EIGHT
     39 |  00000039 | DIGIT NINE
     3A |  0000003A | COLON
     3B |  0000003B | SEMICOLON
     3C |  0000003C | LESS-THAN SIGN
     3D |  0000003D | EQUALS SIGN
     3E |  0000003E | GREATER-THAN SIGN
     3F |  0000003F | QUESTION MARK
     40 |  00000040 | COMMERCIAL AT
     41 |  00000041 | LATIN CAPITAL LETTER A
     42 |  00000042 | LATIN CAPITAL LETTER B
     43 |  00000043 | LATIN CAPITAL LETTER C
     44 |  00000044 | LATIN CAPITAL LETTER D
     45 |  00000045 | LATIN CAPITAL LETTER E
     46 |  00000046 | LATIN CAPITAL LETTER F
     47 |  00000047 | LATIN CAPITAL LETTER G
     48 |  00000048 | LATIN CAPITAL LETTER H
     49 |  00000049 | LATIN CAPITAL LETTER I
     4A |  0000004A | LATIN CAPITAL LETTER J
     4B |  0000004B | LATIN CAPITAL LETTER K
     4C |  0000004C | LATIN CAPITAL LETTER L
     4D |  0000004D | LATIN CAPITAL LETTER M
     4E |  0000004E | LATIN CAPITAL LETTER N
     4F |  0000004F | LATIN CAPITAL LETTER O
     50 |  00000050 | LATIN CAPITAL LETTER P
     51 |  00000051 | LATIN CAPITAL LETTER Q
     52 |  00000052 | LATIN CAPITAL LETTER R
     53 |  00000053 | LATIN CAPITAL LETTER S
     54 |  00000054 | LATIN CAPITAL LETTER T
     55 |  00000055 | LATIN CAPITAL LETTER U
     56 |  00000056 | LATIN CAPITAL LETTER V
     57 |  00000057 | LATIN CAPITAL LETTER W
     58 |  00000058 | LATIN CAPITAL LETTER X
     59 |  00000059 | LATIN CAPITAL LETTER Y
     5A |  0000005A | LATIN CAPITAL LETTER Z
     5B |  0000005B | LEFT SQUARE BRACKET
     5C |  0000005C | REVERSE SOLIDUS
     5D |  0000005D | RIGHT SQUARE BRACKET
     5E |  0000005E | CIRCUMFLEX ACCENT
     5F |  0000005F | LOW LINE
     60 |  00000060 | GRAVE ACCENT
     61 |  00000061 | LATIN SMALL LETTER A
     62 |  00000062 | LATIN SMALL LETTER B
     63 |  00000063 | LATIN SMALL LETTER C
     64 |  00000064 | LATIN SMALL LETTER D
     65 |  00000065 | LATIN SMALL LETTER E
     66 |  00000066 | LATIN SMALL LETTER F
     67 |  00000067 | LATIN SMALL LETTER G
     68 |  00000068 | LATIN SMALL LETTER H
     69 |  00000069 | LATIN SMALL LETTER I
     6A |  0000006A | LATIN SMALL LETTER J
     6B |  0000006B | LATIN SMALL LETTER K
     6C |  0000006C | LATIN SMALL LETTER L
     6D |  0000006D | LATIN SMALL LETTER M
     6E |  0000006E | LATIN SMALL LETTER N
     6F |  0000006F | LATIN SMALL LETTER O
     70 |  00000070 | LATIN SMALL LETTER P
     71 |  00000071 | LATIN SMALL LETTER Q
     72 |  00000072 | LATIN SMALL LETTER R
     73 |  00000073 | LATIN SMALL LETTER S
     74 |  00000074 | LATIN SMALL LETTER T
     75 |  00000075 | LATIN SMALL LETTER U
     76 |  00000076 | LATIN SMALL LETTER V
     77 |  00000077 | LATIN SMALL LETTER W
     78 |  00000078 | LATIN SMALL LETTER X
     79 |  00000079 | LATIN SMALL LETTER Y
     7A |  0000007A | LATIN SMALL LETTER Z
     7B |  0000007B | LEFT CURLY BRACKET
     7C |  0000007C | VERTICAL LINE
     7D |  0000007D | RIGHT CURLY BRACKET
     7E |  0000007E | TILDE
     7F |  0000007F | DELETE (DEL)
     80 |  000020AC | EURO SIGN
     81 |  0000067E | ARABIC LETTER PEH
     82 |  0000201A | SINGLE LOW-9 QUOTATION MARK
     83 |  00000192 | LATIN SMALL LETTER F WITH HOOK
     84 |  0000201E | DOUBLE LOW-9 QUOTATION MARK
     85 |  00002026 | HORIZONTAL ELLIPSIS
     86 |  00002020 | DAGGER
     87 |  00002021 | DOUBLE DAGGER
     88 |  000002C6 | MODIFIER LETTER CIRCUMFLEX ACCENT
     89 |  00002030 | PER MILLE SIGN
     8A |  00000679 | ARABIC LETTER TTEH
     8B |  00002039 | SINGLE LEFT-POINTING ANGLE QUOTATION MARK
     8C |  00000152 | LATIN CAPITAL LIGATURE OE
     8D |  00000686 | ARABIC LETTER TCHEH
     8E |  00000698 | ARABIC LETTER JEH
     8F |  00000688 | ARABIC LETTER DDAL
     90 |  000006AF | ARABIC LETTER GAF
     91 |  00002018 | LEFT SINGLE QUOTATION MARK
     92 |  00002019 | RIGHT SINGLE QUOTATION MARK
     93 |  0000201C | LEFT DOUBLE QUOTATION MARK
     94 |  0000201D | RIGHT DOUBLE QUOTATION MARK
     95 |  00002022 | BULLET
     96 |  00002013 | EN DASH
     97 |  00002014 | EM DASH
     98 |  000006A9 | ARABIC LETTER KEHEH
     99 |  00002122 | TRADE MARK SIGN
     9A |  00000691 | ARABIC LETTER RREH
     9B |  0000203A | SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
     9C |  00000153 | LATIN SMALL LIGATURE OE
     9D |  0000200C | ZERO WIDTH NON-JOINER
     9E |  0000200D | ZERO WIDTH JOINER
     9F |  000006BA | ARABIC LETTER NOON
     A0 |  000000A0 | NO-BREAK SPACE
     A1 |  0000060C | ARABIC COMMA
     A2 |  000000A2 | CENT SIGN
     A3 |  000000A3 | POUND SIGN
     A4 |  000000A4 | CURRENCY SIGN
     A5 |  000000A5 | YEN SIGN
     A6 |  000000A6 | BROKEN BAR
     A7 |  000000A7 | SECTION SIGN
     A8 |  000000A8 | DIAERESIS
     A9 |  000000A9 | COPYRIGHT SIGN
     AA |  000006BE | ARABIC LETTER HEH DOACHASHMEE
     AB |  000000AB | LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
     AC |  000000AC | NOT SIGN
     AD |  000000AD | SOFT HYPHEN
     AE |  000000AE | REGISTERED SIGN
     AF |  000000AF | MACRON
     B0 |  000000B0 | DEGREE SIGN
     B1 |  000000B1 | PLUS-MINUS SIGN
     B2 |  000000B2 | SUPERSCRIPT TWO
     B3 |  000000B3 | SUPERSCRIPT THREE
     B4 |  000000B4 | ACUTE ACCENT
     B5 |  000000B5 | MICRO SIGN
     B6 |  000000B6 | PILCROW SIGN
     B7 |  000000B7 | MIDDLE DOT
     B8 |  000000B8 | CEDILLA
     B9 |  000000B9 | SUPERSCRIPT ONE
     BA |  0000061B | ARABIC SEMICOLON
     BB |  000000BB | RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
     BC |  000000BC | VULGAR FRACTION ONE QUARTER
     BD |  000000BD | VULGAR FRACTION ONE HALF
     BE |  000000BE | VULGAR FRACTION THREE QUARTERS
     BF |  0000061F | ARABIC QUESTION MARK
     C0 |  000006C1 | ARABIC LETTER HEH GOAL
     C1 |  00000621 | ARABIC LETTER HAMZA
     C2 |  00000622 | ARABIC LETTER ALEF WITH MADDA ABOVE
     C3 |  00000623 | ARABIC LETTER ALEF WITH HAMZA ABOVE
     C4 |  00000624 | ARABIC LETTER WAW WITH HAMZA ABOVE
     C5 |  00000625 | ARABIC LETTER ALEF WITH HAMZA BELOW
     C6 |  00000626 | ARABIC LETTER YEH WITH HAMZA ABOVE
     C7 |  00000627 | ARABIC LETTER ALEF
     C8 |  00000628 | ARABIC LETTER BEH
     C9 |  00000629 | ARABIC LETTER TEH MARBUTA
     CA |  0000062A | ARABIC LETTER TEH
     CB |  0000062B | ARABIC LETTER THEH
     CC |  0000062C | ARABIC LETTER JEEM
     CD |  0000062D | ARABIC LETTER HAH
     CE |  0000062E | ARABIC LETTER KHAH
     CF |  0000062F | ARABIC LETTER DAL
     D0 |  00000630 | ARABIC LETTER THAL
     D1 |  00000631 | ARABIC LETTER REH
     D2 |  00000632 | ARABIC LETTER ZAIN
     D3 |  00000633 | ARABIC LETTER SEEN
     D4 |  00000634 | ARABIC LETTER SHEEN
     D5 |  00000635 | ARABIC LETTER SAD
     D6 |  00000636 | ARABIC LETTER DAD
     D7 |  000000D7 | MULTIPLICATION SIGN
     D8 |  00000637 | ARABIC LETTER TAH
     D9 |  00000638 | ARABIC LETTER ZAH
     DA |  00000639 | ARABIC LETTER AIN
     DB |  0000063A | ARABIC LETTER GHAIN
     DC |  00000640 | ARABIC TATWEEL
     DD |  00000641 | ARABIC LETTER FEH
     DE |  00000642 | ARABIC LETTER QAF
     DF |  00000643 | ARABIC LETTER KAF
     E0 |  000000E0 | LATIN SMALL LETTER A WITH GRAVE
     E1 |  00000644 | ARABIC LETTER LAM
     E2 |  000000E2 | LATIN SMALL LETTER A WITH CIRCUMFLEX
     E3 |  00000645 | ARABIC LETTER MEEM
     E4 |  00000646 | ARABIC LETTER NOON
     E5 |  00000647 | ARABIC LETTER HEH
     E6 |  00000648 | ARABIC LETTER WAW
     E7 |  000000E7 | LATIN SMALL LETTER C WITH CEDILLA
     E8 |  000000E8 | LATIN SMALL LETTER E WITH GRAVE
     E9 |  000000E9 | LATIN SMALL LETTER E WITH ACUTE
     EA |  000000EA | LATIN SMALL LETTER E WITH CIRCUMFLEX
     EB |  000000EB | LATIN SMALL LETTER E WITH DIAERESIS
     EC |  00000649 | ARABIC LETTER ALEF MAKSURA
     ED |  0000064A | ARABIC LETTER YEH
     EE |  000000EE | LATIN SMALL LETTER I WITH CIRCUMFLEX
     EF |  000000EF | LATIN SMALL LETTER I WITH DIAERESIS
     F0 |  0000064B | ARABIC FATHATAN
     F1 |  0000064C | ARABIC DAMMATAN
     F2 |  0000064D | ARABIC KASRATAN
     F3 |  0000064E | ARABIC FATHA
     F4 |  000000F4 | LATIN SMALL LETTER O WITH CIRCUMFLEX
     F5 |  0000064F | ARABIC DAMMA
     F6 |  00000650 | ARABIC KASRA
     F7 |  000000F7 | DIVISION SIGN
     F8 |  00000651 | ARABIC SHADDA
     F9 |  000000F9 | LATIN SMALL LETTER U WITH GRAVE
     FA |  00000652 | ARABIC SUKUN
     FB |  000000FB | LATIN SMALL LETTER U WITH CIRCUMFLEX
     FC |  000000FC | LATIN SMALL LETTER U WITH DIAERESIS
     FD |  0000200E | LEFT-TO-RIGHT MARK
     FE |  0000200F | RIGHT-TO-LEFT MARK
     FF |  000006D2 | ARABIC LETTER YEH BARREE
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/CP1257.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for CP1257.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::CP1257;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x0004,
     0x0005,
     0x0006,
     0x0007,
     0x0008,
     0x0009,
     0x000a,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x0014,
     0x0015,
     0x0016,
     0x0017,
     0x0018,
     0x0019,
     0x001a,
     0x001b,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0020,
     0x0021,
     0x0022,
     0x0023,
     0x0024,
     0x0025,
     0x0026,
     0x0027,
     0x0028,
     0x0029,
     0x002a,
     0x002b,
     0x002c,
     0x002d,
     0x002e,
     0x002f,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x003a,
     0x003b,
     0x003c,
     0x003d,
     0x003e,
     0x003f,
     0x0040,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x005b,
     0x005c,
     0x005d,
     0x005e,
     0x005f,
     0x0060,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x007b,
     0x007c,
     0x007d,
     0x007e,
     0x007f,
     0x20ac,
     0xfffd,
     0x201a,
     0xfffd,
     0x201e,
     0x2026,
     0x2020,
     0x2021,
     0xfffd,
     0x2030,
     0xfffd,
     0x2039,
     0xfffd,
     0x00a8,
     0x02c7,
     0x00b8,
     0xfffd,
     0x2018,
     0x2019,
     0x201c,
     0x201d,
     0x2022,
     0x2013,
     0x2014,
     0xfffd,
     0x2122,
     0xfffd,
     0x203a,
     0xfffd,
     0x00af,
     0x02db,
     0xfffd,
     0x00a0,
     0xfffd,
     0x00a2,
     0x00a3,
     0x00a4,
     0xfffd,
     0x00a6,
     0x00a7,
     0x00d8,
     0x00a9,
     0x0156,
     0x00ab,
     0x00ac,
     0x00ad,
     0x00ae,
     0x00c6,
     0x00b0,
     0x00b1,
     0x00b2,
     0x00b3,
     0x00b4,
     0x00b5,
     0x00b6,
     0x00b7,
     0x00f8,
     0x00b9,
     0x0157,
     0x00bb,
     0x00bc,
     0x00bd,
     0x00be,
     0x00e6,
     0x0104,
     0x012e,
     0x0100,
     0x0106,
     0x00c4,
     0x00c5,
     0x0118,
     0x0112,
     0x010c,
     0x00c9,
     0x0179,
     0x0116,
     0x0122,
     0x0136,
     0x012a,
     0x013b,
     0x0160,
     0x0143,
     0x0145,
     0x00d3,
     0x014c,
     0x00d5,
     0x00d6,
     0x00d7,
     0x0172,
     0x0141,
     0x015a,
     0x016a,
     0x00dc,
     0x017b,
     0x017d,
     0x00df,
     0x0105,
     0x012f,
     0x0101,
     0x0107,
     0x00e4,
     0x00e5,
     0x0119,
     0x0113,
     0x010d,
     0x00e9,
     0x017a,
     0x0117,
     0x0123,
     0x0137,
     0x012b,
     0x013c,
     0x0161,
     0x0144,
     0x0146,
     0x00f3,
     0x014d,
     0x00f5,
     0x00f6,
     0x00f7,
     0x0173,
     0x0142,
     0x015b,
     0x016b,
     0x00fc,
     0x017c,
     0x017e,
     0x02d9,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\x04",
     "\x05",
     "\x06",
     "\x07",
     "\x08",
     "\x09",
     "\x0a",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\x14",
     "\x15",
     "\x16",
     "\x17",
     "\x18",
     "\x19",
     "\x1a",
     "\x1b",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\x20",
     "\x21",
     "\x22",
     "\x23",
     "\x24",
     "\x25",
     "\x26",
     "\x27",
     "\x28",
     "\x29",
     "\x2a",
     "\x2b",
     "\x2c",
     "\x2d",
     "\x2e",
     "\x2f",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\x3a",
     "\x3b",
     "\x3c",
     "\x3d",
     "\x3e",
     "\x3f",
     "\x40",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\x5b",
     "\x5c",
     "\x5d",
     "\x5e",
     "\x5f",
     "\x60",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\x7b",
     "\x7c",
     "\x7d",
     "\x7e",
     "\x7f",
     "\xe2\x82\xac",
     "\xef\xbf\xbd",
     "\xe2\x80\x9a",
     "\xef\xbf\xbd",
     "\xe2\x80\x9e",
     "\xe2\x80\xa6",
     "\xe2\x80\xa0",
     "\xe2\x80\xa1",
     "\xef\xbf\xbd",
     "\xe2\x80\xb0",
     "\xef\xbf\xbd",
     "\xe2\x80\xb9",
     "\xef\xbf\xbd",
     "\xc2\xa8",
     "\xcb\x87",
     "\xc2\xb8",
     "\xef\xbf\xbd",
     "\xe2\x80\x98",
     "\xe2\x80\x99",
     "\xe2\x80\x9c",
     "\xe2\x80\x9d",
     "\xe2\x80\xa2",
     "\xe2\x80\x93",
     "\xe2\x80\x94",
     "\xef\xbf\xbd",
     "\xe2\x84\xa2",
     "\xef\xbf\xbd",
     "\xe2\x80\xba",
     "\xef\xbf\xbd",
     "\xc2\xaf",
     "\xcb\x9b",
     "\xef\xbf\xbd",
     "\xc2\xa0",
     "\xef\xbf\xbd",
     "\xc2\xa2",
     "\xc2\xa3",
     "\xc2\xa4",
     "\xef\xbf\xbd",
     "\xc2\xa6",
     "\xc2\xa7",
     "\xc3\x98",
     "\xc2\xa9",
     "\xc5\x96",
     "\xc2\xab",
     "\xc2\xac",
     "\xc2\xad",
     "\xc2\xae",
     "\xc3\x86",
     "\xc2\xb0",
     "\xc2\xb1",
     "\xc2\xb2",
     "\xc2\xb3",
     "\xc2\xb4",
     "\xc2\xb5",
     "\xc2\xb6",
     "\xc2\xb7",
     "\xc3\xb8",
     "\xc2\xb9",
     "\xc5\x97",
     "\xc2\xbb",
     "\xc2\xbc",
     "\xc2\xbd",
     "\xc2\xbe",
     "\xc3\xa6",
     "\xc4\x84",
     "\xc4\xae",
     "\xc4\x80",
     "\xc4\x86",
     "\xc3\x84",
     "\xc3\x85",
     "\xc4\x98",
     "\xc4\x92",
     "\xc4\x8c",
     "\xc3\x89",
     "\xc5\xb9",
     "\xc4\x96",
     "\xc4\xa2",
     "\xc4\xb6",
     "\xc4\xaa",
     "\xc4\xbb",
     "\xc5\xa0",
     "\xc5\x83",
     "\xc5\x85",
     "\xc3\x93",
     "\xc5\x8c",
     "\xc3\x95",
     "\xc3\x96",
     "\xc3\x97",
     "\xc5\xb2",
     "\xc5\x81",
     "\xc5\x9a",
     "\xc5\xaa",
     "\xc3\x9c",
     "\xc5\xbb",
     "\xc5\xbd",
     "\xc3\x9f",
     "\xc4\x85",
     "\xc4\xaf",
     "\xc4\x81",
     "\xc4\x87",
     "\xc3\xa4",
     "\xc3\xa5",
     "\xc4\x99",
     "\xc4\x93",
     "\xc4\x8d",
     "\xc3\xa9",
     "\xc5\xba",
     "\xc4\x97",
     "\xc4\xa3",
     "\xc4\xb7",
     "\xc4\xab",
     "\xc4\xbc",
     "\xc5\xa1",
     "\xc5\x84",
     "\xc5\x86",
     "\xc3\xb3",
     "\xc5\x8d",
     "\xc3\xb5",
     "\xc3\xb6",
     "\xc3\xb7",
     "\xc5\xb3",
     "\xc5\x82",
     "\xc5\x9b",
     "\xc5\xab",
     "\xc3\xbc",
     "\xc5\xbc",
     "\xc5\xbe",
     "\xcb\x99",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x04",
     0x00000005 => "\x05",
     0x00000006 => "\x06",
     0x00000007 => "\x07",
     0x00000008 => "\x08",
     0x00000009 => "\x09",
     0x0000000a => "\x0a",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x14",
     0x00000015 => "\x15",
     0x00000016 => "\x16",
     0x00000017 => "\x17",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x1a",
     0x0000001b => "\x1b",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x20",
     0x00000021 => "\x21",
     0x00000022 => "\x22",
     0x00000023 => "\x23",
     0x00000024 => "\x24",
     0x00000025 => "\x25",
     0x00000026 => "\x26",
     0x00000027 => "\x27",
     0x00000028 => "\x28",
     0x00000029 => "\x29",
     0x0000002a => "\x2a",
     0x0000002b => "\x2b",
     0x0000002c => "\x2c",
     0x0000002d => "\x2d",
     0x0000002e => "\x2e",
     0x0000002f => "\x2f",
     0x00000030 => "\x30",
     0x00000031 => "\x31",
     0x00000032 => "\x32",
     0x00000033 => "\x33",
     0x00000034 => "\x34",
     0x00000035 => "\x35",
     0x00000036 => "\x36",
     0x00000037 => "\x37",
     0x00000038 => "\x38",
     0x00000039 => "\x39",
     0x0000003a => "\x3a",
     0x0000003b => "\x3b",
     0x0000003c => "\x3c",
     0x0000003d => "\x3d",
     0x0000003e => "\x3e",
     0x0000003f => "\x3f",
     0x00000040 => "\x40",
     0x00000041 => "\x41",
     0x00000042 => "\x42",
     0x00000043 => "\x43",
     0x00000044 => "\x44",
     0x00000045 => "\x45",
     0x00000046 => "\x46",
     0x00000047 => "\x47",
     0x00000048 => "\x48",
     0x00000049 => "\x49",
     0x0000004a => "\x4a",
     0x0000004b => "\x4b",
     0x0000004c => "\x4c",
     0x0000004d => "\x4d",
     0x0000004e => "\x4e",
     0x0000004f => "\x4f",
     0x00000050 => "\x50",
     0x00000051 => "\x51",
     0x00000052 => "\x52",
     0x00000053 => "\x53",
     0x00000054 => "\x54",
     0x00000055 => "\x55",
     0x00000056 => "\x56",
     0x00000057 => "\x57",
     0x00000058 => "\x58",
     0x00000059 => "\x59",
     0x0000005a => "\x5a",
     0x0000005b => "\x5b",
     0x0000005c => "\x5c",
     0x0000005d => "\x5d",
     0x0000005e => "\x5e",
     0x0000005f => "\x5f",
     0x00000060 => "\x60",
     0x00000061 => "\x61",
     0x00000062 => "\x62",
     0x00000063 => "\x63",
     0x00000064 => "\x64",
     0x00000065 => "\x65",
     0x00000066 => "\x66",
     0x00000067 => "\x67",
     0x00000068 => "\x68",
     0x00000069 => "\x69",
     0x0000006a => "\x6a",
     0x0000006b => "\x6b",
     0x0000006c => "\x6c",
     0x0000006d => "\x6d",
     0x0000006e => "\x6e",
     0x0000006f => "\x6f",
     0x00000070 => "\x70",
     0x00000071 => "\x71",
     0x00000072 => "\x72",
     0x00000073 => "\x73",
     0x00000074 => "\x74",
     0x00000075 => "\x75",
     0x00000076 => "\x76",
     0x00000077 => "\x77",
     0x00000078 => "\x78",
     0x00000079 => "\x79",
     0x0000007a => "\x7a",
     0x0000007b => "\x7b",
     0x0000007c => "\x7c",
     0x0000007d => "\x7d",
     0x0000007e => "\x7e",
     0x0000007f => "\x7f",
     0x000000a0 => "\xa0",
     0x000000a2 => "\xa2",
     0x000000a3 => "\xa3",
     0x000000a4 => "\xa4",
     0x000000a6 => "\xa6",
     0x000000a7 => "\xa7",
     0x000000a8 => "\x8d",
     0x000000a9 => "\xa9",
     0x000000ab => "\xab",
     0x000000ac => "\xac",
     0x000000ad => "\xad",
     0x000000ae => "\xae",
     0x000000af => "\x9d",
     0x000000b0 => "\xb0",
     0x000000b1 => "\xb1",
     0x000000b2 => "\xb2",
     0x000000b3 => "\xb3",
     0x000000b4 => "\xb4",
     0x000000b5 => "\xb5",
     0x000000b6 => "\xb6",
     0x000000b7 => "\xb7",
     0x000000b8 => "\x8f",
     0x000000b9 => "\xb9",
     0x000000bb => "\xbb",
     0x000000bc => "\xbc",
     0x000000bd => "\xbd",
     0x000000be => "\xbe",
     0x000000c4 => "\xc4",
     0x000000c5 => "\xc5",
     0x000000c6 => "\xaf",
     0x000000c9 => "\xc9",
     0x000000d3 => "\xd3",
     0x000000d5 => "\xd5",
     0x000000d6 => "\xd6",
     0x000000d7 => "\xd7",
     0x000000d8 => "\xa8",
     0x000000dc => "\xdc",
     0x000000df => "\xdf",
     0x000000e4 => "\xe4",
     0x000000e5 => "\xe5",
     0x000000e6 => "\xbf",
     0x000000e9 => "\xe9",
     0x000000f3 => "\xf3",
     0x000000f5 => "\xf5",
     0x000000f6 => "\xf6",
     0x000000f7 => "\xf7",
     0x000000f8 => "\xb8",
     0x000000fc => "\xfc",
     0x00000100 => "\xc2",
     0x00000101 => "\xe2",
     0x00000104 => "\xc0",
     0x00000105 => "\xe0",
     0x00000106 => "\xc3",
     0x00000107 => "\xe3",
     0x0000010c => "\xc8",
     0x0000010d => "\xe8",
     0x00000112 => "\xc7",
     0x00000113 => "\xe7",
     0x00000116 => "\xcb",
     0x00000117 => "\xeb",
     0x00000118 => "\xc6",
     0x00000119 => "\xe6",
     0x00000122 => "\xcc",
     0x00000123 => "\xec",
     0x0000012a => "\xce",
     0x0000012b => "\xee",
     0x0000012e => "\xc1",
     0x0000012f => "\xe1",
     0x00000136 => "\xcd",
     0x00000137 => "\xed",
     0x0000013b => "\xcf",
     0x0000013c => "\xef",
     0x00000141 => "\xd9",
     0x00000142 => "\xf9",
     0x00000143 => "\xd1",
     0x00000144 => "\xf1",
     0x00000145 => "\xd2",
     0x00000146 => "\xf2",
     0x0000014c => "\xd4",
     0x0000014d => "\xf4",
     0x00000156 => "\xaa",
     0x00000157 => "\xba",
     0x0000015a => "\xda",
     0x0000015b => "\xfa",
     0x00000160 => "\xd0",
     0x00000161 => "\xf0",
     0x0000016a => "\xdb",
     0x0000016b => "\xfb",
     0x00000172 => "\xd8",
     0x00000173 => "\xf8",
     0x00000179 => "\xca",
     0x0000017a => "\xea",
     0x0000017b => "\xdd",
     0x0000017c => "\xfd",
     0x0000017d => "\xde",
     0x0000017e => "\xfe",
     0x000002c7 => "\x8e",
     0x000002d9 => "\xff",
     0x000002db => "\x9e",
     0x00002013 => "\x96",
     0x00002014 => "\x97",
     0x00002018 => "\x91",
     0x00002019 => "\x92",
     0x0000201a => "\x82",
     0x0000201c => "\x93",
     0x0000201d => "\x94",
     0x0000201e => "\x84",
     0x00002020 => "\x86",
     0x00002021 => "\x87",
     0x00002022 => "\x95",
     0x00002026 => "\x85",
     0x00002030 => "\x89",
     0x00002039 => "\x8b",
     0x0000203a => "\x9b",
     0x000020ac => "\x80",
     0x00002122 => "\x99",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::CP1257 - Conversion routines for CP1257
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for CP1257.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
   source: CEN/TC304 N283
  alias WINBALTRIM
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  00000004 | END OF TRANSMISSION (EOT)
     05 |  00000005 | ENQUIRY (ENQ)
     06 |  00000006 | ACKNOWLEDGE (ACK)
     07 |  00000007 | BELL (BEL)
     08 |  00000008 | BACKSPACE (BS)
     09 |  00000009 | CHARACTER TABULATION (HT)
     0A |  0000000A | LINE FEED (LF)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  00000014 | DEVICE CONTROL FOUR (DC4)
     15 |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     16 |  00000016 | SYNCHRONOUS IDLE (SYN)
     17 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  0000001A | SUBSTITUTE (SUB)
     1B |  0000001B | ESCAPE (ESC)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000020 | SPACE
     21 |  00000021 | EXCLAMATION MARK
     22 |  00000022 | QUOTATION MARK
     23 |  00000023 | NUMBER SIGN
     24 |  00000024 | DOLLAR SIGN
     25 |  00000025 | PERCENT SIGN
     26 |  00000026 | AMPERSAND
     27 |  00000027 | APOSTROPHE
     28 |  00000028 | LEFT PARENTHESIS
     29 |  00000029 | RIGHT PARENTHESIS
     2A |  0000002A | ASTERISK
     2B |  0000002B | PLUS SIGN
     2C |  0000002C | COMMA
     2D |  0000002D | HYPHEN-MINUS
     2E |  0000002E | FULL STOP
     2F |  0000002F | SOLIDUS
     30 |  00000030 | DIGIT ZERO
     31 |  00000031 | DIGIT ONE
     32 |  00000032 | DIGIT TWO
     33 |  00000033 | DIGIT THREE
     34 |  00000034 | DIGIT FOUR
     35 |  00000035 | DIGIT FIVE
     36 |  00000036 | DIGIT SIX
     37 |  00000037 | DIGIT SEVEN
     38 |  00000038 | DIGIT EIGHT
     39 |  00000039 | DIGIT NINE
     3A |  0000003A | COLON
     3B |  0000003B | SEMICOLON
     3C |  0000003C | LESS-THAN SIGN
     3D |  0000003D | EQUALS SIGN
     3E |  0000003E | GREATER-THAN SIGN
     3F |  0000003F | QUESTION MARK
     40 |  00000040 | COMMERCIAL AT
     41 |  00000041 | LATIN CAPITAL LETTER A
     42 |  00000042 | LATIN CAPITAL LETTER B
     43 |  00000043 | LATIN CAPITAL LETTER C
     44 |  00000044 | LATIN CAPITAL LETTER D
     45 |  00000045 | LATIN CAPITAL LETTER E
     46 |  00000046 | LATIN CAPITAL LETTER F
     47 |  00000047 | LATIN CAPITAL LETTER G
     48 |  00000048 | LATIN CAPITAL LETTER H
     49 |  00000049 | LATIN CAPITAL LETTER I
     4A |  0000004A | LATIN CAPITAL LETTER J
     4B |  0000004B | LATIN CAPITAL LETTER K
     4C |  0000004C | LATIN CAPITAL LETTER L
     4D |  0000004D | LATIN CAPITAL LETTER M
     4E |  0000004E | LATIN CAPITAL LETTER N
     4F |  0000004F | LATIN CAPITAL LETTER O
     50 |  00000050 | LATIN CAPITAL LETTER P
     51 |  00000051 | LATIN CAPITAL LETTER Q
     52 |  00000052 | LATIN CAPITAL LETTER R
     53 |  00000053 | LATIN CAPITAL LETTER S
     54 |  00000054 | LATIN CAPITAL LETTER T
     55 |  00000055 | LATIN CAPITAL LETTER U
     56 |  00000056 | LATIN CAPITAL LETTER V
     57 |  00000057 | LATIN CAPITAL LETTER W
     58 |  00000058 | LATIN CAPITAL LETTER X
     59 |  00000059 | LATIN CAPITAL LETTER Y
     5A |  0000005A | LATIN CAPITAL LETTER Z
     5B |  0000005B | LEFT SQUARE BRACKET
     5C |  0000005C | REVERSE SOLIDUS
     5D |  0000005D | RIGHT SQUARE BRACKET
     5E |  0000005E | CIRCUMFLEX ACCENT
     5F |  0000005F | LOW LINE
     60 |  00000060 | GRAVE ACCENT
     61 |  00000061 | LATIN SMALL LETTER A
     62 |  00000062 | LATIN SMALL LETTER B
     63 |  00000063 | LATIN SMALL LETTER C
     64 |  00000064 | LATIN SMALL LETTER D
     65 |  00000065 | LATIN SMALL LETTER E
     66 |  00000066 | LATIN SMALL LETTER F
     67 |  00000067 | LATIN SMALL LETTER G
     68 |  00000068 | LATIN SMALL LETTER H
     69 |  00000069 | LATIN SMALL LETTER I
     6A |  0000006A | LATIN SMALL LETTER J
     6B |  0000006B | LATIN SMALL LETTER K
     6C |  0000006C | LATIN SMALL LETTER L
     6D |  0000006D | LATIN SMALL LETTER M
     6E |  0000006E | LATIN SMALL LETTER N
     6F |  0000006F | LATIN SMALL LETTER O
     70 |  00000070 | LATIN SMALL LETTER P
     71 |  00000071 | LATIN SMALL LETTER Q
     72 |  00000072 | LATIN SMALL LETTER R
     73 |  00000073 | LATIN SMALL LETTER S
     74 |  00000074 | LATIN SMALL LETTER T
     75 |  00000075 | LATIN SMALL LETTER U
     76 |  00000076 | LATIN SMALL LETTER V
     77 |  00000077 | LATIN SMALL LETTER W
     78 |  00000078 | LATIN SMALL LETTER X
     79 |  00000079 | LATIN SMALL LETTER Y
     7A |  0000007A | LATIN SMALL LETTER Z
     7B |  0000007B | LEFT CURLY BRACKET
     7C |  0000007C | VERTICAL LINE
     7D |  0000007D | RIGHT CURLY BRACKET
     7E |  0000007E | TILDE
     7F |  0000007F | DELETE (DEL)
     80 |  000020AC | EURO SIGN
     82 |  0000201A | SINGLE LOW-9 QUOTATION MARK
     84 |  0000201E | DOUBLE LOW-9 QUOTATION MARK
     85 |  00002026 | HORIZONTAL ELLIPSIS
     86 |  00002020 | DAGGER
     87 |  00002021 | DOUBLE DAGGER
     89 |  00002030 | PER MILLE SIGN
     8B |  00002039 | SINGLE LEFT-POINTING ANGLE QUOTATION MARK
     8D |  000000A8 | DIAERESIS
     8E |  000002C7 | CARON (Mandarin Chinese third tone)
     8F |  000000B8 | CEDILLA
     91 |  00002018 | LEFT SINGLE QUOTATION MARK
     92 |  00002019 | RIGHT SINGLE QUOTATION MARK
     93 |  0000201C | LEFT DOUBLE QUOTATION MARK
     94 |  0000201D | RIGHT DOUBLE QUOTATION MARK
     95 |  00002022 | BULLET
     96 |  00002013 | EN DASH
     97 |  00002014 | EM DASH
     99 |  00002122 | TRADE MARK SIGN
     9B |  0000203A | SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
     9D |  000000AF | MACRON
     9E |  000002DB | OGONEK
     A0 |  000000A0 | NO-BREAK SPACE
     A2 |  000000A2 | CENT SIGN
     A3 |  000000A3 | POUND SIGN
     A4 |  000000A4 | CURRENCY SIGN
     A6 |  000000A6 | BROKEN BAR
     A7 |  000000A7 | SECTION SIGN
     A8 |  000000D8 | LATIN CAPITAL LETTER O WITH STROKE
     A9 |  000000A9 | COPYRIGHT SIGN
     AA |  00000156 | LATIN CAPITAL LETTER R WITH CEDILLA
     AB |  000000AB | LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
     AC |  000000AC | NOT SIGN
     AD |  000000AD | SOFT HYPHEN
     AE |  000000AE | REGISTERED SIGN
     AF |  000000C6 | LATIN CAPITAL LETTER AE
     B0 |  000000B0 | DEGREE SIGN
     B1 |  000000B1 | PLUS-MINUS SIGN
     B2 |  000000B2 | SUPERSCRIPT TWO
     B3 |  000000B3 | SUPERSCRIPT THREE
     B4 |  000000B4 | ACUTE ACCENT
     B5 |  000000B5 | MICRO SIGN
     B6 |  000000B6 | PILCROW SIGN
     B7 |  000000B7 | MIDDLE DOT
     B8 |  000000F8 | LATIN SMALL LETTER O WITH STROKE
     B9 |  000000B9 | SUPERSCRIPT ONE
     BA |  00000157 | LATIN SMALL LETTER R WITH CEDILLA
     BB |  000000BB | RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
     BC |  000000BC | VULGAR FRACTION ONE QUARTER
     BD |  000000BD | VULGAR FRACTION ONE HALF
     BE |  000000BE | VULGAR FRACTION THREE QUARTERS
     BF |  000000E6 | LATIN SMALL LETTER AE
     C0 |  00000104 | LATIN CAPITAL LETTER A WITH OGONEK
     C1 |  0000012E | LATIN CAPITAL LETTER I WITH OGONEK
     C2 |  00000100 | LATIN CAPITAL LETTER A WITH MACRON
     C3 |  00000106 | LATIN CAPITAL LETTER C WITH ACUTE
     C4 |  000000C4 | LATIN CAPITAL LETTER A WITH DIAERESIS
     C5 |  000000C5 | LATIN CAPITAL LETTER A WITH RING ABOVE
     C6 |  00000118 | LATIN CAPITAL LETTER E WITH OGONEK
     C7 |  00000112 | LATIN CAPITAL LETTER E WITH MACRON
     C8 |  0000010C | LATIN CAPITAL LETTER C WITH CARON
     C9 |  000000C9 | LATIN CAPITAL LETTER E WITH ACUTE
     CA |  00000179 | LATIN CAPITAL LETTER Z WITH ACUTE
     CB |  00000116 | LATIN CAPITAL LETTER E WITH DOT ABOVE
     CC |  00000122 | LATIN CAPITAL LETTER G WITH CEDILLA
     CD |  00000136 | LATIN CAPITAL LETTER K WITH CEDILLA
     CE |  0000012A | LATIN CAPITAL LETTER I WITH MACRON
     CF |  0000013B | LATIN CAPITAL LETTER L WITH CEDILLA
     D0 |  00000160 | LATIN CAPITAL LETTER S WITH CARON
     D1 |  00000143 | LATIN CAPITAL LETTER N WITH ACUTE
     D2 |  00000145 | LATIN CAPITAL LETTER N WITH CEDILLA
     D3 |  000000D3 | LATIN CAPITAL LETTER O WITH ACUTE
     D4 |  0000014C | LATIN CAPITAL LETTER O WITH MACRON
     D5 |  000000D5 | LATIN CAPITAL LETTER O WITH TILDE
     D6 |  000000D6 | LATIN CAPITAL LETTER O WITH DIAERESIS
     D7 |  000000D7 | MULTIPLICATION SIGN
     D8 |  00000172 | LATIN CAPITAL LETTER U WITH OGONEK
     D9 |  00000141 | LATIN CAPITAL LETTER L WITH STROKE
     DA |  0000015A | LATIN CAPITAL LETTER S WITH ACUTE
     DB |  0000016A | LATIN CAPITAL LETTER U WITH MACRON
     DC |  000000DC | LATIN CAPITAL LETTER U WITH DIAERESIS
     DD |  0000017B | LATIN CAPITAL LETTER Z WITH DOT ABOVE
     DE |  0000017D | LATIN CAPITAL LETTER Z WITH CARON
     DF |  000000DF | LATIN SMALL LETTER SHARP S (German)
     E0 |  00000105 | LATIN SMALL LETTER A WITH OGONEK
     E1 |  0000012F | LATIN SMALL LETTER I WITH OGONEK
     E2 |  00000101 | LATIN SMALL LETTER A WITH MACRON
     E3 |  00000107 | LATIN SMALL LETTER C WITH ACUTE
     E4 |  000000E4 | LATIN SMALL LETTER A WITH DIAERESIS
     E5 |  000000E5 | LATIN SMALL LETTER A WITH RING ABOVE
     E6 |  00000119 | LATIN SMALL LETTER E WITH OGONEK
     E7 |  00000113 | LATIN SMALL LETTER E WITH MACRON
     E8 |  0000010D | LATIN SMALL LETTER C WITH CARON
     E9 |  000000E9 | LATIN SMALL LETTER E WITH ACUTE
     EA |  0000017A | LATIN SMALL LETTER Z WITH ACUTE
     EB |  00000117 | LATIN SMALL LETTER E WITH DOT ABOVE
     EC |  00000123 | LATIN SMALL LETTER G WITH CEDILLA
     ED |  00000137 | LATIN SMALL LETTER K WITH CEDILLA
     EE |  0000012B | LATIN SMALL LETTER I WITH MACRON
     EF |  0000013C | LATIN SMALL LETTER L WITH CEDILLA
     F0 |  00000161 | LATIN SMALL LETTER S WITH CARON
     F1 |  00000144 | LATIN SMALL LETTER N WITH ACUTE
     F2 |  00000146 | LATIN SMALL LETTER N WITH CEDILLA
     F3 |  000000F3 | LATIN SMALL LETTER O WITH ACUTE
     F4 |  0000014D | LATIN SMALL LETTER O WITH MACRON
     F5 |  000000F5 | LATIN SMALL LETTER O WITH TILDE
     F6 |  000000F6 | LATIN SMALL LETTER O WITH DIAERESIS
     F7 |  000000F7 | DIVISION SIGN
     F8 |  00000173 | LATIN SMALL LETTER U WITH OGONEK
     F9 |  00000142 | LATIN SMALL LETTER L WITH STROKE
     FA |  0000015B | LATIN SMALL LETTER S WITH ACUTE
     FB |  0000016B | LATIN SMALL LETTER U WITH MACRON
     FC |  000000FC | LATIN SMALL LETTER U WITH DIAERESIS
     FD |  0000017C | LATIN SMALL LETTER Z WITH DOT ABOVE
     FE |  0000017E | LATIN SMALL LETTER Z WITH CARON
     FF |  000002D9 | DOT ABOVE (Mandarin Chinese light tone)
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/CSN_369103.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for CSN_369103.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::CSN_369103;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x0004,
     0x0005,
     0x0006,
     0x0007,
     0x0008,
     0x0009,
     0x000a,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x0014,
     0x0015,
     0x0016,
     0x0017,
     0x0018,
     0x0019,
     0x001a,
     0x001b,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0020,
     0x0021,
     0x0022,
     0x0023,
     0x00a4,
     0x0025,
     0x0026,
     0x0027,
     0x0028,
     0x0029,
     0x002a,
     0x002b,
     0x002c,
     0x002d,
     0x002e,
     0x002f,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x003a,
     0x003b,
     0x003c,
     0x003d,
     0x003e,
     0x003f,
     0x0040,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x005b,
     0x005c,
     0x005d,
     0x005e,
     0x005f,
     0x0060,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x007b,
     0x007c,
     0x007d,
     0x007e,
     0x007f,
     0x0080,
     0x0081,
     0x0082,
     0x0083,
     0x0084,
     0x0085,
     0x0086,
     0x0087,
     0x0088,
     0x0089,
     0x008a,
     0x008b,
     0x008c,
     0x008d,
     0x008e,
     0x008f,
     0x0090,
     0x0091,
     0x0092,
     0x0093,
     0x0094,
     0x0095,
     0x0096,
     0x0097,
     0x0098,
     0x0099,
     0x009a,
     0x009b,
     0x009c,
     0x009d,
     0x009e,
     0x009f,
     0x00a0,
     0x0104,
     0x02d8,
     0x0141,
     0x0024,
     0x013d,
     0x015a,
     0x00a7,
     0x00a8,
     0x0160,
     0x015e,
     0x0164,
     0x0179,
     0x00ad,
     0x017d,
     0x017b,
     0x00b0,
     0x0105,
     0x02db,
     0x0142,
     0x00b4,
     0x013e,
     0x015b,
     0x02c7,
     0x00b8,
     0x0161,
     0x015f,
     0x0165,
     0x017a,
     0x02dd,
     0x017e,
     0x017c,
     0x0154,
     0x00c1,
     0x00c2,
     0x0102,
     0x00c4,
     0x0139,
     0x0106,
     0x00c7,
     0x010c,
     0x00c9,
     0x0118,
     0x00cb,
     0x011a,
     0x00cd,
     0x00ce,
     0x010e,
     0x0110,
     0x0143,
     0x0147,
     0x00d3,
     0x00d4,
     0x0150,
     0x00d6,
     0x00d7,
     0x0158,
     0x016e,
     0x00da,
     0x0170,
     0x00dc,
     0x00dd,
     0x0162,
     0x00df,
     0x0155,
     0x00e1,
     0x00e2,
     0x0103,
     0x00e4,
     0x013a,
     0x0107,
     0x00e7,
     0x010d,
     0x00e9,
     0x0119,
     0x00eb,
     0x011b,
     0x00ed,
     0x00ee,
     0x010f,
     0x0111,
     0x0144,
     0x0148,
     0x00f3,
     0x00f4,
     0x0151,
     0x00f6,
     0x00f7,
     0x0159,
     0x016f,
     0x00fa,
     0x0171,
     0x00fc,
     0x00fd,
     0x0163,
     0x02d9,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\x04",
     "\x05",
     "\x06",
     "\x07",
     "\x08",
     "\x09",
     "\x0a",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\x14",
     "\x15",
     "\x16",
     "\x17",
     "\x18",
     "\x19",
     "\x1a",
     "\x1b",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\x20",
     "\x21",
     "\x22",
     "\x23",
     "\xc2\xa4",
     "\x25",
     "\x26",
     "\x27",
     "\x28",
     "\x29",
     "\x2a",
     "\x2b",
     "\x2c",
     "\x2d",
     "\x2e",
     "\x2f",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\x3a",
     "\x3b",
     "\x3c",
     "\x3d",
     "\x3e",
     "\x3f",
     "\x40",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\x5b",
     "\x5c",
     "\x5d",
     "\x5e",
     "\x5f",
     "\x60",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\x7b",
     "\x7c",
     "\x7d",
     "\x7e",
     "\x7f",
     "\xc2\x80",
     "\xc2\x81",
     "\xc2\x82",
     "\xc2\x83",
     "\xc2\x84",
     "\xc2\x85",
     "\xc2\x86",
     "\xc2\x87",
     "\xc2\x88",
     "\xc2\x89",
     "\xc2\x8a",
     "\xc2\x8b",
     "\xc2\x8c",
     "\xc2\x8d",
     "\xc2\x8e",
     "\xc2\x8f",
     "\xc2\x90",
     "\xc2\x91",
     "\xc2\x92",
     "\xc2\x93",
     "\xc2\x94",
     "\xc2\x95",
     "\xc2\x96",
     "\xc2\x97",
     "\xc2\x98",
     "\xc2\x99",
     "\xc2\x9a",
     "\xc2\x9b",
     "\xc2\x9c",
     "\xc2\x9d",
     "\xc2\x9e",
     "\xc2\x9f",
     "\xc2\xa0",
     "\xc4\x84",
     "\xcb\x98",
     "\xc5\x81",
     "\x24",
     "\xc4\xbd",
     "\xc5\x9a",
     "\xc2\xa7",
     "\xc2\xa8",
     "\xc5\xa0",
     "\xc5\x9e",
     "\xc5\xa4",
     "\xc5\xb9",
     "\xc2\xad",
     "\xc5\xbd",
     "\xc5\xbb",
     "\xc2\xb0",
     "\xc4\x85",
     "\xcb\x9b",
     "\xc5\x82",
     "\xc2\xb4",
     "\xc4\xbe",
     "\xc5\x9b",
     "\xcb\x87",
     "\xc2\xb8",
     "\xc5\xa1",
     "\xc5\x9f",
     "\xc5\xa5",
     "\xc5\xba",
     "\xcb\x9d",
     "\xc5\xbe",
     "\xc5\xbc",
     "\xc5\x94",
     "\xc3\x81",
     "\xc3\x82",
     "\xc4\x82",
     "\xc3\x84",
     "\xc4\xb9",
     "\xc4\x86",
     "\xc3\x87",
     "\xc4\x8c",
     "\xc3\x89",
     "\xc4\x98",
     "\xc3\x8b",
     "\xc4\x9a",
     "\xc3\x8d",
     "\xc3\x8e",
     "\xc4\x8e",
     "\xc4\x90",
     "\xc5\x83",
     "\xc5\x87",
     "\xc3\x93",
     "\xc3\x94",
     "\xc5\x90",
     "\xc3\x96",
     "\xc3\x97",
     "\xc5\x98",
     "\xc5\xae",
     "\xc3\x9a",
     "\xc5\xb0",
     "\xc3\x9c",
     "\xc3\x9d",
     "\xc5\xa2",
     "\xc3\x9f",
     "\xc5\x95",
     "\xc3\xa1",
     "\xc3\xa2",
     "\xc4\x83",
     "\xc3\xa4",
     "\xc4\xba",
     "\xc4\x87",
     "\xc3\xa7",
     "\xc4\x8d",
     "\xc3\xa9",
     "\xc4\x99",
     "\xc3\xab",
     "\xc4\x9b",
     "\xc3\xad",
     "\xc3\xae",
     "\xc4\x8f",
     "\xc4\x91",
     "\xc5\x84",
     "\xc5\x88",
     "\xc3\xb3",
     "\xc3\xb4",
     "\xc5\x91",
     "\xc3\xb6",
     "\xc3\xb7",
     "\xc5\x99",
     "\xc5\xaf",
     "\xc3\xba",
     "\xc5\xb1",
     "\xc3\xbc",
     "\xc3\xbd",
     "\xc5\xa3",
     "\xcb\x99",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x04",
     0x00000005 => "\x05",
     0x00000006 => "\x06",
     0x00000007 => "\x07",
     0x00000008 => "\x08",
     0x00000009 => "\x09",
     0x0000000a => "\x0a",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x14",
     0x00000015 => "\x15",
     0x00000016 => "\x16",
     0x00000017 => "\x17",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x1a",
     0x0000001b => "\x1b",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x20",
     0x00000021 => "\x21",
     0x00000022 => "\x22",
     0x00000023 => "\x23",
     0x00000024 => "\xa4",
     0x00000025 => "\x25",
     0x00000026 => "\x26",
     0x00000027 => "\x27",
     0x00000028 => "\x28",
     0x00000029 => "\x29",
     0x0000002a => "\x2a",
     0x0000002b => "\x2b",
     0x0000002c => "\x2c",
     0x0000002d => "\x2d",
     0x0000002e => "\x2e",
     0x0000002f => "\x2f",
     0x00000030 => "\x30",
     0x00000031 => "\x31",
     0x00000032 => "\x32",
     0x00000033 => "\x33",
     0x00000034 => "\x34",
     0x00000035 => "\x35",
     0x00000036 => "\x36",
     0x00000037 => "\x37",
     0x00000038 => "\x38",
     0x00000039 => "\x39",
     0x0000003a => "\x3a",
     0x0000003b => "\x3b",
     0x0000003c => "\x3c",
     0x0000003d => "\x3d",
     0x0000003e => "\x3e",
     0x0000003f => "\x3f",
     0x00000040 => "\x40",
     0x00000041 => "\x41",
     0x00000042 => "\x42",
     0x00000043 => "\x43",
     0x00000044 => "\x44",
     0x00000045 => "\x45",
     0x00000046 => "\x46",
     0x00000047 => "\x47",
     0x00000048 => "\x48",
     0x00000049 => "\x49",
     0x0000004a => "\x4a",
     0x0000004b => "\x4b",
     0x0000004c => "\x4c",
     0x0000004d => "\x4d",
     0x0000004e => "\x4e",
     0x0000004f => "\x4f",
     0x00000050 => "\x50",
     0x00000051 => "\x51",
     0x00000052 => "\x52",
     0x00000053 => "\x53",
     0x00000054 => "\x54",
     0x00000055 => "\x55",
     0x00000056 => "\x56",
     0x00000057 => "\x57",
     0x00000058 => "\x58",
     0x00000059 => "\x59",
     0x0000005a => "\x5a",
     0x0000005b => "\x5b",
     0x0000005c => "\x5c",
     0x0000005d => "\x5d",
     0x0000005e => "\x5e",
     0x0000005f => "\x5f",
     0x00000060 => "\x60",
     0x00000061 => "\x61",
     0x00000062 => "\x62",
     0x00000063 => "\x63",
     0x00000064 => "\x64",
     0x00000065 => "\x65",
     0x00000066 => "\x66",
     0x00000067 => "\x67",
     0x00000068 => "\x68",
     0x00000069 => "\x69",
     0x0000006a => "\x6a",
     0x0000006b => "\x6b",
     0x0000006c => "\x6c",
     0x0000006d => "\x6d",
     0x0000006e => "\x6e",
     0x0000006f => "\x6f",
     0x00000070 => "\x70",
     0x00000071 => "\x71",
     0x00000072 => "\x72",
     0x00000073 => "\x73",
     0x00000074 => "\x74",
     0x00000075 => "\x75",
     0x00000076 => "\x76",
     0x00000077 => "\x77",
     0x00000078 => "\x78",
     0x00000079 => "\x79",
     0x0000007a => "\x7a",
     0x0000007b => "\x7b",
     0x0000007c => "\x7c",
     0x0000007d => "\x7d",
     0x0000007e => "\x7e",
     0x0000007f => "\x7f",
     0x00000080 => "\x80",
     0x00000081 => "\x81",
     0x00000082 => "\x82",
     0x00000083 => "\x83",
     0x00000084 => "\x84",
     0x00000085 => "\x85",
     0x00000086 => "\x86",
     0x00000087 => "\x87",
     0x00000088 => "\x88",
     0x00000089 => "\x89",
     0x0000008a => "\x8a",
     0x0000008b => "\x8b",
     0x0000008c => "\x8c",
     0x0000008d => "\x8d",
     0x0000008e => "\x8e",
     0x0000008f => "\x8f",
     0x00000090 => "\x90",
     0x00000091 => "\x91",
     0x00000092 => "\x92",
     0x00000093 => "\x93",
     0x00000094 => "\x94",
     0x00000095 => "\x95",
     0x00000096 => "\x96",
     0x00000097 => "\x97",
     0x00000098 => "\x98",
     0x00000099 => "\x99",
     0x0000009a => "\x9a",
     0x0000009b => "\x9b",
     0x0000009c => "\x9c",
     0x0000009d => "\x9d",
     0x0000009e => "\x9e",
     0x0000009f => "\x9f",
     0x000000a0 => "\xa0",
     0x000000a4 => "\x24",
     0x000000a7 => "\xa7",
     0x000000a8 => "\xa8",
     0x000000ad => "\xad",
     0x000000b0 => "\xb0",
     0x000000b4 => "\xb4",
     0x000000b8 => "\xb8",
     0x000000c1 => "\xc1",
     0x000000c2 => "\xc2",
     0x000000c4 => "\xc4",
     0x000000c7 => "\xc7",
     0x000000c9 => "\xc9",
     0x000000cb => "\xcb",
     0x000000cd => "\xcd",
     0x000000ce => "\xce",
     0x000000d3 => "\xd3",
     0x000000d4 => "\xd4",
     0x000000d6 => "\xd6",
     0x000000d7 => "\xd7",
     0x000000da => "\xda",
     0x000000dc => "\xdc",
     0x000000dd => "\xdd",
     0x000000df => "\xdf",
     0x000000e1 => "\xe1",
     0x000000e2 => "\xe2",
     0x000000e4 => "\xe4",
     0x000000e7 => "\xe7",
     0x000000e9 => "\xe9",
     0x000000eb => "\xeb",
     0x000000ed => "\xed",
     0x000000ee => "\xee",
     0x000000f3 => "\xf3",
     0x000000f4 => "\xf4",
     0x000000f6 => "\xf6",
     0x000000f7 => "\xf7",
     0x000000fa => "\xfa",
     0x000000fc => "\xfc",
     0x000000fd => "\xfd",
     0x00000102 => "\xc3",
     0x00000103 => "\xe3",
     0x00000104 => "\xa1",
     0x00000105 => "\xb1",
     0x00000106 => "\xc6",
     0x00000107 => "\xe6",
     0x0000010c => "\xc8",
     0x0000010d => "\xe8",
     0x0000010e => "\xcf",
     0x0000010f => "\xef",
     0x00000110 => "\xd0",
     0x00000111 => "\xf0",
     0x00000118 => "\xca",
     0x00000119 => "\xea",
     0x0000011a => "\xcc",
     0x0000011b => "\xec",
     0x00000139 => "\xc5",
     0x0000013a => "\xe5",
     0x0000013d => "\xa5",
     0x0000013e => "\xb5",
     0x00000141 => "\xa3",
     0x00000142 => "\xb3",
     0x00000143 => "\xd1",
     0x00000144 => "\xf1",
     0x00000147 => "\xd2",
     0x00000148 => "\xf2",
     0x00000150 => "\xd5",
     0x00000151 => "\xf5",
     0x00000154 => "\xc0",
     0x00000155 => "\xe0",
     0x00000158 => "\xd8",
     0x00000159 => "\xf8",
     0x0000015a => "\xa6",
     0x0000015b => "\xb6",
     0x0000015e => "\xaa",
     0x0000015f => "\xba",
     0x00000160 => "\xa9",
     0x00000161 => "\xb9",
     0x00000162 => "\xde",
     0x00000163 => "\xfe",
     0x00000164 => "\xab",
     0x00000165 => "\xbb",
     0x0000016e => "\xd9",
     0x0000016f => "\xf9",
     0x00000170 => "\xdb",
     0x00000171 => "\xfb",
     0x00000179 => "\xac",
     0x0000017a => "\xbc",
     0x0000017b => "\xaf",
     0x0000017c => "\xbf",
     0x0000017d => "\xae",
     0x0000017e => "\xbe",
     0x000002c7 => "\xb7",
     0x000002d8 => "\xa2",
     0x000002d9 => "\xff",
     0x000002db => "\xb2",
     0x000002dd => "\xbd",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::CSN_369103 - Conversion routines for CSN_369103
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for CSN_369103.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
  repertoiremap: mnemonic,ds
   source: ECMA registry
  alias ISO-IR-139
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  00000004 | END OF TRANSMISSION (EOT)
     05 |  00000005 | ENQUIRY (ENQ)
     06 |  00000006 | ACKNOWLEDGE (ACK)
     07 |  00000007 | BELL (BEL)
     08 |  00000008 | BACKSPACE (BS)
     09 |  00000009 | CHARACTER TABULATION (HT)
     0A |  0000000A | LINE FEED (LF)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  00000014 | DEVICE CONTROL FOUR (DC4)
     15 |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     16 |  00000016 | SYNCHRONOUS IDLE (SYN)
     17 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  0000001A | SUBSTITUTE (SUB)
     1B |  0000001B | ESCAPE (ESC)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000020 | SPACE
     21 |  00000021 | EXCLAMATION MARK
     22 |  00000022 | QUOTATION MARK
     23 |  00000023 | NUMBER SIGN
     24 |  000000A4 | CURRENCY SIGN
     25 |  00000025 | PERCENT SIGN
     26 |  00000026 | AMPERSAND
     27 |  00000027 | APOSTROPHE
     28 |  00000028 | LEFT PARENTHESIS
     29 |  00000029 | RIGHT PARENTHESIS
     2A |  0000002A | ASTERISK
     2B |  0000002B | PLUS SIGN
     2C |  0000002C | COMMA
     2D |  0000002D | HYPHEN-MINUS
     2E |  0000002E | FULL STOP
     2F |  0000002F | SOLIDUS
     30 |  00000030 | DIGIT ZERO
     31 |  00000031 | DIGIT ONE
     32 |  00000032 | DIGIT TWO
     33 |  00000033 | DIGIT THREE
     34 |  00000034 | DIGIT FOUR
     35 |  00000035 | DIGIT FIVE
     36 |  00000036 | DIGIT SIX
     37 |  00000037 | DIGIT SEVEN
     38 |  00000038 | DIGIT EIGHT
     39 |  00000039 | DIGIT NINE
     3A |  0000003A | COLON
     3B |  0000003B | SEMICOLON
     3C |  0000003C | LESS-THAN SIGN
     3D |  0000003D | EQUALS SIGN
     3E |  0000003E | GREATER-THAN SIGN
     3F |  0000003F | QUESTION MARK
     40 |  00000040 | COMMERCIAL AT
     41 |  00000041 | LATIN CAPITAL LETTER A
     42 |  00000042 | LATIN CAPITAL LETTER B
     43 |  00000043 | LATIN CAPITAL LETTER C
     44 |  00000044 | LATIN CAPITAL LETTER D
     45 |  00000045 | LATIN CAPITAL LETTER E
     46 |  00000046 | LATIN CAPITAL LETTER F
     47 |  00000047 | LATIN CAPITAL LETTER G
     48 |  00000048 | LATIN CAPITAL LETTER H
     49 |  00000049 | LATIN CAPITAL LETTER I
     4A |  0000004A | LATIN CAPITAL LETTER J
     4B |  0000004B | LATIN CAPITAL LETTER K
     4C |  0000004C | LATIN CAPITAL LETTER L
     4D |  0000004D | LATIN CAPITAL LETTER M
     4E |  0000004E | LATIN CAPITAL LETTER N
     4F |  0000004F | LATIN CAPITAL LETTER O
     50 |  00000050 | LATIN CAPITAL LETTER P
     51 |  00000051 | LATIN CAPITAL LETTER Q
     52 |  00000052 | LATIN CAPITAL LETTER R
     53 |  00000053 | LATIN CAPITAL LETTER S
     54 |  00000054 | LATIN CAPITAL LETTER T
     55 |  00000055 | LATIN CAPITAL LETTER U
     56 |  00000056 | LATIN CAPITAL LETTER V
     57 |  00000057 | LATIN CAPITAL LETTER W
     58 |  00000058 | LATIN CAPITAL LETTER X
     59 |  00000059 | LATIN CAPITAL LETTER Y
     5A |  0000005A | LATIN CAPITAL LETTER Z
     5B |  0000005B | LEFT SQUARE BRACKET
     5C |  0000005C | REVERSE SOLIDUS
     5D |  0000005D | RIGHT SQUARE BRACKET
     5E |  0000005E | CIRCUMFLEX ACCENT
     5F |  0000005F | LOW LINE
     60 |  00000060 | GRAVE ACCENT
     61 |  00000061 | LATIN SMALL LETTER A
     62 |  00000062 | LATIN SMALL LETTER B
     63 |  00000063 | LATIN SMALL LETTER C
     64 |  00000064 | LATIN SMALL LETTER D
     65 |  00000065 | LATIN SMALL LETTER E
     66 |  00000066 | LATIN SMALL LETTER F
     67 |  00000067 | LATIN SMALL LETTER G
     68 |  00000068 | LATIN SMALL LETTER H
     69 |  00000069 | LATIN SMALL LETTER I
     6A |  0000006A | LATIN SMALL LETTER J
     6B |  0000006B | LATIN SMALL LETTER K
     6C |  0000006C | LATIN SMALL LETTER L
     6D |  0000006D | LATIN SMALL LETTER M
     6E |  0000006E | LATIN SMALL LETTER N
     6F |  0000006F | LATIN SMALL LETTER O
     70 |  00000070 | LATIN SMALL LETTER P
     71 |  00000071 | LATIN SMALL LETTER Q
     72 |  00000072 | LATIN SMALL LETTER R
     73 |  00000073 | LATIN SMALL LETTER S
     74 |  00000074 | LATIN SMALL LETTER T
     75 |  00000075 | LATIN SMALL LETTER U
     76 |  00000076 | LATIN SMALL LETTER V
     77 |  00000077 | LATIN SMALL LETTER W
     78 |  00000078 | LATIN SMALL LETTER X
     79 |  00000079 | LATIN SMALL LETTER Y
     7A |  0000007A | LATIN SMALL LETTER Z
     7B |  0000007B | LEFT CURLY BRACKET
     7C |  0000007C | VERTICAL LINE
     7D |  0000007D | RIGHT CURLY BRACKET
     7E |  0000007E | TILDE
     7F |  0000007F | DELETE (DEL)
     80 |  00000080 | PADDING CHARACTER (PAD)
     81 |  00000081 | HIGH OCTET PRESET (HOP)
     82 |  00000082 | BREAK PERMITTED HERE (BPH)
     83 |  00000083 | NO BREAK HERE (NBH)
     84 |  00000084 | INDEX (IND)
     85 |  00000085 | NEXT LINE (NEL)
     86 |  00000086 | START OF SELECTED AREA (SSA)
     87 |  00000087 | END OF SELECTED AREA (ESA)
     88 |  00000088 | CHARACTER TABULATION SET (HTS)
     89 |  00000089 | CHARACTER TABULATION WITH JUSTIFICATION (HTJ)
     8A |  0000008A | LINE TABULATION SET (VTS)
     8B |  0000008B | PARTIAL LINE FORWARD (PLD)
     8C |  0000008C | PARTIAL LINE BACKWARD (PLU)
     8D |  0000008D | REVERSE LINE FEED (RI)
     8E |  0000008E | SINGLE-SHIFT TWO (SS2)
     8F |  0000008F | SINGLE-SHIFT THREE (SS3)
     90 |  00000090 | DEVICE CONTROL STRING (DCS)
     91 |  00000091 | PRIVATE USE ONE (PU1)
     92 |  00000092 | PRIVATE USE TWO (PU2)
     93 |  00000093 | SET TRANSMIT STATE (STS)
     94 |  00000094 | CANCEL CHARACTER (CCH)
     95 |  00000095 | MESSAGE WAITING (MW)
     96 |  00000096 | START OF GUARDED AREA (SPA)
     97 |  00000097 | END OF GUARDED AREA (EPA)
     98 |  00000098 | START OF STRING (SOS)
     99 |  00000099 | SINGLE GRAPHIC CHARACTER INTRODUCER (SGCI)
     9A |  0000009A | SINGLE CHARACTER INTRODUCER (SCI)
     9B |  0000009B | CONTROL SEQUENCE INTRODUCER (CSI)
     9C |  0000009C | STRING TERMINATOR (ST)
     9D |  0000009D | OPERATING SYSTEM COMMAND (OSC)
     9E |  0000009E | PRIVACY MESSAGE (PM)
     9F |  0000009F | APPLICATION PROGRAM COMMAND (APC)
     A0 |  000000A0 | NO-BREAK SPACE
     A1 |  00000104 | LATIN CAPITAL LETTER A WITH OGONEK
     A2 |  000002D8 | BREVE
     A3 |  00000141 | LATIN CAPITAL LETTER L WITH STROKE
     A4 |  00000024 | DOLLAR SIGN
     A5 |  0000013D | LATIN CAPITAL LETTER L WITH CARON
     A6 |  0000015A | LATIN CAPITAL LETTER S WITH ACUTE
     A7 |  000000A7 | SECTION SIGN
     A8 |  000000A8 | DIAERESIS
     A9 |  00000160 | LATIN CAPITAL LETTER S WITH CARON
     AA |  0000015E | LATIN CAPITAL LETTER S WITH CEDILLA
     AB |  00000164 | LATIN CAPITAL LETTER T WITH CARON
     AC |  00000179 | LATIN CAPITAL LETTER Z WITH ACUTE
     AD |  000000AD | SOFT HYPHEN
     AE |  0000017D | LATIN CAPITAL LETTER Z WITH CARON
     AF |  0000017B | LATIN CAPITAL LETTER Z WITH DOT ABOVE
     B0 |  000000B0 | DEGREE SIGN
     B1 |  00000105 | LATIN SMALL LETTER A WITH OGONEK
     B2 |  000002DB | OGONEK
     B3 |  00000142 | LATIN SMALL LETTER L WITH STROKE
     B4 |  000000B4 | ACUTE ACCENT
     B5 |  0000013E | LATIN SMALL LETTER L WITH CARON
     B6 |  0000015B | LATIN SMALL LETTER S WITH ACUTE
     B7 |  000002C7 | CARON (Mandarin Chinese third tone)
     B8 |  000000B8 | CEDILLA
     B9 |  00000161 | LATIN SMALL LETTER S WITH CARON
     BA |  0000015F | LATIN SMALL LETTER S WITH CEDILLA
     BB |  00000165 | LATIN SMALL LETTER T WITH CARON
     BC |  0000017A | LATIN SMALL LETTER Z WITH ACUTE
     BD |  000002DD | DOUBLE ACUTE ACCENT
     BE |  0000017E | LATIN SMALL LETTER Z WITH CARON
     BF |  0000017C | LATIN SMALL LETTER Z WITH DOT ABOVE
     C0 |  00000154 | LATIN CAPITAL LETTER R WITH ACUTE
     C1 |  000000C1 | LATIN CAPITAL LETTER A WITH ACUTE
     C2 |  000000C2 | LATIN CAPITAL LETTER A WITH CIRCUMFLEX
     C3 |  00000102 | LATIN CAPITAL LETTER A WITH BREVE
     C4 |  000000C4 | LATIN CAPITAL LETTER A WITH DIAERESIS
     C5 |  00000139 | LATIN CAPITAL LETTER L WITH ACUTE
     C6 |  00000106 | LATIN CAPITAL LETTER C WITH ACUTE
     C7 |  000000C7 | LATIN CAPITAL LETTER C WITH CEDILLA
     C8 |  0000010C | LATIN CAPITAL LETTER C WITH CARON
     C9 |  000000C9 | LATIN CAPITAL LETTER E WITH ACUTE
     CA |  00000118 | LATIN CAPITAL LETTER E WITH OGONEK
     CB |  000000CB | LATIN CAPITAL LETTER E WITH DIAERESIS
     CC |  0000011A | LATIN CAPITAL LETTER E WITH CARON
     CD |  000000CD | LATIN CAPITAL LETTER I WITH ACUTE
     CE |  000000CE | LATIN CAPITAL LETTER I WITH CIRCUMFLEX
     CF |  0000010E | LATIN CAPITAL LETTER D WITH CARON
     D0 |  00000110 | LATIN CAPITAL LETTER D WITH STROKE
     D1 |  00000143 | LATIN CAPITAL LETTER N WITH ACUTE
     D2 |  00000147 | LATIN CAPITAL LETTER N WITH CARON
     D3 |  000000D3 | LATIN CAPITAL LETTER O WITH ACUTE
     D4 |  000000D4 | LATIN CAPITAL LETTER O WITH CIRCUMFLEX
     D5 |  00000150 | LATIN CAPITAL LETTER O WITH DOUBLE ACUTE
     D6 |  000000D6 | LATIN CAPITAL LETTER O WITH DIAERESIS
     D7 |  000000D7 | MULTIPLICATION SIGN
     D8 |  00000158 | LATIN CAPITAL LETTER R WITH CARON
     D9 |  0000016E | LATIN CAPITAL LETTER U WITH RING ABOVE
     DA |  000000DA | LATIN CAPITAL LETTER U WITH ACUTE
     DB |  00000170 | LATIN CAPITAL LETTER U WITH DOUBLE ACUTE
     DC |  000000DC | LATIN CAPITAL LETTER U WITH DIAERESIS
     DD |  000000DD | LATIN CAPITAL LETTER Y WITH ACUTE
     DE |  00000162 | LATIN CAPITAL LETTER T WITH CEDILLA
     DF |  000000DF | LATIN SMALL LETTER SHARP S (German)
     E0 |  00000155 | LATIN SMALL LETTER R WITH ACUTE
     E1 |  000000E1 | LATIN SMALL LETTER A WITH ACUTE
     E2 |  000000E2 | LATIN SMALL LETTER A WITH CIRCUMFLEX
     E3 |  00000103 | LATIN SMALL LETTER A WITH BREVE
     E4 |  000000E4 | LATIN SMALL LETTER A WITH DIAERESIS
     E5 |  0000013A | LATIN SMALL LETTER L WITH ACUTE
     E6 |  00000107 | LATIN SMALL LETTER C WITH ACUTE
     E7 |  000000E7 | LATIN SMALL LETTER C WITH CEDILLA
     E8 |  0000010D | LATIN SMALL LETTER C WITH CARON
     E9 |  000000E9 | LATIN SMALL LETTER E WITH ACUTE
     EA |  00000119 | LATIN SMALL LETTER E WITH OGONEK
     EB |  000000EB | LATIN SMALL LETTER E WITH DIAERESIS
     EC |  0000011B | LATIN SMALL LETTER E WITH CARON
     ED |  000000ED | LATIN SMALL LETTER I WITH ACUTE
     EE |  000000EE | LATIN SMALL LETTER I WITH CIRCUMFLEX
     EF |  0000010F | LATIN SMALL LETTER D WITH CARON
     F0 |  00000111 | LATIN SMALL LETTER D WITH STROKE
     F1 |  00000144 | LATIN SMALL LETTER N WITH ACUTE
     F2 |  00000148 | LATIN SMALL LETTER N WITH CARON
     F3 |  000000F3 | LATIN SMALL LETTER O WITH ACUTE
     F4 |  000000F4 | LATIN SMALL LETTER O WITH CIRCUMFLEX
     F5 |  00000151 | LATIN SMALL LETTER O WITH DOUBLE ACUTE
     F6 |  000000F6 | LATIN SMALL LETTER O WITH DIAERESIS
     F7 |  000000F7 | DIVISION SIGN
     F8 |  00000159 | LATIN SMALL LETTER R WITH CARON
     F9 |  0000016F | LATIN SMALL LETTER U WITH RING ABOVE
     FA |  000000FA | LATIN SMALL LETTER U WITH ACUTE
     FB |  00000171 | LATIN SMALL LETTER U WITH DOUBLE ACUTE
     FC |  000000FC | LATIN SMALL LETTER U WITH DIAERESIS
     FD |  000000FD | LATIN SMALL LETTER Y WITH ACUTE
     FE |  00000163 | LATIN SMALL LETTER T WITH CEDILLA
     FF |  000002D9 | DOT ABOVE (Mandarin Chinese light tone)
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/CWI.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for CWI.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::CWI;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x0004,
     0x0005,
     0x0006,
     0x0007,
     0x0008,
     0x0009,
     0x000a,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x0014,
     0x0015,
     0x0016,
     0x0017,
     0x0018,
     0x0019,
     0x001a,
     0x001b,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0020,
     0x0021,
     0x0022,
     0x0023,
     0x0024,
     0x0025,
     0x0026,
     0x0027,
     0x0028,
     0x0029,
     0x002a,
     0x002b,
     0x002c,
     0x002d,
     0x002e,
     0x002f,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x003a,
     0x003b,
     0x003c,
     0x003d,
     0x003e,
     0x003f,
     0x0040,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x005b,
     0x005c,
     0x005d,
     0x005e,
     0x005f,
     0x0060,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x007b,
     0x007c,
     0x007d,
     0x007e,
     0x007f,
     0x00c7,
     0x00fc,
     0x00e9,
     0x00e2,
     0x00e4,
     0x00e0,
     0x00e5,
     0x00e7,
     0x00ea,
     0x00eb,
     0x00e8,
     0x00ef,
     0x00ee,
     0x00cd,
     0x00c4,
     0x00c1,
     0x00c9,
     0x00e6,
     0x00c6,
     0x0151,
     0x00f6,
     0x00d3,
     0x0171,
     0x00da,
     0x0170,
     0x00d6,
     0x00dc,
     0x00a2,
     0x00a3,
     0x00a5,
     0x20a7,
     0xe01f,
     0x00e1,
     0x00ed,
     0x00f3,
     0x00fa,
     0x00f1,
     0x00d1,
     0x00aa,
     0x0150,
     0x00bf,
     0x2310,
     0x00ac,
     0x00bd,
     0x00bc,
     0x00a1,
     0x00ab,
     0x00bb,
     0x2591,
     0x2592,
     0x2593,
     0x2502,
     0x2524,
     0x2561,
     0x2562,
     0x2556,
     0x2555,
     0x2563,
     0x2551,
     0x2557,
     0x255d,
     0x255c,
     0x255b,
     0x2510,
     0x2514,
     0x2534,
     0x252c,
     0x251c,
     0x2500,
     0x253c,
     0x255e,
     0x255f,
     0x255a,
     0x2554,
     0x2569,
     0x2566,
     0x2560,
     0x2550,
     0x256c,
     0x2567,
     0x2568,
     0x2564,
     0x2565,
     0x2559,
     0x2558,
     0x2552,
     0x2553,
     0x256b,
     0x256a,
     0x2518,
     0x250c,
     0x2588,
     0x2584,
     0x258c,
     0x2590,
     0x2580,
     0x03b1,
     0x03b2,
     0x0393,
     0x03c0,
     0x03a3,
     0x03c3,
     0x03bc,
     0x03c4,
     0x03a6,
     0x0398,
     0x03a9,
     0x03b4,
     0x221e,
     0x2205,
     0x03b5,
     0x2229,
     0x2261,
     0x00b1,
     0x2265,
     0x2264,
     0x2320,
     0x2321,
     0x00f7,
     0x2248,
     0x2218,
     0x00b7,
     0x2022,
     0x221a,
     0x207f,
     0x00b2,
     0x25a0,
     0x00a0,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\x04",
     "\x05",
     "\x06",
     "\x07",
     "\x08",
     "\x09",
     "\x0a",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\x14",
     "\x15",
     "\x16",
     "\x17",
     "\x18",
     "\x19",
     "\x1a",
     "\x1b",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\x20",
     "\x21",
     "\x22",
     "\x23",
     "\x24",
     "\x25",
     "\x26",
     "\x27",
     "\x28",
     "\x29",
     "\x2a",
     "\x2b",
     "\x2c",
     "\x2d",
     "\x2e",
     "\x2f",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\x3a",
     "\x3b",
     "\x3c",
     "\x3d",
     "\x3e",
     "\x3f",
     "\x40",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\x5b",
     "\x5c",
     "\x5d",
     "\x5e",
     "\x5f",
     "\x60",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\x7b",
     "\x7c",
     "\x7d",
     "\x7e",
     "\x7f",
     "\xc3\x87",
     "\xc3\xbc",
     "\xc3\xa9",
     "\xc3\xa2",
     "\xc3\xa4",
     "\xc3\xa0",
     "\xc3\xa5",
     "\xc3\xa7",
     "\xc3\xaa",
     "\xc3\xab",
     "\xc3\xa8",
     "\xc3\xaf",
     "\xc3\xae",
     "\xc3\x8d",
     "\xc3\x84",
     "\xc3\x81",
     "\xc3\x89",
     "\xc3\xa6",
     "\xc3\x86",
     "\xc5\x91",
     "\xc3\xb6",
     "\xc3\x93",
     "\xc5\xb1",
     "\xc3\x9a",
     "\xc5\xb0",
     "\xc3\x96",
     "\xc3\x9c",
     "\xc2\xa2",
     "\xc2\xa3",
     "\xc2\xa5",
     "\xe2\x82\xa7",
     "\xee\x80\x9f",
     "\xc3\xa1",
     "\xc3\xad",
     "\xc3\xb3",
     "\xc3\xba",
     "\xc3\xb1",
     "\xc3\x91",
     "\xc2\xaa",
     "\xc5\x90",
     "\xc2\xbf",
     "\xe2\x8c\x90",
     "\xc2\xac",
     "\xc2\xbd",
     "\xc2\xbc",
     "\xc2\xa1",
     "\xc2\xab",
     "\xc2\xbb",
     "\xe2\x96\x91",
     "\xe2\x96\x92",
     "\xe2\x96\x93",
     "\xe2\x94\x82",
     "\xe2\x94\xa4",
     "\xe2\x95\xa1",
     "\xe2\x95\xa2",
     "\xe2\x95\x96",
     "\xe2\x95\x95",
     "\xe2\x95\xa3",
     "\xe2\x95\x91",
     "\xe2\x95\x97",
     "\xe2\x95\x9d",
     "\xe2\x95\x9c",
     "\xe2\x95\x9b",
     "\xe2\x94\x90",
     "\xe2\x94\x94",
     "\xe2\x94\xb4",
     "\xe2\x94\xac",
     "\xe2\x94\x9c",
     "\xe2\x94\x80",
     "\xe2\x94\xbc",
     "\xe2\x95\x9e",
     "\xe2\x95\x9f",
     "\xe2\x95\x9a",
     "\xe2\x95\x94",
     "\xe2\x95\xa9",
     "\xe2\x95\xa6",
     "\xe2\x95\xa0",
     "\xe2\x95\x90",
     "\xe2\x95\xac",
     "\xe2\x95\xa7",
     "\xe2\x95\xa8",
     "\xe2\x95\xa4",
     "\xe2\x95\xa5",
     "\xe2\x95\x99",
     "\xe2\x95\x98",
     "\xe2\x95\x92",
     "\xe2\x95\x93",
     "\xe2\x95\xab",
     "\xe2\x95\xaa",
     "\xe2\x94\x98",
     "\xe2\x94\x8c",
     "\xe2\x96\x88",
     "\xe2\x96\x84",
     "\xe2\x96\x8c",
     "\xe2\x96\x90",
     "\xe2\x96\x80",
     "\xce\xb1",
     "\xce\xb2",
     "\xce\x93",
     "\xcf\x80",
     "\xce\xa3",
     "\xcf\x83",
     "\xce\xbc",
     "\xcf\x84",
     "\xce\xa6",
     "\xce\x98",
     "\xce\xa9",
     "\xce\xb4",
     "\xe2\x88\x9e",
     "\xe2\x88\x85",
     "\xce\xb5",
     "\xe2\x88\xa9",
     "\xe2\x89\xa1",
     "\xc2\xb1",
     "\xe2\x89\xa5",
     "\xe2\x89\xa4",
     "\xe2\x8c\xa0",
     "\xe2\x8c\xa1",
     "\xc3\xb7",
     "\xe2\x89\x88",
     "\xe2\x88\x98",
     "\xc2\xb7",
     "\xe2\x80\xa2",
     "\xe2\x88\x9a",
     "\xe2\x81\xbf",
     "\xc2\xb2",
     "\xe2\x96\xa0",
     "\xc2\xa0",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x04",
     0x00000005 => "\x05",
     0x00000006 => "\x06",
     0x00000007 => "\x07",
     0x00000008 => "\x08",
     0x00000009 => "\x09",
     0x0000000a => "\x0a",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x14",
     0x00000015 => "\x15",
     0x00000016 => "\x16",
     0x00000017 => "\x17",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x1a",
     0x0000001b => "\x1b",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x20",
     0x00000021 => "\x21",
     0x00000022 => "\x22",
     0x00000023 => "\x23",
     0x00000024 => "\x24",
     0x00000025 => "\x25",
     0x00000026 => "\x26",
     0x00000027 => "\x27",
     0x00000028 => "\x28",
     0x00000029 => "\x29",
     0x0000002a => "\x2a",
     0x0000002b => "\x2b",
     0x0000002c => "\x2c",
     0x0000002d => "\x2d",
     0x0000002e => "\x2e",
     0x0000002f => "\x2f",
     0x00000030 => "\x30",
     0x00000031 => "\x31",
     0x00000032 => "\x32",
     0x00000033 => "\x33",
     0x00000034 => "\x34",
     0x00000035 => "\x35",
     0x00000036 => "\x36",
     0x00000037 => "\x37",
     0x00000038 => "\x38",
     0x00000039 => "\x39",
     0x0000003a => "\x3a",
     0x0000003b => "\x3b",
     0x0000003c => "\x3c",
     0x0000003d => "\x3d",
     0x0000003e => "\x3e",
     0x0000003f => "\x3f",
     0x00000040 => "\x40",
     0x00000041 => "\x41",
     0x00000042 => "\x42",
     0x00000043 => "\x43",
     0x00000044 => "\x44",
     0x00000045 => "\x45",
     0x00000046 => "\x46",
     0x00000047 => "\x47",
     0x00000048 => "\x48",
     0x00000049 => "\x49",
     0x0000004a => "\x4a",
     0x0000004b => "\x4b",
     0x0000004c => "\x4c",
     0x0000004d => "\x4d",
     0x0000004e => "\x4e",
     0x0000004f => "\x4f",
     0x00000050 => "\x50",
     0x00000051 => "\x51",
     0x00000052 => "\x52",
     0x00000053 => "\x53",
     0x00000054 => "\x54",
     0x00000055 => "\x55",
     0x00000056 => "\x56",
     0x00000057 => "\x57",
     0x00000058 => "\x58",
     0x00000059 => "\x59",
     0x0000005a => "\x5a",
     0x0000005b => "\x5b",
     0x0000005c => "\x5c",
     0x0000005d => "\x5d",
     0x0000005e => "\x5e",
     0x0000005f => "\x5f",
     0x00000060 => "\x60",
     0x00000061 => "\x61",
     0x00000062 => "\x62",
     0x00000063 => "\x63",
     0x00000064 => "\x64",
     0x00000065 => "\x65",
     0x00000066 => "\x66",
     0x00000067 => "\x67",
     0x00000068 => "\x68",
     0x00000069 => "\x69",
     0x0000006a => "\x6a",
     0x0000006b => "\x6b",
     0x0000006c => "\x6c",
     0x0000006d => "\x6d",
     0x0000006e => "\x6e",
     0x0000006f => "\x6f",
     0x00000070 => "\x70",
     0x00000071 => "\x71",
     0x00000072 => "\x72",
     0x00000073 => "\x73",
     0x00000074 => "\x74",
     0x00000075 => "\x75",
     0x00000076 => "\x76",
     0x00000077 => "\x77",
     0x00000078 => "\x78",
     0x00000079 => "\x79",
     0x0000007a => "\x7a",
     0x0000007b => "\x7b",
     0x0000007c => "\x7c",
     0x0000007d => "\x7d",
     0x0000007e => "\x7e",
     0x0000007f => "\x7f",
     0x000000a0 => "\xff",
     0x000000a1 => "\xad",
     0x000000a2 => "\x9b",
     0x000000a3 => "\x9c",
     0x000000a5 => "\x9d",
     0x000000aa => "\xa6",
     0x000000ab => "\xae",
     0x000000ac => "\xaa",
     0x000000b1 => "\xf1",
     0x000000b2 => "\xfd",
     0x000000b7 => "\xf9",
     0x000000bb => "\xaf",
     0x000000bc => "\xac",
     0x000000bd => "\xab",
     0x000000bf => "\xa8",
     0x000000c1 => "\x8f",
     0x000000c4 => "\x8e",
     0x000000c6 => "\x92",
     0x000000c7 => "\x80",
     0x000000c9 => "\x90",
     0x000000cd => "\x8d",
     0x000000d1 => "\xa5",
     0x000000d3 => "\x95",
     0x000000d6 => "\x99",
     0x000000da => "\x97",
     0x000000dc => "\x9a",
     0x000000e0 => "\x85",
     0x000000e1 => "\xa0",
     0x000000e2 => "\x83",
     0x000000e4 => "\x84",
     0x000000e5 => "\x86",
     0x000000e6 => "\x91",
     0x000000e7 => "\x87",
     0x000000e8 => "\x8a",
     0x000000e9 => "\x82",
     0x000000ea => "\x88",
     0x000000eb => "\x89",
     0x000000ed => "\xa1",
     0x000000ee => "\x8c",
     0x000000ef => "\x8b",
     0x000000f1 => "\xa4",
     0x000000f3 => "\xa2",
     0x000000f6 => "\x94",
     0x000000f7 => "\xf6",
     0x000000fa => "\xa3",
     0x000000fc => "\x81",
     0x00000150 => "\xa7",
     0x00000151 => "\x93",
     0x00000170 => "\x98",
     0x00000171 => "\x96",
     0x00000393 => "\xe2",
     0x00000398 => "\xe9",
     0x000003a3 => "\xe4",
     0x000003a6 => "\xe8",
     0x000003a9 => "\xea",
     0x000003b1 => "\xe0",
     0x000003b2 => "\xe1",
     0x000003b4 => "\xeb",
     0x000003b5 => "\xee",
     0x000003bc => "\xe6",
     0x000003c0 => "\xe3",
     0x000003c3 => "\xe5",
     0x000003c4 => "\xe7",
     0x00002022 => "\xfa",
     0x0000207f => "\xfc",
     0x000020a7 => "\x9e",
     0x00002205 => "\xed",
     0x00002218 => "\xf8",
     0x0000221a => "\xfb",
     0x0000221e => "\xec",
     0x00002229 => "\xef",
     0x00002248 => "\xf7",
     0x00002261 => "\xf0",
     0x00002264 => "\xf3",
     0x00002265 => "\xf2",
     0x00002310 => "\xa9",
     0x00002320 => "\xf4",
     0x00002321 => "\xf5",
     0x00002500 => "\xc4",
     0x00002502 => "\xb3",
     0x0000250c => "\xda",
     0x00002510 => "\xbf",
     0x00002514 => "\xc0",
     0x00002518 => "\xd9",
     0x0000251c => "\xc3",
     0x00002524 => "\xb4",
     0x0000252c => "\xc2",
     0x00002534 => "\xc1",
     0x0000253c => "\xc5",
     0x00002550 => "\xcd",
     0x00002551 => "\xba",
     0x00002552 => "\xd5",
     0x00002553 => "\xd6",
     0x00002554 => "\xc9",
     0x00002555 => "\xb8",
     0x00002556 => "\xb7",
     0x00002557 => "\xbb",
     0x00002558 => "\xd4",
     0x00002559 => "\xd3",
     0x0000255a => "\xc8",
     0x0000255b => "\xbe",
     0x0000255c => "\xbd",
     0x0000255d => "\xbc",
     0x0000255e => "\xc6",
     0x0000255f => "\xc7",
     0x00002560 => "\xcc",
     0x00002561 => "\xb5",
     0x00002562 => "\xb6",
     0x00002563 => "\xb9",
     0x00002564 => "\xd1",
     0x00002565 => "\xd2",
     0x00002566 => "\xcb",
     0x00002567 => "\xcf",
     0x00002568 => "\xd0",
     0x00002569 => "\xca",
     0x0000256a => "\xd8",
     0x0000256b => "\xd7",
     0x0000256c => "\xce",
     0x00002580 => "\xdf",
     0x00002584 => "\xdc",
     0x00002588 => "\xdb",
     0x0000258c => "\xdd",
     0x00002590 => "\xde",
     0x00002591 => "\xb0",
     0x00002592 => "\xb1",
     0x00002593 => "\xb2",
     0x000025a0 => "\xfe",
     0x0000e01f => "\x9f",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::CWI - Conversion routines for CWI
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for CWI.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
   source: Computerworld Sza'mita'stechnika vol 3 issue 13 1988-06-29
  alias CWI-2
  alias CP-HU
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  00000004 | END OF TRANSMISSION (EOT)
     05 |  00000005 | ENQUIRY (ENQ)
     06 |  00000006 | ACKNOWLEDGE (ACK)
     07 |  00000007 | BELL (BEL)
     08 |  00000008 | BACKSPACE (BS)
     09 |  00000009 | CHARACTER TABULATION (HT)
     0A |  0000000A | LINE FEED (LF)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  00000014 | DEVICE CONTROL FOUR (DC4)
     15 |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     16 |  00000016 | SYNCHRONOUS IDLE (SYN)
     17 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  0000001A | SUBSTITUTE (SUB)
     1B |  0000001B | ESCAPE (ESC)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000020 | SPACE
     21 |  00000021 | EXCLAMATION MARK
     22 |  00000022 | QUOTATION MARK
     23 |  00000023 | NUMBER SIGN
     24 |  00000024 | DOLLAR SIGN
     25 |  00000025 | PERCENT SIGN
     26 |  00000026 | AMPERSAND
     27 |  00000027 | APOSTROPHE
     28 |  00000028 | LEFT PARENTHESIS
     29 |  00000029 | RIGHT PARENTHESIS
     2A |  0000002A | ASTERISK
     2B |  0000002B | PLUS SIGN
     2C |  0000002C | COMMA
     2D |  0000002D | HYPHEN-MINUS
     2E |  0000002E | FULL STOP
     2F |  0000002F | SOLIDUS
     30 |  00000030 | DIGIT ZERO
     31 |  00000031 | DIGIT ONE
     32 |  00000032 | DIGIT TWO
     33 |  00000033 | DIGIT THREE
     34 |  00000034 | DIGIT FOUR
     35 |  00000035 | DIGIT FIVE
     36 |  00000036 | DIGIT SIX
     37 |  00000037 | DIGIT SEVEN
     38 |  00000038 | DIGIT EIGHT
     39 |  00000039 | DIGIT NINE
     3A |  0000003A | COLON
     3B |  0000003B | SEMICOLON
     3C |  0000003C | LESS-THAN SIGN
     3D |  0000003D | EQUALS SIGN
     3E |  0000003E | GREATER-THAN SIGN
     3F |  0000003F | QUESTION MARK
     40 |  00000040 | COMMERCIAL AT
     41 |  00000041 | LATIN CAPITAL LETTER A
     42 |  00000042 | LATIN CAPITAL LETTER B
     43 |  00000043 | LATIN CAPITAL LETTER C
     44 |  00000044 | LATIN CAPITAL LETTER D
     45 |  00000045 | LATIN CAPITAL LETTER E
     46 |  00000046 | LATIN CAPITAL LETTER F
     47 |  00000047 | LATIN CAPITAL LETTER G
     48 |  00000048 | LATIN CAPITAL LETTER H
     49 |  00000049 | LATIN CAPITAL LETTER I
     4A |  0000004A | LATIN CAPITAL LETTER J
     4B |  0000004B | LATIN CAPITAL LETTER K
     4C |  0000004C | LATIN CAPITAL LETTER L
     4D |  0000004D | LATIN CAPITAL LETTER M
     4E |  0000004E | LATIN CAPITAL LETTER N
     4F |  0000004F | LATIN CAPITAL LETTER O
     50 |  00000050 | LATIN CAPITAL LETTER P
     51 |  00000051 | LATIN CAPITAL LETTER Q
     52 |  00000052 | LATIN CAPITAL LETTER R
     53 |  00000053 | LATIN CAPITAL LETTER S
     54 |  00000054 | LATIN CAPITAL LETTER T
     55 |  00000055 | LATIN CAPITAL LETTER U
     56 |  00000056 | LATIN CAPITAL LETTER V
     57 |  00000057 | LATIN CAPITAL LETTER W
     58 |  00000058 | LATIN CAPITAL LETTER X
     59 |  00000059 | LATIN CAPITAL LETTER Y
     5A |  0000005A | LATIN CAPITAL LETTER Z
     5B |  0000005B | LEFT SQUARE BRACKET
     5C |  0000005C | REVERSE SOLIDUS
     5D |  0000005D | RIGHT SQUARE BRACKET
     5E |  0000005E | CIRCUMFLEX ACCENT
     5F |  0000005F | LOW LINE
     60 |  00000060 | GRAVE ACCENT
     61 |  00000061 | LATIN SMALL LETTER A
     62 |  00000062 | LATIN SMALL LETTER B
     63 |  00000063 | LATIN SMALL LETTER C
     64 |  00000064 | LATIN SMALL LETTER D
     65 |  00000065 | LATIN SMALL LETTER E
     66 |  00000066 | LATIN SMALL LETTER F
     67 |  00000067 | LATIN SMALL LETTER G
     68 |  00000068 | LATIN SMALL LETTER H
     69 |  00000069 | LATIN SMALL LETTER I
     6A |  0000006A | LATIN SMALL LETTER J
     6B |  0000006B | LATIN SMALL LETTER K
     6C |  0000006C | LATIN SMALL LETTER L
     6D |  0000006D | LATIN SMALL LETTER M
     6E |  0000006E | LATIN SMALL LETTER N
     6F |  0000006F | LATIN SMALL LETTER O
     70 |  00000070 | LATIN SMALL LETTER P
     71 |  00000071 | LATIN SMALL LETTER Q
     72 |  00000072 | LATIN SMALL LETTER R
     73 |  00000073 | LATIN SMALL LETTER S
     74 |  00000074 | LATIN SMALL LETTER T
     75 |  00000075 | LATIN SMALL LETTER U
     76 |  00000076 | LATIN SMALL LETTER V
     77 |  00000077 | LATIN SMALL LETTER W
     78 |  00000078 | LATIN SMALL LETTER X
     79 |  00000079 | LATIN SMALL LETTER Y
     7A |  0000007A | LATIN SMALL LETTER Z
     7B |  0000007B | LEFT CURLY BRACKET
     7C |  0000007C | VERTICAL LINE
     7D |  0000007D | RIGHT CURLY BRACKET
     7E |  0000007E | TILDE
     7F |  0000007F | DELETE (DEL)
     80 |  000000C7 | LATIN CAPITAL LETTER C WITH CEDILLA
     81 |  000000FC | LATIN SMALL LETTER U WITH DIAERESIS
     82 |  000000E9 | LATIN SMALL LETTER E WITH ACUTE
     83 |  000000E2 | LATIN SMALL LETTER A WITH CIRCUMFLEX
     84 |  000000E4 | LATIN SMALL LETTER A WITH DIAERESIS
     85 |  000000E0 | LATIN SMALL LETTER A WITH GRAVE
     86 |  000000E5 | LATIN SMALL LETTER A WITH RING ABOVE
     87 |  000000E7 | LATIN SMALL LETTER C WITH CEDILLA
     88 |  000000EA | LATIN SMALL LETTER E WITH CIRCUMFLEX
     89 |  000000EB | LATIN SMALL LETTER E WITH DIAERESIS
     8A |  000000E8 | LATIN SMALL LETTER E WITH GRAVE
     8B |  000000EF | LATIN SMALL LETTER I WITH DIAERESIS
     8C |  000000EE | LATIN SMALL LETTER I WITH CIRCUMFLEX
     8D |  000000CD | LATIN CAPITAL LETTER I WITH ACUTE
     8E |  000000C4 | LATIN CAPITAL LETTER A WITH DIAERESIS
     8F |  000000C1 | LATIN CAPITAL LETTER A WITH ACUTE
     90 |  000000C9 | LATIN CAPITAL LETTER E WITH ACUTE
     91 |  000000E6 | LATIN SMALL LETTER AE
     92 |  000000C6 | LATIN CAPITAL LETTER AE
     93 |  00000151 | LATIN SMALL LETTER O WITH DOUBLE ACUTE
     94 |  000000F6 | LATIN SMALL LETTER O WITH DIAERESIS
     95 |  000000D3 | LATIN CAPITAL LETTER O WITH ACUTE
     96 |  00000171 | LATIN SMALL LETTER U WITH DOUBLE ACUTE
     97 |  000000DA | LATIN CAPITAL LETTER U WITH ACUTE
     98 |  00000170 | LATIN CAPITAL LETTER U WITH DOUBLE ACUTE
     99 |  000000D6 | LATIN CAPITAL LETTER O WITH DIAERESIS
     9A |  000000DC | LATIN CAPITAL LETTER U WITH DIAERESIS
     9B |  000000A2 | CENT SIGN
     9C |  000000A3 | POUND SIGN
     9D |  000000A5 | YEN SIGN
     9E |  000020A7 | PESETA SIGN
     9F |  0000E01F | HUNGARIAN FLORINTH (CWI_9F)
     A0 |  000000E1 | LATIN SMALL LETTER A WITH ACUTE
     A1 |  000000ED | LATIN SMALL LETTER I WITH ACUTE
     A2 |  000000F3 | LATIN SMALL LETTER O WITH ACUTE
     A3 |  000000FA | LATIN SMALL LETTER U WITH ACUTE
     A4 |  000000F1 | LATIN SMALL LETTER N WITH TILDE
     A5 |  000000D1 | LATIN CAPITAL LETTER N WITH TILDE
     A6 |  000000AA | FEMININE ORDINAL INDICATOR
     A7 |  00000150 | LATIN CAPITAL LETTER O WITH DOUBLE ACUTE
     A8 |  000000BF | INVERTED QUESTION MARK
     A9 |  00002310 | REVERSED NOT SIGN
     AA |  000000AC | NOT SIGN
     AB |  000000BD | VULGAR FRACTION ONE HALF
     AC |  000000BC | VULGAR FRACTION ONE QUARTER
     AD |  000000A1 | INVERTED EXCLAMATION MARK
     AE |  000000AB | LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
     AF |  000000BB | RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
     B0 |  00002591 | LIGHT SHADE
     B1 |  00002592 | MEDIUM SHADE
     B2 |  00002593 | DARK SHADE
     B3 |  00002502 | BOX DRAWINGS LIGHT VERTICAL
     B4 |  00002524 | BOX DRAWINGS LIGHT VERTICAL AND LEFT
     B5 |  00002561 | BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE
     B6 |  00002562 | BOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLE
     B7 |  00002556 | BOX DRAWINGS DOWN DOUBLE AND LEFT SINGLE
     B8 |  00002555 | BOX DRAWINGS DOWN SINGLE AND LEFT DOUBLE
     B9 |  00002563 | BOX DRAWINGS DOUBLE VERTICAL AND LEFT
     BA |  00002551 | BOX DRAWINGS DOUBLE VERTICAL
     BB |  00002557 | BOX DRAWINGS DOUBLE DOWN AND LEFT
     BC |  0000255D | BOX DRAWINGS DOUBLE UP AND LEFT
     BD |  0000255C | BOX DRAWINGS UP DOUBLE AND LEFT SINGLE
     BE |  0000255B | BOX DRAWINGS UP SINGLE AND LEFT DOUBLE
     BF |  00002510 | BOX DRAWINGS LIGHT DOWN AND LEFT
     C0 |  00002514 | BOX DRAWINGS LIGHT UP AND RIGHT
     C1 |  00002534 | BOX DRAWINGS LIGHT UP AND HORIZONTAL
     C2 |  0000252C | BOX DRAWINGS LIGHT DOWN AND HORIZONTAL
     C3 |  0000251C | BOX DRAWINGS LIGHT VERTICAL AND RIGHT
     C4 |  00002500 | BOX DRAWINGS LIGHT HORIZONTAL
     C5 |  0000253C | BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL
     C6 |  0000255E | BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE
     C7 |  0000255F | BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE
     C8 |  0000255A | BOX DRAWINGS DOUBLE UP AND RIGHT
     C9 |  00002554 | BOX DRAWINGS DOUBLE DOWN AND RIGHT
     CA |  00002569 | BOX DRAWINGS DOUBLE UP AND HORIZONTAL
     CB |  00002566 | BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL
     CC |  00002560 | BOX DRAWINGS DOUBLE VERTICAL AND RIGHT
     CD |  00002550 | BOX DRAWINGS DOUBLE HORIZONTAL
     CE |  0000256C | BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL
     CF |  00002567 | BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE
     D0 |  00002568 | BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE
     D1 |  00002564 | BOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLE
     D2 |  00002565 | BOX DRAWINGS DOWN DOUBLE AND HORIZONTAL SINGLE
     D3 |  00002559 | BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE
     D4 |  00002558 | BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE
     D5 |  00002552 | BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE
     D6 |  00002553 | BOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLE
     D7 |  0000256B | BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLE
     D8 |  0000256A | BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE
     D9 |  00002518 | BOX DRAWINGS LIGHT UP AND LEFT
     DA |  0000250C | BOX DRAWINGS LIGHT DOWN AND RIGHT
     DB |  00002588 | FULL BLOCK
     DC |  00002584 | LOWER HALF BLOCK
     DD |  0000258C | LEFT HALF BLOCK
     DE |  00002590 | RIGHT HALF BLOCK
     DF |  00002580 | UPPER HALF BLOCK
     E0 |  000003B1 | GREEK SMALL LETTER ALPHA
     E1 |  000003B2 | GREEK SMALL LETTER BETA
     E2 |  00000393 | GREEK CAPITAL LETTER GAMMA
     E3 |  000003C0 | GREEK SMALL LETTER PI
     E4 |  000003A3 | GREEK CAPITAL LETTER SIGMA
     E5 |  000003C3 | GREEK SMALL LETTER SIGMA
     E6 |  000003BC | GREEK SMALL LETTER MU
     E7 |  000003C4 | GREEK SMALL LETTER TAU
     E8 |  000003A6 | GREEK CAPITAL LETTER PHI
     E9 |  00000398 | GREEK CAPITAL LETTER THETA
     EA |  000003A9 | GREEK CAPITAL LETTER OMEGA
     EB |  000003B4 | GREEK SMALL LETTER DELTA
     EC |  0000221E | INFINITY
     ED |  00002205 | EMPTY SET
     EE |  000003B5 | GREEK SMALL LETTER EPSILON
     EF |  00002229 | INTERSECTION
     F0 |  00002261 | IDENTICAL TO
     F1 |  000000B1 | PLUS-MINUS SIGN
     F2 |  00002265 | GREATER-THAN OR EQUAL TO
     F3 |  00002264 | LESS-THAN OR EQUAL TO
     F4 |  00002320 | TOP HALF INTEGRAL
     F5 |  00002321 | BOTTOM HALF INTEGRAL
     F6 |  000000F7 | DIVISION SIGN
     F7 |  00002248 | ALMOST EQUAL TO
     F8 |  00002218 | RING OPERATOR
     F9 |  000000B7 | MIDDLE DOT
     FA |  00002022 | BULLET
     FB |  0000221A | SQUARE ROOT
     FC |  0000207F | SUPERSCRIPT LATIN SMALL LETTER N
     FD |  000000B2 | SUPERSCRIPT TWO
     FE |  000025A0 | BLACK SQUARE
     FF |  000000A0 | NO-BREAK SPACE
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/DEC_MCS.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for DEC-MCS.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::DEC_MCS;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x0004,
     0x0005,
     0x0006,
     0x0007,
     0x0008,
     0x0009,
     0x000a,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x0014,
     0x0015,
     0x0016,
     0x0017,
     0x0018,
     0x0019,
     0x001a,
     0x001b,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0020,
     0x0021,
     0x0022,
     0x0023,
     0x0024,
     0x0025,
     0x0026,
     0x0027,
     0x0028,
     0x0029,
     0x002a,
     0x002b,
     0x002c,
     0x002d,
     0x002e,
     0x002f,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x003a,
     0x003b,
     0x003c,
     0x003d,
     0x003e,
     0x003f,
     0x0040,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x005b,
     0x005c,
     0x005d,
     0x005e,
     0x005f,
     0x0060,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x007b,
     0x007c,
     0x007d,
     0x007e,
     0x007f,
     0x0080,
     0x0081,
     0x0082,
     0x0083,
     0x0084,
     0x0085,
     0x0086,
     0x0087,
     0x0088,
     0x0089,
     0x008a,
     0x008b,
     0x008c,
     0x008d,
     0x008e,
     0x008f,
     0x0090,
     0x0091,
     0x0092,
     0x0093,
     0x0094,
     0x0095,
     0x0096,
     0x0097,
     0x0098,
     0x0099,
     0x009a,
     0x009b,
     0x009c,
     0x009d,
     0x009e,
     0x009f,
     0xfffd,
     0x00a1,
     0x00a2,
     0x00a3,
     0xfffd,
     0x00a5,
     0xfffd,
     0x00a7,
     0x00a4,
     0x00a9,
     0x00aa,
     0x00ab,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00b0,
     0x00b1,
     0x00b2,
     0x00b3,
     0xfffd,
     0x00b5,
     0x00b6,
     0x00b7,
     0xfffd,
     0x00b9,
     0x00ba,
     0x00bb,
     0x00bc,
     0x00bd,
     0xfffd,
     0x00bf,
     0x00c0,
     0x00c1,
     0x00c2,
     0x00c3,
     0x00c4,
     0x00c5,
     0x00c6,
     0x00c7,
     0x00c8,
     0x00c9,
     0x00ca,
     0x00cb,
     0x00cc,
     0x00cd,
     0x00ce,
     0x00cf,
     0xfffd,
     0x00d1,
     0x00d2,
     0x00d3,
     0x00d4,
     0x00d5,
     0x00d6,
     0x0152,
     0x00d8,
     0x00d9,
     0x00da,
     0x00db,
     0x00dc,
     0x0178,
     0xfffd,
     0x00df,
     0x00e0,
     0x00e1,
     0x00e2,
     0x00e3,
     0x00e4,
     0x00e5,
     0x00e6,
     0x00e7,
     0x00e8,
     0x00e9,
     0x00ea,
     0x00eb,
     0x00ec,
     0x00ed,
     0x00ee,
     0x00ef,
     0xfffd,
     0x00f1,
     0x00f2,
     0x00f3,
     0x00f4,
     0x00f5,
     0x00f6,
     0x0153,
     0x00f8,
     0x00f9,
     0x00fa,
     0x00fb,
     0x00fc,
     0x00ff,
     0xfffd,
     0xfffd,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\x04",
     "\x05",
     "\x06",
     "\x07",
     "\x08",
     "\x09",
     "\x0a",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\x14",
     "\x15",
     "\x16",
     "\x17",
     "\x18",
     "\x19",
     "\x1a",
     "\x1b",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\x20",
     "\x21",
     "\x22",
     "\x23",
     "\x24",
     "\x25",
     "\x26",
     "\x27",
     "\x28",
     "\x29",
     "\x2a",
     "\x2b",
     "\x2c",
     "\x2d",
     "\x2e",
     "\x2f",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\x3a",
     "\x3b",
     "\x3c",
     "\x3d",
     "\x3e",
     "\x3f",
     "\x40",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\x5b",
     "\x5c",
     "\x5d",
     "\x5e",
     "\x5f",
     "\x60",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\x7b",
     "\x7c",
     "\x7d",
     "\x7e",
     "\x7f",
     "\xc2\x80",
     "\xc2\x81",
     "\xc2\x82",
     "\xc2\x83",
     "\xc2\x84",
     "\xc2\x85",
     "\xc2\x86",
     "\xc2\x87",
     "\xc2\x88",
     "\xc2\x89",
     "\xc2\x8a",
     "\xc2\x8b",
     "\xc2\x8c",
     "\xc2\x8d",
     "\xc2\x8e",
     "\xc2\x8f",
     "\xc2\x90",
     "\xc2\x91",
     "\xc2\x92",
     "\xc2\x93",
     "\xc2\x94",
     "\xc2\x95",
     "\xc2\x96",
     "\xc2\x97",
     "\xc2\x98",
     "\xc2\x99",
     "\xc2\x9a",
     "\xc2\x9b",
     "\xc2\x9c",
     "\xc2\x9d",
     "\xc2\x9e",
     "\xc2\x9f",
     "\xef\xbf\xbd",
     "\xc2\xa1",
     "\xc2\xa2",
     "\xc2\xa3",
     "\xef\xbf\xbd",
     "\xc2\xa5",
     "\xef\xbf\xbd",
     "\xc2\xa7",
     "\xc2\xa4",
     "\xc2\xa9",
     "\xc2\xaa",
     "\xc2\xab",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc2\xb0",
     "\xc2\xb1",
     "\xc2\xb2",
     "\xc2\xb3",
     "\xef\xbf\xbd",
     "\xc2\xb5",
     "\xc2\xb6",
     "\xc2\xb7",
     "\xef\xbf\xbd",
     "\xc2\xb9",
     "\xc2\xba",
     "\xc2\xbb",
     "\xc2\xbc",
     "\xc2\xbd",
     "\xef\xbf\xbd",
     "\xc2\xbf",
     "\xc3\x80",
     "\xc3\x81",
     "\xc3\x82",
     "\xc3\x83",
     "\xc3\x84",
     "\xc3\x85",
     "\xc3\x86",
     "\xc3\x87",
     "\xc3\x88",
     "\xc3\x89",
     "\xc3\x8a",
     "\xc3\x8b",
     "\xc3\x8c",
     "\xc3\x8d",
     "\xc3\x8e",
     "\xc3\x8f",
     "\xef\xbf\xbd",
     "\xc3\x91",
     "\xc3\x92",
     "\xc3\x93",
     "\xc3\x94",
     "\xc3\x95",
     "\xc3\x96",
     "\xc5\x92",
     "\xc3\x98",
     "\xc3\x99",
     "\xc3\x9a",
     "\xc3\x9b",
     "\xc3\x9c",
     "\xc5\xb8",
     "\xef\xbf\xbd",
     "\xc3\x9f",
     "\xc3\xa0",
     "\xc3\xa1",
     "\xc3\xa2",
     "\xc3\xa3",
     "\xc3\xa4",
     "\xc3\xa5",
     "\xc3\xa6",
     "\xc3\xa7",
     "\xc3\xa8",
     "\xc3\xa9",
     "\xc3\xaa",
     "\xc3\xab",
     "\xc3\xac",
     "\xc3\xad",
     "\xc3\xae",
     "\xc3\xaf",
     "\xef\xbf\xbd",
     "\xc3\xb1",
     "\xc3\xb2",
     "\xc3\xb3",
     "\xc3\xb4",
     "\xc3\xb5",
     "\xc3\xb6",
     "\xc5\x93",
     "\xc3\xb8",
     "\xc3\xb9",
     "\xc3\xba",
     "\xc3\xbb",
     "\xc3\xbc",
     "\xc3\xbf",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x04",
     0x00000005 => "\x05",
     0x00000006 => "\x06",
     0x00000007 => "\x07",
     0x00000008 => "\x08",
     0x00000009 => "\x09",
     0x0000000a => "\x0a",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x14",
     0x00000015 => "\x15",
     0x00000016 => "\x16",
     0x00000017 => "\x17",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x1a",
     0x0000001b => "\x1b",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x20",
     0x00000021 => "\x21",
     0x00000022 => "\x22",
     0x00000023 => "\x23",
     0x00000024 => "\x24",
     0x00000025 => "\x25",
     0x00000026 => "\x26",
     0x00000027 => "\x27",
     0x00000028 => "\x28",
     0x00000029 => "\x29",
     0x0000002a => "\x2a",
     0x0000002b => "\x2b",
     0x0000002c => "\x2c",
     0x0000002d => "\x2d",
     0x0000002e => "\x2e",
     0x0000002f => "\x2f",
     0x00000030 => "\x30",
     0x00000031 => "\x31",
     0x00000032 => "\x32",
     0x00000033 => "\x33",
     0x00000034 => "\x34",
     0x00000035 => "\x35",
     0x00000036 => "\x36",
     0x00000037 => "\x37",
     0x00000038 => "\x38",
     0x00000039 => "\x39",
     0x0000003a => "\x3a",
     0x0000003b => "\x3b",
     0x0000003c => "\x3c",
     0x0000003d => "\x3d",
     0x0000003e => "\x3e",
     0x0000003f => "\x3f",
     0x00000040 => "\x40",
     0x00000041 => "\x41",
     0x00000042 => "\x42",
     0x00000043 => "\x43",
     0x00000044 => "\x44",
     0x00000045 => "\x45",
     0x00000046 => "\x46",
     0x00000047 => "\x47",
     0x00000048 => "\x48",
     0x00000049 => "\x49",
     0x0000004a => "\x4a",
     0x0000004b => "\x4b",
     0x0000004c => "\x4c",
     0x0000004d => "\x4d",
     0x0000004e => "\x4e",
     0x0000004f => "\x4f",
     0x00000050 => "\x50",
     0x00000051 => "\x51",
     0x00000052 => "\x52",
     0x00000053 => "\x53",
     0x00000054 => "\x54",
     0x00000055 => "\x55",
     0x00000056 => "\x56",
     0x00000057 => "\x57",
     0x00000058 => "\x58",
     0x00000059 => "\x59",
     0x0000005a => "\x5a",
     0x0000005b => "\x5b",
     0x0000005c => "\x5c",
     0x0000005d => "\x5d",
     0x0000005e => "\x5e",
     0x0000005f => "\x5f",
     0x00000060 => "\x60",
     0x00000061 => "\x61",
     0x00000062 => "\x62",
     0x00000063 => "\x63",
     0x00000064 => "\x64",
     0x00000065 => "\x65",
     0x00000066 => "\x66",
     0x00000067 => "\x67",
     0x00000068 => "\x68",
     0x00000069 => "\x69",
     0x0000006a => "\x6a",
     0x0000006b => "\x6b",
     0x0000006c => "\x6c",
     0x0000006d => "\x6d",
     0x0000006e => "\x6e",
     0x0000006f => "\x6f",
     0x00000070 => "\x70",
     0x00000071 => "\x71",
     0x00000072 => "\x72",
     0x00000073 => "\x73",
     0x00000074 => "\x74",
     0x00000075 => "\x75",
     0x00000076 => "\x76",
     0x00000077 => "\x77",
     0x00000078 => "\x78",
     0x00000079 => "\x79",
     0x0000007a => "\x7a",
     0x0000007b => "\x7b",
     0x0000007c => "\x7c",
     0x0000007d => "\x7d",
     0x0000007e => "\x7e",
     0x0000007f => "\x7f",
     0x00000080 => "\x80",
     0x00000081 => "\x81",
     0x00000082 => "\x82",
     0x00000083 => "\x83",
     0x00000084 => "\x84",
     0x00000085 => "\x85",
     0x00000086 => "\x86",
     0x00000087 => "\x87",
     0x00000088 => "\x88",
     0x00000089 => "\x89",
     0x0000008a => "\x8a",
     0x0000008b => "\x8b",
     0x0000008c => "\x8c",
     0x0000008d => "\x8d",
     0x0000008e => "\x8e",
     0x0000008f => "\x8f",
     0x00000090 => "\x90",
     0x00000091 => "\x91",
     0x00000092 => "\x92",
     0x00000093 => "\x93",
     0x00000094 => "\x94",
     0x00000095 => "\x95",
     0x00000096 => "\x96",
     0x00000097 => "\x97",
     0x00000098 => "\x98",
     0x00000099 => "\x99",
     0x0000009a => "\x9a",
     0x0000009b => "\x9b",
     0x0000009c => "\x9c",
     0x0000009d => "\x9d",
     0x0000009e => "\x9e",
     0x0000009f => "\x9f",
     0x000000a1 => "\xa1",
     0x000000a2 => "\xa2",
     0x000000a3 => "\xa3",
     0x000000a4 => "\xa8",
     0x000000a5 => "\xa5",
     0x000000a7 => "\xa7",
     0x000000a9 => "\xa9",
     0x000000aa => "\xaa",
     0x000000ab => "\xab",
     0x000000b0 => "\xb0",
     0x000000b1 => "\xb1",
     0x000000b2 => "\xb2",
     0x000000b3 => "\xb3",
     0x000000b5 => "\xb5",
     0x000000b6 => "\xb6",
     0x000000b7 => "\xb7",
     0x000000b9 => "\xb9",
     0x000000ba => "\xba",
     0x000000bb => "\xbb",
     0x000000bc => "\xbc",
     0x000000bd => "\xbd",
     0x000000bf => "\xbf",
     0x000000c0 => "\xc0",
     0x000000c1 => "\xc1",
     0x000000c2 => "\xc2",
     0x000000c3 => "\xc3",
     0x000000c4 => "\xc4",
     0x000000c5 => "\xc5",
     0x000000c6 => "\xc6",
     0x000000c7 => "\xc7",
     0x000000c8 => "\xc8",
     0x000000c9 => "\xc9",
     0x000000ca => "\xca",
     0x000000cb => "\xcb",
     0x000000cc => "\xcc",
     0x000000cd => "\xcd",
     0x000000ce => "\xce",
     0x000000cf => "\xcf",
     0x000000d1 => "\xd1",
     0x000000d2 => "\xd2",
     0x000000d3 => "\xd3",
     0x000000d4 => "\xd4",
     0x000000d5 => "\xd5",
     0x000000d6 => "\xd6",
     0x000000d8 => "\xd8",
     0x000000d9 => "\xd9",
     0x000000da => "\xda",
     0x000000db => "\xdb",
     0x000000dc => "\xdc",
     0x000000df => "\xdf",
     0x000000e0 => "\xe0",
     0x000000e1 => "\xe1",
     0x000000e2 => "\xe2",
     0x000000e3 => "\xe3",
     0x000000e4 => "\xe4",
     0x000000e5 => "\xe5",
     0x000000e6 => "\xe6",
     0x000000e7 => "\xe7",
     0x000000e8 => "\xe8",
     0x000000e9 => "\xe9",
     0x000000ea => "\xea",
     0x000000eb => "\xeb",
     0x000000ec => "\xec",
     0x000000ed => "\xed",
     0x000000ee => "\xee",
     0x000000ef => "\xef",
     0x000000f1 => "\xf1",
     0x000000f2 => "\xf2",
     0x000000f3 => "\xf3",
     0x000000f4 => "\xf4",
     0x000000f5 => "\xf5",
     0x000000f6 => "\xf6",
     0x000000f8 => "\xf8",
     0x000000f9 => "\xf9",
     0x000000fa => "\xfa",
     0x000000fb => "\xfb",
     0x000000fc => "\xfc",
     0x000000ff => "\xfd",
     0x00000152 => "\xd7",
     0x00000153 => "\xf7",
     0x00000178 => "\xdd",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::DEC_MCS - Conversion routines for DEC_MCS
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for DEC-MCS.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
   VAX/VMS User's Manual, Order Number: AI-Y517A-TE, April 1986.
  alias DEC
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  00000004 | END OF TRANSMISSION (EOT)
     05 |  00000005 | ENQUIRY (ENQ)
     06 |  00000006 | ACKNOWLEDGE (ACK)
     07 |  00000007 | BELL (BEL)
     08 |  00000008 | BACKSPACE (BS)
     09 |  00000009 | CHARACTER TABULATION (HT)
     0A |  0000000A | LINE FEED (LF)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  00000014 | DEVICE CONTROL FOUR (DC4)
     15 |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     16 |  00000016 | SYNCHRONOUS IDLE (SYN)
     17 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  0000001A | SUBSTITUTE (SUB)
     1B |  0000001B | ESCAPE (ESC)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000020 | SPACE
     21 |  00000021 | EXCLAMATION MARK
     22 |  00000022 | QUOTATION MARK
     23 |  00000023 | NUMBER SIGN
     24 |  00000024 | DOLLAR SIGN
     25 |  00000025 | PERCENT SIGN
     26 |  00000026 | AMPERSAND
     27 |  00000027 | APOSTROPHE
     28 |  00000028 | LEFT PARENTHESIS
     29 |  00000029 | RIGHT PARENTHESIS
     2A |  0000002A | ASTERISK
     2B |  0000002B | PLUS SIGN
     2C |  0000002C | COMMA
     2D |  0000002D | HYPHEN-MINUS
     2E |  0000002E | FULL STOP
     2F |  0000002F | SOLIDUS
     30 |  00000030 | DIGIT ZERO
     31 |  00000031 | DIGIT ONE
     32 |  00000032 | DIGIT TWO
     33 |  00000033 | DIGIT THREE
     34 |  00000034 | DIGIT FOUR
     35 |  00000035 | DIGIT FIVE
     36 |  00000036 | DIGIT SIX
     37 |  00000037 | DIGIT SEVEN
     38 |  00000038 | DIGIT EIGHT
     39 |  00000039 | DIGIT NINE
     3A |  0000003A | COLON
     3B |  0000003B | SEMICOLON
     3C |  0000003C | LESS-THAN SIGN
     3D |  0000003D | EQUALS SIGN
     3E |  0000003E | GREATER-THAN SIGN
     3F |  0000003F | QUESTION MARK
     40 |  00000040 | COMMERCIAL AT
     41 |  00000041 | LATIN CAPITAL LETTER A
     42 |  00000042 | LATIN CAPITAL LETTER B
     43 |  00000043 | LATIN CAPITAL LETTER C
     44 |  00000044 | LATIN CAPITAL LETTER D
     45 |  00000045 | LATIN CAPITAL LETTER E
     46 |  00000046 | LATIN CAPITAL LETTER F
     47 |  00000047 | LATIN CAPITAL LETTER G
     48 |  00000048 | LATIN CAPITAL LETTER H
     49 |  00000049 | LATIN CAPITAL LETTER I
     4A |  0000004A | LATIN CAPITAL LETTER J
     4B |  0000004B | LATIN CAPITAL LETTER K
     4C |  0000004C | LATIN CAPITAL LETTER L
     4D |  0000004D | LATIN CAPITAL LETTER M
     4E |  0000004E | LATIN CAPITAL LETTER N
     4F |  0000004F | LATIN CAPITAL LETTER O
     50 |  00000050 | LATIN CAPITAL LETTER P
     51 |  00000051 | LATIN CAPITAL LETTER Q
     52 |  00000052 | LATIN CAPITAL LETTER R
     53 |  00000053 | LATIN CAPITAL LETTER S
     54 |  00000054 | LATIN CAPITAL LETTER T
     55 |  00000055 | LATIN CAPITAL LETTER U
     56 |  00000056 | LATIN CAPITAL LETTER V
     57 |  00000057 | LATIN CAPITAL LETTER W
     58 |  00000058 | LATIN CAPITAL LETTER X
     59 |  00000059 | LATIN CAPITAL LETTER Y
     5A |  0000005A | LATIN CAPITAL LETTER Z
     5B |  0000005B | LEFT SQUARE BRACKET
     5C |  0000005C | REVERSE SOLIDUS
     5D |  0000005D | RIGHT SQUARE BRACKET
     5E |  0000005E | CIRCUMFLEX ACCENT
     5F |  0000005F | LOW LINE
     60 |  00000060 | GRAVE ACCENT
     61 |  00000061 | LATIN SMALL LETTER A
     62 |  00000062 | LATIN SMALL LETTER B
     63 |  00000063 | LATIN SMALL LETTER C
     64 |  00000064 | LATIN SMALL LETTER D
     65 |  00000065 | LATIN SMALL LETTER E
     66 |  00000066 | LATIN SMALL LETTER F
     67 |  00000067 | LATIN SMALL LETTER G
     68 |  00000068 | LATIN SMALL LETTER H
     69 |  00000069 | LATIN SMALL LETTER I
     6A |  0000006A | LATIN SMALL LETTER J
     6B |  0000006B | LATIN SMALL LETTER K
     6C |  0000006C | LATIN SMALL LETTER L
     6D |  0000006D | LATIN SMALL LETTER M
     6E |  0000006E | LATIN SMALL LETTER N
     6F |  0000006F | LATIN SMALL LETTER O
     70 |  00000070 | LATIN SMALL LETTER P
     71 |  00000071 | LATIN SMALL LETTER Q
     72 |  00000072 | LATIN SMALL LETTER R
     73 |  00000073 | LATIN SMALL LETTER S
     74 |  00000074 | LATIN SMALL LETTER T
     75 |  00000075 | LATIN SMALL LETTER U
     76 |  00000076 | LATIN SMALL LETTER V
     77 |  00000077 | LATIN SMALL LETTER W
     78 |  00000078 | LATIN SMALL LETTER X
     79 |  00000079 | LATIN SMALL LETTER Y
     7A |  0000007A | LATIN SMALL LETTER Z
     7B |  0000007B | LEFT CURLY BRACKET
     7C |  0000007C | VERTICAL LINE
     7D |  0000007D | RIGHT CURLY BRACKET
     7E |  0000007E | TILDE
     7F |  0000007F | DELETE (DEL)
     80 |  00000080 | PADDING CHARACTER (PAD)
     81 |  00000081 | HIGH OCTET PRESET (HOP)
     82 |  00000082 | BREAK PERMITTED HERE (BPH)
     83 |  00000083 | NO BREAK HERE (NBH)
     84 |  00000084 | INDEX (IND)
     85 |  00000085 | NEXT LINE (NEL)
     86 |  00000086 | START OF SELECTED AREA (SSA)
     87 |  00000087 | END OF SELECTED AREA (ESA)
     88 |  00000088 | CHARACTER TABULATION SET (HTS)
     89 |  00000089 | CHARACTER TABULATION WITH JUSTIFICATION (HTJ)
     8A |  0000008A | LINE TABULATION SET (VTS)
     8B |  0000008B | PARTIAL LINE FORWARD (PLD)
     8C |  0000008C | PARTIAL LINE BACKWARD (PLU)
     8D |  0000008D | REVERSE LINE FEED (RI)
     8E |  0000008E | SINGLE-SHIFT TWO (SS2)
     8F |  0000008F | SINGLE-SHIFT THREE (SS3)
     90 |  00000090 | DEVICE CONTROL STRING (DCS)
     91 |  00000091 | PRIVATE USE ONE (PU1)
     92 |  00000092 | PRIVATE USE TWO (PU2)
     93 |  00000093 | SET TRANSMIT STATE (STS)
     94 |  00000094 | CANCEL CHARACTER (CCH)
     95 |  00000095 | MESSAGE WAITING (MW)
     96 |  00000096 | START OF GUARDED AREA (SPA)
     97 |  00000097 | END OF GUARDED AREA (EPA)
     98 |  00000098 | START OF STRING (SOS)
     99 |  00000099 | SINGLE GRAPHIC CHARACTER INTRODUCER (SGCI)
     9A |  0000009A | SINGLE CHARACTER INTRODUCER (SCI)
     9B |  0000009B | CONTROL SEQUENCE INTRODUCER (CSI)
     9C |  0000009C | STRING TERMINATOR (ST)
     9D |  0000009D | OPERATING SYSTEM COMMAND (OSC)
     9E |  0000009E | PRIVACY MESSAGE (PM)
     9F |  0000009F | APPLICATION PROGRAM COMMAND (APC)
     A1 |  000000A1 | INVERTED EXCLAMATION MARK
     A2 |  000000A2 | CENT SIGN
     A3 |  000000A3 | POUND SIGN
     A5 |  000000A5 | YEN SIGN
     A7 |  000000A7 | SECTION SIGN
     A8 |  000000A4 | CURRENCY SIGN
     A9 |  000000A9 | COPYRIGHT SIGN
     AA |  000000AA | FEMININE ORDINAL INDICATOR
     AB |  000000AB | LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
     B0 |  000000B0 | DEGREE SIGN
     B1 |  000000B1 | PLUS-MINUS SIGN
     B2 |  000000B2 | SUPERSCRIPT TWO
     B3 |  000000B3 | SUPERSCRIPT THREE
     B5 |  000000B5 | MICRO SIGN
     B6 |  000000B6 | PILCROW SIGN
     B7 |  000000B7 | MIDDLE DOT
     B9 |  000000B9 | SUPERSCRIPT ONE
     BA |  000000BA | MASCULINE ORDINAL INDICATOR
     BB |  000000BB | RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
     BC |  000000BC | VULGAR FRACTION ONE QUARTER
     BD |  000000BD | VULGAR FRACTION ONE HALF
     BF |  000000BF | INVERTED QUESTION MARK
     C0 |  000000C0 | LATIN CAPITAL LETTER A WITH GRAVE
     C1 |  000000C1 | LATIN CAPITAL LETTER A WITH ACUTE
     C2 |  000000C2 | LATIN CAPITAL LETTER A WITH CIRCUMFLEX
     C3 |  000000C3 | LATIN CAPITAL LETTER A WITH TILDE
     C4 |  000000C4 | LATIN CAPITAL LETTER A WITH DIAERESIS
     C5 |  000000C5 | LATIN CAPITAL LETTER A WITH RING ABOVE
     C6 |  000000C6 | LATIN CAPITAL LETTER AE
     C7 |  000000C7 | LATIN CAPITAL LETTER C WITH CEDILLA
     C8 |  000000C8 | LATIN CAPITAL LETTER E WITH GRAVE
     C9 |  000000C9 | LATIN CAPITAL LETTER E WITH ACUTE
     CA |  000000CA | LATIN CAPITAL LETTER E WITH CIRCUMFLEX
     CB |  000000CB | LATIN CAPITAL LETTER E WITH DIAERESIS
     CC |  000000CC | LATIN CAPITAL LETTER I WITH GRAVE
     CD |  000000CD | LATIN CAPITAL LETTER I WITH ACUTE
     CE |  000000CE | LATIN CAPITAL LETTER I WITH CIRCUMFLEX
     CF |  000000CF | LATIN CAPITAL LETTER I WITH DIAERESIS
     D1 |  000000D1 | LATIN CAPITAL LETTER N WITH TILDE
     D2 |  000000D2 | LATIN CAPITAL LETTER O WITH GRAVE
     D3 |  000000D3 | LATIN CAPITAL LETTER O WITH ACUTE
     D4 |  000000D4 | LATIN CAPITAL LETTER O WITH CIRCUMFLEX
     D5 |  000000D5 | LATIN CAPITAL LETTER O WITH TILDE
     D6 |  000000D6 | LATIN CAPITAL LETTER O WITH DIAERESIS
     D7 |  00000152 | LATIN CAPITAL LIGATURE OE
     D8 |  000000D8 | LATIN CAPITAL LETTER O WITH STROKE
     D9 |  000000D9 | LATIN CAPITAL LETTER U WITH GRAVE
     DA |  000000DA | LATIN CAPITAL LETTER U WITH ACUTE
     DB |  000000DB | LATIN CAPITAL LETTER U WITH CIRCUMFLEX
     DC |  000000DC | LATIN CAPITAL LETTER U WITH DIAERESIS
     DD |  00000178 | LATIN CAPITAL LETTER Y WITH DIAERESIS
     DF |  000000DF | LATIN SMALL LETTER SHARP S (German)
     E0 |  000000E0 | LATIN SMALL LETTER A WITH GRAVE
     E1 |  000000E1 | LATIN SMALL LETTER A WITH ACUTE
     E2 |  000000E2 | LATIN SMALL LETTER A WITH CIRCUMFLEX
     E3 |  000000E3 | LATIN SMALL LETTER A WITH TILDE
     E4 |  000000E4 | LATIN SMALL LETTER A WITH DIAERESIS
     E5 |  000000E5 | LATIN SMALL LETTER A WITH RING ABOVE
     E6 |  000000E6 | LATIN SMALL LETTER AE
     E7 |  000000E7 | LATIN SMALL LETTER C WITH CEDILLA
     E8 |  000000E8 | LATIN SMALL LETTER E WITH GRAVE
     E9 |  000000E9 | LATIN SMALL LETTER E WITH ACUTE
     EA |  000000EA | LATIN SMALL LETTER E WITH CIRCUMFLEX
     EB |  000000EB | LATIN SMALL LETTER E WITH DIAERESIS
     EC |  000000EC | LATIN SMALL LETTER I WITH GRAVE
     ED |  000000ED | LATIN SMALL LETTER I WITH ACUTE
     EE |  000000EE | LATIN SMALL LETTER I WITH CIRCUMFLEX
     EF |  000000EF | LATIN SMALL LETTER I WITH DIAERESIS
     F1 |  000000F1 | LATIN SMALL LETTER N WITH TILDE
     F2 |  000000F2 | LATIN SMALL LETTER O WITH GRAVE
     F3 |  000000F3 | LATIN SMALL LETTER O WITH ACUTE
     F4 |  000000F4 | LATIN SMALL LETTER O WITH CIRCUMFLEX
     F5 |  000000F5 | LATIN SMALL LETTER O WITH TILDE
     F6 |  000000F6 | LATIN SMALL LETTER O WITH DIAERESIS
     F7 |  00000153 | LATIN SMALL LIGATURE OE
     F8 |  000000F8 | LATIN SMALL LETTER O WITH STROKE
     F9 |  000000F9 | LATIN SMALL LETTER U WITH GRAVE
     FA |  000000FA | LATIN SMALL LETTER U WITH ACUTE
     FB |  000000FB | LATIN SMALL LETTER U WITH CIRCUMFLEX
     FC |  000000FC | LATIN SMALL LETTER U WITH DIAERESIS
     FD |  000000FF | LATIN SMALL LETTER Y WITH DIAERESIS
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/EBCDIC_AT_DE.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for EBCDIC-AT-DE.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::EBCDIC_AT_DE;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x009c,
     0x0009,
     0x0086,
     0x007f,
     0x0097,
     0x008d,
     0x008e,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x009d,
     0x0085,
     0x0008,
     0x0087,
     0x0018,
     0x0019,
     0x0092,
     0x008f,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0080,
     0x0081,
     0x0082,
     0x0083,
     0x0084,
     0x000a,
     0x0017,
     0x001b,
     0x0088,
     0x0089,
     0x008a,
     0x008b,
     0x008c,
     0x0005,
     0x0006,
     0x0007,
     0x0090,
     0x0091,
     0x0016,
     0x0093,
     0x0094,
     0x0095,
     0x0096,
     0x0004,
     0x0098,
     0x0099,
     0x009a,
     0x009b,
     0x0014,
     0x0015,
     0x009e,
     0x001a,
     0x0020,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00c4,
     0x002e,
     0x003c,
     0x0028,
     0x002b,
     0x0021,
     0x0026,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00dc,
     0x0024,
     0x002a,
     0x0029,
     0x003b,
     0x005e,
     0x002d,
     0x002f,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00f6,
     0x002c,
     0x0025,
     0x005f,
     0x003e,
     0x003f,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x0060,
     0x003a,
     0x0023,
     0x00a7,
     0x0027,
     0x003d,
     0x0022,
     0xfffd,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00df,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00e4,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00fc,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00d6,
     0xfffd,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x009f,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\xc2\x9c",
     "\x09",
     "\xc2\x86",
     "\x7f",
     "\xc2\x97",
     "\xc2\x8d",
     "\xc2\x8e",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\xc2\x9d",
     "\xc2\x85",
     "\x08",
     "\xc2\x87",
     "\x18",
     "\x19",
     "\xc2\x92",
     "\xc2\x8f",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\xc2\x80",
     "\xc2\x81",
     "\xc2\x82",
     "\xc2\x83",
     "\xc2\x84",
     "\x0a",
     "\x17",
     "\x1b",
     "\xc2\x88",
     "\xc2\x89",
     "\xc2\x8a",
     "\xc2\x8b",
     "\xc2\x8c",
     "\x05",
     "\x06",
     "\x07",
     "\xc2\x90",
     "\xc2\x91",
     "\x16",
     "\xc2\x93",
     "\xc2\x94",
     "\xc2\x95",
     "\xc2\x96",
     "\x04",
     "\xc2\x98",
     "\xc2\x99",
     "\xc2\x9a",
     "\xc2\x9b",
     "\x14",
     "\x15",
     "\xc2\x9e",
     "\x1a",
     "\x20",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc3\x84",
     "\x2e",
     "\x3c",
     "\x28",
     "\x2b",
     "\x21",
     "\x26",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc3\x9c",
     "\x24",
     "\x2a",
     "\x29",
     "\x3b",
     "\x5e",
     "\x2d",
     "\x2f",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc3\xb6",
     "\x2c",
     "\x25",
     "\x5f",
     "\x3e",
     "\x3f",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x60",
     "\x3a",
     "\x23",
     "\xc2\xa7",
     "\x27",
     "\x3d",
     "\x22",
     "\xef\xbf\xbd",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc3\x9f",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc3\xa4",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc3\xbc",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc3\x96",
     "\xef\xbf\xbd",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc2\x9f",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x37",
     0x00000005 => "\x2d",
     0x00000006 => "\x2e",
     0x00000007 => "\x2f",
     0x00000008 => "\x16",
     0x00000009 => "\x05",
     0x0000000a => "\x25",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x3c",
     0x00000015 => "\x3d",
     0x00000016 => "\x32",
     0x00000017 => "\x26",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x3f",
     0x0000001b => "\x27",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x40",
     0x00000021 => "\x4f",
     0x00000022 => "\x7f",
     0x00000023 => "\x7b",
     0x00000024 => "\x5b",
     0x00000025 => "\x6c",
     0x00000026 => "\x50",
     0x00000027 => "\x7d",
     0x00000028 => "\x4d",
     0x00000029 => "\x5d",
     0x0000002a => "\x5c",
     0x0000002b => "\x4e",
     0x0000002c => "\x6b",
     0x0000002d => "\x60",
     0x0000002e => "\x4b",
     0x0000002f => "\x61",
     0x00000030 => "\xf0",
     0x00000031 => "\xf1",
     0x00000032 => "\xf2",
     0x00000033 => "\xf3",
     0x00000034 => "\xf4",
     0x00000035 => "\xf5",
     0x00000036 => "\xf6",
     0x00000037 => "\xf7",
     0x00000038 => "\xf8",
     0x00000039 => "\xf9",
     0x0000003a => "\x7a",
     0x0000003b => "\x5e",
     0x0000003c => "\x4c",
     0x0000003d => "\x7e",
     0x0000003e => "\x6e",
     0x0000003f => "\x6f",
     0x00000041 => "\xc1",
     0x00000042 => "\xc2",
     0x00000043 => "\xc3",
     0x00000044 => "\xc4",
     0x00000045 => "\xc5",
     0x00000046 => "\xc6",
     0x00000047 => "\xc7",
     0x00000048 => "\xc8",
     0x00000049 => "\xc9",
     0x0000004a => "\xd1",
     0x0000004b => "\xd2",
     0x0000004c => "\xd3",
     0x0000004d => "\xd4",
     0x0000004e => "\xd5",
     0x0000004f => "\xd6",
     0x00000050 => "\xd7",
     0x00000051 => "\xd8",
     0x00000052 => "\xd9",
     0x00000053 => "\xe2",
     0x00000054 => "\xe3",
     0x00000055 => "\xe4",
     0x00000056 => "\xe5",
     0x00000057 => "\xe6",
     0x00000058 => "\xe7",
     0x00000059 => "\xe8",
     0x0000005a => "\xe9",
     0x0000005e => "\x5f",
     0x0000005f => "\x6d",
     0x00000060 => "\x79",
     0x00000061 => "\x81",
     0x00000062 => "\x82",
     0x00000063 => "\x83",
     0x00000064 => "\x84",
     0x00000065 => "\x85",
     0x00000066 => "\x86",
     0x00000067 => "\x87",
     0x00000068 => "\x88",
     0x00000069 => "\x89",
     0x0000006a => "\x91",
     0x0000006b => "\x92",
     0x0000006c => "\x93",
     0x0000006d => "\x94",
     0x0000006e => "\x95",
     0x0000006f => "\x96",
     0x00000070 => "\x97",
     0x00000071 => "\x98",
     0x00000072 => "\x99",
     0x00000073 => "\xa2",
     0x00000074 => "\xa3",
     0x00000075 => "\xa4",
     0x00000076 => "\xa5",
     0x00000077 => "\xa6",
     0x00000078 => "\xa7",
     0x00000079 => "\xa8",
     0x0000007a => "\xa9",
     0x0000007f => "\x07",
     0x00000080 => "\x20",
     0x00000081 => "\x21",
     0x00000082 => "\x22",
     0x00000083 => "\x23",
     0x00000084 => "\x24",
     0x00000085 => "\x15",
     0x00000086 => "\x06",
     0x00000087 => "\x17",
     0x00000088 => "\x28",
     0x00000089 => "\x29",
     0x0000008a => "\x2a",
     0x0000008b => "\x2b",
     0x0000008c => "\x2c",
     0x0000008d => "\x09",
     0x0000008e => "\x0a",
     0x0000008f => "\x1b",
     0x00000090 => "\x30",
     0x00000091 => "\x31",
     0x00000092 => "\x1a",
     0x00000093 => "\x33",
     0x00000094 => "\x34",
     0x00000095 => "\x35",
     0x00000096 => "\x36",
     0x00000097 => "\x08",
     0x00000098 => "\x38",
     0x00000099 => "\x39",
     0x0000009a => "\x3a",
     0x0000009b => "\x3b",
     0x0000009c => "\x04",
     0x0000009d => "\x14",
     0x0000009e => "\x3e",
     0x0000009f => "\xff",
     0x000000a7 => "\x7c",
     0x000000c4 => "\x4a",
     0x000000d6 => "\xe0",
     0x000000dc => "\x5a",
     0x000000df => "\xa1",
     0x000000e4 => "\xc0",
     0x000000f6 => "\x6a",
     0x000000fc => "\xd0",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::EBCDIC_AT_DE - Conversion routines for EBCDIC_AT_DE
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for EBCDIC-AT-DE.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
   source: IBM 3270 Char Set Ref Ch 10, GA27-2837-9, April 1987
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  0000009C | STRING TERMINATOR (ST)
     05 |  00000009 | CHARACTER TABULATION (HT)
     06 |  00000086 | START OF SELECTED AREA (SSA)
     07 |  0000007F | DELETE (DEL)
     08 |  00000097 | END OF GUARDED AREA (EPA)
     09 |  0000008D | REVERSE LINE FEED (RI)
     0A |  0000008E | SINGLE-SHIFT TWO (SS2)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  0000009D | OPERATING SYSTEM COMMAND (OSC)
     15 |  00000085 | NEXT LINE (NEL)
     16 |  00000008 | BACKSPACE (BS)
     17 |  00000087 | END OF SELECTED AREA (ESA)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  00000092 | PRIVATE USE TWO (PU2)
     1B |  0000008F | SINGLE-SHIFT THREE (SS3)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000080 | PADDING CHARACTER (PAD)
     21 |  00000081 | HIGH OCTET PRESET (HOP)
     22 |  00000082 | BREAK PERMITTED HERE (BPH)
     23 |  00000083 | NO BREAK HERE (NBH)
     24 |  00000084 | INDEX (IND)
     25 |  0000000A | LINE FEED (LF)
     26 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     27 |  0000001B | ESCAPE (ESC)
     28 |  00000088 | CHARACTER TABULATION SET (HTS)
     29 |  00000089 | CHARACTER TABULATION WITH JUSTIFICATION (HTJ)
     2A |  0000008A | LINE TABULATION SET (VTS)
     2B |  0000008B | PARTIAL LINE FORWARD (PLD)
     2C |  0000008C | PARTIAL LINE BACKWARD (PLU)
     2D |  00000005 | ENQUIRY (ENQ)
     2E |  00000006 | ACKNOWLEDGE (ACK)
     2F |  00000007 | BELL (BEL)
     30 |  00000090 | DEVICE CONTROL STRING (DCS)
     31 |  00000091 | PRIVATE USE ONE (PU1)
     32 |  00000016 | SYNCHRONOUS IDLE (SYN)
     33 |  00000093 | SET TRANSMIT STATE (STS)
     34 |  00000094 | CANCEL CHARACTER (CCH)
     35 |  00000095 | MESSAGE WAITING (MW)
     36 |  00000096 | START OF GUARDED AREA (SPA)
     37 |  00000004 | END OF TRANSMISSION (EOT)
     38 |  00000098 | START OF STRING (SOS)
     39 |  00000099 | SINGLE GRAPHIC CHARACTER INTRODUCER (SGCI)
     3A |  0000009A | SINGLE CHARACTER INTRODUCER (SCI)
     3B |  0000009B | CONTROL SEQUENCE INTRODUCER (CSI)
     3C |  00000014 | DEVICE CONTROL FOUR (DC4)
     3D |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     3E |  0000009E | PRIVACY MESSAGE (PM)
     3F |  0000001A | SUBSTITUTE (SUB)
     40 |  00000020 | SPACE
     4A |  000000C4 | LATIN CAPITAL LETTER A WITH DIAERESIS
     4B |  0000002E | FULL STOP
     4C |  0000003C | LESS-THAN SIGN
     4D |  00000028 | LEFT PARENTHESIS
     4E |  0000002B | PLUS SIGN
     4F |  00000021 | EXCLAMATION MARK
     50 |  00000026 | AMPERSAND
     5A |  000000DC | LATIN CAPITAL LETTER U WITH DIAERESIS
     5B |  00000024 | DOLLAR SIGN
     5C |  0000002A | ASTERISK
     5D |  00000029 | RIGHT PARENTHESIS
     5E |  0000003B | SEMICOLON
     5F |  0000005E | CIRCUMFLEX ACCENT
     60 |  0000002D | HYPHEN-MINUS
     61 |  0000002F | SOLIDUS
     6A |  000000F6 | LATIN SMALL LETTER O WITH DIAERESIS
     6B |  0000002C | COMMA
     6C |  00000025 | PERCENT SIGN
     6D |  0000005F | LOW LINE
     6E |  0000003E | GREATER-THAN SIGN
     6F |  0000003F | QUESTION MARK
     79 |  00000060 | GRAVE ACCENT
     7A |  0000003A | COLON
     7B |  00000023 | NUMBER SIGN
     7C |  000000A7 | SECTION SIGN
     7D |  00000027 | APOSTROPHE
     7E |  0000003D | EQUALS SIGN
     7F |  00000022 | QUOTATION MARK
     81 |  00000061 | LATIN SMALL LETTER A
     82 |  00000062 | LATIN SMALL LETTER B
     83 |  00000063 | LATIN SMALL LETTER C
     84 |  00000064 | LATIN SMALL LETTER D
     85 |  00000065 | LATIN SMALL LETTER E
     86 |  00000066 | LATIN SMALL LETTER F
     87 |  00000067 | LATIN SMALL LETTER G
     88 |  00000068 | LATIN SMALL LETTER H
     89 |  00000069 | LATIN SMALL LETTER I
     91 |  0000006A | LATIN SMALL LETTER J
     92 |  0000006B | LATIN SMALL LETTER K
     93 |  0000006C | LATIN SMALL LETTER L
     94 |  0000006D | LATIN SMALL LETTER M
     95 |  0000006E | LATIN SMALL LETTER N
     96 |  0000006F | LATIN SMALL LETTER O
     97 |  00000070 | LATIN SMALL LETTER P
     98 |  00000071 | LATIN SMALL LETTER Q
     99 |  00000072 | LATIN SMALL LETTER R
     A1 |  000000DF | LATIN SMALL LETTER SHARP S (German)
     A2 |  00000073 | LATIN SMALL LETTER S
     A3 |  00000074 | LATIN SMALL LETTER T
     A4 |  00000075 | LATIN SMALL LETTER U
     A5 |  00000076 | LATIN SMALL LETTER V
     A6 |  00000077 | LATIN SMALL LETTER W
     A7 |  00000078 | LATIN SMALL LETTER X
     A8 |  00000079 | LATIN SMALL LETTER Y
     A9 |  0000007A | LATIN SMALL LETTER Z
     C0 |  000000E4 | LATIN SMALL LETTER A WITH DIAERESIS
     C1 |  00000041 | LATIN CAPITAL LETTER A
     C2 |  00000042 | LATIN CAPITAL LETTER B
     C3 |  00000043 | LATIN CAPITAL LETTER C
     C4 |  00000044 | LATIN CAPITAL LETTER D
     C5 |  00000045 | LATIN CAPITAL LETTER E
     C6 |  00000046 | LATIN CAPITAL LETTER F
     C7 |  00000047 | LATIN CAPITAL LETTER G
     C8 |  00000048 | LATIN CAPITAL LETTER H
     C9 |  00000049 | LATIN CAPITAL LETTER I
     D0 |  000000FC | LATIN SMALL LETTER U WITH DIAERESIS
     D1 |  0000004A | LATIN CAPITAL LETTER J
     D2 |  0000004B | LATIN CAPITAL LETTER K
     D3 |  0000004C | LATIN CAPITAL LETTER L
     D4 |  0000004D | LATIN CAPITAL LETTER M
     D5 |  0000004E | LATIN CAPITAL LETTER N
     D6 |  0000004F | LATIN CAPITAL LETTER O
     D7 |  00000050 | LATIN CAPITAL LETTER P
     D8 |  00000051 | LATIN CAPITAL LETTER Q
     D9 |  00000052 | LATIN CAPITAL LETTER R
     E0 |  000000D6 | LATIN CAPITAL LETTER O WITH DIAERESIS
     E2 |  00000053 | LATIN CAPITAL LETTER S
     E3 |  00000054 | LATIN CAPITAL LETTER T
     E4 |  00000055 | LATIN CAPITAL LETTER U
     E5 |  00000056 | LATIN CAPITAL LETTER V
     E6 |  00000057 | LATIN CAPITAL LETTER W
     E7 |  00000058 | LATIN CAPITAL LETTER X
     E8 |  00000059 | LATIN CAPITAL LETTER Y
     E9 |  0000005A | LATIN CAPITAL LETTER Z
     F0 |  00000030 | DIGIT ZERO
     F1 |  00000031 | DIGIT ONE
     F2 |  00000032 | DIGIT TWO
     F3 |  00000033 | DIGIT THREE
     F4 |  00000034 | DIGIT FOUR
     F5 |  00000035 | DIGIT FIVE
     F6 |  00000036 | DIGIT SIX
     F7 |  00000037 | DIGIT SEVEN
     F8 |  00000038 | DIGIT EIGHT
     F9 |  00000039 | DIGIT NINE
     FF |  0000009F | APPLICATION PROGRAM COMMAND (APC)
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/EBCDIC_AT_DE_A.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for EBCDIC-AT-DE-A.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::EBCDIC_AT_DE_A;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x009c,
     0x0009,
     0x0086,
     0x007f,
     0x0097,
     0x008d,
     0x008e,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x009d,
     0x0085,
     0x0008,
     0x0087,
     0x0018,
     0x0019,
     0x0092,
     0x008f,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0080,
     0x0081,
     0x0082,
     0x0083,
     0x0084,
     0x000a,
     0x0017,
     0x001b,
     0x0088,
     0x0089,
     0x008a,
     0x008b,
     0x008c,
     0x0005,
     0x0006,
     0x0007,
     0x0090,
     0x0091,
     0x0016,
     0x0093,
     0x0094,
     0x0095,
     0x0096,
     0x0004,
     0x0098,
     0x0099,
     0x009a,
     0x009b,
     0x0014,
     0x0015,
     0x009e,
     0x001a,
     0x0020,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00f6,
     0x002e,
     0x003c,
     0x0028,
     0x002b,
     0x007c,
     0x0026,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00fc,
     0x00dc,
     0x002a,
     0x0029,
     0x003b,
     0x00ac,
     0x002d,
     0x002f,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00df,
     0x002c,
     0x0025,
     0x005f,
     0x003e,
     0x003f,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x003a,
     0x00c4,
     0x00d6,
     0x0027,
     0x003d,
     0x00e4,
     0xfffd,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x009f,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\xc2\x9c",
     "\x09",
     "\xc2\x86",
     "\x7f",
     "\xc2\x97",
     "\xc2\x8d",
     "\xc2\x8e",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\xc2\x9d",
     "\xc2\x85",
     "\x08",
     "\xc2\x87",
     "\x18",
     "\x19",
     "\xc2\x92",
     "\xc2\x8f",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\xc2\x80",
     "\xc2\x81",
     "\xc2\x82",
     "\xc2\x83",
     "\xc2\x84",
     "\x0a",
     "\x17",
     "\x1b",
     "\xc2\x88",
     "\xc2\x89",
     "\xc2\x8a",
     "\xc2\x8b",
     "\xc2\x8c",
     "\x05",
     "\x06",
     "\x07",
     "\xc2\x90",
     "\xc2\x91",
     "\x16",
     "\xc2\x93",
     "\xc2\x94",
     "\xc2\x95",
     "\xc2\x96",
     "\x04",
     "\xc2\x98",
     "\xc2\x99",
     "\xc2\x9a",
     "\xc2\x9b",
     "\x14",
     "\x15",
     "\xc2\x9e",
     "\x1a",
     "\x20",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc3\xb6",
     "\x2e",
     "\x3c",
     "\x28",
     "\x2b",
     "\x7c",
     "\x26",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc3\xbc",
     "\xc3\x9c",
     "\x2a",
     "\x29",
     "\x3b",
     "\xc2\xac",
     "\x2d",
     "\x2f",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc3\x9f",
     "\x2c",
     "\x25",
     "\x5f",
     "\x3e",
     "\x3f",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x3a",
     "\xc3\x84",
     "\xc3\x96",
     "\x27",
     "\x3d",
     "\xc3\xa4",
     "\xef\xbf\xbd",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc2\x9f",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x37",
     0x00000005 => "\x2d",
     0x00000006 => "\x2e",
     0x00000007 => "\x2f",
     0x00000008 => "\x16",
     0x00000009 => "\x05",
     0x0000000a => "\x25",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x3c",
     0x00000015 => "\x3d",
     0x00000016 => "\x32",
     0x00000017 => "\x26",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x3f",
     0x0000001b => "\x27",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x40",
     0x00000025 => "\x6c",
     0x00000026 => "\x50",
     0x00000027 => "\x7d",
     0x00000028 => "\x4d",
     0x00000029 => "\x5d",
     0x0000002a => "\x5c",
     0x0000002b => "\x4e",
     0x0000002c => "\x6b",
     0x0000002d => "\x60",
     0x0000002e => "\x4b",
     0x0000002f => "\x61",
     0x00000030 => "\xf0",
     0x00000031 => "\xf1",
     0x00000032 => "\xf2",
     0x00000033 => "\xf3",
     0x00000034 => "\xf4",
     0x00000035 => "\xf5",
     0x00000036 => "\xf6",
     0x00000037 => "\xf7",
     0x00000038 => "\xf8",
     0x00000039 => "\xf9",
     0x0000003a => "\x7a",
     0x0000003b => "\x5e",
     0x0000003c => "\x4c",
     0x0000003d => "\x7e",
     0x0000003e => "\x6e",
     0x0000003f => "\x6f",
     0x00000041 => "\xc1",
     0x00000042 => "\xc2",
     0x00000043 => "\xc3",
     0x00000044 => "\xc4",
     0x00000045 => "\xc5",
     0x00000046 => "\xc6",
     0x00000047 => "\xc7",
     0x00000048 => "\xc8",
     0x00000049 => "\xc9",
     0x0000004a => "\xd1",
     0x0000004b => "\xd2",
     0x0000004c => "\xd3",
     0x0000004d => "\xd4",
     0x0000004e => "\xd5",
     0x0000004f => "\xd6",
     0x00000050 => "\xd7",
     0x00000051 => "\xd8",
     0x00000052 => "\xd9",
     0x00000053 => "\xe2",
     0x00000054 => "\xe3",
     0x00000055 => "\xe4",
     0x00000056 => "\xe5",
     0x00000057 => "\xe6",
     0x00000058 => "\xe7",
     0x00000059 => "\xe8",
     0x0000005a => "\xe9",
     0x0000005f => "\x6d",
     0x00000061 => "\x81",
     0x00000062 => "\x82",
     0x00000063 => "\x83",
     0x00000064 => "\x84",
     0x00000065 => "\x85",
     0x00000066 => "\x86",
     0x00000067 => "\x87",
     0x00000068 => "\x88",
     0x00000069 => "\x89",
     0x0000006a => "\x91",
     0x0000006b => "\x92",
     0x0000006c => "\x93",
     0x0000006d => "\x94",
     0x0000006e => "\x95",
     0x0000006f => "\x96",
     0x00000070 => "\x97",
     0x00000071 => "\x98",
     0x00000072 => "\x99",
     0x00000073 => "\xa2",
     0x00000074 => "\xa3",
     0x00000075 => "\xa4",
     0x00000076 => "\xa5",
     0x00000077 => "\xa6",
     0x00000078 => "\xa7",
     0x00000079 => "\xa8",
     0x0000007a => "\xa9",
     0x0000007c => "\x4f",
     0x0000007f => "\x07",
     0x00000080 => "\x20",
     0x00000081 => "\x21",
     0x00000082 => "\x22",
     0x00000083 => "\x23",
     0x00000084 => "\x24",
     0x00000085 => "\x15",
     0x00000086 => "\x06",
     0x00000087 => "\x17",
     0x00000088 => "\x28",
     0x00000089 => "\x29",
     0x0000008a => "\x2a",
     0x0000008b => "\x2b",
     0x0000008c => "\x2c",
     0x0000008d => "\x09",
     0x0000008e => "\x0a",
     0x0000008f => "\x1b",
     0x00000090 => "\x30",
     0x00000091 => "\x31",
     0x00000092 => "\x1a",
     0x00000093 => "\x33",
     0x00000094 => "\x34",
     0x00000095 => "\x35",
     0x00000096 => "\x36",
     0x00000097 => "\x08",
     0x00000098 => "\x38",
     0x00000099 => "\x39",
     0x0000009a => "\x3a",
     0x0000009b => "\x3b",
     0x0000009c => "\x04",
     0x0000009d => "\x14",
     0x0000009e => "\x3e",
     0x0000009f => "\xff",
     0x000000ac => "\x5f",
     0x000000c4 => "\x7b",
     0x000000d6 => "\x7c",
     0x000000dc => "\x5b",
     0x000000df => "\x6a",
     0x000000e4 => "\x7f",
     0x000000f6 => "\x4a",
     0x000000fc => "\x5a",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::EBCDIC_AT_DE_A - Conversion routines for EBCDIC_AT_DE_A
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for EBCDIC-AT-DE-A.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
   source: IBM 3270 Char Set Ref Ch 10, GA27-2837-9, April 1987
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  0000009C | STRING TERMINATOR (ST)
     05 |  00000009 | CHARACTER TABULATION (HT)
     06 |  00000086 | START OF SELECTED AREA (SSA)
     07 |  0000007F | DELETE (DEL)
     08 |  00000097 | END OF GUARDED AREA (EPA)
     09 |  0000008D | REVERSE LINE FEED (RI)
     0A |  0000008E | SINGLE-SHIFT TWO (SS2)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  0000009D | OPERATING SYSTEM COMMAND (OSC)
     15 |  00000085 | NEXT LINE (NEL)
     16 |  00000008 | BACKSPACE (BS)
     17 |  00000087 | END OF SELECTED AREA (ESA)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  00000092 | PRIVATE USE TWO (PU2)
     1B |  0000008F | SINGLE-SHIFT THREE (SS3)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000080 | PADDING CHARACTER (PAD)
     21 |  00000081 | HIGH OCTET PRESET (HOP)
     22 |  00000082 | BREAK PERMITTED HERE (BPH)
     23 |  00000083 | NO BREAK HERE (NBH)
     24 |  00000084 | INDEX (IND)
     25 |  0000000A | LINE FEED (LF)
     26 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     27 |  0000001B | ESCAPE (ESC)
     28 |  00000088 | CHARACTER TABULATION SET (HTS)
     29 |  00000089 | CHARACTER TABULATION WITH JUSTIFICATION (HTJ)
     2A |  0000008A | LINE TABULATION SET (VTS)
     2B |  0000008B | PARTIAL LINE FORWARD (PLD)
     2C |  0000008C | PARTIAL LINE BACKWARD (PLU)
     2D |  00000005 | ENQUIRY (ENQ)
     2E |  00000006 | ACKNOWLEDGE (ACK)
     2F |  00000007 | BELL (BEL)
     30 |  00000090 | DEVICE CONTROL STRING (DCS)
     31 |  00000091 | PRIVATE USE ONE (PU1)
     32 |  00000016 | SYNCHRONOUS IDLE (SYN)
     33 |  00000093 | SET TRANSMIT STATE (STS)
     34 |  00000094 | CANCEL CHARACTER (CCH)
     35 |  00000095 | MESSAGE WAITING (MW)
     36 |  00000096 | START OF GUARDED AREA (SPA)
     37 |  00000004 | END OF TRANSMISSION (EOT)
     38 |  00000098 | START OF STRING (SOS)
     39 |  00000099 | SINGLE GRAPHIC CHARACTER INTRODUCER (SGCI)
     3A |  0000009A | SINGLE CHARACTER INTRODUCER (SCI)
     3B |  0000009B | CONTROL SEQUENCE INTRODUCER (CSI)
     3C |  00000014 | DEVICE CONTROL FOUR (DC4)
     3D |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     3E |  0000009E | PRIVACY MESSAGE (PM)
     3F |  0000001A | SUBSTITUTE (SUB)
     40 |  00000020 | SPACE
     4A |  000000F6 | LATIN SMALL LETTER O WITH DIAERESIS
     4B |  0000002E | FULL STOP
     4C |  0000003C | LESS-THAN SIGN
     4D |  00000028 | LEFT PARENTHESIS
     4E |  0000002B | PLUS SIGN
     4F |  0000007C | VERTICAL LINE
     50 |  00000026 | AMPERSAND
     5A |  000000FC | LATIN SMALL LETTER U WITH DIAERESIS
     5B |  000000DC | LATIN CAPITAL LETTER U WITH DIAERESIS
     5C |  0000002A | ASTERISK
     5D |  00000029 | RIGHT PARENTHESIS
     5E |  0000003B | SEMICOLON
     5F |  000000AC | NOT SIGN
     60 |  0000002D | HYPHEN-MINUS
     61 |  0000002F | SOLIDUS
     6A |  000000DF | LATIN SMALL LETTER SHARP S (German)
     6B |  0000002C | COMMA
     6C |  00000025 | PERCENT SIGN
     6D |  0000005F | LOW LINE
     6E |  0000003E | GREATER-THAN SIGN
     6F |  0000003F | QUESTION MARK
     7A |  0000003A | COLON
     7B |  000000C4 | LATIN CAPITAL LETTER A WITH DIAERESIS
     7C |  000000D6 | LATIN CAPITAL LETTER O WITH DIAERESIS
     7D |  00000027 | APOSTROPHE
     7E |  0000003D | EQUALS SIGN
     7F |  000000E4 | LATIN SMALL LETTER A WITH DIAERESIS
     81 |  00000061 | LATIN SMALL LETTER A
     82 |  00000062 | LATIN SMALL LETTER B
     83 |  00000063 | LATIN SMALL LETTER C
     84 |  00000064 | LATIN SMALL LETTER D
     85 |  00000065 | LATIN SMALL LETTER E
     86 |  00000066 | LATIN SMALL LETTER F
     87 |  00000067 | LATIN SMALL LETTER G
     88 |  00000068 | LATIN SMALL LETTER H
     89 |  00000069 | LATIN SMALL LETTER I
     91 |  0000006A | LATIN SMALL LETTER J
     92 |  0000006B | LATIN SMALL LETTER K
     93 |  0000006C | LATIN SMALL LETTER L
     94 |  0000006D | LATIN SMALL LETTER M
     95 |  0000006E | LATIN SMALL LETTER N
     96 |  0000006F | LATIN SMALL LETTER O
     97 |  00000070 | LATIN SMALL LETTER P
     98 |  00000071 | LATIN SMALL LETTER Q
     99 |  00000072 | LATIN SMALL LETTER R
     A2 |  00000073 | LATIN SMALL LETTER S
     A3 |  00000074 | LATIN SMALL LETTER T
     A4 |  00000075 | LATIN SMALL LETTER U
     A5 |  00000076 | LATIN SMALL LETTER V
     A6 |  00000077 | LATIN SMALL LETTER W
     A7 |  00000078 | LATIN SMALL LETTER X
     A8 |  00000079 | LATIN SMALL LETTER Y
     A9 |  0000007A | LATIN SMALL LETTER Z
     C1 |  00000041 | LATIN CAPITAL LETTER A
     C2 |  00000042 | LATIN CAPITAL LETTER B
     C3 |  00000043 | LATIN CAPITAL LETTER C
     C4 |  00000044 | LATIN CAPITAL LETTER D
     C5 |  00000045 | LATIN CAPITAL LETTER E
     C6 |  00000046 | LATIN CAPITAL LETTER F
     C7 |  00000047 | LATIN CAPITAL LETTER G
     C8 |  00000048 | LATIN CAPITAL LETTER H
     C9 |  00000049 | LATIN CAPITAL LETTER I
     D1 |  0000004A | LATIN CAPITAL LETTER J
     D2 |  0000004B | LATIN CAPITAL LETTER K
     D3 |  0000004C | LATIN CAPITAL LETTER L
     D4 |  0000004D | LATIN CAPITAL LETTER M
     D5 |  0000004E | LATIN CAPITAL LETTER N
     D6 |  0000004F | LATIN CAPITAL LETTER O
     D7 |  00000050 | LATIN CAPITAL LETTER P
     D8 |  00000051 | LATIN CAPITAL LETTER Q
     D9 |  00000052 | LATIN CAPITAL LETTER R
     E2 |  00000053 | LATIN CAPITAL LETTER S
     E3 |  00000054 | LATIN CAPITAL LETTER T
     E4 |  00000055 | LATIN CAPITAL LETTER U
     E5 |  00000056 | LATIN CAPITAL LETTER V
     E6 |  00000057 | LATIN CAPITAL LETTER W
     E7 |  00000058 | LATIN CAPITAL LETTER X
     E8 |  00000059 | LATIN CAPITAL LETTER Y
     E9 |  0000005A | LATIN CAPITAL LETTER Z
     F0 |  00000030 | DIGIT ZERO
     F1 |  00000031 | DIGIT ONE
     F2 |  00000032 | DIGIT TWO
     F3 |  00000033 | DIGIT THREE
     F4 |  00000034 | DIGIT FOUR
     F5 |  00000035 | DIGIT FIVE
     F6 |  00000036 | DIGIT SIX
     F7 |  00000037 | DIGIT SEVEN
     F8 |  00000038 | DIGIT EIGHT
     F9 |  00000039 | DIGIT NINE
     FF |  0000009F | APPLICATION PROGRAM COMMAND (APC)
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/EBCDIC_CA_FR.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for EBCDIC-CA-FR.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::EBCDIC_CA_FR;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x009c,
     0x0009,
     0x0086,
     0x007f,
     0x0097,
     0x008d,
     0x008e,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x009d,
     0x0085,
     0x0008,
     0x0087,
     0x0018,
     0x0019,
     0x0092,
     0x008f,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0080,
     0x0081,
     0x0082,
     0x0083,
     0x0084,
     0x000a,
     0x0017,
     0x001b,
     0x0088,
     0x0089,
     0x008a,
     0x008b,
     0x008c,
     0x0005,
     0x0006,
     0x0007,
     0x0090,
     0x0091,
     0x0016,
     0x0093,
     0x0094,
     0x0095,
     0x0096,
     0x0004,
     0x0098,
     0x0099,
     0x009a,
     0x009b,
     0x0014,
     0x0015,
     0x009e,
     0x001a,
     0x0020,
     0xfffd,
     0x00e2,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00e7,
     0xfffd,
     0x00e0,
     0x002e,
     0x003c,
     0x0028,
     0x002b,
     0x0021,
     0x0026,
     0xfffd,
     0x00ea,
     0x00eb,
     0xfffd,
     0xfffd,
     0x00ee,
     0x00ef,
     0xfffd,
     0xfffd,
     0x00b4,
     0x0024,
     0x002a,
     0x0029,
     0x003b,
     0x005e,
     0x002d,
     0x002f,
     0x00c2,
     0xfffd,
     0x00c0,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00c7,
     0xfffd,
     0x00f9,
     0x002c,
     0x0025,
     0x005f,
     0x003e,
     0x003f,
     0xfffd,
     0x00c9,
     0x00ca,
     0x00cb,
     0xfffd,
     0x00ce,
     0x00cf,
     0xfffd,
     0xfffd,
     0x0060,
     0x003a,
     0x0023,
     0x0040,
     0x0027,
     0x003d,
     0x0022,
     0xfffd,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00a8,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00e9,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0xfffd,
     0x00f4,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00e8,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0xfffd,
     0x00fb,
     0x00fc,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00b8,
     0xfffd,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0xfffd,
     0x00d4,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0xfffd,
     0x00db,
     0x00dc,
     0x00d9,
     0xfffd,
     0x009f,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\xc2\x9c",
     "\x09",
     "\xc2\x86",
     "\x7f",
     "\xc2\x97",
     "\xc2\x8d",
     "\xc2\x8e",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\xc2\x9d",
     "\xc2\x85",
     "\x08",
     "\xc2\x87",
     "\x18",
     "\x19",
     "\xc2\x92",
     "\xc2\x8f",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\xc2\x80",
     "\xc2\x81",
     "\xc2\x82",
     "\xc2\x83",
     "\xc2\x84",
     "\x0a",
     "\x17",
     "\x1b",
     "\xc2\x88",
     "\xc2\x89",
     "\xc2\x8a",
     "\xc2\x8b",
     "\xc2\x8c",
     "\x05",
     "\x06",
     "\x07",
     "\xc2\x90",
     "\xc2\x91",
     "\x16",
     "\xc2\x93",
     "\xc2\x94",
     "\xc2\x95",
     "\xc2\x96",
     "\x04",
     "\xc2\x98",
     "\xc2\x99",
     "\xc2\x9a",
     "\xc2\x9b",
     "\x14",
     "\x15",
     "\xc2\x9e",
     "\x1a",
     "\x20",
     "\xef\xbf\xbd",
     "\xc3\xa2",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc3\xa7",
     "\xef\xbf\xbd",
     "\xc3\xa0",
     "\x2e",
     "\x3c",
     "\x28",
     "\x2b",
     "\x21",
     "\x26",
     "\xef\xbf\xbd",
     "\xc3\xaa",
     "\xc3\xab",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc3\xae",
     "\xc3\xaf",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc2\xb4",
     "\x24",
     "\x2a",
     "\x29",
     "\x3b",
     "\x5e",
     "\x2d",
     "\x2f",
     "\xc3\x82",
     "\xef\xbf\xbd",
     "\xc3\x80",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc3\x87",
     "\xef\xbf\xbd",
     "\xc3\xb9",
     "\x2c",
     "\x25",
     "\x5f",
     "\x3e",
     "\x3f",
     "\xef\xbf\xbd",
     "\xc3\x89",
     "\xc3\x8a",
     "\xc3\x8b",
     "\xef\xbf\xbd",
     "\xc3\x8e",
     "\xc3\x8f",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x60",
     "\x3a",
     "\x23",
     "\x40",
     "\x27",
     "\x3d",
     "\x22",
     "\xef\xbf\xbd",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc2\xa8",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc3\xa9",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\xef\xbf\xbd",
     "\xc3\xb4",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc3\xa8",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\xef\xbf\xbd",
     "\xc3\xbb",
     "\xc3\xbc",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc2\xb8",
     "\xef\xbf\xbd",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\xef\xbf\xbd",
     "\xc3\x94",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\xef\xbf\xbd",
     "\xc3\x9b",
     "\xc3\x9c",
     "\xc3\x99",
     "\xef\xbf\xbd",
     "\xc2\x9f",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x37",
     0x00000005 => "\x2d",
     0x00000006 => "\x2e",
     0x00000007 => "\x2f",
     0x00000008 => "\x16",
     0x00000009 => "\x05",
     0x0000000a => "\x25",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x3c",
     0x00000015 => "\x3d",
     0x00000016 => "\x32",
     0x00000017 => "\x26",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x3f",
     0x0000001b => "\x27",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x40",
     0x00000021 => "\x4f",
     0x00000022 => "\x7f",
     0x00000023 => "\x7b",
     0x00000024 => "\x5b",
     0x00000025 => "\x6c",
     0x00000026 => "\x50",
     0x00000027 => "\x7d",
     0x00000028 => "\x4d",
     0x00000029 => "\x5d",
     0x0000002a => "\x5c",
     0x0000002b => "\x4e",
     0x0000002c => "\x6b",
     0x0000002d => "\x60",
     0x0000002e => "\x4b",
     0x0000002f => "\x61",
     0x00000030 => "\xf0",
     0x00000031 => "\xf1",
     0x00000032 => "\xf2",
     0x00000033 => "\xf3",
     0x00000034 => "\xf4",
     0x00000035 => "\xf5",
     0x00000036 => "\xf6",
     0x00000037 => "\xf7",
     0x00000038 => "\xf8",
     0x00000039 => "\xf9",
     0x0000003a => "\x7a",
     0x0000003b => "\x5e",
     0x0000003c => "\x4c",
     0x0000003d => "\x7e",
     0x0000003e => "\x6e",
     0x0000003f => "\x6f",
     0x00000040 => "\x7c",
     0x00000041 => "\xc1",
     0x00000042 => "\xc2",
     0x00000043 => "\xc3",
     0x00000044 => "\xc4",
     0x00000045 => "\xc5",
     0x00000046 => "\xc6",
     0x00000047 => "\xc7",
     0x00000048 => "\xc8",
     0x00000049 => "\xc9",
     0x0000004a => "\xd1",
     0x0000004b => "\xd2",
     0x0000004c => "\xd3",
     0x0000004d => "\xd4",
     0x0000004e => "\xd5",
     0x0000004f => "\xd6",
     0x00000050 => "\xd7",
     0x00000051 => "\xd8",
     0x00000052 => "\xd9",
     0x00000053 => "\xe2",
     0x00000054 => "\xe3",
     0x00000055 => "\xe4",
     0x00000056 => "\xe5",
     0x00000057 => "\xe6",
     0x00000058 => "\xe7",
     0x00000059 => "\xe8",
     0x0000005a => "\xe9",
     0x0000005e => "\x5f",
     0x0000005f => "\x6d",
     0x00000060 => "\x79",
     0x00000061 => "\x81",
     0x00000062 => "\x82",
     0x00000063 => "\x83",
     0x00000064 => "\x84",
     0x00000065 => "\x85",
     0x00000066 => "\x86",
     0x00000067 => "\x87",
     0x00000068 => "\x88",
     0x00000069 => "\x89",
     0x0000006a => "\x91",
     0x0000006b => "\x92",
     0x0000006c => "\x93",
     0x0000006d => "\x94",
     0x0000006e => "\x95",
     0x0000006f => "\x96",
     0x00000070 => "\x97",
     0x00000071 => "\x98",
     0x00000072 => "\x99",
     0x00000073 => "\xa2",
     0x00000074 => "\xa3",
     0x00000075 => "\xa4",
     0x00000076 => "\xa5",
     0x00000077 => "\xa6",
     0x00000078 => "\xa7",
     0x00000079 => "\xa8",
     0x0000007a => "\xa9",
     0x0000007f => "\x07",
     0x00000080 => "\x20",
     0x00000081 => "\x21",
     0x00000082 => "\x22",
     0x00000083 => "\x23",
     0x00000084 => "\x24",
     0x00000085 => "\x15",
     0x00000086 => "\x06",
     0x00000087 => "\x17",
     0x00000088 => "\x28",
     0x00000089 => "\x29",
     0x0000008a => "\x2a",
     0x0000008b => "\x2b",
     0x0000008c => "\x2c",
     0x0000008d => "\x09",
     0x0000008e => "\x0a",
     0x0000008f => "\x1b",
     0x00000090 => "\x30",
     0x00000091 => "\x31",
     0x00000092 => "\x1a",
     0x00000093 => "\x33",
     0x00000094 => "\x34",
     0x00000095 => "\x35",
     0x00000096 => "\x36",
     0x00000097 => "\x08",
     0x00000098 => "\x38",
     0x00000099 => "\x39",
     0x0000009a => "\x3a",
     0x0000009b => "\x3b",
     0x0000009c => "\x04",
     0x0000009d => "\x14",
     0x0000009e => "\x3e",
     0x0000009f => "\xff",
     0x000000a8 => "\xa1",
     0x000000b4 => "\x5a",
     0x000000b8 => "\xe0",
     0x000000c0 => "\x64",
     0x000000c2 => "\x62",
     0x000000c7 => "\x68",
     0x000000c9 => "\x71",
     0x000000ca => "\x72",
     0x000000cb => "\x73",
     0x000000ce => "\x75",
     0x000000cf => "\x76",
     0x000000d4 => "\xeb",
     0x000000d9 => "\xfd",
     0x000000db => "\xfb",
     0x000000dc => "\xfc",
     0x000000e0 => "\x4a",
     0x000000e2 => "\x42",
     0x000000e7 => "\x48",
     0x000000e8 => "\xd0",
     0x000000e9 => "\xc0",
     0x000000ea => "\x52",
     0x000000eb => "\x53",
     0x000000ee => "\x56",
     0x000000ef => "\x57",
     0x000000f4 => "\xcb",
     0x000000f9 => "\x6a",
     0x000000fb => "\xdb",
     0x000000fc => "\xdc",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::EBCDIC_CA_FR - Conversion routines for EBCDIC_CA_FR
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for EBCDIC-CA-FR.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
   source: IBM 3270 Char Set Ref Ch 10, GA27-2837-9, April 1987
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  0000009C | STRING TERMINATOR (ST)
     05 |  00000009 | CHARACTER TABULATION (HT)
     06 |  00000086 | START OF SELECTED AREA (SSA)
     07 |  0000007F | DELETE (DEL)
     08 |  00000097 | END OF GUARDED AREA (EPA)
     09 |  0000008D | REVERSE LINE FEED (RI)
     0A |  0000008E | SINGLE-SHIFT TWO (SS2)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  0000009D | OPERATING SYSTEM COMMAND (OSC)
     15 |  00000085 | NEXT LINE (NEL)
     16 |  00000008 | BACKSPACE (BS)
     17 |  00000087 | END OF SELECTED AREA (ESA)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  00000092 | PRIVATE USE TWO (PU2)
     1B |  0000008F | SINGLE-SHIFT THREE (SS3)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000080 | PADDING CHARACTER (PAD)
     21 |  00000081 | HIGH OCTET PRESET (HOP)
     22 |  00000082 | BREAK PERMITTED HERE (BPH)
     23 |  00000083 | NO BREAK HERE (NBH)
     24 |  00000084 | INDEX (IND)
     25 |  0000000A | LINE FEED (LF)
     26 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     27 |  0000001B | ESCAPE (ESC)
     28 |  00000088 | CHARACTER TABULATION SET (HTS)
     29 |  00000089 | CHARACTER TABULATION WITH JUSTIFICATION (HTJ)
     2A |  0000008A | LINE TABULATION SET (VTS)
     2B |  0000008B | PARTIAL LINE FORWARD (PLD)
     2C |  0000008C | PARTIAL LINE BACKWARD (PLU)
     2D |  00000005 | ENQUIRY (ENQ)
     2E |  00000006 | ACKNOWLEDGE (ACK)
     2F |  00000007 | BELL (BEL)
     30 |  00000090 | DEVICE CONTROL STRING (DCS)
     31 |  00000091 | PRIVATE USE ONE (PU1)
     32 |  00000016 | SYNCHRONOUS IDLE (SYN)
     33 |  00000093 | SET TRANSMIT STATE (STS)
     34 |  00000094 | CANCEL CHARACTER (CCH)
     35 |  00000095 | MESSAGE WAITING (MW)
     36 |  00000096 | START OF GUARDED AREA (SPA)
     37 |  00000004 | END OF TRANSMISSION (EOT)
     38 |  00000098 | START OF STRING (SOS)
     39 |  00000099 | SINGLE GRAPHIC CHARACTER INTRODUCER (SGCI)
     3A |  0000009A | SINGLE CHARACTER INTRODUCER (SCI)
     3B |  0000009B | CONTROL SEQUENCE INTRODUCER (CSI)
     3C |  00000014 | DEVICE CONTROL FOUR (DC4)
     3D |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     3E |  0000009E | PRIVACY MESSAGE (PM)
     3F |  0000001A | SUBSTITUTE (SUB)
     40 |  00000020 | SPACE
     42 |  000000E2 | LATIN SMALL LETTER A WITH CIRCUMFLEX
     48 |  000000E7 | LATIN SMALL LETTER C WITH CEDILLA
     4A |  000000E0 | LATIN SMALL LETTER A WITH GRAVE
     4B |  0000002E | FULL STOP
     4C |  0000003C | LESS-THAN SIGN
     4D |  00000028 | LEFT PARENTHESIS
     4E |  0000002B | PLUS SIGN
     4F |  00000021 | EXCLAMATION MARK
     50 |  00000026 | AMPERSAND
     52 |  000000EA | LATIN SMALL LETTER E WITH CIRCUMFLEX
     53 |  000000EB | LATIN SMALL LETTER E WITH DIAERESIS
     56 |  000000EE | LATIN SMALL LETTER I WITH CIRCUMFLEX
     57 |  000000EF | LATIN SMALL LETTER I WITH DIAERESIS
     5A |  000000B4 | ACUTE ACCENT
     5B |  00000024 | DOLLAR SIGN
     5C |  0000002A | ASTERISK
     5D |  00000029 | RIGHT PARENTHESIS
     5E |  0000003B | SEMICOLON
     5F |  0000005E | CIRCUMFLEX ACCENT
     60 |  0000002D | HYPHEN-MINUS
     61 |  0000002F | SOLIDUS
     62 |  000000C2 | LATIN CAPITAL LETTER A WITH CIRCUMFLEX
     64 |  000000C0 | LATIN CAPITAL LETTER A WITH GRAVE
     68 |  000000C7 | LATIN CAPITAL LETTER C WITH CEDILLA
     6A |  000000F9 | LATIN SMALL LETTER U WITH GRAVE
     6B |  0000002C | COMMA
     6C |  00000025 | PERCENT SIGN
     6D |  0000005F | LOW LINE
     6E |  0000003E | GREATER-THAN SIGN
     6F |  0000003F | QUESTION MARK
     71 |  000000C9 | LATIN CAPITAL LETTER E WITH ACUTE
     72 |  000000CA | LATIN CAPITAL LETTER E WITH CIRCUMFLEX
     73 |  000000CB | LATIN CAPITAL LETTER E WITH DIAERESIS
     75 |  000000CE | LATIN CAPITAL LETTER I WITH CIRCUMFLEX
     76 |  000000CF | LATIN CAPITAL LETTER I WITH DIAERESIS
     79 |  00000060 | GRAVE ACCENT
     7A |  0000003A | COLON
     7B |  00000023 | NUMBER SIGN
     7C |  00000040 | COMMERCIAL AT
     7D |  00000027 | APOSTROPHE
     7E |  0000003D | EQUALS SIGN
     7F |  00000022 | QUOTATION MARK
     81 |  00000061 | LATIN SMALL LETTER A
     82 |  00000062 | LATIN SMALL LETTER B
     83 |  00000063 | LATIN SMALL LETTER C
     84 |  00000064 | LATIN SMALL LETTER D
     85 |  00000065 | LATIN SMALL LETTER E
     86 |  00000066 | LATIN SMALL LETTER F
     87 |  00000067 | LATIN SMALL LETTER G
     88 |  00000068 | LATIN SMALL LETTER H
     89 |  00000069 | LATIN SMALL LETTER I
     91 |  0000006A | LATIN SMALL LETTER J
     92 |  0000006B | LATIN SMALL LETTER K
     93 |  0000006C | LATIN SMALL LETTER L
     94 |  0000006D | LATIN SMALL LETTER M
     95 |  0000006E | LATIN SMALL LETTER N
     96 |  0000006F | LATIN SMALL LETTER O
     97 |  00000070 | LATIN SMALL LETTER P
     98 |  00000071 | LATIN SMALL LETTER Q
     99 |  00000072 | LATIN SMALL LETTER R
     A1 |  000000A8 | DIAERESIS
     A2 |  00000073 | LATIN SMALL LETTER S
     A3 |  00000074 | LATIN SMALL LETTER T
     A4 |  00000075 | LATIN SMALL LETTER U
     A5 |  00000076 | LATIN SMALL LETTER V
     A6 |  00000077 | LATIN SMALL LETTER W
     A7 |  00000078 | LATIN SMALL LETTER X
     A8 |  00000079 | LATIN SMALL LETTER Y
     A9 |  0000007A | LATIN SMALL LETTER Z
     C0 |  000000E9 | LATIN SMALL LETTER E WITH ACUTE
     C1 |  00000041 | LATIN CAPITAL LETTER A
     C2 |  00000042 | LATIN CAPITAL LETTER B
     C3 |  00000043 | LATIN CAPITAL LETTER C
     C4 |  00000044 | LATIN CAPITAL LETTER D
     C5 |  00000045 | LATIN CAPITAL LETTER E
     C6 |  00000046 | LATIN CAPITAL LETTER F
     C7 |  00000047 | LATIN CAPITAL LETTER G
     C8 |  00000048 | LATIN CAPITAL LETTER H
     C9 |  00000049 | LATIN CAPITAL LETTER I
     CB |  000000F4 | LATIN SMALL LETTER O WITH CIRCUMFLEX
     D0 |  000000E8 | LATIN SMALL LETTER E WITH GRAVE
     D1 |  0000004A | LATIN CAPITAL LETTER J
     D2 |  0000004B | LATIN CAPITAL LETTER K
     D3 |  0000004C | LATIN CAPITAL LETTER L
     D4 |  0000004D | LATIN CAPITAL LETTER M
     D5 |  0000004E | LATIN CAPITAL LETTER N
     D6 |  0000004F | LATIN CAPITAL LETTER O
     D7 |  00000050 | LATIN CAPITAL LETTER P
     D8 |  00000051 | LATIN CAPITAL LETTER Q
     D9 |  00000052 | LATIN CAPITAL LETTER R
     DB |  000000FB | LATIN SMALL LETTER U WITH CIRCUMFLEX
     DC |  000000FC | LATIN SMALL LETTER U WITH DIAERESIS
     E0 |  000000B8 | CEDILLA
     E2 |  00000053 | LATIN CAPITAL LETTER S
     E3 |  00000054 | LATIN CAPITAL LETTER T
     E4 |  00000055 | LATIN CAPITAL LETTER U
     E5 |  00000056 | LATIN CAPITAL LETTER V
     E6 |  00000057 | LATIN CAPITAL LETTER W
     E7 |  00000058 | LATIN CAPITAL LETTER X
     E8 |  00000059 | LATIN CAPITAL LETTER Y
     E9 |  0000005A | LATIN CAPITAL LETTER Z
     EB |  000000D4 | LATIN CAPITAL LETTER O WITH CIRCUMFLEX
     F0 |  00000030 | DIGIT ZERO
     F1 |  00000031 | DIGIT ONE
     F2 |  00000032 | DIGIT TWO
     F3 |  00000033 | DIGIT THREE
     F4 |  00000034 | DIGIT FOUR
     F5 |  00000035 | DIGIT FIVE
     F6 |  00000036 | DIGIT SIX
     F7 |  00000037 | DIGIT SEVEN
     F8 |  00000038 | DIGIT EIGHT
     F9 |  00000039 | DIGIT NINE
     FB |  000000DB | LATIN CAPITAL LETTER U WITH CIRCUMFLEX
     FC |  000000DC | LATIN CAPITAL LETTER U WITH DIAERESIS
     FD |  000000D9 | LATIN CAPITAL LETTER U WITH GRAVE
     FF |  0000009F | APPLICATION PROGRAM COMMAND (APC)
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/EBCDIC_DK_NO.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for EBCDIC-DK-NO.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::EBCDIC_DK_NO;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x009c,
     0x0009,
     0x0086,
     0x007f,
     0x0097,
     0x008d,
     0x008e,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x009d,
     0x0085,
     0x0008,
     0x0087,
     0x0018,
     0x0019,
     0x0092,
     0x008f,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0080,
     0x0081,
     0x0082,
     0x0083,
     0x0084,
     0x000a,
     0x0017,
     0x001b,
     0x0088,
     0x0089,
     0x008a,
     0x008b,
     0x008c,
     0x0005,
     0x0006,
     0x0007,
     0x0090,
     0x0091,
     0x0016,
     0x0093,
     0x0094,
     0x0095,
     0x0096,
     0x0004,
     0x0098,
     0x0099,
     0x009a,
     0x009b,
     0x0014,
     0x0015,
     0x009e,
     0x001a,
     0x0020,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x0023,
     0x002e,
     0x003c,
     0x0028,
     0x002b,
     0x0021,
     0x0026,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00a4,
     0x00c5,
     0x002a,
     0x0029,
     0x003b,
     0x005e,
     0x002d,
     0x002f,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00f8,
     0x002c,
     0x0025,
     0x005f,
     0x003e,
     0x003f,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x0060,
     0x003a,
     0x00c6,
     0x00d8,
     0x0027,
     0x003d,
     0x0022,
     0xfffd,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00fc,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00e6,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00e5,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x005c,
     0xfffd,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x009f,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\xc2\x9c",
     "\x09",
     "\xc2\x86",
     "\x7f",
     "\xc2\x97",
     "\xc2\x8d",
     "\xc2\x8e",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\xc2\x9d",
     "\xc2\x85",
     "\x08",
     "\xc2\x87",
     "\x18",
     "\x19",
     "\xc2\x92",
     "\xc2\x8f",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\xc2\x80",
     "\xc2\x81",
     "\xc2\x82",
     "\xc2\x83",
     "\xc2\x84",
     "\x0a",
     "\x17",
     "\x1b",
     "\xc2\x88",
     "\xc2\x89",
     "\xc2\x8a",
     "\xc2\x8b",
     "\xc2\x8c",
     "\x05",
     "\x06",
     "\x07",
     "\xc2\x90",
     "\xc2\x91",
     "\x16",
     "\xc2\x93",
     "\xc2\x94",
     "\xc2\x95",
     "\xc2\x96",
     "\x04",
     "\xc2\x98",
     "\xc2\x99",
     "\xc2\x9a",
     "\xc2\x9b",
     "\x14",
     "\x15",
     "\xc2\x9e",
     "\x1a",
     "\x20",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x23",
     "\x2e",
     "\x3c",
     "\x28",
     "\x2b",
     "\x21",
     "\x26",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc2\xa4",
     "\xc3\x85",
     "\x2a",
     "\x29",
     "\x3b",
     "\x5e",
     "\x2d",
     "\x2f",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc3\xb8",
     "\x2c",
     "\x25",
     "\x5f",
     "\x3e",
     "\x3f",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x60",
     "\x3a",
     "\xc3\x86",
     "\xc3\x98",
     "\x27",
     "\x3d",
     "\x22",
     "\xef\xbf\xbd",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc3\xbc",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc3\xa6",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc3\xa5",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x5c",
     "\xef\xbf\xbd",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc2\x9f",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x37",
     0x00000005 => "\x2d",
     0x00000006 => "\x2e",
     0x00000007 => "\x2f",
     0x00000008 => "\x16",
     0x00000009 => "\x05",
     0x0000000a => "\x25",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x3c",
     0x00000015 => "\x3d",
     0x00000016 => "\x32",
     0x00000017 => "\x26",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x3f",
     0x0000001b => "\x27",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x40",
     0x00000021 => "\x4f",
     0x00000022 => "\x7f",
     0x00000023 => "\x4a",
     0x00000025 => "\x6c",
     0x00000026 => "\x50",
     0x00000027 => "\x7d",
     0x00000028 => "\x4d",
     0x00000029 => "\x5d",
     0x0000002a => "\x5c",
     0x0000002b => "\x4e",
     0x0000002c => "\x6b",
     0x0000002d => "\x60",
     0x0000002e => "\x4b",
     0x0000002f => "\x61",
     0x00000030 => "\xf0",
     0x00000031 => "\xf1",
     0x00000032 => "\xf2",
     0x00000033 => "\xf3",
     0x00000034 => "\xf4",
     0x00000035 => "\xf5",
     0x00000036 => "\xf6",
     0x00000037 => "\xf7",
     0x00000038 => "\xf8",
     0x00000039 => "\xf9",
     0x0000003a => "\x7a",
     0x0000003b => "\x5e",
     0x0000003c => "\x4c",
     0x0000003d => "\x7e",
     0x0000003e => "\x6e",
     0x0000003f => "\x6f",
     0x00000041 => "\xc1",
     0x00000042 => "\xc2",
     0x00000043 => "\xc3",
     0x00000044 => "\xc4",
     0x00000045 => "\xc5",
     0x00000046 => "\xc6",
     0x00000047 => "\xc7",
     0x00000048 => "\xc8",
     0x00000049 => "\xc9",
     0x0000004a => "\xd1",
     0x0000004b => "\xd2",
     0x0000004c => "\xd3",
     0x0000004d => "\xd4",
     0x0000004e => "\xd5",
     0x0000004f => "\xd6",
     0x00000050 => "\xd7",
     0x00000051 => "\xd8",
     0x00000052 => "\xd9",
     0x00000053 => "\xe2",
     0x00000054 => "\xe3",
     0x00000055 => "\xe4",
     0x00000056 => "\xe5",
     0x00000057 => "\xe6",
     0x00000058 => "\xe7",
     0x00000059 => "\xe8",
     0x0000005a => "\xe9",
     0x0000005c => "\xe0",
     0x0000005e => "\x5f",
     0x0000005f => "\x6d",
     0x00000060 => "\x79",
     0x00000061 => "\x81",
     0x00000062 => "\x82",
     0x00000063 => "\x83",
     0x00000064 => "\x84",
     0x00000065 => "\x85",
     0x00000066 => "\x86",
     0x00000067 => "\x87",
     0x00000068 => "\x88",
     0x00000069 => "\x89",
     0x0000006a => "\x91",
     0x0000006b => "\x92",
     0x0000006c => "\x93",
     0x0000006d => "\x94",
     0x0000006e => "\x95",
     0x0000006f => "\x96",
     0x00000070 => "\x97",
     0x00000071 => "\x98",
     0x00000072 => "\x99",
     0x00000073 => "\xa2",
     0x00000074 => "\xa3",
     0x00000075 => "\xa4",
     0x00000076 => "\xa5",
     0x00000077 => "\xa6",
     0x00000078 => "\xa7",
     0x00000079 => "\xa8",
     0x0000007a => "\xa9",
     0x0000007f => "\x07",
     0x00000080 => "\x20",
     0x00000081 => "\x21",
     0x00000082 => "\x22",
     0x00000083 => "\x23",
     0x00000084 => "\x24",
     0x00000085 => "\x15",
     0x00000086 => "\x06",
     0x00000087 => "\x17",
     0x00000088 => "\x28",
     0x00000089 => "\x29",
     0x0000008a => "\x2a",
     0x0000008b => "\x2b",
     0x0000008c => "\x2c",
     0x0000008d => "\x09",
     0x0000008e => "\x0a",
     0x0000008f => "\x1b",
     0x00000090 => "\x30",
     0x00000091 => "\x31",
     0x00000092 => "\x1a",
     0x00000093 => "\x33",
     0x00000094 => "\x34",
     0x00000095 => "\x35",
     0x00000096 => "\x36",
     0x00000097 => "\x08",
     0x00000098 => "\x38",
     0x00000099 => "\x39",
     0x0000009a => "\x3a",
     0x0000009b => "\x3b",
     0x0000009c => "\x04",
     0x0000009d => "\x14",
     0x0000009e => "\x3e",
     0x0000009f => "\xff",
     0x000000a4 => "\x5a",
     0x000000c5 => "\x5b",
     0x000000c6 => "\x7b",
     0x000000d8 => "\x7c",
     0x000000e5 => "\xd0",
     0x000000e6 => "\xc0",
     0x000000f8 => "\x6a",
     0x000000fc => "\xa1",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::EBCDIC_DK_NO - Conversion routines for EBCDIC_DK_NO
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for EBCDIC-DK-NO.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
  repertoiremap: mnemonic,ds
   source: IBM 3270 Char Set Ref Ch 10, GA27-2837-9, April 1987
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  0000009C | STRING TERMINATOR (ST)
     05 |  00000009 | CHARACTER TABULATION (HT)
     06 |  00000086 | START OF SELECTED AREA (SSA)
     07 |  0000007F | DELETE (DEL)
     08 |  00000097 | END OF GUARDED AREA (EPA)
     09 |  0000008D | REVERSE LINE FEED (RI)
     0A |  0000008E | SINGLE-SHIFT TWO (SS2)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  0000009D | OPERATING SYSTEM COMMAND (OSC)
     15 |  00000085 | NEXT LINE (NEL)
     16 |  00000008 | BACKSPACE (BS)
     17 |  00000087 | END OF SELECTED AREA (ESA)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  00000092 | PRIVATE USE TWO (PU2)
     1B |  0000008F | SINGLE-SHIFT THREE (SS3)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000080 | PADDING CHARACTER (PAD)
     21 |  00000081 | HIGH OCTET PRESET (HOP)
     22 |  00000082 | BREAK PERMITTED HERE (BPH)
     23 |  00000083 | NO BREAK HERE (NBH)
     24 |  00000084 | INDEX (IND)
     25 |  0000000A | LINE FEED (LF)
     26 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     27 |  0000001B | ESCAPE (ESC)
     28 |  00000088 | CHARACTER TABULATION SET (HTS)
     29 |  00000089 | CHARACTER TABULATION WITH JUSTIFICATION (HTJ)
     2A |  0000008A | LINE TABULATION SET (VTS)
     2B |  0000008B | PARTIAL LINE FORWARD (PLD)
     2C |  0000008C | PARTIAL LINE BACKWARD (PLU)
     2D |  00000005 | ENQUIRY (ENQ)
     2E |  00000006 | ACKNOWLEDGE (ACK)
     2F |  00000007 | BELL (BEL)
     30 |  00000090 | DEVICE CONTROL STRING (DCS)
     31 |  00000091 | PRIVATE USE ONE (PU1)
     32 |  00000016 | SYNCHRONOUS IDLE (SYN)
     33 |  00000093 | SET TRANSMIT STATE (STS)
     34 |  00000094 | CANCEL CHARACTER (CCH)
     35 |  00000095 | MESSAGE WAITING (MW)
     36 |  00000096 | START OF GUARDED AREA (SPA)
     37 |  00000004 | END OF TRANSMISSION (EOT)
     38 |  00000098 | START OF STRING (SOS)
     39 |  00000099 | SINGLE GRAPHIC CHARACTER INTRODUCER (SGCI)
     3A |  0000009A | SINGLE CHARACTER INTRODUCER (SCI)
     3B |  0000009B | CONTROL SEQUENCE INTRODUCER (CSI)
     3C |  00000014 | DEVICE CONTROL FOUR (DC4)
     3D |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     3E |  0000009E | PRIVACY MESSAGE (PM)
     3F |  0000001A | SUBSTITUTE (SUB)
     40 |  00000020 | SPACE
     4A |  00000023 | NUMBER SIGN
     4B |  0000002E | FULL STOP
     4C |  0000003C | LESS-THAN SIGN
     4D |  00000028 | LEFT PARENTHESIS
     4E |  0000002B | PLUS SIGN
     4F |  00000021 | EXCLAMATION MARK
     50 |  00000026 | AMPERSAND
     5A |  000000A4 | CURRENCY SIGN
     5B |  000000C5 | LATIN CAPITAL LETTER A WITH RING ABOVE
     5C |  0000002A | ASTERISK
     5D |  00000029 | RIGHT PARENTHESIS
     5E |  0000003B | SEMICOLON
     5F |  0000005E | CIRCUMFLEX ACCENT
     60 |  0000002D | HYPHEN-MINUS
     61 |  0000002F | SOLIDUS
     6A |  000000F8 | LATIN SMALL LETTER O WITH STROKE
     6B |  0000002C | COMMA
     6C |  00000025 | PERCENT SIGN
     6D |  0000005F | LOW LINE
     6E |  0000003E | GREATER-THAN SIGN
     6F |  0000003F | QUESTION MARK
     79 |  00000060 | GRAVE ACCENT
     7A |  0000003A | COLON
     7B |  000000C6 | LATIN CAPITAL LETTER AE
     7C |  000000D8 | LATIN CAPITAL LETTER O WITH STROKE
     7D |  00000027 | APOSTROPHE
     7E |  0000003D | EQUALS SIGN
     7F |  00000022 | QUOTATION MARK
     81 |  00000061 | LATIN SMALL LETTER A
     82 |  00000062 | LATIN SMALL LETTER B
     83 |  00000063 | LATIN SMALL LETTER C
     84 |  00000064 | LATIN SMALL LETTER D
     85 |  00000065 | LATIN SMALL LETTER E
     86 |  00000066 | LATIN SMALL LETTER F
     87 |  00000067 | LATIN SMALL LETTER G
     88 |  00000068 | LATIN SMALL LETTER H
     89 |  00000069 | LATIN SMALL LETTER I
     91 |  0000006A | LATIN SMALL LETTER J
     92 |  0000006B | LATIN SMALL LETTER K
     93 |  0000006C | LATIN SMALL LETTER L
     94 |  0000006D | LATIN SMALL LETTER M
     95 |  0000006E | LATIN SMALL LETTER N
     96 |  0000006F | LATIN SMALL LETTER O
     97 |  00000070 | LATIN SMALL LETTER P
     98 |  00000071 | LATIN SMALL LETTER Q
     99 |  00000072 | LATIN SMALL LETTER R
     A1 |  000000FC | LATIN SMALL LETTER U WITH DIAERESIS
     A2 |  00000073 | LATIN SMALL LETTER S
     A3 |  00000074 | LATIN SMALL LETTER T
     A4 |  00000075 | LATIN SMALL LETTER U
     A5 |  00000076 | LATIN SMALL LETTER V
     A6 |  00000077 | LATIN SMALL LETTER W
     A7 |  00000078 | LATIN SMALL LETTER X
     A8 |  00000079 | LATIN SMALL LETTER Y
     A9 |  0000007A | LATIN SMALL LETTER Z
     C0 |  000000E6 | LATIN SMALL LETTER AE
     C1 |  00000041 | LATIN CAPITAL LETTER A
     C2 |  00000042 | LATIN CAPITAL LETTER B
     C3 |  00000043 | LATIN CAPITAL LETTER C
     C4 |  00000044 | LATIN CAPITAL LETTER D
     C5 |  00000045 | LATIN CAPITAL LETTER E
     C6 |  00000046 | LATIN CAPITAL LETTER F
     C7 |  00000047 | LATIN CAPITAL LETTER G
     C8 |  00000048 | LATIN CAPITAL LETTER H
     C9 |  00000049 | LATIN CAPITAL LETTER I
     D0 |  000000E5 | LATIN SMALL LETTER A WITH RING ABOVE
     D1 |  0000004A | LATIN CAPITAL LETTER J
     D2 |  0000004B | LATIN CAPITAL LETTER K
     D3 |  0000004C | LATIN CAPITAL LETTER L
     D4 |  0000004D | LATIN CAPITAL LETTER M
     D5 |  0000004E | LATIN CAPITAL LETTER N
     D6 |  0000004F | LATIN CAPITAL LETTER O
     D7 |  00000050 | LATIN CAPITAL LETTER P
     D8 |  00000051 | LATIN CAPITAL LETTER Q
     D9 |  00000052 | LATIN CAPITAL LETTER R
     E0 |  0000005C | REVERSE SOLIDUS
     E2 |  00000053 | LATIN CAPITAL LETTER S
     E3 |  00000054 | LATIN CAPITAL LETTER T
     E4 |  00000055 | LATIN CAPITAL LETTER U
     E5 |  00000056 | LATIN CAPITAL LETTER V
     E6 |  00000057 | LATIN CAPITAL LETTER W
     E7 |  00000058 | LATIN CAPITAL LETTER X
     E8 |  00000059 | LATIN CAPITAL LETTER Y
     E9 |  0000005A | LATIN CAPITAL LETTER Z
     F0 |  00000030 | DIGIT ZERO
     F1 |  00000031 | DIGIT ONE
     F2 |  00000032 | DIGIT TWO
     F3 |  00000033 | DIGIT THREE
     F4 |  00000034 | DIGIT FOUR
     F5 |  00000035 | DIGIT FIVE
     F6 |  00000036 | DIGIT SIX
     F7 |  00000037 | DIGIT SEVEN
     F8 |  00000038 | DIGIT EIGHT
     F9 |  00000039 | DIGIT NINE
     FF |  0000009F | APPLICATION PROGRAM COMMAND (APC)
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/EBCDIC_DK_NO_A.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for EBCDIC-DK-NO-A.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::EBCDIC_DK_NO_A;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x009c,
     0x0009,
     0x0086,
     0x007f,
     0x0097,
     0x008d,
     0x008e,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x009d,
     0x0085,
     0x0008,
     0x0087,
     0x0018,
     0x0019,
     0x0092,
     0x008f,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0080,
     0x0081,
     0x0082,
     0x0083,
     0x0084,
     0x000a,
     0x0017,
     0x001b,
     0x0088,
     0x0089,
     0x008a,
     0x008b,
     0x008c,
     0x0005,
     0x0006,
     0x0007,
     0x0090,
     0x0091,
     0x0016,
     0x0093,
     0x0094,
     0x0095,
     0x0096,
     0x0004,
     0x0098,
     0x0099,
     0x009a,
     0x009b,
     0x0014,
     0x0015,
     0x009e,
     0x001a,
     0x0020,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00f8,
     0x002e,
     0x003c,
     0x0028,
     0x002b,
     0x007c,
     0x0026,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00e5,
     0x00c5,
     0x002a,
     0x0029,
     0x003b,
     0x00ac,
     0x002d,
     0x002f,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00a6,
     0x002c,
     0x0025,
     0x005f,
     0x003e,
     0x003f,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x003a,
     0x00c6,
     0x00d8,
     0x0027,
     0x003d,
     0x00e6,
     0xfffd,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x009f,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\xc2\x9c",
     "\x09",
     "\xc2\x86",
     "\x7f",
     "\xc2\x97",
     "\xc2\x8d",
     "\xc2\x8e",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\xc2\x9d",
     "\xc2\x85",
     "\x08",
     "\xc2\x87",
     "\x18",
     "\x19",
     "\xc2\x92",
     "\xc2\x8f",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\xc2\x80",
     "\xc2\x81",
     "\xc2\x82",
     "\xc2\x83",
     "\xc2\x84",
     "\x0a",
     "\x17",
     "\x1b",
     "\xc2\x88",
     "\xc2\x89",
     "\xc2\x8a",
     "\xc2\x8b",
     "\xc2\x8c",
     "\x05",
     "\x06",
     "\x07",
     "\xc2\x90",
     "\xc2\x91",
     "\x16",
     "\xc2\x93",
     "\xc2\x94",
     "\xc2\x95",
     "\xc2\x96",
     "\x04",
     "\xc2\x98",
     "\xc2\x99",
     "\xc2\x9a",
     "\xc2\x9b",
     "\x14",
     "\x15",
     "\xc2\x9e",
     "\x1a",
     "\x20",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc3\xb8",
     "\x2e",
     "\x3c",
     "\x28",
     "\x2b",
     "\x7c",
     "\x26",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc3\xa5",
     "\xc3\x85",
     "\x2a",
     "\x29",
     "\x3b",
     "\xc2\xac",
     "\x2d",
     "\x2f",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc2\xa6",
     "\x2c",
     "\x25",
     "\x5f",
     "\x3e",
     "\x3f",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x3a",
     "\xc3\x86",
     "\xc3\x98",
     "\x27",
     "\x3d",
     "\xc3\xa6",
     "\xef\xbf\xbd",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc2\x9f",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x37",
     0x00000005 => "\x2d",
     0x00000006 => "\x2e",
     0x00000007 => "\x2f",
     0x00000008 => "\x16",
     0x00000009 => "\x05",
     0x0000000a => "\x25",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x3c",
     0x00000015 => "\x3d",
     0x00000016 => "\x32",
     0x00000017 => "\x26",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x3f",
     0x0000001b => "\x27",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x40",
     0x00000025 => "\x6c",
     0x00000026 => "\x50",
     0x00000027 => "\x7d",
     0x00000028 => "\x4d",
     0x00000029 => "\x5d",
     0x0000002a => "\x5c",
     0x0000002b => "\x4e",
     0x0000002c => "\x6b",
     0x0000002d => "\x60",
     0x0000002e => "\x4b",
     0x0000002f => "\x61",
     0x00000030 => "\xf0",
     0x00000031 => "\xf1",
     0x00000032 => "\xf2",
     0x00000033 => "\xf3",
     0x00000034 => "\xf4",
     0x00000035 => "\xf5",
     0x00000036 => "\xf6",
     0x00000037 => "\xf7",
     0x00000038 => "\xf8",
     0x00000039 => "\xf9",
     0x0000003a => "\x7a",
     0x0000003b => "\x5e",
     0x0000003c => "\x4c",
     0x0000003d => "\x7e",
     0x0000003e => "\x6e",
     0x0000003f => "\x6f",
     0x00000041 => "\xc1",
     0x00000042 => "\xc2",
     0x00000043 => "\xc3",
     0x00000044 => "\xc4",
     0x00000045 => "\xc5",
     0x00000046 => "\xc6",
     0x00000047 => "\xc7",
     0x00000048 => "\xc8",
     0x00000049 => "\xc9",
     0x0000004a => "\xd1",
     0x0000004b => "\xd2",
     0x0000004c => "\xd3",
     0x0000004d => "\xd4",
     0x0000004e => "\xd5",
     0x0000004f => "\xd6",
     0x00000050 => "\xd7",
     0x00000051 => "\xd8",
     0x00000052 => "\xd9",
     0x00000053 => "\xe2",
     0x00000054 => "\xe3",
     0x00000055 => "\xe4",
     0x00000056 => "\xe5",
     0x00000057 => "\xe6",
     0x00000058 => "\xe7",
     0x00000059 => "\xe8",
     0x0000005a => "\xe9",
     0x0000005f => "\x6d",
     0x00000061 => "\x81",
     0x00000062 => "\x82",
     0x00000063 => "\x83",
     0x00000064 => "\x84",
     0x00000065 => "\x85",
     0x00000066 => "\x86",
     0x00000067 => "\x87",
     0x00000068 => "\x88",
     0x00000069 => "\x89",
     0x0000006a => "\x91",
     0x0000006b => "\x92",
     0x0000006c => "\x93",
     0x0000006d => "\x94",
     0x0000006e => "\x95",
     0x0000006f => "\x96",
     0x00000070 => "\x97",
     0x00000071 => "\x98",
     0x00000072 => "\x99",
     0x00000073 => "\xa2",
     0x00000074 => "\xa3",
     0x00000075 => "\xa4",
     0x00000076 => "\xa5",
     0x00000077 => "\xa6",
     0x00000078 => "\xa7",
     0x00000079 => "\xa8",
     0x0000007a => "\xa9",
     0x0000007c => "\x4f",
     0x0000007f => "\x07",
     0x00000080 => "\x20",
     0x00000081 => "\x21",
     0x00000082 => "\x22",
     0x00000083 => "\x23",
     0x00000084 => "\x24",
     0x00000085 => "\x15",
     0x00000086 => "\x06",
     0x00000087 => "\x17",
     0x00000088 => "\x28",
     0x00000089 => "\x29",
     0x0000008a => "\x2a",
     0x0000008b => "\x2b",
     0x0000008c => "\x2c",
     0x0000008d => "\x09",
     0x0000008e => "\x0a",
     0x0000008f => "\x1b",
     0x00000090 => "\x30",
     0x00000091 => "\x31",
     0x00000092 => "\x1a",
     0x00000093 => "\x33",
     0x00000094 => "\x34",
     0x00000095 => "\x35",
     0x00000096 => "\x36",
     0x00000097 => "\x08",
     0x00000098 => "\x38",
     0x00000099 => "\x39",
     0x0000009a => "\x3a",
     0x0000009b => "\x3b",
     0x0000009c => "\x04",
     0x0000009d => "\x14",
     0x0000009e => "\x3e",
     0x0000009f => "\xff",
     0x000000a6 => "\x6a",
     0x000000ac => "\x5f",
     0x000000c5 => "\x5b",
     0x000000c6 => "\x7b",
     0x000000d8 => "\x7c",
     0x000000e5 => "\x5a",
     0x000000e6 => "\x7f",
     0x000000f8 => "\x4a",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::EBCDIC_DK_NO_A - Conversion routines for EBCDIC_DK_NO_A
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for EBCDIC-DK-NO-A.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
   source: IBM 3270 Char Set Ref Ch 10, GA27-2837-9, April 1987
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  0000009C | STRING TERMINATOR (ST)
     05 |  00000009 | CHARACTER TABULATION (HT)
     06 |  00000086 | START OF SELECTED AREA (SSA)
     07 |  0000007F | DELETE (DEL)
     08 |  00000097 | END OF GUARDED AREA (EPA)
     09 |  0000008D | REVERSE LINE FEED (RI)
     0A |  0000008E | SINGLE-SHIFT TWO (SS2)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  0000009D | OPERATING SYSTEM COMMAND (OSC)
     15 |  00000085 | NEXT LINE (NEL)
     16 |  00000008 | BACKSPACE (BS)
     17 |  00000087 | END OF SELECTED AREA (ESA)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  00000092 | PRIVATE USE TWO (PU2)
     1B |  0000008F | SINGLE-SHIFT THREE (SS3)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000080 | PADDING CHARACTER (PAD)
     21 |  00000081 | HIGH OCTET PRESET (HOP)
     22 |  00000082 | BREAK PERMITTED HERE (BPH)
     23 |  00000083 | NO BREAK HERE (NBH)
     24 |  00000084 | INDEX (IND)
     25 |  0000000A | LINE FEED (LF)
     26 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     27 |  0000001B | ESCAPE (ESC)
     28 |  00000088 | CHARACTER TABULATION SET (HTS)
     29 |  00000089 | CHARACTER TABULATION WITH JUSTIFICATION (HTJ)
     2A |  0000008A | LINE TABULATION SET (VTS)
     2B |  0000008B | PARTIAL LINE FORWARD (PLD)
     2C |  0000008C | PARTIAL LINE BACKWARD (PLU)
     2D |  00000005 | ENQUIRY (ENQ)
     2E |  00000006 | ACKNOWLEDGE (ACK)
     2F |  00000007 | BELL (BEL)
     30 |  00000090 | DEVICE CONTROL STRING (DCS)
     31 |  00000091 | PRIVATE USE ONE (PU1)
     32 |  00000016 | SYNCHRONOUS IDLE (SYN)
     33 |  00000093 | SET TRANSMIT STATE (STS)
     34 |  00000094 | CANCEL CHARACTER (CCH)
     35 |  00000095 | MESSAGE WAITING (MW)
     36 |  00000096 | START OF GUARDED AREA (SPA)
     37 |  00000004 | END OF TRANSMISSION (EOT)
     38 |  00000098 | START OF STRING (SOS)
     39 |  00000099 | SINGLE GRAPHIC CHARACTER INTRODUCER (SGCI)
     3A |  0000009A | SINGLE CHARACTER INTRODUCER (SCI)
     3B |  0000009B | CONTROL SEQUENCE INTRODUCER (CSI)
     3C |  00000014 | DEVICE CONTROL FOUR (DC4)
     3D |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     3E |  0000009E | PRIVACY MESSAGE (PM)
     3F |  0000001A | SUBSTITUTE (SUB)
     40 |  00000020 | SPACE
     4A |  000000F8 | LATIN SMALL LETTER O WITH STROKE
     4B |  0000002E | FULL STOP
     4C |  0000003C | LESS-THAN SIGN
     4D |  00000028 | LEFT PARENTHESIS
     4E |  0000002B | PLUS SIGN
     4F |  0000007C | VERTICAL LINE
     50 |  00000026 | AMPERSAND
     5A |  000000E5 | LATIN SMALL LETTER A WITH RING ABOVE
     5B |  000000C5 | LATIN CAPITAL LETTER A WITH RING ABOVE
     5C |  0000002A | ASTERISK
     5D |  00000029 | RIGHT PARENTHESIS
     5E |  0000003B | SEMICOLON
     5F |  000000AC | NOT SIGN
     60 |  0000002D | HYPHEN-MINUS
     61 |  0000002F | SOLIDUS
     6A |  000000A6 | BROKEN BAR
     6B |  0000002C | COMMA
     6C |  00000025 | PERCENT SIGN
     6D |  0000005F | LOW LINE
     6E |  0000003E | GREATER-THAN SIGN
     6F |  0000003F | QUESTION MARK
     7A |  0000003A | COLON
     7B |  000000C6 | LATIN CAPITAL LETTER AE
     7C |  000000D8 | LATIN CAPITAL LETTER O WITH STROKE
     7D |  00000027 | APOSTROPHE
     7E |  0000003D | EQUALS SIGN
     7F |  000000E6 | LATIN SMALL LETTER AE
     81 |  00000061 | LATIN SMALL LETTER A
     82 |  00000062 | LATIN SMALL LETTER B
     83 |  00000063 | LATIN SMALL LETTER C
     84 |  00000064 | LATIN SMALL LETTER D
     85 |  00000065 | LATIN SMALL LETTER E
     86 |  00000066 | LATIN SMALL LETTER F
     87 |  00000067 | LATIN SMALL LETTER G
     88 |  00000068 | LATIN SMALL LETTER H
     89 |  00000069 | LATIN SMALL LETTER I
     91 |  0000006A | LATIN SMALL LETTER J
     92 |  0000006B | LATIN SMALL LETTER K
     93 |  0000006C | LATIN SMALL LETTER L
     94 |  0000006D | LATIN SMALL LETTER M
     95 |  0000006E | LATIN SMALL LETTER N
     96 |  0000006F | LATIN SMALL LETTER O
     97 |  00000070 | LATIN SMALL LETTER P
     98 |  00000071 | LATIN SMALL LETTER Q
     99 |  00000072 | LATIN SMALL LETTER R
     A2 |  00000073 | LATIN SMALL LETTER S
     A3 |  00000074 | LATIN SMALL LETTER T
     A4 |  00000075 | LATIN SMALL LETTER U
     A5 |  00000076 | LATIN SMALL LETTER V
     A6 |  00000077 | LATIN SMALL LETTER W
     A7 |  00000078 | LATIN SMALL LETTER X
     A8 |  00000079 | LATIN SMALL LETTER Y
     A9 |  0000007A | LATIN SMALL LETTER Z
     C1 |  00000041 | LATIN CAPITAL LETTER A
     C2 |  00000042 | LATIN CAPITAL LETTER B
     C3 |  00000043 | LATIN CAPITAL LETTER C
     C4 |  00000044 | LATIN CAPITAL LETTER D
     C5 |  00000045 | LATIN CAPITAL LETTER E
     C6 |  00000046 | LATIN CAPITAL LETTER F
     C7 |  00000047 | LATIN CAPITAL LETTER G
     C8 |  00000048 | LATIN CAPITAL LETTER H
     C9 |  00000049 | LATIN CAPITAL LETTER I
     D1 |  0000004A | LATIN CAPITAL LETTER J
     D2 |  0000004B | LATIN CAPITAL LETTER K
     D3 |  0000004C | LATIN CAPITAL LETTER L
     D4 |  0000004D | LATIN CAPITAL LETTER M
     D5 |  0000004E | LATIN CAPITAL LETTER N
     D6 |  0000004F | LATIN CAPITAL LETTER O
     D7 |  00000050 | LATIN CAPITAL LETTER P
     D8 |  00000051 | LATIN CAPITAL LETTER Q
     D9 |  00000052 | LATIN CAPITAL LETTER R
     E2 |  00000053 | LATIN CAPITAL LETTER S
     E3 |  00000054 | LATIN CAPITAL LETTER T
     E4 |  00000055 | LATIN CAPITAL LETTER U
     E5 |  00000056 | LATIN CAPITAL LETTER V
     E6 |  00000057 | LATIN CAPITAL LETTER W
     E7 |  00000058 | LATIN CAPITAL LETTER X
     E8 |  00000059 | LATIN CAPITAL LETTER Y
     E9 |  0000005A | LATIN CAPITAL LETTER Z
     F0 |  00000030 | DIGIT ZERO
     F1 |  00000031 | DIGIT ONE
     F2 |  00000032 | DIGIT TWO
     F3 |  00000033 | DIGIT THREE
     F4 |  00000034 | DIGIT FOUR
     F5 |  00000035 | DIGIT FIVE
     F6 |  00000036 | DIGIT SIX
     F7 |  00000037 | DIGIT SEVEN
     F8 |  00000038 | DIGIT EIGHT
     F9 |  00000039 | DIGIT NINE
     FF |  0000009F | APPLICATION PROGRAM COMMAND (APC)
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/EBCDIC_ES.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for EBCDIC-ES.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::EBCDIC_ES;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x009c,
     0x0009,
     0x0086,
     0x007f,
     0x0097,
     0x008d,
     0x008e,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x009d,
     0x0085,
     0x0008,
     0x0087,
     0x0018,
     0x0019,
     0x0092,
     0x008f,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0080,
     0x0081,
     0x0082,
     0x0083,
     0x0084,
     0x000a,
     0x0017,
     0x001b,
     0x0088,
     0x0089,
     0x008a,
     0x008b,
     0x008c,
     0x0005,
     0x0006,
     0x0007,
     0x0090,
     0x0091,
     0x0016,
     0x0093,
     0x0094,
     0x0095,
     0x0096,
     0x0004,
     0x0098,
     0x0099,
     0x009a,
     0x009b,
     0x0014,
     0x0015,
     0x009e,
     0x001a,
     0x0020,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00a2,
     0x002e,
     0x003c,
     0x0028,
     0x002b,
     0x007c,
     0x0026,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x0021,
     0x20a7,
     0x002a,
     0x0029,
     0x003b,
     0x00ac,
     0x002d,
     0x002f,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00f1,
     0x002c,
     0x0025,
     0x005f,
     0x003e,
     0x003f,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x0060,
     0x003a,
     0x00d1,
     0x0040,
     0x0027,
     0x003d,
     0x0022,
     0xfffd,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00a8,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x007b,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x007d,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x005c,
     0xfffd,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x009f,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\xc2\x9c",
     "\x09",
     "\xc2\x86",
     "\x7f",
     "\xc2\x97",
     "\xc2\x8d",
     "\xc2\x8e",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\xc2\x9d",
     "\xc2\x85",
     "\x08",
     "\xc2\x87",
     "\x18",
     "\x19",
     "\xc2\x92",
     "\xc2\x8f",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\xc2\x80",
     "\xc2\x81",
     "\xc2\x82",
     "\xc2\x83",
     "\xc2\x84",
     "\x0a",
     "\x17",
     "\x1b",
     "\xc2\x88",
     "\xc2\x89",
     "\xc2\x8a",
     "\xc2\x8b",
     "\xc2\x8c",
     "\x05",
     "\x06",
     "\x07",
     "\xc2\x90",
     "\xc2\x91",
     "\x16",
     "\xc2\x93",
     "\xc2\x94",
     "\xc2\x95",
     "\xc2\x96",
     "\x04",
     "\xc2\x98",
     "\xc2\x99",
     "\xc2\x9a",
     "\xc2\x9b",
     "\x14",
     "\x15",
     "\xc2\x9e",
     "\x1a",
     "\x20",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc2\xa2",
     "\x2e",
     "\x3c",
     "\x28",
     "\x2b",
     "\x7c",
     "\x26",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x21",
     "\xe2\x82\xa7",
     "\x2a",
     "\x29",
     "\x3b",
     "\xc2\xac",
     "\x2d",
     "\x2f",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc3\xb1",
     "\x2c",
     "\x25",
     "\x5f",
     "\x3e",
     "\x3f",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x60",
     "\x3a",
     "\xc3\x91",
     "\x40",
     "\x27",
     "\x3d",
     "\x22",
     "\xef\xbf\xbd",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc2\xa8",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x7b",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x7d",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x5c",
     "\xef\xbf\xbd",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc2\x9f",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x37",
     0x00000005 => "\x2d",
     0x00000006 => "\x2e",
     0x00000007 => "\x2f",
     0x00000008 => "\x16",
     0x00000009 => "\x05",
     0x0000000a => "\x25",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x3c",
     0x00000015 => "\x3d",
     0x00000016 => "\x32",
     0x00000017 => "\x26",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x3f",
     0x0000001b => "\x27",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x40",
     0x00000021 => "\x5a",
     0x00000022 => "\x7f",
     0x00000025 => "\x6c",
     0x00000026 => "\x50",
     0x00000027 => "\x7d",
     0x00000028 => "\x4d",
     0x00000029 => "\x5d",
     0x0000002a => "\x5c",
     0x0000002b => "\x4e",
     0x0000002c => "\x6b",
     0x0000002d => "\x60",
     0x0000002e => "\x4b",
     0x0000002f => "\x61",
     0x00000030 => "\xf0",
     0x00000031 => "\xf1",
     0x00000032 => "\xf2",
     0x00000033 => "\xf3",
     0x00000034 => "\xf4",
     0x00000035 => "\xf5",
     0x00000036 => "\xf6",
     0x00000037 => "\xf7",
     0x00000038 => "\xf8",
     0x00000039 => "\xf9",
     0x0000003a => "\x7a",
     0x0000003b => "\x5e",
     0x0000003c => "\x4c",
     0x0000003d => "\x7e",
     0x0000003e => "\x6e",
     0x0000003f => "\x6f",
     0x00000040 => "\x7c",
     0x00000041 => "\xc1",
     0x00000042 => "\xc2",
     0x00000043 => "\xc3",
     0x00000044 => "\xc4",
     0x00000045 => "\xc5",
     0x00000046 => "\xc6",
     0x00000047 => "\xc7",
     0x00000048 => "\xc8",
     0x00000049 => "\xc9",
     0x0000004a => "\xd1",
     0x0000004b => "\xd2",
     0x0000004c => "\xd3",
     0x0000004d => "\xd4",
     0x0000004e => "\xd5",
     0x0000004f => "\xd6",
     0x00000050 => "\xd7",
     0x00000051 => "\xd8",
     0x00000052 => "\xd9",
     0x00000053 => "\xe2",
     0x00000054 => "\xe3",
     0x00000055 => "\xe4",
     0x00000056 => "\xe5",
     0x00000057 => "\xe6",
     0x00000058 => "\xe7",
     0x00000059 => "\xe8",
     0x0000005a => "\xe9",
     0x0000005c => "\xe0",
     0x0000005f => "\x6d",
     0x00000060 => "\x79",
     0x00000061 => "\x81",
     0x00000062 => "\x82",
     0x00000063 => "\x83",
     0x00000064 => "\x84",
     0x00000065 => "\x85",
     0x00000066 => "\x86",
     0x00000067 => "\x87",
     0x00000068 => "\x88",
     0x00000069 => "\x89",
     0x0000006a => "\x91",
     0x0000006b => "\x92",
     0x0000006c => "\x93",
     0x0000006d => "\x94",
     0x0000006e => "\x95",
     0x0000006f => "\x96",
     0x00000070 => "\x97",
     0x00000071 => "\x98",
     0x00000072 => "\x99",
     0x00000073 => "\xa2",
     0x00000074 => "\xa3",
     0x00000075 => "\xa4",
     0x00000076 => "\xa5",
     0x00000077 => "\xa6",
     0x00000078 => "\xa7",
     0x00000079 => "\xa8",
     0x0000007a => "\xa9",
     0x0000007b => "\xc0",
     0x0000007c => "\x4f",
     0x0000007d => "\xd0",
     0x0000007f => "\x07",
     0x00000080 => "\x20",
     0x00000081 => "\x21",
     0x00000082 => "\x22",
     0x00000083 => "\x23",
     0x00000084 => "\x24",
     0x00000085 => "\x15",
     0x00000086 => "\x06",
     0x00000087 => "\x17",
     0x00000088 => "\x28",
     0x00000089 => "\x29",
     0x0000008a => "\x2a",
     0x0000008b => "\x2b",
     0x0000008c => "\x2c",
     0x0000008d => "\x09",
     0x0000008e => "\x0a",
     0x0000008f => "\x1b",
     0x00000090 => "\x30",
     0x00000091 => "\x31",
     0x00000092 => "\x1a",
     0x00000093 => "\x33",
     0x00000094 => "\x34",
     0x00000095 => "\x35",
     0x00000096 => "\x36",
     0x00000097 => "\x08",
     0x00000098 => "\x38",
     0x00000099 => "\x39",
     0x0000009a => "\x3a",
     0x0000009b => "\x3b",
     0x0000009c => "\x04",
     0x0000009d => "\x14",
     0x0000009e => "\x3e",
     0x0000009f => "\xff",
     0x000000a2 => "\x4a",
     0x000000a8 => "\xa1",
     0x000000ac => "\x5f",
     0x000000d1 => "\x7b",
     0x000000f1 => "\x6a",
     0x000020a7 => "\x5b",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::EBCDIC_ES - Conversion routines for EBCDIC_ES
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for EBCDIC-ES.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
   source: IBM 3270 Char Set Ref Ch 10, GA27-2837-9, April 1987
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  0000009C | STRING TERMINATOR (ST)
     05 |  00000009 | CHARACTER TABULATION (HT)
     06 |  00000086 | START OF SELECTED AREA (SSA)
     07 |  0000007F | DELETE (DEL)
     08 |  00000097 | END OF GUARDED AREA (EPA)
     09 |  0000008D | REVERSE LINE FEED (RI)
     0A |  0000008E | SINGLE-SHIFT TWO (SS2)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  0000009D | OPERATING SYSTEM COMMAND (OSC)
     15 |  00000085 | NEXT LINE (NEL)
     16 |  00000008 | BACKSPACE (BS)
     17 |  00000087 | END OF SELECTED AREA (ESA)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  00000092 | PRIVATE USE TWO (PU2)
     1B |  0000008F | SINGLE-SHIFT THREE (SS3)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000080 | PADDING CHARACTER (PAD)
     21 |  00000081 | HIGH OCTET PRESET (HOP)
     22 |  00000082 | BREAK PERMITTED HERE (BPH)
     23 |  00000083 | NO BREAK HERE (NBH)
     24 |  00000084 | INDEX (IND)
     25 |  0000000A | LINE FEED (LF)
     26 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     27 |  0000001B | ESCAPE (ESC)
     28 |  00000088 | CHARACTER TABULATION SET (HTS)
     29 |  00000089 | CHARACTER TABULATION WITH JUSTIFICATION (HTJ)
     2A |  0000008A | LINE TABULATION SET (VTS)
     2B |  0000008B | PARTIAL LINE FORWARD (PLD)
     2C |  0000008C | PARTIAL LINE BACKWARD (PLU)
     2D |  00000005 | ENQUIRY (ENQ)
     2E |  00000006 | ACKNOWLEDGE (ACK)
     2F |  00000007 | BELL (BEL)
     30 |  00000090 | DEVICE CONTROL STRING (DCS)
     31 |  00000091 | PRIVATE USE ONE (PU1)
     32 |  00000016 | SYNCHRONOUS IDLE (SYN)
     33 |  00000093 | SET TRANSMIT STATE (STS)
     34 |  00000094 | CANCEL CHARACTER (CCH)
     35 |  00000095 | MESSAGE WAITING (MW)
     36 |  00000096 | START OF GUARDED AREA (SPA)
     37 |  00000004 | END OF TRANSMISSION (EOT)
     38 |  00000098 | START OF STRING (SOS)
     39 |  00000099 | SINGLE GRAPHIC CHARACTER INTRODUCER (SGCI)
     3A |  0000009A | SINGLE CHARACTER INTRODUCER (SCI)
     3B |  0000009B | CONTROL SEQUENCE INTRODUCER (CSI)
     3C |  00000014 | DEVICE CONTROL FOUR (DC4)
     3D |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     3E |  0000009E | PRIVACY MESSAGE (PM)
     3F |  0000001A | SUBSTITUTE (SUB)
     40 |  00000020 | SPACE
     4A |  000000A2 | CENT SIGN
     4B |  0000002E | FULL STOP
     4C |  0000003C | LESS-THAN SIGN
     4D |  00000028 | LEFT PARENTHESIS
     4E |  0000002B | PLUS SIGN
     4F |  0000007C | VERTICAL LINE
     50 |  00000026 | AMPERSAND
     5A |  00000021 | EXCLAMATION MARK
     5B |  000020A7 | PESETA SIGN
     5C |  0000002A | ASTERISK
     5D |  00000029 | RIGHT PARENTHESIS
     5E |  0000003B | SEMICOLON
     5F |  000000AC | NOT SIGN
     60 |  0000002D | HYPHEN-MINUS
     61 |  0000002F | SOLIDUS
     6A |  000000F1 | LATIN SMALL LETTER N WITH TILDE
     6B |  0000002C | COMMA
     6C |  00000025 | PERCENT SIGN
     6D |  0000005F | LOW LINE
     6E |  0000003E | GREATER-THAN SIGN
     6F |  0000003F | QUESTION MARK
     79 |  00000060 | GRAVE ACCENT
     7A |  0000003A | COLON
     7B |  000000D1 | LATIN CAPITAL LETTER N WITH TILDE
     7C |  00000040 | COMMERCIAL AT
     7D |  00000027 | APOSTROPHE
     7E |  0000003D | EQUALS SIGN
     7F |  00000022 | QUOTATION MARK
     81 |  00000061 | LATIN SMALL LETTER A
     82 |  00000062 | LATIN SMALL LETTER B
     83 |  00000063 | LATIN SMALL LETTER C
     84 |  00000064 | LATIN SMALL LETTER D
     85 |  00000065 | LATIN SMALL LETTER E
     86 |  00000066 | LATIN SMALL LETTER F
     87 |  00000067 | LATIN SMALL LETTER G
     88 |  00000068 | LATIN SMALL LETTER H
     89 |  00000069 | LATIN SMALL LETTER I
     91 |  0000006A | LATIN SMALL LETTER J
     92 |  0000006B | LATIN SMALL LETTER K
     93 |  0000006C | LATIN SMALL LETTER L
     94 |  0000006D | LATIN SMALL LETTER M
     95 |  0000006E | LATIN SMALL LETTER N
     96 |  0000006F | LATIN SMALL LETTER O
     97 |  00000070 | LATIN SMALL LETTER P
     98 |  00000071 | LATIN SMALL LETTER Q
     99 |  00000072 | LATIN SMALL LETTER R
     A1 |  000000A8 | DIAERESIS
     A2 |  00000073 | LATIN SMALL LETTER S
     A3 |  00000074 | LATIN SMALL LETTER T
     A4 |  00000075 | LATIN SMALL LETTER U
     A5 |  00000076 | LATIN SMALL LETTER V
     A6 |  00000077 | LATIN SMALL LETTER W
     A7 |  00000078 | LATIN SMALL LETTER X
     A8 |  00000079 | LATIN SMALL LETTER Y
     A9 |  0000007A | LATIN SMALL LETTER Z
     C0 |  0000007B | LEFT CURLY BRACKET
     C1 |  00000041 | LATIN CAPITAL LETTER A
     C2 |  00000042 | LATIN CAPITAL LETTER B
     C3 |  00000043 | LATIN CAPITAL LETTER C
     C4 |  00000044 | LATIN CAPITAL LETTER D
     C5 |  00000045 | LATIN CAPITAL LETTER E
     C6 |  00000046 | LATIN CAPITAL LETTER F
     C7 |  00000047 | LATIN CAPITAL LETTER G
     C8 |  00000048 | LATIN CAPITAL LETTER H
     C9 |  00000049 | LATIN CAPITAL LETTER I
     D0 |  0000007D | RIGHT CURLY BRACKET
     D1 |  0000004A | LATIN CAPITAL LETTER J
     D2 |  0000004B | LATIN CAPITAL LETTER K
     D3 |  0000004C | LATIN CAPITAL LETTER L
     D4 |  0000004D | LATIN CAPITAL LETTER M
     D5 |  0000004E | LATIN CAPITAL LETTER N
     D6 |  0000004F | LATIN CAPITAL LETTER O
     D7 |  00000050 | LATIN CAPITAL LETTER P
     D8 |  00000051 | LATIN CAPITAL LETTER Q
     D9 |  00000052 | LATIN CAPITAL LETTER R
     E0 |  0000005C | REVERSE SOLIDUS
     E2 |  00000053 | LATIN CAPITAL LETTER S
     E3 |  00000054 | LATIN CAPITAL LETTER T
     E4 |  00000055 | LATIN CAPITAL LETTER U
     E5 |  00000056 | LATIN CAPITAL LETTER V
     E6 |  00000057 | LATIN CAPITAL LETTER W
     E7 |  00000058 | LATIN CAPITAL LETTER X
     E8 |  00000059 | LATIN CAPITAL LETTER Y
     E9 |  0000005A | LATIN CAPITAL LETTER Z
     F0 |  00000030 | DIGIT ZERO
     F1 |  00000031 | DIGIT ONE
     F2 |  00000032 | DIGIT TWO
     F3 |  00000033 | DIGIT THREE
     F4 |  00000034 | DIGIT FOUR
     F5 |  00000035 | DIGIT FIVE
     F6 |  00000036 | DIGIT SIX
     F7 |  00000037 | DIGIT SEVEN
     F8 |  00000038 | DIGIT EIGHT
     F9 |  00000039 | DIGIT NINE
     FF |  0000009F | APPLICATION PROGRAM COMMAND (APC)
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/EBCDIC_ES_A.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for EBCDIC-ES-A.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::EBCDIC_ES_A;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x009c,
     0x0009,
     0x0086,
     0x007f,
     0x0097,
     0x008d,
     0x008e,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x009d,
     0x0085,
     0x0008,
     0x0087,
     0x0018,
     0x0019,
     0x0092,
     0x008f,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0080,
     0x0081,
     0x0082,
     0x0083,
     0x0084,
     0x000a,
     0x0017,
     0x001b,
     0x0088,
     0x0089,
     0x008a,
     0x008b,
     0x008c,
     0x0005,
     0x0006,
     0x0007,
     0x0090,
     0x0091,
     0x0016,
     0x0093,
     0x0094,
     0x0095,
     0x0096,
     0x0004,
     0x0098,
     0x0099,
     0x009a,
     0x009b,
     0x0014,
     0x0015,
     0x009e,
     0x001a,
     0x0020,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00a2,
     0x002e,
     0x003c,
     0x0028,
     0x002b,
     0x007c,
     0x0026,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x0021,
     0x20a7,
     0x002a,
     0x0029,
     0x003b,
     0x00ac,
     0x002d,
     0x002f,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00a6,
     0x002c,
     0x0025,
     0x005f,
     0x003e,
     0x003f,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x003a,
     0x00d1,
     0x0040,
     0x0027,
     0x003d,
     0x00f1,
     0xfffd,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x009f,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\xc2\x9c",
     "\x09",
     "\xc2\x86",
     "\x7f",
     "\xc2\x97",
     "\xc2\x8d",
     "\xc2\x8e",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\xc2\x9d",
     "\xc2\x85",
     "\x08",
     "\xc2\x87",
     "\x18",
     "\x19",
     "\xc2\x92",
     "\xc2\x8f",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\xc2\x80",
     "\xc2\x81",
     "\xc2\x82",
     "\xc2\x83",
     "\xc2\x84",
     "\x0a",
     "\x17",
     "\x1b",
     "\xc2\x88",
     "\xc2\x89",
     "\xc2\x8a",
     "\xc2\x8b",
     "\xc2\x8c",
     "\x05",
     "\x06",
     "\x07",
     "\xc2\x90",
     "\xc2\x91",
     "\x16",
     "\xc2\x93",
     "\xc2\x94",
     "\xc2\x95",
     "\xc2\x96",
     "\x04",
     "\xc2\x98",
     "\xc2\x99",
     "\xc2\x9a",
     "\xc2\x9b",
     "\x14",
     "\x15",
     "\xc2\x9e",
     "\x1a",
     "\x20",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc2\xa2",
     "\x2e",
     "\x3c",
     "\x28",
     "\x2b",
     "\x7c",
     "\x26",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x21",
     "\xe2\x82\xa7",
     "\x2a",
     "\x29",
     "\x3b",
     "\xc2\xac",
     "\x2d",
     "\x2f",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc2\xa6",
     "\x2c",
     "\x25",
     "\x5f",
     "\x3e",
     "\x3f",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x3a",
     "\xc3\x91",
     "\x40",
     "\x27",
     "\x3d",
     "\xc3\xb1",
     "\xef\xbf\xbd",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc2\x9f",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x37",
     0x00000005 => "\x2d",
     0x00000006 => "\x2e",
     0x00000007 => "\x2f",
     0x00000008 => "\x16",
     0x00000009 => "\x05",
     0x0000000a => "\x25",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x3c",
     0x00000015 => "\x3d",
     0x00000016 => "\x32",
     0x00000017 => "\x26",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x3f",
     0x0000001b => "\x27",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x40",
     0x00000021 => "\x5a",
     0x00000025 => "\x6c",
     0x00000026 => "\x50",
     0x00000027 => "\x7d",
     0x00000028 => "\x4d",
     0x00000029 => "\x5d",
     0x0000002a => "\x5c",
     0x0000002b => "\x4e",
     0x0000002c => "\x6b",
     0x0000002d => "\x60",
     0x0000002e => "\x4b",
     0x0000002f => "\x61",
     0x00000030 => "\xf0",
     0x00000031 => "\xf1",
     0x00000032 => "\xf2",
     0x00000033 => "\xf3",
     0x00000034 => "\xf4",
     0x00000035 => "\xf5",
     0x00000036 => "\xf6",
     0x00000037 => "\xf7",
     0x00000038 => "\xf8",
     0x00000039 => "\xf9",
     0x0000003a => "\x7a",
     0x0000003b => "\x5e",
     0x0000003c => "\x4c",
     0x0000003d => "\x7e",
     0x0000003e => "\x6e",
     0x0000003f => "\x6f",
     0x00000040 => "\x7c",
     0x00000041 => "\xc1",
     0x00000042 => "\xc2",
     0x00000043 => "\xc3",
     0x00000044 => "\xc4",
     0x00000045 => "\xc5",
     0x00000046 => "\xc6",
     0x00000047 => "\xc7",
     0x00000048 => "\xc8",
     0x00000049 => "\xc9",
     0x0000004a => "\xd1",
     0x0000004b => "\xd2",
     0x0000004c => "\xd3",
     0x0000004d => "\xd4",
     0x0000004e => "\xd5",
     0x0000004f => "\xd6",
     0x00000050 => "\xd7",
     0x00000051 => "\xd8",
     0x00000052 => "\xd9",
     0x00000053 => "\xe2",
     0x00000054 => "\xe3",
     0x00000055 => "\xe4",
     0x00000056 => "\xe5",
     0x00000057 => "\xe6",
     0x00000058 => "\xe7",
     0x00000059 => "\xe8",
     0x0000005a => "\xe9",
     0x0000005f => "\x6d",
     0x00000061 => "\x81",
     0x00000062 => "\x82",
     0x00000063 => "\x83",
     0x00000064 => "\x84",
     0x00000065 => "\x85",
     0x00000066 => "\x86",
     0x00000067 => "\x87",
     0x00000068 => "\x88",
     0x00000069 => "\x89",
     0x0000006a => "\x91",
     0x0000006b => "\x92",
     0x0000006c => "\x93",
     0x0000006d => "\x94",
     0x0000006e => "\x95",
     0x0000006f => "\x96",
     0x00000070 => "\x97",
     0x00000071 => "\x98",
     0x00000072 => "\x99",
     0x00000073 => "\xa2",
     0x00000074 => "\xa3",
     0x00000075 => "\xa4",
     0x00000076 => "\xa5",
     0x00000077 => "\xa6",
     0x00000078 => "\xa7",
     0x00000079 => "\xa8",
     0x0000007a => "\xa9",
     0x0000007c => "\x4f",
     0x0000007f => "\x07",
     0x00000080 => "\x20",
     0x00000081 => "\x21",
     0x00000082 => "\x22",
     0x00000083 => "\x23",
     0x00000084 => "\x24",
     0x00000085 => "\x15",
     0x00000086 => "\x06",
     0x00000087 => "\x17",
     0x00000088 => "\x28",
     0x00000089 => "\x29",
     0x0000008a => "\x2a",
     0x0000008b => "\x2b",
     0x0000008c => "\x2c",
     0x0000008d => "\x09",
     0x0000008e => "\x0a",
     0x0000008f => "\x1b",
     0x00000090 => "\x30",
     0x00000091 => "\x31",
     0x00000092 => "\x1a",
     0x00000093 => "\x33",
     0x00000094 => "\x34",
     0x00000095 => "\x35",
     0x00000096 => "\x36",
     0x00000097 => "\x08",
     0x00000098 => "\x38",
     0x00000099 => "\x39",
     0x0000009a => "\x3a",
     0x0000009b => "\x3b",
     0x0000009c => "\x04",
     0x0000009d => "\x14",
     0x0000009e => "\x3e",
     0x0000009f => "\xff",
     0x000000a2 => "\x4a",
     0x000000a6 => "\x6a",
     0x000000ac => "\x5f",
     0x000000d1 => "\x7b",
     0x000000f1 => "\x7f",
     0x000020a7 => "\x5b",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::EBCDIC_ES_A - Conversion routines for EBCDIC_ES_A
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for EBCDIC-ES-A.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
   source: IBM 3270 Char Set Ref Ch 10, GA27-2837-9, April 1987
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  0000009C | STRING TERMINATOR (ST)
     05 |  00000009 | CHARACTER TABULATION (HT)
     06 |  00000086 | START OF SELECTED AREA (SSA)
     07 |  0000007F | DELETE (DEL)
     08 |  00000097 | END OF GUARDED AREA (EPA)
     09 |  0000008D | REVERSE LINE FEED (RI)
     0A |  0000008E | SINGLE-SHIFT TWO (SS2)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  0000009D | OPERATING SYSTEM COMMAND (OSC)
     15 |  00000085 | NEXT LINE (NEL)
     16 |  00000008 | BACKSPACE (BS)
     17 |  00000087 | END OF SELECTED AREA (ESA)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  00000092 | PRIVATE USE TWO (PU2)
     1B |  0000008F | SINGLE-SHIFT THREE (SS3)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000080 | PADDING CHARACTER (PAD)
     21 |  00000081 | HIGH OCTET PRESET (HOP)
     22 |  00000082 | BREAK PERMITTED HERE (BPH)
     23 |  00000083 | NO BREAK HERE (NBH)
     24 |  00000084 | INDEX (IND)
     25 |  0000000A | LINE FEED (LF)
     26 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     27 |  0000001B | ESCAPE (ESC)
     28 |  00000088 | CHARACTER TABULATION SET (HTS)
     29 |  00000089 | CHARACTER TABULATION WITH JUSTIFICATION (HTJ)
     2A |  0000008A | LINE TABULATION SET (VTS)
     2B |  0000008B | PARTIAL LINE FORWARD (PLD)
     2C |  0000008C | PARTIAL LINE BACKWARD (PLU)
     2D |  00000005 | ENQUIRY (ENQ)
     2E |  00000006 | ACKNOWLEDGE (ACK)
     2F |  00000007 | BELL (BEL)
     30 |  00000090 | DEVICE CONTROL STRING (DCS)
     31 |  00000091 | PRIVATE USE ONE (PU1)
     32 |  00000016 | SYNCHRONOUS IDLE (SYN)
     33 |  00000093 | SET TRANSMIT STATE (STS)
     34 |  00000094 | CANCEL CHARACTER (CCH)
     35 |  00000095 | MESSAGE WAITING (MW)
     36 |  00000096 | START OF GUARDED AREA (SPA)
     37 |  00000004 | END OF TRANSMISSION (EOT)
     38 |  00000098 | START OF STRING (SOS)
     39 |  00000099 | SINGLE GRAPHIC CHARACTER INTRODUCER (SGCI)
     3A |  0000009A | SINGLE CHARACTER INTRODUCER (SCI)
     3B |  0000009B | CONTROL SEQUENCE INTRODUCER (CSI)
     3C |  00000014 | DEVICE CONTROL FOUR (DC4)
     3D |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     3E |  0000009E | PRIVACY MESSAGE (PM)
     3F |  0000001A | SUBSTITUTE (SUB)
     40 |  00000020 | SPACE
     4A |  000000A2 | CENT SIGN
     4B |  0000002E | FULL STOP
     4C |  0000003C | LESS-THAN SIGN
     4D |  00000028 | LEFT PARENTHESIS
     4E |  0000002B | PLUS SIGN
     4F |  0000007C | VERTICAL LINE
     50 |  00000026 | AMPERSAND
     5A |  00000021 | EXCLAMATION MARK
     5B |  000020A7 | PESETA SIGN
     5C |  0000002A | ASTERISK
     5D |  00000029 | RIGHT PARENTHESIS
     5E |  0000003B | SEMICOLON
     5F |  000000AC | NOT SIGN
     60 |  0000002D | HYPHEN-MINUS
     61 |  0000002F | SOLIDUS
     6A |  000000A6 | BROKEN BAR
     6B |  0000002C | COMMA
     6C |  00000025 | PERCENT SIGN
     6D |  0000005F | LOW LINE
     6E |  0000003E | GREATER-THAN SIGN
     6F |  0000003F | QUESTION MARK
     7A |  0000003A | COLON
     7B |  000000D1 | LATIN CAPITAL LETTER N WITH TILDE
     7C |  00000040 | COMMERCIAL AT
     7D |  00000027 | APOSTROPHE
     7E |  0000003D | EQUALS SIGN
     7F |  000000F1 | LATIN SMALL LETTER N WITH TILDE
     81 |  00000061 | LATIN SMALL LETTER A
     82 |  00000062 | LATIN SMALL LETTER B
     83 |  00000063 | LATIN SMALL LETTER C
     84 |  00000064 | LATIN SMALL LETTER D
     85 |  00000065 | LATIN SMALL LETTER E
     86 |  00000066 | LATIN SMALL LETTER F
     87 |  00000067 | LATIN SMALL LETTER G
     88 |  00000068 | LATIN SMALL LETTER H
     89 |  00000069 | LATIN SMALL LETTER I
     91 |  0000006A | LATIN SMALL LETTER J
     92 |  0000006B | LATIN SMALL LETTER K
     93 |  0000006C | LATIN SMALL LETTER L
     94 |  0000006D | LATIN SMALL LETTER M
     95 |  0000006E | LATIN SMALL LETTER N
     96 |  0000006F | LATIN SMALL LETTER O
     97 |  00000070 | LATIN SMALL LETTER P
     98 |  00000071 | LATIN SMALL LETTER Q
     99 |  00000072 | LATIN SMALL LETTER R
     A2 |  00000073 | LATIN SMALL LETTER S
     A3 |  00000074 | LATIN SMALL LETTER T
     A4 |  00000075 | LATIN SMALL LETTER U
     A5 |  00000076 | LATIN SMALL LETTER V
     A6 |  00000077 | LATIN SMALL LETTER W
     A7 |  00000078 | LATIN SMALL LETTER X
     A8 |  00000079 | LATIN SMALL LETTER Y
     A9 |  0000007A | LATIN SMALL LETTER Z
     C1 |  00000041 | LATIN CAPITAL LETTER A
     C2 |  00000042 | LATIN CAPITAL LETTER B
     C3 |  00000043 | LATIN CAPITAL LETTER C
     C4 |  00000044 | LATIN CAPITAL LETTER D
     C5 |  00000045 | LATIN CAPITAL LETTER E
     C6 |  00000046 | LATIN CAPITAL LETTER F
     C7 |  00000047 | LATIN CAPITAL LETTER G
     C8 |  00000048 | LATIN CAPITAL LETTER H
     C9 |  00000049 | LATIN CAPITAL LETTER I
     D1 |  0000004A | LATIN CAPITAL LETTER J
     D2 |  0000004B | LATIN CAPITAL LETTER K
     D3 |  0000004C | LATIN CAPITAL LETTER L
     D4 |  0000004D | LATIN CAPITAL LETTER M
     D5 |  0000004E | LATIN CAPITAL LETTER N
     D6 |  0000004F | LATIN CAPITAL LETTER O
     D7 |  00000050 | LATIN CAPITAL LETTER P
     D8 |  00000051 | LATIN CAPITAL LETTER Q
     D9 |  00000052 | LATIN CAPITAL LETTER R
     E2 |  00000053 | LATIN CAPITAL LETTER S
     E3 |  00000054 | LATIN CAPITAL LETTER T
     E4 |  00000055 | LATIN CAPITAL LETTER U
     E5 |  00000056 | LATIN CAPITAL LETTER V
     E6 |  00000057 | LATIN CAPITAL LETTER W
     E7 |  00000058 | LATIN CAPITAL LETTER X
     E8 |  00000059 | LATIN CAPITAL LETTER Y
     E9 |  0000005A | LATIN CAPITAL LETTER Z
     F0 |  00000030 | DIGIT ZERO
     F1 |  00000031 | DIGIT ONE
     F2 |  00000032 | DIGIT TWO
     F3 |  00000033 | DIGIT THREE
     F4 |  00000034 | DIGIT FOUR
     F5 |  00000035 | DIGIT FIVE
     F6 |  00000036 | DIGIT SIX
     F7 |  00000037 | DIGIT SEVEN
     F8 |  00000038 | DIGIT EIGHT
     F9 |  00000039 | DIGIT NINE
     FF |  0000009F | APPLICATION PROGRAM COMMAND (APC)
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/EBCDIC_ES_S.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for EBCDIC-ES-S.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::EBCDIC_ES_S;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x009c,
     0x0009,
     0x0086,
     0x007f,
     0x0097,
     0x008d,
     0x008e,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x009d,
     0x0085,
     0x0008,
     0x0087,
     0x0018,
     0x0019,
     0x0092,
     0x008f,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0080,
     0x0081,
     0x0082,
     0x0083,
     0x0084,
     0x000a,
     0x0017,
     0x001b,
     0x0088,
     0x0089,
     0x008a,
     0x008b,
     0x008c,
     0x0005,
     0x0006,
     0x0007,
     0x0090,
     0x0091,
     0x0016,
     0x0093,
     0x0094,
     0x0095,
     0x0096,
     0x0004,
     0x0098,
     0x0099,
     0x009a,
     0x009b,
     0x0014,
     0x0015,
     0x009e,
     0x001a,
     0x0020,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00a2,
     0x002e,
     0x003c,
     0x0028,
     0x002b,
     0x007c,
     0x0026,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x0021,
     0x0024,
     0x002a,
     0x0029,
     0x003b,
     0x00ac,
     0x002d,
     0x002f,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00f1,
     0x002c,
     0x0025,
     0x005f,
     0x003e,
     0x003f,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x0060,
     0x003a,
     0x00d1,
     0x0040,
     0x0027,
     0x003d,
     0x0022,
     0xfffd,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00a8,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x007b,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x007d,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x005c,
     0xfffd,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x009f,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\xc2\x9c",
     "\x09",
     "\xc2\x86",
     "\x7f",
     "\xc2\x97",
     "\xc2\x8d",
     "\xc2\x8e",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\xc2\x9d",
     "\xc2\x85",
     "\x08",
     "\xc2\x87",
     "\x18",
     "\x19",
     "\xc2\x92",
     "\xc2\x8f",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\xc2\x80",
     "\xc2\x81",
     "\xc2\x82",
     "\xc2\x83",
     "\xc2\x84",
     "\x0a",
     "\x17",
     "\x1b",
     "\xc2\x88",
     "\xc2\x89",
     "\xc2\x8a",
     "\xc2\x8b",
     "\xc2\x8c",
     "\x05",
     "\x06",
     "\x07",
     "\xc2\x90",
     "\xc2\x91",
     "\x16",
     "\xc2\x93",
     "\xc2\x94",
     "\xc2\x95",
     "\xc2\x96",
     "\x04",
     "\xc2\x98",
     "\xc2\x99",
     "\xc2\x9a",
     "\xc2\x9b",
     "\x14",
     "\x15",
     "\xc2\x9e",
     "\x1a",
     "\x20",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc2\xa2",
     "\x2e",
     "\x3c",
     "\x28",
     "\x2b",
     "\x7c",
     "\x26",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x21",
     "\x24",
     "\x2a",
     "\x29",
     "\x3b",
     "\xc2\xac",
     "\x2d",
     "\x2f",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc3\xb1",
     "\x2c",
     "\x25",
     "\x5f",
     "\x3e",
     "\x3f",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x60",
     "\x3a",
     "\xc3\x91",
     "\x40",
     "\x27",
     "\x3d",
     "\x22",
     "\xef\xbf\xbd",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc2\xa8",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x7b",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x7d",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x5c",
     "\xef\xbf\xbd",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc2\x9f",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x37",
     0x00000005 => "\x2d",
     0x00000006 => "\x2e",
     0x00000007 => "\x2f",
     0x00000008 => "\x16",
     0x00000009 => "\x05",
     0x0000000a => "\x25",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x3c",
     0x00000015 => "\x3d",
     0x00000016 => "\x32",
     0x00000017 => "\x26",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x3f",
     0x0000001b => "\x27",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x40",
     0x00000021 => "\x5a",
     0x00000022 => "\x7f",
     0x00000024 => "\x5b",
     0x00000025 => "\x6c",
     0x00000026 => "\x50",
     0x00000027 => "\x7d",
     0x00000028 => "\x4d",
     0x00000029 => "\x5d",
     0x0000002a => "\x5c",
     0x0000002b => "\x4e",
     0x0000002c => "\x6b",
     0x0000002d => "\x60",
     0x0000002e => "\x4b",
     0x0000002f => "\x61",
     0x00000030 => "\xf0",
     0x00000031 => "\xf1",
     0x00000032 => "\xf2",
     0x00000033 => "\xf3",
     0x00000034 => "\xf4",
     0x00000035 => "\xf5",
     0x00000036 => "\xf6",
     0x00000037 => "\xf7",
     0x00000038 => "\xf8",
     0x00000039 => "\xf9",
     0x0000003a => "\x7a",
     0x0000003b => "\x5e",
     0x0000003c => "\x4c",
     0x0000003d => "\x7e",
     0x0000003e => "\x6e",
     0x0000003f => "\x6f",
     0x00000040 => "\x7c",
     0x00000041 => "\xc1",
     0x00000042 => "\xc2",
     0x00000043 => "\xc3",
     0x00000044 => "\xc4",
     0x00000045 => "\xc5",
     0x00000046 => "\xc6",
     0x00000047 => "\xc7",
     0x00000048 => "\xc8",
     0x00000049 => "\xc9",
     0x0000004a => "\xd1",
     0x0000004b => "\xd2",
     0x0000004c => "\xd3",
     0x0000004d => "\xd4",
     0x0000004e => "\xd5",
     0x0000004f => "\xd6",
     0x00000050 => "\xd7",
     0x00000051 => "\xd8",
     0x00000052 => "\xd9",
     0x00000053 => "\xe2",
     0x00000054 => "\xe3",
     0x00000055 => "\xe4",
     0x00000056 => "\xe5",
     0x00000057 => "\xe6",
     0x00000058 => "\xe7",
     0x00000059 => "\xe8",
     0x0000005a => "\xe9",
     0x0000005c => "\xe0",
     0x0000005f => "\x6d",
     0x00000060 => "\x79",
     0x00000061 => "\x81",
     0x00000062 => "\x82",
     0x00000063 => "\x83",
     0x00000064 => "\x84",
     0x00000065 => "\x85",
     0x00000066 => "\x86",
     0x00000067 => "\x87",
     0x00000068 => "\x88",
     0x00000069 => "\x89",
     0x0000006a => "\x91",
     0x0000006b => "\x92",
     0x0000006c => "\x93",
     0x0000006d => "\x94",
     0x0000006e => "\x95",
     0x0000006f => "\x96",
     0x00000070 => "\x97",
     0x00000071 => "\x98",
     0x00000072 => "\x99",
     0x00000073 => "\xa2",
     0x00000074 => "\xa3",
     0x00000075 => "\xa4",
     0x00000076 => "\xa5",
     0x00000077 => "\xa6",
     0x00000078 => "\xa7",
     0x00000079 => "\xa8",
     0x0000007a => "\xa9",
     0x0000007b => "\xc0",
     0x0000007c => "\x4f",
     0x0000007d => "\xd0",
     0x0000007f => "\x07",
     0x00000080 => "\x20",
     0x00000081 => "\x21",
     0x00000082 => "\x22",
     0x00000083 => "\x23",
     0x00000084 => "\x24",
     0x00000085 => "\x15",
     0x00000086 => "\x06",
     0x00000087 => "\x17",
     0x00000088 => "\x28",
     0x00000089 => "\x29",
     0x0000008a => "\x2a",
     0x0000008b => "\x2b",
     0x0000008c => "\x2c",
     0x0000008d => "\x09",
     0x0000008e => "\x0a",
     0x0000008f => "\x1b",
     0x00000090 => "\x30",
     0x00000091 => "\x31",
     0x00000092 => "\x1a",
     0x00000093 => "\x33",
     0x00000094 => "\x34",
     0x00000095 => "\x35",
     0x00000096 => "\x36",
     0x00000097 => "\x08",
     0x00000098 => "\x38",
     0x00000099 => "\x39",
     0x0000009a => "\x3a",
     0x0000009b => "\x3b",
     0x0000009c => "\x04",
     0x0000009d => "\x14",
     0x0000009e => "\x3e",
     0x0000009f => "\xff",
     0x000000a2 => "\x4a",
     0x000000a8 => "\xa1",
     0x000000ac => "\x5f",
     0x000000d1 => "\x7b",
     0x000000f1 => "\x6a",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::EBCDIC_ES_S - Conversion routines for EBCDIC_ES_S
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for EBCDIC-ES-S.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
   source: IBM 3270 Char Set Ref Ch 10, GA27-2837-9, April 1987
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  0000009C | STRING TERMINATOR (ST)
     05 |  00000009 | CHARACTER TABULATION (HT)
     06 |  00000086 | START OF SELECTED AREA (SSA)
     07 |  0000007F | DELETE (DEL)
     08 |  00000097 | END OF GUARDED AREA (EPA)
     09 |  0000008D | REVERSE LINE FEED (RI)
     0A |  0000008E | SINGLE-SHIFT TWO (SS2)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  0000009D | OPERATING SYSTEM COMMAND (OSC)
     15 |  00000085 | NEXT LINE (NEL)
     16 |  00000008 | BACKSPACE (BS)
     17 |  00000087 | END OF SELECTED AREA (ESA)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  00000092 | PRIVATE USE TWO (PU2)
     1B |  0000008F | SINGLE-SHIFT THREE (SS3)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000080 | PADDING CHARACTER (PAD)
     21 |  00000081 | HIGH OCTET PRESET (HOP)
     22 |  00000082 | BREAK PERMITTED HERE (BPH)
     23 |  00000083 | NO BREAK HERE (NBH)
     24 |  00000084 | INDEX (IND)
     25 |  0000000A | LINE FEED (LF)
     26 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     27 |  0000001B | ESCAPE (ESC)
     28 |  00000088 | CHARACTER TABULATION SET (HTS)
     29 |  00000089 | CHARACTER TABULATION WITH JUSTIFICATION (HTJ)
     2A |  0000008A | LINE TABULATION SET (VTS)
     2B |  0000008B | PARTIAL LINE FORWARD (PLD)
     2C |  0000008C | PARTIAL LINE BACKWARD (PLU)
     2D |  00000005 | ENQUIRY (ENQ)
     2E |  00000006 | ACKNOWLEDGE (ACK)
     2F |  00000007 | BELL (BEL)
     30 |  00000090 | DEVICE CONTROL STRING (DCS)
     31 |  00000091 | PRIVATE USE ONE (PU1)
     32 |  00000016 | SYNCHRONOUS IDLE (SYN)
     33 |  00000093 | SET TRANSMIT STATE (STS)
     34 |  00000094 | CANCEL CHARACTER (CCH)
     35 |  00000095 | MESSAGE WAITING (MW)
     36 |  00000096 | START OF GUARDED AREA (SPA)
     37 |  00000004 | END OF TRANSMISSION (EOT)
     38 |  00000098 | START OF STRING (SOS)
     39 |  00000099 | SINGLE GRAPHIC CHARACTER INTRODUCER (SGCI)
     3A |  0000009A | SINGLE CHARACTER INTRODUCER (SCI)
     3B |  0000009B | CONTROL SEQUENCE INTRODUCER (CSI)
     3C |  00000014 | DEVICE CONTROL FOUR (DC4)
     3D |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     3E |  0000009E | PRIVACY MESSAGE (PM)
     3F |  0000001A | SUBSTITUTE (SUB)
     40 |  00000020 | SPACE
     4A |  000000A2 | CENT SIGN
     4B |  0000002E | FULL STOP
     4C |  0000003C | LESS-THAN SIGN
     4D |  00000028 | LEFT PARENTHESIS
     4E |  0000002B | PLUS SIGN
     4F |  0000007C | VERTICAL LINE
     50 |  00000026 | AMPERSAND
     5A |  00000021 | EXCLAMATION MARK
     5B |  00000024 | DOLLAR SIGN
     5C |  0000002A | ASTERISK
     5D |  00000029 | RIGHT PARENTHESIS
     5E |  0000003B | SEMICOLON
     5F |  000000AC | NOT SIGN
     60 |  0000002D | HYPHEN-MINUS
     61 |  0000002F | SOLIDUS
     6A |  000000F1 | LATIN SMALL LETTER N WITH TILDE
     6B |  0000002C | COMMA
     6C |  00000025 | PERCENT SIGN
     6D |  0000005F | LOW LINE
     6E |  0000003E | GREATER-THAN SIGN
     6F |  0000003F | QUESTION MARK
     79 |  00000060 | GRAVE ACCENT
     7A |  0000003A | COLON
     7B |  000000D1 | LATIN CAPITAL LETTER N WITH TILDE
     7C |  00000040 | COMMERCIAL AT
     7D |  00000027 | APOSTROPHE
     7E |  0000003D | EQUALS SIGN
     7F |  00000022 | QUOTATION MARK
     81 |  00000061 | LATIN SMALL LETTER A
     82 |  00000062 | LATIN SMALL LETTER B
     83 |  00000063 | LATIN SMALL LETTER C
     84 |  00000064 | LATIN SMALL LETTER D
     85 |  00000065 | LATIN SMALL LETTER E
     86 |  00000066 | LATIN SMALL LETTER F
     87 |  00000067 | LATIN SMALL LETTER G
     88 |  00000068 | LATIN SMALL LETTER H
     89 |  00000069 | LATIN SMALL LETTER I
     91 |  0000006A | LATIN SMALL LETTER J
     92 |  0000006B | LATIN SMALL LETTER K
     93 |  0000006C | LATIN SMALL LETTER L
     94 |  0000006D | LATIN SMALL LETTER M
     95 |  0000006E | LATIN SMALL LETTER N
     96 |  0000006F | LATIN SMALL LETTER O
     97 |  00000070 | LATIN SMALL LETTER P
     98 |  00000071 | LATIN SMALL LETTER Q
     99 |  00000072 | LATIN SMALL LETTER R
     A1 |  000000A8 | DIAERESIS
     A2 |  00000073 | LATIN SMALL LETTER S
     A3 |  00000074 | LATIN SMALL LETTER T
     A4 |  00000075 | LATIN SMALL LETTER U
     A5 |  00000076 | LATIN SMALL LETTER V
     A6 |  00000077 | LATIN SMALL LETTER W
     A7 |  00000078 | LATIN SMALL LETTER X
     A8 |  00000079 | LATIN SMALL LETTER Y
     A9 |  0000007A | LATIN SMALL LETTER Z
     C0 |  0000007B | LEFT CURLY BRACKET
     C1 |  00000041 | LATIN CAPITAL LETTER A
     C2 |  00000042 | LATIN CAPITAL LETTER B
     C3 |  00000043 | LATIN CAPITAL LETTER C
     C4 |  00000044 | LATIN CAPITAL LETTER D
     C5 |  00000045 | LATIN CAPITAL LETTER E
     C6 |  00000046 | LATIN CAPITAL LETTER F
     C7 |  00000047 | LATIN CAPITAL LETTER G
     C8 |  00000048 | LATIN CAPITAL LETTER H
     C9 |  00000049 | LATIN CAPITAL LETTER I
     D0 |  0000007D | RIGHT CURLY BRACKET
     D1 |  0000004A | LATIN CAPITAL LETTER J
     D2 |  0000004B | LATIN CAPITAL LETTER K
     D3 |  0000004C | LATIN CAPITAL LETTER L
     D4 |  0000004D | LATIN CAPITAL LETTER M
     D5 |  0000004E | LATIN CAPITAL LETTER N
     D6 |  0000004F | LATIN CAPITAL LETTER O
     D7 |  00000050 | LATIN CAPITAL LETTER P
     D8 |  00000051 | LATIN CAPITAL LETTER Q
     D9 |  00000052 | LATIN CAPITAL LETTER R
     E0 |  0000005C | REVERSE SOLIDUS
     E2 |  00000053 | LATIN CAPITAL LETTER S
     E3 |  00000054 | LATIN CAPITAL LETTER T
     E4 |  00000055 | LATIN CAPITAL LETTER U
     E5 |  00000056 | LATIN CAPITAL LETTER V
     E6 |  00000057 | LATIN CAPITAL LETTER W
     E7 |  00000058 | LATIN CAPITAL LETTER X
     E8 |  00000059 | LATIN CAPITAL LETTER Y
     E9 |  0000005A | LATIN CAPITAL LETTER Z
     F0 |  00000030 | DIGIT ZERO
     F1 |  00000031 | DIGIT ONE
     F2 |  00000032 | DIGIT TWO
     F3 |  00000033 | DIGIT THREE
     F4 |  00000034 | DIGIT FOUR
     F5 |  00000035 | DIGIT FIVE
     F6 |  00000036 | DIGIT SIX
     F7 |  00000037 | DIGIT SEVEN
     F8 |  00000038 | DIGIT EIGHT
     F9 |  00000039 | DIGIT NINE
     FF |  0000009F | APPLICATION PROGRAM COMMAND (APC)
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/EBCDIC_FI_SE.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for EBCDIC-FI-SE.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::EBCDIC_FI_SE;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x009c,
     0x0009,
     0x0086,
     0x007f,
     0x0097,
     0x008d,
     0x008e,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x009d,
     0x0085,
     0x0008,
     0x0087,
     0x0018,
     0x0019,
     0x0092,
     0x008f,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0080,
     0x0081,
     0x0082,
     0x0083,
     0x0084,
     0x000a,
     0x0017,
     0x001b,
     0x0088,
     0x0089,
     0x008a,
     0x008b,
     0x008c,
     0x0005,
     0x0006,
     0x0007,
     0x0090,
     0x0091,
     0x0016,
     0x0093,
     0x0094,
     0x0095,
     0x0096,
     0x0004,
     0x0098,
     0x0099,
     0x009a,
     0x009b,
     0x0014,
     0x0015,
     0x009e,
     0x001a,
     0x0020,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00a7,
     0x002e,
     0x003c,
     0x0028,
     0x002b,
     0x0021,
     0x0026,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00a4,
     0x00c5,
     0x002a,
     0x0029,
     0x003b,
     0x005e,
     0x002d,
     0x002f,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00f6,
     0x002c,
     0x0025,
     0x005f,
     0x003e,
     0x003f,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00e9,
     0x003a,
     0x00c4,
     0x00d6,
     0x0027,
     0x003d,
     0x0022,
     0xfffd,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00fc,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00e4,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00e5,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00c9,
     0xfffd,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x009f,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\xc2\x9c",
     "\x09",
     "\xc2\x86",
     "\x7f",
     "\xc2\x97",
     "\xc2\x8d",
     "\xc2\x8e",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\xc2\x9d",
     "\xc2\x85",
     "\x08",
     "\xc2\x87",
     "\x18",
     "\x19",
     "\xc2\x92",
     "\xc2\x8f",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\xc2\x80",
     "\xc2\x81",
     "\xc2\x82",
     "\xc2\x83",
     "\xc2\x84",
     "\x0a",
     "\x17",
     "\x1b",
     "\xc2\x88",
     "\xc2\x89",
     "\xc2\x8a",
     "\xc2\x8b",
     "\xc2\x8c",
     "\x05",
     "\x06",
     "\x07",
     "\xc2\x90",
     "\xc2\x91",
     "\x16",
     "\xc2\x93",
     "\xc2\x94",
     "\xc2\x95",
     "\xc2\x96",
     "\x04",
     "\xc2\x98",
     "\xc2\x99",
     "\xc2\x9a",
     "\xc2\x9b",
     "\x14",
     "\x15",
     "\xc2\x9e",
     "\x1a",
     "\x20",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc2\xa7",
     "\x2e",
     "\x3c",
     "\x28",
     "\x2b",
     "\x21",
     "\x26",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc2\xa4",
     "\xc3\x85",
     "\x2a",
     "\x29",
     "\x3b",
     "\x5e",
     "\x2d",
     "\x2f",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc3\xb6",
     "\x2c",
     "\x25",
     "\x5f",
     "\x3e",
     "\x3f",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc3\xa9",
     "\x3a",
     "\xc3\x84",
     "\xc3\x96",
     "\x27",
     "\x3d",
     "\x22",
     "\xef\xbf\xbd",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc3\xbc",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc3\xa4",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc3\xa5",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc3\x89",
     "\xef\xbf\xbd",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc2\x9f",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x37",
     0x00000005 => "\x2d",
     0x00000006 => "\x2e",
     0x00000007 => "\x2f",
     0x00000008 => "\x16",
     0x00000009 => "\x05",
     0x0000000a => "\x25",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x3c",
     0x00000015 => "\x3d",
     0x00000016 => "\x32",
     0x00000017 => "\x26",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x3f",
     0x0000001b => "\x27",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x40",
     0x00000021 => "\x4f",
     0x00000022 => "\x7f",
     0x00000025 => "\x6c",
     0x00000026 => "\x50",
     0x00000027 => "\x7d",
     0x00000028 => "\x4d",
     0x00000029 => "\x5d",
     0x0000002a => "\x5c",
     0x0000002b => "\x4e",
     0x0000002c => "\x6b",
     0x0000002d => "\x60",
     0x0000002e => "\x4b",
     0x0000002f => "\x61",
     0x00000030 => "\xf0",
     0x00000031 => "\xf1",
     0x00000032 => "\xf2",
     0x00000033 => "\xf3",
     0x00000034 => "\xf4",
     0x00000035 => "\xf5",
     0x00000036 => "\xf6",
     0x00000037 => "\xf7",
     0x00000038 => "\xf8",
     0x00000039 => "\xf9",
     0x0000003a => "\x7a",
     0x0000003b => "\x5e",
     0x0000003c => "\x4c",
     0x0000003d => "\x7e",
     0x0000003e => "\x6e",
     0x0000003f => "\x6f",
     0x00000041 => "\xc1",
     0x00000042 => "\xc2",
     0x00000043 => "\xc3",
     0x00000044 => "\xc4",
     0x00000045 => "\xc5",
     0x00000046 => "\xc6",
     0x00000047 => "\xc7",
     0x00000048 => "\xc8",
     0x00000049 => "\xc9",
     0x0000004a => "\xd1",
     0x0000004b => "\xd2",
     0x0000004c => "\xd3",
     0x0000004d => "\xd4",
     0x0000004e => "\xd5",
     0x0000004f => "\xd6",
     0x00000050 => "\xd7",
     0x00000051 => "\xd8",
     0x00000052 => "\xd9",
     0x00000053 => "\xe2",
     0x00000054 => "\xe3",
     0x00000055 => "\xe4",
     0x00000056 => "\xe5",
     0x00000057 => "\xe6",
     0x00000058 => "\xe7",
     0x00000059 => "\xe8",
     0x0000005a => "\xe9",
     0x0000005e => "\x5f",
     0x0000005f => "\x6d",
     0x00000061 => "\x81",
     0x00000062 => "\x82",
     0x00000063 => "\x83",
     0x00000064 => "\x84",
     0x00000065 => "\x85",
     0x00000066 => "\x86",
     0x00000067 => "\x87",
     0x00000068 => "\x88",
     0x00000069 => "\x89",
     0x0000006a => "\x91",
     0x0000006b => "\x92",
     0x0000006c => "\x93",
     0x0000006d => "\x94",
     0x0000006e => "\x95",
     0x0000006f => "\x96",
     0x00000070 => "\x97",
     0x00000071 => "\x98",
     0x00000072 => "\x99",
     0x00000073 => "\xa2",
     0x00000074 => "\xa3",
     0x00000075 => "\xa4",
     0x00000076 => "\xa5",
     0x00000077 => "\xa6",
     0x00000078 => "\xa7",
     0x00000079 => "\xa8",
     0x0000007a => "\xa9",
     0x0000007f => "\x07",
     0x00000080 => "\x20",
     0x00000081 => "\x21",
     0x00000082 => "\x22",
     0x00000083 => "\x23",
     0x00000084 => "\x24",
     0x00000085 => "\x15",
     0x00000086 => "\x06",
     0x00000087 => "\x17",
     0x00000088 => "\x28",
     0x00000089 => "\x29",
     0x0000008a => "\x2a",
     0x0000008b => "\x2b",
     0x0000008c => "\x2c",
     0x0000008d => "\x09",
     0x0000008e => "\x0a",
     0x0000008f => "\x1b",
     0x00000090 => "\x30",
     0x00000091 => "\x31",
     0x00000092 => "\x1a",
     0x00000093 => "\x33",
     0x00000094 => "\x34",
     0x00000095 => "\x35",
     0x00000096 => "\x36",
     0x00000097 => "\x08",
     0x00000098 => "\x38",
     0x00000099 => "\x39",
     0x0000009a => "\x3a",
     0x0000009b => "\x3b",
     0x0000009c => "\x04",
     0x0000009d => "\x14",
     0x0000009e => "\x3e",
     0x0000009f => "\xff",
     0x000000a4 => "\x5a",
     0x000000a7 => "\x4a",
     0x000000c4 => "\x7b",
     0x000000c5 => "\x5b",
     0x000000c9 => "\xe0",
     0x000000d6 => "\x7c",
     0x000000e4 => "\xc0",
     0x000000e5 => "\xd0",
     0x000000e9 => "\x79",
     0x000000f6 => "\x6a",
     0x000000fc => "\xa1",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::EBCDIC_FI_SE - Conversion routines for EBCDIC_FI_SE
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for EBCDIC-FI-SE.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
   source: IBM 3270 Char Set Ref Ch 10, GA27-2837-9, April 1987
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  0000009C | STRING TERMINATOR (ST)
     05 |  00000009 | CHARACTER TABULATION (HT)
     06 |  00000086 | START OF SELECTED AREA (SSA)
     07 |  0000007F | DELETE (DEL)
     08 |  00000097 | END OF GUARDED AREA (EPA)
     09 |  0000008D | REVERSE LINE FEED (RI)
     0A |  0000008E | SINGLE-SHIFT TWO (SS2)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  0000009D | OPERATING SYSTEM COMMAND (OSC)
     15 |  00000085 | NEXT LINE (NEL)
     16 |  00000008 | BACKSPACE (BS)
     17 |  00000087 | END OF SELECTED AREA (ESA)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  00000092 | PRIVATE USE TWO (PU2)
     1B |  0000008F | SINGLE-SHIFT THREE (SS3)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000080 | PADDING CHARACTER (PAD)
     21 |  00000081 | HIGH OCTET PRESET (HOP)
     22 |  00000082 | BREAK PERMITTED HERE (BPH)
     23 |  00000083 | NO BREAK HERE (NBH)
     24 |  00000084 | INDEX (IND)
     25 |  0000000A | LINE FEED (LF)
     26 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     27 |  0000001B | ESCAPE (ESC)
     28 |  00000088 | CHARACTER TABULATION SET (HTS)
     29 |  00000089 | CHARACTER TABULATION WITH JUSTIFICATION (HTJ)
     2A |  0000008A | LINE TABULATION SET (VTS)
     2B |  0000008B | PARTIAL LINE FORWARD (PLD)
     2C |  0000008C | PARTIAL LINE BACKWARD (PLU)
     2D |  00000005 | ENQUIRY (ENQ)
     2E |  00000006 | ACKNOWLEDGE (ACK)
     2F |  00000007 | BELL (BEL)
     30 |  00000090 | DEVICE CONTROL STRING (DCS)
     31 |  00000091 | PRIVATE USE ONE (PU1)
     32 |  00000016 | SYNCHRONOUS IDLE (SYN)
     33 |  00000093 | SET TRANSMIT STATE (STS)
     34 |  00000094 | CANCEL CHARACTER (CCH)
     35 |  00000095 | MESSAGE WAITING (MW)
     36 |  00000096 | START OF GUARDED AREA (SPA)
     37 |  00000004 | END OF TRANSMISSION (EOT)
     38 |  00000098 | START OF STRING (SOS)
     39 |  00000099 | SINGLE GRAPHIC CHARACTER INTRODUCER (SGCI)
     3A |  0000009A | SINGLE CHARACTER INTRODUCER (SCI)
     3B |  0000009B | CONTROL SEQUENCE INTRODUCER (CSI)
     3C |  00000014 | DEVICE CONTROL FOUR (DC4)
     3D |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     3E |  0000009E | PRIVACY MESSAGE (PM)
     3F |  0000001A | SUBSTITUTE (SUB)
     40 |  00000020 | SPACE
     4A |  000000A7 | SECTION SIGN
     4B |  0000002E | FULL STOP
     4C |  0000003C | LESS-THAN SIGN
     4D |  00000028 | LEFT PARENTHESIS
     4E |  0000002B | PLUS SIGN
     4F |  00000021 | EXCLAMATION MARK
     50 |  00000026 | AMPERSAND
     5A |  000000A4 | CURRENCY SIGN
     5B |  000000C5 | LATIN CAPITAL LETTER A WITH RING ABOVE
     5C |  0000002A | ASTERISK
     5D |  00000029 | RIGHT PARENTHESIS
     5E |  0000003B | SEMICOLON
     5F |  0000005E | CIRCUMFLEX ACCENT
     60 |  0000002D | HYPHEN-MINUS
     61 |  0000002F | SOLIDUS
     6A |  000000F6 | LATIN SMALL LETTER O WITH DIAERESIS
     6B |  0000002C | COMMA
     6C |  00000025 | PERCENT SIGN
     6D |  0000005F | LOW LINE
     6E |  0000003E | GREATER-THAN SIGN
     6F |  0000003F | QUESTION MARK
     79 |  000000E9 | LATIN SMALL LETTER E WITH ACUTE
     7A |  0000003A | COLON
     7B |  000000C4 | LATIN CAPITAL LETTER A WITH DIAERESIS
     7C |  000000D6 | LATIN CAPITAL LETTER O WITH DIAERESIS
     7D |  00000027 | APOSTROPHE
     7E |  0000003D | EQUALS SIGN
     7F |  00000022 | QUOTATION MARK
     81 |  00000061 | LATIN SMALL LETTER A
     82 |  00000062 | LATIN SMALL LETTER B
     83 |  00000063 | LATIN SMALL LETTER C
     84 |  00000064 | LATIN SMALL LETTER D
     85 |  00000065 | LATIN SMALL LETTER E
     86 |  00000066 | LATIN SMALL LETTER F
     87 |  00000067 | LATIN SMALL LETTER G
     88 |  00000068 | LATIN SMALL LETTER H
     89 |  00000069 | LATIN SMALL LETTER I
     91 |  0000006A | LATIN SMALL LETTER J
     92 |  0000006B | LATIN SMALL LETTER K
     93 |  0000006C | LATIN SMALL LETTER L
     94 |  0000006D | LATIN SMALL LETTER M
     95 |  0000006E | LATIN SMALL LETTER N
     96 |  0000006F | LATIN SMALL LETTER O
     97 |  00000070 | LATIN SMALL LETTER P
     98 |  00000071 | LATIN SMALL LETTER Q
     99 |  00000072 | LATIN SMALL LETTER R
     A1 |  000000FC | LATIN SMALL LETTER U WITH DIAERESIS
     A2 |  00000073 | LATIN SMALL LETTER S
     A3 |  00000074 | LATIN SMALL LETTER T
     A4 |  00000075 | LATIN SMALL LETTER U
     A5 |  00000076 | LATIN SMALL LETTER V
     A6 |  00000077 | LATIN SMALL LETTER W
     A7 |  00000078 | LATIN SMALL LETTER X
     A8 |  00000079 | LATIN SMALL LETTER Y
     A9 |  0000007A | LATIN SMALL LETTER Z
     C0 |  000000E4 | LATIN SMALL LETTER A WITH DIAERESIS
     C1 |  00000041 | LATIN CAPITAL LETTER A
     C2 |  00000042 | LATIN CAPITAL LETTER B
     C3 |  00000043 | LATIN CAPITAL LETTER C
     C4 |  00000044 | LATIN CAPITAL LETTER D
     C5 |  00000045 | LATIN CAPITAL LETTER E
     C6 |  00000046 | LATIN CAPITAL LETTER F
     C7 |  00000047 | LATIN CAPITAL LETTER G
     C8 |  00000048 | LATIN CAPITAL LETTER H
     C9 |  00000049 | LATIN CAPITAL LETTER I
     D0 |  000000E5 | LATIN SMALL LETTER A WITH RING ABOVE
     D1 |  0000004A | LATIN CAPITAL LETTER J
     D2 |  0000004B | LATIN CAPITAL LETTER K
     D3 |  0000004C | LATIN CAPITAL LETTER L
     D4 |  0000004D | LATIN CAPITAL LETTER M
     D5 |  0000004E | LATIN CAPITAL LETTER N
     D6 |  0000004F | LATIN CAPITAL LETTER O
     D7 |  00000050 | LATIN CAPITAL LETTER P
     D8 |  00000051 | LATIN CAPITAL LETTER Q
     D9 |  00000052 | LATIN CAPITAL LETTER R
     E0 |  000000C9 | LATIN CAPITAL LETTER E WITH ACUTE
     E2 |  00000053 | LATIN CAPITAL LETTER S
     E3 |  00000054 | LATIN CAPITAL LETTER T
     E4 |  00000055 | LATIN CAPITAL LETTER U
     E5 |  00000056 | LATIN CAPITAL LETTER V
     E6 |  00000057 | LATIN CAPITAL LETTER W
     E7 |  00000058 | LATIN CAPITAL LETTER X
     E8 |  00000059 | LATIN CAPITAL LETTER Y
     E9 |  0000005A | LATIN CAPITAL LETTER Z
     F0 |  00000030 | DIGIT ZERO
     F1 |  00000031 | DIGIT ONE
     F2 |  00000032 | DIGIT TWO
     F3 |  00000033 | DIGIT THREE
     F4 |  00000034 | DIGIT FOUR
     F5 |  00000035 | DIGIT FIVE
     F6 |  00000036 | DIGIT SIX
     F7 |  00000037 | DIGIT SEVEN
     F8 |  00000038 | DIGIT EIGHT
     F9 |  00000039 | DIGIT NINE
     FF |  0000009F | APPLICATION PROGRAM COMMAND (APC)
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/EBCDIC_FI_SE_A.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for EBCDIC-FI-SE-A.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::EBCDIC_FI_SE_A;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x009c,
     0x0009,
     0x0086,
     0x007f,
     0x0097,
     0x008d,
     0x008e,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x009d,
     0x0085,
     0x0008,
     0x0087,
     0x0018,
     0x0019,
     0x0092,
     0x008f,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0080,
     0x0081,
     0x0082,
     0x0083,
     0x0084,
     0x000a,
     0x0017,
     0x001b,
     0x0088,
     0x0089,
     0x008a,
     0x008b,
     0x008c,
     0x0005,
     0x0006,
     0x0007,
     0x0090,
     0x0091,
     0x0016,
     0x0093,
     0x0094,
     0x0095,
     0x0096,
     0x0004,
     0x0098,
     0x0099,
     0x009a,
     0x009b,
     0x0014,
     0x0015,
     0x009e,
     0x001a,
     0x0020,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00f6,
     0x002e,
     0x003c,
     0x0028,
     0x002b,
     0x007c,
     0x0026,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00e5,
     0x00c5,
     0x002a,
     0x0029,
     0x003b,
     0x00ac,
     0x002d,
     0x002f,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00a6,
     0x002c,
     0x0025,
     0x005f,
     0x003e,
     0x003f,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x003a,
     0x00c4,
     0x00d6,
     0x0027,
     0x003d,
     0x00e4,
     0xfffd,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x009f,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\xc2\x9c",
     "\x09",
     "\xc2\x86",
     "\x7f",
     "\xc2\x97",
     "\xc2\x8d",
     "\xc2\x8e",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\xc2\x9d",
     "\xc2\x85",
     "\x08",
     "\xc2\x87",
     "\x18",
     "\x19",
     "\xc2\x92",
     "\xc2\x8f",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\xc2\x80",
     "\xc2\x81",
     "\xc2\x82",
     "\xc2\x83",
     "\xc2\x84",
     "\x0a",
     "\x17",
     "\x1b",
     "\xc2\x88",
     "\xc2\x89",
     "\xc2\x8a",
     "\xc2\x8b",
     "\xc2\x8c",
     "\x05",
     "\x06",
     "\x07",
     "\xc2\x90",
     "\xc2\x91",
     "\x16",
     "\xc2\x93",
     "\xc2\x94",
     "\xc2\x95",
     "\xc2\x96",
     "\x04",
     "\xc2\x98",
     "\xc2\x99",
     "\xc2\x9a",
     "\xc2\x9b",
     "\x14",
     "\x15",
     "\xc2\x9e",
     "\x1a",
     "\x20",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc3\xb6",
     "\x2e",
     "\x3c",
     "\x28",
     "\x2b",
     "\x7c",
     "\x26",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc3\xa5",
     "\xc3\x85",
     "\x2a",
     "\x29",
     "\x3b",
     "\xc2\xac",
     "\x2d",
     "\x2f",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc2\xa6",
     "\x2c",
     "\x25",
     "\x5f",
     "\x3e",
     "\x3f",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x3a",
     "\xc3\x84",
     "\xc3\x96",
     "\x27",
     "\x3d",
     "\xc3\xa4",
     "\xef\xbf\xbd",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc2\x9f",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x37",
     0x00000005 => "\x2d",
     0x00000006 => "\x2e",
     0x00000007 => "\x2f",
     0x00000008 => "\x16",
     0x00000009 => "\x05",
     0x0000000a => "\x25",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x3c",
     0x00000015 => "\x3d",
     0x00000016 => "\x32",
     0x00000017 => "\x26",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x3f",
     0x0000001b => "\x27",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x40",
     0x00000025 => "\x6c",
     0x00000026 => "\x50",
     0x00000027 => "\x7d",
     0x00000028 => "\x4d",
     0x00000029 => "\x5d",
     0x0000002a => "\x5c",
     0x0000002b => "\x4e",
     0x0000002c => "\x6b",
     0x0000002d => "\x60",
     0x0000002e => "\x4b",
     0x0000002f => "\x61",
     0x00000030 => "\xf0",
     0x00000031 => "\xf1",
     0x00000032 => "\xf2",
     0x00000033 => "\xf3",
     0x00000034 => "\xf4",
     0x00000035 => "\xf5",
     0x00000036 => "\xf6",
     0x00000037 => "\xf7",
     0x00000038 => "\xf8",
     0x00000039 => "\xf9",
     0x0000003a => "\x7a",
     0x0000003b => "\x5e",
     0x0000003c => "\x4c",
     0x0000003d => "\x7e",
     0x0000003e => "\x6e",
     0x0000003f => "\x6f",
     0x00000041 => "\xc1",
     0x00000042 => "\xc2",
     0x00000043 => "\xc3",
     0x00000044 => "\xc4",
     0x00000045 => "\xc5",
     0x00000046 => "\xc6",
     0x00000047 => "\xc7",
     0x00000048 => "\xc8",
     0x00000049 => "\xc9",
     0x0000004a => "\xd1",
     0x0000004b => "\xd2",
     0x0000004c => "\xd3",
     0x0000004d => "\xd4",
     0x0000004e => "\xd5",
     0x0000004f => "\xd6",
     0x00000050 => "\xd7",
     0x00000051 => "\xd8",
     0x00000052 => "\xd9",
     0x00000053 => "\xe2",
     0x00000054 => "\xe3",
     0x00000055 => "\xe4",
     0x00000056 => "\xe5",
     0x00000057 => "\xe6",
     0x00000058 => "\xe7",
     0x00000059 => "\xe8",
     0x0000005a => "\xe9",
     0x0000005f => "\x6d",
     0x00000061 => "\x81",
     0x00000062 => "\x82",
     0x00000063 => "\x83",
     0x00000064 => "\x84",
     0x00000065 => "\x85",
     0x00000066 => "\x86",
     0x00000067 => "\x87",
     0x00000068 => "\x88",
     0x00000069 => "\x89",
     0x0000006a => "\x91",
     0x0000006b => "\x92",
     0x0000006c => "\x93",
     0x0000006d => "\x94",
     0x0000006e => "\x95",
     0x0000006f => "\x96",
     0x00000070 => "\x97",
     0x00000071 => "\x98",
     0x00000072 => "\x99",
     0x00000073 => "\xa2",
     0x00000074 => "\xa3",
     0x00000075 => "\xa4",
     0x00000076 => "\xa5",
     0x00000077 => "\xa6",
     0x00000078 => "\xa7",
     0x00000079 => "\xa8",
     0x0000007a => "\xa9",
     0x0000007c => "\x4f",
     0x0000007f => "\x07",
     0x00000080 => "\x20",
     0x00000081 => "\x21",
     0x00000082 => "\x22",
     0x00000083 => "\x23",
     0x00000084 => "\x24",
     0x00000085 => "\x15",
     0x00000086 => "\x06",
     0x00000087 => "\x17",
     0x00000088 => "\x28",
     0x00000089 => "\x29",
     0x0000008a => "\x2a",
     0x0000008b => "\x2b",
     0x0000008c => "\x2c",
     0x0000008d => "\x09",
     0x0000008e => "\x0a",
     0x0000008f => "\x1b",
     0x00000090 => "\x30",
     0x00000091 => "\x31",
     0x00000092 => "\x1a",
     0x00000093 => "\x33",
     0x00000094 => "\x34",
     0x00000095 => "\x35",
     0x00000096 => "\x36",
     0x00000097 => "\x08",
     0x00000098 => "\x38",
     0x00000099 => "\x39",
     0x0000009a => "\x3a",
     0x0000009b => "\x3b",
     0x0000009c => "\x04",
     0x0000009d => "\x14",
     0x0000009e => "\x3e",
     0x0000009f => "\xff",
     0x000000a6 => "\x6a",
     0x000000ac => "\x5f",
     0x000000c4 => "\x7b",
     0x000000c5 => "\x5b",
     0x000000d6 => "\x7c",
     0x000000e4 => "\x7f",
     0x000000e5 => "\x5a",
     0x000000f6 => "\x4a",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::EBCDIC_FI_SE_A - Conversion routines for EBCDIC_FI_SE_A
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for EBCDIC-FI-SE-A.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
   source: IBM 3270 Char Set Ref Ch 10, GA27-2837-9, April 1987
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  0000009C | STRING TERMINATOR (ST)
     05 |  00000009 | CHARACTER TABULATION (HT)
     06 |  00000086 | START OF SELECTED AREA (SSA)
     07 |  0000007F | DELETE (DEL)
     08 |  00000097 | END OF GUARDED AREA (EPA)
     09 |  0000008D | REVERSE LINE FEED (RI)
     0A |  0000008E | SINGLE-SHIFT TWO (SS2)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  0000009D | OPERATING SYSTEM COMMAND (OSC)
     15 |  00000085 | NEXT LINE (NEL)
     16 |  00000008 | BACKSPACE (BS)
     17 |  00000087 | END OF SELECTED AREA (ESA)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  00000092 | PRIVATE USE TWO (PU2)
     1B |  0000008F | SINGLE-SHIFT THREE (SS3)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000080 | PADDING CHARACTER (PAD)
     21 |  00000081 | HIGH OCTET PRESET (HOP)
     22 |  00000082 | BREAK PERMITTED HERE (BPH)
     23 |  00000083 | NO BREAK HERE (NBH)
     24 |  00000084 | INDEX (IND)
     25 |  0000000A | LINE FEED (LF)
     26 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     27 |  0000001B | ESCAPE (ESC)
     28 |  00000088 | CHARACTER TABULATION SET (HTS)
     29 |  00000089 | CHARACTER TABULATION WITH JUSTIFICATION (HTJ)
     2A |  0000008A | LINE TABULATION SET (VTS)
     2B |  0000008B | PARTIAL LINE FORWARD (PLD)
     2C |  0000008C | PARTIAL LINE BACKWARD (PLU)
     2D |  00000005 | ENQUIRY (ENQ)
     2E |  00000006 | ACKNOWLEDGE (ACK)
     2F |  00000007 | BELL (BEL)
     30 |  00000090 | DEVICE CONTROL STRING (DCS)
     31 |  00000091 | PRIVATE USE ONE (PU1)
     32 |  00000016 | SYNCHRONOUS IDLE (SYN)
     33 |  00000093 | SET TRANSMIT STATE (STS)
     34 |  00000094 | CANCEL CHARACTER (CCH)
     35 |  00000095 | MESSAGE WAITING (MW)
     36 |  00000096 | START OF GUARDED AREA (SPA)
     37 |  00000004 | END OF TRANSMISSION (EOT)
     38 |  00000098 | START OF STRING (SOS)
     39 |  00000099 | SINGLE GRAPHIC CHARACTER INTRODUCER (SGCI)
     3A |  0000009A | SINGLE CHARACTER INTRODUCER (SCI)
     3B |  0000009B | CONTROL SEQUENCE INTRODUCER (CSI)
     3C |  00000014 | DEVICE CONTROL FOUR (DC4)
     3D |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     3E |  0000009E | PRIVACY MESSAGE (PM)
     3F |  0000001A | SUBSTITUTE (SUB)
     40 |  00000020 | SPACE
     4A |  000000F6 | LATIN SMALL LETTER O WITH DIAERESIS
     4B |  0000002E | FULL STOP
     4C |  0000003C | LESS-THAN SIGN
     4D |  00000028 | LEFT PARENTHESIS
     4E |  0000002B | PLUS SIGN
     4F |  0000007C | VERTICAL LINE
     50 |  00000026 | AMPERSAND
     5A |  000000E5 | LATIN SMALL LETTER A WITH RING ABOVE
     5B |  000000C5 | LATIN CAPITAL LETTER A WITH RING ABOVE
     5C |  0000002A | ASTERISK
     5D |  00000029 | RIGHT PARENTHESIS
     5E |  0000003B | SEMICOLON
     5F |  000000AC | NOT SIGN
     60 |  0000002D | HYPHEN-MINUS
     61 |  0000002F | SOLIDUS
     6A |  000000A6 | BROKEN BAR
     6B |  0000002C | COMMA
     6C |  00000025 | PERCENT SIGN
     6D |  0000005F | LOW LINE
     6E |  0000003E | GREATER-THAN SIGN
     6F |  0000003F | QUESTION MARK
     7A |  0000003A | COLON
     7B |  000000C4 | LATIN CAPITAL LETTER A WITH DIAERESIS
     7C |  000000D6 | LATIN CAPITAL LETTER O WITH DIAERESIS
     7D |  00000027 | APOSTROPHE
     7E |  0000003D | EQUALS SIGN
     7F |  000000E4 | LATIN SMALL LETTER A WITH DIAERESIS
     81 |  00000061 | LATIN SMALL LETTER A
     82 |  00000062 | LATIN SMALL LETTER B
     83 |  00000063 | LATIN SMALL LETTER C
     84 |  00000064 | LATIN SMALL LETTER D
     85 |  00000065 | LATIN SMALL LETTER E
     86 |  00000066 | LATIN SMALL LETTER F
     87 |  00000067 | LATIN SMALL LETTER G
     88 |  00000068 | LATIN SMALL LETTER H
     89 |  00000069 | LATIN SMALL LETTER I
     91 |  0000006A | LATIN SMALL LETTER J
     92 |  0000006B | LATIN SMALL LETTER K
     93 |  0000006C | LATIN SMALL LETTER L
     94 |  0000006D | LATIN SMALL LETTER M
     95 |  0000006E | LATIN SMALL LETTER N
     96 |  0000006F | LATIN SMALL LETTER O
     97 |  00000070 | LATIN SMALL LETTER P
     98 |  00000071 | LATIN SMALL LETTER Q
     99 |  00000072 | LATIN SMALL LETTER R
     A2 |  00000073 | LATIN SMALL LETTER S
     A3 |  00000074 | LATIN SMALL LETTER T
     A4 |  00000075 | LATIN SMALL LETTER U
     A5 |  00000076 | LATIN SMALL LETTER V
     A6 |  00000077 | LATIN SMALL LETTER W
     A7 |  00000078 | LATIN SMALL LETTER X
     A8 |  00000079 | LATIN SMALL LETTER Y
     A9 |  0000007A | LATIN SMALL LETTER Z
     C1 |  00000041 | LATIN CAPITAL LETTER A
     C2 |  00000042 | LATIN CAPITAL LETTER B
     C3 |  00000043 | LATIN CAPITAL LETTER C
     C4 |  00000044 | LATIN CAPITAL LETTER D
     C5 |  00000045 | LATIN CAPITAL LETTER E
     C6 |  00000046 | LATIN CAPITAL LETTER F
     C7 |  00000047 | LATIN CAPITAL LETTER G
     C8 |  00000048 | LATIN CAPITAL LETTER H
     C9 |  00000049 | LATIN CAPITAL LETTER I
     D1 |  0000004A | LATIN CAPITAL LETTER J
     D2 |  0000004B | LATIN CAPITAL LETTER K
     D3 |  0000004C | LATIN CAPITAL LETTER L
     D4 |  0000004D | LATIN CAPITAL LETTER M
     D5 |  0000004E | LATIN CAPITAL LETTER N
     D6 |  0000004F | LATIN CAPITAL LETTER O
     D7 |  00000050 | LATIN CAPITAL LETTER P
     D8 |  00000051 | LATIN CAPITAL LETTER Q
     D9 |  00000052 | LATIN CAPITAL LETTER R
     E2 |  00000053 | LATIN CAPITAL LETTER S
     E3 |  00000054 | LATIN CAPITAL LETTER T
     E4 |  00000055 | LATIN CAPITAL LETTER U
     E5 |  00000056 | LATIN CAPITAL LETTER V
     E6 |  00000057 | LATIN CAPITAL LETTER W
     E7 |  00000058 | LATIN CAPITAL LETTER X
     E8 |  00000059 | LATIN CAPITAL LETTER Y
     E9 |  0000005A | LATIN CAPITAL LETTER Z
     F0 |  00000030 | DIGIT ZERO
     F1 |  00000031 | DIGIT ONE
     F2 |  00000032 | DIGIT TWO
     F3 |  00000033 | DIGIT THREE
     F4 |  00000034 | DIGIT FOUR
     F5 |  00000035 | DIGIT FIVE
     F6 |  00000036 | DIGIT SIX
     F7 |  00000037 | DIGIT SEVEN
     F8 |  00000038 | DIGIT EIGHT
     F9 |  00000039 | DIGIT NINE
     FF |  0000009F | APPLICATION PROGRAM COMMAND (APC)
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/EBCDIC_FR.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for EBCDIC-FR.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::EBCDIC_FR;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x009c,
     0x0009,
     0x0086,
     0x007f,
     0x0097,
     0x008d,
     0x008e,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x009d,
     0x0085,
     0x0008,
     0x0087,
     0x0018,
     0x0019,
     0x0092,
     0x008f,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0080,
     0x0081,
     0x0082,
     0x0083,
     0x0084,
     0x000a,
     0x0017,
     0x001b,
     0x0088,
     0x0089,
     0x008a,
     0x008b,
     0x008c,
     0x0005,
     0x0006,
     0x0007,
     0x0090,
     0x0091,
     0x0016,
     0x0093,
     0x0094,
     0x0095,
     0x0096,
     0x0004,
     0x0098,
     0x0099,
     0x009a,
     0x009b,
     0x0014,
     0x0015,
     0x009e,
     0x001a,
     0x0020,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00b0,
     0x002e,
     0x003c,
     0x0028,
     0x002b,
     0x0021,
     0x0026,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00a7,
     0x0024,
     0x002a,
     0x0029,
     0x003b,
     0x005e,
     0x002d,
     0x002f,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00f9,
     0x002c,
     0x0025,
     0x005f,
     0x003e,
     0x003f,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x0060,
     0x003a,
     0x00a3,
     0x00e0,
     0x0027,
     0x003d,
     0x0022,
     0xfffd,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00a8,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00e9,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00e8,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00e7,
     0xfffd,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x009f,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\xc2\x9c",
     "\x09",
     "\xc2\x86",
     "\x7f",
     "\xc2\x97",
     "\xc2\x8d",
     "\xc2\x8e",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\xc2\x9d",
     "\xc2\x85",
     "\x08",
     "\xc2\x87",
     "\x18",
     "\x19",
     "\xc2\x92",
     "\xc2\x8f",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\xc2\x80",
     "\xc2\x81",
     "\xc2\x82",
     "\xc2\x83",
     "\xc2\x84",
     "\x0a",
     "\x17",
     "\x1b",
     "\xc2\x88",
     "\xc2\x89",
     "\xc2\x8a",
     "\xc2\x8b",
     "\xc2\x8c",
     "\x05",
     "\x06",
     "\x07",
     "\xc2\x90",
     "\xc2\x91",
     "\x16",
     "\xc2\x93",
     "\xc2\x94",
     "\xc2\x95",
     "\xc2\x96",
     "\x04",
     "\xc2\x98",
     "\xc2\x99",
     "\xc2\x9a",
     "\xc2\x9b",
     "\x14",
     "\x15",
     "\xc2\x9e",
     "\x1a",
     "\x20",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc2\xb0",
     "\x2e",
     "\x3c",
     "\x28",
     "\x2b",
     "\x21",
     "\x26",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc2\xa7",
     "\x24",
     "\x2a",
     "\x29",
     "\x3b",
     "\x5e",
     "\x2d",
     "\x2f",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc3\xb9",
     "\x2c",
     "\x25",
     "\x5f",
     "\x3e",
     "\x3f",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x60",
     "\x3a",
     "\xc2\xa3",
     "\xc3\xa0",
     "\x27",
     "\x3d",
     "\x22",
     "\xef\xbf\xbd",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc2\xa8",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc3\xa9",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc3\xa8",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc3\xa7",
     "\xef\xbf\xbd",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc2\x9f",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x37",
     0x00000005 => "\x2d",
     0x00000006 => "\x2e",
     0x00000007 => "\x2f",
     0x00000008 => "\x16",
     0x00000009 => "\x05",
     0x0000000a => "\x25",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x3c",
     0x00000015 => "\x3d",
     0x00000016 => "\x32",
     0x00000017 => "\x26",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x3f",
     0x0000001b => "\x27",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x40",
     0x00000021 => "\x4f",
     0x00000022 => "\x7f",
     0x00000024 => "\x5b",
     0x00000025 => "\x6c",
     0x00000026 => "\x50",
     0x00000027 => "\x7d",
     0x00000028 => "\x4d",
     0x00000029 => "\x5d",
     0x0000002a => "\x5c",
     0x0000002b => "\x4e",
     0x0000002c => "\x6b",
     0x0000002d => "\x60",
     0x0000002e => "\x4b",
     0x0000002f => "\x61",
     0x00000030 => "\xf0",
     0x00000031 => "\xf1",
     0x00000032 => "\xf2",
     0x00000033 => "\xf3",
     0x00000034 => "\xf4",
     0x00000035 => "\xf5",
     0x00000036 => "\xf6",
     0x00000037 => "\xf7",
     0x00000038 => "\xf8",
     0x00000039 => "\xf9",
     0x0000003a => "\x7a",
     0x0000003b => "\x5e",
     0x0000003c => "\x4c",
     0x0000003d => "\x7e",
     0x0000003e => "\x6e",
     0x0000003f => "\x6f",
     0x00000041 => "\xc1",
     0x00000042 => "\xc2",
     0x00000043 => "\xc3",
     0x00000044 => "\xc4",
     0x00000045 => "\xc5",
     0x00000046 => "\xc6",
     0x00000047 => "\xc7",
     0x00000048 => "\xc8",
     0x00000049 => "\xc9",
     0x0000004a => "\xd1",
     0x0000004b => "\xd2",
     0x0000004c => "\xd3",
     0x0000004d => "\xd4",
     0x0000004e => "\xd5",
     0x0000004f => "\xd6",
     0x00000050 => "\xd7",
     0x00000051 => "\xd8",
     0x00000052 => "\xd9",
     0x00000053 => "\xe2",
     0x00000054 => "\xe3",
     0x00000055 => "\xe4",
     0x00000056 => "\xe5",
     0x00000057 => "\xe6",
     0x00000058 => "\xe7",
     0x00000059 => "\xe8",
     0x0000005a => "\xe9",
     0x0000005e => "\x5f",
     0x0000005f => "\x6d",
     0x00000060 => "\x79",
     0x00000061 => "\x81",
     0x00000062 => "\x82",
     0x00000063 => "\x83",
     0x00000064 => "\x84",
     0x00000065 => "\x85",
     0x00000066 => "\x86",
     0x00000067 => "\x87",
     0x00000068 => "\x88",
     0x00000069 => "\x89",
     0x0000006a => "\x91",
     0x0000006b => "\x92",
     0x0000006c => "\x93",
     0x0000006d => "\x94",
     0x0000006e => "\x95",
     0x0000006f => "\x96",
     0x00000070 => "\x97",
     0x00000071 => "\x98",
     0x00000072 => "\x99",
     0x00000073 => "\xa2",
     0x00000074 => "\xa3",
     0x00000075 => "\xa4",
     0x00000076 => "\xa5",
     0x00000077 => "\xa6",
     0x00000078 => "\xa7",
     0x00000079 => "\xa8",
     0x0000007a => "\xa9",
     0x0000007f => "\x07",
     0x00000080 => "\x20",
     0x00000081 => "\x21",
     0x00000082 => "\x22",
     0x00000083 => "\x23",
     0x00000084 => "\x24",
     0x00000085 => "\x15",
     0x00000086 => "\x06",
     0x00000087 => "\x17",
     0x00000088 => "\x28",
     0x00000089 => "\x29",
     0x0000008a => "\x2a",
     0x0000008b => "\x2b",
     0x0000008c => "\x2c",
     0x0000008d => "\x09",
     0x0000008e => "\x0a",
     0x0000008f => "\x1b",
     0x00000090 => "\x30",
     0x00000091 => "\x31",
     0x00000092 => "\x1a",
     0x00000093 => "\x33",
     0x00000094 => "\x34",
     0x00000095 => "\x35",
     0x00000096 => "\x36",
     0x00000097 => "\x08",
     0x00000098 => "\x38",
     0x00000099 => "\x39",
     0x0000009a => "\x3a",
     0x0000009b => "\x3b",
     0x0000009c => "\x04",
     0x0000009d => "\x14",
     0x0000009e => "\x3e",
     0x0000009f => "\xff",
     0x000000a3 => "\x7b",
     0x000000a7 => "\x5a",
     0x000000a8 => "\xa1",
     0x000000b0 => "\x4a",
     0x000000e0 => "\x7c",
     0x000000e7 => "\xe0",
     0x000000e8 => "\xd0",
     0x000000e9 => "\xc0",
     0x000000f9 => "\x6a",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::EBCDIC_FR - Conversion routines for EBCDIC_FR
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for EBCDIC-FR.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
   source: IBM 3270 Char Set Ref Ch 10, GA27-2837-9, April 1987
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  0000009C | STRING TERMINATOR (ST)
     05 |  00000009 | CHARACTER TABULATION (HT)
     06 |  00000086 | START OF SELECTED AREA (SSA)
     07 |  0000007F | DELETE (DEL)
     08 |  00000097 | END OF GUARDED AREA (EPA)
     09 |  0000008D | REVERSE LINE FEED (RI)
     0A |  0000008E | SINGLE-SHIFT TWO (SS2)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  0000009D | OPERATING SYSTEM COMMAND (OSC)
     15 |  00000085 | NEXT LINE (NEL)
     16 |  00000008 | BACKSPACE (BS)
     17 |  00000087 | END OF SELECTED AREA (ESA)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  00000092 | PRIVATE USE TWO (PU2)
     1B |  0000008F | SINGLE-SHIFT THREE (SS3)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000080 | PADDING CHARACTER (PAD)
     21 |  00000081 | HIGH OCTET PRESET (HOP)
     22 |  00000082 | BREAK PERMITTED HERE (BPH)
     23 |  00000083 | NO BREAK HERE (NBH)
     24 |  00000084 | INDEX (IND)
     25 |  0000000A | LINE FEED (LF)
     26 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     27 |  0000001B | ESCAPE (ESC)
     28 |  00000088 | CHARACTER TABULATION SET (HTS)
     29 |  00000089 | CHARACTER TABULATION WITH JUSTIFICATION (HTJ)
     2A |  0000008A | LINE TABULATION SET (VTS)
     2B |  0000008B | PARTIAL LINE FORWARD (PLD)
     2C |  0000008C | PARTIAL LINE BACKWARD (PLU)
     2D |  00000005 | ENQUIRY (ENQ)
     2E |  00000006 | ACKNOWLEDGE (ACK)
     2F |  00000007 | BELL (BEL)
     30 |  00000090 | DEVICE CONTROL STRING (DCS)
     31 |  00000091 | PRIVATE USE ONE (PU1)
     32 |  00000016 | SYNCHRONOUS IDLE (SYN)
     33 |  00000093 | SET TRANSMIT STATE (STS)
     34 |  00000094 | CANCEL CHARACTER (CCH)
     35 |  00000095 | MESSAGE WAITING (MW)
     36 |  00000096 | START OF GUARDED AREA (SPA)
     37 |  00000004 | END OF TRANSMISSION (EOT)
     38 |  00000098 | START OF STRING (SOS)
     39 |  00000099 | SINGLE GRAPHIC CHARACTER INTRODUCER (SGCI)
     3A |  0000009A | SINGLE CHARACTER INTRODUCER (SCI)
     3B |  0000009B | CONTROL SEQUENCE INTRODUCER (CSI)
     3C |  00000014 | DEVICE CONTROL FOUR (DC4)
     3D |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     3E |  0000009E | PRIVACY MESSAGE (PM)
     3F |  0000001A | SUBSTITUTE (SUB)
     40 |  00000020 | SPACE
     4A |  000000B0 | DEGREE SIGN
     4B |  0000002E | FULL STOP
     4C |  0000003C | LESS-THAN SIGN
     4D |  00000028 | LEFT PARENTHESIS
     4E |  0000002B | PLUS SIGN
     4F |  00000021 | EXCLAMATION MARK
     50 |  00000026 | AMPERSAND
     5A |  000000A7 | SECTION SIGN
     5B |  00000024 | DOLLAR SIGN
     5C |  0000002A | ASTERISK
     5D |  00000029 | RIGHT PARENTHESIS
     5E |  0000003B | SEMICOLON
     5F |  0000005E | CIRCUMFLEX ACCENT
     60 |  0000002D | HYPHEN-MINUS
     61 |  0000002F | SOLIDUS
     6A |  000000F9 | LATIN SMALL LETTER U WITH GRAVE
     6B |  0000002C | COMMA
     6C |  00000025 | PERCENT SIGN
     6D |  0000005F | LOW LINE
     6E |  0000003E | GREATER-THAN SIGN
     6F |  0000003F | QUESTION MARK
     79 |  00000060 | GRAVE ACCENT
     7A |  0000003A | COLON
     7B |  000000A3 | POUND SIGN
     7C |  000000E0 | LATIN SMALL LETTER A WITH GRAVE
     7D |  00000027 | APOSTROPHE
     7E |  0000003D | EQUALS SIGN
     7F |  00000022 | QUOTATION MARK
     81 |  00000061 | LATIN SMALL LETTER A
     82 |  00000062 | LATIN SMALL LETTER B
     83 |  00000063 | LATIN SMALL LETTER C
     84 |  00000064 | LATIN SMALL LETTER D
     85 |  00000065 | LATIN SMALL LETTER E
     86 |  00000066 | LATIN SMALL LETTER F
     87 |  00000067 | LATIN SMALL LETTER G
     88 |  00000068 | LATIN SMALL LETTER H
     89 |  00000069 | LATIN SMALL LETTER I
     91 |  0000006A | LATIN SMALL LETTER J
     92 |  0000006B | LATIN SMALL LETTER K
     93 |  0000006C | LATIN SMALL LETTER L
     94 |  0000006D | LATIN SMALL LETTER M
     95 |  0000006E | LATIN SMALL LETTER N
     96 |  0000006F | LATIN SMALL LETTER O
     97 |  00000070 | LATIN SMALL LETTER P
     98 |  00000071 | LATIN SMALL LETTER Q
     99 |  00000072 | LATIN SMALL LETTER R
     A1 |  000000A8 | DIAERESIS
     A2 |  00000073 | LATIN SMALL LETTER S
     A3 |  00000074 | LATIN SMALL LETTER T
     A4 |  00000075 | LATIN SMALL LETTER U
     A5 |  00000076 | LATIN SMALL LETTER V
     A6 |  00000077 | LATIN SMALL LETTER W
     A7 |  00000078 | LATIN SMALL LETTER X
     A8 |  00000079 | LATIN SMALL LETTER Y
     A9 |  0000007A | LATIN SMALL LETTER Z
     C0 |  000000E9 | LATIN SMALL LETTER E WITH ACUTE
     C1 |  00000041 | LATIN CAPITAL LETTER A
     C2 |  00000042 | LATIN CAPITAL LETTER B
     C3 |  00000043 | LATIN CAPITAL LETTER C
     C4 |  00000044 | LATIN CAPITAL LETTER D
     C5 |  00000045 | LATIN CAPITAL LETTER E
     C6 |  00000046 | LATIN CAPITAL LETTER F
     C7 |  00000047 | LATIN CAPITAL LETTER G
     C8 |  00000048 | LATIN CAPITAL LETTER H
     C9 |  00000049 | LATIN CAPITAL LETTER I
     D0 |  000000E8 | LATIN SMALL LETTER E WITH GRAVE
     D1 |  0000004A | LATIN CAPITAL LETTER J
     D2 |  0000004B | LATIN CAPITAL LETTER K
     D3 |  0000004C | LATIN CAPITAL LETTER L
     D4 |  0000004D | LATIN CAPITAL LETTER M
     D5 |  0000004E | LATIN CAPITAL LETTER N
     D6 |  0000004F | LATIN CAPITAL LETTER O
     D7 |  00000050 | LATIN CAPITAL LETTER P
     D8 |  00000051 | LATIN CAPITAL LETTER Q
     D9 |  00000052 | LATIN CAPITAL LETTER R
     E0 |  000000E7 | LATIN SMALL LETTER C WITH CEDILLA
     E2 |  00000053 | LATIN CAPITAL LETTER S
     E3 |  00000054 | LATIN CAPITAL LETTER T
     E4 |  00000055 | LATIN CAPITAL LETTER U
     E5 |  00000056 | LATIN CAPITAL LETTER V
     E6 |  00000057 | LATIN CAPITAL LETTER W
     E7 |  00000058 | LATIN CAPITAL LETTER X
     E8 |  00000059 | LATIN CAPITAL LETTER Y
     E9 |  0000005A | LATIN CAPITAL LETTER Z
     F0 |  00000030 | DIGIT ZERO
     F1 |  00000031 | DIGIT ONE
     F2 |  00000032 | DIGIT TWO
     F3 |  00000033 | DIGIT THREE
     F4 |  00000034 | DIGIT FOUR
     F5 |  00000035 | DIGIT FIVE
     F6 |  00000036 | DIGIT SIX
     F7 |  00000037 | DIGIT SEVEN
     F8 |  00000038 | DIGIT EIGHT
     F9 |  00000039 | DIGIT NINE
     FF |  0000009F | APPLICATION PROGRAM COMMAND (APC)
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/EBCDIC_IS_FRISS.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for EBCDIC-IS-FRISS.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::EBCDIC_IS_FRISS;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x0004,
     0x0005,
     0x0006,
     0x0007,
     0x0008,
     0x0009,
     0x000a,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x0014,
     0x0015,
     0x0016,
     0x0017,
     0x0018,
     0x0019,
     0x001a,
     0x001b,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x0020,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00e1,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x003c,
     0x002e,
     0x00c1,
     0x0028,
     0x002b,
     0x0021,
     0x00d0,
     0x00e9,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00ed,
     0xfffd,
     0xfffd,
     0xfffd,
     0x0024,
     0x0025,
     0x00c9,
     0x002a,
     0x0029,
     0x003b,
     0x0026,
     0x002d,
     0x002f,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x0023,
     0x2018,
     0x002c,
     0x00de,
     0x005f,
     0x003e,
     0x003f,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00cd,
     0xfffd,
     0xfffd,
     0x007c,
     0x00f0,
     0x003a,
     0x00c6,
     0x00d6,
     0x0027,
     0x003d,
     0x0022,
     0xfffd,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00dd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00b0,
     0x00f6,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0xfffd,
     0xfffd,
     0x005b,
     0x00fd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x005d,
     0x00a8,
     0xfffd,
     0xfffd,
     0x00fe,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00f3,
     0xfffd,
     0x00e6,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00fa,
     0xfffd,
     0x00b4,
     0xfffd,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00d3,
     0xfffd,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00da,
     0x007f,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\x04",
     "\x05",
     "\x06",
     "\x07",
     "\x08",
     "\x09",
     "\x0a",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\x14",
     "\x15",
     "\x16",
     "\x17",
     "\x18",
     "\x19",
     "\x1a",
     "\x1b",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x20",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc3\xa1",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x3c",
     "\x2e",
     "\xc3\x81",
     "\x28",
     "\x2b",
     "\x21",
     "\xc3\x90",
     "\xc3\xa9",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc3\xad",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x24",
     "\x25",
     "\xc3\x89",
     "\x2a",
     "\x29",
     "\x3b",
     "\x26",
     "\x2d",
     "\x2f",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x23",
     "\xe2\x80\x98",
     "\x2c",
     "\xc3\x9e",
     "\x5f",
     "\x3e",
     "\x3f",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc3\x8d",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x7c",
     "\xc3\xb0",
     "\x3a",
     "\xc3\x86",
     "\xc3\x96",
     "\x27",
     "\x3d",
     "\x22",
     "\xef\xbf\xbd",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc3\x9d",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc2\xb0",
     "\xc3\xb6",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x5b",
     "\xc3\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x5d",
     "\xc2\xa8",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc3\xbe",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc3\xb3",
     "\xef\xbf\xbd",
     "\xc3\xa6",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc3\xba",
     "\xef\xbf\xbd",
     "\xc2\xb4",
     "\xef\xbf\xbd",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc3\x93",
     "\xef\xbf\xbd",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc3\x9a",
     "\x7f",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x04",
     0x00000005 => "\x05",
     0x00000006 => "\x06",
     0x00000007 => "\x07",
     0x00000008 => "\x08",
     0x00000009 => "\x09",
     0x0000000a => "\x0a",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x14",
     0x00000015 => "\x15",
     0x00000016 => "\x16",
     0x00000017 => "\x17",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x1a",
     0x0000001b => "\x1b",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x40",
     0x00000021 => "\x4f",
     0x00000022 => "\x7f",
     0x00000023 => "\x69",
     0x00000024 => "\x59",
     0x00000025 => "\x5a",
     0x00000026 => "\x5f",
     0x00000027 => "\x7d",
     0x00000028 => "\x4d",
     0x00000029 => "\x5d",
     0x0000002a => "\x5c",
     0x0000002b => "\x4e",
     0x0000002c => "\x6b",
     0x0000002d => "\x60",
     0x0000002e => "\x4b",
     0x0000002f => "\x61",
     0x00000030 => "\xf0",
     0x00000031 => "\xf1",
     0x00000032 => "\xf2",
     0x00000033 => "\xf3",
     0x00000034 => "\xf4",
     0x00000035 => "\xf5",
     0x00000036 => "\xf6",
     0x00000037 => "\xf7",
     0x00000038 => "\xf8",
     0x00000039 => "\xf9",
     0x0000003a => "\x7a",
     0x0000003b => "\x5e",
     0x0000003c => "\x4a",
     0x0000003d => "\x7e",
     0x0000003e => "\x6e",
     0x0000003f => "\x6f",
     0x00000041 => "\xc1",
     0x00000042 => "\xc2",
     0x00000043 => "\xc3",
     0x00000044 => "\xc4",
     0x00000045 => "\xc5",
     0x00000046 => "\xc6",
     0x00000047 => "\xc7",
     0x00000048 => "\xc8",
     0x00000049 => "\xc9",
     0x0000004a => "\xd1",
     0x0000004b => "\xd2",
     0x0000004c => "\xd3",
     0x0000004d => "\xd4",
     0x0000004e => "\xd5",
     0x0000004f => "\xd6",
     0x00000050 => "\xd7",
     0x00000051 => "\xd8",
     0x00000052 => "\xd9",
     0x00000053 => "\xe2",
     0x00000054 => "\xe3",
     0x00000055 => "\xe4",
     0x00000056 => "\xe5",
     0x00000057 => "\xe6",
     0x00000058 => "\xe7",
     0x00000059 => "\xe8",
     0x0000005a => "\xe9",
     0x0000005b => "\xac",
     0x0000005d => "\xbc",
     0x0000005f => "\x6d",
     0x00000061 => "\x81",
     0x00000062 => "\x82",
     0x00000063 => "\x83",
     0x00000064 => "\x84",
     0x00000065 => "\x85",
     0x00000066 => "\x86",
     0x00000067 => "\x87",
     0x00000068 => "\x88",
     0x00000069 => "\x89",
     0x0000006a => "\x91",
     0x0000006b => "\x92",
     0x0000006c => "\x93",
     0x0000006d => "\x94",
     0x0000006e => "\x95",
     0x0000006f => "\x96",
     0x00000070 => "\x97",
     0x00000071 => "\x98",
     0x00000072 => "\x99",
     0x00000073 => "\xa2",
     0x00000074 => "\xa3",
     0x00000075 => "\xa4",
     0x00000076 => "\xa5",
     0x00000077 => "\xa6",
     0x00000078 => "\xa7",
     0x00000079 => "\xa8",
     0x0000007a => "\xa9",
     0x0000007c => "\x78",
     0x0000007f => "\xff",
     0x000000a8 => "\xbd",
     0x000000b0 => "\xa0",
     0x000000b4 => "\xe0",
     0x000000c1 => "\x4c",
     0x000000c6 => "\x7b",
     0x000000c9 => "\x5b",
     0x000000cd => "\x75",
     0x000000d0 => "\x50",
     0x000000d3 => "\xee",
     0x000000d6 => "\x7c",
     0x000000da => "\xfe",
     0x000000dd => "\x8d",
     0x000000de => "\x6c",
     0x000000e1 => "\x45",
     0x000000e6 => "\xd0",
     0x000000e9 => "\x51",
     0x000000ed => "\x55",
     0x000000f0 => "\x79",
     0x000000f3 => "\xce",
     0x000000f6 => "\xa1",
     0x000000fa => "\xde",
     0x000000fd => "\xad",
     0x000000fe => "\xc0",
     0x00002018 => "\x6a",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::EBCDIC_IS_FRISS - Conversion routines for EBCDIC_IS_FRISS
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for EBCDIC-IS-FRISS.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
   source: Skyrsuvelar Rikisins og Reykjavikurborgar, feb 1982
  alias FRISS
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  00000004 | END OF TRANSMISSION (EOT)
     05 |  00000005 | ENQUIRY (ENQ)
     06 |  00000006 | ACKNOWLEDGE (ACK)
     07 |  00000007 | BELL (BEL)
     08 |  00000008 | BACKSPACE (BS)
     09 |  00000009 | CHARACTER TABULATION (HT)
     0A |  0000000A | LINE FEED (LF)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  00000014 | DEVICE CONTROL FOUR (DC4)
     15 |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     16 |  00000016 | SYNCHRONOUS IDLE (SYN)
     17 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  0000001A | SUBSTITUTE (SUB)
     1B |  0000001B | ESCAPE (ESC)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     40 |  00000020 | SPACE
     45 |  000000E1 | LATIN SMALL LETTER A WITH ACUTE
     4A |  0000003C | LESS-THAN SIGN
     4B |  0000002E | FULL STOP
     4C |  000000C1 | LATIN CAPITAL LETTER A WITH ACUTE
     4D |  00000028 | LEFT PARENTHESIS
     4E |  0000002B | PLUS SIGN
     4F |  00000021 | EXCLAMATION MARK
     50 |  000000D0 | LATIN CAPITAL LETTER ETH (Icelandic)
     51 |  000000E9 | LATIN SMALL LETTER E WITH ACUTE
     55 |  000000ED | LATIN SMALL LETTER I WITH ACUTE
     59 |  00000024 | DOLLAR SIGN
     5A |  00000025 | PERCENT SIGN
     5B |  000000C9 | LATIN CAPITAL LETTER E WITH ACUTE
     5C |  0000002A | ASTERISK
     5D |  00000029 | RIGHT PARENTHESIS
     5E |  0000003B | SEMICOLON
     5F |  00000026 | AMPERSAND
     60 |  0000002D | HYPHEN-MINUS
     61 |  0000002F | SOLIDUS
     69 |  00000023 | NUMBER SIGN
     6A |  00002018 | LEFT SINGLE QUOTATION MARK
     6B |  0000002C | COMMA
     6C |  000000DE | LATIN CAPITAL LETTER THORN (Icelandic)
     6D |  0000005F | LOW LINE
     6E |  0000003E | GREATER-THAN SIGN
     6F |  0000003F | QUESTION MARK
     75 |  000000CD | LATIN CAPITAL LETTER I WITH ACUTE
     78 |  0000007C | VERTICAL LINE
     79 |  000000F0 | LATIN SMALL LETTER ETH (Icelandic)
     7A |  0000003A | COLON
     7B |  000000C6 | LATIN CAPITAL LETTER AE
     7C |  000000D6 | LATIN CAPITAL LETTER O WITH DIAERESIS
     7D |  00000027 | APOSTROPHE
     7E |  0000003D | EQUALS SIGN
     7F |  00000022 | QUOTATION MARK
     81 |  00000061 | LATIN SMALL LETTER A
     82 |  00000062 | LATIN SMALL LETTER B
     83 |  00000063 | LATIN SMALL LETTER C
     84 |  00000064 | LATIN SMALL LETTER D
     85 |  00000065 | LATIN SMALL LETTER E
     86 |  00000066 | LATIN SMALL LETTER F
     87 |  00000067 | LATIN SMALL LETTER G
     88 |  00000068 | LATIN SMALL LETTER H
     89 |  00000069 | LATIN SMALL LETTER I
     8D |  000000DD | LATIN CAPITAL LETTER Y WITH ACUTE
     91 |  0000006A | LATIN SMALL LETTER J
     92 |  0000006B | LATIN SMALL LETTER K
     93 |  0000006C | LATIN SMALL LETTER L
     94 |  0000006D | LATIN SMALL LETTER M
     95 |  0000006E | LATIN SMALL LETTER N
     96 |  0000006F | LATIN SMALL LETTER O
     97 |  00000070 | LATIN SMALL LETTER P
     98 |  00000071 | LATIN SMALL LETTER Q
     99 |  00000072 | LATIN SMALL LETTER R
     A0 |  000000B0 | DEGREE SIGN
     A1 |  000000F6 | LATIN SMALL LETTER O WITH DIAERESIS
     A2 |  00000073 | LATIN SMALL LETTER S
     A3 |  00000074 | LATIN SMALL LETTER T
     A4 |  00000075 | LATIN SMALL LETTER U
     A5 |  00000076 | LATIN SMALL LETTER V
     A6 |  00000077 | LATIN SMALL LETTER W
     A7 |  00000078 | LATIN SMALL LETTER X
     A8 |  00000079 | LATIN SMALL LETTER Y
     A9 |  0000007A | LATIN SMALL LETTER Z
     AC |  0000005B | LEFT SQUARE BRACKET
     AD |  000000FD | LATIN SMALL LETTER Y WITH ACUTE
     BC |  0000005D | RIGHT SQUARE BRACKET
     BD |  000000A8 | DIAERESIS
     C0 |  000000FE | LATIN SMALL LETTER THORN (Icelandic)
     C1 |  00000041 | LATIN CAPITAL LETTER A
     C2 |  00000042 | LATIN CAPITAL LETTER B
     C3 |  00000043 | LATIN CAPITAL LETTER C
     C4 |  00000044 | LATIN CAPITAL LETTER D
     C5 |  00000045 | LATIN CAPITAL LETTER E
     C6 |  00000046 | LATIN CAPITAL LETTER F
     C7 |  00000047 | LATIN CAPITAL LETTER G
     C8 |  00000048 | LATIN CAPITAL LETTER H
     C9 |  00000049 | LATIN CAPITAL LETTER I
     CE |  000000F3 | LATIN SMALL LETTER O WITH ACUTE
     D0 |  000000E6 | LATIN SMALL LETTER AE
     D1 |  0000004A | LATIN CAPITAL LETTER J
     D2 |  0000004B | LATIN CAPITAL LETTER K
     D3 |  0000004C | LATIN CAPITAL LETTER L
     D4 |  0000004D | LATIN CAPITAL LETTER M
     D5 |  0000004E | LATIN CAPITAL LETTER N
     D6 |  0000004F | LATIN CAPITAL LETTER O
     D7 |  00000050 | LATIN CAPITAL LETTER P
     D8 |  00000051 | LATIN CAPITAL LETTER Q
     D9 |  00000052 | LATIN CAPITAL LETTER R
     DE |  000000FA | LATIN SMALL LETTER U WITH ACUTE
     E0 |  000000B4 | ACUTE ACCENT
     E2 |  00000053 | LATIN CAPITAL LETTER S
     E3 |  00000054 | LATIN CAPITAL LETTER T
     E4 |  00000055 | LATIN CAPITAL LETTER U
     E5 |  00000056 | LATIN CAPITAL LETTER V
     E6 |  00000057 | LATIN CAPITAL LETTER W
     E7 |  00000058 | LATIN CAPITAL LETTER X
     E8 |  00000059 | LATIN CAPITAL LETTER Y
     E9 |  0000005A | LATIN CAPITAL LETTER Z
     EE |  000000D3 | LATIN CAPITAL LETTER O WITH ACUTE
     F0 |  00000030 | DIGIT ZERO
     F1 |  00000031 | DIGIT ONE
     F2 |  00000032 | DIGIT TWO
     F3 |  00000033 | DIGIT THREE
     F4 |  00000034 | DIGIT FOUR
     F5 |  00000035 | DIGIT FIVE
     F6 |  00000036 | DIGIT SIX
     F7 |  00000037 | DIGIT SEVEN
     F8 |  00000038 | DIGIT EIGHT
     F9 |  00000039 | DIGIT NINE
     FE |  000000DA | LATIN CAPITAL LETTER U WITH ACUTE
     FF |  0000007F | DELETE (DEL)
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/EBCDIC_IT.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for EBCDIC-IT.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::EBCDIC_IT;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x009c,
     0x0009,
     0x0086,
     0x007f,
     0x0097,
     0x008d,
     0x008e,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x009d,
     0x0085,
     0x0008,
     0x0087,
     0x0018,
     0x0019,
     0x0092,
     0x008f,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0080,
     0x0081,
     0x0082,
     0x0083,
     0x0084,
     0x000a,
     0x0017,
     0x001b,
     0x0088,
     0x0089,
     0x008a,
     0x008b,
     0x008c,
     0x0005,
     0x0006,
     0x0007,
     0x0090,
     0x0091,
     0x0016,
     0x0093,
     0x0094,
     0x0095,
     0x0096,
     0x0004,
     0x0098,
     0x0099,
     0x009a,
     0x009b,
     0x0014,
     0x0015,
     0x009e,
     0x001a,
     0x0020,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00b0,
     0x002e,
     0x003c,
     0x0028,
     0x002b,
     0x0021,
     0x0026,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00e9,
     0x0024,
     0x002a,
     0x0029,
     0x003b,
     0x005e,
     0x002d,
     0x002f,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00f2,
     0x002c,
     0x0025,
     0x005f,
     0x003e,
     0x003f,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00f9,
     0x003a,
     0x00a3,
     0x00a7,
     0x0027,
     0x003d,
     0x0022,
     0xfffd,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00ec,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00e0,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00e8,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00e7,
     0xfffd,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x009f,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\xc2\x9c",
     "\x09",
     "\xc2\x86",
     "\x7f",
     "\xc2\x97",
     "\xc2\x8d",
     "\xc2\x8e",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\xc2\x9d",
     "\xc2\x85",
     "\x08",
     "\xc2\x87",
     "\x18",
     "\x19",
     "\xc2\x92",
     "\xc2\x8f",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\xc2\x80",
     "\xc2\x81",
     "\xc2\x82",
     "\xc2\x83",
     "\xc2\x84",
     "\x0a",
     "\x17",
     "\x1b",
     "\xc2\x88",
     "\xc2\x89",
     "\xc2\x8a",
     "\xc2\x8b",
     "\xc2\x8c",
     "\x05",
     "\x06",
     "\x07",
     "\xc2\x90",
     "\xc2\x91",
     "\x16",
     "\xc2\x93",
     "\xc2\x94",
     "\xc2\x95",
     "\xc2\x96",
     "\x04",
     "\xc2\x98",
     "\xc2\x99",
     "\xc2\x9a",
     "\xc2\x9b",
     "\x14",
     "\x15",
     "\xc2\x9e",
     "\x1a",
     "\x20",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc2\xb0",
     "\x2e",
     "\x3c",
     "\x28",
     "\x2b",
     "\x21",
     "\x26",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc3\xa9",
     "\x24",
     "\x2a",
     "\x29",
     "\x3b",
     "\x5e",
     "\x2d",
     "\x2f",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc3\xb2",
     "\x2c",
     "\x25",
     "\x5f",
     "\x3e",
     "\x3f",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc3\xb9",
     "\x3a",
     "\xc2\xa3",
     "\xc2\xa7",
     "\x27",
     "\x3d",
     "\x22",
     "\xef\xbf\xbd",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc3\xac",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc3\xa0",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc3\xa8",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc3\xa7",
     "\xef\xbf\xbd",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc2\x9f",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x37",
     0x00000005 => "\x2d",
     0x00000006 => "\x2e",
     0x00000007 => "\x2f",
     0x00000008 => "\x16",
     0x00000009 => "\x05",
     0x0000000a => "\x25",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x3c",
     0x00000015 => "\x3d",
     0x00000016 => "\x32",
     0x00000017 => "\x26",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x3f",
     0x0000001b => "\x27",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x40",
     0x00000021 => "\x4f",
     0x00000022 => "\x7f",
     0x00000024 => "\x5b",
     0x00000025 => "\x6c",
     0x00000026 => "\x50",
     0x00000027 => "\x7d",
     0x00000028 => "\x4d",
     0x00000029 => "\x5d",
     0x0000002a => "\x5c",
     0x0000002b => "\x4e",
     0x0000002c => "\x6b",
     0x0000002d => "\x60",
     0x0000002e => "\x4b",
     0x0000002f => "\x61",
     0x00000030 => "\xf0",
     0x00000031 => "\xf1",
     0x00000032 => "\xf2",
     0x00000033 => "\xf3",
     0x00000034 => "\xf4",
     0x00000035 => "\xf5",
     0x00000036 => "\xf6",
     0x00000037 => "\xf7",
     0x00000038 => "\xf8",
     0x00000039 => "\xf9",
     0x0000003a => "\x7a",
     0x0000003b => "\x5e",
     0x0000003c => "\x4c",
     0x0000003d => "\x7e",
     0x0000003e => "\x6e",
     0x0000003f => "\x6f",
     0x00000041 => "\xc1",
     0x00000042 => "\xc2",
     0x00000043 => "\xc3",
     0x00000044 => "\xc4",
     0x00000045 => "\xc5",
     0x00000046 => "\xc6",
     0x00000047 => "\xc7",
     0x00000048 => "\xc8",
     0x00000049 => "\xc9",
     0x0000004a => "\xd1",
     0x0000004b => "\xd2",
     0x0000004c => "\xd3",
     0x0000004d => "\xd4",
     0x0000004e => "\xd5",
     0x0000004f => "\xd6",
     0x00000050 => "\xd7",
     0x00000051 => "\xd8",
     0x00000052 => "\xd9",
     0x00000053 => "\xe2",
     0x00000054 => "\xe3",
     0x00000055 => "\xe4",
     0x00000056 => "\xe5",
     0x00000057 => "\xe6",
     0x00000058 => "\xe7",
     0x00000059 => "\xe8",
     0x0000005a => "\xe9",
     0x0000005e => "\x5f",
     0x0000005f => "\x6d",
     0x00000061 => "\x81",
     0x00000062 => "\x82",
     0x00000063 => "\x83",
     0x00000064 => "\x84",
     0x00000065 => "\x85",
     0x00000066 => "\x86",
     0x00000067 => "\x87",
     0x00000068 => "\x88",
     0x00000069 => "\x89",
     0x0000006a => "\x91",
     0x0000006b => "\x92",
     0x0000006c => "\x93",
     0x0000006d => "\x94",
     0x0000006e => "\x95",
     0x0000006f => "\x96",
     0x00000070 => "\x97",
     0x00000071 => "\x98",
     0x00000072 => "\x99",
     0x00000073 => "\xa2",
     0x00000074 => "\xa3",
     0x00000075 => "\xa4",
     0x00000076 => "\xa5",
     0x00000077 => "\xa6",
     0x00000078 => "\xa7",
     0x00000079 => "\xa8",
     0x0000007a => "\xa9",
     0x0000007f => "\x07",
     0x00000080 => "\x20",
     0x00000081 => "\x21",
     0x00000082 => "\x22",
     0x00000083 => "\x23",
     0x00000084 => "\x24",
     0x00000085 => "\x15",
     0x00000086 => "\x06",
     0x00000087 => "\x17",
     0x00000088 => "\x28",
     0x00000089 => "\x29",
     0x0000008a => "\x2a",
     0x0000008b => "\x2b",
     0x0000008c => "\x2c",
     0x0000008d => "\x09",
     0x0000008e => "\x0a",
     0x0000008f => "\x1b",
     0x00000090 => "\x30",
     0x00000091 => "\x31",
     0x00000092 => "\x1a",
     0x00000093 => "\x33",
     0x00000094 => "\x34",
     0x00000095 => "\x35",
     0x00000096 => "\x36",
     0x00000097 => "\x08",
     0x00000098 => "\x38",
     0x00000099 => "\x39",
     0x0000009a => "\x3a",
     0x0000009b => "\x3b",
     0x0000009c => "\x04",
     0x0000009d => "\x14",
     0x0000009e => "\x3e",
     0x0000009f => "\xff",
     0x000000a3 => "\x7b",
     0x000000a7 => "\x7c",
     0x000000b0 => "\x4a",
     0x000000e0 => "\xc0",
     0x000000e7 => "\xe0",
     0x000000e8 => "\xd0",
     0x000000e9 => "\x5a",
     0x000000ec => "\xa1",
     0x000000f2 => "\x6a",
     0x000000f9 => "\x79",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::EBCDIC_IT - Conversion routines for EBCDIC_IT
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for EBCDIC-IT.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
   source: IBM 3270 Char Set Ref Ch 10, GA27-2837-9, April 1987
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  0000009C | STRING TERMINATOR (ST)
     05 |  00000009 | CHARACTER TABULATION (HT)
     06 |  00000086 | START OF SELECTED AREA (SSA)
     07 |  0000007F | DELETE (DEL)
     08 |  00000097 | END OF GUARDED AREA (EPA)
     09 |  0000008D | REVERSE LINE FEED (RI)
     0A |  0000008E | SINGLE-SHIFT TWO (SS2)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  0000009D | OPERATING SYSTEM COMMAND (OSC)
     15 |  00000085 | NEXT LINE (NEL)
     16 |  00000008 | BACKSPACE (BS)
     17 |  00000087 | END OF SELECTED AREA (ESA)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  00000092 | PRIVATE USE TWO (PU2)
     1B |  0000008F | SINGLE-SHIFT THREE (SS3)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000080 | PADDING CHARACTER (PAD)
     21 |  00000081 | HIGH OCTET PRESET (HOP)
     22 |  00000082 | BREAK PERMITTED HERE (BPH)
     23 |  00000083 | NO BREAK HERE (NBH)
     24 |  00000084 | INDEX (IND)
     25 |  0000000A | LINE FEED (LF)
     26 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     27 |  0000001B | ESCAPE (ESC)
     28 |  00000088 | CHARACTER TABULATION SET (HTS)
     29 |  00000089 | CHARACTER TABULATION WITH JUSTIFICATION (HTJ)
     2A |  0000008A | LINE TABULATION SET (VTS)
     2B |  0000008B | PARTIAL LINE FORWARD (PLD)
     2C |  0000008C | PARTIAL LINE BACKWARD (PLU)
     2D |  00000005 | ENQUIRY (ENQ)
     2E |  00000006 | ACKNOWLEDGE (ACK)
     2F |  00000007 | BELL (BEL)
     30 |  00000090 | DEVICE CONTROL STRING (DCS)
     31 |  00000091 | PRIVATE USE ONE (PU1)
     32 |  00000016 | SYNCHRONOUS IDLE (SYN)
     33 |  00000093 | SET TRANSMIT STATE (STS)
     34 |  00000094 | CANCEL CHARACTER (CCH)
     35 |  00000095 | MESSAGE WAITING (MW)
     36 |  00000096 | START OF GUARDED AREA (SPA)
     37 |  00000004 | END OF TRANSMISSION (EOT)
     38 |  00000098 | START OF STRING (SOS)
     39 |  00000099 | SINGLE GRAPHIC CHARACTER INTRODUCER (SGCI)
     3A |  0000009A | SINGLE CHARACTER INTRODUCER (SCI)
     3B |  0000009B | CONTROL SEQUENCE INTRODUCER (CSI)
     3C |  00000014 | DEVICE CONTROL FOUR (DC4)
     3D |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     3E |  0000009E | PRIVACY MESSAGE (PM)
     3F |  0000001A | SUBSTITUTE (SUB)
     40 |  00000020 | SPACE
     4A |  000000B0 | DEGREE SIGN
     4B |  0000002E | FULL STOP
     4C |  0000003C | LESS-THAN SIGN
     4D |  00000028 | LEFT PARENTHESIS
     4E |  0000002B | PLUS SIGN
     4F |  00000021 | EXCLAMATION MARK
     50 |  00000026 | AMPERSAND
     5A |  000000E9 | LATIN SMALL LETTER E WITH ACUTE
     5B |  00000024 | DOLLAR SIGN
     5C |  0000002A | ASTERISK
     5D |  00000029 | RIGHT PARENTHESIS
     5E |  0000003B | SEMICOLON
     5F |  0000005E | CIRCUMFLEX ACCENT
     60 |  0000002D | HYPHEN-MINUS
     61 |  0000002F | SOLIDUS
     6A |  000000F2 | LATIN SMALL LETTER O WITH GRAVE
     6B |  0000002C | COMMA
     6C |  00000025 | PERCENT SIGN
     6D |  0000005F | LOW LINE
     6E |  0000003E | GREATER-THAN SIGN
     6F |  0000003F | QUESTION MARK
     79 |  000000F9 | LATIN SMALL LETTER U WITH GRAVE
     7A |  0000003A | COLON
     7B |  000000A3 | POUND SIGN
     7C |  000000A7 | SECTION SIGN
     7D |  00000027 | APOSTROPHE
     7E |  0000003D | EQUALS SIGN
     7F |  00000022 | QUOTATION MARK
     81 |  00000061 | LATIN SMALL LETTER A
     82 |  00000062 | LATIN SMALL LETTER B
     83 |  00000063 | LATIN SMALL LETTER C
     84 |  00000064 | LATIN SMALL LETTER D
     85 |  00000065 | LATIN SMALL LETTER E
     86 |  00000066 | LATIN SMALL LETTER F
     87 |  00000067 | LATIN SMALL LETTER G
     88 |  00000068 | LATIN SMALL LETTER H
     89 |  00000069 | LATIN SMALL LETTER I
     91 |  0000006A | LATIN SMALL LETTER J
     92 |  0000006B | LATIN SMALL LETTER K
     93 |  0000006C | LATIN SMALL LETTER L
     94 |  0000006D | LATIN SMALL LETTER M
     95 |  0000006E | LATIN SMALL LETTER N
     96 |  0000006F | LATIN SMALL LETTER O
     97 |  00000070 | LATIN SMALL LETTER P
     98 |  00000071 | LATIN SMALL LETTER Q
     99 |  00000072 | LATIN SMALL LETTER R
     A1 |  000000EC | LATIN SMALL LETTER I WITH GRAVE
     A2 |  00000073 | LATIN SMALL LETTER S
     A3 |  00000074 | LATIN SMALL LETTER T
     A4 |  00000075 | LATIN SMALL LETTER U
     A5 |  00000076 | LATIN SMALL LETTER V
     A6 |  00000077 | LATIN SMALL LETTER W
     A7 |  00000078 | LATIN SMALL LETTER X
     A8 |  00000079 | LATIN SMALL LETTER Y
     A9 |  0000007A | LATIN SMALL LETTER Z
     C0 |  000000E0 | LATIN SMALL LETTER A WITH GRAVE
     C1 |  00000041 | LATIN CAPITAL LETTER A
     C2 |  00000042 | LATIN CAPITAL LETTER B
     C3 |  00000043 | LATIN CAPITAL LETTER C
     C4 |  00000044 | LATIN CAPITAL LETTER D
     C5 |  00000045 | LATIN CAPITAL LETTER E
     C6 |  00000046 | LATIN CAPITAL LETTER F
     C7 |  00000047 | LATIN CAPITAL LETTER G
     C8 |  00000048 | LATIN CAPITAL LETTER H
     C9 |  00000049 | LATIN CAPITAL LETTER I
     D0 |  000000E8 | LATIN SMALL LETTER E WITH GRAVE
     D1 |  0000004A | LATIN CAPITAL LETTER J
     D2 |  0000004B | LATIN CAPITAL LETTER K
     D3 |  0000004C | LATIN CAPITAL LETTER L
     D4 |  0000004D | LATIN CAPITAL LETTER M
     D5 |  0000004E | LATIN CAPITAL LETTER N
     D6 |  0000004F | LATIN CAPITAL LETTER O
     D7 |  00000050 | LATIN CAPITAL LETTER P
     D8 |  00000051 | LATIN CAPITAL LETTER Q
     D9 |  00000052 | LATIN CAPITAL LETTER R
     E0 |  000000E7 | LATIN SMALL LETTER C WITH CEDILLA
     E2 |  00000053 | LATIN CAPITAL LETTER S
     E3 |  00000054 | LATIN CAPITAL LETTER T
     E4 |  00000055 | LATIN CAPITAL LETTER U
     E5 |  00000056 | LATIN CAPITAL LETTER V
     E6 |  00000057 | LATIN CAPITAL LETTER W
     E7 |  00000058 | LATIN CAPITAL LETTER X
     E8 |  00000059 | LATIN CAPITAL LETTER Y
     E9 |  0000005A | LATIN CAPITAL LETTER Z
     F0 |  00000030 | DIGIT ZERO
     F1 |  00000031 | DIGIT ONE
     F2 |  00000032 | DIGIT TWO
     F3 |  00000033 | DIGIT THREE
     F4 |  00000034 | DIGIT FOUR
     F5 |  00000035 | DIGIT FIVE
     F6 |  00000036 | DIGIT SIX
     F7 |  00000037 | DIGIT SEVEN
     F8 |  00000038 | DIGIT EIGHT
     F9 |  00000039 | DIGIT NINE
     FF |  0000009F | APPLICATION PROGRAM COMMAND (APC)
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/EBCDIC_PT.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for EBCDIC-PT.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::EBCDIC_PT;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x009c,
     0x0009,
     0x0086,
     0x007f,
     0x0097,
     0x008d,
     0x008e,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x009d,
     0x0085,
     0x0008,
     0x0087,
     0x0018,
     0x0019,
     0x0092,
     0x008f,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0080,
     0x0081,
     0x0082,
     0x0083,
     0x0084,
     0x000a,
     0x0017,
     0x001b,
     0x0088,
     0x0089,
     0x008a,
     0x008b,
     0x008c,
     0x0005,
     0x0006,
     0x0007,
     0x0090,
     0x0091,
     0x0016,
     0x0093,
     0x0094,
     0x0095,
     0x0096,
     0x0004,
     0x0098,
     0x0099,
     0x009a,
     0x009b,
     0x0014,
     0x0015,
     0x009e,
     0x001a,
     0x0020,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x005b,
     0x002e,
     0x003c,
     0x0028,
     0x002b,
     0x0021,
     0x0026,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x005d,
     0x0024,
     0x002a,
     0x0029,
     0x003b,
     0x005e,
     0x002d,
     0x002f,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00f5,
     0x002c,
     0x0025,
     0x005f,
     0x003e,
     0x003f,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x0060,
     0x003a,
     0x00c3,
     0x00d5,
     0x0027,
     0x003d,
     0x0022,
     0xfffd,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00e7,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00e3,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00b4,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00c7,
     0xfffd,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x009f,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\xc2\x9c",
     "\x09",
     "\xc2\x86",
     "\x7f",
     "\xc2\x97",
     "\xc2\x8d",
     "\xc2\x8e",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\xc2\x9d",
     "\xc2\x85",
     "\x08",
     "\xc2\x87",
     "\x18",
     "\x19",
     "\xc2\x92",
     "\xc2\x8f",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\xc2\x80",
     "\xc2\x81",
     "\xc2\x82",
     "\xc2\x83",
     "\xc2\x84",
     "\x0a",
     "\x17",
     "\x1b",
     "\xc2\x88",
     "\xc2\x89",
     "\xc2\x8a",
     "\xc2\x8b",
     "\xc2\x8c",
     "\x05",
     "\x06",
     "\x07",
     "\xc2\x90",
     "\xc2\x91",
     "\x16",
     "\xc2\x93",
     "\xc2\x94",
     "\xc2\x95",
     "\xc2\x96",
     "\x04",
     "\xc2\x98",
     "\xc2\x99",
     "\xc2\x9a",
     "\xc2\x9b",
     "\x14",
     "\x15",
     "\xc2\x9e",
     "\x1a",
     "\x20",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x5b",
     "\x2e",
     "\x3c",
     "\x28",
     "\x2b",
     "\x21",
     "\x26",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x5d",
     "\x24",
     "\x2a",
     "\x29",
     "\x3b",
     "\x5e",
     "\x2d",
     "\x2f",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc3\xb5",
     "\x2c",
     "\x25",
     "\x5f",
     "\x3e",
     "\x3f",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x60",
     "\x3a",
     "\xc3\x83",
     "\xc3\x95",
     "\x27",
     "\x3d",
     "\x22",
     "\xef\xbf\xbd",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc3\xa7",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc3\xa3",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc2\xb4",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc3\x87",
     "\xef\xbf\xbd",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc2\x9f",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x37",
     0x00000005 => "\x2d",
     0x00000006 => "\x2e",
     0x00000007 => "\x2f",
     0x00000008 => "\x16",
     0x00000009 => "\x05",
     0x0000000a => "\x25",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x3c",
     0x00000015 => "\x3d",
     0x00000016 => "\x32",
     0x00000017 => "\x26",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x3f",
     0x0000001b => "\x27",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x40",
     0x00000021 => "\x4f",
     0x00000022 => "\x7f",
     0x00000024 => "\x5b",
     0x00000025 => "\x6c",
     0x00000026 => "\x50",
     0x00000027 => "\x7d",
     0x00000028 => "\x4d",
     0x00000029 => "\x5d",
     0x0000002a => "\x5c",
     0x0000002b => "\x4e",
     0x0000002c => "\x6b",
     0x0000002d => "\x60",
     0x0000002e => "\x4b",
     0x0000002f => "\x61",
     0x00000030 => "\xf0",
     0x00000031 => "\xf1",
     0x00000032 => "\xf2",
     0x00000033 => "\xf3",
     0x00000034 => "\xf4",
     0x00000035 => "\xf5",
     0x00000036 => "\xf6",
     0x00000037 => "\xf7",
     0x00000038 => "\xf8",
     0x00000039 => "\xf9",
     0x0000003a => "\x7a",
     0x0000003b => "\x5e",
     0x0000003c => "\x4c",
     0x0000003d => "\x7e",
     0x0000003e => "\x6e",
     0x0000003f => "\x6f",
     0x00000041 => "\xc1",
     0x00000042 => "\xc2",
     0x00000043 => "\xc3",
     0x00000044 => "\xc4",
     0x00000045 => "\xc5",
     0x00000046 => "\xc6",
     0x00000047 => "\xc7",
     0x00000048 => "\xc8",
     0x00000049 => "\xc9",
     0x0000004a => "\xd1",
     0x0000004b => "\xd2",
     0x0000004c => "\xd3",
     0x0000004d => "\xd4",
     0x0000004e => "\xd5",
     0x0000004f => "\xd6",
     0x00000050 => "\xd7",
     0x00000051 => "\xd8",
     0x00000052 => "\xd9",
     0x00000053 => "\xe2",
     0x00000054 => "\xe3",
     0x00000055 => "\xe4",
     0x00000056 => "\xe5",
     0x00000057 => "\xe6",
     0x00000058 => "\xe7",
     0x00000059 => "\xe8",
     0x0000005a => "\xe9",
     0x0000005b => "\x4a",
     0x0000005d => "\x5a",
     0x0000005e => "\x5f",
     0x0000005f => "\x6d",
     0x00000060 => "\x79",
     0x00000061 => "\x81",
     0x00000062 => "\x82",
     0x00000063 => "\x83",
     0x00000064 => "\x84",
     0x00000065 => "\x85",
     0x00000066 => "\x86",
     0x00000067 => "\x87",
     0x00000068 => "\x88",
     0x00000069 => "\x89",
     0x0000006a => "\x91",
     0x0000006b => "\x92",
     0x0000006c => "\x93",
     0x0000006d => "\x94",
     0x0000006e => "\x95",
     0x0000006f => "\x96",
     0x00000070 => "\x97",
     0x00000071 => "\x98",
     0x00000072 => "\x99",
     0x00000073 => "\xa2",
     0x00000074 => "\xa3",
     0x00000075 => "\xa4",
     0x00000076 => "\xa5",
     0x00000077 => "\xa6",
     0x00000078 => "\xa7",
     0x00000079 => "\xa8",
     0x0000007a => "\xa9",
     0x0000007f => "\x07",
     0x00000080 => "\x20",
     0x00000081 => "\x21",
     0x00000082 => "\x22",
     0x00000083 => "\x23",
     0x00000084 => "\x24",
     0x00000085 => "\x15",
     0x00000086 => "\x06",
     0x00000087 => "\x17",
     0x00000088 => "\x28",
     0x00000089 => "\x29",
     0x0000008a => "\x2a",
     0x0000008b => "\x2b",
     0x0000008c => "\x2c",
     0x0000008d => "\x09",
     0x0000008e => "\x0a",
     0x0000008f => "\x1b",
     0x00000090 => "\x30",
     0x00000091 => "\x31",
     0x00000092 => "\x1a",
     0x00000093 => "\x33",
     0x00000094 => "\x34",
     0x00000095 => "\x35",
     0x00000096 => "\x36",
     0x00000097 => "\x08",
     0x00000098 => "\x38",
     0x00000099 => "\x39",
     0x0000009a => "\x3a",
     0x0000009b => "\x3b",
     0x0000009c => "\x04",
     0x0000009d => "\x14",
     0x0000009e => "\x3e",
     0x0000009f => "\xff",
     0x000000b4 => "\xd0",
     0x000000c3 => "\x7b",
     0x000000c7 => "\xe0",
     0x000000d5 => "\x7c",
     0x000000e3 => "\xc0",
     0x000000e7 => "\xa1",
     0x000000f5 => "\x6a",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::EBCDIC_PT - Conversion routines for EBCDIC_PT
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for EBCDIC-PT.
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  0000009C | STRING TERMINATOR (ST)
     05 |  00000009 | CHARACTER TABULATION (HT)
     06 |  00000086 | START OF SELECTED AREA (SSA)
     07 |  0000007F | DELETE (DEL)
     08 |  00000097 | END OF GUARDED AREA (EPA)
     09 |  0000008D | REVERSE LINE FEED (RI)
     0A |  0000008E | SINGLE-SHIFT TWO (SS2)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  0000009D | OPERATING SYSTEM COMMAND (OSC)
     15 |  00000085 | NEXT LINE (NEL)
     16 |  00000008 | BACKSPACE (BS)
     17 |  00000087 | END OF SELECTED AREA (ESA)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  00000092 | PRIVATE USE TWO (PU2)
     1B |  0000008F | SINGLE-SHIFT THREE (SS3)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000080 | PADDING CHARACTER (PAD)
     21 |  00000081 | HIGH OCTET PRESET (HOP)
     22 |  00000082 | BREAK PERMITTED HERE (BPH)
     23 |  00000083 | NO BREAK HERE (NBH)
     24 |  00000084 | INDEX (IND)
     25 |  0000000A | LINE FEED (LF)
     26 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     27 |  0000001B | ESCAPE (ESC)
     28 |  00000088 | CHARACTER TABULATION SET (HTS)
     29 |  00000089 | CHARACTER TABULATION WITH JUSTIFICATION (HTJ)
     2A |  0000008A | LINE TABULATION SET (VTS)
     2B |  0000008B | PARTIAL LINE FORWARD (PLD)
     2C |  0000008C | PARTIAL LINE BACKWARD (PLU)
     2D |  00000005 | ENQUIRY (ENQ)
     2E |  00000006 | ACKNOWLEDGE (ACK)
     2F |  00000007 | BELL (BEL)
     30 |  00000090 | DEVICE CONTROL STRING (DCS)
     31 |  00000091 | PRIVATE USE ONE (PU1)
     32 |  00000016 | SYNCHRONOUS IDLE (SYN)
     33 |  00000093 | SET TRANSMIT STATE (STS)
     34 |  00000094 | CANCEL CHARACTER (CCH)
     35 |  00000095 | MESSAGE WAITING (MW)
     36 |  00000096 | START OF GUARDED AREA (SPA)
     37 |  00000004 | END OF TRANSMISSION (EOT)
     38 |  00000098 | START OF STRING (SOS)
     39 |  00000099 | SINGLE GRAPHIC CHARACTER INTRODUCER (SGCI)
     3A |  0000009A | SINGLE CHARACTER INTRODUCER (SCI)
     3B |  0000009B | CONTROL SEQUENCE INTRODUCER (CSI)
     3C |  00000014 | DEVICE CONTROL FOUR (DC4)
     3D |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     3E |  0000009E | PRIVACY MESSAGE (PM)
     3F |  0000001A | SUBSTITUTE (SUB)
     40 |  00000020 | SPACE
     4A |  0000005B | LEFT SQUARE BRACKET
     4B |  0000002E | FULL STOP
     4C |  0000003C | LESS-THAN SIGN
     4D |  00000028 | LEFT PARENTHESIS
     4E |  0000002B | PLUS SIGN
     4F |  00000021 | EXCLAMATION MARK
     50 |  00000026 | AMPERSAND
     5A |  0000005D | RIGHT SQUARE BRACKET
     5B |  00000024 | DOLLAR SIGN
     5C |  0000002A | ASTERISK
     5D |  00000029 | RIGHT PARENTHESIS
     5E |  0000003B | SEMICOLON
     5F |  0000005E | CIRCUMFLEX ACCENT
     60 |  0000002D | HYPHEN-MINUS
     61 |  0000002F | SOLIDUS
     6A |  000000F5 | LATIN SMALL LETTER O WITH TILDE
     6B |  0000002C | COMMA
     6C |  00000025 | PERCENT SIGN
     6D |  0000005F | LOW LINE
     6E |  0000003E | GREATER-THAN SIGN
     6F |  0000003F | QUESTION MARK
     79 |  00000060 | GRAVE ACCENT
     7A |  0000003A | COLON
     7B |  000000C3 | LATIN CAPITAL LETTER A WITH TILDE
     7C |  000000D5 | LATIN CAPITAL LETTER O WITH TILDE
     7D |  00000027 | APOSTROPHE
     7E |  0000003D | EQUALS SIGN
     7F |  00000022 | QUOTATION MARK
     81 |  00000061 | LATIN SMALL LETTER A
     82 |  00000062 | LATIN SMALL LETTER B
     83 |  00000063 | LATIN SMALL LETTER C
     84 |  00000064 | LATIN SMALL LETTER D
     85 |  00000065 | LATIN SMALL LETTER E
     86 |  00000066 | LATIN SMALL LETTER F
     87 |  00000067 | LATIN SMALL LETTER G
     88 |  00000068 | LATIN SMALL LETTER H
     89 |  00000069 | LATIN SMALL LETTER I
     91 |  0000006A | LATIN SMALL LETTER J
     92 |  0000006B | LATIN SMALL LETTER K
     93 |  0000006C | LATIN SMALL LETTER L
     94 |  0000006D | LATIN SMALL LETTER M
     95 |  0000006E | LATIN SMALL LETTER N
     96 |  0000006F | LATIN SMALL LETTER O
     97 |  00000070 | LATIN SMALL LETTER P
     98 |  00000071 | LATIN SMALL LETTER Q
     99 |  00000072 | LATIN SMALL LETTER R
     A1 |  000000E7 | LATIN SMALL LETTER C WITH CEDILLA
     A2 |  00000073 | LATIN SMALL LETTER S
     A3 |  00000074 | LATIN SMALL LETTER T
     A4 |  00000075 | LATIN SMALL LETTER U
     A5 |  00000076 | LATIN SMALL LETTER V
     A6 |  00000077 | LATIN SMALL LETTER W
     A7 |  00000078 | LATIN SMALL LETTER X
     A8 |  00000079 | LATIN SMALL LETTER Y
     A9 |  0000007A | LATIN SMALL LETTER Z
     C0 |  000000E3 | LATIN SMALL LETTER A WITH TILDE
     C1 |  00000041 | LATIN CAPITAL LETTER A
     C2 |  00000042 | LATIN CAPITAL LETTER B
     C3 |  00000043 | LATIN CAPITAL LETTER C
     C4 |  00000044 | LATIN CAPITAL LETTER D
     C5 |  00000045 | LATIN CAPITAL LETTER E
     C6 |  00000046 | LATIN CAPITAL LETTER F
     C7 |  00000047 | LATIN CAPITAL LETTER G
     C8 |  00000048 | LATIN CAPITAL LETTER H
     C9 |  00000049 | LATIN CAPITAL LETTER I
     D0 |  000000B4 | ACUTE ACCENT
     D1 |  0000004A | LATIN CAPITAL LETTER J
     D2 |  0000004B | LATIN CAPITAL LETTER K
     D3 |  0000004C | LATIN CAPITAL LETTER L
     D4 |  0000004D | LATIN CAPITAL LETTER M
     D5 |  0000004E | LATIN CAPITAL LETTER N
     D6 |  0000004F | LATIN CAPITAL LETTER O
     D7 |  00000050 | LATIN CAPITAL LETTER P
     D8 |  00000051 | LATIN CAPITAL LETTER Q
     D9 |  00000052 | LATIN CAPITAL LETTER R
     E0 |  000000C7 | LATIN CAPITAL LETTER C WITH CEDILLA
     E2 |  00000053 | LATIN CAPITAL LETTER S
     E3 |  00000054 | LATIN CAPITAL LETTER T
     E4 |  00000055 | LATIN CAPITAL LETTER U
     E5 |  00000056 | LATIN CAPITAL LETTER V
     E6 |  00000057 | LATIN CAPITAL LETTER W
     E7 |  00000058 | LATIN CAPITAL LETTER X
     E8 |  00000059 | LATIN CAPITAL LETTER Y
     E9 |  0000005A | LATIN CAPITAL LETTER Z
     F0 |  00000030 | DIGIT ZERO
     F1 |  00000031 | DIGIT ONE
     F2 |  00000032 | DIGIT TWO
     F3 |  00000033 | DIGIT THREE
     F4 |  00000034 | DIGIT FOUR
     F5 |  00000035 | DIGIT FIVE
     F6 |  00000036 | DIGIT SIX
     F7 |  00000037 | DIGIT SEVEN
     F8 |  00000038 | DIGIT EIGHT
     F9 |  00000039 | DIGIT NINE
     FF |  0000009F | APPLICATION PROGRAM COMMAND (APC)
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/EBCDIC_UK.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for EBCDIC-UK.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::EBCDIC_UK;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x009c,
     0x0009,
     0x0086,
     0x007f,
     0x0097,
     0x008d,
     0x008e,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x009d,
     0x0085,
     0x0008,
     0x0087,
     0x0018,
     0x0019,
     0x0092,
     0x008f,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0080,
     0x0081,
     0x0082,
     0x0083,
     0x0084,
     0x000a,
     0x0017,
     0x001b,
     0x0088,
     0x0089,
     0x008a,
     0x008b,
     0x008c,
     0x0005,
     0x0006,
     0x0007,
     0x0090,
     0x0091,
     0x0016,
     0x0093,
     0x0094,
     0x0095,
     0x0096,
     0x0004,
     0x0098,
     0x0099,
     0x009a,
     0x009b,
     0x0014,
     0x0015,
     0x009e,
     0x001a,
     0x0020,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x0024,
     0x002e,
     0x003c,
     0x0028,
     0x002b,
     0x007c,
     0x0026,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x0021,
     0x00a3,
     0x002a,
     0x0029,
     0x003b,
     0x00ac,
     0x002d,
     0x002f,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00a6,
     0x002c,
     0x0025,
     0x005f,
     0x003e,
     0x003f,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x0060,
     0x003a,
     0x0023,
     0x0040,
     0x0027,
     0x003d,
     0x0022,
     0xfffd,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x203e,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x007b,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x007d,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x005c,
     0xfffd,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x009f,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\xc2\x9c",
     "\x09",
     "\xc2\x86",
     "\x7f",
     "\xc2\x97",
     "\xc2\x8d",
     "\xc2\x8e",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\xc2\x9d",
     "\xc2\x85",
     "\x08",
     "\xc2\x87",
     "\x18",
     "\x19",
     "\xc2\x92",
     "\xc2\x8f",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\xc2\x80",
     "\xc2\x81",
     "\xc2\x82",
     "\xc2\x83",
     "\xc2\x84",
     "\x0a",
     "\x17",
     "\x1b",
     "\xc2\x88",
     "\xc2\x89",
     "\xc2\x8a",
     "\xc2\x8b",
     "\xc2\x8c",
     "\x05",
     "\x06",
     "\x07",
     "\xc2\x90",
     "\xc2\x91",
     "\x16",
     "\xc2\x93",
     "\xc2\x94",
     "\xc2\x95",
     "\xc2\x96",
     "\x04",
     "\xc2\x98",
     "\xc2\x99",
     "\xc2\x9a",
     "\xc2\x9b",
     "\x14",
     "\x15",
     "\xc2\x9e",
     "\x1a",
     "\x20",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x24",
     "\x2e",
     "\x3c",
     "\x28",
     "\x2b",
     "\x7c",
     "\x26",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x21",
     "\xc2\xa3",
     "\x2a",
     "\x29",
     "\x3b",
     "\xc2\xac",
     "\x2d",
     "\x2f",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc2\xa6",
     "\x2c",
     "\x25",
     "\x5f",
     "\x3e",
     "\x3f",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x60",
     "\x3a",
     "\x23",
     "\x40",
     "\x27",
     "\x3d",
     "\x22",
     "\xef\xbf\xbd",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xe2\x80\xbe",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x7b",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x7d",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x5c",
     "\xef\xbf\xbd",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc2\x9f",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x37",
     0x00000005 => "\x2d",
     0x00000006 => "\x2e",
     0x00000007 => "\x2f",
     0x00000008 => "\x16",
     0x00000009 => "\x05",
     0x0000000a => "\x25",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x3c",
     0x00000015 => "\x3d",
     0x00000016 => "\x32",
     0x00000017 => "\x26",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x3f",
     0x0000001b => "\x27",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x40",
     0x00000021 => "\x5a",
     0x00000022 => "\x7f",
     0x00000023 => "\x7b",
     0x00000024 => "\x4a",
     0x00000025 => "\x6c",
     0x00000026 => "\x50",
     0x00000027 => "\x7d",
     0x00000028 => "\x4d",
     0x00000029 => "\x5d",
     0x0000002a => "\x5c",
     0x0000002b => "\x4e",
     0x0000002c => "\x6b",
     0x0000002d => "\x60",
     0x0000002e => "\x4b",
     0x0000002f => "\x61",
     0x00000030 => "\xf0",
     0x00000031 => "\xf1",
     0x00000032 => "\xf2",
     0x00000033 => "\xf3",
     0x00000034 => "\xf4",
     0x00000035 => "\xf5",
     0x00000036 => "\xf6",
     0x00000037 => "\xf7",
     0x00000038 => "\xf8",
     0x00000039 => "\xf9",
     0x0000003a => "\x7a",
     0x0000003b => "\x5e",
     0x0000003c => "\x4c",
     0x0000003d => "\x7e",
     0x0000003e => "\x6e",
     0x0000003f => "\x6f",
     0x00000040 => "\x7c",
     0x00000041 => "\xc1",
     0x00000042 => "\xc2",
     0x00000043 => "\xc3",
     0x00000044 => "\xc4",
     0x00000045 => "\xc5",
     0x00000046 => "\xc6",
     0x00000047 => "\xc7",
     0x00000048 => "\xc8",
     0x00000049 => "\xc9",
     0x0000004a => "\xd1",
     0x0000004b => "\xd2",
     0x0000004c => "\xd3",
     0x0000004d => "\xd4",
     0x0000004e => "\xd5",
     0x0000004f => "\xd6",
     0x00000050 => "\xd7",
     0x00000051 => "\xd8",
     0x00000052 => "\xd9",
     0x00000053 => "\xe2",
     0x00000054 => "\xe3",
     0x00000055 => "\xe4",
     0x00000056 => "\xe5",
     0x00000057 => "\xe6",
     0x00000058 => "\xe7",
     0x00000059 => "\xe8",
     0x0000005a => "\xe9",
     0x0000005c => "\xe0",
     0x0000005f => "\x6d",
     0x00000060 => "\x79",
     0x00000061 => "\x81",
     0x00000062 => "\x82",
     0x00000063 => "\x83",
     0x00000064 => "\x84",
     0x00000065 => "\x85",
     0x00000066 => "\x86",
     0x00000067 => "\x87",
     0x00000068 => "\x88",
     0x00000069 => "\x89",
     0x0000006a => "\x91",
     0x0000006b => "\x92",
     0x0000006c => "\x93",
     0x0000006d => "\x94",
     0x0000006e => "\x95",
     0x0000006f => "\x96",
     0x00000070 => "\x97",
     0x00000071 => "\x98",
     0x00000072 => "\x99",
     0x00000073 => "\xa2",
     0x00000074 => "\xa3",
     0x00000075 => "\xa4",
     0x00000076 => "\xa5",
     0x00000077 => "\xa6",
     0x00000078 => "\xa7",
     0x00000079 => "\xa8",
     0x0000007a => "\xa9",
     0x0000007b => "\xc0",
     0x0000007c => "\x4f",
     0x0000007d => "\xd0",
     0x0000007f => "\x07",
     0x00000080 => "\x20",
     0x00000081 => "\x21",
     0x00000082 => "\x22",
     0x00000083 => "\x23",
     0x00000084 => "\x24",
     0x00000085 => "\x15",
     0x00000086 => "\x06",
     0x00000087 => "\x17",
     0x00000088 => "\x28",
     0x00000089 => "\x29",
     0x0000008a => "\x2a",
     0x0000008b => "\x2b",
     0x0000008c => "\x2c",
     0x0000008d => "\x09",
     0x0000008e => "\x0a",
     0x0000008f => "\x1b",
     0x00000090 => "\x30",
     0x00000091 => "\x31",
     0x00000092 => "\x1a",
     0x00000093 => "\x33",
     0x00000094 => "\x34",
     0x00000095 => "\x35",
     0x00000096 => "\x36",
     0x00000097 => "\x08",
     0x00000098 => "\x38",
     0x00000099 => "\x39",
     0x0000009a => "\x3a",
     0x0000009b => "\x3b",
     0x0000009c => "\x04",
     0x0000009d => "\x14",
     0x0000009e => "\x3e",
     0x0000009f => "\xff",
     0x000000a3 => "\x5b",
     0x000000a6 => "\x6a",
     0x000000ac => "\x5f",
     0x0000203e => "\xa1",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::EBCDIC_UK - Conversion routines for EBCDIC_UK
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for EBCDIC-UK.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
   source: IBM 3270 Char Set Ref Ch 10, GA27-2837-9, April 1987
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  0000009C | STRING TERMINATOR (ST)
     05 |  00000009 | CHARACTER TABULATION (HT)
     06 |  00000086 | START OF SELECTED AREA (SSA)
     07 |  0000007F | DELETE (DEL)
     08 |  00000097 | END OF GUARDED AREA (EPA)
     09 |  0000008D | REVERSE LINE FEED (RI)
     0A |  0000008E | SINGLE-SHIFT TWO (SS2)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  0000009D | OPERATING SYSTEM COMMAND (OSC)
     15 |  00000085 | NEXT LINE (NEL)
     16 |  00000008 | BACKSPACE (BS)
     17 |  00000087 | END OF SELECTED AREA (ESA)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  00000092 | PRIVATE USE TWO (PU2)
     1B |  0000008F | SINGLE-SHIFT THREE (SS3)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000080 | PADDING CHARACTER (PAD)
     21 |  00000081 | HIGH OCTET PRESET (HOP)
     22 |  00000082 | BREAK PERMITTED HERE (BPH)
     23 |  00000083 | NO BREAK HERE (NBH)
     24 |  00000084 | INDEX (IND)
     25 |  0000000A | LINE FEED (LF)
     26 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     27 |  0000001B | ESCAPE (ESC)
     28 |  00000088 | CHARACTER TABULATION SET (HTS)
     29 |  00000089 | CHARACTER TABULATION WITH JUSTIFICATION (HTJ)
     2A |  0000008A | LINE TABULATION SET (VTS)
     2B |  0000008B | PARTIAL LINE FORWARD (PLD)
     2C |  0000008C | PARTIAL LINE BACKWARD (PLU)
     2D |  00000005 | ENQUIRY (ENQ)
     2E |  00000006 | ACKNOWLEDGE (ACK)
     2F |  00000007 | BELL (BEL)
     30 |  00000090 | DEVICE CONTROL STRING (DCS)
     31 |  00000091 | PRIVATE USE ONE (PU1)
     32 |  00000016 | SYNCHRONOUS IDLE (SYN)
     33 |  00000093 | SET TRANSMIT STATE (STS)
     34 |  00000094 | CANCEL CHARACTER (CCH)
     35 |  00000095 | MESSAGE WAITING (MW)
     36 |  00000096 | START OF GUARDED AREA (SPA)
     37 |  00000004 | END OF TRANSMISSION (EOT)
     38 |  00000098 | START OF STRING (SOS)
     39 |  00000099 | SINGLE GRAPHIC CHARACTER INTRODUCER (SGCI)
     3A |  0000009A | SINGLE CHARACTER INTRODUCER (SCI)
     3B |  0000009B | CONTROL SEQUENCE INTRODUCER (CSI)
     3C |  00000014 | DEVICE CONTROL FOUR (DC4)
     3D |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     3E |  0000009E | PRIVACY MESSAGE (PM)
     3F |  0000001A | SUBSTITUTE (SUB)
     40 |  00000020 | SPACE
     4A |  00000024 | DOLLAR SIGN
     4B |  0000002E | FULL STOP
     4C |  0000003C | LESS-THAN SIGN
     4D |  00000028 | LEFT PARENTHESIS
     4E |  0000002B | PLUS SIGN
     4F |  0000007C | VERTICAL LINE
     50 |  00000026 | AMPERSAND
     5A |  00000021 | EXCLAMATION MARK
     5B |  000000A3 | POUND SIGN
     5C |  0000002A | ASTERISK
     5D |  00000029 | RIGHT PARENTHESIS
     5E |  0000003B | SEMICOLON
     5F |  000000AC | NOT SIGN
     60 |  0000002D | HYPHEN-MINUS
     61 |  0000002F | SOLIDUS
     6A |  000000A6 | BROKEN BAR
     6B |  0000002C | COMMA
     6C |  00000025 | PERCENT SIGN
     6D |  0000005F | LOW LINE
     6E |  0000003E | GREATER-THAN SIGN
     6F |  0000003F | QUESTION MARK
     79 |  00000060 | GRAVE ACCENT
     7A |  0000003A | COLON
     7B |  00000023 | NUMBER SIGN
     7C |  00000040 | COMMERCIAL AT
     7D |  00000027 | APOSTROPHE
     7E |  0000003D | EQUALS SIGN
     7F |  00000022 | QUOTATION MARK
     81 |  00000061 | LATIN SMALL LETTER A
     82 |  00000062 | LATIN SMALL LETTER B
     83 |  00000063 | LATIN SMALL LETTER C
     84 |  00000064 | LATIN SMALL LETTER D
     85 |  00000065 | LATIN SMALL LETTER E
     86 |  00000066 | LATIN SMALL LETTER F
     87 |  00000067 | LATIN SMALL LETTER G
     88 |  00000068 | LATIN SMALL LETTER H
     89 |  00000069 | LATIN SMALL LETTER I
     91 |  0000006A | LATIN SMALL LETTER J
     92 |  0000006B | LATIN SMALL LETTER K
     93 |  0000006C | LATIN SMALL LETTER L
     94 |  0000006D | LATIN SMALL LETTER M
     95 |  0000006E | LATIN SMALL LETTER N
     96 |  0000006F | LATIN SMALL LETTER O
     97 |  00000070 | LATIN SMALL LETTER P
     98 |  00000071 | LATIN SMALL LETTER Q
     99 |  00000072 | LATIN SMALL LETTER R
     A1 |  0000203E | OVERLINE
     A2 |  00000073 | LATIN SMALL LETTER S
     A3 |  00000074 | LATIN SMALL LETTER T
     A4 |  00000075 | LATIN SMALL LETTER U
     A5 |  00000076 | LATIN SMALL LETTER V
     A6 |  00000077 | LATIN SMALL LETTER W
     A7 |  00000078 | LATIN SMALL LETTER X
     A8 |  00000079 | LATIN SMALL LETTER Y
     A9 |  0000007A | LATIN SMALL LETTER Z
     C0 |  0000007B | LEFT CURLY BRACKET
     C1 |  00000041 | LATIN CAPITAL LETTER A
     C2 |  00000042 | LATIN CAPITAL LETTER B
     C3 |  00000043 | LATIN CAPITAL LETTER C
     C4 |  00000044 | LATIN CAPITAL LETTER D
     C5 |  00000045 | LATIN CAPITAL LETTER E
     C6 |  00000046 | LATIN CAPITAL LETTER F
     C7 |  00000047 | LATIN CAPITAL LETTER G
     C8 |  00000048 | LATIN CAPITAL LETTER H
     C9 |  00000049 | LATIN CAPITAL LETTER I
     D0 |  0000007D | RIGHT CURLY BRACKET
     D1 |  0000004A | LATIN CAPITAL LETTER J
     D2 |  0000004B | LATIN CAPITAL LETTER K
     D3 |  0000004C | LATIN CAPITAL LETTER L
     D4 |  0000004D | LATIN CAPITAL LETTER M
     D5 |  0000004E | LATIN CAPITAL LETTER N
     D6 |  0000004F | LATIN CAPITAL LETTER O
     D7 |  00000050 | LATIN CAPITAL LETTER P
     D8 |  00000051 | LATIN CAPITAL LETTER Q
     D9 |  00000052 | LATIN CAPITAL LETTER R
     E0 |  0000005C | REVERSE SOLIDUS
     E2 |  00000053 | LATIN CAPITAL LETTER S
     E3 |  00000054 | LATIN CAPITAL LETTER T
     E4 |  00000055 | LATIN CAPITAL LETTER U
     E5 |  00000056 | LATIN CAPITAL LETTER V
     E6 |  00000057 | LATIN CAPITAL LETTER W
     E7 |  00000058 | LATIN CAPITAL LETTER X
     E8 |  00000059 | LATIN CAPITAL LETTER Y
     E9 |  0000005A | LATIN CAPITAL LETTER Z
     F0 |  00000030 | DIGIT ZERO
     F1 |  00000031 | DIGIT ONE
     F2 |  00000032 | DIGIT TWO
     F3 |  00000033 | DIGIT THREE
     F4 |  00000034 | DIGIT FOUR
     F5 |  00000035 | DIGIT FIVE
     F6 |  00000036 | DIGIT SIX
     F7 |  00000037 | DIGIT SEVEN
     F8 |  00000038 | DIGIT EIGHT
     F9 |  00000039 | DIGIT NINE
     FF |  0000009F | APPLICATION PROGRAM COMMAND (APC)
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/EBCDIC_US.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for EBCDIC-US.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::EBCDIC_US;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x009c,
     0x0009,
     0x0086,
     0x007f,
     0x0097,
     0x008d,
     0x008e,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x009d,
     0x0085,
     0x0008,
     0x0087,
     0x0018,
     0x0019,
     0x0092,
     0x008f,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0080,
     0x0081,
     0x0082,
     0x0083,
     0x0084,
     0x000a,
     0x0017,
     0x001b,
     0x0088,
     0x0089,
     0x008a,
     0x008b,
     0x008c,
     0x0005,
     0x0006,
     0x0007,
     0x0090,
     0x0091,
     0x0016,
     0x0093,
     0x0094,
     0x0095,
     0x0096,
     0x0004,
     0x0098,
     0x0099,
     0x009a,
     0x009b,
     0x0014,
     0x0015,
     0x009e,
     0x001a,
     0x0020,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00a2,
     0x002e,
     0x003c,
     0x0028,
     0x002b,
     0x007c,
     0x0026,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x0021,
     0x0024,
     0x002a,
     0x0029,
     0x003b,
     0x00ac,
     0x002d,
     0x002f,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00a6,
     0x002c,
     0x0025,
     0x005f,
     0x003e,
     0x003f,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x0060,
     0x003a,
     0x0023,
     0x0040,
     0x0027,
     0x003d,
     0x0022,
     0xfffd,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x007e,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x007b,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x007d,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x005c,
     0xfffd,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x009f,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\xc2\x9c",
     "\x09",
     "\xc2\x86",
     "\x7f",
     "\xc2\x97",
     "\xc2\x8d",
     "\xc2\x8e",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\xc2\x9d",
     "\xc2\x85",
     "\x08",
     "\xc2\x87",
     "\x18",
     "\x19",
     "\xc2\x92",
     "\xc2\x8f",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\xc2\x80",
     "\xc2\x81",
     "\xc2\x82",
     "\xc2\x83",
     "\xc2\x84",
     "\x0a",
     "\x17",
     "\x1b",
     "\xc2\x88",
     "\xc2\x89",
     "\xc2\x8a",
     "\xc2\x8b",
     "\xc2\x8c",
     "\x05",
     "\x06",
     "\x07",
     "\xc2\x90",
     "\xc2\x91",
     "\x16",
     "\xc2\x93",
     "\xc2\x94",
     "\xc2\x95",
     "\xc2\x96",
     "\x04",
     "\xc2\x98",
     "\xc2\x99",
     "\xc2\x9a",
     "\xc2\x9b",
     "\x14",
     "\x15",
     "\xc2\x9e",
     "\x1a",
     "\x20",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc2\xa2",
     "\x2e",
     "\x3c",
     "\x28",
     "\x2b",
     "\x7c",
     "\x26",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x21",
     "\x24",
     "\x2a",
     "\x29",
     "\x3b",
     "\xc2\xac",
     "\x2d",
     "\x2f",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc2\xa6",
     "\x2c",
     "\x25",
     "\x5f",
     "\x3e",
     "\x3f",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x60",
     "\x3a",
     "\x23",
     "\x40",
     "\x27",
     "\x3d",
     "\x22",
     "\xef\xbf\xbd",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x7e",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x7b",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x7d",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x5c",
     "\xef\xbf\xbd",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc2\x9f",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x37",
     0x00000005 => "\x2d",
     0x00000006 => "\x2e",
     0x00000007 => "\x2f",
     0x00000008 => "\x16",
     0x00000009 => "\x05",
     0x0000000a => "\x25",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x3c",
     0x00000015 => "\x3d",
     0x00000016 => "\x32",
     0x00000017 => "\x26",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x3f",
     0x0000001b => "\x27",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x40",
     0x00000021 => "\x5a",
     0x00000022 => "\x7f",
     0x00000023 => "\x7b",
     0x00000024 => "\x5b",
     0x00000025 => "\x6c",
     0x00000026 => "\x50",
     0x00000027 => "\x7d",
     0x00000028 => "\x4d",
     0x00000029 => "\x5d",
     0x0000002a => "\x5c",
     0x0000002b => "\x4e",
     0x0000002c => "\x6b",
     0x0000002d => "\x60",
     0x0000002e => "\x4b",
     0x0000002f => "\x61",
     0x00000030 => "\xf0",
     0x00000031 => "\xf1",
     0x00000032 => "\xf2",
     0x00000033 => "\xf3",
     0x00000034 => "\xf4",
     0x00000035 => "\xf5",
     0x00000036 => "\xf6",
     0x00000037 => "\xf7",
     0x00000038 => "\xf8",
     0x00000039 => "\xf9",
     0x0000003a => "\x7a",
     0x0000003b => "\x5e",
     0x0000003c => "\x4c",
     0x0000003d => "\x7e",
     0x0000003e => "\x6e",
     0x0000003f => "\x6f",
     0x00000040 => "\x7c",
     0x00000041 => "\xc1",
     0x00000042 => "\xc2",
     0x00000043 => "\xc3",
     0x00000044 => "\xc4",
     0x00000045 => "\xc5",
     0x00000046 => "\xc6",
     0x00000047 => "\xc7",
     0x00000048 => "\xc8",
     0x00000049 => "\xc9",
     0x0000004a => "\xd1",
     0x0000004b => "\xd2",
     0x0000004c => "\xd3",
     0x0000004d => "\xd4",
     0x0000004e => "\xd5",
     0x0000004f => "\xd6",
     0x00000050 => "\xd7",
     0x00000051 => "\xd8",
     0x00000052 => "\xd9",
     0x00000053 => "\xe2",
     0x00000054 => "\xe3",
     0x00000055 => "\xe4",
     0x00000056 => "\xe5",
     0x00000057 => "\xe6",
     0x00000058 => "\xe7",
     0x00000059 => "\xe8",
     0x0000005a => "\xe9",
     0x0000005c => "\xe0",
     0x0000005f => "\x6d",
     0x00000060 => "\x79",
     0x00000061 => "\x81",
     0x00000062 => "\x82",
     0x00000063 => "\x83",
     0x00000064 => "\x84",
     0x00000065 => "\x85",
     0x00000066 => "\x86",
     0x00000067 => "\x87",
     0x00000068 => "\x88",
     0x00000069 => "\x89",
     0x0000006a => "\x91",
     0x0000006b => "\x92",
     0x0000006c => "\x93",
     0x0000006d => "\x94",
     0x0000006e => "\x95",
     0x0000006f => "\x96",
     0x00000070 => "\x97",
     0x00000071 => "\x98",
     0x00000072 => "\x99",
     0x00000073 => "\xa2",
     0x00000074 => "\xa3",
     0x00000075 => "\xa4",
     0x00000076 => "\xa5",
     0x00000077 => "\xa6",
     0x00000078 => "\xa7",
     0x00000079 => "\xa8",
     0x0000007a => "\xa9",
     0x0000007b => "\xc0",
     0x0000007c => "\x4f",
     0x0000007d => "\xd0",
     0x0000007e => "\xa1",
     0x0000007f => "\x07",
     0x00000080 => "\x20",
     0x00000081 => "\x21",
     0x00000082 => "\x22",
     0x00000083 => "\x23",
     0x00000084 => "\x24",
     0x00000085 => "\x15",
     0x00000086 => "\x06",
     0x00000087 => "\x17",
     0x00000088 => "\x28",
     0x00000089 => "\x29",
     0x0000008a => "\x2a",
     0x0000008b => "\x2b",
     0x0000008c => "\x2c",
     0x0000008d => "\x09",
     0x0000008e => "\x0a",
     0x0000008f => "\x1b",
     0x00000090 => "\x30",
     0x00000091 => "\x31",
     0x00000092 => "\x1a",
     0x00000093 => "\x33",
     0x00000094 => "\x34",
     0x00000095 => "\x35",
     0x00000096 => "\x36",
     0x00000097 => "\x08",
     0x00000098 => "\x38",
     0x00000099 => "\x39",
     0x0000009a => "\x3a",
     0x0000009b => "\x3b",
     0x0000009c => "\x04",
     0x0000009d => "\x14",
     0x0000009e => "\x3e",
     0x0000009f => "\xff",
     0x000000a2 => "\x4a",
     0x000000a6 => "\x6a",
     0x000000ac => "\x5f",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::EBCDIC_US - Conversion routines for EBCDIC_US
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for EBCDIC-US.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
   source: IBM 3270 Char Set Ref Ch 10, GA27-2837-9, April 1987
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  0000009C | STRING TERMINATOR (ST)
     05 |  00000009 | CHARACTER TABULATION (HT)
     06 |  00000086 | START OF SELECTED AREA (SSA)
     07 |  0000007F | DELETE (DEL)
     08 |  00000097 | END OF GUARDED AREA (EPA)
     09 |  0000008D | REVERSE LINE FEED (RI)
     0A |  0000008E | SINGLE-SHIFT TWO (SS2)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  0000009D | OPERATING SYSTEM COMMAND (OSC)
     15 |  00000085 | NEXT LINE (NEL)
     16 |  00000008 | BACKSPACE (BS)
     17 |  00000087 | END OF SELECTED AREA (ESA)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  00000092 | PRIVATE USE TWO (PU2)
     1B |  0000008F | SINGLE-SHIFT THREE (SS3)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000080 | PADDING CHARACTER (PAD)
     21 |  00000081 | HIGH OCTET PRESET (HOP)
     22 |  00000082 | BREAK PERMITTED HERE (BPH)
     23 |  00000083 | NO BREAK HERE (NBH)
     24 |  00000084 | INDEX (IND)
     25 |  0000000A | LINE FEED (LF)
     26 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     27 |  0000001B | ESCAPE (ESC)
     28 |  00000088 | CHARACTER TABULATION SET (HTS)
     29 |  00000089 | CHARACTER TABULATION WITH JUSTIFICATION (HTJ)
     2A |  0000008A | LINE TABULATION SET (VTS)
     2B |  0000008B | PARTIAL LINE FORWARD (PLD)
     2C |  0000008C | PARTIAL LINE BACKWARD (PLU)
     2D |  00000005 | ENQUIRY (ENQ)
     2E |  00000006 | ACKNOWLEDGE (ACK)
     2F |  00000007 | BELL (BEL)
     30 |  00000090 | DEVICE CONTROL STRING (DCS)
     31 |  00000091 | PRIVATE USE ONE (PU1)
     32 |  00000016 | SYNCHRONOUS IDLE (SYN)
     33 |  00000093 | SET TRANSMIT STATE (STS)
     34 |  00000094 | CANCEL CHARACTER (CCH)
     35 |  00000095 | MESSAGE WAITING (MW)
     36 |  00000096 | START OF GUARDED AREA (SPA)
     37 |  00000004 | END OF TRANSMISSION (EOT)
     38 |  00000098 | START OF STRING (SOS)
     39 |  00000099 | SINGLE GRAPHIC CHARACTER INTRODUCER (SGCI)
     3A |  0000009A | SINGLE CHARACTER INTRODUCER (SCI)
     3B |  0000009B | CONTROL SEQUENCE INTRODUCER (CSI)
     3C |  00000014 | DEVICE CONTROL FOUR (DC4)
     3D |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     3E |  0000009E | PRIVACY MESSAGE (PM)
     3F |  0000001A | SUBSTITUTE (SUB)
     40 |  00000020 | SPACE
     4A |  000000A2 | CENT SIGN
     4B |  0000002E | FULL STOP
     4C |  0000003C | LESS-THAN SIGN
     4D |  00000028 | LEFT PARENTHESIS
     4E |  0000002B | PLUS SIGN
     4F |  0000007C | VERTICAL LINE
     50 |  00000026 | AMPERSAND
     5A |  00000021 | EXCLAMATION MARK
     5B |  00000024 | DOLLAR SIGN
     5C |  0000002A | ASTERISK
     5D |  00000029 | RIGHT PARENTHESIS
     5E |  0000003B | SEMICOLON
     5F |  000000AC | NOT SIGN
     60 |  0000002D | HYPHEN-MINUS
     61 |  0000002F | SOLIDUS
     6A |  000000A6 | BROKEN BAR
     6B |  0000002C | COMMA
     6C |  00000025 | PERCENT SIGN
     6D |  0000005F | LOW LINE
     6E |  0000003E | GREATER-THAN SIGN
     6F |  0000003F | QUESTION MARK
     79 |  00000060 | GRAVE ACCENT
     7A |  0000003A | COLON
     7B |  00000023 | NUMBER SIGN
     7C |  00000040 | COMMERCIAL AT
     7D |  00000027 | APOSTROPHE
     7E |  0000003D | EQUALS SIGN
     7F |  00000022 | QUOTATION MARK
     81 |  00000061 | LATIN SMALL LETTER A
     82 |  00000062 | LATIN SMALL LETTER B
     83 |  00000063 | LATIN SMALL LETTER C
     84 |  00000064 | LATIN SMALL LETTER D
     85 |  00000065 | LATIN SMALL LETTER E
     86 |  00000066 | LATIN SMALL LETTER F
     87 |  00000067 | LATIN SMALL LETTER G
     88 |  00000068 | LATIN SMALL LETTER H
     89 |  00000069 | LATIN SMALL LETTER I
     91 |  0000006A | LATIN SMALL LETTER J
     92 |  0000006B | LATIN SMALL LETTER K
     93 |  0000006C | LATIN SMALL LETTER L
     94 |  0000006D | LATIN SMALL LETTER M
     95 |  0000006E | LATIN SMALL LETTER N
     96 |  0000006F | LATIN SMALL LETTER O
     97 |  00000070 | LATIN SMALL LETTER P
     98 |  00000071 | LATIN SMALL LETTER Q
     99 |  00000072 | LATIN SMALL LETTER R
     A1 |  0000007E | TILDE
     A2 |  00000073 | LATIN SMALL LETTER S
     A3 |  00000074 | LATIN SMALL LETTER T
     A4 |  00000075 | LATIN SMALL LETTER U
     A5 |  00000076 | LATIN SMALL LETTER V
     A6 |  00000077 | LATIN SMALL LETTER W
     A7 |  00000078 | LATIN SMALL LETTER X
     A8 |  00000079 | LATIN SMALL LETTER Y
     A9 |  0000007A | LATIN SMALL LETTER Z
     C0 |  0000007B | LEFT CURLY BRACKET
     C1 |  00000041 | LATIN CAPITAL LETTER A
     C2 |  00000042 | LATIN CAPITAL LETTER B
     C3 |  00000043 | LATIN CAPITAL LETTER C
     C4 |  00000044 | LATIN CAPITAL LETTER D
     C5 |  00000045 | LATIN CAPITAL LETTER E
     C6 |  00000046 | LATIN CAPITAL LETTER F
     C7 |  00000047 | LATIN CAPITAL LETTER G
     C8 |  00000048 | LATIN CAPITAL LETTER H
     C9 |  00000049 | LATIN CAPITAL LETTER I
     D0 |  0000007D | RIGHT CURLY BRACKET
     D1 |  0000004A | LATIN CAPITAL LETTER J
     D2 |  0000004B | LATIN CAPITAL LETTER K
     D3 |  0000004C | LATIN CAPITAL LETTER L
     D4 |  0000004D | LATIN CAPITAL LETTER M
     D5 |  0000004E | LATIN CAPITAL LETTER N
     D6 |  0000004F | LATIN CAPITAL LETTER O
     D7 |  00000050 | LATIN CAPITAL LETTER P
     D8 |  00000051 | LATIN CAPITAL LETTER Q
     D9 |  00000052 | LATIN CAPITAL LETTER R
     E0 |  0000005C | REVERSE SOLIDUS
     E2 |  00000053 | LATIN CAPITAL LETTER S
     E3 |  00000054 | LATIN CAPITAL LETTER T
     E4 |  00000055 | LATIN CAPITAL LETTER U
     E5 |  00000056 | LATIN CAPITAL LETTER V
     E6 |  00000057 | LATIN CAPITAL LETTER W
     E7 |  00000058 | LATIN CAPITAL LETTER X
     E8 |  00000059 | LATIN CAPITAL LETTER Y
     E9 |  0000005A | LATIN CAPITAL LETTER Z
     F0 |  00000030 | DIGIT ZERO
     F1 |  00000031 | DIGIT ONE
     F2 |  00000032 | DIGIT TWO
     F3 |  00000033 | DIGIT THREE
     F4 |  00000034 | DIGIT FOUR
     F5 |  00000035 | DIGIT FIVE
     F6 |  00000036 | DIGIT SIX
     F7 |  00000037 | DIGIT SEVEN
     F8 |  00000038 | DIGIT EIGHT
     F9 |  00000039 | DIGIT NINE
     FF |  0000009F | APPLICATION PROGRAM COMMAND (APC)
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/ECMA_CYRILLIC.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for ECMA-CYRILLIC.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::ECMA_CYRILLIC;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x0004,
     0x0005,
     0x0006,
     0x0007,
     0x0008,
     0x0009,
     0x000a,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x0014,
     0x0015,
     0x0016,
     0x0017,
     0x0018,
     0x0019,
     0x001a,
     0x001b,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0020,
     0x0021,
     0x0022,
     0x0023,
     0x0024,
     0x0025,
     0x0026,
     0x0027,
     0x0028,
     0x0029,
     0x002a,
     0x002b,
     0x002c,
     0x002d,
     0x002e,
     0x002f,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x003a,
     0x003b,
     0x003c,
     0x003d,
     0x003e,
     0x003f,
     0x0040,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x005b,
     0x005c,
     0x005d,
     0x005e,
     0x005f,
     0x0060,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x007b,
     0x007c,
     0x007d,
     0x007e,
     0x007f,
     0x0080,
     0x0081,
     0x0082,
     0x0083,
     0x0084,
     0x0085,
     0x0086,
     0x0087,
     0x0088,
     0x0089,
     0x008a,
     0x008b,
     0x008c,
     0x008d,
     0x008e,
     0x008f,
     0x0090,
     0x0091,
     0x0092,
     0x0093,
     0x0094,
     0x0095,
     0x0096,
     0x0097,
     0x0098,
     0x0099,
     0x009a,
     0x009b,
     0x009c,
     0x009d,
     0x009e,
     0x009f,
     0x00a0,
     0x0452,
     0x0453,
     0x0451,
     0x0454,
     0x0455,
     0x0456,
     0x0457,
     0x0458,
     0x0459,
     0x045a,
     0x045b,
     0x045c,
     0x00ad,
     0x045e,
     0x045f,
     0x2116,
     0x0402,
     0x0403,
     0x0401,
     0x0404,
     0x0405,
     0x0406,
     0x0407,
     0x0408,
     0x0409,
     0x040a,
     0x040b,
     0x040c,
     0x00a4,
     0x040e,
     0x040f,
     0x044e,
     0x0430,
     0x0431,
     0x0446,
     0x0434,
     0x0435,
     0x0444,
     0x0433,
     0x0445,
     0x0438,
     0x0439,
     0x043a,
     0x043b,
     0x043c,
     0x043d,
     0x043e,
     0x043f,
     0x044f,
     0x0440,
     0x0441,
     0x0442,
     0x0443,
     0x0436,
     0x0432,
     0x044c,
     0x044b,
     0x0437,
     0x0448,
     0x044d,
     0x0449,
     0x0447,
     0x044a,
     0x042e,
     0x0410,
     0x0411,
     0x0426,
     0x0414,
     0x0415,
     0x0424,
     0x0413,
     0x0425,
     0x0418,
     0x0419,
     0x041a,
     0x041b,
     0x041c,
     0x041d,
     0x041e,
     0x041f,
     0x042f,
     0x0420,
     0x0421,
     0x0422,
     0x0423,
     0x0416,
     0x0412,
     0x042c,
     0x042b,
     0x0417,
     0x0428,
     0x042d,
     0x0429,
     0x0427,
     0x042a,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\x04",
     "\x05",
     "\x06",
     "\x07",
     "\x08",
     "\x09",
     "\x0a",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\x14",
     "\x15",
     "\x16",
     "\x17",
     "\x18",
     "\x19",
     "\x1a",
     "\x1b",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\x20",
     "\x21",
     "\x22",
     "\x23",
     "\x24",
     "\x25",
     "\x26",
     "\x27",
     "\x28",
     "\x29",
     "\x2a",
     "\x2b",
     "\x2c",
     "\x2d",
     "\x2e",
     "\x2f",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\x3a",
     "\x3b",
     "\x3c",
     "\x3d",
     "\x3e",
     "\x3f",
     "\x40",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\x5b",
     "\x5c",
     "\x5d",
     "\x5e",
     "\x5f",
     "\x60",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\x7b",
     "\x7c",
     "\x7d",
     "\x7e",
     "\x7f",
     "\xc2\x80",
     "\xc2\x81",
     "\xc2\x82",
     "\xc2\x83",
     "\xc2\x84",
     "\xc2\x85",
     "\xc2\x86",
     "\xc2\x87",
     "\xc2\x88",
     "\xc2\x89",
     "\xc2\x8a",
     "\xc2\x8b",
     "\xc2\x8c",
     "\xc2\x8d",
     "\xc2\x8e",
     "\xc2\x8f",
     "\xc2\x90",
     "\xc2\x91",
     "\xc2\x92",
     "\xc2\x93",
     "\xc2\x94",
     "\xc2\x95",
     "\xc2\x96",
     "\xc2\x97",
     "\xc2\x98",
     "\xc2\x99",
     "\xc2\x9a",
     "\xc2\x9b",
     "\xc2\x9c",
     "\xc2\x9d",
     "\xc2\x9e",
     "\xc2\x9f",
     "\xc2\xa0",
     "\xd1\x92",
     "\xd1\x93",
     "\xd1\x91",
     "\xd1\x94",
     "\xd1\x95",
     "\xd1\x96",
     "\xd1\x97",
     "\xd1\x98",
     "\xd1\x99",
     "\xd1\x9a",
     "\xd1\x9b",
     "\xd1\x9c",
     "\xc2\xad",
     "\xd1\x9e",
     "\xd1\x9f",
     "\xe2\x84\x96",
     "\xd0\x82",
     "\xd0\x83",
     "\xd0\x81",
     "\xd0\x84",
     "\xd0\x85",
     "\xd0\x86",
     "\xd0\x87",
     "\xd0\x88",
     "\xd0\x89",
     "\xd0\x8a",
     "\xd0\x8b",
     "\xd0\x8c",
     "\xc2\xa4",
     "\xd0\x8e",
     "\xd0\x8f",
     "\xd1\x8e",
     "\xd0\xb0",
     "\xd0\xb1",
     "\xd1\x86",
     "\xd0\xb4",
     "\xd0\xb5",
     "\xd1\x84",
     "\xd0\xb3",
     "\xd1\x85",
     "\xd0\xb8",
     "\xd0\xb9",
     "\xd0\xba",
     "\xd0\xbb",
     "\xd0\xbc",
     "\xd0\xbd",
     "\xd0\xbe",
     "\xd0\xbf",
     "\xd1\x8f",
     "\xd1\x80",
     "\xd1\x81",
     "\xd1\x82",
     "\xd1\x83",
     "\xd0\xb6",
     "\xd0\xb2",
     "\xd1\x8c",
     "\xd1\x8b",
     "\xd0\xb7",
     "\xd1\x88",
     "\xd1\x8d",
     "\xd1\x89",
     "\xd1\x87",
     "\xd1\x8a",
     "\xd0\xae",
     "\xd0\x90",
     "\xd0\x91",
     "\xd0\xa6",
     "\xd0\x94",
     "\xd0\x95",
     "\xd0\xa4",
     "\xd0\x93",
     "\xd0\xa5",
     "\xd0\x98",
     "\xd0\x99",
     "\xd0\x9a",
     "\xd0\x9b",
     "\xd0\x9c",
     "\xd0\x9d",
     "\xd0\x9e",
     "\xd0\x9f",
     "\xd0\xaf",
     "\xd0\xa0",
     "\xd0\xa1",
     "\xd0\xa2",
     "\xd0\xa3",
     "\xd0\x96",
     "\xd0\x92",
     "\xd0\xac",
     "\xd0\xab",
     "\xd0\x97",
     "\xd0\xa8",
     "\xd0\xad",
     "\xd0\xa9",
     "\xd0\xa7",
     "\xd0\xaa",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x04",
     0x00000005 => "\x05",
     0x00000006 => "\x06",
     0x00000007 => "\x07",
     0x00000008 => "\x08",
     0x00000009 => "\x09",
     0x0000000a => "\x0a",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x14",
     0x00000015 => "\x15",
     0x00000016 => "\x16",
     0x00000017 => "\x17",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x1a",
     0x0000001b => "\x1b",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x20",
     0x00000021 => "\x21",
     0x00000022 => "\x22",
     0x00000023 => "\x23",
     0x00000024 => "\x24",
     0x00000025 => "\x25",
     0x00000026 => "\x26",
     0x00000027 => "\x27",
     0x00000028 => "\x28",
     0x00000029 => "\x29",
     0x0000002a => "\x2a",
     0x0000002b => "\x2b",
     0x0000002c => "\x2c",
     0x0000002d => "\x2d",
     0x0000002e => "\x2e",
     0x0000002f => "\x2f",
     0x00000030 => "\x30",
     0x00000031 => "\x31",
     0x00000032 => "\x32",
     0x00000033 => "\x33",
     0x00000034 => "\x34",
     0x00000035 => "\x35",
     0x00000036 => "\x36",
     0x00000037 => "\x37",
     0x00000038 => "\x38",
     0x00000039 => "\x39",
     0x0000003a => "\x3a",
     0x0000003b => "\x3b",
     0x0000003c => "\x3c",
     0x0000003d => "\x3d",
     0x0000003e => "\x3e",
     0x0000003f => "\x3f",
     0x00000040 => "\x40",
     0x00000041 => "\x41",
     0x00000042 => "\x42",
     0x00000043 => "\x43",
     0x00000044 => "\x44",
     0x00000045 => "\x45",
     0x00000046 => "\x46",
     0x00000047 => "\x47",
     0x00000048 => "\x48",
     0x00000049 => "\x49",
     0x0000004a => "\x4a",
     0x0000004b => "\x4b",
     0x0000004c => "\x4c",
     0x0000004d => "\x4d",
     0x0000004e => "\x4e",
     0x0000004f => "\x4f",
     0x00000050 => "\x50",
     0x00000051 => "\x51",
     0x00000052 => "\x52",
     0x00000053 => "\x53",
     0x00000054 => "\x54",
     0x00000055 => "\x55",
     0x00000056 => "\x56",
     0x00000057 => "\x57",
     0x00000058 => "\x58",
     0x00000059 => "\x59",
     0x0000005a => "\x5a",
     0x0000005b => "\x5b",
     0x0000005c => "\x5c",
     0x0000005d => "\x5d",
     0x0000005e => "\x5e",
     0x0000005f => "\x5f",
     0x00000060 => "\x60",
     0x00000061 => "\x61",
     0x00000062 => "\x62",
     0x00000063 => "\x63",
     0x00000064 => "\x64",
     0x00000065 => "\x65",
     0x00000066 => "\x66",
     0x00000067 => "\x67",
     0x00000068 => "\x68",
     0x00000069 => "\x69",
     0x0000006a => "\x6a",
     0x0000006b => "\x6b",
     0x0000006c => "\x6c",
     0x0000006d => "\x6d",
     0x0000006e => "\x6e",
     0x0000006f => "\x6f",
     0x00000070 => "\x70",
     0x00000071 => "\x71",
     0x00000072 => "\x72",
     0x00000073 => "\x73",
     0x00000074 => "\x74",
     0x00000075 => "\x75",
     0x00000076 => "\x76",
     0x00000077 => "\x77",
     0x00000078 => "\x78",
     0x00000079 => "\x79",
     0x0000007a => "\x7a",
     0x0000007b => "\x7b",
     0x0000007c => "\x7c",
     0x0000007d => "\x7d",
     0x0000007e => "\x7e",
     0x0000007f => "\x7f",
     0x00000080 => "\x80",
     0x00000081 => "\x81",
     0x00000082 => "\x82",
     0x00000083 => "\x83",
     0x00000084 => "\x84",
     0x00000085 => "\x85",
     0x00000086 => "\x86",
     0x00000087 => "\x87",
     0x00000088 => "\x88",
     0x00000089 => "\x89",
     0x0000008a => "\x8a",
     0x0000008b => "\x8b",
     0x0000008c => "\x8c",
     0x0000008d => "\x8d",
     0x0000008e => "\x8e",
     0x0000008f => "\x8f",
     0x00000090 => "\x90",
     0x00000091 => "\x91",
     0x00000092 => "\x92",
     0x00000093 => "\x93",
     0x00000094 => "\x94",
     0x00000095 => "\x95",
     0x00000096 => "\x96",
     0x00000097 => "\x97",
     0x00000098 => "\x98",
     0x00000099 => "\x99",
     0x0000009a => "\x9a",
     0x0000009b => "\x9b",
     0x0000009c => "\x9c",
     0x0000009d => "\x9d",
     0x0000009e => "\x9e",
     0x0000009f => "\x9f",
     0x000000a0 => "\xa0",
     0x000000a4 => "\xbd",
     0x000000ad => "\xad",
     0x00000401 => "\xb3",
     0x00000402 => "\xb1",
     0x00000403 => "\xb2",
     0x00000404 => "\xb4",
     0x00000405 => "\xb5",
     0x00000406 => "\xb6",
     0x00000407 => "\xb7",
     0x00000408 => "\xb8",
     0x00000409 => "\xb9",
     0x0000040a => "\xba",
     0x0000040b => "\xbb",
     0x0000040c => "\xbc",
     0x0000040e => "\xbe",
     0x0000040f => "\xbf",
     0x00000410 => "\xe1",
     0x00000411 => "\xe2",
     0x00000412 => "\xf7",
     0x00000413 => "\xe7",
     0x00000414 => "\xe4",
     0x00000415 => "\xe5",
     0x00000416 => "\xf6",
     0x00000417 => "\xfa",
     0x00000418 => "\xe9",
     0x00000419 => "\xea",
     0x0000041a => "\xeb",
     0x0000041b => "\xec",
     0x0000041c => "\xed",
     0x0000041d => "\xee",
     0x0000041e => "\xef",
     0x0000041f => "\xf0",
     0x00000420 => "\xf2",
     0x00000421 => "\xf3",
     0x00000422 => "\xf4",
     0x00000423 => "\xf5",
     0x00000424 => "\xe6",
     0x00000425 => "\xe8",
     0x00000426 => "\xe3",
     0x00000427 => "\xfe",
     0x00000428 => "\xfb",
     0x00000429 => "\xfd",
     0x0000042a => "\xff",
     0x0000042b => "\xf9",
     0x0000042c => "\xf8",
     0x0000042d => "\xfc",
     0x0000042e => "\xe0",
     0x0000042f => "\xf1",
     0x00000430 => "\xc1",
     0x00000431 => "\xc2",
     0x00000432 => "\xd7",
     0x00000433 => "\xc7",
     0x00000434 => "\xc4",
     0x00000435 => "\xc5",
     0x00000436 => "\xd6",
     0x00000437 => "\xda",
     0x00000438 => "\xc9",
     0x00000439 => "\xca",
     0x0000043a => "\xcb",
     0x0000043b => "\xcc",
     0x0000043c => "\xcd",
     0x0000043d => "\xce",
     0x0000043e => "\xcf",
     0x0000043f => "\xd0",
     0x00000440 => "\xd2",
     0x00000441 => "\xd3",
     0x00000442 => "\xd4",
     0x00000443 => "\xd5",
     0x00000444 => "\xc6",
     0x00000445 => "\xc8",
     0x00000446 => "\xc3",
     0x00000447 => "\xde",
     0x00000448 => "\xdb",
     0x00000449 => "\xdd",
     0x0000044a => "\xdf",
     0x0000044b => "\xd9",
     0x0000044c => "\xd8",
     0x0000044d => "\xdc",
     0x0000044e => "\xc0",
     0x0000044f => "\xd1",
     0x00000451 => "\xa3",
     0x00000452 => "\xa1",
     0x00000453 => "\xa2",
     0x00000454 => "\xa4",
     0x00000455 => "\xa5",
     0x00000456 => "\xa6",
     0x00000457 => "\xa7",
     0x00000458 => "\xa8",
     0x00000459 => "\xa9",
     0x0000045a => "\xaa",
     0x0000045b => "\xab",
     0x0000045c => "\xac",
     0x0000045e => "\xae",
     0x0000045f => "\xaf",
     0x00002116 => "\xb0",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::ECMA_CYRILLIC - Conversion routines for ECMA_CYRILLIC
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for ECMA-CYRILLIC.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
   source: ECMA registry
  alias ISO-IR-111
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  00000004 | END OF TRANSMISSION (EOT)
     05 |  00000005 | ENQUIRY (ENQ)
     06 |  00000006 | ACKNOWLEDGE (ACK)
     07 |  00000007 | BELL (BEL)
     08 |  00000008 | BACKSPACE (BS)
     09 |  00000009 | CHARACTER TABULATION (HT)
     0A |  0000000A | LINE FEED (LF)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  00000014 | DEVICE CONTROL FOUR (DC4)
     15 |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     16 |  00000016 | SYNCHRONOUS IDLE (SYN)
     17 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  0000001A | SUBSTITUTE (SUB)
     1B |  0000001B | ESCAPE (ESC)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000020 | SPACE
     21 |  00000021 | EXCLAMATION MARK
     22 |  00000022 | QUOTATION MARK
     23 |  00000023 | NUMBER SIGN
     24 |  00000024 | DOLLAR SIGN
     25 |  00000025 | PERCENT SIGN
     26 |  00000026 | AMPERSAND
     27 |  00000027 | APOSTROPHE
     28 |  00000028 | LEFT PARENTHESIS
     29 |  00000029 | RIGHT PARENTHESIS
     2A |  0000002A | ASTERISK
     2B |  0000002B | PLUS SIGN
     2C |  0000002C | COMMA
     2D |  0000002D | HYPHEN-MINUS
     2E |  0000002E | FULL STOP
     2F |  0000002F | SOLIDUS
     30 |  00000030 | DIGIT ZERO
     31 |  00000031 | DIGIT ONE
     32 |  00000032 | DIGIT TWO
     33 |  00000033 | DIGIT THREE
     34 |  00000034 | DIGIT FOUR
     35 |  00000035 | DIGIT FIVE
     36 |  00000036 | DIGIT SIX
     37 |  00000037 | DIGIT SEVEN
     38 |  00000038 | DIGIT EIGHT
     39 |  00000039 | DIGIT NINE
     3A |  0000003A | COLON
     3B |  0000003B | SEMICOLON
     3C |  0000003C | LESS-THAN SIGN
     3D |  0000003D | EQUALS SIGN
     3E |  0000003E | GREATER-THAN SIGN
     3F |  0000003F | QUESTION MARK
     40 |  00000040 | COMMERCIAL AT
     41 |  00000041 | LATIN CAPITAL LETTER A
     42 |  00000042 | LATIN CAPITAL LETTER B
     43 |  00000043 | LATIN CAPITAL LETTER C
     44 |  00000044 | LATIN CAPITAL LETTER D
     45 |  00000045 | LATIN CAPITAL LETTER E
     46 |  00000046 | LATIN CAPITAL LETTER F
     47 |  00000047 | LATIN CAPITAL LETTER G
     48 |  00000048 | LATIN CAPITAL LETTER H
     49 |  00000049 | LATIN CAPITAL LETTER I
     4A |  0000004A | LATIN CAPITAL LETTER J
     4B |  0000004B | LATIN CAPITAL LETTER K
     4C |  0000004C | LATIN CAPITAL LETTER L
     4D |  0000004D | LATIN CAPITAL LETTER M
     4E |  0000004E | LATIN CAPITAL LETTER N
     4F |  0000004F | LATIN CAPITAL LETTER O
     50 |  00000050 | LATIN CAPITAL LETTER P
     51 |  00000051 | LATIN CAPITAL LETTER Q
     52 |  00000052 | LATIN CAPITAL LETTER R
     53 |  00000053 | LATIN CAPITAL LETTER S
     54 |  00000054 | LATIN CAPITAL LETTER T
     55 |  00000055 | LATIN CAPITAL LETTER U
     56 |  00000056 | LATIN CAPITAL LETTER V
     57 |  00000057 | LATIN CAPITAL LETTER W
     58 |  00000058 | LATIN CAPITAL LETTER X
     59 |  00000059 | LATIN CAPITAL LETTER Y
     5A |  0000005A | LATIN CAPITAL LETTER Z
     5B |  0000005B | LEFT SQUARE BRACKET
     5C |  0000005C | REVERSE SOLIDUS
     5D |  0000005D | RIGHT SQUARE BRACKET
     5E |  0000005E | CIRCUMFLEX ACCENT
     5F |  0000005F | LOW LINE
     60 |  00000060 | GRAVE ACCENT
     61 |  00000061 | LATIN SMALL LETTER A
     62 |  00000062 | LATIN SMALL LETTER B
     63 |  00000063 | LATIN SMALL LETTER C
     64 |  00000064 | LATIN SMALL LETTER D
     65 |  00000065 | LATIN SMALL LETTER E
     66 |  00000066 | LATIN SMALL LETTER F
     67 |  00000067 | LATIN SMALL LETTER G
     68 |  00000068 | LATIN SMALL LETTER H
     69 |  00000069 | LATIN SMALL LETTER I
     6A |  0000006A | LATIN SMALL LETTER J
     6B |  0000006B | LATIN SMALL LETTER K
     6C |  0000006C | LATIN SMALL LETTER L
     6D |  0000006D | LATIN SMALL LETTER M
     6E |  0000006E | LATIN SMALL LETTER N
     6F |  0000006F | LATIN SMALL LETTER O
     70 |  00000070 | LATIN SMALL LETTER P
     71 |  00000071 | LATIN SMALL LETTER Q
     72 |  00000072 | LATIN SMALL LETTER R
     73 |  00000073 | LATIN SMALL LETTER S
     74 |  00000074 | LATIN SMALL LETTER T
     75 |  00000075 | LATIN SMALL LETTER U
     76 |  00000076 | LATIN SMALL LETTER V
     77 |  00000077 | LATIN SMALL LETTER W
     78 |  00000078 | LATIN SMALL LETTER X
     79 |  00000079 | LATIN SMALL LETTER Y
     7A |  0000007A | LATIN SMALL LETTER Z
     7B |  0000007B | LEFT CURLY BRACKET
     7C |  0000007C | VERTICAL LINE
     7D |  0000007D | RIGHT CURLY BRACKET
     7E |  0000007E | TILDE
     7F |  0000007F | DELETE (DEL)
     80 |  00000080 | PADDING CHARACTER (PAD)
     81 |  00000081 | HIGH OCTET PRESET (HOP)
     82 |  00000082 | BREAK PERMITTED HERE (BPH)
     83 |  00000083 | NO BREAK HERE (NBH)
     84 |  00000084 | INDEX (IND)
     85 |  00000085 | NEXT LINE (NEL)
     86 |  00000086 | START OF SELECTED AREA (SSA)
     87 |  00000087 | END OF SELECTED AREA (ESA)
     88 |  00000088 | CHARACTER TABULATION SET (HTS)
     89 |  00000089 | CHARACTER TABULATION WITH JUSTIFICATION (HTJ)
     8A |  0000008A | LINE TABULATION SET (VTS)
     8B |  0000008B | PARTIAL LINE FORWARD (PLD)
     8C |  0000008C | PARTIAL LINE BACKWARD (PLU)
     8D |  0000008D | REVERSE LINE FEED (RI)
     8E |  0000008E | SINGLE-SHIFT TWO (SS2)
     8F |  0000008F | SINGLE-SHIFT THREE (SS3)
     90 |  00000090 | DEVICE CONTROL STRING (DCS)
     91 |  00000091 | PRIVATE USE ONE (PU1)
     92 |  00000092 | PRIVATE USE TWO (PU2)
     93 |  00000093 | SET TRANSMIT STATE (STS)
     94 |  00000094 | CANCEL CHARACTER (CCH)
     95 |  00000095 | MESSAGE WAITING (MW)
     96 |  00000096 | START OF GUARDED AREA (SPA)
     97 |  00000097 | END OF GUARDED AREA (EPA)
     98 |  00000098 | START OF STRING (SOS)
     99 |  00000099 | SINGLE GRAPHIC CHARACTER INTRODUCER (SGCI)
     9A |  0000009A | SINGLE CHARACTER INTRODUCER (SCI)
     9B |  0000009B | CONTROL SEQUENCE INTRODUCER (CSI)
     9C |  0000009C | STRING TERMINATOR (ST)
     9D |  0000009D | OPERATING SYSTEM COMMAND (OSC)
     9E |  0000009E | PRIVACY MESSAGE (PM)
     9F |  0000009F | APPLICATION PROGRAM COMMAND (APC)
     A0 |  000000A0 | NO-BREAK SPACE
     A1 |  00000452 | CYRILLIC SMALL LETTER DJE (Serbocroatian)
     A2 |  00000453 | CYRILLIC SMALL LETTER GJE
     A3 |  00000451 | CYRILLIC SMALL LETTER IO
     A4 |  00000454 | CYRILLIC SMALL LETTER UKRAINIAN IE
     A5 |  00000455 | CYRILLIC SMALL LETTER DZE
     A6 |  00000456 | CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I
     A7 |  00000457 | CYRILLIC SMALL LETTER YI (Ukrainian)
     A8 |  00000458 | CYRILLIC SMALL LETTER JE
     A9 |  00000459 | CYRILLIC SMALL LETTER LJE
     AA |  0000045A | CYRILLIC SMALL LETTER NJE
     AB |  0000045B | CYRILLIC SMALL LETTER TSHE (Serbocroatian)
     AC |  0000045C | CYRILLIC SMALL LETTER KJE
     AD |  000000AD | SOFT HYPHEN
     AE |  0000045E | CYRILLIC SMALL LETTER SHORT U (Byelorussian)
     AF |  0000045F | CYRILLIC SMALL LETTER DZHE
     B0 |  00002116 | NUMERO SIGN
     B1 |  00000402 | CYRILLIC CAPITAL LETTER DJE (Serbocroatian)
     B2 |  00000403 | CYRILLIC CAPITAL LETTER GJE
     B3 |  00000401 | CYRILLIC CAPITAL LETTER IO
     B4 |  00000404 | CYRILLIC CAPITAL LETTER UKRAINIAN IE
     B5 |  00000405 | CYRILLIC CAPITAL LETTER DZE
     B6 |  00000406 | CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I
     B7 |  00000407 | CYRILLIC CAPITAL LETTER YI (Ukrainian)
     B8 |  00000408 | CYRILLIC CAPITAL LETTER JE
     B9 |  00000409 | CYRILLIC CAPITAL LETTER LJE
     BA |  0000040A | CYRILLIC CAPITAL LETTER NJE
     BB |  0000040B | CYRILLIC CAPITAL LETTER TSHE (Serbocroatian)
     BC |  0000040C | CYRILLIC CAPITAL LETTER KJE
     BD |  000000A4 | CURRENCY SIGN
     BE |  0000040E | CYRILLIC CAPITAL LETTER SHORT U (Byelorussian)
     BF |  0000040F | CYRILLIC CAPITAL LETTER DZHE
     C0 |  0000044E | CYRILLIC SMALL LETTER YU
     C1 |  00000430 | CYRILLIC SMALL LETTER A
     C2 |  00000431 | CYRILLIC SMALL LETTER BE
     C3 |  00000446 | CYRILLIC SMALL LETTER TSE
     C4 |  00000434 | CYRILLIC SMALL LETTER DE
     C5 |  00000435 | CYRILLIC SMALL LETTER IE
     C6 |  00000444 | CYRILLIC SMALL LETTER EF
     C7 |  00000433 | CYRILLIC SMALL LETTER GHE
     C8 |  00000445 | CYRILLIC SMALL LETTER HA
     C9 |  00000438 | CYRILLIC SMALL LETTER I
     CA |  00000439 | CYRILLIC SMALL LETTER SHORT I
     CB |  0000043A | CYRILLIC SMALL LETTER KA
     CC |  0000043B | CYRILLIC SMALL LETTER EL
     CD |  0000043C | CYRILLIC SMALL LETTER EM
     CE |  0000043D | CYRILLIC SMALL LETTER EN
     CF |  0000043E | CYRILLIC SMALL LETTER O
     D0 |  0000043F | CYRILLIC SMALL LETTER PE
     D1 |  0000044F | CYRILLIC SMALL LETTER YA
     D2 |  00000440 | CYRILLIC SMALL LETTER ER
     D3 |  00000441 | CYRILLIC SMALL LETTER ES
     D4 |  00000442 | CYRILLIC SMALL LETTER TE
     D5 |  00000443 | CYRILLIC SMALL LETTER U
     D6 |  00000436 | CYRILLIC SMALL LETTER ZHE
     D7 |  00000432 | CYRILLIC SMALL LETTER VE
     D8 |  0000044C | CYRILLIC SMALL LETTER SOFT SIGN
     D9 |  0000044B | CYRILLIC SMALL LETTER YERU
     DA |  00000437 | CYRILLIC SMALL LETTER ZE
     DB |  00000448 | CYRILLIC SMALL LETTER SHA
     DC |  0000044D | CYRILLIC SMALL LETTER E
     DD |  00000449 | CYRILLIC SMALL LETTER SHCHA
     DE |  00000447 | CYRILLIC SMALL LETTER CHE
     DF |  0000044A | CYRILLIC SMALL LETTER HARD SIGN
     E0 |  0000042E | CYRILLIC CAPITAL LETTER YU
     E1 |  00000410 | CYRILLIC CAPITAL LETTER A
     E2 |  00000411 | CYRILLIC CAPITAL LETTER BE
     E3 |  00000426 | CYRILLIC CAPITAL LETTER TSE
     E4 |  00000414 | CYRILLIC CAPITAL LETTER DE
     E5 |  00000415 | CYRILLIC CAPITAL LETTER IE
     E6 |  00000424 | CYRILLIC CAPITAL LETTER EF
     E7 |  00000413 | CYRILLIC CAPITAL LETTER GHE
     E8 |  00000425 | CYRILLIC CAPITAL LETTER HA
     E9 |  00000418 | CYRILLIC CAPITAL LETTER I
     EA |  00000419 | CYRILLIC CAPITAL LETTER SHORT I
     EB |  0000041A | CYRILLIC CAPITAL LETTER KA
     EC |  0000041B | CYRILLIC CAPITAL LETTER EL
     ED |  0000041C | CYRILLIC CAPITAL LETTER EM
     EE |  0000041D | CYRILLIC CAPITAL LETTER EN
     EF |  0000041E | CYRILLIC CAPITAL LETTER O
     F0 |  0000041F | CYRILLIC CAPITAL LETTER PE
     F1 |  0000042F | CYRILLIC CAPITAL LETTER YA
     F2 |  00000420 | CYRILLIC CAPITAL LETTER ER
     F3 |  00000421 | CYRILLIC CAPITAL LETTER ES
     F4 |  00000422 | CYRILLIC CAPITAL LETTER TE
     F5 |  00000423 | CYRILLIC CAPITAL LETTER U
     F6 |  00000416 | CYRILLIC CAPITAL LETTER ZHE
     F7 |  00000412 | CYRILLIC CAPITAL LETTER VE
     F8 |  0000042C | CYRILLIC CAPITAL LETTER SOFT SIGN
     F9 |  0000042B | CYRILLIC CAPITAL LETTER YERU
     FA |  00000417 | CYRILLIC CAPITAL LETTER ZE
     FB |  00000428 | CYRILLIC CAPITAL LETTER SHA
     FC |  0000042D | CYRILLIC CAPITAL LETTER E
     FD |  00000429 | CYRILLIC CAPITAL LETTER SHCHA
     FE |  00000427 | CYRILLIC CAPITAL LETTER CHE
     FF |  0000042A | CYRILLIC CAPITAL LETTER HARD SIGN
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/GEORGIAN_ACADEMY.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for GEORGIAN-ACADEMY.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::GEORGIAN_ACADEMY;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x0004,
     0x0005,
     0x0006,
     0x0007,
     0x0008,
     0x0009,
     0x000a,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x0014,
     0x0015,
     0x0016,
     0x0017,
     0x0018,
     0x0019,
     0x001a,
     0x001b,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0020,
     0x0021,
     0x0022,
     0x0023,
     0x0024,
     0x0025,
     0x0026,
     0x0027,
     0x0028,
     0x0029,
     0x002a,
     0x002b,
     0x002c,
     0x002d,
     0x002e,
     0x002f,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x003a,
     0x003b,
     0x003c,
     0x003d,
     0x003e,
     0x003f,
     0x0040,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x005b,
     0x005c,
     0x005d,
     0x005e,
     0x005f,
     0x0060,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x007b,
     0x007c,
     0x007d,
     0x007e,
     0x007f,
     0x0080,
     0x0081,
     0x201a,
     0x0192,
     0x201e,
     0x2026,
     0x2020,
     0x2021,
     0x02c6,
     0x2030,
     0x0160,
     0x2039,
     0x0152,
     0x008d,
     0x008e,
     0x008f,
     0x0090,
     0x2018,
     0x2019,
     0x201c,
     0x201d,
     0x2022,
     0x2013,
     0x2014,
     0x02dc,
     0x2122,
     0x0161,
     0x203a,
     0x0153,
     0x009d,
     0x009e,
     0x0178,
     0x00a0,
     0x00a1,
     0x00a2,
     0x00a3,
     0x00a4,
     0x00a5,
     0x00a6,
     0x00a7,
     0x00a8,
     0x00a9,
     0x00aa,
     0x00ab,
     0x00ac,
     0x00ad,
     0x00ae,
     0x00af,
     0x00b0,
     0x00b1,
     0x00b2,
     0x00b3,
     0x00b4,
     0x00b5,
     0x00b6,
     0x00b7,
     0x00b8,
     0x00b9,
     0x00ba,
     0x00bb,
     0x00bc,
     0x00bd,
     0x00be,
     0x00bf,
     0x10d0,
     0x10d1,
     0x10d2,
     0x10d3,
     0x10d4,
     0x10d5,
     0x10d6,
     0x10d7,
     0x10d8,
     0x10d9,
     0x10da,
     0x10db,
     0x10dc,
     0x10dd,
     0x10de,
     0x10df,
     0x10e0,
     0x10e1,
     0x10e2,
     0x10e3,
     0x10e4,
     0x10e5,
     0x10e6,
     0x10e7,
     0x10e8,
     0x10e9,
     0x10ea,
     0x10eb,
     0x10ec,
     0x10ed,
     0x10ee,
     0x10ef,
     0x10f0,
     0x10f1,
     0x10f2,
     0x10f3,
     0x10f4,
     0x10f5,
     0x10f6,
     0x00e7,
     0x00e8,
     0x00e9,
     0x00ea,
     0x00eb,
     0x00ec,
     0x00ed,
     0x00ee,
     0x00ef,
     0x00f0,
     0x00f1,
     0x00f2,
     0x00f3,
     0x00f4,
     0x00f5,
     0x00f6,
     0x00f7,
     0x00f8,
     0x00f9,
     0x00fa,
     0x00fb,
     0x00fc,
     0x00fd,
     0x00fe,
     0x00ff,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\x04",
     "\x05",
     "\x06",
     "\x07",
     "\x08",
     "\x09",
     "\x0a",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\x14",
     "\x15",
     "\x16",
     "\x17",
     "\x18",
     "\x19",
     "\x1a",
     "\x1b",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\x20",
     "\x21",
     "\x22",
     "\x23",
     "\x24",
     "\x25",
     "\x26",
     "\x27",
     "\x28",
     "\x29",
     "\x2a",
     "\x2b",
     "\x2c",
     "\x2d",
     "\x2e",
     "\x2f",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\x3a",
     "\x3b",
     "\x3c",
     "\x3d",
     "\x3e",
     "\x3f",
     "\x40",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\x5b",
     "\x5c",
     "\x5d",
     "\x5e",
     "\x5f",
     "\x60",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\x7b",
     "\x7c",
     "\x7d",
     "\x7e",
     "\x7f",
     "\xc2\x80",
     "\xc2\x81",
     "\xe2\x80\x9a",
     "\xc6\x92",
     "\xe2\x80\x9e",
     "\xe2\x80\xa6",
     "\xe2\x80\xa0",
     "\xe2\x80\xa1",
     "\xcb\x86",
     "\xe2\x80\xb0",
     "\xc5\xa0",
     "\xe2\x80\xb9",
     "\xc5\x92",
     "\xc2\x8d",
     "\xc2\x8e",
     "\xc2\x8f",
     "\xc2\x90",
     "\xe2\x80\x98",
     "\xe2\x80\x99",
     "\xe2\x80\x9c",
     "\xe2\x80\x9d",
     "\xe2\x80\xa2",
     "\xe2\x80\x93",
     "\xe2\x80\x94",
     "\xcb\x9c",
     "\xe2\x84\xa2",
     "\xc5\xa1",
     "\xe2\x80\xba",
     "\xc5\x93",
     "\xc2\x9d",
     "\xc2\x9e",
     "\xc5\xb8",
     "\xc2\xa0",
     "\xc2\xa1",
     "\xc2\xa2",
     "\xc2\xa3",
     "\xc2\xa4",
     "\xc2\xa5",
     "\xc2\xa6",
     "\xc2\xa7",
     "\xc2\xa8",
     "\xc2\xa9",
     "\xc2\xaa",
     "\xc2\xab",
     "\xc2\xac",
     "\xc2\xad",
     "\xc2\xae",
     "\xc2\xaf",
     "\xc2\xb0",
     "\xc2\xb1",
     "\xc2\xb2",
     "\xc2\xb3",
     "\xc2\xb4",
     "\xc2\xb5",
     "\xc2\xb6",
     "\xc2\xb7",
     "\xc2\xb8",
     "\xc2\xb9",
     "\xc2\xba",
     "\xc2\xbb",
     "\xc2\xbc",
     "\xc2\xbd",
     "\xc2\xbe",
     "\xc2\xbf",
     "\xe1\x83\x90",
     "\xe1\x83\x91",
     "\xe1\x83\x92",
     "\xe1\x83\x93",
     "\xe1\x83\x94",
     "\xe1\x83\x95",
     "\xe1\x83\x96",
     "\xe1\x83\x97",
     "\xe1\x83\x98",
     "\xe1\x83\x99",
     "\xe1\x83\x9a",
     "\xe1\x83\x9b",
     "\xe1\x83\x9c",
     "\xe1\x83\x9d",
     "\xe1\x83\x9e",
     "\xe1\x83\x9f",
     "\xe1\x83\xa0",
     "\xe1\x83\xa1",
     "\xe1\x83\xa2",
     "\xe1\x83\xa3",
     "\xe1\x83\xa4",
     "\xe1\x83\xa5",
     "\xe1\x83\xa6",
     "\xe1\x83\xa7",
     "\xe1\x83\xa8",
     "\xe1\x83\xa9",
     "\xe1\x83\xaa",
     "\xe1\x83\xab",
     "\xe1\x83\xac",
     "\xe1\x83\xad",
     "\xe1\x83\xae",
     "\xe1\x83\xaf",
     "\xe1\x83\xb0",
     "\xe1\x83\xb1",
     "\xe1\x83\xb2",
     "\xe1\x83\xb3",
     "\xe1\x83\xb4",
     "\xe1\x83\xb5",
     "\xe1\x83\xb6",
     "\xc3\xa7",
     "\xc3\xa8",
     "\xc3\xa9",
     "\xc3\xaa",
     "\xc3\xab",
     "\xc3\xac",
     "\xc3\xad",
     "\xc3\xae",
     "\xc3\xaf",
     "\xc3\xb0",
     "\xc3\xb1",
     "\xc3\xb2",
     "\xc3\xb3",
     "\xc3\xb4",
     "\xc3\xb5",
     "\xc3\xb6",
     "\xc3\xb7",
     "\xc3\xb8",
     "\xc3\xb9",
     "\xc3\xba",
     "\xc3\xbb",
     "\xc3\xbc",
     "\xc3\xbd",
     "\xc3\xbe",
     "\xc3\xbf",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x04",
     0x00000005 => "\x05",
     0x00000006 => "\x06",
     0x00000007 => "\x07",
     0x00000008 => "\x08",
     0x00000009 => "\x09",
     0x0000000a => "\x0a",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x14",
     0x00000015 => "\x15",
     0x00000016 => "\x16",
     0x00000017 => "\x17",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x1a",
     0x0000001b => "\x1b",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x20",
     0x00000021 => "\x21",
     0x00000022 => "\x22",
     0x00000023 => "\x23",
     0x00000024 => "\x24",
     0x00000025 => "\x25",
     0x00000026 => "\x26",
     0x00000027 => "\x27",
     0x00000028 => "\x28",
     0x00000029 => "\x29",
     0x0000002a => "\x2a",
     0x0000002b => "\x2b",
     0x0000002c => "\x2c",
     0x0000002d => "\x2d",
     0x0000002e => "\x2e",
     0x0000002f => "\x2f",
     0x00000030 => "\x30",
     0x00000031 => "\x31",
     0x00000032 => "\x32",
     0x00000033 => "\x33",
     0x00000034 => "\x34",
     0x00000035 => "\x35",
     0x00000036 => "\x36",
     0x00000037 => "\x37",
     0x00000038 => "\x38",
     0x00000039 => "\x39",
     0x0000003a => "\x3a",
     0x0000003b => "\x3b",
     0x0000003c => "\x3c",
     0x0000003d => "\x3d",
     0x0000003e => "\x3e",
     0x0000003f => "\x3f",
     0x00000040 => "\x40",
     0x00000041 => "\x41",
     0x00000042 => "\x42",
     0x00000043 => "\x43",
     0x00000044 => "\x44",
     0x00000045 => "\x45",
     0x00000046 => "\x46",
     0x00000047 => "\x47",
     0x00000048 => "\x48",
     0x00000049 => "\x49",
     0x0000004a => "\x4a",
     0x0000004b => "\x4b",
     0x0000004c => "\x4c",
     0x0000004d => "\x4d",
     0x0000004e => "\x4e",
     0x0000004f => "\x4f",
     0x00000050 => "\x50",
     0x00000051 => "\x51",
     0x00000052 => "\x52",
     0x00000053 => "\x53",
     0x00000054 => "\x54",
     0x00000055 => "\x55",
     0x00000056 => "\x56",
     0x00000057 => "\x57",
     0x00000058 => "\x58",
     0x00000059 => "\x59",
     0x0000005a => "\x5a",
     0x0000005b => "\x5b",
     0x0000005c => "\x5c",
     0x0000005d => "\x5d",
     0x0000005e => "\x5e",
     0x0000005f => "\x5f",
     0x00000060 => "\x60",
     0x00000061 => "\x61",
     0x00000062 => "\x62",
     0x00000063 => "\x63",
     0x00000064 => "\x64",
     0x00000065 => "\x65",
     0x00000066 => "\x66",
     0x00000067 => "\x67",
     0x00000068 => "\x68",
     0x00000069 => "\x69",
     0x0000006a => "\x6a",
     0x0000006b => "\x6b",
     0x0000006c => "\x6c",
     0x0000006d => "\x6d",
     0x0000006e => "\x6e",
     0x0000006f => "\x6f",
     0x00000070 => "\x70",
     0x00000071 => "\x71",
     0x00000072 => "\x72",
     0x00000073 => "\x73",
     0x00000074 => "\x74",
     0x00000075 => "\x75",
     0x00000076 => "\x76",
     0x00000077 => "\x77",
     0x00000078 => "\x78",
     0x00000079 => "\x79",
     0x0000007a => "\x7a",
     0x0000007b => "\x7b",
     0x0000007c => "\x7c",
     0x0000007d => "\x7d",
     0x0000007e => "\x7e",
     0x0000007f => "\x7f",
     0x00000080 => "\x80",
     0x00000081 => "\x81",
     0x0000008d => "\x8d",
     0x0000008e => "\x8e",
     0x0000008f => "\x8f",
     0x00000090 => "\x90",
     0x0000009d => "\x9d",
     0x0000009e => "\x9e",
     0x000000a0 => "\xa0",
     0x000000a1 => "\xa1",
     0x000000a2 => "\xa2",
     0x000000a3 => "\xa3",
     0x000000a4 => "\xa4",
     0x000000a5 => "\xa5",
     0x000000a6 => "\xa6",
     0x000000a7 => "\xa7",
     0x000000a8 => "\xa8",
     0x000000a9 => "\xa9",
     0x000000aa => "\xaa",
     0x000000ab => "\xab",
     0x000000ac => "\xac",
     0x000000ad => "\xad",
     0x000000ae => "\xae",
     0x000000af => "\xaf",
     0x000000b0 => "\xb0",
     0x000000b1 => "\xb1",
     0x000000b2 => "\xb2",
     0x000000b3 => "\xb3",
     0x000000b4 => "\xb4",
     0x000000b5 => "\xb5",
     0x000000b6 => "\xb6",
     0x000000b7 => "\xb7",
     0x000000b8 => "\xb8",
     0x000000b9 => "\xb9",
     0x000000ba => "\xba",
     0x000000bb => "\xbb",
     0x000000bc => "\xbc",
     0x000000bd => "\xbd",
     0x000000be => "\xbe",
     0x000000bf => "\xbf",
     0x000000e7 => "\xe7",
     0x000000e8 => "\xe8",
     0x000000e9 => "\xe9",
     0x000000ea => "\xea",
     0x000000eb => "\xeb",
     0x000000ec => "\xec",
     0x000000ed => "\xed",
     0x000000ee => "\xee",
     0x000000ef => "\xef",
     0x000000f0 => "\xf0",
     0x000000f1 => "\xf1",
     0x000000f2 => "\xf2",
     0x000000f3 => "\xf3",
     0x000000f4 => "\xf4",
     0x000000f5 => "\xf5",
     0x000000f6 => "\xf6",
     0x000000f7 => "\xf7",
     0x000000f8 => "\xf8",
     0x000000f9 => "\xf9",
     0x000000fa => "\xfa",
     0x000000fb => "\xfb",
     0x000000fc => "\xfc",
     0x000000fd => "\xfd",
     0x000000fe => "\xfe",
     0x000000ff => "\xff",
     0x00000152 => "\x8c",
     0x00000153 => "\x9c",
     0x00000160 => "\x8a",
     0x00000161 => "\x9a",
     0x00000178 => "\x9f",
     0x00000192 => "\x83",
     0x000002c6 => "\x88",
     0x000002dc => "\x98",
     0x000010d0 => "\xc0",
     0x000010d1 => "\xc1",
     0x000010d2 => "\xc2",
     0x000010d3 => "\xc3",
     0x000010d4 => "\xc4",
     0x000010d5 => "\xc5",
     0x000010d6 => "\xc6",
     0x000010d7 => "\xc7",
     0x000010d8 => "\xc8",
     0x000010d9 => "\xc9",
     0x000010da => "\xca",
     0x000010db => "\xcb",
     0x000010dc => "\xcc",
     0x000010dd => "\xcd",
     0x000010de => "\xce",
     0x000010df => "\xcf",
     0x000010e0 => "\xd0",
     0x000010e1 => "\xd1",
     0x000010e2 => "\xd2",
     0x000010e3 => "\xd3",
     0x000010e4 => "\xd4",
     0x000010e5 => "\xd5",
     0x000010e6 => "\xd6",
     0x000010e7 => "\xd7",
     0x000010e8 => "\xd8",
     0x000010e9 => "\xd9",
     0x000010ea => "\xda",
     0x000010eb => "\xdb",
     0x000010ec => "\xdc",
     0x000010ed => "\xdd",
     0x000010ee => "\xde",
     0x000010ef => "\xdf",
     0x000010f0 => "\xe0",
     0x000010f1 => "\xe1",
     0x000010f2 => "\xe2",
     0x000010f3 => "\xe3",
     0x000010f4 => "\xe4",
     0x000010f5 => "\xe5",
     0x000010f6 => "\xe6",
     0x00002013 => "\x96",
     0x00002014 => "\x97",
     0x00002018 => "\x91",
     0x00002019 => "\x92",
     0x0000201a => "\x82",
     0x0000201c => "\x93",
     0x0000201d => "\x94",
     0x0000201e => "\x84",
     0x00002020 => "\x86",
     0x00002021 => "\x87",
     0x00002022 => "\x95",
     0x00002026 => "\x85",
     0x00002030 => "\x89",
     0x00002039 => "\x8b",
     0x0000203a => "\x9b",
     0x00002122 => "\x99",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::GEORGIAN_ACADEMY - Conversion routines for GEORGIAN-ACADEMY
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for GEORGIAN-ACADEMY.
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  00000004 | END OF TRANSMISSION (EOT)
     05 |  00000005 | ENQUIRY (ENQ)
     06 |  00000006 | ACKNOWLEDGE (ACK)
     07 |  00000007 | BELL (BEL)
     08 |  00000008 | BACKSPACE (BS)
     09 |  00000009 | CHARACTER TABULATION (HT)
     0A |  0000000A | LINE FEED (LF)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  00000014 | DEVICE CONTROL FOUR (DC4)
     15 |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     16 |  00000016 | SYNCHRONOUS IDLE (SYN)
     17 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  0000001A | SUBSTITUTE (SUB)
     1B |  0000001B | ESCAPE (ESC)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000020 | SPACE
     21 |  00000021 | EXCLAMATION MARK
     22 |  00000022 | QUOTATION MARK
     23 |  00000023 | NUMBER SIGN
     24 |  00000024 | DOLLAR SIGN
     25 |  00000025 | PERCENT SIGN
     26 |  00000026 | AMPERSAND
     27 |  00000027 | APOSTROPHE
     28 |  00000028 | LEFT PARENTHESIS
     29 |  00000029 | RIGHT PARENTHESIS
     2A |  0000002A | ASTERISK
     2B |  0000002B | PLUS SIGN
     2C |  0000002C | COMMA
     2D |  0000002D | HYPHEN-MINUS
     2E |  0000002E | FULL STOP
     2F |  0000002F | SOLIDUS
     30 |  00000030 | DIGIT ZERO
     31 |  00000031 | DIGIT ONE
     32 |  00000032 | DIGIT TWO
     33 |  00000033 | DIGIT THREE
     34 |  00000034 | DIGIT FOUR
     35 |  00000035 | DIGIT FIVE
     36 |  00000036 | DIGIT SIX
     37 |  00000037 | DIGIT SEVEN
     38 |  00000038 | DIGIT EIGHT
     39 |  00000039 | DIGIT NINE
     3A |  0000003A | COLON
     3B |  0000003B | SEMICOLON
     3C |  0000003C | LESS-THAN SIGN
     3D |  0000003D | EQUALS SIGN
     3E |  0000003E | GREATER-THAN SIGN
     3F |  0000003F | QUESTION MARK
     40 |  00000040 | COMMERCIAL AT
     41 |  00000041 | LATIN CAPITAL LETTER A
     42 |  00000042 | LATIN CAPITAL LETTER B
     43 |  00000043 | LATIN CAPITAL LETTER C
     44 |  00000044 | LATIN CAPITAL LETTER D
     45 |  00000045 | LATIN CAPITAL LETTER E
     46 |  00000046 | LATIN CAPITAL LETTER F
     47 |  00000047 | LATIN CAPITAL LETTER G
     48 |  00000048 | LATIN CAPITAL LETTER H
     49 |  00000049 | LATIN CAPITAL LETTER I
     4A |  0000004A | LATIN CAPITAL LETTER J
     4B |  0000004B | LATIN CAPITAL LETTER K
     4C |  0000004C | LATIN CAPITAL LETTER L
     4D |  0000004D | LATIN CAPITAL LETTER M
     4E |  0000004E | LATIN CAPITAL LETTER N
     4F |  0000004F | LATIN CAPITAL LETTER O
     50 |  00000050 | LATIN CAPITAL LETTER P
     51 |  00000051 | LATIN CAPITAL LETTER Q
     52 |  00000052 | LATIN CAPITAL LETTER R
     53 |  00000053 | LATIN CAPITAL LETTER S
     54 |  00000054 | LATIN CAPITAL LETTER T
     55 |  00000055 | LATIN CAPITAL LETTER U
     56 |  00000056 | LATIN CAPITAL LETTER V
     57 |  00000057 | LATIN CAPITAL LETTER W
     58 |  00000058 | LATIN CAPITAL LETTER X
     59 |  00000059 | LATIN CAPITAL LETTER Y
     5A |  0000005A | LATIN CAPITAL LETTER Z
     5B |  0000005B | LEFT SQUARE BRACKET
     5C |  0000005C | REVERSE SOLIDUS
     5D |  0000005D | RIGHT SQUARE BRACKET
     5E |  0000005E | CIRCUMFLEX ACCENT
     5F |  0000005F | LOW LINE
     60 |  00000060 | GRAVE ACCENT
     61 |  00000061 | LATIN SMALL LETTER A
     62 |  00000062 | LATIN SMALL LETTER B
     63 |  00000063 | LATIN SMALL LETTER C
     64 |  00000064 | LATIN SMALL LETTER D
     65 |  00000065 | LATIN SMALL LETTER E
     66 |  00000066 | LATIN SMALL LETTER F
     67 |  00000067 | LATIN SMALL LETTER G
     68 |  00000068 | LATIN SMALL LETTER H
     69 |  00000069 | LATIN SMALL LETTER I
     6A |  0000006A | LATIN SMALL LETTER J
     6B |  0000006B | LATIN SMALL LETTER K
     6C |  0000006C | LATIN SMALL LETTER L
     6D |  0000006D | LATIN SMALL LETTER M
     6E |  0000006E | LATIN SMALL LETTER N
     6F |  0000006F | LATIN SMALL LETTER O
     70 |  00000070 | LATIN SMALL LETTER P
     71 |  00000071 | LATIN SMALL LETTER Q
     72 |  00000072 | LATIN SMALL LETTER R
     73 |  00000073 | LATIN SMALL LETTER S
     74 |  00000074 | LATIN SMALL LETTER T
     75 |  00000075 | LATIN SMALL LETTER U
     76 |  00000076 | LATIN SMALL LETTER V
     77 |  00000077 | LATIN SMALL LETTER W
     78 |  00000078 | LATIN SMALL LETTER X
     79 |  00000079 | LATIN SMALL LETTER Y
     7A |  0000007A | LATIN SMALL LETTER Z
     7B |  0000007B | LEFT CURLY BRACKET
     7C |  0000007C | VERTICAL LINE
     7D |  0000007D | RIGHT CURLY BRACKET
     7E |  0000007E | TILDE
     7F |  0000007F | DELETE (DEL)
     80 |  00000080 | PADDING CHARACTER (PAD)
     81 |  00000081 | HIGH OCTET PRESET (HOP)
     82 |  0000201A | SINGLE LOW-9 QUOTATION MARK
     83 |  00000192 | LATIN SMALL LETTER F WITH HOOK
     84 |  0000201E | DOUBLE LOW-9 QUOTATION MARK
     85 |  00002026 | HORIZONTAL ELLIPSIS
     86 |  00002020 | DAGGER
     87 |  00002021 | DOUBLE DAGGER
     88 |  000002C6 | MODIFIER LETTER CIRCUMFLEX ACCENT
     89 |  00002030 | PER MILLE SIGN
     8A |  00000160 | LATIN CAPITAL LETTER S WITH CARON
     8B |  00002039 | SINGLE LEFT-POINTING ANGLE QUOTATION MARK
     8C |  00000152 | LATIN CAPITAL LIGATURE OE
     8D |  0000008D | REVERSE LINE FEED (RI)
     8E |  0000008E | SINGLE-SHIFT TWO (SS2)
     8F |  0000008F | SINGLE-SHIFT THREE (SS3)
     90 |  00000090 | DEVICE CONTROL STRING (DCS)
     91 |  00002018 | LEFT SINGLE QUOTATION MARK
     92 |  00002019 | RIGHT SINGLE QUOTATION MARK
     93 |  0000201C | LEFT DOUBLE QUOTATION MARK
     94 |  0000201D | RIGHT DOUBLE QUOTATION MARK
     95 |  00002022 | BULLET
     96 |  00002013 | EN DASH
     97 |  00002014 | EM DASH
     98 |  000002DC | SMALL TILDE
     99 |  00002122 | TRADE MARK SIGN
     9A |  00000161 | LATIN SMALL LETTER S WITH CARON
     9B |  0000203A | SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
     9C |  00000153 | LATIN SMALL LIGATURE OE
     9D |  0000009D | OPERATING SYSTEM COMMAND (OSC)
     9E |  0000009E | PRIVACY MESSAGE (PM)
     9F |  00000178 | LATIN CAPITAL LETTER Y WITH DIAERESIS
     A0 |  000000A0 | NO-BREAK SPACE
     A1 |  000000A1 | INVERTED EXCLAMATION MARK
     A2 |  000000A2 | CENT SIGN
     A3 |  000000A3 | POUND SIGN
     A4 |  000000A4 | CURRENCY SIGN
     A5 |  000000A5 | YEN SIGN
     A6 |  000000A6 | BROKEN BAR
     A7 |  000000A7 | SECTION SIGN
     A8 |  000000A8 | DIAERESIS
     A9 |  000000A9 | COPYRIGHT SIGN
     AA |  000000AA | FEMININE ORDINAL INDICATOR
     AB |  000000AB | LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
     AC |  000000AC | NOT SIGN
     AD |  000000AD | SOFT HYPHEN
     AE |  000000AE | REGISTERED SIGN
     AF |  000000AF | MACRON
     B0 |  000000B0 | DEGREE SIGN
     B1 |  000000B1 | PLUS-MINUS SIGN
     B2 |  000000B2 | SUPERSCRIPT TWO
     B3 |  000000B3 | SUPERSCRIPT THREE
     B4 |  000000B4 | ACUTE ACCENT
     B5 |  000000B5 | MICRO SIGN
     B6 |  000000B6 | PILCROW SIGN
     B7 |  000000B7 | MIDDLE DOT
     B8 |  000000B8 | CEDILLA
     B9 |  000000B9 | SUPERSCRIPT ONE
     BA |  000000BA | MASCULINE ORDINAL INDICATOR
     BB |  000000BB | RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
     BC |  000000BC | VULGAR FRACTION ONE QUARTER
     BD |  000000BD | VULGAR FRACTION ONE HALF
     BE |  000000BE | VULGAR FRACTION THREE QUARTERS
     BF |  000000BF | INVERTED QUESTION MARK
     C0 |  000010D0 | GEORGIAN LETTER AN
     C1 |  000010D1 | GEORGIAN LETTER BAN
     C2 |  000010D2 | GEORGIAN LETTER GAN
     C3 |  000010D3 | GEORGIAN LETTER DON
     C4 |  000010D4 | GEORGIAN LETTER EN
     C5 |  000010D5 | GEORGIAN LETTER VIN
     C6 |  000010D6 | GEORGIAN LETTER ZEN
     C7 |  000010D7 | GEORGIAN LETTER TAN
     C8 |  000010D8 | GEORGIAN LETTER IN
     C9 |  000010D9 | GEORGIAN LETTER KAN
     CA |  000010DA | GEORGIAN LETTER LAS
     CB |  000010DB | GEORGIAN LETTER MAN
     CC |  000010DC | GEORGIAN LETTER NAR
     CD |  000010DD | GEORGIAN LETTER ON
     CE |  000010DE | GEORGIAN LETTER PAR
     CF |  000010DF | GEORGIAN LETTER ZHAR
     D0 |  000010E0 | GEORGIAN LETTER RAE
     D1 |  000010E1 | GEORGIAN LETTER SAN
     D2 |  000010E2 | GEORGIAN LETTER TAR
     D3 |  000010E3 | GEORGIAN LETTER UN
     D4 |  000010E4 | GEORGIAN LETTER PHAR
     D5 |  000010E5 | GEORGIAN LETTER KHAR
     D6 |  000010E6 | GEORGIAN LETTER GHAN
     D7 |  000010E7 | GEORGIAN LETTER QAR
     D8 |  000010E8 | GEORGIAN LETTER SHIN
     D9 |  000010E9 | GEORGIAN LETTER CHIN
     DA |  000010EA | GEORGIAN LETTER CAN
     DB |  000010EB | GEORGIAN LETTER JIL
     DC |  000010EC | GEORGIAN LETTER CIL
     DD |  000010ED | GEORGIAN LETTER CHAR
     DE |  000010EE | GEORGIAN LETTER XAN
     DF |  000010EF | GEORGIAN LETTER JHAN
     E0 |  000010F0 | GEORGIAN LETTER HAE
     E1 |  000010F1 | GEORGIAN LETTER HE
     E2 |  000010F2 | GEORGIAN LETTER HIE
     E3 |  000010F3 | GEORGIAN LETTER WE
     E4 |  000010F4 | GEORGIAN LETTER HAR
     E5 |  000010F5 | GEORGIAN LETTER HOE
     E6 |  000010F6 | GEORGIAN LETTER FI
     E7 |  000000E7 | LATIN SMALL LETTER C WITH CEDILLA
     E8 |  000000E8 | LATIN SMALL LETTER E WITH GRAVE
     E9 |  000000E9 | LATIN SMALL LETTER E WITH ACUTE
     EA |  000000EA | LATIN SMALL LETTER E WITH CIRCUMFLEX
     EB |  000000EB | LATIN SMALL LETTER E WITH DIAERESIS
     EC |  000000EC | LATIN SMALL LETTER I WITH GRAVE
     ED |  000000ED | LATIN SMALL LETTER I WITH ACUTE
     EE |  000000EE | LATIN SMALL LETTER I WITH CIRCUMFLEX
     EF |  000000EF | LATIN SMALL LETTER I WITH DIAERESIS
     F0 |  000000F0 | LATIN SMALL LETTER ETH (Icelandic)
     F1 |  000000F1 | LATIN SMALL LETTER N WITH TILDE
     F2 |  000000F2 | LATIN SMALL LETTER O WITH GRAVE
     F3 |  000000F3 | LATIN SMALL LETTER O WITH ACUTE
     F4 |  000000F4 | LATIN SMALL LETTER O WITH CIRCUMFLEX
     F5 |  000000F5 | LATIN SMALL LETTER O WITH TILDE
     F6 |  000000F6 | LATIN SMALL LETTER O WITH DIAERESIS
     F7 |  000000F7 | DIVISION SIGN
     F8 |  000000F8 | LATIN SMALL LETTER O WITH STROKE
     F9 |  000000F9 | LATIN SMALL LETTER U WITH GRAVE
     FA |  000000FA | LATIN SMALL LETTER U WITH ACUTE
     FB |  000000FB | LATIN SMALL LETTER U WITH CIRCUMFLEX
     FC |  000000FC | LATIN SMALL LETTER U WITH DIAERESIS
     FD |  000000FD | LATIN SMALL LETTER Y WITH ACUTE
     FE |  000000FE | LATIN SMALL LETTER THORN (Icelandic)
     FF |  000000FF | LATIN SMALL LETTER Y WITH DIAERESIS
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/GEORGIAN_PS.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for GEORGIAN-PS.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::GEORGIAN_PS;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x0004,
     0x0005,
     0x0006,
     0x0007,
     0x0008,
     0x0009,
     0x000a,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x0014,
     0x0015,
     0x0016,
     0x0017,
     0x0018,
     0x0019,
     0x001a,
     0x001b,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0020,
     0x0021,
     0x0022,
     0x0023,
     0x0024,
     0x0025,
     0x0026,
     0x0027,
     0x0028,
     0x0029,
     0x002a,
     0x002b,
     0x002c,
     0x002d,
     0x002e,
     0x002f,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x003a,
     0x003b,
     0x003c,
     0x003d,
     0x003e,
     0x003f,
     0x0040,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x005b,
     0x005c,
     0x005d,
     0x005e,
     0x005f,
     0x0060,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x007b,
     0x007c,
     0x007d,
     0x007e,
     0x007f,
     0x0080,
     0x0081,
     0x201a,
     0x0192,
     0x201e,
     0x2026,
     0x2020,
     0x2021,
     0x02c6,
     0x2030,
     0x0160,
     0x2039,
     0x0152,
     0x008d,
     0x008e,
     0x008f,
     0x0090,
     0x2018,
     0x2019,
     0x201c,
     0x201d,
     0x2022,
     0x2013,
     0x2014,
     0x02dc,
     0x2122,
     0x0161,
     0x203a,
     0x0153,
     0x009d,
     0x009e,
     0x0178,
     0x00a0,
     0x00a1,
     0x00a2,
     0x00a3,
     0x00a4,
     0x00a5,
     0x00a6,
     0x00a7,
     0x00a8,
     0x00a9,
     0x00aa,
     0x00ab,
     0x00ac,
     0x00ad,
     0x00ae,
     0x00af,
     0x00b0,
     0x00b1,
     0x00b2,
     0x00b3,
     0x00b4,
     0x00b5,
     0x00b6,
     0x00b7,
     0x00b8,
     0x00b9,
     0x00ba,
     0x00bb,
     0x00bc,
     0x00bd,
     0x00be,
     0x00bf,
     0x10d0,
     0x10d1,
     0x10d2,
     0x10d3,
     0x10d4,
     0x10d5,
     0x10d6,
     0x10f1,
     0x10d7,
     0x10d8,
     0x10d9,
     0x10da,
     0x10db,
     0x10dc,
     0x10f2,
     0x10dd,
     0x10de,
     0x10df,
     0x10e0,
     0x10e1,
     0x10e2,
     0x10f3,
     0x10e3,
     0x10e4,
     0x10e5,
     0x10e6,
     0x10e7,
     0x10e8,
     0x10e9,
     0x10ea,
     0x10eb,
     0x10ec,
     0x10ed,
     0x10ee,
     0x10f4,
     0x10ef,
     0x10f0,
     0x10f5,
     0x00e6,
     0x00e7,
     0x00e8,
     0x00e9,
     0x00ea,
     0x00eb,
     0x00ec,
     0x00ed,
     0x00ee,
     0x00ef,
     0x00f0,
     0x00f1,
     0x00f2,
     0x00f3,
     0x00f4,
     0x00f5,
     0x00f6,
     0x00f7,
     0x00f8,
     0x00f9,
     0x00fa,
     0x00fb,
     0x00fc,
     0x00fd,
     0x00fe,
     0x00ff,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\x04",
     "\x05",
     "\x06",
     "\x07",
     "\x08",
     "\x09",
     "\x0a",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\x14",
     "\x15",
     "\x16",
     "\x17",
     "\x18",
     "\x19",
     "\x1a",
     "\x1b",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\x20",
     "\x21",
     "\x22",
     "\x23",
     "\x24",
     "\x25",
     "\x26",
     "\x27",
     "\x28",
     "\x29",
     "\x2a",
     "\x2b",
     "\x2c",
     "\x2d",
     "\x2e",
     "\x2f",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\x3a",
     "\x3b",
     "\x3c",
     "\x3d",
     "\x3e",
     "\x3f",
     "\x40",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\x5b",
     "\x5c",
     "\x5d",
     "\x5e",
     "\x5f",
     "\x60",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\x7b",
     "\x7c",
     "\x7d",
     "\x7e",
     "\x7f",
     "\xc2\x80",
     "\xc2\x81",
     "\xe2\x80\x9a",
     "\xc6\x92",
     "\xe2\x80\x9e",
     "\xe2\x80\xa6",
     "\xe2\x80\xa0",
     "\xe2\x80\xa1",
     "\xcb\x86",
     "\xe2\x80\xb0",
     "\xc5\xa0",
     "\xe2\x80\xb9",
     "\xc5\x92",
     "\xc2\x8d",
     "\xc2\x8e",
     "\xc2\x8f",
     "\xc2\x90",
     "\xe2\x80\x98",
     "\xe2\x80\x99",
     "\xe2\x80\x9c",
     "\xe2\x80\x9d",
     "\xe2\x80\xa2",
     "\xe2\x80\x93",
     "\xe2\x80\x94",
     "\xcb\x9c",
     "\xe2\x84\xa2",
     "\xc5\xa1",
     "\xe2\x80\xba",
     "\xc5\x93",
     "\xc2\x9d",
     "\xc2\x9e",
     "\xc5\xb8",
     "\xc2\xa0",
     "\xc2\xa1",
     "\xc2\xa2",
     "\xc2\xa3",
     "\xc2\xa4",
     "\xc2\xa5",
     "\xc2\xa6",
     "\xc2\xa7",
     "\xc2\xa8",
     "\xc2\xa9",
     "\xc2\xaa",
     "\xc2\xab",
     "\xc2\xac",
     "\xc2\xad",
     "\xc2\xae",
     "\xc2\xaf",
     "\xc2\xb0",
     "\xc2\xb1",
     "\xc2\xb2",
     "\xc2\xb3",
     "\xc2\xb4",
     "\xc2\xb5",
     "\xc2\xb6",
     "\xc2\xb7",
     "\xc2\xb8",
     "\xc2\xb9",
     "\xc2\xba",
     "\xc2\xbb",
     "\xc2\xbc",
     "\xc2\xbd",
     "\xc2\xbe",
     "\xc2\xbf",
     "\xe1\x83\x90",
     "\xe1\x83\x91",
     "\xe1\x83\x92",
     "\xe1\x83\x93",
     "\xe1\x83\x94",
     "\xe1\x83\x95",
     "\xe1\x83\x96",
     "\xe1\x83\xb1",
     "\xe1\x83\x97",
     "\xe1\x83\x98",
     "\xe1\x83\x99",
     "\xe1\x83\x9a",
     "\xe1\x83\x9b",
     "\xe1\x83\x9c",
     "\xe1\x83\xb2",
     "\xe1\x83\x9d",
     "\xe1\x83\x9e",
     "\xe1\x83\x9f",
     "\xe1\x83\xa0",
     "\xe1\x83\xa1",
     "\xe1\x83\xa2",
     "\xe1\x83\xb3",
     "\xe1\x83\xa3",
     "\xe1\x83\xa4",
     "\xe1\x83\xa5",
     "\xe1\x83\xa6",
     "\xe1\x83\xa7",
     "\xe1\x83\xa8",
     "\xe1\x83\xa9",
     "\xe1\x83\xaa",
     "\xe1\x83\xab",
     "\xe1\x83\xac",
     "\xe1\x83\xad",
     "\xe1\x83\xae",
     "\xe1\x83\xb4",
     "\xe1\x83\xaf",
     "\xe1\x83\xb0",
     "\xe1\x83\xb5",
     "\xc3\xa6",
     "\xc3\xa7",
     "\xc3\xa8",
     "\xc3\xa9",
     "\xc3\xaa",
     "\xc3\xab",
     "\xc3\xac",
     "\xc3\xad",
     "\xc3\xae",
     "\xc3\xaf",
     "\xc3\xb0",
     "\xc3\xb1",
     "\xc3\xb2",
     "\xc3\xb3",
     "\xc3\xb4",
     "\xc3\xb5",
     "\xc3\xb6",
     "\xc3\xb7",
     "\xc3\xb8",
     "\xc3\xb9",
     "\xc3\xba",
     "\xc3\xbb",
     "\xc3\xbc",
     "\xc3\xbd",
     "\xc3\xbe",
     "\xc3\xbf",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x04",
     0x00000005 => "\x05",
     0x00000006 => "\x06",
     0x00000007 => "\x07",
     0x00000008 => "\x08",
     0x00000009 => "\x09",
     0x0000000a => "\x0a",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x14",
     0x00000015 => "\x15",
     0x00000016 => "\x16",
     0x00000017 => "\x17",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x1a",
     0x0000001b => "\x1b",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x20",
     0x00000021 => "\x21",
     0x00000022 => "\x22",
     0x00000023 => "\x23",
     0x00000024 => "\x24",
     0x00000025 => "\x25",
     0x00000026 => "\x26",
     0x00000027 => "\x27",
     0x00000028 => "\x28",
     0x00000029 => "\x29",
     0x0000002a => "\x2a",
     0x0000002b => "\x2b",
     0x0000002c => "\x2c",
     0x0000002d => "\x2d",
     0x0000002e => "\x2e",
     0x0000002f => "\x2f",
     0x00000030 => "\x30",
     0x00000031 => "\x31",
     0x00000032 => "\x32",
     0x00000033 => "\x33",
     0x00000034 => "\x34",
     0x00000035 => "\x35",
     0x00000036 => "\x36",
     0x00000037 => "\x37",
     0x00000038 => "\x38",
     0x00000039 => "\x39",
     0x0000003a => "\x3a",
     0x0000003b => "\x3b",
     0x0000003c => "\x3c",
     0x0000003d => "\x3d",
     0x0000003e => "\x3e",
     0x0000003f => "\x3f",
     0x00000040 => "\x40",
     0x00000041 => "\x41",
     0x00000042 => "\x42",
     0x00000043 => "\x43",
     0x00000044 => "\x44",
     0x00000045 => "\x45",
     0x00000046 => "\x46",
     0x00000047 => "\x47",
     0x00000048 => "\x48",
     0x00000049 => "\x49",
     0x0000004a => "\x4a",
     0x0000004b => "\x4b",
     0x0000004c => "\x4c",
     0x0000004d => "\x4d",
     0x0000004e => "\x4e",
     0x0000004f => "\x4f",
     0x00000050 => "\x50",
     0x00000051 => "\x51",
     0x00000052 => "\x52",
     0x00000053 => "\x53",
     0x00000054 => "\x54",
     0x00000055 => "\x55",
     0x00000056 => "\x56",
     0x00000057 => "\x57",
     0x00000058 => "\x58",
     0x00000059 => "\x59",
     0x0000005a => "\x5a",
     0x0000005b => "\x5b",
     0x0000005c => "\x5c",
     0x0000005d => "\x5d",
     0x0000005e => "\x5e",
     0x0000005f => "\x5f",
     0x00000060 => "\x60",
     0x00000061 => "\x61",
     0x00000062 => "\x62",
     0x00000063 => "\x63",
     0x00000064 => "\x64",
     0x00000065 => "\x65",
     0x00000066 => "\x66",
     0x00000067 => "\x67",
     0x00000068 => "\x68",
     0x00000069 => "\x69",
     0x0000006a => "\x6a",
     0x0000006b => "\x6b",
     0x0000006c => "\x6c",
     0x0000006d => "\x6d",
     0x0000006e => "\x6e",
     0x0000006f => "\x6f",
     0x00000070 => "\x70",
     0x00000071 => "\x71",
     0x00000072 => "\x72",
     0x00000073 => "\x73",
     0x00000074 => "\x74",
     0x00000075 => "\x75",
     0x00000076 => "\x76",
     0x00000077 => "\x77",
     0x00000078 => "\x78",
     0x00000079 => "\x79",
     0x0000007a => "\x7a",
     0x0000007b => "\x7b",
     0x0000007c => "\x7c",
     0x0000007d => "\x7d",
     0x0000007e => "\x7e",
     0x0000007f => "\x7f",
     0x00000080 => "\x80",
     0x00000081 => "\x81",
     0x0000008d => "\x8d",
     0x0000008e => "\x8e",
     0x0000008f => "\x8f",
     0x00000090 => "\x90",
     0x0000009d => "\x9d",
     0x0000009e => "\x9e",
     0x000000a0 => "\xa0",
     0x000000a1 => "\xa1",
     0x000000a2 => "\xa2",
     0x000000a3 => "\xa3",
     0x000000a4 => "\xa4",
     0x000000a5 => "\xa5",
     0x000000a6 => "\xa6",
     0x000000a7 => "\xa7",
     0x000000a8 => "\xa8",
     0x000000a9 => "\xa9",
     0x000000aa => "\xaa",
     0x000000ab => "\xab",
     0x000000ac => "\xac",
     0x000000ad => "\xad",
     0x000000ae => "\xae",
     0x000000af => "\xaf",
     0x000000b0 => "\xb0",
     0x000000b1 => "\xb1",
     0x000000b2 => "\xb2",
     0x000000b3 => "\xb3",
     0x000000b4 => "\xb4",
     0x000000b5 => "\xb5",
     0x000000b6 => "\xb6",
     0x000000b7 => "\xb7",
     0x000000b8 => "\xb8",
     0x000000b9 => "\xb9",
     0x000000ba => "\xba",
     0x000000bb => "\xbb",
     0x000000bc => "\xbc",
     0x000000bd => "\xbd",
     0x000000be => "\xbe",
     0x000000bf => "\xbf",
     0x000000e6 => "\xe6",
     0x000000e7 => "\xe7",
     0x000000e8 => "\xe8",
     0x000000e9 => "\xe9",
     0x000000ea => "\xea",
     0x000000eb => "\xeb",
     0x000000ec => "\xec",
     0x000000ed => "\xed",
     0x000000ee => "\xee",
     0x000000ef => "\xef",
     0x000000f0 => "\xf0",
     0x000000f1 => "\xf1",
     0x000000f2 => "\xf2",
     0x000000f3 => "\xf3",
     0x000000f4 => "\xf4",
     0x000000f5 => "\xf5",
     0x000000f6 => "\xf6",
     0x000000f7 => "\xf7",
     0x000000f8 => "\xf8",
     0x000000f9 => "\xf9",
     0x000000fa => "\xfa",
     0x000000fb => "\xfb",
     0x000000fc => "\xfc",
     0x000000fd => "\xfd",
     0x000000fe => "\xfe",
     0x000000ff => "\xff",
     0x00000152 => "\x8c",
     0x00000153 => "\x9c",
     0x00000160 => "\x8a",
     0x00000161 => "\x9a",
     0x00000178 => "\x9f",
     0x00000192 => "\x83",
     0x000002c6 => "\x88",
     0x000002dc => "\x98",
     0x000010d0 => "\xc0",
     0x000010d1 => "\xc1",
     0x000010d2 => "\xc2",
     0x000010d3 => "\xc3",
     0x000010d4 => "\xc4",
     0x000010d5 => "\xc5",
     0x000010d6 => "\xc6",
     0x000010d7 => "\xc8",
     0x000010d8 => "\xc9",
     0x000010d9 => "\xca",
     0x000010da => "\xcb",
     0x000010db => "\xcc",
     0x000010dc => "\xcd",
     0x000010dd => "\xcf",
     0x000010de => "\xd0",
     0x000010df => "\xd1",
     0x000010e0 => "\xd2",
     0x000010e1 => "\xd3",
     0x000010e2 => "\xd4",
     0x000010e3 => "\xd6",
     0x000010e4 => "\xd7",
     0x000010e5 => "\xd8",
     0x000010e6 => "\xd9",
     0x000010e7 => "\xda",
     0x000010e8 => "\xdb",
     0x000010e9 => "\xdc",
     0x000010ea => "\xdd",
     0x000010eb => "\xde",
     0x000010ec => "\xdf",
     0x000010ed => "\xe0",
     0x000010ee => "\xe1",
     0x000010ef => "\xe3",
     0x000010f0 => "\xe4",
     0x000010f1 => "\xc7",
     0x000010f2 => "\xce",
     0x000010f3 => "\xd5",
     0x000010f4 => "\xe2",
     0x000010f5 => "\xe5",
     0x00002013 => "\x96",
     0x00002014 => "\x97",
     0x00002018 => "\x91",
     0x00002019 => "\x92",
     0x0000201a => "\x82",
     0x0000201c => "\x93",
     0x0000201d => "\x94",
     0x0000201e => "\x84",
     0x00002020 => "\x86",
     0x00002021 => "\x87",
     0x00002022 => "\x95",
     0x00002026 => "\x85",
     0x00002030 => "\x89",
     0x00002039 => "\x8b",
     0x0000203a => "\x9b",
     0x00002122 => "\x99",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::GEORGIAN_PS - Conversion routines for GEORGIAN-PS
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for GEORGIAN-PS.
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  00000004 | END OF TRANSMISSION (EOT)
     05 |  00000005 | ENQUIRY (ENQ)
     06 |  00000006 | ACKNOWLEDGE (ACK)
     07 |  00000007 | BELL (BEL)
     08 |  00000008 | BACKSPACE (BS)
     09 |  00000009 | CHARACTER TABULATION (HT)
     0A |  0000000A | LINE FEED (LF)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  00000014 | DEVICE CONTROL FOUR (DC4)
     15 |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     16 |  00000016 | SYNCHRONOUS IDLE (SYN)
     17 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  0000001A | SUBSTITUTE (SUB)
     1B |  0000001B | ESCAPE (ESC)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000020 | SPACE
     21 |  00000021 | EXCLAMATION MARK
     22 |  00000022 | QUOTATION MARK
     23 |  00000023 | NUMBER SIGN
     24 |  00000024 | DOLLAR SIGN
     25 |  00000025 | PERCENT SIGN
     26 |  00000026 | AMPERSAND
     27 |  00000027 | APOSTROPHE
     28 |  00000028 | LEFT PARENTHESIS
     29 |  00000029 | RIGHT PARENTHESIS
     2A |  0000002A | ASTERISK
     2B |  0000002B | PLUS SIGN
     2C |  0000002C | COMMA
     2D |  0000002D | HYPHEN-MINUS
     2E |  0000002E | FULL STOP
     2F |  0000002F | SOLIDUS
     30 |  00000030 | DIGIT ZERO
     31 |  00000031 | DIGIT ONE
     32 |  00000032 | DIGIT TWO
     33 |  00000033 | DIGIT THREE
     34 |  00000034 | DIGIT FOUR
     35 |  00000035 | DIGIT FIVE
     36 |  00000036 | DIGIT SIX
     37 |  00000037 | DIGIT SEVEN
     38 |  00000038 | DIGIT EIGHT
     39 |  00000039 | DIGIT NINE
     3A |  0000003A | COLON
     3B |  0000003B | SEMICOLON
     3C |  0000003C | LESS-THAN SIGN
     3D |  0000003D | EQUALS SIGN
     3E |  0000003E | GREATER-THAN SIGN
     3F |  0000003F | QUESTION MARK
     40 |  00000040 | COMMERCIAL AT
     41 |  00000041 | LATIN CAPITAL LETTER A
     42 |  00000042 | LATIN CAPITAL LETTER B
     43 |  00000043 | LATIN CAPITAL LETTER C
     44 |  00000044 | LATIN CAPITAL LETTER D
     45 |  00000045 | LATIN CAPITAL LETTER E
     46 |  00000046 | LATIN CAPITAL LETTER F
     47 |  00000047 | LATIN CAPITAL LETTER G
     48 |  00000048 | LATIN CAPITAL LETTER H
     49 |  00000049 | LATIN CAPITAL LETTER I
     4A |  0000004A | LATIN CAPITAL LETTER J
     4B |  0000004B | LATIN CAPITAL LETTER K
     4C |  0000004C | LATIN CAPITAL LETTER L
     4D |  0000004D | LATIN CAPITAL LETTER M
     4E |  0000004E | LATIN CAPITAL LETTER N
     4F |  0000004F | LATIN CAPITAL LETTER O
     50 |  00000050 | LATIN CAPITAL LETTER P
     51 |  00000051 | LATIN CAPITAL LETTER Q
     52 |  00000052 | LATIN CAPITAL LETTER R
     53 |  00000053 | LATIN CAPITAL LETTER S
     54 |  00000054 | LATIN CAPITAL LETTER T
     55 |  00000055 | LATIN CAPITAL LETTER U
     56 |  00000056 | LATIN CAPITAL LETTER V
     57 |  00000057 | LATIN CAPITAL LETTER W
     58 |  00000058 | LATIN CAPITAL LETTER X
     59 |  00000059 | LATIN CAPITAL LETTER Y
     5A |  0000005A | LATIN CAPITAL LETTER Z
     5B |  0000005B | LEFT SQUARE BRACKET
     5C |  0000005C | REVERSE SOLIDUS
     5D |  0000005D | RIGHT SQUARE BRACKET
     5E |  0000005E | CIRCUMFLEX ACCENT
     5F |  0000005F | LOW LINE
     60 |  00000060 | GRAVE ACCENT
     61 |  00000061 | LATIN SMALL LETTER A
     62 |  00000062 | LATIN SMALL LETTER B
     63 |  00000063 | LATIN SMALL LETTER C
     64 |  00000064 | LATIN SMALL LETTER D
     65 |  00000065 | LATIN SMALL LETTER E
     66 |  00000066 | LATIN SMALL LETTER F
     67 |  00000067 | LATIN SMALL LETTER G
     68 |  00000068 | LATIN SMALL LETTER H
     69 |  00000069 | LATIN SMALL LETTER I
     6A |  0000006A | LATIN SMALL LETTER J
     6B |  0000006B | LATIN SMALL LETTER K
     6C |  0000006C | LATIN SMALL LETTER L
     6D |  0000006D | LATIN SMALL LETTER M
     6E |  0000006E | LATIN SMALL LETTER N
     6F |  0000006F | LATIN SMALL LETTER O
     70 |  00000070 | LATIN SMALL LETTER P
     71 |  00000071 | LATIN SMALL LETTER Q
     72 |  00000072 | LATIN SMALL LETTER R
     73 |  00000073 | LATIN SMALL LETTER S
     74 |  00000074 | LATIN SMALL LETTER T
     75 |  00000075 | LATIN SMALL LETTER U
     76 |  00000076 | LATIN SMALL LETTER V
     77 |  00000077 | LATIN SMALL LETTER W
     78 |  00000078 | LATIN SMALL LETTER X
     79 |  00000079 | LATIN SMALL LETTER Y
     7A |  0000007A | LATIN SMALL LETTER Z
     7B |  0000007B | LEFT CURLY BRACKET
     7C |  0000007C | VERTICAL LINE
     7D |  0000007D | RIGHT CURLY BRACKET
     7E |  0000007E | TILDE
     7F |  0000007F | DELETE (DEL)
     80 |  00000080 | PADDING CHARACTER (PAD)
     81 |  00000081 | HIGH OCTET PRESET (HOP)
     82 |  0000201A | SINGLE LOW-9 QUOTATION MARK
     83 |  00000192 | LATIN SMALL LETTER F WITH HOOK
     84 |  0000201E | DOUBLE LOW-9 QUOTATION MARK
     85 |  00002026 | HORIZONTAL ELLIPSIS
     86 |  00002020 | DAGGER
     87 |  00002021 | DOUBLE DAGGER
     88 |  000002C6 | MODIFIER LETTER CIRCUMFLEX ACCENT
     89 |  00002030 | PER MILLE SIGN
     8A |  00000160 | LATIN CAPITAL LETTER S WITH CARON
     8B |  00002039 | SINGLE LEFT-POINTING ANGLE QUOTATION MARK
     8C |  00000152 | LATIN CAPITAL LIGATURE OE
     8D |  0000008D | REVERSE LINE FEED (RI)
     8E |  0000008E | SINGLE-SHIFT TWO (SS2)
     8F |  0000008F | SINGLE-SHIFT THREE (SS3)
     90 |  00000090 | DEVICE CONTROL STRING (DCS)
     91 |  00002018 | LEFT SINGLE QUOTATION MARK
     92 |  00002019 | RIGHT SINGLE QUOTATION MARK
     93 |  0000201C | LEFT DOUBLE QUOTATION MARK
     94 |  0000201D | RIGHT DOUBLE QUOTATION MARK
     95 |  00002022 | BULLET
     96 |  00002013 | EN DASH
     97 |  00002014 | EM DASH
     98 |  000002DC | SMALL TILDE
     99 |  00002122 | TRADE MARK SIGN
     9A |  00000161 | LATIN SMALL LETTER S WITH CARON
     9B |  0000203A | SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
     9C |  00000153 | LATIN SMALL LIGATURE OE
     9D |  0000009D | OPERATING SYSTEM COMMAND (OSC)
     9E |  0000009E | PRIVACY MESSAGE (PM)
     9F |  00000178 | LATIN CAPITAL LETTER Y WITH DIAERESIS
     A0 |  000000A0 | NO-BREAK SPACE
     A1 |  000000A1 | INVERTED EXCLAMATION MARK
     A2 |  000000A2 | CENT SIGN
     A3 |  000000A3 | POUND SIGN
     A4 |  000000A4 | CURRENCY SIGN
     A5 |  000000A5 | YEN SIGN
     A6 |  000000A6 | BROKEN BAR
     A7 |  000000A7 | SECTION SIGN
     A8 |  000000A8 | DIAERESIS
     A9 |  000000A9 | COPYRIGHT SIGN
     AA |  000000AA | FEMININE ORDINAL INDICATOR
     AB |  000000AB | LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
     AC |  000000AC | NOT SIGN
     AD |  000000AD | SOFT HYPHEN
     AE |  000000AE | REGISTERED SIGN
     AF |  000000AF | MACRON
     B0 |  000000B0 | DEGREE SIGN
     B1 |  000000B1 | PLUS-MINUS SIGN
     B2 |  000000B2 | SUPERSCRIPT TWO
     B3 |  000000B3 | SUPERSCRIPT THREE
     B4 |  000000B4 | ACUTE ACCENT
     B5 |  000000B5 | MICRO SIGN
     B6 |  000000B6 | PILCROW SIGN
     B7 |  000000B7 | MIDDLE DOT
     B8 |  000000B8 | CEDILLA
     B9 |  000000B9 | SUPERSCRIPT ONE
     BA |  000000BA | MASCULINE ORDINAL INDICATOR
     BB |  000000BB | RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
     BC |  000000BC | VULGAR FRACTION ONE QUARTER
     BD |  000000BD | VULGAR FRACTION ONE HALF
     BE |  000000BE | VULGAR FRACTION THREE QUARTERS
     BF |  000000BF | INVERTED QUESTION MARK
     C0 |  000010D0 | GEORGIAN LETTER AN
     C1 |  000010D1 | GEORGIAN LETTER BAN
     C2 |  000010D2 | GEORGIAN LETTER GAN
     C3 |  000010D3 | GEORGIAN LETTER DON
     C4 |  000010D4 | GEORGIAN LETTER EN
     C5 |  000010D5 | GEORGIAN LETTER VIN
     C6 |  000010D6 | GEORGIAN LETTER ZEN
     C7 |  000010F1 | GEORGIAN LETTER HE
     C8 |  000010D7 | GEORGIAN LETTER TAN
     C9 |  000010D8 | GEORGIAN LETTER IN
     CA |  000010D9 | GEORGIAN LETTER KAN
     CB |  000010DA | GEORGIAN LETTER LAS
     CC |  000010DB | GEORGIAN LETTER MAN
     CD |  000010DC | GEORGIAN LETTER NAR
     CE |  000010F2 | GEORGIAN LETTER HIE
     CF |  000010DD | GEORGIAN LETTER ON
     D0 |  000010DE | GEORGIAN LETTER PAR
     D1 |  000010DF | GEORGIAN LETTER ZHAR
     D2 |  000010E0 | GEORGIAN LETTER RAE
     D3 |  000010E1 | GEORGIAN LETTER SAN
     D4 |  000010E2 | GEORGIAN LETTER TAR
     D5 |  000010F3 | GEORGIAN LETTER WE
     D6 |  000010E3 | GEORGIAN LETTER UN
     D7 |  000010E4 | GEORGIAN LETTER PHAR
     D8 |  000010E5 | GEORGIAN LETTER KHAR
     D9 |  000010E6 | GEORGIAN LETTER GHAN
     DA |  000010E7 | GEORGIAN LETTER QAR
     DB |  000010E8 | GEORGIAN LETTER SHIN
     DC |  000010E9 | GEORGIAN LETTER CHIN
     DD |  000010EA | GEORGIAN LETTER CAN
     DE |  000010EB | GEORGIAN LETTER JIL
     DF |  000010EC | GEORGIAN LETTER CIL
     E0 |  000010ED | GEORGIAN LETTER CHAR
     E1 |  000010EE | GEORGIAN LETTER XAN
     E2 |  000010F4 | GEORGIAN LETTER HAR
     E3 |  000010EF | GEORGIAN LETTER JHAN
     E4 |  000010F0 | GEORGIAN LETTER HAE
     E5 |  000010F5 | GEORGIAN LETTER HOE
     E6 |  000000E6 | LATIN SMALL LETTER AE
     E7 |  000000E7 | LATIN SMALL LETTER C WITH CEDILLA
     E8 |  000000E8 | LATIN SMALL LETTER E WITH GRAVE
     E9 |  000000E9 | LATIN SMALL LETTER E WITH ACUTE
     EA |  000000EA | LATIN SMALL LETTER E WITH CIRCUMFLEX
     EB |  000000EB | LATIN SMALL LETTER E WITH DIAERESIS
     EC |  000000EC | LATIN SMALL LETTER I WITH GRAVE
     ED |  000000ED | LATIN SMALL LETTER I WITH ACUTE
     EE |  000000EE | LATIN SMALL LETTER I WITH CIRCUMFLEX
     EF |  000000EF | LATIN SMALL LETTER I WITH DIAERESIS
     F0 |  000000F0 | LATIN SMALL LETTER ETH (Icelandic)
     F1 |  000000F1 | LATIN SMALL LETTER N WITH TILDE
     F2 |  000000F2 | LATIN SMALL LETTER O WITH GRAVE
     F3 |  000000F3 | LATIN SMALL LETTER O WITH ACUTE
     F4 |  000000F4 | LATIN SMALL LETTER O WITH CIRCUMFLEX
     F5 |  000000F5 | LATIN SMALL LETTER O WITH TILDE
     F6 |  000000F6 | LATIN SMALL LETTER O WITH DIAERESIS
     F7 |  000000F7 | DIVISION SIGN
     F8 |  000000F8 | LATIN SMALL LETTER O WITH STROKE
     F9 |  000000F9 | LATIN SMALL LETTER U WITH GRAVE
     FA |  000000FA | LATIN SMALL LETTER U WITH ACUTE
     FB |  000000FB | LATIN SMALL LETTER U WITH CIRCUMFLEX
     FC |  000000FC | LATIN SMALL LETTER U WITH DIAERESIS
     FD |  000000FD | LATIN SMALL LETTER Y WITH ACUTE
     FE |  000000FE | LATIN SMALL LETTER THORN (Icelandic)
     FF |  000000FF | LATIN SMALL LETTER Y WITH DIAERESIS
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/GOST_19768_74.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for GOST_19768-74.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::GOST_19768_74;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x0004,
     0x0005,
     0x0006,
     0x0007,
     0x0008,
     0x0009,
     0x000a,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x0014,
     0x0015,
     0x0016,
     0x0017,
     0x0018,
     0x0019,
     0x001a,
     0x001b,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0020,
     0x0021,
     0x0022,
     0x0023,
     0x0024,
     0x0025,
     0x0026,
     0x0027,
     0x0028,
     0x0029,
     0x002a,
     0x002b,
     0x002c,
     0x002d,
     0x002e,
     0x002f,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x003a,
     0x003b,
     0x003c,
     0x003d,
     0x003e,
     0x003f,
     0x0040,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x005b,
     0x005c,
     0x005d,
     0x005e,
     0x005f,
     0x0060,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x007b,
     0x007c,
     0x007d,
     0x007e,
     0x007f,
     0x0080,
     0x0081,
     0x0082,
     0x0083,
     0x0084,
     0x0085,
     0x0086,
     0x0087,
     0x0088,
     0x0089,
     0x008a,
     0x008b,
     0x008c,
     0x008d,
     0x008e,
     0x008f,
     0x0090,
     0x0091,
     0x0092,
     0x0093,
     0x0094,
     0x0095,
     0x0096,
     0x0097,
     0x0098,
     0x0099,
     0x009a,
     0x009b,
     0x009c,
     0x009d,
     0x009e,
     0x009f,
     0x00a0,
     0x0401,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00ad,
     0xfffd,
     0xfffd,
     0x0410,
     0x0411,
     0x0412,
     0x0413,
     0x0414,
     0x0415,
     0x0416,
     0x0417,
     0x0418,
     0x0419,
     0x041a,
     0x041b,
     0x041c,
     0x041d,
     0x041e,
     0x041f,
     0x0420,
     0x0421,
     0x0422,
     0x0423,
     0x0424,
     0x0425,
     0x0426,
     0x0427,
     0x0428,
     0x0429,
     0x042a,
     0x042b,
     0x042c,
     0x042d,
     0x042e,
     0x042f,
     0x0430,
     0x0431,
     0x0432,
     0x0433,
     0x0434,
     0x0435,
     0x0436,
     0x0437,
     0x0438,
     0x0439,
     0x043a,
     0x043b,
     0x043c,
     0x043d,
     0x043e,
     0x043f,
     0x0440,
     0x0441,
     0x0442,
     0x0443,
     0x0444,
     0x0445,
     0x0446,
     0x0447,
     0x0448,
     0x0449,
     0x044a,
     0x044b,
     0x044c,
     0x044d,
     0x044e,
     0x044f,
     0xfffd,
     0x0451,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\x04",
     "\x05",
     "\x06",
     "\x07",
     "\x08",
     "\x09",
     "\x0a",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\x14",
     "\x15",
     "\x16",
     "\x17",
     "\x18",
     "\x19",
     "\x1a",
     "\x1b",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\x20",
     "\x21",
     "\x22",
     "\x23",
     "\x24",
     "\x25",
     "\x26",
     "\x27",
     "\x28",
     "\x29",
     "\x2a",
     "\x2b",
     "\x2c",
     "\x2d",
     "\x2e",
     "\x2f",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\x3a",
     "\x3b",
     "\x3c",
     "\x3d",
     "\x3e",
     "\x3f",
     "\x40",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\x5b",
     "\x5c",
     "\x5d",
     "\x5e",
     "\x5f",
     "\x60",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\x7b",
     "\x7c",
     "\x7d",
     "\x7e",
     "\x7f",
     "\xc2\x80",
     "\xc2\x81",
     "\xc2\x82",
     "\xc2\x83",
     "\xc2\x84",
     "\xc2\x85",
     "\xc2\x86",
     "\xc2\x87",
     "\xc2\x88",
     "\xc2\x89",
     "\xc2\x8a",
     "\xc2\x8b",
     "\xc2\x8c",
     "\xc2\x8d",
     "\xc2\x8e",
     "\xc2\x8f",
     "\xc2\x90",
     "\xc2\x91",
     "\xc2\x92",
     "\xc2\x93",
     "\xc2\x94",
     "\xc2\x95",
     "\xc2\x96",
     "\xc2\x97",
     "\xc2\x98",
     "\xc2\x99",
     "\xc2\x9a",
     "\xc2\x9b",
     "\xc2\x9c",
     "\xc2\x9d",
     "\xc2\x9e",
     "\xc2\x9f",
     "\xc2\xa0",
     "\xd0\x81",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc2\xad",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xd0\x90",
     "\xd0\x91",
     "\xd0\x92",
     "\xd0\x93",
     "\xd0\x94",
     "\xd0\x95",
     "\xd0\x96",
     "\xd0\x97",
     "\xd0\x98",
     "\xd0\x99",
     "\xd0\x9a",
     "\xd0\x9b",
     "\xd0\x9c",
     "\xd0\x9d",
     "\xd0\x9e",
     "\xd0\x9f",
     "\xd0\xa0",
     "\xd0\xa1",
     "\xd0\xa2",
     "\xd0\xa3",
     "\xd0\xa4",
     "\xd0\xa5",
     "\xd0\xa6",
     "\xd0\xa7",
     "\xd0\xa8",
     "\xd0\xa9",
     "\xd0\xaa",
     "\xd0\xab",
     "\xd0\xac",
     "\xd0\xad",
     "\xd0\xae",
     "\xd0\xaf",
     "\xd0\xb0",
     "\xd0\xb1",
     "\xd0\xb2",
     "\xd0\xb3",
     "\xd0\xb4",
     "\xd0\xb5",
     "\xd0\xb6",
     "\xd0\xb7",
     "\xd0\xb8",
     "\xd0\xb9",
     "\xd0\xba",
     "\xd0\xbb",
     "\xd0\xbc",
     "\xd0\xbd",
     "\xd0\xbe",
     "\xd0\xbf",
     "\xd1\x80",
     "\xd1\x81",
     "\xd1\x82",
     "\xd1\x83",
     "\xd1\x84",
     "\xd1\x85",
     "\xd1\x86",
     "\xd1\x87",
     "\xd1\x88",
     "\xd1\x89",
     "\xd1\x8a",
     "\xd1\x8b",
     "\xd1\x8c",
     "\xd1\x8d",
     "\xd1\x8e",
     "\xd1\x8f",
     "\xef\xbf\xbd",
     "\xd1\x91",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x04",
     0x00000005 => "\x05",
     0x00000006 => "\x06",
     0x00000007 => "\x07",
     0x00000008 => "\x08",
     0x00000009 => "\x09",
     0x0000000a => "\x0a",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x14",
     0x00000015 => "\x15",
     0x00000016 => "\x16",
     0x00000017 => "\x17",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x1a",
     0x0000001b => "\x1b",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x20",
     0x00000021 => "\x21",
     0x00000022 => "\x22",
     0x00000023 => "\x23",
     0x00000024 => "\x24",
     0x00000025 => "\x25",
     0x00000026 => "\x26",
     0x00000027 => "\x27",
     0x00000028 => "\x28",
     0x00000029 => "\x29",
     0x0000002a => "\x2a",
     0x0000002b => "\x2b",
     0x0000002c => "\x2c",
     0x0000002d => "\x2d",
     0x0000002e => "\x2e",
     0x0000002f => "\x2f",
     0x00000030 => "\x30",
     0x00000031 => "\x31",
     0x00000032 => "\x32",
     0x00000033 => "\x33",
     0x00000034 => "\x34",
     0x00000035 => "\x35",
     0x00000036 => "\x36",
     0x00000037 => "\x37",
     0x00000038 => "\x38",
     0x00000039 => "\x39",
     0x0000003a => "\x3a",
     0x0000003b => "\x3b",
     0x0000003c => "\x3c",
     0x0000003d => "\x3d",
     0x0000003e => "\x3e",
     0x0000003f => "\x3f",
     0x00000040 => "\x40",
     0x00000041 => "\x41",
     0x00000042 => "\x42",
     0x00000043 => "\x43",
     0x00000044 => "\x44",
     0x00000045 => "\x45",
     0x00000046 => "\x46",
     0x00000047 => "\x47",
     0x00000048 => "\x48",
     0x00000049 => "\x49",
     0x0000004a => "\x4a",
     0x0000004b => "\x4b",
     0x0000004c => "\x4c",
     0x0000004d => "\x4d",
     0x0000004e => "\x4e",
     0x0000004f => "\x4f",
     0x00000050 => "\x50",
     0x00000051 => "\x51",
     0x00000052 => "\x52",
     0x00000053 => "\x53",
     0x00000054 => "\x54",
     0x00000055 => "\x55",
     0x00000056 => "\x56",
     0x00000057 => "\x57",
     0x00000058 => "\x58",
     0x00000059 => "\x59",
     0x0000005a => "\x5a",
     0x0000005b => "\x5b",
     0x0000005c => "\x5c",
     0x0000005d => "\x5d",
     0x0000005e => "\x5e",
     0x0000005f => "\x5f",
     0x00000060 => "\x60",
     0x00000061 => "\x61",
     0x00000062 => "\x62",
     0x00000063 => "\x63",
     0x00000064 => "\x64",
     0x00000065 => "\x65",
     0x00000066 => "\x66",
     0x00000067 => "\x67",
     0x00000068 => "\x68",
     0x00000069 => "\x69",
     0x0000006a => "\x6a",
     0x0000006b => "\x6b",
     0x0000006c => "\x6c",
     0x0000006d => "\x6d",
     0x0000006e => "\x6e",
     0x0000006f => "\x6f",
     0x00000070 => "\x70",
     0x00000071 => "\x71",
     0x00000072 => "\x72",
     0x00000073 => "\x73",
     0x00000074 => "\x74",
     0x00000075 => "\x75",
     0x00000076 => "\x76",
     0x00000077 => "\x77",
     0x00000078 => "\x78",
     0x00000079 => "\x79",
     0x0000007a => "\x7a",
     0x0000007b => "\x7b",
     0x0000007c => "\x7c",
     0x0000007d => "\x7d",
     0x0000007e => "\x7e",
     0x0000007f => "\x7f",
     0x00000080 => "\x80",
     0x00000081 => "\x81",
     0x00000082 => "\x82",
     0x00000083 => "\x83",
     0x00000084 => "\x84",
     0x00000085 => "\x85",
     0x00000086 => "\x86",
     0x00000087 => "\x87",
     0x00000088 => "\x88",
     0x00000089 => "\x89",
     0x0000008a => "\x8a",
     0x0000008b => "\x8b",
     0x0000008c => "\x8c",
     0x0000008d => "\x8d",
     0x0000008e => "\x8e",
     0x0000008f => "\x8f",
     0x00000090 => "\x90",
     0x00000091 => "\x91",
     0x00000092 => "\x92",
     0x00000093 => "\x93",
     0x00000094 => "\x94",
     0x00000095 => "\x95",
     0x00000096 => "\x96",
     0x00000097 => "\x97",
     0x00000098 => "\x98",
     0x00000099 => "\x99",
     0x0000009a => "\x9a",
     0x0000009b => "\x9b",
     0x0000009c => "\x9c",
     0x0000009d => "\x9d",
     0x0000009e => "\x9e",
     0x0000009f => "\x9f",
     0x000000a0 => "\xa0",
     0x000000ad => "\xad",
     0x00000401 => "\xa1",
     0x00000410 => "\xb0",
     0x00000411 => "\xb1",
     0x00000412 => "\xb2",
     0x00000413 => "\xb3",
     0x00000414 => "\xb4",
     0x00000415 => "\xb5",
     0x00000416 => "\xb6",
     0x00000417 => "\xb7",
     0x00000418 => "\xb8",
     0x00000419 => "\xb9",
     0x0000041a => "\xba",
     0x0000041b => "\xbb",
     0x0000041c => "\xbc",
     0x0000041d => "\xbd",
     0x0000041e => "\xbe",
     0x0000041f => "\xbf",
     0x00000420 => "\xc0",
     0x00000421 => "\xc1",
     0x00000422 => "\xc2",
     0x00000423 => "\xc3",
     0x00000424 => "\xc4",
     0x00000425 => "\xc5",
     0x00000426 => "\xc6",
     0x00000427 => "\xc7",
     0x00000428 => "\xc8",
     0x00000429 => "\xc9",
     0x0000042a => "\xca",
     0x0000042b => "\xcb",
     0x0000042c => "\xcc",
     0x0000042d => "\xcd",
     0x0000042e => "\xce",
     0x0000042f => "\xcf",
     0x00000430 => "\xd0",
     0x00000431 => "\xd1",
     0x00000432 => "\xd2",
     0x00000433 => "\xd3",
     0x00000434 => "\xd4",
     0x00000435 => "\xd5",
     0x00000436 => "\xd6",
     0x00000437 => "\xd7",
     0x00000438 => "\xd8",
     0x00000439 => "\xd9",
     0x0000043a => "\xda",
     0x0000043b => "\xdb",
     0x0000043c => "\xdc",
     0x0000043d => "\xdd",
     0x0000043e => "\xde",
     0x0000043f => "\xdf",
     0x00000440 => "\xe0",
     0x00000441 => "\xe1",
     0x00000442 => "\xe2",
     0x00000443 => "\xe3",
     0x00000444 => "\xe4",
     0x00000445 => "\xe5",
     0x00000446 => "\xe6",
     0x00000447 => "\xe7",
     0x00000448 => "\xe8",
     0x00000449 => "\xe9",
     0x0000044a => "\xea",
     0x0000044b => "\xeb",
     0x0000044c => "\xec",
     0x0000044d => "\xed",
     0x0000044e => "\xee",
     0x0000044f => "\xef",
     0x00000451 => "\xf1",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::GOST_19768_74 - Conversion routines for GOST_19768_74
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for GOST_19768-74.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
   source: ECMA registry
  alias ST_SEV_358-88
  alias ISO-IR-153
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  00000004 | END OF TRANSMISSION (EOT)
     05 |  00000005 | ENQUIRY (ENQ)
     06 |  00000006 | ACKNOWLEDGE (ACK)
     07 |  00000007 | BELL (BEL)
     08 |  00000008 | BACKSPACE (BS)
     09 |  00000009 | CHARACTER TABULATION (HT)
     0A |  0000000A | LINE FEED (LF)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  00000014 | DEVICE CONTROL FOUR (DC4)
     15 |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     16 |  00000016 | SYNCHRONOUS IDLE (SYN)
     17 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  0000001A | SUBSTITUTE (SUB)
     1B |  0000001B | ESCAPE (ESC)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000020 | SPACE
     21 |  00000021 | EXCLAMATION MARK
     22 |  00000022 | QUOTATION MARK
     23 |  00000023 | NUMBER SIGN
     24 |  00000024 | DOLLAR SIGN
     25 |  00000025 | PERCENT SIGN
     26 |  00000026 | AMPERSAND
     27 |  00000027 | APOSTROPHE
     28 |  00000028 | LEFT PARENTHESIS
     29 |  00000029 | RIGHT PARENTHESIS
     2A |  0000002A | ASTERISK
     2B |  0000002B | PLUS SIGN
     2C |  0000002C | COMMA
     2D |  0000002D | HYPHEN-MINUS
     2E |  0000002E | FULL STOP
     2F |  0000002F | SOLIDUS
     30 |  00000030 | DIGIT ZERO
     31 |  00000031 | DIGIT ONE
     32 |  00000032 | DIGIT TWO
     33 |  00000033 | DIGIT THREE
     34 |  00000034 | DIGIT FOUR
     35 |  00000035 | DIGIT FIVE
     36 |  00000036 | DIGIT SIX
     37 |  00000037 | DIGIT SEVEN
     38 |  00000038 | DIGIT EIGHT
     39 |  00000039 | DIGIT NINE
     3A |  0000003A | COLON
     3B |  0000003B | SEMICOLON
     3C |  0000003C | LESS-THAN SIGN
     3D |  0000003D | EQUALS SIGN
     3E |  0000003E | GREATER-THAN SIGN
     3F |  0000003F | QUESTION MARK
     40 |  00000040 | COMMERCIAL AT
     41 |  00000041 | LATIN CAPITAL LETTER A
     42 |  00000042 | LATIN CAPITAL LETTER B
     43 |  00000043 | LATIN CAPITAL LETTER C
     44 |  00000044 | LATIN CAPITAL LETTER D
     45 |  00000045 | LATIN CAPITAL LETTER E
     46 |  00000046 | LATIN CAPITAL LETTER F
     47 |  00000047 | LATIN CAPITAL LETTER G
     48 |  00000048 | LATIN CAPITAL LETTER H
     49 |  00000049 | LATIN CAPITAL LETTER I
     4A |  0000004A | LATIN CAPITAL LETTER J
     4B |  0000004B | LATIN CAPITAL LETTER K
     4C |  0000004C | LATIN CAPITAL LETTER L
     4D |  0000004D | LATIN CAPITAL LETTER M
     4E |  0000004E | LATIN CAPITAL LETTER N
     4F |  0000004F | LATIN CAPITAL LETTER O
     50 |  00000050 | LATIN CAPITAL LETTER P
     51 |  00000051 | LATIN CAPITAL LETTER Q
     52 |  00000052 | LATIN CAPITAL LETTER R
     53 |  00000053 | LATIN CAPITAL LETTER S
     54 |  00000054 | LATIN CAPITAL LETTER T
     55 |  00000055 | LATIN CAPITAL LETTER U
     56 |  00000056 | LATIN CAPITAL LETTER V
     57 |  00000057 | LATIN CAPITAL LETTER W
     58 |  00000058 | LATIN CAPITAL LETTER X
     59 |  00000059 | LATIN CAPITAL LETTER Y
     5A |  0000005A | LATIN CAPITAL LETTER Z
     5B |  0000005B | LEFT SQUARE BRACKET
     5C |  0000005C | REVERSE SOLIDUS
     5D |  0000005D | RIGHT SQUARE BRACKET
     5E |  0000005E | CIRCUMFLEX ACCENT
     5F |  0000005F | LOW LINE
     60 |  00000060 | GRAVE ACCENT
     61 |  00000061 | LATIN SMALL LETTER A
     62 |  00000062 | LATIN SMALL LETTER B
     63 |  00000063 | LATIN SMALL LETTER C
     64 |  00000064 | LATIN SMALL LETTER D
     65 |  00000065 | LATIN SMALL LETTER E
     66 |  00000066 | LATIN SMALL LETTER F
     67 |  00000067 | LATIN SMALL LETTER G
     68 |  00000068 | LATIN SMALL LETTER H
     69 |  00000069 | LATIN SMALL LETTER I
     6A |  0000006A | LATIN SMALL LETTER J
     6B |  0000006B | LATIN SMALL LETTER K
     6C |  0000006C | LATIN SMALL LETTER L
     6D |  0000006D | LATIN SMALL LETTER M
     6E |  0000006E | LATIN SMALL LETTER N
     6F |  0000006F | LATIN SMALL LETTER O
     70 |  00000070 | LATIN SMALL LETTER P
     71 |  00000071 | LATIN SMALL LETTER Q
     72 |  00000072 | LATIN SMALL LETTER R
     73 |  00000073 | LATIN SMALL LETTER S
     74 |  00000074 | LATIN SMALL LETTER T
     75 |  00000075 | LATIN SMALL LETTER U
     76 |  00000076 | LATIN SMALL LETTER V
     77 |  00000077 | LATIN SMALL LETTER W
     78 |  00000078 | LATIN SMALL LETTER X
     79 |  00000079 | LATIN SMALL LETTER Y
     7A |  0000007A | LATIN SMALL LETTER Z
     7B |  0000007B | LEFT CURLY BRACKET
     7C |  0000007C | VERTICAL LINE
     7D |  0000007D | RIGHT CURLY BRACKET
     7E |  0000007E | TILDE
     7F |  0000007F | DELETE (DEL)
     80 |  00000080 | PADDING CHARACTER (PAD)
     81 |  00000081 | HIGH OCTET PRESET (HOP)
     82 |  00000082 | BREAK PERMITTED HERE (BPH)
     83 |  00000083 | NO BREAK HERE (NBH)
     84 |  00000084 | INDEX (IND)
     85 |  00000085 | NEXT LINE (NEL)
     86 |  00000086 | START OF SELECTED AREA (SSA)
     87 |  00000087 | END OF SELECTED AREA (ESA)
     88 |  00000088 | CHARACTER TABULATION SET (HTS)
     89 |  00000089 | CHARACTER TABULATION WITH JUSTIFICATION (HTJ)
     8A |  0000008A | LINE TABULATION SET (VTS)
     8B |  0000008B | PARTIAL LINE FORWARD (PLD)
     8C |  0000008C | PARTIAL LINE BACKWARD (PLU)
     8D |  0000008D | REVERSE LINE FEED (RI)
     8E |  0000008E | SINGLE-SHIFT TWO (SS2)
     8F |  0000008F | SINGLE-SHIFT THREE (SS3)
     90 |  00000090 | DEVICE CONTROL STRING (DCS)
     91 |  00000091 | PRIVATE USE ONE (PU1)
     92 |  00000092 | PRIVATE USE TWO (PU2)
     93 |  00000093 | SET TRANSMIT STATE (STS)
     94 |  00000094 | CANCEL CHARACTER (CCH)
     95 |  00000095 | MESSAGE WAITING (MW)
     96 |  00000096 | START OF GUARDED AREA (SPA)
     97 |  00000097 | END OF GUARDED AREA (EPA)
     98 |  00000098 | START OF STRING (SOS)
     99 |  00000099 | SINGLE GRAPHIC CHARACTER INTRODUCER (SGCI)
     9A |  0000009A | SINGLE CHARACTER INTRODUCER (SCI)
     9B |  0000009B | CONTROL SEQUENCE INTRODUCER (CSI)
     9C |  0000009C | STRING TERMINATOR (ST)
     9D |  0000009D | OPERATING SYSTEM COMMAND (OSC)
     9E |  0000009E | PRIVACY MESSAGE (PM)
     9F |  0000009F | APPLICATION PROGRAM COMMAND (APC)
     A0 |  000000A0 | NO-BREAK SPACE
     A1 |  00000401 | CYRILLIC CAPITAL LETTER IO
     AD |  000000AD | SOFT HYPHEN
     B0 |  00000410 | CYRILLIC CAPITAL LETTER A
     B1 |  00000411 | CYRILLIC CAPITAL LETTER BE
     B2 |  00000412 | CYRILLIC CAPITAL LETTER VE
     B3 |  00000413 | CYRILLIC CAPITAL LETTER GHE
     B4 |  00000414 | CYRILLIC CAPITAL LETTER DE
     B5 |  00000415 | CYRILLIC CAPITAL LETTER IE
     B6 |  00000416 | CYRILLIC CAPITAL LETTER ZHE
     B7 |  00000417 | CYRILLIC CAPITAL LETTER ZE
     B8 |  00000418 | CYRILLIC CAPITAL LETTER I
     B9 |  00000419 | CYRILLIC CAPITAL LETTER SHORT I
     BA |  0000041A | CYRILLIC CAPITAL LETTER KA
     BB |  0000041B | CYRILLIC CAPITAL LETTER EL
     BC |  0000041C | CYRILLIC CAPITAL LETTER EM
     BD |  0000041D | CYRILLIC CAPITAL LETTER EN
     BE |  0000041E | CYRILLIC CAPITAL LETTER O
     BF |  0000041F | CYRILLIC CAPITAL LETTER PE
     C0 |  00000420 | CYRILLIC CAPITAL LETTER ER
     C1 |  00000421 | CYRILLIC CAPITAL LETTER ES
     C2 |  00000422 | CYRILLIC CAPITAL LETTER TE
     C3 |  00000423 | CYRILLIC CAPITAL LETTER U
     C4 |  00000424 | CYRILLIC CAPITAL LETTER EF
     C5 |  00000425 | CYRILLIC CAPITAL LETTER HA
     C6 |  00000426 | CYRILLIC CAPITAL LETTER TSE
     C7 |  00000427 | CYRILLIC CAPITAL LETTER CHE
     C8 |  00000428 | CYRILLIC CAPITAL LETTER SHA
     C9 |  00000429 | CYRILLIC CAPITAL LETTER SHCHA
     CA |  0000042A | CYRILLIC CAPITAL LETTER HARD SIGN
     CB |  0000042B | CYRILLIC CAPITAL LETTER YERU
     CC |  0000042C | CYRILLIC CAPITAL LETTER SOFT SIGN
     CD |  0000042D | CYRILLIC CAPITAL LETTER E
     CE |  0000042E | CYRILLIC CAPITAL LETTER YU
     CF |  0000042F | CYRILLIC CAPITAL LETTER YA
     D0 |  00000430 | CYRILLIC SMALL LETTER A
     D1 |  00000431 | CYRILLIC SMALL LETTER BE
     D2 |  00000432 | CYRILLIC SMALL LETTER VE
     D3 |  00000433 | CYRILLIC SMALL LETTER GHE
     D4 |  00000434 | CYRILLIC SMALL LETTER DE
     D5 |  00000435 | CYRILLIC SMALL LETTER IE
     D6 |  00000436 | CYRILLIC SMALL LETTER ZHE
     D7 |  00000437 | CYRILLIC SMALL LETTER ZE
     D8 |  00000438 | CYRILLIC SMALL LETTER I
     D9 |  00000439 | CYRILLIC SMALL LETTER SHORT I
     DA |  0000043A | CYRILLIC SMALL LETTER KA
     DB |  0000043B | CYRILLIC SMALL LETTER EL
     DC |  0000043C | CYRILLIC SMALL LETTER EM
     DD |  0000043D | CYRILLIC SMALL LETTER EN
     DE |  0000043E | CYRILLIC SMALL LETTER O
     DF |  0000043F | CYRILLIC SMALL LETTER PE
     E0 |  00000440 | CYRILLIC SMALL LETTER ER
     E1 |  00000441 | CYRILLIC SMALL LETTER ES
     E2 |  00000442 | CYRILLIC SMALL LETTER TE
     E3 |  00000443 | CYRILLIC SMALL LETTER U
     E4 |  00000444 | CYRILLIC SMALL LETTER EF
     E5 |  00000445 | CYRILLIC SMALL LETTER HA
     E6 |  00000446 | CYRILLIC SMALL LETTER TSE
     E7 |  00000447 | CYRILLIC SMALL LETTER CHE
     E8 |  00000448 | CYRILLIC SMALL LETTER SHA
     E9 |  00000449 | CYRILLIC SMALL LETTER SHCHA
     EA |  0000044A | CYRILLIC SMALL LETTER HARD SIGN
     EB |  0000044B | CYRILLIC SMALL LETTER YERU
     EC |  0000044C | CYRILLIC SMALL LETTER SOFT SIGN
     ED |  0000044D | CYRILLIC SMALL LETTER E
     EE |  0000044E | CYRILLIC SMALL LETTER YU
     EF |  0000044F | CYRILLIC SMALL LETTER YA
     F1 |  00000451 | CYRILLIC SMALL LETTER IO
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/GREEK7.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for GREEK7.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::GREEK7;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x0004,
     0x0005,
     0x0006,
     0x0007,
     0x0008,
     0x0009,
     0x000a,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x0014,
     0x0015,
     0x0016,
     0x0017,
     0x0018,
     0x0019,
     0x001a,
     0x001b,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0020,
     0x0021,
     0x0022,
     0x0023,
     0x00a4,
     0x0025,
     0x0026,
     0x0027,
     0x0028,
     0x0029,
     0x002a,
     0x002b,
     0x002c,
     0x002d,
     0x002e,
     0x002f,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x003a,
     0x003b,
     0x003c,
     0x003d,
     0x003e,
     0x003f,
     0x0040,
     0x0391,
     0x0392,
     0x0393,
     0x0394,
     0x0395,
     0x0396,
     0x0397,
     0x0398,
     0x0399,
     0xfffd,
     0x039a,
     0x039b,
     0x039c,
     0x039d,
     0x039e,
     0x039f,
     0x03a0,
     0x03a1,
     0x03a3,
     0x03a4,
     0x03a5,
     0x03a6,
     0xfffd,
     0x03a7,
     0x03a8,
     0x03a9,
     0x005b,
     0x005c,
     0x005d,
     0x005e,
     0x005f,
     0x0060,
     0x03b1,
     0x03b2,
     0x03b3,
     0x03b4,
     0x03b5,
     0x03b6,
     0x03b7,
     0x03b8,
     0x03b9,
     0xfffd,
     0x03ba,
     0x03bb,
     0x03bc,
     0x03bd,
     0x03be,
     0x03bf,
     0x03c0,
     0x03c1,
     0x03c3,
     0x03c4,
     0x03c5,
     0x03c6,
     0x03c2,
     0x03c7,
     0x03c8,
     0x03c9,
     0x007b,
     0x007c,
     0x007d,
     0x203e,
     0x007f,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\x04",
     "\x05",
     "\x06",
     "\x07",
     "\x08",
     "\x09",
     "\x0a",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\x14",
     "\x15",
     "\x16",
     "\x17",
     "\x18",
     "\x19",
     "\x1a",
     "\x1b",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\x20",
     "\x21",
     "\x22",
     "\x23",
     "\xc2\xa4",
     "\x25",
     "\x26",
     "\x27",
     "\x28",
     "\x29",
     "\x2a",
     "\x2b",
     "\x2c",
     "\x2d",
     "\x2e",
     "\x2f",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\x3a",
     "\x3b",
     "\x3c",
     "\x3d",
     "\x3e",
     "\x3f",
     "\x40",
     "\xce\x91",
     "\xce\x92",
     "\xce\x93",
     "\xce\x94",
     "\xce\x95",
     "\xce\x96",
     "\xce\x97",
     "\xce\x98",
     "\xce\x99",
     "\xef\xbf\xbd",
     "\xce\x9a",
     "\xce\x9b",
     "\xce\x9c",
     "\xce\x9d",
     "\xce\x9e",
     "\xce\x9f",
     "\xce\xa0",
     "\xce\xa1",
     "\xce\xa3",
     "\xce\xa4",
     "\xce\xa5",
     "\xce\xa6",
     "\xef\xbf\xbd",
     "\xce\xa7",
     "\xce\xa8",
     "\xce\xa9",
     "\x5b",
     "\x5c",
     "\x5d",
     "\x5e",
     "\x5f",
     "\x60",
     "\xce\xb1",
     "\xce\xb2",
     "\xce\xb3",
     "\xce\xb4",
     "\xce\xb5",
     "\xce\xb6",
     "\xce\xb7",
     "\xce\xb8",
     "\xce\xb9",
     "\xef\xbf\xbd",
     "\xce\xba",
     "\xce\xbb",
     "\xce\xbc",
     "\xce\xbd",
     "\xce\xbe",
     "\xce\xbf",
     "\xcf\x80",
     "\xcf\x81",
     "\xcf\x83",
     "\xcf\x84",
     "\xcf\x85",
     "\xcf\x86",
     "\xcf\x82",
     "\xcf\x87",
     "\xcf\x88",
     "\xcf\x89",
     "\x7b",
     "\x7c",
     "\x7d",
     "\xe2\x80\xbe",
     "\x7f",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x04",
     0x00000005 => "\x05",
     0x00000006 => "\x06",
     0x00000007 => "\x07",
     0x00000008 => "\x08",
     0x00000009 => "\x09",
     0x0000000a => "\x0a",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x14",
     0x00000015 => "\x15",
     0x00000016 => "\x16",
     0x00000017 => "\x17",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x1a",
     0x0000001b => "\x1b",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x20",
     0x00000021 => "\x21",
     0x00000022 => "\x22",
     0x00000023 => "\x23",
     0x00000025 => "\x25",
     0x00000026 => "\x26",
     0x00000027 => "\x27",
     0x00000028 => "\x28",
     0x00000029 => "\x29",
     0x0000002a => "\x2a",
     0x0000002b => "\x2b",
     0x0000002c => "\x2c",
     0x0000002d => "\x2d",
     0x0000002e => "\x2e",
     0x0000002f => "\x2f",
     0x00000030 => "\x30",
     0x00000031 => "\x31",
     0x00000032 => "\x32",
     0x00000033 => "\x33",
     0x00000034 => "\x34",
     0x00000035 => "\x35",
     0x00000036 => "\x36",
     0x00000037 => "\x37",
     0x00000038 => "\x38",
     0x00000039 => "\x39",
     0x0000003a => "\x3a",
     0x0000003b => "\x3b",
     0x0000003c => "\x3c",
     0x0000003d => "\x3d",
     0x0000003e => "\x3e",
     0x0000003f => "\x3f",
     0x00000040 => "\x40",
     0x0000005b => "\x5b",
     0x0000005c => "\x5c",
     0x0000005d => "\x5d",
     0x0000005e => "\x5e",
     0x0000005f => "\x5f",
     0x00000060 => "\x60",
     0x0000007b => "\x7b",
     0x0000007c => "\x7c",
     0x0000007d => "\x7d",
     0x0000007f => "\x7f",
     0x000000a4 => "\x24",
     0x00000391 => "\x41",
     0x00000392 => "\x42",
     0x00000393 => "\x43",
     0x00000394 => "\x44",
     0x00000395 => "\x45",
     0x00000396 => "\x46",
     0x00000397 => "\x47",
     0x00000398 => "\x48",
     0x00000399 => "\x49",
     0x0000039a => "\x4b",
     0x0000039b => "\x4c",
     0x0000039c => "\x4d",
     0x0000039d => "\x4e",
     0x0000039e => "\x4f",
     0x0000039f => "\x50",
     0x000003a0 => "\x51",
     0x000003a1 => "\x52",
     0x000003a3 => "\x53",
     0x000003a4 => "\x54",
     0x000003a5 => "\x55",
     0x000003a6 => "\x56",
     0x000003a7 => "\x58",
     0x000003a8 => "\x59",
     0x000003a9 => "\x5a",
     0x000003b1 => "\x61",
     0x000003b2 => "\x62",
     0x000003b3 => "\x63",
     0x000003b4 => "\x64",
     0x000003b5 => "\x65",
     0x000003b6 => "\x66",
     0x000003b7 => "\x67",
     0x000003b8 => "\x68",
     0x000003b9 => "\x69",
     0x000003ba => "\x6b",
     0x000003bb => "\x6c",
     0x000003bc => "\x6d",
     0x000003bd => "\x6e",
     0x000003be => "\x6f",
     0x000003bf => "\x70",
     0x000003c0 => "\x71",
     0x000003c1 => "\x72",
     0x000003c2 => "\x77",
     0x000003c3 => "\x73",
     0x000003c4 => "\x74",
     0x000003c5 => "\x75",
     0x000003c6 => "\x76",
     0x000003c7 => "\x78",
     0x000003c8 => "\x79",
     0x000003c9 => "\x7a",
     0x0000203e => "\x7e",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::GREEK7 - Conversion routines for GREEK7
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for GREEK7.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
  repertoiremap: mnemonic,ds
   source: ECMA registry
  alias ISO-IR-88
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  00000004 | END OF TRANSMISSION (EOT)
     05 |  00000005 | ENQUIRY (ENQ)
     06 |  00000006 | ACKNOWLEDGE (ACK)
     07 |  00000007 | BELL (BEL)
     08 |  00000008 | BACKSPACE (BS)
     09 |  00000009 | CHARACTER TABULATION (HT)
     0A |  0000000A | LINE FEED (LF)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  00000014 | DEVICE CONTROL FOUR (DC4)
     15 |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     16 |  00000016 | SYNCHRONOUS IDLE (SYN)
     17 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  0000001A | SUBSTITUTE (SUB)
     1B |  0000001B | ESCAPE (ESC)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000020 | SPACE
     21 |  00000021 | EXCLAMATION MARK
     22 |  00000022 | QUOTATION MARK
     23 |  00000023 | NUMBER SIGN
     24 |  000000A4 | CURRENCY SIGN
     25 |  00000025 | PERCENT SIGN
     26 |  00000026 | AMPERSAND
     27 |  00000027 | APOSTROPHE
     28 |  00000028 | LEFT PARENTHESIS
     29 |  00000029 | RIGHT PARENTHESIS
     2A |  0000002A | ASTERISK
     2B |  0000002B | PLUS SIGN
     2C |  0000002C | COMMA
     2D |  0000002D | HYPHEN-MINUS
     2E |  0000002E | FULL STOP
     2F |  0000002F | SOLIDUS
     30 |  00000030 | DIGIT ZERO
     31 |  00000031 | DIGIT ONE
     32 |  00000032 | DIGIT TWO
     33 |  00000033 | DIGIT THREE
     34 |  00000034 | DIGIT FOUR
     35 |  00000035 | DIGIT FIVE
     36 |  00000036 | DIGIT SIX
     37 |  00000037 | DIGIT SEVEN
     38 |  00000038 | DIGIT EIGHT
     39 |  00000039 | DIGIT NINE
     3A |  0000003A | COLON
     3B |  0000003B | SEMICOLON
     3C |  0000003C | LESS-THAN SIGN
     3D |  0000003D | EQUALS SIGN
     3E |  0000003E | GREATER-THAN SIGN
     3F |  0000003F | QUESTION MARK
     40 |  00000040 | COMMERCIAL AT
     41 |  00000391 | GREEK CAPITAL LETTER ALPHA
     42 |  00000392 | GREEK CAPITAL LETTER BETA
     43 |  00000393 | GREEK CAPITAL LETTER GAMMA
     44 |  00000394 | GREEK CAPITAL LETTER DELTA
     45 |  00000395 | GREEK CAPITAL LETTER EPSILON
     46 |  00000396 | GREEK CAPITAL LETTER ZETA
     47 |  00000397 | GREEK CAPITAL LETTER ETA
     48 |  00000398 | GREEK CAPITAL LETTER THETA
     49 |  00000399 | GREEK CAPITAL LETTER IOTA
     4B |  0000039A | GREEK CAPITAL LETTER KAPPA
     4C |  0000039B | GREEK CAPITAL LETTER LAMDA
     4D |  0000039C | GREEK CAPITAL LETTER MU
     4E |  0000039D | GREEK CAPITAL LETTER NU
     4F |  0000039E | GREEK CAPITAL LETTER XI
     50 |  0000039F | GREEK CAPITAL LETTER OMICRON
     51 |  000003A0 | GREEK CAPITAL LETTER PI
     52 |  000003A1 | GREEK CAPITAL LETTER RHO
     53 |  000003A3 | GREEK CAPITAL LETTER SIGMA
     54 |  000003A4 | GREEK CAPITAL LETTER TAU
     55 |  000003A5 | GREEK CAPITAL LETTER UPSILON
     56 |  000003A6 | GREEK CAPITAL LETTER PHI
     58 |  000003A7 | GREEK CAPITAL LETTER CHI
     59 |  000003A8 | GREEK CAPITAL LETTER PSI
     5A |  000003A9 | GREEK CAPITAL LETTER OMEGA
     5B |  0000005B | LEFT SQUARE BRACKET
     5C |  0000005C | REVERSE SOLIDUS
     5D |  0000005D | RIGHT SQUARE BRACKET
     5E |  0000005E | CIRCUMFLEX ACCENT
     5F |  0000005F | LOW LINE
     60 |  00000060 | GRAVE ACCENT
     61 |  000003B1 | GREEK SMALL LETTER ALPHA
     62 |  000003B2 | GREEK SMALL LETTER BETA
     63 |  000003B3 | GREEK SMALL LETTER GAMMA
     64 |  000003B4 | GREEK SMALL LETTER DELTA
     65 |  000003B5 | GREEK SMALL LETTER EPSILON
     66 |  000003B6 | GREEK SMALL LETTER ZETA
     67 |  000003B7 | GREEK SMALL LETTER ETA
     68 |  000003B8 | GREEK SMALL LETTER THETA
     69 |  000003B9 | GREEK SMALL LETTER IOTA
     6B |  000003BA | GREEK SMALL LETTER KAPPA
     6C |  000003BB | GREEK SMALL LETTER LAMDA
     6D |  000003BC | GREEK SMALL LETTER MU
     6E |  000003BD | GREEK SMALL LETTER NU
     6F |  000003BE | GREEK SMALL LETTER XI
     70 |  000003BF | GREEK SMALL LETTER OMICRON
     71 |  000003C0 | GREEK SMALL LETTER PI
     72 |  000003C1 | GREEK SMALL LETTER RHO
     73 |  000003C3 | GREEK SMALL LETTER SIGMA
     74 |  000003C4 | GREEK SMALL LETTER TAU
     75 |  000003C5 | GREEK SMALL LETTER UPSILON
     76 |  000003C6 | GREEK SMALL LETTER PHI
     77 |  000003C2 | GREEK SMALL LETTER FINAL SIGMA
     78 |  000003C7 | GREEK SMALL LETTER CHI
     79 |  000003C8 | GREEK SMALL LETTER PSI
     7A |  000003C9 | GREEK SMALL LETTER OMEGA
     7B |  0000007B | LEFT CURLY BRACKET
     7C |  0000007C | VERTICAL LINE
     7D |  0000007D | RIGHT CURLY BRACKET
     7E |  0000203E | OVERLINE
     7F |  0000007F | DELETE (DEL)
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/GREEK7_OLD.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for GREEK7-OLD.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::GREEK7_OLD;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x0004,
     0x0005,
     0x0006,
     0x0007,
     0x0008,
     0x0009,
     0x000a,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x0014,
     0x0015,
     0x0016,
     0x0017,
     0x0018,
     0x0019,
     0x001a,
     0x001b,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0020,
     0x0021,
     0x0022,
     0x00a3,
     0x0024,
     0x0025,
     0x0026,
     0x0027,
     0x0028,
     0x0029,
     0x002a,
     0x002b,
     0x002c,
     0x002d,
     0x002e,
     0x002f,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x003a,
     0x003b,
     0x003c,
     0x003d,
     0x003e,
     0x003f,
     0x00b4,
     0x03b1,
     0x03b2,
     0x03c8,
     0x03b4,
     0x03b5,
     0x03c6,
     0x03b3,
     0x03b7,
     0x03b9,
     0x03be,
     0x03ba,
     0x03bb,
     0x03bc,
     0x03bd,
     0x03bf,
     0x03c0,
     0x037a,
     0x03c1,
     0x03c3,
     0x03c4,
     0x03b8,
     0x03c9,
     0x03c2,
     0x03c7,
     0x03c5,
     0x03b6,
     0x1fcf,
     0x1fbf,
     0x1fce,
     0x007e,
     0x005f,
     0x0060,
     0x0391,
     0x0392,
     0x03a8,
     0x0394,
     0x0395,
     0x03a6,
     0x0393,
     0x0397,
     0x0399,
     0x039e,
     0x039a,
     0x039b,
     0x039c,
     0x039d,
     0x039f,
     0x03a0,
     0xfffd,
     0x03a1,
     0x03a3,
     0x03a4,
     0x0398,
     0x03a9,
     0x00b7,
     0x03a7,
     0x03a5,
     0x0396,
     0x1fdf,
     0x1ffe,
     0x1fde,
     0x00a8,
     0x007f,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\x04",
     "\x05",
     "\x06",
     "\x07",
     "\x08",
     "\x09",
     "\x0a",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\x14",
     "\x15",
     "\x16",
     "\x17",
     "\x18",
     "\x19",
     "\x1a",
     "\x1b",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\x20",
     "\x21",
     "\x22",
     "\xc2\xa3",
     "\x24",
     "\x25",
     "\x26",
     "\x27",
     "\x28",
     "\x29",
     "\x2a",
     "\x2b",
     "\x2c",
     "\x2d",
     "\x2e",
     "\x2f",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\x3a",
     "\x3b",
     "\x3c",
     "\x3d",
     "\x3e",
     "\x3f",
     "\xc2\xb4",
     "\xce\xb1",
     "\xce\xb2",
     "\xcf\x88",
     "\xce\xb4",
     "\xce\xb5",
     "\xcf\x86",
     "\xce\xb3",
     "\xce\xb7",
     "\xce\xb9",
     "\xce\xbe",
     "\xce\xba",
     "\xce\xbb",
     "\xce\xbc",
     "\xce\xbd",
     "\xce\xbf",
     "\xcf\x80",
     "\xcd\xba",
     "\xcf\x81",
     "\xcf\x83",
     "\xcf\x84",
     "\xce\xb8",
     "\xcf\x89",
     "\xcf\x82",
     "\xcf\x87",
     "\xcf\x85",
     "\xce\xb6",
     "\xe1\xbf\x8f",
     "\xe1\xbe\xbf",
     "\xe1\xbf\x8e",
     "\x7e",
     "\x5f",
     "\x60",
     "\xce\x91",
     "\xce\x92",
     "\xce\xa8",
     "\xce\x94",
     "\xce\x95",
     "\xce\xa6",
     "\xce\x93",
     "\xce\x97",
     "\xce\x99",
     "\xce\x9e",
     "\xce\x9a",
     "\xce\x9b",
     "\xce\x9c",
     "\xce\x9d",
     "\xce\x9f",
     "\xce\xa0",
     "\xef\xbf\xbd",
     "\xce\xa1",
     "\xce\xa3",
     "\xce\xa4",
     "\xce\x98",
     "\xce\xa9",
     "\xc2\xb7",
     "\xce\xa7",
     "\xce\xa5",
     "\xce\x96",
     "\xe1\xbf\x9f",
     "\xe1\xbf\xbe",
     "\xe1\xbf\x9e",
     "\xc2\xa8",
     "\x7f",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x04",
     0x00000005 => "\x05",
     0x00000006 => "\x06",
     0x00000007 => "\x07",
     0x00000008 => "\x08",
     0x00000009 => "\x09",
     0x0000000a => "\x0a",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x14",
     0x00000015 => "\x15",
     0x00000016 => "\x16",
     0x00000017 => "\x17",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x1a",
     0x0000001b => "\x1b",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x20",
     0x00000021 => "\x21",
     0x00000022 => "\x22",
     0x00000024 => "\x24",
     0x00000025 => "\x25",
     0x00000026 => "\x26",
     0x00000027 => "\x27",
     0x00000028 => "\x28",
     0x00000029 => "\x29",
     0x0000002a => "\x2a",
     0x0000002b => "\x2b",
     0x0000002c => "\x2c",
     0x0000002d => "\x2d",
     0x0000002e => "\x2e",
     0x0000002f => "\x2f",
     0x00000030 => "\x30",
     0x00000031 => "\x31",
     0x00000032 => "\x32",
     0x00000033 => "\x33",
     0x00000034 => "\x34",
     0x00000035 => "\x35",
     0x00000036 => "\x36",
     0x00000037 => "\x37",
     0x00000038 => "\x38",
     0x00000039 => "\x39",
     0x0000003a => "\x3a",
     0x0000003b => "\x3b",
     0x0000003c => "\x3c",
     0x0000003d => "\x3d",
     0x0000003e => "\x3e",
     0x0000003f => "\x3f",
     0x0000005f => "\x5f",
     0x00000060 => "\x60",
     0x0000007e => "\x5e",
     0x0000007f => "\x7f",
     0x000000a3 => "\x23",
     0x000000a8 => "\x7e",
     0x000000b4 => "\x40",
     0x000000b7 => "\x77",
     0x0000037a => "\x51",
     0x00000391 => "\x61",
     0x00000392 => "\x62",
     0x00000393 => "\x67",
     0x00000394 => "\x64",
     0x00000395 => "\x65",
     0x00000396 => "\x7a",
     0x00000397 => "\x68",
     0x00000398 => "\x75",
     0x00000399 => "\x69",
     0x0000039a => "\x6b",
     0x0000039b => "\x6c",
     0x0000039c => "\x6d",
     0x0000039d => "\x6e",
     0x0000039e => "\x6a",
     0x0000039f => "\x6f",
     0x000003a0 => "\x70",
     0x000003a1 => "\x72",
     0x000003a3 => "\x73",
     0x000003a4 => "\x74",
     0x000003a5 => "\x79",
     0x000003a6 => "\x66",
     0x000003a7 => "\x78",
     0x000003a8 => "\x63",
     0x000003a9 => "\x76",
     0x000003b1 => "\x41",
     0x000003b2 => "\x42",
     0x000003b3 => "\x47",
     0x000003b4 => "\x44",
     0x000003b5 => "\x45",
     0x000003b6 => "\x5a",
     0x000003b7 => "\x48",
     0x000003b8 => "\x55",
     0x000003b9 => "\x49",
     0x000003ba => "\x4b",
     0x000003bb => "\x4c",
     0x000003bc => "\x4d",
     0x000003bd => "\x4e",
     0x000003be => "\x4a",
     0x000003bf => "\x4f",
     0x000003c0 => "\x50",
     0x000003c1 => "\x52",
     0x000003c2 => "\x57",
     0x000003c3 => "\x53",
     0x000003c4 => "\x54",
     0x000003c5 => "\x59",
     0x000003c6 => "\x46",
     0x000003c7 => "\x58",
     0x000003c8 => "\x43",
     0x000003c9 => "\x56",
     0x00001fbf => "\x5c",
     0x00001fce => "\x5d",
     0x00001fcf => "\x5b",
     0x00001fde => "\x7d",
     0x00001fdf => "\x7b",
     0x00001ffe => "\x7c",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::GREEK7_OLD - Conversion routines for GREEK7_OLD
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for GREEK7-OLD.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
   source: ECMA registry
  alias ISO-IR-18
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  00000004 | END OF TRANSMISSION (EOT)
     05 |  00000005 | ENQUIRY (ENQ)
     06 |  00000006 | ACKNOWLEDGE (ACK)
     07 |  00000007 | BELL (BEL)
     08 |  00000008 | BACKSPACE (BS)
     09 |  00000009 | CHARACTER TABULATION (HT)
     0A |  0000000A | LINE FEED (LF)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  00000014 | DEVICE CONTROL FOUR (DC4)
     15 |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     16 |  00000016 | SYNCHRONOUS IDLE (SYN)
     17 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  0000001A | SUBSTITUTE (SUB)
     1B |  0000001B | ESCAPE (ESC)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000020 | SPACE
     21 |  00000021 | EXCLAMATION MARK
     22 |  00000022 | QUOTATION MARK
     23 |  000000A3 | POUND SIGN
     24 |  00000024 | DOLLAR SIGN
     25 |  00000025 | PERCENT SIGN
     26 |  00000026 | AMPERSAND
     27 |  00000027 | APOSTROPHE
     28 |  00000028 | LEFT PARENTHESIS
     29 |  00000029 | RIGHT PARENTHESIS
     2A |  0000002A | ASTERISK
     2B |  0000002B | PLUS SIGN
     2C |  0000002C | COMMA
     2D |  0000002D | HYPHEN-MINUS
     2E |  0000002E | FULL STOP
     2F |  0000002F | SOLIDUS
     30 |  00000030 | DIGIT ZERO
     31 |  00000031 | DIGIT ONE
     32 |  00000032 | DIGIT TWO
     33 |  00000033 | DIGIT THREE
     34 |  00000034 | DIGIT FOUR
     35 |  00000035 | DIGIT FIVE
     36 |  00000036 | DIGIT SIX
     37 |  00000037 | DIGIT SEVEN
     38 |  00000038 | DIGIT EIGHT
     39 |  00000039 | DIGIT NINE
     3A |  0000003A | COLON
     3B |  0000003B | SEMICOLON
     3C |  0000003C | LESS-THAN SIGN
     3D |  0000003D | EQUALS SIGN
     3E |  0000003E | GREATER-THAN SIGN
     3F |  0000003F | QUESTION MARK
     40 |  000000B4 | ACUTE ACCENT
     41 |  000003B1 | GREEK SMALL LETTER ALPHA
     42 |  000003B2 | GREEK SMALL LETTER BETA
     43 |  000003C8 | GREEK SMALL LETTER PSI
     44 |  000003B4 | GREEK SMALL LETTER DELTA
     45 |  000003B5 | GREEK SMALL LETTER EPSILON
     46 |  000003C6 | GREEK SMALL LETTER PHI
     47 |  000003B3 | GREEK SMALL LETTER GAMMA
     48 |  000003B7 | GREEK SMALL LETTER ETA
     49 |  000003B9 | GREEK SMALL LETTER IOTA
     4A |  000003BE | GREEK SMALL LETTER XI
     4B |  000003BA | GREEK SMALL LETTER KAPPA
     4C |  000003BB | GREEK SMALL LETTER LAMDA
     4D |  000003BC | GREEK SMALL LETTER MU
     4E |  000003BD | GREEK SMALL LETTER NU
     4F |  000003BF | GREEK SMALL LETTER OMICRON
     50 |  000003C0 | GREEK SMALL LETTER PI
     51 |  0000037A | GREEK YPOGEGRAMMENI
     52 |  000003C1 | GREEK SMALL LETTER RHO
     53 |  000003C3 | GREEK SMALL LETTER SIGMA
     54 |  000003C4 | GREEK SMALL LETTER TAU
     55 |  000003B8 | GREEK SMALL LETTER THETA
     56 |  000003C9 | GREEK SMALL LETTER OMEGA
     57 |  000003C2 | GREEK SMALL LETTER FINAL SIGMA
     58 |  000003C7 | GREEK SMALL LETTER CHI
     59 |  000003C5 | GREEK SMALL LETTER UPSILON
     5A |  000003B6 | GREEK SMALL LETTER ZETA
     5B |  00001FCF | GREEK PSILI AND PERISPOMENI
     5C |  00001FBF | GREEK PSILI
     5D |  00001FCE | GREEK PSILI AND OXIA
     5E |  0000007E | TILDE
     5F |  0000005F | LOW LINE
     60 |  00000060 | GRAVE ACCENT
     61 |  00000391 | GREEK CAPITAL LETTER ALPHA
     62 |  00000392 | GREEK CAPITAL LETTER BETA
     63 |  000003A8 | GREEK CAPITAL LETTER PSI
     64 |  00000394 | GREEK CAPITAL LETTER DELTA
     65 |  00000395 | GREEK CAPITAL LETTER EPSILON
     66 |  000003A6 | GREEK CAPITAL LETTER PHI
     67 |  00000393 | GREEK CAPITAL LETTER GAMMA
     68 |  00000397 | GREEK CAPITAL LETTER ETA
     69 |  00000399 | GREEK CAPITAL LETTER IOTA
     6A |  0000039E | GREEK CAPITAL LETTER XI
     6B |  0000039A | GREEK CAPITAL LETTER KAPPA
     6C |  0000039B | GREEK CAPITAL LETTER LAMDA
     6D |  0000039C | GREEK CAPITAL LETTER MU
     6E |  0000039D | GREEK CAPITAL LETTER NU
     6F |  0000039F | GREEK CAPITAL LETTER OMICRON
     70 |  000003A0 | GREEK CAPITAL LETTER PI
     72 |  000003A1 | GREEK CAPITAL LETTER RHO
     73 |  000003A3 | GREEK CAPITAL LETTER SIGMA
     74 |  000003A4 | GREEK CAPITAL LETTER TAU
     75 |  00000398 | GREEK CAPITAL LETTER THETA
     76 |  000003A9 | GREEK CAPITAL LETTER OMEGA
     77 |  000000B7 | MIDDLE DOT
     78 |  000003A7 | GREEK CAPITAL LETTER CHI
     79 |  000003A5 | GREEK CAPITAL LETTER UPSILON
     7A |  00000396 | GREEK CAPITAL LETTER ZETA
     7B |  00001FDF | GREEK DASIA AND PERISPOMENI
     7C |  00001FFE | GREEK DASIA
     7D |  00001FDE | GREEK DASIA AND OXIA
     7E |  000000A8 | DIAERESIS
     7F |  0000007F | DELETE (DEL)
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/GREEK_CCITT.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for GREEK-CCITT.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::GREEK_CCITT;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x0004,
     0x0005,
     0x0006,
     0x0007,
     0x0008,
     0x0009,
     0x000a,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x0014,
     0x0015,
     0x0016,
     0x0017,
     0x0018,
     0x0019,
     0x001a,
     0x001b,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0020,
     0x0021,
     0x0022,
     0x0023,
     0x00a4,
     0x0025,
     0x0026,
     0x0027,
     0x0028,
     0x0029,
     0x002a,
     0x002b,
     0x002c,
     0x002d,
     0x002e,
     0x002f,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x003a,
     0x003b,
     0x003c,
     0x003d,
     0x003e,
     0x003f,
     0x0040,
     0x0391,
     0x0392,
     0x0393,
     0x0394,
     0x0395,
     0x0396,
     0x0397,
     0x0398,
     0x0399,
     0x039a,
     0x039b,
     0x039c,
     0x039d,
     0x039e,
     0x039f,
     0x03a0,
     0x03a1,
     0xfffd,
     0x03a3,
     0x03a4,
     0x03a5,
     0x03a6,
     0x03a7,
     0x03a8,
     0x03a9,
     0xfffd,
     0x005b,
     0x005c,
     0x005d,
     0x005e,
     0x005f,
     0xfffd,
     0x03b1,
     0x03b2,
     0x03b3,
     0x03b4,
     0x03b5,
     0x03b6,
     0x03b7,
     0x03b8,
     0x03b9,
     0x03ba,
     0x03bb,
     0x03bc,
     0x03bd,
     0x03be,
     0x03bf,
     0x03c0,
     0x03c1,
     0x03c2,
     0x03c3,
     0x03c4,
     0x03c5,
     0x03c6,
     0x03c7,
     0x03c8,
     0x03c9,
     0xfffd,
     0x007b,
     0x007c,
     0x007d,
     0x00af,
     0x007f,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\x04",
     "\x05",
     "\x06",
     "\x07",
     "\x08",
     "\x09",
     "\x0a",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\x14",
     "\x15",
     "\x16",
     "\x17",
     "\x18",
     "\x19",
     "\x1a",
     "\x1b",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\x20",
     "\x21",
     "\x22",
     "\x23",
     "\xc2\xa4",
     "\x25",
     "\x26",
     "\x27",
     "\x28",
     "\x29",
     "\x2a",
     "\x2b",
     "\x2c",
     "\x2d",
     "\x2e",
     "\x2f",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\x3a",
     "\x3b",
     "\x3c",
     "\x3d",
     "\x3e",
     "\x3f",
     "\x40",
     "\xce\x91",
     "\xce\x92",
     "\xce\x93",
     "\xce\x94",
     "\xce\x95",
     "\xce\x96",
     "\xce\x97",
     "\xce\x98",
     "\xce\x99",
     "\xce\x9a",
     "\xce\x9b",
     "\xce\x9c",
     "\xce\x9d",
     "\xce\x9e",
     "\xce\x9f",
     "\xce\xa0",
     "\xce\xa1",
     "\xef\xbf\xbd",
     "\xce\xa3",
     "\xce\xa4",
     "\xce\xa5",
     "\xce\xa6",
     "\xce\xa7",
     "\xce\xa8",
     "\xce\xa9",
     "\xef\xbf\xbd",
     "\x5b",
     "\x5c",
     "\x5d",
     "\x5e",
     "\x5f",
     "\xef\xbf\xbd",
     "\xce\xb1",
     "\xce\xb2",
     "\xce\xb3",
     "\xce\xb4",
     "\xce\xb5",
     "\xce\xb6",
     "\xce\xb7",
     "\xce\xb8",
     "\xce\xb9",
     "\xce\xba",
     "\xce\xbb",
     "\xce\xbc",
     "\xce\xbd",
     "\xce\xbe",
     "\xce\xbf",
     "\xcf\x80",
     "\xcf\x81",
     "\xcf\x82",
     "\xcf\x83",
     "\xcf\x84",
     "\xcf\x85",
     "\xcf\x86",
     "\xcf\x87",
     "\xcf\x88",
     "\xcf\x89",
     "\xef\xbf\xbd",
     "\x7b",
     "\x7c",
     "\x7d",
     "\xc2\xaf",
     "\x7f",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x04",
     0x00000005 => "\x05",
     0x00000006 => "\x06",
     0x00000007 => "\x07",
     0x00000008 => "\x08",
     0x00000009 => "\x09",
     0x0000000a => "\x0a",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x14",
     0x00000015 => "\x15",
     0x00000016 => "\x16",
     0x00000017 => "\x17",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x1a",
     0x0000001b => "\x1b",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x20",
     0x00000021 => "\x21",
     0x00000022 => "\x22",
     0x00000023 => "\x23",
     0x00000025 => "\x25",
     0x00000026 => "\x26",
     0x00000027 => "\x27",
     0x00000028 => "\x28",
     0x00000029 => "\x29",
     0x0000002a => "\x2a",
     0x0000002b => "\x2b",
     0x0000002c => "\x2c",
     0x0000002d => "\x2d",
     0x0000002e => "\x2e",
     0x0000002f => "\x2f",
     0x00000030 => "\x30",
     0x00000031 => "\x31",
     0x00000032 => "\x32",
     0x00000033 => "\x33",
     0x00000034 => "\x34",
     0x00000035 => "\x35",
     0x00000036 => "\x36",
     0x00000037 => "\x37",
     0x00000038 => "\x38",
     0x00000039 => "\x39",
     0x0000003a => "\x3a",
     0x0000003b => "\x3b",
     0x0000003c => "\x3c",
     0x0000003d => "\x3d",
     0x0000003e => "\x3e",
     0x0000003f => "\x3f",
     0x00000040 => "\x40",
     0x0000005b => "\x5b",
     0x0000005c => "\x5c",
     0x0000005d => "\x5d",
     0x0000005e => "\x5e",
     0x0000005f => "\x5f",
     0x0000007b => "\x7b",
     0x0000007c => "\x7c",
     0x0000007d => "\x7d",
     0x0000007f => "\x7f",
     0x000000a4 => "\x24",
     0x000000af => "\x7e",
     0x00000391 => "\x41",
     0x00000392 => "\x42",
     0x00000393 => "\x43",
     0x00000394 => "\x44",
     0x00000395 => "\x45",
     0x00000396 => "\x46",
     0x00000397 => "\x47",
     0x00000398 => "\x48",
     0x00000399 => "\x49",
     0x0000039a => "\x4a",
     0x0000039b => "\x4b",
     0x0000039c => "\x4c",
     0x0000039d => "\x4d",
     0x0000039e => "\x4e",
     0x0000039f => "\x4f",
     0x000003a0 => "\x50",
     0x000003a1 => "\x51",
     0x000003a3 => "\x53",
     0x000003a4 => "\x54",
     0x000003a5 => "\x55",
     0x000003a6 => "\x56",
     0x000003a7 => "\x57",
     0x000003a8 => "\x58",
     0x000003a9 => "\x59",
     0x000003b1 => "\x61",
     0x000003b2 => "\x62",
     0x000003b3 => "\x63",
     0x000003b4 => "\x64",
     0x000003b5 => "\x65",
     0x000003b6 => "\x66",
     0x000003b7 => "\x67",
     0x000003b8 => "\x68",
     0x000003b9 => "\x69",
     0x000003ba => "\x6a",
     0x000003bb => "\x6b",
     0x000003bc => "\x6c",
     0x000003bd => "\x6d",
     0x000003be => "\x6e",
     0x000003bf => "\x6f",
     0x000003c0 => "\x70",
     0x000003c1 => "\x71",
     0x000003c2 => "\x72",
     0x000003c3 => "\x73",
     0x000003c4 => "\x74",
     0x000003c5 => "\x75",
     0x000003c6 => "\x76",
     0x000003c7 => "\x77",
     0x000003c8 => "\x78",
     0x000003c9 => "\x79",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::GREEK_CCITT - Conversion routines for GREEK_CCITT
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for GREEK-CCITT.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
  repertoiremap: mnemonic,ds
   source: ECMA registry
  alias ISO-IR-150
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  00000004 | END OF TRANSMISSION (EOT)
     05 |  00000005 | ENQUIRY (ENQ)
     06 |  00000006 | ACKNOWLEDGE (ACK)
     07 |  00000007 | BELL (BEL)
     08 |  00000008 | BACKSPACE (BS)
     09 |  00000009 | CHARACTER TABULATION (HT)
     0A |  0000000A | LINE FEED (LF)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  00000014 | DEVICE CONTROL FOUR (DC4)
     15 |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     16 |  00000016 | SYNCHRONOUS IDLE (SYN)
     17 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  0000001A | SUBSTITUTE (SUB)
     1B |  0000001B | ESCAPE (ESC)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000020 | SPACE
     21 |  00000021 | EXCLAMATION MARK
     22 |  00000022 | QUOTATION MARK
     23 |  00000023 | NUMBER SIGN
     24 |  000000A4 | CURRENCY SIGN
     25 |  00000025 | PERCENT SIGN
     26 |  00000026 | AMPERSAND
     27 |  00000027 | APOSTROPHE
     28 |  00000028 | LEFT PARENTHESIS
     29 |  00000029 | RIGHT PARENTHESIS
     2A |  0000002A | ASTERISK
     2B |  0000002B | PLUS SIGN
     2C |  0000002C | COMMA
     2D |  0000002D | HYPHEN-MINUS
     2E |  0000002E | FULL STOP
     2F |  0000002F | SOLIDUS
     30 |  00000030 | DIGIT ZERO
     31 |  00000031 | DIGIT ONE
     32 |  00000032 | DIGIT TWO
     33 |  00000033 | DIGIT THREE
     34 |  00000034 | DIGIT FOUR
     35 |  00000035 | DIGIT FIVE
     36 |  00000036 | DIGIT SIX
     37 |  00000037 | DIGIT SEVEN
     38 |  00000038 | DIGIT EIGHT
     39 |  00000039 | DIGIT NINE
     3A |  0000003A | COLON
     3B |  0000003B | SEMICOLON
     3C |  0000003C | LESS-THAN SIGN
     3D |  0000003D | EQUALS SIGN
     3E |  0000003E | GREATER-THAN SIGN
     3F |  0000003F | QUESTION MARK
     40 |  00000040 | COMMERCIAL AT
     41 |  00000391 | GREEK CAPITAL LETTER ALPHA
     42 |  00000392 | GREEK CAPITAL LETTER BETA
     43 |  00000393 | GREEK CAPITAL LETTER GAMMA
     44 |  00000394 | GREEK CAPITAL LETTER DELTA
     45 |  00000395 | GREEK CAPITAL LETTER EPSILON
     46 |  00000396 | GREEK CAPITAL LETTER ZETA
     47 |  00000397 | GREEK CAPITAL LETTER ETA
     48 |  00000398 | GREEK CAPITAL LETTER THETA
     49 |  00000399 | GREEK CAPITAL LETTER IOTA
     4A |  0000039A | GREEK CAPITAL LETTER KAPPA
     4B |  0000039B | GREEK CAPITAL LETTER LAMDA
     4C |  0000039C | GREEK CAPITAL LETTER MU
     4D |  0000039D | GREEK CAPITAL LETTER NU
     4E |  0000039E | GREEK CAPITAL LETTER XI
     4F |  0000039F | GREEK CAPITAL LETTER OMICRON
     50 |  000003A0 | GREEK CAPITAL LETTER PI
     51 |  000003A1 | GREEK CAPITAL LETTER RHO
     53 |  000003A3 | GREEK CAPITAL LETTER SIGMA
     54 |  000003A4 | GREEK CAPITAL LETTER TAU
     55 |  000003A5 | GREEK CAPITAL LETTER UPSILON
     56 |  000003A6 | GREEK CAPITAL LETTER PHI
     57 |  000003A7 | GREEK CAPITAL LETTER CHI
     58 |  000003A8 | GREEK CAPITAL LETTER PSI
     59 |  000003A9 | GREEK CAPITAL LETTER OMEGA
     5B |  0000005B | LEFT SQUARE BRACKET
     5C |  0000005C | REVERSE SOLIDUS
     5D |  0000005D | RIGHT SQUARE BRACKET
     5E |  0000005E | CIRCUMFLEX ACCENT
     5F |  0000005F | LOW LINE
     61 |  000003B1 | GREEK SMALL LETTER ALPHA
     62 |  000003B2 | GREEK SMALL LETTER BETA
     63 |  000003B3 | GREEK SMALL LETTER GAMMA
     64 |  000003B4 | GREEK SMALL LETTER DELTA
     65 |  000003B5 | GREEK SMALL LETTER EPSILON
     66 |  000003B6 | GREEK SMALL LETTER ZETA
     67 |  000003B7 | GREEK SMALL LETTER ETA
     68 |  000003B8 | GREEK SMALL LETTER THETA
     69 |  000003B9 | GREEK SMALL LETTER IOTA
     6A |  000003BA | GREEK SMALL LETTER KAPPA
     6B |  000003BB | GREEK SMALL LETTER LAMDA
     6C |  000003BC | GREEK SMALL LETTER MU
     6D |  000003BD | GREEK SMALL LETTER NU
     6E |  000003BE | GREEK SMALL LETTER XI
     6F |  000003BF | GREEK SMALL LETTER OMICRON
     70 |  000003C0 | GREEK SMALL LETTER PI
     71 |  000003C1 | GREEK SMALL LETTER RHO
     72 |  000003C2 | GREEK SMALL LETTER FINAL SIGMA
     73 |  000003C3 | GREEK SMALL LETTER SIGMA
     74 |  000003C4 | GREEK SMALL LETTER TAU
     75 |  000003C5 | GREEK SMALL LETTER UPSILON
     76 |  000003C6 | GREEK SMALL LETTER PHI
     77 |  000003C7 | GREEK SMALL LETTER CHI
     78 |  000003C8 | GREEK SMALL LETTER PSI
     79 |  000003C9 | GREEK SMALL LETTER OMEGA
     7B |  0000007B | LEFT CURLY BRACKET
     7C |  0000007C | VERTICAL LINE
     7D |  0000007D | RIGHT CURLY BRACKET
     7E |  000000AF | MACRON
     7F |  0000007F | DELETE (DEL)
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/HP_ROMAN8.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for HP-ROMAN8.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::HP_ROMAN8;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x0004,
     0x0005,
     0x0006,
     0x0007,
     0x0008,
     0x0009,
     0x000a,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x0014,
     0x0015,
     0x0016,
     0x0017,
     0x0018,
     0x0019,
     0x001a,
     0x001b,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0020,
     0x0021,
     0x0022,
     0x0023,
     0x0024,
     0x0025,
     0x0026,
     0x0027,
     0x0028,
     0x0029,
     0x002a,
     0x002b,
     0x002c,
     0x002d,
     0x002e,
     0x002f,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x003a,
     0x003b,
     0x003c,
     0x003d,
     0x003e,
     0x003f,
     0x0040,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x005b,
     0x005c,
     0x005d,
     0x005e,
     0x005f,
     0x0060,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x007b,
     0x007c,
     0x007d,
     0x007e,
     0x007f,
     0x0080,
     0x0081,
     0x0082,
     0x0083,
     0x0084,
     0x0085,
     0x0086,
     0x0087,
     0x0088,
     0x0089,
     0x008a,
     0x008b,
     0x008c,
     0x008d,
     0x008e,
     0x008f,
     0x0090,
     0x0091,
     0x0092,
     0x0093,
     0x0094,
     0x0095,
     0x0096,
     0x0097,
     0x0098,
     0x0099,
     0x009a,
     0x009b,
     0x009c,
     0x009d,
     0x009e,
     0x009f,
     0x00a0,
     0x00c0,
     0x00c2,
     0x00c8,
     0x00ca,
     0x00cb,
     0x00ce,
     0x00cf,
     0x00b4,
     0x02cb,
     0x02c6,
     0x00a8,
     0x02dc,
     0x00d9,
     0x00db,
     0x20a4,
     0x00af,
     0x00dd,
     0x00fd,
     0x00b0,
     0x00c7,
     0x00e7,
     0x00d1,
     0x00f1,
     0x00a1,
     0x00bf,
     0x00a4,
     0x00a3,
     0x00a5,
     0x00a7,
     0x0192,
     0x00a2,
     0x00e2,
     0x00ea,
     0x00f4,
     0x00fb,
     0x00e1,
     0x00e9,
     0x00f3,
     0x00fa,
     0x00e0,
     0x00e8,
     0x00f2,
     0x00f9,
     0x00e4,
     0x00eb,
     0x00f6,
     0x00fc,
     0x00c5,
     0x00ee,
     0x00d8,
     0x00c6,
     0x00e5,
     0x00ed,
     0x00f8,
     0x00e6,
     0x00c4,
     0x00ec,
     0x00d6,
     0x00dc,
     0x00c9,
     0x00ef,
     0x00df,
     0x00d4,
     0x00c1,
     0x00c3,
     0x00e3,
     0x00d0,
     0x00f0,
     0x00cd,
     0x00cc,
     0x00d3,
     0x00d2,
     0x00d5,
     0x00f5,
     0x0160,
     0x0161,
     0x00da,
     0x0178,
     0x00ff,
     0x00de,
     0x00fe,
     0x00b7,
     0x00b5,
     0x00b6,
     0x00be,
     0x2014,
     0x00bc,
     0x00bd,
     0x00aa,
     0x00ba,
     0x00ab,
     0x25a0,
     0x00bb,
     0x00b1,
     0xfffd,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\x04",
     "\x05",
     "\x06",
     "\x07",
     "\x08",
     "\x09",
     "\x0a",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\x14",
     "\x15",
     "\x16",
     "\x17",
     "\x18",
     "\x19",
     "\x1a",
     "\x1b",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\x20",
     "\x21",
     "\x22",
     "\x23",
     "\x24",
     "\x25",
     "\x26",
     "\x27",
     "\x28",
     "\x29",
     "\x2a",
     "\x2b",
     "\x2c",
     "\x2d",
     "\x2e",
     "\x2f",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\x3a",
     "\x3b",
     "\x3c",
     "\x3d",
     "\x3e",
     "\x3f",
     "\x40",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\x5b",
     "\x5c",
     "\x5d",
     "\x5e",
     "\x5f",
     "\x60",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\x7b",
     "\x7c",
     "\x7d",
     "\x7e",
     "\x7f",
     "\xc2\x80",
     "\xc2\x81",
     "\xc2\x82",
     "\xc2\x83",
     "\xc2\x84",
     "\xc2\x85",
     "\xc2\x86",
     "\xc2\x87",
     "\xc2\x88",
     "\xc2\x89",
     "\xc2\x8a",
     "\xc2\x8b",
     "\xc2\x8c",
     "\xc2\x8d",
     "\xc2\x8e",
     "\xc2\x8f",
     "\xc2\x90",
     "\xc2\x91",
     "\xc2\x92",
     "\xc2\x93",
     "\xc2\x94",
     "\xc2\x95",
     "\xc2\x96",
     "\xc2\x97",
     "\xc2\x98",
     "\xc2\x99",
     "\xc2\x9a",
     "\xc2\x9b",
     "\xc2\x9c",
     "\xc2\x9d",
     "\xc2\x9e",
     "\xc2\x9f",
     "\xc2\xa0",
     "\xc3\x80",
     "\xc3\x82",
     "\xc3\x88",
     "\xc3\x8a",
     "\xc3\x8b",
     "\xc3\x8e",
     "\xc3\x8f",
     "\xc2\xb4",
     "\xcb\x8b",
     "\xcb\x86",
     "\xc2\xa8",
     "\xcb\x9c",
     "\xc3\x99",
     "\xc3\x9b",
     "\xe2\x82\xa4",
     "\xc2\xaf",
     "\xc3\x9d",
     "\xc3\xbd",
     "\xc2\xb0",
     "\xc3\x87",
     "\xc3\xa7",
     "\xc3\x91",
     "\xc3\xb1",
     "\xc2\xa1",
     "\xc2\xbf",
     "\xc2\xa4",
     "\xc2\xa3",
     "\xc2\xa5",
     "\xc2\xa7",
     "\xc6\x92",
     "\xc2\xa2",
     "\xc3\xa2",
     "\xc3\xaa",
     "\xc3\xb4",
     "\xc3\xbb",
     "\xc3\xa1",
     "\xc3\xa9",
     "\xc3\xb3",
     "\xc3\xba",
     "\xc3\xa0",
     "\xc3\xa8",
     "\xc3\xb2",
     "\xc3\xb9",
     "\xc3\xa4",
     "\xc3\xab",
     "\xc3\xb6",
     "\xc3\xbc",
     "\xc3\x85",
     "\xc3\xae",
     "\xc3\x98",
     "\xc3\x86",
     "\xc3\xa5",
     "\xc3\xad",
     "\xc3\xb8",
     "\xc3\xa6",
     "\xc3\x84",
     "\xc3\xac",
     "\xc3\x96",
     "\xc3\x9c",
     "\xc3\x89",
     "\xc3\xaf",
     "\xc3\x9f",
     "\xc3\x94",
     "\xc3\x81",
     "\xc3\x83",
     "\xc3\xa3",
     "\xc3\x90",
     "\xc3\xb0",
     "\xc3\x8d",
     "\xc3\x8c",
     "\xc3\x93",
     "\xc3\x92",
     "\xc3\x95",
     "\xc3\xb5",
     "\xc5\xa0",
     "\xc5\xa1",
     "\xc3\x9a",
     "\xc5\xb8",
     "\xc3\xbf",
     "\xc3\x9e",
     "\xc3\xbe",
     "\xc2\xb7",
     "\xc2\xb5",
     "\xc2\xb6",
     "\xc2\xbe",
     "\xe2\x80\x94",
     "\xc2\xbc",
     "\xc2\xbd",
     "\xc2\xaa",
     "\xc2\xba",
     "\xc2\xab",
     "\xe2\x96\xa0",
     "\xc2\xbb",
     "\xc2\xb1",
     "\xef\xbf\xbd",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x04",
     0x00000005 => "\x05",
     0x00000006 => "\x06",
     0x00000007 => "\x07",
     0x00000008 => "\x08",
     0x00000009 => "\x09",
     0x0000000a => "\x0a",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x14",
     0x00000015 => "\x15",
     0x00000016 => "\x16",
     0x00000017 => "\x17",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x1a",
     0x0000001b => "\x1b",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x20",
     0x00000021 => "\x21",
     0x00000022 => "\x22",
     0x00000023 => "\x23",
     0x00000024 => "\x24",
     0x00000025 => "\x25",
     0x00000026 => "\x26",
     0x00000027 => "\x27",
     0x00000028 => "\x28",
     0x00000029 => "\x29",
     0x0000002a => "\x2a",
     0x0000002b => "\x2b",
     0x0000002c => "\x2c",
     0x0000002d => "\x2d",
     0x0000002e => "\x2e",
     0x0000002f => "\x2f",
     0x00000030 => "\x30",
     0x00000031 => "\x31",
     0x00000032 => "\x32",
     0x00000033 => "\x33",
     0x00000034 => "\x34",
     0x00000035 => "\x35",
     0x00000036 => "\x36",
     0x00000037 => "\x37",
     0x00000038 => "\x38",
     0x00000039 => "\x39",
     0x0000003a => "\x3a",
     0x0000003b => "\x3b",
     0x0000003c => "\x3c",
     0x0000003d => "\x3d",
     0x0000003e => "\x3e",
     0x0000003f => "\x3f",
     0x00000040 => "\x40",
     0x00000041 => "\x41",
     0x00000042 => "\x42",
     0x00000043 => "\x43",
     0x00000044 => "\x44",
     0x00000045 => "\x45",
     0x00000046 => "\x46",
     0x00000047 => "\x47",
     0x00000048 => "\x48",
     0x00000049 => "\x49",
     0x0000004a => "\x4a",
     0x0000004b => "\x4b",
     0x0000004c => "\x4c",
     0x0000004d => "\x4d",
     0x0000004e => "\x4e",
     0x0000004f => "\x4f",
     0x00000050 => "\x50",
     0x00000051 => "\x51",
     0x00000052 => "\x52",
     0x00000053 => "\x53",
     0x00000054 => "\x54",
     0x00000055 => "\x55",
     0x00000056 => "\x56",
     0x00000057 => "\x57",
     0x00000058 => "\x58",
     0x00000059 => "\x59",
     0x0000005a => "\x5a",
     0x0000005b => "\x5b",
     0x0000005c => "\x5c",
     0x0000005d => "\x5d",
     0x0000005e => "\x5e",
     0x0000005f => "\x5f",
     0x00000060 => "\x60",
     0x00000061 => "\x61",
     0x00000062 => "\x62",
     0x00000063 => "\x63",
     0x00000064 => "\x64",
     0x00000065 => "\x65",
     0x00000066 => "\x66",
     0x00000067 => "\x67",
     0x00000068 => "\x68",
     0x00000069 => "\x69",
     0x0000006a => "\x6a",
     0x0000006b => "\x6b",
     0x0000006c => "\x6c",
     0x0000006d => "\x6d",
     0x0000006e => "\x6e",
     0x0000006f => "\x6f",
     0x00000070 => "\x70",
     0x00000071 => "\x71",
     0x00000072 => "\x72",
     0x00000073 => "\x73",
     0x00000074 => "\x74",
     0x00000075 => "\x75",
     0x00000076 => "\x76",
     0x00000077 => "\x77",
     0x00000078 => "\x78",
     0x00000079 => "\x79",
     0x0000007a => "\x7a",
     0x0000007b => "\x7b",
     0x0000007c => "\x7c",
     0x0000007d => "\x7d",
     0x0000007e => "\x7e",
     0x0000007f => "\x7f",
     0x00000080 => "\x80",
     0x00000081 => "\x81",
     0x00000082 => "\x82",
     0x00000083 => "\x83",
     0x00000084 => "\x84",
     0x00000085 => "\x85",
     0x00000086 => "\x86",
     0x00000087 => "\x87",
     0x00000088 => "\x88",
     0x00000089 => "\x89",
     0x0000008a => "\x8a",
     0x0000008b => "\x8b",
     0x0000008c => "\x8c",
     0x0000008d => "\x8d",
     0x0000008e => "\x8e",
     0x0000008f => "\x8f",
     0x00000090 => "\x90",
     0x00000091 => "\x91",
     0x00000092 => "\x92",
     0x00000093 => "\x93",
     0x00000094 => "\x94",
     0x00000095 => "\x95",
     0x00000096 => "\x96",
     0x00000097 => "\x97",
     0x00000098 => "\x98",
     0x00000099 => "\x99",
     0x0000009a => "\x9a",
     0x0000009b => "\x9b",
     0x0000009c => "\x9c",
     0x0000009d => "\x9d",
     0x0000009e => "\x9e",
     0x0000009f => "\x9f",
     0x000000a0 => "\xa0",
     0x000000a1 => "\xb8",
     0x000000a2 => "\xbf",
     0x000000a3 => "\xbb",
     0x000000a4 => "\xba",
     0x000000a5 => "\xbc",
     0x000000a7 => "\xbd",
     0x000000a8 => "\xab",
     0x000000aa => "\xf9",
     0x000000ab => "\xfb",
     0x000000af => "\xb0",
     0x000000b0 => "\xb3",
     0x000000b1 => "\xfe",
     0x000000b4 => "\xa8",
     0x000000b5 => "\xf3",
     0x000000b6 => "\xf4",
     0x000000b7 => "\xf2",
     0x000000ba => "\xfa",
     0x000000bb => "\xfd",
     0x000000bc => "\xf7",
     0x000000bd => "\xf8",
     0x000000be => "\xf5",
     0x000000bf => "\xb9",
     0x000000c0 => "\xa1",
     0x000000c1 => "\xe0",
     0x000000c2 => "\xa2",
     0x000000c3 => "\xe1",
     0x000000c4 => "\xd8",
     0x000000c5 => "\xd0",
     0x000000c6 => "\xd3",
     0x000000c7 => "\xb4",
     0x000000c8 => "\xa3",
     0x000000c9 => "\xdc",
     0x000000ca => "\xa4",
     0x000000cb => "\xa5",
     0x000000cc => "\xe6",
     0x000000cd => "\xe5",
     0x000000ce => "\xa6",
     0x000000cf => "\xa7",
     0x000000d0 => "\xe3",
     0x000000d1 => "\xb6",
     0x000000d2 => "\xe8",
     0x000000d3 => "\xe7",
     0x000000d4 => "\xdf",
     0x000000d5 => "\xe9",
     0x000000d6 => "\xda",
     0x000000d8 => "\xd2",
     0x000000d9 => "\xad",
     0x000000da => "\xed",
     0x000000db => "\xae",
     0x000000dc => "\xdb",
     0x000000dd => "\xb1",
     0x000000de => "\xf0",
     0x000000df => "\xde",
     0x000000e0 => "\xc8",
     0x000000e1 => "\xc4",
     0x000000e2 => "\xc0",
     0x000000e3 => "\xe2",
     0x000000e4 => "\xcc",
     0x000000e5 => "\xd4",
     0x000000e6 => "\xd7",
     0x000000e7 => "\xb5",
     0x000000e8 => "\xc9",
     0x000000e9 => "\xc5",
     0x000000ea => "\xc1",
     0x000000eb => "\xcd",
     0x000000ec => "\xd9",
     0x000000ed => "\xd5",
     0x000000ee => "\xd1",
     0x000000ef => "\xdd",
     0x000000f0 => "\xe4",
     0x000000f1 => "\xb7",
     0x000000f2 => "\xca",
     0x000000f3 => "\xc6",
     0x000000f4 => "\xc2",
     0x000000f5 => "\xea",
     0x000000f6 => "\xce",
     0x000000f8 => "\xd6",
     0x000000f9 => "\xcb",
     0x000000fa => "\xc7",
     0x000000fb => "\xc3",
     0x000000fc => "\xcf",
     0x000000fd => "\xb2",
     0x000000fe => "\xf1",
     0x000000ff => "\xef",
     0x00000160 => "\xeb",
     0x00000161 => "\xec",
     0x00000178 => "\xee",
     0x00000192 => "\xbe",
     0x000002c6 => "\xaa",
     0x000002cb => "\xa9",
     0x000002dc => "\xac",
     0x00002014 => "\xf6",
     0x000020a4 => "\xaf",
     0x000025a0 => "\xfc",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::HP_ROMAN8 - Conversion routines for HP_ROMAN8
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for HP-ROMAN8.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
   source: LaserJet IIP Printer User's Manual,
   HP part no 33471-90901, Hewlet-Packard, June 1989.
  alias ROMAN8
  alias R8
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  00000004 | END OF TRANSMISSION (EOT)
     05 |  00000005 | ENQUIRY (ENQ)
     06 |  00000006 | ACKNOWLEDGE (ACK)
     07 |  00000007 | BELL (BEL)
     08 |  00000008 | BACKSPACE (BS)
     09 |  00000009 | CHARACTER TABULATION (HT)
     0A |  0000000A | LINE FEED (LF)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  00000014 | DEVICE CONTROL FOUR (DC4)
     15 |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     16 |  00000016 | SYNCHRONOUS IDLE (SYN)
     17 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  0000001A | SUBSTITUTE (SUB)
     1B |  0000001B | ESCAPE (ESC)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000020 | SPACE
     21 |  00000021 | EXCLAMATION MARK
     22 |  00000022 | QUOTATION MARK
     23 |  00000023 | NUMBER SIGN
     24 |  00000024 | DOLLAR SIGN
     25 |  00000025 | PERCENT SIGN
     26 |  00000026 | AMPERSAND
     27 |  00000027 | APOSTROPHE
     28 |  00000028 | LEFT PARENTHESIS
     29 |  00000029 | RIGHT PARENTHESIS
     2A |  0000002A | ASTERISK
     2B |  0000002B | PLUS SIGN
     2C |  0000002C | COMMA
     2D |  0000002D | HYPHEN-MINUS
     2E |  0000002E | FULL STOP
     2F |  0000002F | SOLIDUS
     30 |  00000030 | DIGIT ZERO
     31 |  00000031 | DIGIT ONE
     32 |  00000032 | DIGIT TWO
     33 |  00000033 | DIGIT THREE
     34 |  00000034 | DIGIT FOUR
     35 |  00000035 | DIGIT FIVE
     36 |  00000036 | DIGIT SIX
     37 |  00000037 | DIGIT SEVEN
     38 |  00000038 | DIGIT EIGHT
     39 |  00000039 | DIGIT NINE
     3A |  0000003A | COLON
     3B |  0000003B | SEMICOLON
     3C |  0000003C | LESS-THAN SIGN
     3D |  0000003D | EQUALS SIGN
     3E |  0000003E | GREATER-THAN SIGN
     3F |  0000003F | QUESTION MARK
     40 |  00000040 | COMMERCIAL AT
     41 |  00000041 | LATIN CAPITAL LETTER A
     42 |  00000042 | LATIN CAPITAL LETTER B
     43 |  00000043 | LATIN CAPITAL LETTER C
     44 |  00000044 | LATIN CAPITAL LETTER D
     45 |  00000045 | LATIN CAPITAL LETTER E
     46 |  00000046 | LATIN CAPITAL LETTER F
     47 |  00000047 | LATIN CAPITAL LETTER G
     48 |  00000048 | LATIN CAPITAL LETTER H
     49 |  00000049 | LATIN CAPITAL LETTER I
     4A |  0000004A | LATIN CAPITAL LETTER J
     4B |  0000004B | LATIN CAPITAL LETTER K
     4C |  0000004C | LATIN CAPITAL LETTER L
     4D |  0000004D | LATIN CAPITAL LETTER M
     4E |  0000004E | LATIN CAPITAL LETTER N
     4F |  0000004F | LATIN CAPITAL LETTER O
     50 |  00000050 | LATIN CAPITAL LETTER P
     51 |  00000051 | LATIN CAPITAL LETTER Q
     52 |  00000052 | LATIN CAPITAL LETTER R
     53 |  00000053 | LATIN CAPITAL LETTER S
     54 |  00000054 | LATIN CAPITAL LETTER T
     55 |  00000055 | LATIN CAPITAL LETTER U
     56 |  00000056 | LATIN CAPITAL LETTER V
     57 |  00000057 | LATIN CAPITAL LETTER W
     58 |  00000058 | LATIN CAPITAL LETTER X
     59 |  00000059 | LATIN CAPITAL LETTER Y
     5A |  0000005A | LATIN CAPITAL LETTER Z
     5B |  0000005B | LEFT SQUARE BRACKET
     5C |  0000005C | REVERSE SOLIDUS
     5D |  0000005D | RIGHT SQUARE BRACKET
     5E |  0000005E | CIRCUMFLEX ACCENT
     5F |  0000005F | LOW LINE
     60 |  00000060 | GRAVE ACCENT
     61 |  00000061 | LATIN SMALL LETTER A
     62 |  00000062 | LATIN SMALL LETTER B
     63 |  00000063 | LATIN SMALL LETTER C
     64 |  00000064 | LATIN SMALL LETTER D
     65 |  00000065 | LATIN SMALL LETTER E
     66 |  00000066 | LATIN SMALL LETTER F
     67 |  00000067 | LATIN SMALL LETTER G
     68 |  00000068 | LATIN SMALL LETTER H
     69 |  00000069 | LATIN SMALL LETTER I
     6A |  0000006A | LATIN SMALL LETTER J
     6B |  0000006B | LATIN SMALL LETTER K
     6C |  0000006C | LATIN SMALL LETTER L
     6D |  0000006D | LATIN SMALL LETTER M
     6E |  0000006E | LATIN SMALL LETTER N
     6F |  0000006F | LATIN SMALL LETTER O
     70 |  00000070 | LATIN SMALL LETTER P
     71 |  00000071 | LATIN SMALL LETTER Q
     72 |  00000072 | LATIN SMALL LETTER R
     73 |  00000073 | LATIN SMALL LETTER S
     74 |  00000074 | LATIN SMALL LETTER T
     75 |  00000075 | LATIN SMALL LETTER U
     76 |  00000076 | LATIN SMALL LETTER V
     77 |  00000077 | LATIN SMALL LETTER W
     78 |  00000078 | LATIN SMALL LETTER X
     79 |  00000079 | LATIN SMALL LETTER Y
     7A |  0000007A | LATIN SMALL LETTER Z
     7B |  0000007B | LEFT CURLY BRACKET
     7C |  0000007C | VERTICAL LINE
     7D |  0000007D | RIGHT CURLY BRACKET
     7E |  0000007E | TILDE
     7F |  0000007F | DELETE (DEL)
     80 |  00000080 | PADDING CHARACTER (PAD)
     81 |  00000081 | HIGH OCTET PRESET (HOP)
     82 |  00000082 | BREAK PERMITTED HERE (BPH)
     83 |  00000083 | NO BREAK HERE (NBH)
     84 |  00000084 | INDEX (IND)
     85 |  00000085 | NEXT LINE (NEL)
     86 |  00000086 | START OF SELECTED AREA (SSA)
     87 |  00000087 | END OF SELECTED AREA (ESA)
     88 |  00000088 | CHARACTER TABULATION SET (HTS)
     89 |  00000089 | CHARACTER TABULATION WITH JUSTIFICATION (HTJ)
     8A |  0000008A | LINE TABULATION SET (VTS)
     8B |  0000008B | PARTIAL LINE FORWARD (PLD)
     8C |  0000008C | PARTIAL LINE BACKWARD (PLU)
     8D |  0000008D | REVERSE LINE FEED (RI)
     8E |  0000008E | SINGLE-SHIFT TWO (SS2)
     8F |  0000008F | SINGLE-SHIFT THREE (SS3)
     90 |  00000090 | DEVICE CONTROL STRING (DCS)
     91 |  00000091 | PRIVATE USE ONE (PU1)
     92 |  00000092 | PRIVATE USE TWO (PU2)
     93 |  00000093 | SET TRANSMIT STATE (STS)
     94 |  00000094 | CANCEL CHARACTER (CCH)
     95 |  00000095 | MESSAGE WAITING (MW)
     96 |  00000096 | START OF GUARDED AREA (SPA)
     97 |  00000097 | END OF GUARDED AREA (EPA)
     98 |  00000098 | START OF STRING (SOS)
     99 |  00000099 | SINGLE GRAPHIC CHARACTER INTRODUCER (SGCI)
     9A |  0000009A | SINGLE CHARACTER INTRODUCER (SCI)
     9B |  0000009B | CONTROL SEQUENCE INTRODUCER (CSI)
     9C |  0000009C | STRING TERMINATOR (ST)
     9D |  0000009D | OPERATING SYSTEM COMMAND (OSC)
     9E |  0000009E | PRIVACY MESSAGE (PM)
     9F |  0000009F | APPLICATION PROGRAM COMMAND (APC)
     A0 |  000000A0 | NO-BREAK SPACE
     A1 |  000000C0 | LATIN CAPITAL LETTER A WITH GRAVE
     A2 |  000000C2 | LATIN CAPITAL LETTER A WITH CIRCUMFLEX
     A3 |  000000C8 | LATIN CAPITAL LETTER E WITH GRAVE
     A4 |  000000CA | LATIN CAPITAL LETTER E WITH CIRCUMFLEX
     A5 |  000000CB | LATIN CAPITAL LETTER E WITH DIAERESIS
     A6 |  000000CE | LATIN CAPITAL LETTER I WITH CIRCUMFLEX
     A7 |  000000CF | LATIN CAPITAL LETTER I WITH DIAERESIS
     A8 |  000000B4 | ACUTE ACCENT
     A9 |  000002CB | MODIFIER LETTER GRAVE ACCENT (Mandarin Chinese fourth tone)
     AA |  000002C6 | MODIFIER LETTER CIRCUMFLEX ACCENT
     AB |  000000A8 | DIAERESIS
     AC |  000002DC | SMALL TILDE
     AD |  000000D9 | LATIN CAPITAL LETTER U WITH GRAVE
     AE |  000000DB | LATIN CAPITAL LETTER U WITH CIRCUMFLEX
     AF |  000020A4 | LIRA SIGN
     B0 |  000000AF | MACRON
     B1 |  000000DD | LATIN CAPITAL LETTER Y WITH ACUTE
     B2 |  000000FD | LATIN SMALL LETTER Y WITH ACUTE
     B3 |  000000B0 | DEGREE SIGN
     B4 |  000000C7 | LATIN CAPITAL LETTER C WITH CEDILLA
     B5 |  000000E7 | LATIN SMALL LETTER C WITH CEDILLA
     B6 |  000000D1 | LATIN CAPITAL LETTER N WITH TILDE
     B7 |  000000F1 | LATIN SMALL LETTER N WITH TILDE
     B8 |  000000A1 | INVERTED EXCLAMATION MARK
     B9 |  000000BF | INVERTED QUESTION MARK
     BA |  000000A4 | CURRENCY SIGN
     BB |  000000A3 | POUND SIGN
     BC |  000000A5 | YEN SIGN
     BD |  000000A7 | SECTION SIGN
     BE |  00000192 | LATIN SMALL LETTER F WITH HOOK
     BF |  000000A2 | CENT SIGN
     C0 |  000000E2 | LATIN SMALL LETTER A WITH CIRCUMFLEX
     C1 |  000000EA | LATIN SMALL LETTER E WITH CIRCUMFLEX
     C2 |  000000F4 | LATIN SMALL LETTER O WITH CIRCUMFLEX
     C3 |  000000FB | LATIN SMALL LETTER U WITH CIRCUMFLEX
     C4 |  000000E1 | LATIN SMALL LETTER A WITH ACUTE
     C5 |  000000E9 | LATIN SMALL LETTER E WITH ACUTE
     C6 |  000000F3 | LATIN SMALL LETTER O WITH ACUTE
     C7 |  000000FA | LATIN SMALL LETTER U WITH ACUTE
     C8 |  000000E0 | LATIN SMALL LETTER A WITH GRAVE
     C9 |  000000E8 | LATIN SMALL LETTER E WITH GRAVE
     CA |  000000F2 | LATIN SMALL LETTER O WITH GRAVE
     CB |  000000F9 | LATIN SMALL LETTER U WITH GRAVE
     CC |  000000E4 | LATIN SMALL LETTER A WITH DIAERESIS
     CD |  000000EB | LATIN SMALL LETTER E WITH DIAERESIS
     CE |  000000F6 | LATIN SMALL LETTER O WITH DIAERESIS
     CF |  000000FC | LATIN SMALL LETTER U WITH DIAERESIS
     D0 |  000000C5 | LATIN CAPITAL LETTER A WITH RING ABOVE
     D1 |  000000EE | LATIN SMALL LETTER I WITH CIRCUMFLEX
     D2 |  000000D8 | LATIN CAPITAL LETTER O WITH STROKE
     D3 |  000000C6 | LATIN CAPITAL LETTER AE
     D4 |  000000E5 | LATIN SMALL LETTER A WITH RING ABOVE
     D5 |  000000ED | LATIN SMALL LETTER I WITH ACUTE
     D6 |  000000F8 | LATIN SMALL LETTER O WITH STROKE
     D7 |  000000E6 | LATIN SMALL LETTER AE
     D8 |  000000C4 | LATIN CAPITAL LETTER A WITH DIAERESIS
     D9 |  000000EC | LATIN SMALL LETTER I WITH GRAVE
     DA |  000000D6 | LATIN CAPITAL LETTER O WITH DIAERESIS
     DB |  000000DC | LATIN CAPITAL LETTER U WITH DIAERESIS
     DC |  000000C9 | LATIN CAPITAL LETTER E WITH ACUTE
     DD |  000000EF | LATIN SMALL LETTER I WITH DIAERESIS
     DE |  000000DF | LATIN SMALL LETTER SHARP S (German)
     DF |  000000D4 | LATIN CAPITAL LETTER O WITH CIRCUMFLEX
     E0 |  000000C1 | LATIN CAPITAL LETTER A WITH ACUTE
     E1 |  000000C3 | LATIN CAPITAL LETTER A WITH TILDE
     E2 |  000000E3 | LATIN SMALL LETTER A WITH TILDE
     E3 |  000000D0 | LATIN CAPITAL LETTER ETH (Icelandic)
     E4 |  000000F0 | LATIN SMALL LETTER ETH (Icelandic)
     E5 |  000000CD | LATIN CAPITAL LETTER I WITH ACUTE
     E6 |  000000CC | LATIN CAPITAL LETTER I WITH GRAVE
     E7 |  000000D3 | LATIN CAPITAL LETTER O WITH ACUTE
     E8 |  000000D2 | LATIN CAPITAL LETTER O WITH GRAVE
     E9 |  000000D5 | LATIN CAPITAL LETTER O WITH TILDE
     EA |  000000F5 | LATIN SMALL LETTER O WITH TILDE
     EB |  00000160 | LATIN CAPITAL LETTER S WITH CARON
     EC |  00000161 | LATIN SMALL LETTER S WITH CARON
     ED |  000000DA | LATIN CAPITAL LETTER U WITH ACUTE
     EE |  00000178 | LATIN CAPITAL LETTER Y WITH DIAERESIS
     EF |  000000FF | LATIN SMALL LETTER Y WITH DIAERESIS
     F0 |  000000DE | LATIN CAPITAL LETTER THORN (Icelandic)
     F1 |  000000FE | LATIN SMALL LETTER THORN (Icelandic)
     F2 |  000000B7 | MIDDLE DOT
     F3 |  000000B5 | MICRO SIGN
     F4 |  000000B6 | PILCROW SIGN
     F5 |  000000BE | VULGAR FRACTION THREE QUARTERS
     F6 |  00002014 | EM DASH
     F7 |  000000BC | VULGAR FRACTION ONE QUARTER
     F8 |  000000BD | VULGAR FRACTION ONE HALF
     F9 |  000000AA | FEMININE ORDINAL INDICATOR
     FA |  000000BA | MASCULINE ORDINAL INDICATOR
     FB |  000000AB | LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
     FC |  000025A0 | BLACK SQUARE
     FD |  000000BB | RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
     FE |  000000B1 | PLUS-MINUS SIGN
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/IBM037.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for IBM037.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::IBM037;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x009c,
     0x0009,
     0x0086,
     0x007f,
     0x0097,
     0x008d,
     0x008e,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x009d,
     0x0085,
     0x0008,
     0x0087,
     0x0018,
     0x0019,
     0x0092,
     0x008f,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0080,
     0x0081,
     0x0082,
     0x0083,
     0x0084,
     0x000a,
     0x0017,
     0x001b,
     0x0088,
     0x0089,
     0x008a,
     0x008b,
     0x008c,
     0x0005,
     0x0006,
     0x0007,
     0x0090,
     0x0091,
     0x0016,
     0x0093,
     0x0094,
     0x0095,
     0x0096,
     0x0004,
     0x0098,
     0x0099,
     0x009a,
     0x009b,
     0x0014,
     0x0015,
     0x009e,
     0x001a,
     0x0020,
     0x00a0,
     0x00e2,
     0x00e4,
     0x00e0,
     0x00e1,
     0x00e3,
     0x00e5,
     0x00e7,
     0x00f1,
     0x00a2,
     0x002e,
     0x003c,
     0x0028,
     0x002b,
     0x007c,
     0x0026,
     0x00e9,
     0x00ea,
     0x00eb,
     0x00e8,
     0x00ed,
     0x00ee,
     0x00ef,
     0x00ec,
     0x00df,
     0x0021,
     0x0024,
     0x002a,
     0x0029,
     0x003b,
     0x00ac,
     0x002d,
     0x002f,
     0x00c2,
     0x00c4,
     0x00c0,
     0x00c1,
     0x00c3,
     0x00c5,
     0x00c7,
     0x00d1,
     0x00a6,
     0x002c,
     0x0025,
     0x005f,
     0x003e,
     0x003f,
     0x00f8,
     0x00c9,
     0x00ca,
     0x00cb,
     0x00c8,
     0x00cd,
     0x00ce,
     0x00cf,
     0x00cc,
     0x0060,
     0x003a,
     0x0023,
     0x0040,
     0x0027,
     0x003d,
     0x0022,
     0x00d8,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x00ab,
     0x00bb,
     0x00f0,
     0x00fd,
     0x00fe,
     0x00b1,
     0x00b0,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x00aa,
     0x00ba,
     0x00e6,
     0x00b8,
     0x00c6,
     0x00a4,
     0x00b5,
     0x007e,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x00a1,
     0x00bf,
     0x00d0,
     0x00dd,
     0x00de,
     0x00ae,
     0x005e,
     0x00a3,
     0x00a5,
     0x00b7,
     0x00a9,
     0x00a7,
     0x00b6,
     0x00bc,
     0x00bd,
     0x00be,
     0x005b,
     0x005d,
     0x00af,
     0x00a8,
     0x00b4,
     0x00d7,
     0x007b,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x00ad,
     0x00f4,
     0x00f6,
     0x00f2,
     0x00f3,
     0x00f5,
     0x007d,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x00b9,
     0x00fb,
     0x00fc,
     0x00f9,
     0x00fa,
     0x00ff,
     0x005c,
     0x00f7,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x00b2,
     0x00d4,
     0x00d6,
     0x00d2,
     0x00d3,
     0x00d5,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x00b3,
     0x00db,
     0x00dc,
     0x00d9,
     0x00da,
     0x009f,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\xc2\x9c",
     "\x09",
     "\xc2\x86",
     "\x7f",
     "\xc2\x97",
     "\xc2\x8d",
     "\xc2\x8e",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\xc2\x9d",
     "\xc2\x85",
     "\x08",
     "\xc2\x87",
     "\x18",
     "\x19",
     "\xc2\x92",
     "\xc2\x8f",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\xc2\x80",
     "\xc2\x81",
     "\xc2\x82",
     "\xc2\x83",
     "\xc2\x84",
     "\x0a",
     "\x17",
     "\x1b",
     "\xc2\x88",
     "\xc2\x89",
     "\xc2\x8a",
     "\xc2\x8b",
     "\xc2\x8c",
     "\x05",
     "\x06",
     "\x07",
     "\xc2\x90",
     "\xc2\x91",
     "\x16",
     "\xc2\x93",
     "\xc2\x94",
     "\xc2\x95",
     "\xc2\x96",
     "\x04",
     "\xc2\x98",
     "\xc2\x99",
     "\xc2\x9a",
     "\xc2\x9b",
     "\x14",
     "\x15",
     "\xc2\x9e",
     "\x1a",
     "\x20",
     "\xc2\xa0",
     "\xc3\xa2",
     "\xc3\xa4",
     "\xc3\xa0",
     "\xc3\xa1",
     "\xc3\xa3",
     "\xc3\xa5",
     "\xc3\xa7",
     "\xc3\xb1",
     "\xc2\xa2",
     "\x2e",
     "\x3c",
     "\x28",
     "\x2b",
     "\x7c",
     "\x26",
     "\xc3\xa9",
     "\xc3\xaa",
     "\xc3\xab",
     "\xc3\xa8",
     "\xc3\xad",
     "\xc3\xae",
     "\xc3\xaf",
     "\xc3\xac",
     "\xc3\x9f",
     "\x21",
     "\x24",
     "\x2a",
     "\x29",
     "\x3b",
     "\xc2\xac",
     "\x2d",
     "\x2f",
     "\xc3\x82",
     "\xc3\x84",
     "\xc3\x80",
     "\xc3\x81",
     "\xc3\x83",
     "\xc3\x85",
     "\xc3\x87",
     "\xc3\x91",
     "\xc2\xa6",
     "\x2c",
     "\x25",
     "\x5f",
     "\x3e",
     "\x3f",
     "\xc3\xb8",
     "\xc3\x89",
     "\xc3\x8a",
     "\xc3\x8b",
     "\xc3\x88",
     "\xc3\x8d",
     "\xc3\x8e",
     "\xc3\x8f",
     "\xc3\x8c",
     "\x60",
     "\x3a",
     "\x23",
     "\x40",
     "\x27",
     "\x3d",
     "\x22",
     "\xc3\x98",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\xc2\xab",
     "\xc2\xbb",
     "\xc3\xb0",
     "\xc3\xbd",
     "\xc3\xbe",
     "\xc2\xb1",
     "\xc2\xb0",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\xc2\xaa",
     "\xc2\xba",
     "\xc3\xa6",
     "\xc2\xb8",
     "\xc3\x86",
     "\xc2\xa4",
     "\xc2\xb5",
     "\x7e",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\xc2\xa1",
     "\xc2\xbf",
     "\xc3\x90",
     "\xc3\x9d",
     "\xc3\x9e",
     "\xc2\xae",
     "\x5e",
     "\xc2\xa3",
     "\xc2\xa5",
     "\xc2\xb7",
     "\xc2\xa9",
     "\xc2\xa7",
     "\xc2\xb6",
     "\xc2\xbc",
     "\xc2\xbd",
     "\xc2\xbe",
     "\x5b",
     "\x5d",
     "\xc2\xaf",
     "\xc2\xa8",
     "\xc2\xb4",
     "\xc3\x97",
     "\x7b",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\xc2\xad",
     "\xc3\xb4",
     "\xc3\xb6",
     "\xc3\xb2",
     "\xc3\xb3",
     "\xc3\xb5",
     "\x7d",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\xc2\xb9",
     "\xc3\xbb",
     "\xc3\xbc",
     "\xc3\xb9",
     "\xc3\xba",
     "\xc3\xbf",
     "\x5c",
     "\xc3\xb7",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\xc2\xb2",
     "\xc3\x94",
     "\xc3\x96",
     "\xc3\x92",
     "\xc3\x93",
     "\xc3\x95",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\xc2\xb3",
     "\xc3\x9b",
     "\xc3\x9c",
     "\xc3\x99",
     "\xc3\x9a",
     "\xc2\x9f",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x37",
     0x00000005 => "\x2d",
     0x00000006 => "\x2e",
     0x00000007 => "\x2f",
     0x00000008 => "\x16",
     0x00000009 => "\x05",
     0x0000000a => "\x25",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x3c",
     0x00000015 => "\x3d",
     0x00000016 => "\x32",
     0x00000017 => "\x26",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x3f",
     0x0000001b => "\x27",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x40",
     0x00000021 => "\x5a",
     0x00000022 => "\x7f",
     0x00000023 => "\x7b",
     0x00000024 => "\x5b",
     0x00000025 => "\x6c",
     0x00000026 => "\x50",
     0x00000027 => "\x7d",
     0x00000028 => "\x4d",
     0x00000029 => "\x5d",
     0x0000002a => "\x5c",
     0x0000002b => "\x4e",
     0x0000002c => "\x6b",
     0x0000002d => "\x60",
     0x0000002e => "\x4b",
     0x0000002f => "\x61",
     0x00000030 => "\xf0",
     0x00000031 => "\xf1",
     0x00000032 => "\xf2",
     0x00000033 => "\xf3",
     0x00000034 => "\xf4",
     0x00000035 => "\xf5",
     0x00000036 => "\xf6",
     0x00000037 => "\xf7",
     0x00000038 => "\xf8",
     0x00000039 => "\xf9",
     0x0000003a => "\x7a",
     0x0000003b => "\x5e",
     0x0000003c => "\x4c",
     0x0000003d => "\x7e",
     0x0000003e => "\x6e",
     0x0000003f => "\x6f",
     0x00000040 => "\x7c",
     0x00000041 => "\xc1",
     0x00000042 => "\xc2",
     0x00000043 => "\xc3",
     0x00000044 => "\xc4",
     0x00000045 => "\xc5",
     0x00000046 => "\xc6",
     0x00000047 => "\xc7",
     0x00000048 => "\xc8",
     0x00000049 => "\xc9",
     0x0000004a => "\xd1",
     0x0000004b => "\xd2",
     0x0000004c => "\xd3",
     0x0000004d => "\xd4",
     0x0000004e => "\xd5",
     0x0000004f => "\xd6",
     0x00000050 => "\xd7",
     0x00000051 => "\xd8",
     0x00000052 => "\xd9",
     0x00000053 => "\xe2",
     0x00000054 => "\xe3",
     0x00000055 => "\xe4",
     0x00000056 => "\xe5",
     0x00000057 => "\xe6",
     0x00000058 => "\xe7",
     0x00000059 => "\xe8",
     0x0000005a => "\xe9",
     0x0000005b => "\xba",
     0x0000005c => "\xe0",
     0x0000005d => "\xbb",
     0x0000005e => "\xb0",
     0x0000005f => "\x6d",
     0x00000060 => "\x79",
     0x00000061 => "\x81",
     0x00000062 => "\x82",
     0x00000063 => "\x83",
     0x00000064 => "\x84",
     0x00000065 => "\x85",
     0x00000066 => "\x86",
     0x00000067 => "\x87",
     0x00000068 => "\x88",
     0x00000069 => "\x89",
     0x0000006a => "\x91",
     0x0000006b => "\x92",
     0x0000006c => "\x93",
     0x0000006d => "\x94",
     0x0000006e => "\x95",
     0x0000006f => "\x96",
     0x00000070 => "\x97",
     0x00000071 => "\x98",
     0x00000072 => "\x99",
     0x00000073 => "\xa2",
     0x00000074 => "\xa3",
     0x00000075 => "\xa4",
     0x00000076 => "\xa5",
     0x00000077 => "\xa6",
     0x00000078 => "\xa7",
     0x00000079 => "\xa8",
     0x0000007a => "\xa9",
     0x0000007b => "\xc0",
     0x0000007c => "\x4f",
     0x0000007d => "\xd0",
     0x0000007e => "\xa1",
     0x0000007f => "\x07",
     0x00000080 => "\x20",
     0x00000081 => "\x21",
     0x00000082 => "\x22",
     0x00000083 => "\x23",
     0x00000084 => "\x24",
     0x00000085 => "\x15",
     0x00000086 => "\x06",
     0x00000087 => "\x17",
     0x00000088 => "\x28",
     0x00000089 => "\x29",
     0x0000008a => "\x2a",
     0x0000008b => "\x2b",
     0x0000008c => "\x2c",
     0x0000008d => "\x09",
     0x0000008e => "\x0a",
     0x0000008f => "\x1b",
     0x00000090 => "\x30",
     0x00000091 => "\x31",
     0x00000092 => "\x1a",
     0x00000093 => "\x33",
     0x00000094 => "\x34",
     0x00000095 => "\x35",
     0x00000096 => "\x36",
     0x00000097 => "\x08",
     0x00000098 => "\x38",
     0x00000099 => "\x39",
     0x0000009a => "\x3a",
     0x0000009b => "\x3b",
     0x0000009c => "\x04",
     0x0000009d => "\x14",
     0x0000009e => "\x3e",
     0x0000009f => "\xff",
     0x000000a0 => "\x41",
     0x000000a1 => "\xaa",
     0x000000a2 => "\x4a",
     0x000000a3 => "\xb1",
     0x000000a4 => "\x9f",
     0x000000a5 => "\xb2",
     0x000000a6 => "\x6a",
     0x000000a7 => "\xb5",
     0x000000a8 => "\xbd",
     0x000000a9 => "\xb4",
     0x000000aa => "\x9a",
     0x000000ab => "\x8a",
     0x000000ac => "\x5f",
     0x000000ad => "\xca",
     0x000000ae => "\xaf",
     0x000000af => "\xbc",
     0x000000b0 => "\x90",
     0x000000b1 => "\x8f",
     0x000000b2 => "\xea",
     0x000000b3 => "\xfa",
     0x000000b4 => "\xbe",
     0x000000b5 => "\xa0",
     0x000000b6 => "\xb6",
     0x000000b7 => "\xb3",
     0x000000b8 => "\x9d",
     0x000000b9 => "\xda",
     0x000000ba => "\x9b",
     0x000000bb => "\x8b",
     0x000000bc => "\xb7",
     0x000000bd => "\xb8",
     0x000000be => "\xb9",
     0x000000bf => "\xab",
     0x000000c0 => "\x64",
     0x000000c1 => "\x65",
     0x000000c2 => "\x62",
     0x000000c3 => "\x66",
     0x000000c4 => "\x63",
     0x000000c5 => "\x67",
     0x000000c6 => "\x9e",
     0x000000c7 => "\x68",
     0x000000c8 => "\x74",
     0x000000c9 => "\x71",
     0x000000ca => "\x72",
     0x000000cb => "\x73",
     0x000000cc => "\x78",
     0x000000cd => "\x75",
     0x000000ce => "\x76",
     0x000000cf => "\x77",
     0x000000d0 => "\xac",
     0x000000d1 => "\x69",
     0x000000d2 => "\xed",
     0x000000d3 => "\xee",
     0x000000d4 => "\xeb",
     0x000000d5 => "\xef",
     0x000000d6 => "\xec",
     0x000000d7 => "\xbf",
     0x000000d8 => "\x80",
     0x000000d9 => "\xfd",
     0x000000da => "\xfe",
     0x000000db => "\xfb",
     0x000000dc => "\xfc",
     0x000000dd => "\xad",
     0x000000de => "\xae",
     0x000000df => "\x59",
     0x000000e0 => "\x44",
     0x000000e1 => "\x45",
     0x000000e2 => "\x42",
     0x000000e3 => "\x46",
     0x000000e4 => "\x43",
     0x000000e5 => "\x47",
     0x000000e6 => "\x9c",
     0x000000e7 => "\x48",
     0x000000e8 => "\x54",
     0x000000e9 => "\x51",
     0x000000ea => "\x52",
     0x000000eb => "\x53",
     0x000000ec => "\x58",
     0x000000ed => "\x55",
     0x000000ee => "\x56",
     0x000000ef => "\x57",
     0x000000f0 => "\x8c",
     0x000000f1 => "\x49",
     0x000000f2 => "\xcd",
     0x000000f3 => "\xce",
     0x000000f4 => "\xcb",
     0x000000f5 => "\xcf",
     0x000000f6 => "\xcc",
     0x000000f7 => "\xe1",
     0x000000f8 => "\x70",
     0x000000f9 => "\xdd",
     0x000000fa => "\xde",
     0x000000fb => "\xdb",
     0x000000fc => "\xdc",
     0x000000fd => "\x8d",
     0x000000fe => "\x8e",
     0x000000ff => "\xdf",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x6f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::IBM037 - Conversion routines for IBM037
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for IBM037.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
   source: IBM NLS RM Vol2 SE09-8002-01, March 1990
  alias CP037
  alias EBCDIC-CP-US
  alias EBCDIC-CP-CA
  alias EBCDIC-CP-WT
  alias EBCDIC-CP-NL
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  0000009C | STRING TERMINATOR (ST)
     05 |  00000009 | CHARACTER TABULATION (HT)
     06 |  00000086 | START OF SELECTED AREA (SSA)
     07 |  0000007F | DELETE (DEL)
     08 |  00000097 | END OF GUARDED AREA (EPA)
     09 |  0000008D | REVERSE LINE FEED (RI)
     0A |  0000008E | SINGLE-SHIFT TWO (SS2)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  0000009D | OPERATING SYSTEM COMMAND (OSC)
     15 |  00000085 | NEXT LINE (NEL)
     16 |  00000008 | BACKSPACE (BS)
     17 |  00000087 | END OF SELECTED AREA (ESA)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  00000092 | PRIVATE USE TWO (PU2)
     1B |  0000008F | SINGLE-SHIFT THREE (SS3)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000080 | PADDING CHARACTER (PAD)
     21 |  00000081 | HIGH OCTET PRESET (HOP)
     22 |  00000082 | BREAK PERMITTED HERE (BPH)
     23 |  00000083 | NO BREAK HERE (NBH)
     24 |  00000084 | INDEX (IND)
     25 |  0000000A | LINE FEED (LF)
     26 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     27 |  0000001B | ESCAPE (ESC)
     28 |  00000088 | CHARACTER TABULATION SET (HTS)
     29 |  00000089 | CHARACTER TABULATION WITH JUSTIFICATION (HTJ)
     2A |  0000008A | LINE TABULATION SET (VTS)
     2B |  0000008B | PARTIAL LINE FORWARD (PLD)
     2C |  0000008C | PARTIAL LINE BACKWARD (PLU)
     2D |  00000005 | ENQUIRY (ENQ)
     2E |  00000006 | ACKNOWLEDGE (ACK)
     2F |  00000007 | BELL (BEL)
     30 |  00000090 | DEVICE CONTROL STRING (DCS)
     31 |  00000091 | PRIVATE USE ONE (PU1)
     32 |  00000016 | SYNCHRONOUS IDLE (SYN)
     33 |  00000093 | SET TRANSMIT STATE (STS)
     34 |  00000094 | CANCEL CHARACTER (CCH)
     35 |  00000095 | MESSAGE WAITING (MW)
     36 |  00000096 | START OF GUARDED AREA (SPA)
     37 |  00000004 | END OF TRANSMISSION (EOT)
     38 |  00000098 | START OF STRING (SOS)
     39 |  00000099 | SINGLE GRAPHIC CHARACTER INTRODUCER (SGCI)
     3A |  0000009A | SINGLE CHARACTER INTRODUCER (SCI)
     3B |  0000009B | CONTROL SEQUENCE INTRODUCER (CSI)
     3C |  00000014 | DEVICE CONTROL FOUR (DC4)
     3D |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     3E |  0000009E | PRIVACY MESSAGE (PM)
     3F |  0000001A | SUBSTITUTE (SUB)
     40 |  00000020 | SPACE
     41 |  000000A0 | NO-BREAK SPACE
     42 |  000000E2 | LATIN SMALL LETTER A WITH CIRCUMFLEX
     43 |  000000E4 | LATIN SMALL LETTER A WITH DIAERESIS
     44 |  000000E0 | LATIN SMALL LETTER A WITH GRAVE
     45 |  000000E1 | LATIN SMALL LETTER A WITH ACUTE
     46 |  000000E3 | LATIN SMALL LETTER A WITH TILDE
     47 |  000000E5 | LATIN SMALL LETTER A WITH RING ABOVE
     48 |  000000E7 | LATIN SMALL LETTER C WITH CEDILLA
     49 |  000000F1 | LATIN SMALL LETTER N WITH TILDE
     4A |  000000A2 | CENT SIGN
     4B |  0000002E | FULL STOP
     4C |  0000003C | LESS-THAN SIGN
     4D |  00000028 | LEFT PARENTHESIS
     4E |  0000002B | PLUS SIGN
     4F |  0000007C | VERTICAL LINE
     50 |  00000026 | AMPERSAND
     51 |  000000E9 | LATIN SMALL LETTER E WITH ACUTE
     52 |  000000EA | LATIN SMALL LETTER E WITH CIRCUMFLEX
     53 |  000000EB | LATIN SMALL LETTER E WITH DIAERESIS
     54 |  000000E8 | LATIN SMALL LETTER E WITH GRAVE
     55 |  000000ED | LATIN SMALL LETTER I WITH ACUTE
     56 |  000000EE | LATIN SMALL LETTER I WITH CIRCUMFLEX
     57 |  000000EF | LATIN SMALL LETTER I WITH DIAERESIS
     58 |  000000EC | LATIN SMALL LETTER I WITH GRAVE
     59 |  000000DF | LATIN SMALL LETTER SHARP S (German)
     5A |  00000021 | EXCLAMATION MARK
     5B |  00000024 | DOLLAR SIGN
     5C |  0000002A | ASTERISK
     5D |  00000029 | RIGHT PARENTHESIS
     5E |  0000003B | SEMICOLON
     5F |  000000AC | NOT SIGN
     60 |  0000002D | HYPHEN-MINUS
     61 |  0000002F | SOLIDUS
     62 |  000000C2 | LATIN CAPITAL LETTER A WITH CIRCUMFLEX
     63 |  000000C4 | LATIN CAPITAL LETTER A WITH DIAERESIS
     64 |  000000C0 | LATIN CAPITAL LETTER A WITH GRAVE
     65 |  000000C1 | LATIN CAPITAL LETTER A WITH ACUTE
     66 |  000000C3 | LATIN CAPITAL LETTER A WITH TILDE
     67 |  000000C5 | LATIN CAPITAL LETTER A WITH RING ABOVE
     68 |  000000C7 | LATIN CAPITAL LETTER C WITH CEDILLA
     69 |  000000D1 | LATIN CAPITAL LETTER N WITH TILDE
     6A |  000000A6 | BROKEN BAR
     6B |  0000002C | COMMA
     6C |  00000025 | PERCENT SIGN
     6D |  0000005F | LOW LINE
     6E |  0000003E | GREATER-THAN SIGN
     6F |  0000003F | QUESTION MARK
     70 |  000000F8 | LATIN SMALL LETTER O WITH STROKE
     71 |  000000C9 | LATIN CAPITAL LETTER E WITH ACUTE
     72 |  000000CA | LATIN CAPITAL LETTER E WITH CIRCUMFLEX
     73 |  000000CB | LATIN CAPITAL LETTER E WITH DIAERESIS
     74 |  000000C8 | LATIN CAPITAL LETTER E WITH GRAVE
     75 |  000000CD | LATIN CAPITAL LETTER I WITH ACUTE
     76 |  000000CE | LATIN CAPITAL LETTER I WITH CIRCUMFLEX
     77 |  000000CF | LATIN CAPITAL LETTER I WITH DIAERESIS
     78 |  000000CC | LATIN CAPITAL LETTER I WITH GRAVE
     79 |  00000060 | GRAVE ACCENT
     7A |  0000003A | COLON
     7B |  00000023 | NUMBER SIGN
     7C |  00000040 | COMMERCIAL AT
     7D |  00000027 | APOSTROPHE
     7E |  0000003D | EQUALS SIGN
     7F |  00000022 | QUOTATION MARK
     80 |  000000D8 | LATIN CAPITAL LETTER O WITH STROKE
     81 |  00000061 | LATIN SMALL LETTER A
     82 |  00000062 | LATIN SMALL LETTER B
     83 |  00000063 | LATIN SMALL LETTER C
     84 |  00000064 | LATIN SMALL LETTER D
     85 |  00000065 | LATIN SMALL LETTER E
     86 |  00000066 | LATIN SMALL LETTER F
     87 |  00000067 | LATIN SMALL LETTER G
     88 |  00000068 | LATIN SMALL LETTER H
     89 |  00000069 | LATIN SMALL LETTER I
     8A |  000000AB | LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
     8B |  000000BB | RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
     8C |  000000F0 | LATIN SMALL LETTER ETH (Icelandic)
     8D |  000000FD | LATIN SMALL LETTER Y WITH ACUTE
     8E |  000000FE | LATIN SMALL LETTER THORN (Icelandic)
     8F |  000000B1 | PLUS-MINUS SIGN
     90 |  000000B0 | DEGREE SIGN
     91 |  0000006A | LATIN SMALL LETTER J
     92 |  0000006B | LATIN SMALL LETTER K
     93 |  0000006C | LATIN SMALL LETTER L
     94 |  0000006D | LATIN SMALL LETTER M
     95 |  0000006E | LATIN SMALL LETTER N
     96 |  0000006F | LATIN SMALL LETTER O
     97 |  00000070 | LATIN SMALL LETTER P
     98 |  00000071 | LATIN SMALL LETTER Q
     99 |  00000072 | LATIN SMALL LETTER R
     9A |  000000AA | FEMININE ORDINAL INDICATOR
     9B |  000000BA | MASCULINE ORDINAL INDICATOR
     9C |  000000E6 | LATIN SMALL LETTER AE
     9D |  000000B8 | CEDILLA
     9E |  000000C6 | LATIN CAPITAL LETTER AE
     9F |  000000A4 | CURRENCY SIGN
     A0 |  000000B5 | MICRO SIGN
     A1 |  0000007E | TILDE
     A2 |  00000073 | LATIN SMALL LETTER S
     A3 |  00000074 | LATIN SMALL LETTER T
     A4 |  00000075 | LATIN SMALL LETTER U
     A5 |  00000076 | LATIN SMALL LETTER V
     A6 |  00000077 | LATIN SMALL LETTER W
     A7 |  00000078 | LATIN SMALL LETTER X
     A8 |  00000079 | LATIN SMALL LETTER Y
     A9 |  0000007A | LATIN SMALL LETTER Z
     AA |  000000A1 | INVERTED EXCLAMATION MARK
     AB |  000000BF | INVERTED QUESTION MARK
     AC |  000000D0 | LATIN CAPITAL LETTER ETH (Icelandic)
     AD |  000000DD | LATIN CAPITAL LETTER Y WITH ACUTE
     AE |  000000DE | LATIN CAPITAL LETTER THORN (Icelandic)
     AF |  000000AE | REGISTERED SIGN
     B0 |  0000005E | CIRCUMFLEX ACCENT
     B1 |  000000A3 | POUND SIGN
     B2 |  000000A5 | YEN SIGN
     B3 |  000000B7 | MIDDLE DOT
     B4 |  000000A9 | COPYRIGHT SIGN
     B5 |  000000A7 | SECTION SIGN
     B6 |  000000B6 | PILCROW SIGN
     B7 |  000000BC | VULGAR FRACTION ONE QUARTER
     B8 |  000000BD | VULGAR FRACTION ONE HALF
     B9 |  000000BE | VULGAR FRACTION THREE QUARTERS
     BA |  0000005B | LEFT SQUARE BRACKET
     BB |  0000005D | RIGHT SQUARE BRACKET
     BC |  000000AF | MACRON
     BD |  000000A8 | DIAERESIS
     BE |  000000B4 | ACUTE ACCENT
     BF |  000000D7 | MULTIPLICATION SIGN
     C0 |  0000007B | LEFT CURLY BRACKET
     C1 |  00000041 | LATIN CAPITAL LETTER A
     C2 |  00000042 | LATIN CAPITAL LETTER B
     C3 |  00000043 | LATIN CAPITAL LETTER C
     C4 |  00000044 | LATIN CAPITAL LETTER D
     C5 |  00000045 | LATIN CAPITAL LETTER E
     C6 |  00000046 | LATIN CAPITAL LETTER F
     C7 |  00000047 | LATIN CAPITAL LETTER G
     C8 |  00000048 | LATIN CAPITAL LETTER H
     C9 |  00000049 | LATIN CAPITAL LETTER I
     CA |  000000AD | SOFT HYPHEN
     CB |  000000F4 | LATIN SMALL LETTER O WITH CIRCUMFLEX
     CC |  000000F6 | LATIN SMALL LETTER O WITH DIAERESIS
     CD |  000000F2 | LATIN SMALL LETTER O WITH GRAVE
     CE |  000000F3 | LATIN SMALL LETTER O WITH ACUTE
     CF |  000000F5 | LATIN SMALL LETTER O WITH TILDE
     D0 |  0000007D | RIGHT CURLY BRACKET
     D1 |  0000004A | LATIN CAPITAL LETTER J
     D2 |  0000004B | LATIN CAPITAL LETTER K
     D3 |  0000004C | LATIN CAPITAL LETTER L
     D4 |  0000004D | LATIN CAPITAL LETTER M
     D5 |  0000004E | LATIN CAPITAL LETTER N
     D6 |  0000004F | LATIN CAPITAL LETTER O
     D7 |  00000050 | LATIN CAPITAL LETTER P
     D8 |  00000051 | LATIN CAPITAL LETTER Q
     D9 |  00000052 | LATIN CAPITAL LETTER R
     DA |  000000B9 | SUPERSCRIPT ONE
     DB |  000000FB | LATIN SMALL LETTER U WITH CIRCUMFLEX
     DC |  000000FC | LATIN SMALL LETTER U WITH DIAERESIS
     DD |  000000F9 | LATIN SMALL LETTER U WITH GRAVE
     DE |  000000FA | LATIN SMALL LETTER U WITH ACUTE
     DF |  000000FF | LATIN SMALL LETTER Y WITH DIAERESIS
     E0 |  0000005C | REVERSE SOLIDUS
     E1 |  000000F7 | DIVISION SIGN
     E2 |  00000053 | LATIN CAPITAL LETTER S
     E3 |  00000054 | LATIN CAPITAL LETTER T
     E4 |  00000055 | LATIN CAPITAL LETTER U
     E5 |  00000056 | LATIN CAPITAL LETTER V
     E6 |  00000057 | LATIN CAPITAL LETTER W
     E7 |  00000058 | LATIN CAPITAL LETTER X
     E8 |  00000059 | LATIN CAPITAL LETTER Y
     E9 |  0000005A | LATIN CAPITAL LETTER Z
     EA |  000000B2 | SUPERSCRIPT TWO
     EB |  000000D4 | LATIN CAPITAL LETTER O WITH CIRCUMFLEX
     EC |  000000D6 | LATIN CAPITAL LETTER O WITH DIAERESIS
     ED |  000000D2 | LATIN CAPITAL LETTER O WITH GRAVE
     EE |  000000D3 | LATIN CAPITAL LETTER O WITH ACUTE
     EF |  000000D5 | LATIN CAPITAL LETTER O WITH TILDE
     F0 |  00000030 | DIGIT ZERO
     F1 |  00000031 | DIGIT ONE
     F2 |  00000032 | DIGIT TWO
     F3 |  00000033 | DIGIT THREE
     F4 |  00000034 | DIGIT FOUR
     F5 |  00000035 | DIGIT FIVE
     F6 |  00000036 | DIGIT SIX
     F7 |  00000037 | DIGIT SEVEN
     F8 |  00000038 | DIGIT EIGHT
     F9 |  00000039 | DIGIT NINE
     FA |  000000B3 | SUPERSCRIPT THREE
     FB |  000000DB | LATIN CAPITAL LETTER U WITH CIRCUMFLEX
     FC |  000000DC | LATIN CAPITAL LETTER U WITH DIAERESIS
     FD |  000000D9 | LATIN CAPITAL LETTER U WITH GRAVE
     FE |  000000DA | LATIN CAPITAL LETTER U WITH ACUTE
     FF |  0000009F | APPLICATION PROGRAM COMMAND (APC)
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/IBM038.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for IBM038.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::IBM038;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x009c,
     0x0009,
     0x0086,
     0x007f,
     0x0097,
     0x008d,
     0x008e,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x009d,
     0x0085,
     0x0008,
     0x0087,
     0x0018,
     0x0019,
     0x0092,
     0x008f,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0080,
     0x0081,
     0x0082,
     0x0083,
     0x0084,
     0x000a,
     0x0017,
     0x001b,
     0x0088,
     0x0089,
     0x008a,
     0x008b,
     0x008c,
     0x0005,
     0x0006,
     0x0007,
     0x0090,
     0x0091,
     0x0016,
     0x0093,
     0x0094,
     0x0095,
     0x0096,
     0x0004,
     0x0098,
     0x0099,
     0x009a,
     0x009b,
     0x0014,
     0x0015,
     0x009e,
     0x001a,
     0x0020,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x005b,
     0x002e,
     0x003c,
     0x0028,
     0x002b,
     0x0021,
     0x0026,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x005d,
     0x0024,
     0x002a,
     0x0029,
     0x003b,
     0x005e,
     0x002d,
     0x002f,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00a6,
     0x002c,
     0x0025,
     0x005f,
     0x003e,
     0x003f,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x0060,
     0x003a,
     0x0023,
     0x0040,
     0x0027,
     0x003d,
     0x0022,
     0xfffd,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x007e,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x007b,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x007d,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x005c,
     0xfffd,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x009f,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\xc2\x9c",
     "\x09",
     "\xc2\x86",
     "\x7f",
     "\xc2\x97",
     "\xc2\x8d",
     "\xc2\x8e",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\xc2\x9d",
     "\xc2\x85",
     "\x08",
     "\xc2\x87",
     "\x18",
     "\x19",
     "\xc2\x92",
     "\xc2\x8f",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\xc2\x80",
     "\xc2\x81",
     "\xc2\x82",
     "\xc2\x83",
     "\xc2\x84",
     "\x0a",
     "\x17",
     "\x1b",
     "\xc2\x88",
     "\xc2\x89",
     "\xc2\x8a",
     "\xc2\x8b",
     "\xc2\x8c",
     "\x05",
     "\x06",
     "\x07",
     "\xc2\x90",
     "\xc2\x91",
     "\x16",
     "\xc2\x93",
     "\xc2\x94",
     "\xc2\x95",
     "\xc2\x96",
     "\x04",
     "\xc2\x98",
     "\xc2\x99",
     "\xc2\x9a",
     "\xc2\x9b",
     "\x14",
     "\x15",
     "\xc2\x9e",
     "\x1a",
     "\x20",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x5b",
     "\x2e",
     "\x3c",
     "\x28",
     "\x2b",
     "\x21",
     "\x26",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x5d",
     "\x24",
     "\x2a",
     "\x29",
     "\x3b",
     "\x5e",
     "\x2d",
     "\x2f",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc2\xa6",
     "\x2c",
     "\x25",
     "\x5f",
     "\x3e",
     "\x3f",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x60",
     "\x3a",
     "\x23",
     "\x40",
     "\x27",
     "\x3d",
     "\x22",
     "\xef\xbf\xbd",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x7e",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x7b",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x7d",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x5c",
     "\xef\xbf\xbd",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc2\x9f",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x37",
     0x00000005 => "\x2d",
     0x00000006 => "\x2e",
     0x00000007 => "\x2f",
     0x00000008 => "\x16",
     0x00000009 => "\x05",
     0x0000000a => "\x25",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x3c",
     0x00000015 => "\x3d",
     0x00000016 => "\x32",
     0x00000017 => "\x26",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x3f",
     0x0000001b => "\x27",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x40",
     0x00000021 => "\x4f",
     0x00000022 => "\x7f",
     0x00000023 => "\x7b",
     0x00000024 => "\x5b",
     0x00000025 => "\x6c",
     0x00000026 => "\x50",
     0x00000027 => "\x7d",
     0x00000028 => "\x4d",
     0x00000029 => "\x5d",
     0x0000002a => "\x5c",
     0x0000002b => "\x4e",
     0x0000002c => "\x6b",
     0x0000002d => "\x60",
     0x0000002e => "\x4b",
     0x0000002f => "\x61",
     0x00000030 => "\xf0",
     0x00000031 => "\xf1",
     0x00000032 => "\xf2",
     0x00000033 => "\xf3",
     0x00000034 => "\xf4",
     0x00000035 => "\xf5",
     0x00000036 => "\xf6",
     0x00000037 => "\xf7",
     0x00000038 => "\xf8",
     0x00000039 => "\xf9",
     0x0000003a => "\x7a",
     0x0000003b => "\x5e",
     0x0000003c => "\x4c",
     0x0000003d => "\x7e",
     0x0000003e => "\x6e",
     0x0000003f => "\x6f",
     0x00000040 => "\x7c",
     0x00000041 => "\xc1",
     0x00000042 => "\xc2",
     0x00000043 => "\xc3",
     0x00000044 => "\xc4",
     0x00000045 => "\xc5",
     0x00000046 => "\xc6",
     0x00000047 => "\xc7",
     0x00000048 => "\xc8",
     0x00000049 => "\xc9",
     0x0000004a => "\xd1",
     0x0000004b => "\xd2",
     0x0000004c => "\xd3",
     0x0000004d => "\xd4",
     0x0000004e => "\xd5",
     0x0000004f => "\xd6",
     0x00000050 => "\xd7",
     0x00000051 => "\xd8",
     0x00000052 => "\xd9",
     0x00000053 => "\xe2",
     0x00000054 => "\xe3",
     0x00000055 => "\xe4",
     0x00000056 => "\xe5",
     0x00000057 => "\xe6",
     0x00000058 => "\xe7",
     0x00000059 => "\xe8",
     0x0000005a => "\xe9",
     0x0000005b => "\x4a",
     0x0000005c => "\xe0",
     0x0000005d => "\x5a",
     0x0000005e => "\x5f",
     0x0000005f => "\x6d",
     0x00000060 => "\x79",
     0x00000061 => "\x81",
     0x00000062 => "\x82",
     0x00000063 => "\x83",
     0x00000064 => "\x84",
     0x00000065 => "\x85",
     0x00000066 => "\x86",
     0x00000067 => "\x87",
     0x00000068 => "\x88",
     0x00000069 => "\x89",
     0x0000006a => "\x91",
     0x0000006b => "\x92",
     0x0000006c => "\x93",
     0x0000006d => "\x94",
     0x0000006e => "\x95",
     0x0000006f => "\x96",
     0x00000070 => "\x97",
     0x00000071 => "\x98",
     0x00000072 => "\x99",
     0x00000073 => "\xa2",
     0x00000074 => "\xa3",
     0x00000075 => "\xa4",
     0x00000076 => "\xa5",
     0x00000077 => "\xa6",
     0x00000078 => "\xa7",
     0x00000079 => "\xa8",
     0x0000007a => "\xa9",
     0x0000007b => "\xc0",
     0x0000007d => "\xd0",
     0x0000007e => "\xa1",
     0x0000007f => "\x07",
     0x00000080 => "\x20",
     0x00000081 => "\x21",
     0x00000082 => "\x22",
     0x00000083 => "\x23",
     0x00000084 => "\x24",
     0x00000085 => "\x15",
     0x00000086 => "\x06",
     0x00000087 => "\x17",
     0x00000088 => "\x28",
     0x00000089 => "\x29",
     0x0000008a => "\x2a",
     0x0000008b => "\x2b",
     0x0000008c => "\x2c",
     0x0000008d => "\x09",
     0x0000008e => "\x0a",
     0x0000008f => "\x1b",
     0x00000090 => "\x30",
     0x00000091 => "\x31",
     0x00000092 => "\x1a",
     0x00000093 => "\x33",
     0x00000094 => "\x34",
     0x00000095 => "\x35",
     0x00000096 => "\x36",
     0x00000097 => "\x08",
     0x00000098 => "\x38",
     0x00000099 => "\x39",
     0x0000009a => "\x3a",
     0x0000009b => "\x3b",
     0x0000009c => "\x04",
     0x0000009d => "\x14",
     0x0000009e => "\x3e",
     0x0000009f => "\xff",
     0x000000a6 => "\x6a",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x6f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::IBM038 - Conversion routines for IBM038
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for IBM038.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
   source: IBM 3174 Character Set Ref, GA27-3831-02, March 1990
  alias EBCDIC-INT
  alias CP038
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  0000009C | STRING TERMINATOR (ST)
     05 |  00000009 | CHARACTER TABULATION (HT)
     06 |  00000086 | START OF SELECTED AREA (SSA)
     07 |  0000007F | DELETE (DEL)
     08 |  00000097 | END OF GUARDED AREA (EPA)
     09 |  0000008D | REVERSE LINE FEED (RI)
     0A |  0000008E | SINGLE-SHIFT TWO (SS2)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  0000009D | OPERATING SYSTEM COMMAND (OSC)
     15 |  00000085 | NEXT LINE (NEL)
     16 |  00000008 | BACKSPACE (BS)
     17 |  00000087 | END OF SELECTED AREA (ESA)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  00000092 | PRIVATE USE TWO (PU2)
     1B |  0000008F | SINGLE-SHIFT THREE (SS3)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000080 | PADDING CHARACTER (PAD)
     21 |  00000081 | HIGH OCTET PRESET (HOP)
     22 |  00000082 | BREAK PERMITTED HERE (BPH)
     23 |  00000083 | NO BREAK HERE (NBH)
     24 |  00000084 | INDEX (IND)
     25 |  0000000A | LINE FEED (LF)
     26 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     27 |  0000001B | ESCAPE (ESC)
     28 |  00000088 | CHARACTER TABULATION SET (HTS)
     29 |  00000089 | CHARACTER TABULATION WITH JUSTIFICATION (HTJ)
     2A |  0000008A | LINE TABULATION SET (VTS)
     2B |  0000008B | PARTIAL LINE FORWARD (PLD)
     2C |  0000008C | PARTIAL LINE BACKWARD (PLU)
     2D |  00000005 | ENQUIRY (ENQ)
     2E |  00000006 | ACKNOWLEDGE (ACK)
     2F |  00000007 | BELL (BEL)
     30 |  00000090 | DEVICE CONTROL STRING (DCS)
     31 |  00000091 | PRIVATE USE ONE (PU1)
     32 |  00000016 | SYNCHRONOUS IDLE (SYN)
     33 |  00000093 | SET TRANSMIT STATE (STS)
     34 |  00000094 | CANCEL CHARACTER (CCH)
     35 |  00000095 | MESSAGE WAITING (MW)
     36 |  00000096 | START OF GUARDED AREA (SPA)
     37 |  00000004 | END OF TRANSMISSION (EOT)
     38 |  00000098 | START OF STRING (SOS)
     39 |  00000099 | SINGLE GRAPHIC CHARACTER INTRODUCER (SGCI)
     3A |  0000009A | SINGLE CHARACTER INTRODUCER (SCI)
     3B |  0000009B | CONTROL SEQUENCE INTRODUCER (CSI)
     3C |  00000014 | DEVICE CONTROL FOUR (DC4)
     3D |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     3E |  0000009E | PRIVACY MESSAGE (PM)
     3F |  0000001A | SUBSTITUTE (SUB)
     40 |  00000020 | SPACE
     4A |  0000005B | LEFT SQUARE BRACKET
     4B |  0000002E | FULL STOP
     4C |  0000003C | LESS-THAN SIGN
     4D |  00000028 | LEFT PARENTHESIS
     4E |  0000002B | PLUS SIGN
     4F |  00000021 | EXCLAMATION MARK
     50 |  00000026 | AMPERSAND
     5A |  0000005D | RIGHT SQUARE BRACKET
     5B |  00000024 | DOLLAR SIGN
     5C |  0000002A | ASTERISK
     5D |  00000029 | RIGHT PARENTHESIS
     5E |  0000003B | SEMICOLON
     5F |  0000005E | CIRCUMFLEX ACCENT
     60 |  0000002D | HYPHEN-MINUS
     61 |  0000002F | SOLIDUS
     6A |  000000A6 | BROKEN BAR
     6B |  0000002C | COMMA
     6C |  00000025 | PERCENT SIGN
     6D |  0000005F | LOW LINE
     6E |  0000003E | GREATER-THAN SIGN
     6F |  0000003F | QUESTION MARK
     79 |  00000060 | GRAVE ACCENT
     7A |  0000003A | COLON
     7B |  00000023 | NUMBER SIGN
     7C |  00000040 | COMMERCIAL AT
     7D |  00000027 | APOSTROPHE
     7E |  0000003D | EQUALS SIGN
     7F |  00000022 | QUOTATION MARK
     81 |  00000061 | LATIN SMALL LETTER A
     82 |  00000062 | LATIN SMALL LETTER B
     83 |  00000063 | LATIN SMALL LETTER C
     84 |  00000064 | LATIN SMALL LETTER D
     85 |  00000065 | LATIN SMALL LETTER E
     86 |  00000066 | LATIN SMALL LETTER F
     87 |  00000067 | LATIN SMALL LETTER G
     88 |  00000068 | LATIN SMALL LETTER H
     89 |  00000069 | LATIN SMALL LETTER I
     91 |  0000006A | LATIN SMALL LETTER J
     92 |  0000006B | LATIN SMALL LETTER K
     93 |  0000006C | LATIN SMALL LETTER L
     94 |  0000006D | LATIN SMALL LETTER M
     95 |  0000006E | LATIN SMALL LETTER N
     96 |  0000006F | LATIN SMALL LETTER O
     97 |  00000070 | LATIN SMALL LETTER P
     98 |  00000071 | LATIN SMALL LETTER Q
     99 |  00000072 | LATIN SMALL LETTER R
     A1 |  0000007E | TILDE
     A2 |  00000073 | LATIN SMALL LETTER S
     A3 |  00000074 | LATIN SMALL LETTER T
     A4 |  00000075 | LATIN SMALL LETTER U
     A5 |  00000076 | LATIN SMALL LETTER V
     A6 |  00000077 | LATIN SMALL LETTER W
     A7 |  00000078 | LATIN SMALL LETTER X
     A8 |  00000079 | LATIN SMALL LETTER Y
     A9 |  0000007A | LATIN SMALL LETTER Z
     C0 |  0000007B | LEFT CURLY BRACKET
     C1 |  00000041 | LATIN CAPITAL LETTER A
     C2 |  00000042 | LATIN CAPITAL LETTER B
     C3 |  00000043 | LATIN CAPITAL LETTER C
     C4 |  00000044 | LATIN CAPITAL LETTER D
     C5 |  00000045 | LATIN CAPITAL LETTER E
     C6 |  00000046 | LATIN CAPITAL LETTER F
     C7 |  00000047 | LATIN CAPITAL LETTER G
     C8 |  00000048 | LATIN CAPITAL LETTER H
     C9 |  00000049 | LATIN CAPITAL LETTER I
     D0 |  0000007D | RIGHT CURLY BRACKET
     D1 |  0000004A | LATIN CAPITAL LETTER J
     D2 |  0000004B | LATIN CAPITAL LETTER K
     D3 |  0000004C | LATIN CAPITAL LETTER L
     D4 |  0000004D | LATIN CAPITAL LETTER M
     D5 |  0000004E | LATIN CAPITAL LETTER N
     D6 |  0000004F | LATIN CAPITAL LETTER O
     D7 |  00000050 | LATIN CAPITAL LETTER P
     D8 |  00000051 | LATIN CAPITAL LETTER Q
     D9 |  00000052 | LATIN CAPITAL LETTER R
     E0 |  0000005C | REVERSE SOLIDUS
     E2 |  00000053 | LATIN CAPITAL LETTER S
     E3 |  00000054 | LATIN CAPITAL LETTER T
     E4 |  00000055 | LATIN CAPITAL LETTER U
     E5 |  00000056 | LATIN CAPITAL LETTER V
     E6 |  00000057 | LATIN CAPITAL LETTER W
     E7 |  00000058 | LATIN CAPITAL LETTER X
     E8 |  00000059 | LATIN CAPITAL LETTER Y
     E9 |  0000005A | LATIN CAPITAL LETTER Z
     F0 |  00000030 | DIGIT ZERO
     F1 |  00000031 | DIGIT ONE
     F2 |  00000032 | DIGIT TWO
     F3 |  00000033 | DIGIT THREE
     F4 |  00000034 | DIGIT FOUR
     F5 |  00000035 | DIGIT FIVE
     F6 |  00000036 | DIGIT SIX
     F7 |  00000037 | DIGIT SEVEN
     F8 |  00000038 | DIGIT EIGHT
     F9 |  00000039 | DIGIT NINE
     FF |  0000009F | APPLICATION PROGRAM COMMAND (APC)
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/IBM1004.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for IBM1004.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::IBM1004;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x0004,
     0x0005,
     0x0006,
     0x0007,
     0x0008,
     0x0009,
     0x000a,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x0014,
     0x0015,
     0x0016,
     0x0017,
     0x0018,
     0x0019,
     0x001a,
     0x001b,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0020,
     0x0021,
     0x0022,
     0x0023,
     0x0024,
     0x0025,
     0x0026,
     0x0027,
     0x0028,
     0x0029,
     0x002a,
     0x002b,
     0x002c,
     0x002d,
     0x002e,
     0x002f,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x003a,
     0x003b,
     0x003c,
     0x003d,
     0x003e,
     0x003f,
     0x0040,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x005b,
     0x005c,
     0x005d,
     0x005e,
     0x005f,
     0x0060,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x007b,
     0x007c,
     0x007d,
     0x007e,
     0x007f,
     0xfffd,
     0xfffd,
     0x201a,
     0xfffd,
     0x201e,
     0x2026,
     0x2020,
     0x2021,
     0x02c6,
     0x2030,
     0x0160,
     0x2039,
     0x0152,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x2018,
     0x2019,
     0x201c,
     0x201d,
     0x2022,
     0x2013,
     0x2014,
     0x02dc,
     0x2122,
     0x0161,
     0x203a,
     0x0153,
     0xfffd,
     0xfffd,
     0x0178,
     0x00a0,
     0x00a1,
     0x00a2,
     0x00a3,
     0x00a4,
     0x00a5,
     0x00a6,
     0x00a7,
     0x00a8,
     0x00a9,
     0x00aa,
     0x00ab,
     0x00ac,
     0x00ad,
     0x00ae,
     0x00af,
     0x00b0,
     0x00b1,
     0x00b2,
     0x00b3,
     0x00b4,
     0x00b5,
     0x00b6,
     0x00b7,
     0x00b8,
     0x00b9,
     0x00ba,
     0x00bb,
     0x00bc,
     0x00bd,
     0x00be,
     0x00bf,
     0x00c0,
     0x00c1,
     0x00c2,
     0x00c3,
     0x00c4,
     0x00c5,
     0x00c6,
     0x00c7,
     0x00c8,
     0x00c9,
     0x00ca,
     0x00cb,
     0x00cc,
     0x00cd,
     0x00ce,
     0x00cf,
     0x00d0,
     0x00d1,
     0x00d2,
     0x00d3,
     0x00d4,
     0x00d5,
     0x00d6,
     0x00d7,
     0x00d8,
     0x00d9,
     0x00da,
     0x00db,
     0x00dc,
     0x00dd,
     0x00de,
     0x00df,
     0x00e0,
     0x00e1,
     0x00e2,
     0x00e3,
     0x00e4,
     0x00e5,
     0x00e6,
     0x00e7,
     0x00e8,
     0x00e9,
     0x00ea,
     0x00eb,
     0x00ec,
     0x00ed,
     0x00ee,
     0x00ef,
     0x00f0,
     0x00f1,
     0x00f2,
     0x00f3,
     0x00f4,
     0x00f5,
     0x00f6,
     0x00f7,
     0x00f8,
     0x00f9,
     0x00fa,
     0x00fb,
     0x00fc,
     0x00fd,
     0x00fe,
     0x00ff,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\x04",
     "\x05",
     "\x06",
     "\x07",
     "\x08",
     "\x09",
     "\x0a",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\x14",
     "\x15",
     "\x16",
     "\x17",
     "\x18",
     "\x19",
     "\x1a",
     "\x1b",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\x20",
     "\x21",
     "\x22",
     "\x23",
     "\x24",
     "\x25",
     "\x26",
     "\x27",
     "\x28",
     "\x29",
     "\x2a",
     "\x2b",
     "\x2c",
     "\x2d",
     "\x2e",
     "\x2f",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\x3a",
     "\x3b",
     "\x3c",
     "\x3d",
     "\x3e",
     "\x3f",
     "\x40",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\x5b",
     "\x5c",
     "\x5d",
     "\x5e",
     "\x5f",
     "\x60",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\x7b",
     "\x7c",
     "\x7d",
     "\x7e",
     "\x7f",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xe2\x80\x9a",
     "\xef\xbf\xbd",
     "\xe2\x80\x9e",
     "\xe2\x80\xa6",
     "\xe2\x80\xa0",
     "\xe2\x80\xa1",
     "\xcb\x86",
     "\xe2\x80\xb0",
     "\xc5\xa0",
     "\xe2\x80\xb9",
     "\xc5\x92",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xe2\x80\x98",
     "\xe2\x80\x99",
     "\xe2\x80\x9c",
     "\xe2\x80\x9d",
     "\xe2\x80\xa2",
     "\xe2\x80\x93",
     "\xe2\x80\x94",
     "\xcb\x9c",
     "\xe2\x84\xa2",
     "\xc5\xa1",
     "\xe2\x80\xba",
     "\xc5\x93",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc5\xb8",
     "\xc2\xa0",
     "\xc2\xa1",
     "\xc2\xa2",
     "\xc2\xa3",
     "\xc2\xa4",
     "\xc2\xa5",
     "\xc2\xa6",
     "\xc2\xa7",
     "\xc2\xa8",
     "\xc2\xa9",
     "\xc2\xaa",
     "\xc2\xab",
     "\xc2\xac",
     "\xc2\xad",
     "\xc2\xae",
     "\xc2\xaf",
     "\xc2\xb0",
     "\xc2\xb1",
     "\xc2\xb2",
     "\xc2\xb3",
     "\xc2\xb4",
     "\xc2\xb5",
     "\xc2\xb6",
     "\xc2\xb7",
     "\xc2\xb8",
     "\xc2\xb9",
     "\xc2\xba",
     "\xc2\xbb",
     "\xc2\xbc",
     "\xc2\xbd",
     "\xc2\xbe",
     "\xc2\xbf",
     "\xc3\x80",
     "\xc3\x81",
     "\xc3\x82",
     "\xc3\x83",
     "\xc3\x84",
     "\xc3\x85",
     "\xc3\x86",
     "\xc3\x87",
     "\xc3\x88",
     "\xc3\x89",
     "\xc3\x8a",
     "\xc3\x8b",
     "\xc3\x8c",
     "\xc3\x8d",
     "\xc3\x8e",
     "\xc3\x8f",
     "\xc3\x90",
     "\xc3\x91",
     "\xc3\x92",
     "\xc3\x93",
     "\xc3\x94",
     "\xc3\x95",
     "\xc3\x96",
     "\xc3\x97",
     "\xc3\x98",
     "\xc3\x99",
     "\xc3\x9a",
     "\xc3\x9b",
     "\xc3\x9c",
     "\xc3\x9d",
     "\xc3\x9e",
     "\xc3\x9f",
     "\xc3\xa0",
     "\xc3\xa1",
     "\xc3\xa2",
     "\xc3\xa3",
     "\xc3\xa4",
     "\xc3\xa5",
     "\xc3\xa6",
     "\xc3\xa7",
     "\xc3\xa8",
     "\xc3\xa9",
     "\xc3\xaa",
     "\xc3\xab",
     "\xc3\xac",
     "\xc3\xad",
     "\xc3\xae",
     "\xc3\xaf",
     "\xc3\xb0",
     "\xc3\xb1",
     "\xc3\xb2",
     "\xc3\xb3",
     "\xc3\xb4",
     "\xc3\xb5",
     "\xc3\xb6",
     "\xc3\xb7",
     "\xc3\xb8",
     "\xc3\xb9",
     "\xc3\xba",
     "\xc3\xbb",
     "\xc3\xbc",
     "\xc3\xbd",
     "\xc3\xbe",
     "\xc3\xbf",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x04",
     0x00000005 => "\x05",
     0x00000006 => "\x06",
     0x00000007 => "\x07",
     0x00000008 => "\x08",
     0x00000009 => "\x09",
     0x0000000a => "\x0a",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x14",
     0x00000015 => "\x15",
     0x00000016 => "\x16",
     0x00000017 => "\x17",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x1a",
     0x0000001b => "\x1b",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x20",
     0x00000021 => "\x21",
     0x00000022 => "\x22",
     0x00000023 => "\x23",
     0x00000024 => "\x24",
     0x00000025 => "\x25",
     0x00000026 => "\x26",
     0x00000027 => "\x27",
     0x00000028 => "\x28",
     0x00000029 => "\x29",
     0x0000002a => "\x2a",
     0x0000002b => "\x2b",
     0x0000002c => "\x2c",
     0x0000002d => "\x2d",
     0x0000002e => "\x2e",
     0x0000002f => "\x2f",
     0x00000030 => "\x30",
     0x00000031 => "\x31",
     0x00000032 => "\x32",
     0x00000033 => "\x33",
     0x00000034 => "\x34",
     0x00000035 => "\x35",
     0x00000036 => "\x36",
     0x00000037 => "\x37",
     0x00000038 => "\x38",
     0x00000039 => "\x39",
     0x0000003a => "\x3a",
     0x0000003b => "\x3b",
     0x0000003c => "\x3c",
     0x0000003d => "\x3d",
     0x0000003e => "\x3e",
     0x0000003f => "\x3f",
     0x00000040 => "\x40",
     0x00000041 => "\x41",
     0x00000042 => "\x42",
     0x00000043 => "\x43",
     0x00000044 => "\x44",
     0x00000045 => "\x45",
     0x00000046 => "\x46",
     0x00000047 => "\x47",
     0x00000048 => "\x48",
     0x00000049 => "\x49",
     0x0000004a => "\x4a",
     0x0000004b => "\x4b",
     0x0000004c => "\x4c",
     0x0000004d => "\x4d",
     0x0000004e => "\x4e",
     0x0000004f => "\x4f",
     0x00000050 => "\x50",
     0x00000051 => "\x51",
     0x00000052 => "\x52",
     0x00000053 => "\x53",
     0x00000054 => "\x54",
     0x00000055 => "\x55",
     0x00000056 => "\x56",
     0x00000057 => "\x57",
     0x00000058 => "\x58",
     0x00000059 => "\x59",
     0x0000005a => "\x5a",
     0x0000005b => "\x5b",
     0x0000005c => "\x5c",
     0x0000005d => "\x5d",
     0x0000005e => "\x5e",
     0x0000005f => "\x5f",
     0x00000060 => "\x60",
     0x00000061 => "\x61",
     0x00000062 => "\x62",
     0x00000063 => "\x63",
     0x00000064 => "\x64",
     0x00000065 => "\x65",
     0x00000066 => "\x66",
     0x00000067 => "\x67",
     0x00000068 => "\x68",
     0x00000069 => "\x69",
     0x0000006a => "\x6a",
     0x0000006b => "\x6b",
     0x0000006c => "\x6c",
     0x0000006d => "\x6d",
     0x0000006e => "\x6e",
     0x0000006f => "\x6f",
     0x00000070 => "\x70",
     0x00000071 => "\x71",
     0x00000072 => "\x72",
     0x00000073 => "\x73",
     0x00000074 => "\x74",
     0x00000075 => "\x75",
     0x00000076 => "\x76",
     0x00000077 => "\x77",
     0x00000078 => "\x78",
     0x00000079 => "\x79",
     0x0000007a => "\x7a",
     0x0000007b => "\x7b",
     0x0000007c => "\x7c",
     0x0000007d => "\x7d",
     0x0000007e => "\x7e",
     0x0000007f => "\x7f",
     0x000000a0 => "\xa0",
     0x000000a1 => "\xa1",
     0x000000a2 => "\xa2",
     0x000000a3 => "\xa3",
     0x000000a4 => "\xa4",
     0x000000a5 => "\xa5",
     0x000000a6 => "\xa6",
     0x000000a7 => "\xa7",
     0x000000a8 => "\xa8",
     0x000000a9 => "\xa9",
     0x000000aa => "\xaa",
     0x000000ab => "\xab",
     0x000000ac => "\xac",
     0x000000ad => "\xad",
     0x000000ae => "\xae",
     0x000000af => "\xaf",
     0x000000b0 => "\xb0",
     0x000000b1 => "\xb1",
     0x000000b2 => "\xb2",
     0x000000b3 => "\xb3",
     0x000000b4 => "\xb4",
     0x000000b5 => "\xb5",
     0x000000b6 => "\xb6",
     0x000000b7 => "\xb7",
     0x000000b8 => "\xb8",
     0x000000b9 => "\xb9",
     0x000000ba => "\xba",
     0x000000bb => "\xbb",
     0x000000bc => "\xbc",
     0x000000bd => "\xbd",
     0x000000be => "\xbe",
     0x000000bf => "\xbf",
     0x000000c0 => "\xc0",
     0x000000c1 => "\xc1",
     0x000000c2 => "\xc2",
     0x000000c3 => "\xc3",
     0x000000c4 => "\xc4",
     0x000000c5 => "\xc5",
     0x000000c6 => "\xc6",
     0x000000c7 => "\xc7",
     0x000000c8 => "\xc8",
     0x000000c9 => "\xc9",
     0x000000ca => "\xca",
     0x000000cb => "\xcb",
     0x000000cc => "\xcc",
     0x000000cd => "\xcd",
     0x000000ce => "\xce",
     0x000000cf => "\xcf",
     0x000000d0 => "\xd0",
     0x000000d1 => "\xd1",
     0x000000d2 => "\xd2",
     0x000000d3 => "\xd3",
     0x000000d4 => "\xd4",
     0x000000d5 => "\xd5",
     0x000000d6 => "\xd6",
     0x000000d7 => "\xd7",
     0x000000d8 => "\xd8",
     0x000000d9 => "\xd9",
     0x000000da => "\xda",
     0x000000db => "\xdb",
     0x000000dc => "\xdc",
     0x000000dd => "\xdd",
     0x000000de => "\xde",
     0x000000df => "\xdf",
     0x000000e0 => "\xe0",
     0x000000e1 => "\xe1",
     0x000000e2 => "\xe2",
     0x000000e3 => "\xe3",
     0x000000e4 => "\xe4",
     0x000000e5 => "\xe5",
     0x000000e6 => "\xe6",
     0x000000e7 => "\xe7",
     0x000000e8 => "\xe8",
     0x000000e9 => "\xe9",
     0x000000ea => "\xea",
     0x000000eb => "\xeb",
     0x000000ec => "\xec",
     0x000000ed => "\xed",
     0x000000ee => "\xee",
     0x000000ef => "\xef",
     0x000000f0 => "\xf0",
     0x000000f1 => "\xf1",
     0x000000f2 => "\xf2",
     0x000000f3 => "\xf3",
     0x000000f4 => "\xf4",
     0x000000f5 => "\xf5",
     0x000000f6 => "\xf6",
     0x000000f7 => "\xf7",
     0x000000f8 => "\xf8",
     0x000000f9 => "\xf9",
     0x000000fa => "\xfa",
     0x000000fb => "\xfb",
     0x000000fc => "\xfc",
     0x000000fd => "\xfd",
     0x000000fe => "\xfe",
     0x000000ff => "\xff",
     0x00000152 => "\x8c",
     0x00000153 => "\x9c",
     0x00000160 => "\x8a",
     0x00000161 => "\x9a",
     0x00000178 => "\x9f",
     0x000002c6 => "\x88",
     0x000002dc => "\x98",
     0x00002013 => "\x96",
     0x00002014 => "\x97",
     0x00002018 => "\x91",
     0x00002019 => "\x92",
     0x0000201a => "\x82",
     0x0000201c => "\x93",
     0x0000201d => "\x94",
     0x0000201e => "\x84",
     0x00002020 => "\x86",
     0x00002021 => "\x87",
     0x00002022 => "\x95",
     0x00002026 => "\x85",
     0x00002030 => "\x89",
     0x00002039 => "\x8b",
     0x0000203a => "\x9b",
     0x00002122 => "\x99",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::IBM1004 - Conversion routines for IBM1004
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for IBM1004.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
   source: CEN/TC304 N283, 1994-02-04
  alias CP1004
  alias OS2LATIN1
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  00000004 | END OF TRANSMISSION (EOT)
     05 |  00000005 | ENQUIRY (ENQ)
     06 |  00000006 | ACKNOWLEDGE (ACK)
     07 |  00000007 | BELL (BEL)
     08 |  00000008 | BACKSPACE (BS)
     09 |  00000009 | CHARACTER TABULATION (HT)
     0A |  0000000A | LINE FEED (LF)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  00000014 | DEVICE CONTROL FOUR (DC4)
     15 |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     16 |  00000016 | SYNCHRONOUS IDLE (SYN)
     17 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  0000001A | SUBSTITUTE (SUB)
     1B |  0000001B | ESCAPE (ESC)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000020 | SPACE
     21 |  00000021 | EXCLAMATION MARK
     22 |  00000022 | QUOTATION MARK
     23 |  00000023 | NUMBER SIGN
     24 |  00000024 | DOLLAR SIGN
     25 |  00000025 | PERCENT SIGN
     26 |  00000026 | AMPERSAND
     27 |  00000027 | APOSTROPHE
     28 |  00000028 | LEFT PARENTHESIS
     29 |  00000029 | RIGHT PARENTHESIS
     2A |  0000002A | ASTERISK
     2B |  0000002B | PLUS SIGN
     2C |  0000002C | COMMA
     2D |  0000002D | HYPHEN-MINUS
     2E |  0000002E | FULL STOP
     2F |  0000002F | SOLIDUS
     30 |  00000030 | DIGIT ZERO
     31 |  00000031 | DIGIT ONE
     32 |  00000032 | DIGIT TWO
     33 |  00000033 | DIGIT THREE
     34 |  00000034 | DIGIT FOUR
     35 |  00000035 | DIGIT FIVE
     36 |  00000036 | DIGIT SIX
     37 |  00000037 | DIGIT SEVEN
     38 |  00000038 | DIGIT EIGHT
     39 |  00000039 | DIGIT NINE
     3A |  0000003A | COLON
     3B |  0000003B | SEMICOLON
     3C |  0000003C | LESS-THAN SIGN
     3D |  0000003D | EQUALS SIGN
     3E |  0000003E | GREATER-THAN SIGN
     3F |  0000003F | QUESTION MARK
     40 |  00000040 | COMMERCIAL AT
     41 |  00000041 | LATIN CAPITAL LETTER A
     42 |  00000042 | LATIN CAPITAL LETTER B
     43 |  00000043 | LATIN CAPITAL LETTER C
     44 |  00000044 | LATIN CAPITAL LETTER D
     45 |  00000045 | LATIN CAPITAL LETTER E
     46 |  00000046 | LATIN CAPITAL LETTER F
     47 |  00000047 | LATIN CAPITAL LETTER G
     48 |  00000048 | LATIN CAPITAL LETTER H
     49 |  00000049 | LATIN CAPITAL LETTER I
     4A |  0000004A | LATIN CAPITAL LETTER J
     4B |  0000004B | LATIN CAPITAL LETTER K
     4C |  0000004C | LATIN CAPITAL LETTER L
     4D |  0000004D | LATIN CAPITAL LETTER M
     4E |  0000004E | LATIN CAPITAL LETTER N
     4F |  0000004F | LATIN CAPITAL LETTER O
     50 |  00000050 | LATIN CAPITAL LETTER P
     51 |  00000051 | LATIN CAPITAL LETTER Q
     52 |  00000052 | LATIN CAPITAL LETTER R
     53 |  00000053 | LATIN CAPITAL LETTER S
     54 |  00000054 | LATIN CAPITAL LETTER T
     55 |  00000055 | LATIN CAPITAL LETTER U
     56 |  00000056 | LATIN CAPITAL LETTER V
     57 |  00000057 | LATIN CAPITAL LETTER W
     58 |  00000058 | LATIN CAPITAL LETTER X
     59 |  00000059 | LATIN CAPITAL LETTER Y
     5A |  0000005A | LATIN CAPITAL LETTER Z
     5B |  0000005B | LEFT SQUARE BRACKET
     5C |  0000005C | REVERSE SOLIDUS
     5D |  0000005D | RIGHT SQUARE BRACKET
     5E |  0000005E | CIRCUMFLEX ACCENT
     5F |  0000005F | LOW LINE
     60 |  00000060 | GRAVE ACCENT
     61 |  00000061 | LATIN SMALL LETTER A
     62 |  00000062 | LATIN SMALL LETTER B
     63 |  00000063 | LATIN SMALL LETTER C
     64 |  00000064 | LATIN SMALL LETTER D
     65 |  00000065 | LATIN SMALL LETTER E
     66 |  00000066 | LATIN SMALL LETTER F
     67 |  00000067 | LATIN SMALL LETTER G
     68 |  00000068 | LATIN SMALL LETTER H
     69 |  00000069 | LATIN SMALL LETTER I
     6A |  0000006A | LATIN SMALL LETTER J
     6B |  0000006B | LATIN SMALL LETTER K
     6C |  0000006C | LATIN SMALL LETTER L
     6D |  0000006D | LATIN SMALL LETTER M
     6E |  0000006E | LATIN SMALL LETTER N
     6F |  0000006F | LATIN SMALL LETTER O
     70 |  00000070 | LATIN SMALL LETTER P
     71 |  00000071 | LATIN SMALL LETTER Q
     72 |  00000072 | LATIN SMALL LETTER R
     73 |  00000073 | LATIN SMALL LETTER S
     74 |  00000074 | LATIN SMALL LETTER T
     75 |  00000075 | LATIN SMALL LETTER U
     76 |  00000076 | LATIN SMALL LETTER V
     77 |  00000077 | LATIN SMALL LETTER W
     78 |  00000078 | LATIN SMALL LETTER X
     79 |  00000079 | LATIN SMALL LETTER Y
     7A |  0000007A | LATIN SMALL LETTER Z
     7B |  0000007B | LEFT CURLY BRACKET
     7C |  0000007C | VERTICAL LINE
     7D |  0000007D | RIGHT CURLY BRACKET
     7E |  0000007E | TILDE
     7F |  0000007F | DELETE (DEL)
     82 |  0000201A | SINGLE LOW-9 QUOTATION MARK
     84 |  0000201E | DOUBLE LOW-9 QUOTATION MARK
     85 |  00002026 | HORIZONTAL ELLIPSIS
     86 |  00002020 | DAGGER
     87 |  00002021 | DOUBLE DAGGER
     88 |  000002C6 | MODIFIER LETTER CIRCUMFLEX ACCENT
     89 |  00002030 | PER MILLE SIGN
     8A |  00000160 | LATIN CAPITAL LETTER S WITH CARON
     8B |  00002039 | SINGLE LEFT-POINTING ANGLE QUOTATION MARK
     8C |  00000152 | LATIN CAPITAL LIGATURE OE
     91 |  00002018 | LEFT SINGLE QUOTATION MARK
     92 |  00002019 | RIGHT SINGLE QUOTATION MARK
     93 |  0000201C | LEFT DOUBLE QUOTATION MARK
     94 |  0000201D | RIGHT DOUBLE QUOTATION MARK
     95 |  00002022 | BULLET
     96 |  00002013 | EN DASH
     97 |  00002014 | EM DASH
     98 |  000002DC | SMALL TILDE
     99 |  00002122 | TRADE MARK SIGN
     9A |  00000161 | LATIN SMALL LETTER S WITH CARON
     9B |  0000203A | SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
     9C |  00000153 | LATIN SMALL LIGATURE OE
     9F |  00000178 | LATIN CAPITAL LETTER Y WITH DIAERESIS
     A0 |  000000A0 | NO-BREAK SPACE
     A1 |  000000A1 | INVERTED EXCLAMATION MARK
     A2 |  000000A2 | CENT SIGN
     A3 |  000000A3 | POUND SIGN
     A4 |  000000A4 | CURRENCY SIGN
     A5 |  000000A5 | YEN SIGN
     A6 |  000000A6 | BROKEN BAR
     A7 |  000000A7 | SECTION SIGN
     A8 |  000000A8 | DIAERESIS
     A9 |  000000A9 | COPYRIGHT SIGN
     AA |  000000AA | FEMININE ORDINAL INDICATOR
     AB |  000000AB | LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
     AC |  000000AC | NOT SIGN
     AD |  000000AD | SOFT HYPHEN
     AE |  000000AE | REGISTERED SIGN
     AF |  000000AF | MACRON
     B0 |  000000B0 | DEGREE SIGN
     B1 |  000000B1 | PLUS-MINUS SIGN
     B2 |  000000B2 | SUPERSCRIPT TWO
     B3 |  000000B3 | SUPERSCRIPT THREE
     B4 |  000000B4 | ACUTE ACCENT
     B5 |  000000B5 | MICRO SIGN
     B6 |  000000B6 | PILCROW SIGN
     B7 |  000000B7 | MIDDLE DOT
     B8 |  000000B8 | CEDILLA
     B9 |  000000B9 | SUPERSCRIPT ONE
     BA |  000000BA | MASCULINE ORDINAL INDICATOR
     BB |  000000BB | RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
     BC |  000000BC | VULGAR FRACTION ONE QUARTER
     BD |  000000BD | VULGAR FRACTION ONE HALF
     BE |  000000BE | VULGAR FRACTION THREE QUARTERS
     BF |  000000BF | INVERTED QUESTION MARK
     C0 |  000000C0 | LATIN CAPITAL LETTER A WITH GRAVE
     C1 |  000000C1 | LATIN CAPITAL LETTER A WITH ACUTE
     C2 |  000000C2 | LATIN CAPITAL LETTER A WITH CIRCUMFLEX
     C3 |  000000C3 | LATIN CAPITAL LETTER A WITH TILDE
     C4 |  000000C4 | LATIN CAPITAL LETTER A WITH DIAERESIS
     C5 |  000000C5 | LATIN CAPITAL LETTER A WITH RING ABOVE
     C6 |  000000C6 | LATIN CAPITAL LETTER AE
     C7 |  000000C7 | LATIN CAPITAL LETTER C WITH CEDILLA
     C8 |  000000C8 | LATIN CAPITAL LETTER E WITH GRAVE
     C9 |  000000C9 | LATIN CAPITAL LETTER E WITH ACUTE
     CA |  000000CA | LATIN CAPITAL LETTER E WITH CIRCUMFLEX
     CB |  000000CB | LATIN CAPITAL LETTER E WITH DIAERESIS
     CC |  000000CC | LATIN CAPITAL LETTER I WITH GRAVE
     CD |  000000CD | LATIN CAPITAL LETTER I WITH ACUTE
     CE |  000000CE | LATIN CAPITAL LETTER I WITH CIRCUMFLEX
     CF |  000000CF | LATIN CAPITAL LETTER I WITH DIAERESIS
     D0 |  000000D0 | LATIN CAPITAL LETTER ETH (Icelandic)
     D1 |  000000D1 | LATIN CAPITAL LETTER N WITH TILDE
     D2 |  000000D2 | LATIN CAPITAL LETTER O WITH GRAVE
     D3 |  000000D3 | LATIN CAPITAL LETTER O WITH ACUTE
     D4 |  000000D4 | LATIN CAPITAL LETTER O WITH CIRCUMFLEX
     D5 |  000000D5 | LATIN CAPITAL LETTER O WITH TILDE
     D6 |  000000D6 | LATIN CAPITAL LETTER O WITH DIAERESIS
     D7 |  000000D7 | MULTIPLICATION SIGN
     D8 |  000000D8 | LATIN CAPITAL LETTER O WITH STROKE
     D9 |  000000D9 | LATIN CAPITAL LETTER U WITH GRAVE
     DA |  000000DA | LATIN CAPITAL LETTER U WITH ACUTE
     DB |  000000DB | LATIN CAPITAL LETTER U WITH CIRCUMFLEX
     DC |  000000DC | LATIN CAPITAL LETTER U WITH DIAERESIS
     DD |  000000DD | LATIN CAPITAL LETTER Y WITH ACUTE
     DE |  000000DE | LATIN CAPITAL LETTER THORN (Icelandic)
     DF |  000000DF | LATIN SMALL LETTER SHARP S (German)
     E0 |  000000E0 | LATIN SMALL LETTER A WITH GRAVE
     E1 |  000000E1 | LATIN SMALL LETTER A WITH ACUTE
     E2 |  000000E2 | LATIN SMALL LETTER A WITH CIRCUMFLEX
     E3 |  000000E3 | LATIN SMALL LETTER A WITH TILDE
     E4 |  000000E4 | LATIN SMALL LETTER A WITH DIAERESIS
     E5 |  000000E5 | LATIN SMALL LETTER A WITH RING ABOVE
     E6 |  000000E6 | LATIN SMALL LETTER AE
     E7 |  000000E7 | LATIN SMALL LETTER C WITH CEDILLA
     E8 |  000000E8 | LATIN SMALL LETTER E WITH GRAVE
     E9 |  000000E9 | LATIN SMALL LETTER E WITH ACUTE
     EA |  000000EA | LATIN SMALL LETTER E WITH CIRCUMFLEX
     EB |  000000EB | LATIN SMALL LETTER E WITH DIAERESIS
     EC |  000000EC | LATIN SMALL LETTER I WITH GRAVE
     ED |  000000ED | LATIN SMALL LETTER I WITH ACUTE
     EE |  000000EE | LATIN SMALL LETTER I WITH CIRCUMFLEX
     EF |  000000EF | LATIN SMALL LETTER I WITH DIAERESIS
     F0 |  000000F0 | LATIN SMALL LETTER ETH (Icelandic)
     F1 |  000000F1 | LATIN SMALL LETTER N WITH TILDE
     F2 |  000000F2 | LATIN SMALL LETTER O WITH GRAVE
     F3 |  000000F3 | LATIN SMALL LETTER O WITH ACUTE
     F4 |  000000F4 | LATIN SMALL LETTER O WITH CIRCUMFLEX
     F5 |  000000F5 | LATIN SMALL LETTER O WITH TILDE
     F6 |  000000F6 | LATIN SMALL LETTER O WITH DIAERESIS
     F7 |  000000F7 | DIVISION SIGN
     F8 |  000000F8 | LATIN SMALL LETTER O WITH STROKE
     F9 |  000000F9 | LATIN SMALL LETTER U WITH GRAVE
     FA |  000000FA | LATIN SMALL LETTER U WITH ACUTE
     FB |  000000FB | LATIN SMALL LETTER U WITH CIRCUMFLEX
     FC |  000000FC | LATIN SMALL LETTER U WITH DIAERESIS
     FD |  000000FD | LATIN SMALL LETTER Y WITH ACUTE
     FE |  000000FE | LATIN SMALL LETTER THORN (Icelandic)
     FF |  000000FF | LATIN SMALL LETTER Y WITH DIAERESIS
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/IBM1026.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for IBM1026.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::IBM1026;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x009c,
     0x0009,
     0x0086,
     0x007f,
     0x0097,
     0x008d,
     0x008e,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x009d,
     0x0085,
     0x0008,
     0x0087,
     0x0018,
     0x0019,
     0x0092,
     0x008f,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0080,
     0x0081,
     0x0082,
     0x0083,
     0x0084,
     0x000a,
     0x0017,
     0x001b,
     0x0088,
     0x0089,
     0x008a,
     0x008b,
     0x008c,
     0x0005,
     0x0006,
     0x0007,
     0x0090,
     0x0091,
     0x0016,
     0x0093,
     0x0094,
     0x0095,
     0x0096,
     0x0004,
     0x0098,
     0x0099,
     0x009a,
     0x009b,
     0x0014,
     0x0015,
     0x009e,
     0x001a,
     0x0020,
     0x00a0,
     0x00e2,
     0x00e4,
     0x00e0,
     0x00e1,
     0x00e3,
     0x00e5,
     0x007b,
     0x00f1,
     0x00c7,
     0x002e,
     0x003c,
     0x0028,
     0x002b,
     0x0021,
     0x0026,
     0x00e9,
     0x00ea,
     0x00eb,
     0x00e8,
     0x00ed,
     0x00ee,
     0x00ef,
     0x00ec,
     0x00df,
     0x011e,
     0x0130,
     0x002a,
     0x0029,
     0x003b,
     0x005e,
     0x002d,
     0x002f,
     0x00c2,
     0x00c4,
     0x00c0,
     0x00c1,
     0x00c3,
     0x00c5,
     0x005b,
     0x00d1,
     0x015f,
     0x002c,
     0x0025,
     0x005f,
     0x003e,
     0x003f,
     0x00f8,
     0x00c9,
     0x00ca,
     0x00cb,
     0x00c8,
     0x00cd,
     0x00ce,
     0x00cf,
     0x00cc,
     0x0131,
     0x003a,
     0x00d6,
     0x015e,
     0x0027,
     0x003d,
     0x00dc,
     0x00d8,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x00ab,
     0x00bb,
     0x007d,
     0x0060,
     0x00a6,
     0x00b1,
     0x00b0,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x00aa,
     0x00ba,
     0x00e6,
     0x02db,
     0x00c6,
     0x00a4,
     0x00b5,
     0x00f6,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x00a1,
     0x00bf,
     0x005d,
     0x0024,
     0x0040,
     0x00ae,
     0x00a2,
     0x00a3,
     0x00a5,
     0x00b7,
     0x00a9,
     0x00a7,
     0x00b6,
     0x00bc,
     0x00bd,
     0x00be,
     0x00ac,
     0x007c,
     0x2014,
     0x00a8,
     0x00b4,
     0x00d7,
     0x00e7,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x00ad,
     0x00f4,
     0x007e,
     0x00f2,
     0x00f3,
     0x00f5,
     0x011f,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x00b9,
     0x00fb,
     0x005c,
     0x00f9,
     0x00fa,
     0x00ff,
     0x00fc,
     0x00f7,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x00b2,
     0x00d4,
     0x0023,
     0x00d2,
     0x00d3,
     0x00d5,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x00b3,
     0x00db,
     0x0022,
     0x00d9,
     0x00da,
     0x009f,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\xc2\x9c",
     "\x09",
     "\xc2\x86",
     "\x7f",
     "\xc2\x97",
     "\xc2\x8d",
     "\xc2\x8e",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\xc2\x9d",
     "\xc2\x85",
     "\x08",
     "\xc2\x87",
     "\x18",
     "\x19",
     "\xc2\x92",
     "\xc2\x8f",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\xc2\x80",
     "\xc2\x81",
     "\xc2\x82",
     "\xc2\x83",
     "\xc2\x84",
     "\x0a",
     "\x17",
     "\x1b",
     "\xc2\x88",
     "\xc2\x89",
     "\xc2\x8a",
     "\xc2\x8b",
     "\xc2\x8c",
     "\x05",
     "\x06",
     "\x07",
     "\xc2\x90",
     "\xc2\x91",
     "\x16",
     "\xc2\x93",
     "\xc2\x94",
     "\xc2\x95",
     "\xc2\x96",
     "\x04",
     "\xc2\x98",
     "\xc2\x99",
     "\xc2\x9a",
     "\xc2\x9b",
     "\x14",
     "\x15",
     "\xc2\x9e",
     "\x1a",
     "\x20",
     "\xc2\xa0",
     "\xc3\xa2",
     "\xc3\xa4",
     "\xc3\xa0",
     "\xc3\xa1",
     "\xc3\xa3",
     "\xc3\xa5",
     "\x7b",
     "\xc3\xb1",
     "\xc3\x87",
     "\x2e",
     "\x3c",
     "\x28",
     "\x2b",
     "\x21",
     "\x26",
     "\xc3\xa9",
     "\xc3\xaa",
     "\xc3\xab",
     "\xc3\xa8",
     "\xc3\xad",
     "\xc3\xae",
     "\xc3\xaf",
     "\xc3\xac",
     "\xc3\x9f",
     "\xc4\x9e",
     "\xc4\xb0",
     "\x2a",
     "\x29",
     "\x3b",
     "\x5e",
     "\x2d",
     "\x2f",
     "\xc3\x82",
     "\xc3\x84",
     "\xc3\x80",
     "\xc3\x81",
     "\xc3\x83",
     "\xc3\x85",
     "\x5b",
     "\xc3\x91",
     "\xc5\x9f",
     "\x2c",
     "\x25",
     "\x5f",
     "\x3e",
     "\x3f",
     "\xc3\xb8",
     "\xc3\x89",
     "\xc3\x8a",
     "\xc3\x8b",
     "\xc3\x88",
     "\xc3\x8d",
     "\xc3\x8e",
     "\xc3\x8f",
     "\xc3\x8c",
     "\xc4\xb1",
     "\x3a",
     "\xc3\x96",
     "\xc5\x9e",
     "\x27",
     "\x3d",
     "\xc3\x9c",
     "\xc3\x98",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\xc2\xab",
     "\xc2\xbb",
     "\x7d",
     "\x60",
     "\xc2\xa6",
     "\xc2\xb1",
     "\xc2\xb0",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\xc2\xaa",
     "\xc2\xba",
     "\xc3\xa6",
     "\xcb\x9b",
     "\xc3\x86",
     "\xc2\xa4",
     "\xc2\xb5",
     "\xc3\xb6",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\xc2\xa1",
     "\xc2\xbf",
     "\x5d",
     "\x24",
     "\x40",
     "\xc2\xae",
     "\xc2\xa2",
     "\xc2\xa3",
     "\xc2\xa5",
     "\xc2\xb7",
     "\xc2\xa9",
     "\xc2\xa7",
     "\xc2\xb6",
     "\xc2\xbc",
     "\xc2\xbd",
     "\xc2\xbe",
     "\xc2\xac",
     "\x7c",
     "\xe2\x80\x94",
     "\xc2\xa8",
     "\xc2\xb4",
     "\xc3\x97",
     "\xc3\xa7",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\xc2\xad",
     "\xc3\xb4",
     "\x7e",
     "\xc3\xb2",
     "\xc3\xb3",
     "\xc3\xb5",
     "\xc4\x9f",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\xc2\xb9",
     "\xc3\xbb",
     "\x5c",
     "\xc3\xb9",
     "\xc3\xba",
     "\xc3\xbf",
     "\xc3\xbc",
     "\xc3\xb7",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\xc2\xb2",
     "\xc3\x94",
     "\x23",
     "\xc3\x92",
     "\xc3\x93",
     "\xc3\x95",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\xc2\xb3",
     "\xc3\x9b",
     "\x22",
     "\xc3\x99",
     "\xc3\x9a",
     "\xc2\x9f",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x37",
     0x00000005 => "\x2d",
     0x00000006 => "\x2e",
     0x00000007 => "\x2f",
     0x00000008 => "\x16",
     0x00000009 => "\x05",
     0x0000000a => "\x25",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x3c",
     0x00000015 => "\x3d",
     0x00000016 => "\x32",
     0x00000017 => "\x26",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x3f",
     0x0000001b => "\x27",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x40",
     0x00000021 => "\x4f",
     0x00000022 => "\xfc",
     0x00000023 => "\xec",
     0x00000024 => "\xad",
     0x00000025 => "\x6c",
     0x00000026 => "\x50",
     0x00000027 => "\x7d",
     0x00000028 => "\x4d",
     0x00000029 => "\x5d",
     0x0000002a => "\x5c",
     0x0000002b => "\x4e",
     0x0000002c => "\x6b",
     0x0000002d => "\x60",
     0x0000002e => "\x4b",
     0x0000002f => "\x61",
     0x00000030 => "\xf0",
     0x00000031 => "\xf1",
     0x00000032 => "\xf2",
     0x00000033 => "\xf3",
     0x00000034 => "\xf4",
     0x00000035 => "\xf5",
     0x00000036 => "\xf6",
     0x00000037 => "\xf7",
     0x00000038 => "\xf8",
     0x00000039 => "\xf9",
     0x0000003a => "\x7a",
     0x0000003b => "\x5e",
     0x0000003c => "\x4c",
     0x0000003d => "\x7e",
     0x0000003e => "\x6e",
     0x0000003f => "\x6f",
     0x00000040 => "\xae",
     0x00000041 => "\xc1",
     0x00000042 => "\xc2",
     0x00000043 => "\xc3",
     0x00000044 => "\xc4",
     0x00000045 => "\xc5",
     0x00000046 => "\xc6",
     0x00000047 => "\xc7",
     0x00000048 => "\xc8",
     0x00000049 => "\xc9",
     0x0000004a => "\xd1",
     0x0000004b => "\xd2",
     0x0000004c => "\xd3",
     0x0000004d => "\xd4",
     0x0000004e => "\xd5",
     0x0000004f => "\xd6",
     0x00000050 => "\xd7",
     0x00000051 => "\xd8",
     0x00000052 => "\xd9",
     0x00000053 => "\xe2",
     0x00000054 => "\xe3",
     0x00000055 => "\xe4",
     0x00000056 => "\xe5",
     0x00000057 => "\xe6",
     0x00000058 => "\xe7",
     0x00000059 => "\xe8",
     0x0000005a => "\xe9",
     0x0000005b => "\x68",
     0x0000005c => "\xdc",
     0x0000005d => "\xac",
     0x0000005e => "\x5f",
     0x0000005f => "\x6d",
     0x00000060 => "\x8d",
     0x00000061 => "\x81",
     0x00000062 => "\x82",
     0x00000063 => "\x83",
     0x00000064 => "\x84",
     0x00000065 => "\x85",
     0x00000066 => "\x86",
     0x00000067 => "\x87",
     0x00000068 => "\x88",
     0x00000069 => "\x89",
     0x0000006a => "\x91",
     0x0000006b => "\x92",
     0x0000006c => "\x93",
     0x0000006d => "\x94",
     0x0000006e => "\x95",
     0x0000006f => "\x96",
     0x00000070 => "\x97",
     0x00000071 => "\x98",
     0x00000072 => "\x99",
     0x00000073 => "\xa2",
     0x00000074 => "\xa3",
     0x00000075 => "\xa4",
     0x00000076 => "\xa5",
     0x00000077 => "\xa6",
     0x00000078 => "\xa7",
     0x00000079 => "\xa8",
     0x0000007a => "\xa9",
     0x0000007b => "\x48",
     0x0000007c => "\xbb",
     0x0000007d => "\x8c",
     0x0000007e => "\xcc",
     0x0000007f => "\x07",
     0x00000080 => "\x20",
     0x00000081 => "\x21",
     0x00000082 => "\x22",
     0x00000083 => "\x23",
     0x00000084 => "\x24",
     0x00000085 => "\x15",
     0x00000086 => "\x06",
     0x00000087 => "\x17",
     0x00000088 => "\x28",
     0x00000089 => "\x29",
     0x0000008a => "\x2a",
     0x0000008b => "\x2b",
     0x0000008c => "\x2c",
     0x0000008d => "\x09",
     0x0000008e => "\x0a",
     0x0000008f => "\x1b",
     0x00000090 => "\x30",
     0x00000091 => "\x31",
     0x00000092 => "\x1a",
     0x00000093 => "\x33",
     0x00000094 => "\x34",
     0x00000095 => "\x35",
     0x00000096 => "\x36",
     0x00000097 => "\x08",
     0x00000098 => "\x38",
     0x00000099 => "\x39",
     0x0000009a => "\x3a",
     0x0000009b => "\x3b",
     0x0000009c => "\x04",
     0x0000009d => "\x14",
     0x0000009e => "\x3e",
     0x0000009f => "\xff",
     0x000000a0 => "\x41",
     0x000000a1 => "\xaa",
     0x000000a2 => "\xb0",
     0x000000a3 => "\xb1",
     0x000000a4 => "\x9f",
     0x000000a5 => "\xb2",
     0x000000a6 => "\x8e",
     0x000000a7 => "\xb5",
     0x000000a8 => "\xbd",
     0x000000a9 => "\xb4",
     0x000000aa => "\x9a",
     0x000000ab => "\x8a",
     0x000000ac => "\xba",
     0x000000ad => "\xca",
     0x000000ae => "\xaf",
     0x000000b0 => "\x90",
     0x000000b1 => "\x8f",
     0x000000b2 => "\xea",
     0x000000b3 => "\xfa",
     0x000000b4 => "\xbe",
     0x000000b5 => "\xa0",
     0x000000b6 => "\xb6",
     0x000000b7 => "\xb3",
     0x000000b9 => "\xda",
     0x000000ba => "\x9b",
     0x000000bb => "\x8b",
     0x000000bc => "\xb7",
     0x000000bd => "\xb8",
     0x000000be => "\xb9",
     0x000000bf => "\xab",
     0x000000c0 => "\x64",
     0x000000c1 => "\x65",
     0x000000c2 => "\x62",
     0x000000c3 => "\x66",
     0x000000c4 => "\x63",
     0x000000c5 => "\x67",
     0x000000c6 => "\x9e",
     0x000000c7 => "\x4a",
     0x000000c8 => "\x74",
     0x000000c9 => "\x71",
     0x000000ca => "\x72",
     0x000000cb => "\x73",
     0x000000cc => "\x78",
     0x000000cd => "\x75",
     0x000000ce => "\x76",
     0x000000cf => "\x77",
     0x000000d1 => "\x69",
     0x000000d2 => "\xed",
     0x000000d3 => "\xee",
     0x000000d4 => "\xeb",
     0x000000d5 => "\xef",
     0x000000d6 => "\x7b",
     0x000000d7 => "\xbf",
     0x000000d8 => "\x80",
     0x000000d9 => "\xfd",
     0x000000da => "\xfe",
     0x000000db => "\xfb",
     0x000000dc => "\x7f",
     0x000000df => "\x59",
     0x000000e0 => "\x44",
     0x000000e1 => "\x45",
     0x000000e2 => "\x42",
     0x000000e3 => "\x46",
     0x000000e4 => "\x43",
     0x000000e5 => "\x47",
     0x000000e6 => "\x9c",
     0x000000e7 => "\xc0",
     0x000000e8 => "\x54",
     0x000000e9 => "\x51",
     0x000000ea => "\x52",
     0x000000eb => "\x53",
     0x000000ec => "\x58",
     0x000000ed => "\x55",
     0x000000ee => "\x56",
     0x000000ef => "\x57",
     0x000000f1 => "\x49",
     0x000000f2 => "\xcd",
     0x000000f3 => "\xce",
     0x000000f4 => "\xcb",
     0x000000f5 => "\xcf",
     0x000000f6 => "\xa1",
     0x000000f7 => "\xe1",
     0x000000f8 => "\x70",
     0x000000f9 => "\xdd",
     0x000000fa => "\xde",
     0x000000fb => "\xdb",
     0x000000fc => "\xe0",
     0x000000ff => "\xdf",
     0x0000011e => "\x5a",
     0x0000011f => "\xd0",
     0x00000130 => "\x5b",
     0x00000131 => "\x79",
     0x0000015e => "\x7c",
     0x0000015f => "\x6a",
     0x000002db => "\x9d",
     0x00002014 => "\xbc",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x6f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::IBM1026 - Conversion routines for IBM1026
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for IBM1026.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
   source: IBM NLS RM Vol2 SE09-8002-01, March 1990
  alias CP1026
  alias 1026
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  0000009C | STRING TERMINATOR (ST)
     05 |  00000009 | CHARACTER TABULATION (HT)
     06 |  00000086 | START OF SELECTED AREA (SSA)
     07 |  0000007F | DELETE (DEL)
     08 |  00000097 | END OF GUARDED AREA (EPA)
     09 |  0000008D | REVERSE LINE FEED (RI)
     0A |  0000008E | SINGLE-SHIFT TWO (SS2)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  0000009D | OPERATING SYSTEM COMMAND (OSC)
     15 |  00000085 | NEXT LINE (NEL)
     16 |  00000008 | BACKSPACE (BS)
     17 |  00000087 | END OF SELECTED AREA (ESA)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  00000092 | PRIVATE USE TWO (PU2)
     1B |  0000008F | SINGLE-SHIFT THREE (SS3)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000080 | PADDING CHARACTER (PAD)
     21 |  00000081 | HIGH OCTET PRESET (HOP)
     22 |  00000082 | BREAK PERMITTED HERE (BPH)
     23 |  00000083 | NO BREAK HERE (NBH)
     24 |  00000084 | INDEX (IND)
     25 |  0000000A | LINE FEED (LF)
     26 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     27 |  0000001B | ESCAPE (ESC)
     28 |  00000088 | CHARACTER TABULATION SET (HTS)
     29 |  00000089 | CHARACTER TABULATION WITH JUSTIFICATION (HTJ)
     2A |  0000008A | LINE TABULATION SET (VTS)
     2B |  0000008B | PARTIAL LINE FORWARD (PLD)
     2C |  0000008C | PARTIAL LINE BACKWARD (PLU)
     2D |  00000005 | ENQUIRY (ENQ)
     2E |  00000006 | ACKNOWLEDGE (ACK)
     2F |  00000007 | BELL (BEL)
     30 |  00000090 | DEVICE CONTROL STRING (DCS)
     31 |  00000091 | PRIVATE USE ONE (PU1)
     32 |  00000016 | SYNCHRONOUS IDLE (SYN)
     33 |  00000093 | SET TRANSMIT STATE (STS)
     34 |  00000094 | CANCEL CHARACTER (CCH)
     35 |  00000095 | MESSAGE WAITING (MW)
     36 |  00000096 | START OF GUARDED AREA (SPA)
     37 |  00000004 | END OF TRANSMISSION (EOT)
     38 |  00000098 | START OF STRING (SOS)
     39 |  00000099 | SINGLE GRAPHIC CHARACTER INTRODUCER (SGCI)
     3A |  0000009A | SINGLE CHARACTER INTRODUCER (SCI)
     3B |  0000009B | CONTROL SEQUENCE INTRODUCER (CSI)
     3C |  00000014 | DEVICE CONTROL FOUR (DC4)
     3D |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     3E |  0000009E | PRIVACY MESSAGE (PM)
     3F |  0000001A | SUBSTITUTE (SUB)
     40 |  00000020 | SPACE
     41 |  000000A0 | NO-BREAK SPACE
     42 |  000000E2 | LATIN SMALL LETTER A WITH CIRCUMFLEX
     43 |  000000E4 | LATIN SMALL LETTER A WITH DIAERESIS
     44 |  000000E0 | LATIN SMALL LETTER A WITH GRAVE
     45 |  000000E1 | LATIN SMALL LETTER A WITH ACUTE
     46 |  000000E3 | LATIN SMALL LETTER A WITH TILDE
     47 |  000000E5 | LATIN SMALL LETTER A WITH RING ABOVE
     48 |  0000007B | LEFT CURLY BRACKET
     49 |  000000F1 | LATIN SMALL LETTER N WITH TILDE
     4A |  000000C7 | LATIN CAPITAL LETTER C WITH CEDILLA
     4B |  0000002E | FULL STOP
     4C |  0000003C | LESS-THAN SIGN
     4D |  00000028 | LEFT PARENTHESIS
     4E |  0000002B | PLUS SIGN
     4F |  00000021 | EXCLAMATION MARK
     50 |  00000026 | AMPERSAND
     51 |  000000E9 | LATIN SMALL LETTER E WITH ACUTE
     52 |  000000EA | LATIN SMALL LETTER E WITH CIRCUMFLEX
     53 |  000000EB | LATIN SMALL LETTER E WITH DIAERESIS
     54 |  000000E8 | LATIN SMALL LETTER E WITH GRAVE
     55 |  000000ED | LATIN SMALL LETTER I WITH ACUTE
     56 |  000000EE | LATIN SMALL LETTER I WITH CIRCUMFLEX
     57 |  000000EF | LATIN SMALL LETTER I WITH DIAERESIS
     58 |  000000EC | LATIN SMALL LETTER I WITH GRAVE
     59 |  000000DF | LATIN SMALL LETTER SHARP S (German)
     5A |  0000011E | LATIN CAPITAL LETTER G WITH BREVE
     5B |  00000130 | LATIN CAPITAL LETTER I WITH DOT ABOVE
     5C |  0000002A | ASTERISK
     5D |  00000029 | RIGHT PARENTHESIS
     5E |  0000003B | SEMICOLON
     5F |  0000005E | CIRCUMFLEX ACCENT
     60 |  0000002D | HYPHEN-MINUS
     61 |  0000002F | SOLIDUS
     62 |  000000C2 | LATIN CAPITAL LETTER A WITH CIRCUMFLEX
     63 |  000000C4 | LATIN CAPITAL LETTER A WITH DIAERESIS
     64 |  000000C0 | LATIN CAPITAL LETTER A WITH GRAVE
     65 |  000000C1 | LATIN CAPITAL LETTER A WITH ACUTE
     66 |  000000C3 | LATIN CAPITAL LETTER A WITH TILDE
     67 |  000000C5 | LATIN CAPITAL LETTER A WITH RING ABOVE
     68 |  0000005B | LEFT SQUARE BRACKET
     69 |  000000D1 | LATIN CAPITAL LETTER N WITH TILDE
     6A |  0000015F | LATIN SMALL LETTER S WITH CEDILLA
     6B |  0000002C | COMMA
     6C |  00000025 | PERCENT SIGN
     6D |  0000005F | LOW LINE
     6E |  0000003E | GREATER-THAN SIGN
     6F |  0000003F | QUESTION MARK
     70 |  000000F8 | LATIN SMALL LETTER O WITH STROKE
     71 |  000000C9 | LATIN CAPITAL LETTER E WITH ACUTE
     72 |  000000CA | LATIN CAPITAL LETTER E WITH CIRCUMFLEX
     73 |  000000CB | LATIN CAPITAL LETTER E WITH DIAERESIS
     74 |  000000C8 | LATIN CAPITAL LETTER E WITH GRAVE
     75 |  000000CD | LATIN CAPITAL LETTER I WITH ACUTE
     76 |  000000CE | LATIN CAPITAL LETTER I WITH CIRCUMFLEX
     77 |  000000CF | LATIN CAPITAL LETTER I WITH DIAERESIS
     78 |  000000CC | LATIN CAPITAL LETTER I WITH GRAVE
     79 |  00000131 | LATIN SMALL LETTER DOTLESS I
     7A |  0000003A | COLON
     7B |  000000D6 | LATIN CAPITAL LETTER O WITH DIAERESIS
     7C |  0000015E | LATIN CAPITAL LETTER S WITH CEDILLA
     7D |  00000027 | APOSTROPHE
     7E |  0000003D | EQUALS SIGN
     7F |  000000DC | LATIN CAPITAL LETTER U WITH DIAERESIS
     80 |  000000D8 | LATIN CAPITAL LETTER O WITH STROKE
     81 |  00000061 | LATIN SMALL LETTER A
     82 |  00000062 | LATIN SMALL LETTER B
     83 |  00000063 | LATIN SMALL LETTER C
     84 |  00000064 | LATIN SMALL LETTER D
     85 |  00000065 | LATIN SMALL LETTER E
     86 |  00000066 | LATIN SMALL LETTER F
     87 |  00000067 | LATIN SMALL LETTER G
     88 |  00000068 | LATIN SMALL LETTER H
     89 |  00000069 | LATIN SMALL LETTER I
     8A |  000000AB | LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
     8B |  000000BB | RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
     8C |  0000007D | RIGHT CURLY BRACKET
     8D |  00000060 | GRAVE ACCENT
     8E |  000000A6 | BROKEN BAR
     8F |  000000B1 | PLUS-MINUS SIGN
     90 |  000000B0 | DEGREE SIGN
     91 |  0000006A | LATIN SMALL LETTER J
     92 |  0000006B | LATIN SMALL LETTER K
     93 |  0000006C | LATIN SMALL LETTER L
     94 |  0000006D | LATIN SMALL LETTER M
     95 |  0000006E | LATIN SMALL LETTER N
     96 |  0000006F | LATIN SMALL LETTER O
     97 |  00000070 | LATIN SMALL LETTER P
     98 |  00000071 | LATIN SMALL LETTER Q
     99 |  00000072 | LATIN SMALL LETTER R
     9A |  000000AA | FEMININE ORDINAL INDICATOR
     9B |  000000BA | MASCULINE ORDINAL INDICATOR
     9C |  000000E6 | LATIN SMALL LETTER AE
     9D |  000002DB | OGONEK
     9E |  000000C6 | LATIN CAPITAL LETTER AE
     9F |  000000A4 | CURRENCY SIGN
     A0 |  000000B5 | MICRO SIGN
     A1 |  000000F6 | LATIN SMALL LETTER O WITH DIAERESIS
     A2 |  00000073 | LATIN SMALL LETTER S
     A3 |  00000074 | LATIN SMALL LETTER T
     A4 |  00000075 | LATIN SMALL LETTER U
     A5 |  00000076 | LATIN SMALL LETTER V
     A6 |  00000077 | LATIN SMALL LETTER W
     A7 |  00000078 | LATIN SMALL LETTER X
     A8 |  00000079 | LATIN SMALL LETTER Y
     A9 |  0000007A | LATIN SMALL LETTER Z
     AA |  000000A1 | INVERTED EXCLAMATION MARK
     AB |  000000BF | INVERTED QUESTION MARK
     AC |  0000005D | RIGHT SQUARE BRACKET
     AD |  00000024 | DOLLAR SIGN
     AE |  00000040 | COMMERCIAL AT
     AF |  000000AE | REGISTERED SIGN
     B0 |  000000A2 | CENT SIGN
     B1 |  000000A3 | POUND SIGN
     B2 |  000000A5 | YEN SIGN
     B3 |  000000B7 | MIDDLE DOT
     B4 |  000000A9 | COPYRIGHT SIGN
     B5 |  000000A7 | SECTION SIGN
     B6 |  000000B6 | PILCROW SIGN
     B7 |  000000BC | VULGAR FRACTION ONE QUARTER
     B8 |  000000BD | VULGAR FRACTION ONE HALF
     B9 |  000000BE | VULGAR FRACTION THREE QUARTERS
     BA |  000000AC | NOT SIGN
     BB |  0000007C | VERTICAL LINE
     BC |  00002014 | EM DASH
     BD |  000000A8 | DIAERESIS
     BE |  000000B4 | ACUTE ACCENT
     BF |  000000D7 | MULTIPLICATION SIGN
     C0 |  000000E7 | LATIN SMALL LETTER C WITH CEDILLA
     C1 |  00000041 | LATIN CAPITAL LETTER A
     C2 |  00000042 | LATIN CAPITAL LETTER B
     C3 |  00000043 | LATIN CAPITAL LETTER C
     C4 |  00000044 | LATIN CAPITAL LETTER D
     C5 |  00000045 | LATIN CAPITAL LETTER E
     C6 |  00000046 | LATIN CAPITAL LETTER F
     C7 |  00000047 | LATIN CAPITAL LETTER G
     C8 |  00000048 | LATIN CAPITAL LETTER H
     C9 |  00000049 | LATIN CAPITAL LETTER I
     CA |  000000AD | SOFT HYPHEN
     CB |  000000F4 | LATIN SMALL LETTER O WITH CIRCUMFLEX
     CC |  0000007E | TILDE
     CD |  000000F2 | LATIN SMALL LETTER O WITH GRAVE
     CE |  000000F3 | LATIN SMALL LETTER O WITH ACUTE
     CF |  000000F5 | LATIN SMALL LETTER O WITH TILDE
     D0 |  0000011F | LATIN SMALL LETTER G WITH BREVE
     D1 |  0000004A | LATIN CAPITAL LETTER J
     D2 |  0000004B | LATIN CAPITAL LETTER K
     D3 |  0000004C | LATIN CAPITAL LETTER L
     D4 |  0000004D | LATIN CAPITAL LETTER M
     D5 |  0000004E | LATIN CAPITAL LETTER N
     D6 |  0000004F | LATIN CAPITAL LETTER O
     D7 |  00000050 | LATIN CAPITAL LETTER P
     D8 |  00000051 | LATIN CAPITAL LETTER Q
     D9 |  00000052 | LATIN CAPITAL LETTER R
     DA |  000000B9 | SUPERSCRIPT ONE
     DB |  000000FB | LATIN SMALL LETTER U WITH CIRCUMFLEX
     DC |  0000005C | REVERSE SOLIDUS
     DD |  000000F9 | LATIN SMALL LETTER U WITH GRAVE
     DE |  000000FA | LATIN SMALL LETTER U WITH ACUTE
     DF |  000000FF | LATIN SMALL LETTER Y WITH DIAERESIS
     E0 |  000000FC | LATIN SMALL LETTER U WITH DIAERESIS
     E1 |  000000F7 | DIVISION SIGN
     E2 |  00000053 | LATIN CAPITAL LETTER S
     E3 |  00000054 | LATIN CAPITAL LETTER T
     E4 |  00000055 | LATIN CAPITAL LETTER U
     E5 |  00000056 | LATIN CAPITAL LETTER V
     E6 |  00000057 | LATIN CAPITAL LETTER W
     E7 |  00000058 | LATIN CAPITAL LETTER X
     E8 |  00000059 | LATIN CAPITAL LETTER Y
     E9 |  0000005A | LATIN CAPITAL LETTER Z
     EA |  000000B2 | SUPERSCRIPT TWO
     EB |  000000D4 | LATIN CAPITAL LETTER O WITH CIRCUMFLEX
     EC |  00000023 | NUMBER SIGN
     ED |  000000D2 | LATIN CAPITAL LETTER O WITH GRAVE
     EE |  000000D3 | LATIN CAPITAL LETTER O WITH ACUTE
     EF |  000000D5 | LATIN CAPITAL LETTER O WITH TILDE
     F0 |  00000030 | DIGIT ZERO
     F1 |  00000031 | DIGIT ONE
     F2 |  00000032 | DIGIT TWO
     F3 |  00000033 | DIGIT THREE
     F4 |  00000034 | DIGIT FOUR
     F5 |  00000035 | DIGIT FIVE
     F6 |  00000036 | DIGIT SIX
     F7 |  00000037 | DIGIT SEVEN
     F8 |  00000038 | DIGIT EIGHT
     F9 |  00000039 | DIGIT NINE
     FA |  000000B3 | SUPERSCRIPT THREE
     FB |  000000DB | LATIN CAPITAL LETTER U WITH CIRCUMFLEX
     FC |  00000022 | QUOTATION MARK
     FD |  000000D9 | LATIN CAPITAL LETTER U WITH GRAVE
     FE |  000000DA | LATIN CAPITAL LETTER U WITH ACUTE
     FF |  0000009F | APPLICATION PROGRAM COMMAND (APC)
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/IBM1047.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for IBM1047.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::IBM1047;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x009c,
     0x0009,
     0x0086,
     0x007f,
     0x0097,
     0x008d,
     0x008e,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x009d,
     0x0085,
     0x0008,
     0x0087,
     0x0018,
     0x0019,
     0x0092,
     0x008f,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0080,
     0x0081,
     0x0082,
     0x0083,
     0x0084,
     0x000a,
     0x0017,
     0x001b,
     0x0088,
     0x0089,
     0x008a,
     0x008b,
     0x008c,
     0x0005,
     0x0006,
     0x0007,
     0x0090,
     0x0091,
     0x0016,
     0x0093,
     0x0094,
     0x0095,
     0x0096,
     0x0004,
     0x0098,
     0x0099,
     0x009a,
     0x009b,
     0x0014,
     0x0015,
     0x009e,
     0x001a,
     0x0020,
     0x00a0,
     0x00e2,
     0x00e4,
     0x00e0,
     0x00e1,
     0x00e3,
     0x00e5,
     0x00e7,
     0x00f1,
     0x00a2,
     0x002e,
     0x003c,
     0x0028,
     0x002b,
     0x007c,
     0x0026,
     0x00e9,
     0x00ea,
     0x00eb,
     0x00e8,
     0x00ed,
     0x00ee,
     0x00ef,
     0x00ec,
     0x00df,
     0x0021,
     0x0024,
     0x002a,
     0x0029,
     0x003b,
     0x005e,
     0x002d,
     0x002f,
     0x00c2,
     0x00c4,
     0x00c0,
     0x00c1,
     0x00c3,
     0x00c5,
     0x00c7,
     0x00d1,
     0x00a6,
     0x002c,
     0x0025,
     0x005f,
     0x003e,
     0x003f,
     0x00f8,
     0x00c9,
     0x00ca,
     0x00cb,
     0x00c8,
     0x00cd,
     0x00ce,
     0x00cf,
     0x00cc,
     0x0060,
     0x003a,
     0x0023,
     0x0040,
     0x0027,
     0x003d,
     0x0022,
     0x00d8,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x00ab,
     0x00bb,
     0x00f0,
     0x00fd,
     0x00fe,
     0x00b1,
     0x00b0,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x00aa,
     0x00ba,
     0x00e6,
     0x00b8,
     0x00c6,
     0x00a4,
     0x00b5,
     0x007e,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x00a1,
     0x00bf,
     0x00d0,
     0x005b,
     0x00de,
     0x00ae,
     0x00ac,
     0x00a3,
     0x00a5,
     0x00b7,
     0x00a9,
     0x00a7,
     0x00b6,
     0x00bc,
     0x00bd,
     0x00be,
     0x00dd,
     0x00a8,
     0x00af,
     0x005d,
     0x00b4,
     0x00d7,
     0x007b,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x00ad,
     0x00f4,
     0x00f6,
     0x00f2,
     0x00f3,
     0x00f5,
     0x007d,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x00b9,
     0x00fb,
     0x00fc,
     0x00f9,
     0x00fa,
     0x00ff,
     0x005c,
     0x00f7,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x00b2,
     0x00d4,
     0x00d6,
     0x00d2,
     0x00d3,
     0x00d5,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x00b3,
     0x00db,
     0x00dc,
     0x00d9,
     0x00da,
     0x009f,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\xc2\x9c",
     "\x09",
     "\xc2\x86",
     "\x7f",
     "\xc2\x97",
     "\xc2\x8d",
     "\xc2\x8e",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\xc2\x9d",
     "\xc2\x85",
     "\x08",
     "\xc2\x87",
     "\x18",
     "\x19",
     "\xc2\x92",
     "\xc2\x8f",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\xc2\x80",
     "\xc2\x81",
     "\xc2\x82",
     "\xc2\x83",
     "\xc2\x84",
     "\x0a",
     "\x17",
     "\x1b",
     "\xc2\x88",
     "\xc2\x89",
     "\xc2\x8a",
     "\xc2\x8b",
     "\xc2\x8c",
     "\x05",
     "\x06",
     "\x07",
     "\xc2\x90",
     "\xc2\x91",
     "\x16",
     "\xc2\x93",
     "\xc2\x94",
     "\xc2\x95",
     "\xc2\x96",
     "\x04",
     "\xc2\x98",
     "\xc2\x99",
     "\xc2\x9a",
     "\xc2\x9b",
     "\x14",
     "\x15",
     "\xc2\x9e",
     "\x1a",
     "\x20",
     "\xc2\xa0",
     "\xc3\xa2",
     "\xc3\xa4",
     "\xc3\xa0",
     "\xc3\xa1",
     "\xc3\xa3",
     "\xc3\xa5",
     "\xc3\xa7",
     "\xc3\xb1",
     "\xc2\xa2",
     "\x2e",
     "\x3c",
     "\x28",
     "\x2b",
     "\x7c",
     "\x26",
     "\xc3\xa9",
     "\xc3\xaa",
     "\xc3\xab",
     "\xc3\xa8",
     "\xc3\xad",
     "\xc3\xae",
     "\xc3\xaf",
     "\xc3\xac",
     "\xc3\x9f",
     "\x21",
     "\x24",
     "\x2a",
     "\x29",
     "\x3b",
     "\x5e",
     "\x2d",
     "\x2f",
     "\xc3\x82",
     "\xc3\x84",
     "\xc3\x80",
     "\xc3\x81",
     "\xc3\x83",
     "\xc3\x85",
     "\xc3\x87",
     "\xc3\x91",
     "\xc2\xa6",
     "\x2c",
     "\x25",
     "\x5f",
     "\x3e",
     "\x3f",
     "\xc3\xb8",
     "\xc3\x89",
     "\xc3\x8a",
     "\xc3\x8b",
     "\xc3\x88",
     "\xc3\x8d",
     "\xc3\x8e",
     "\xc3\x8f",
     "\xc3\x8c",
     "\x60",
     "\x3a",
     "\x23",
     "\x40",
     "\x27",
     "\x3d",
     "\x22",
     "\xc3\x98",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\xc2\xab",
     "\xc2\xbb",
     "\xc3\xb0",
     "\xc3\xbd",
     "\xc3\xbe",
     "\xc2\xb1",
     "\xc2\xb0",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\xc2\xaa",
     "\xc2\xba",
     "\xc3\xa6",
     "\xc2\xb8",
     "\xc3\x86",
     "\xc2\xa4",
     "\xc2\xb5",
     "\x7e",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\xc2\xa1",
     "\xc2\xbf",
     "\xc3\x90",
     "\x5b",
     "\xc3\x9e",
     "\xc2\xae",
     "\xc2\xac",
     "\xc2\xa3",
     "\xc2\xa5",
     "\xc2\xb7",
     "\xc2\xa9",
     "\xc2\xa7",
     "\xc2\xb6",
     "\xc2\xbc",
     "\xc2\xbd",
     "\xc2\xbe",
     "\xc3\x9d",
     "\xc2\xa8",
     "\xc2\xaf",
     "\x5d",
     "\xc2\xb4",
     "\xc3\x97",
     "\x7b",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\xc2\xad",
     "\xc3\xb4",
     "\xc3\xb6",
     "\xc3\xb2",
     "\xc3\xb3",
     "\xc3\xb5",
     "\x7d",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\xc2\xb9",
     "\xc3\xbb",
     "\xc3\xbc",
     "\xc3\xb9",
     "\xc3\xba",
     "\xc3\xbf",
     "\x5c",
     "\xc3\xb7",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\xc2\xb2",
     "\xc3\x94",
     "\xc3\x96",
     "\xc3\x92",
     "\xc3\x93",
     "\xc3\x95",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\xc2\xb3",
     "\xc3\x9b",
     "\xc3\x9c",
     "\xc3\x99",
     "\xc3\x9a",
     "\xc2\x9f",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x37",
     0x00000005 => "\x2d",
     0x00000006 => "\x2e",
     0x00000007 => "\x2f",
     0x00000008 => "\x16",
     0x00000009 => "\x05",
     0x0000000a => "\x25",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x3c",
     0x00000015 => "\x3d",
     0x00000016 => "\x32",
     0x00000017 => "\x26",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x3f",
     0x0000001b => "\x27",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x40",
     0x00000021 => "\x5a",
     0x00000022 => "\x7f",
     0x00000023 => "\x7b",
     0x00000024 => "\x5b",
     0x00000025 => "\x6c",
     0x00000026 => "\x50",
     0x00000027 => "\x7d",
     0x00000028 => "\x4d",
     0x00000029 => "\x5d",
     0x0000002a => "\x5c",
     0x0000002b => "\x4e",
     0x0000002c => "\x6b",
     0x0000002d => "\x60",
     0x0000002e => "\x4b",
     0x0000002f => "\x61",
     0x00000030 => "\xf0",
     0x00000031 => "\xf1",
     0x00000032 => "\xf2",
     0x00000033 => "\xf3",
     0x00000034 => "\xf4",
     0x00000035 => "\xf5",
     0x00000036 => "\xf6",
     0x00000037 => "\xf7",
     0x00000038 => "\xf8",
     0x00000039 => "\xf9",
     0x0000003a => "\x7a",
     0x0000003b => "\x5e",
     0x0000003c => "\x4c",
     0x0000003d => "\x7e",
     0x0000003e => "\x6e",
     0x0000003f => "\x6f",
     0x00000040 => "\x7c",
     0x00000041 => "\xc1",
     0x00000042 => "\xc2",
     0x00000043 => "\xc3",
     0x00000044 => "\xc4",
     0x00000045 => "\xc5",
     0x00000046 => "\xc6",
     0x00000047 => "\xc7",
     0x00000048 => "\xc8",
     0x00000049 => "\xc9",
     0x0000004a => "\xd1",
     0x0000004b => "\xd2",
     0x0000004c => "\xd3",
     0x0000004d => "\xd4",
     0x0000004e => "\xd5",
     0x0000004f => "\xd6",
     0x00000050 => "\xd7",
     0x00000051 => "\xd8",
     0x00000052 => "\xd9",
     0x00000053 => "\xe2",
     0x00000054 => "\xe3",
     0x00000055 => "\xe4",
     0x00000056 => "\xe5",
     0x00000057 => "\xe6",
     0x00000058 => "\xe7",
     0x00000059 => "\xe8",
     0x0000005a => "\xe9",
     0x0000005b => "\xad",
     0x0000005c => "\xe0",
     0x0000005d => "\xbd",
     0x0000005e => "\x5f",
     0x0000005f => "\x6d",
     0x00000060 => "\x79",
     0x00000061 => "\x81",
     0x00000062 => "\x82",
     0x00000063 => "\x83",
     0x00000064 => "\x84",
     0x00000065 => "\x85",
     0x00000066 => "\x86",
     0x00000067 => "\x87",
     0x00000068 => "\x88",
     0x00000069 => "\x89",
     0x0000006a => "\x91",
     0x0000006b => "\x92",
     0x0000006c => "\x93",
     0x0000006d => "\x94",
     0x0000006e => "\x95",
     0x0000006f => "\x96",
     0x00000070 => "\x97",
     0x00000071 => "\x98",
     0x00000072 => "\x99",
     0x00000073 => "\xa2",
     0x00000074 => "\xa3",
     0x00000075 => "\xa4",
     0x00000076 => "\xa5",
     0x00000077 => "\xa6",
     0x00000078 => "\xa7",
     0x00000079 => "\xa8",
     0x0000007a => "\xa9",
     0x0000007b => "\xc0",
     0x0000007c => "\x4f",
     0x0000007d => "\xd0",
     0x0000007e => "\xa1",
     0x0000007f => "\x07",
     0x00000080 => "\x20",
     0x00000081 => "\x21",
     0x00000082 => "\x22",
     0x00000083 => "\x23",
     0x00000084 => "\x24",
     0x00000085 => "\x15",
     0x00000086 => "\x06",
     0x00000087 => "\x17",
     0x00000088 => "\x28",
     0x00000089 => "\x29",
     0x0000008a => "\x2a",
     0x0000008b => "\x2b",
     0x0000008c => "\x2c",
     0x0000008d => "\x09",
     0x0000008e => "\x0a",
     0x0000008f => "\x1b",
     0x00000090 => "\x30",
     0x00000091 => "\x31",
     0x00000092 => "\x1a",
     0x00000093 => "\x33",
     0x00000094 => "\x34",
     0x00000095 => "\x35",
     0x00000096 => "\x36",
     0x00000097 => "\x08",
     0x00000098 => "\x38",
     0x00000099 => "\x39",
     0x0000009a => "\x3a",
     0x0000009b => "\x3b",
     0x0000009c => "\x04",
     0x0000009d => "\x14",
     0x0000009e => "\x3e",
     0x0000009f => "\xff",
     0x000000a0 => "\x41",
     0x000000a1 => "\xaa",
     0x000000a2 => "\x4a",
     0x000000a3 => "\xb1",
     0x000000a4 => "\x9f",
     0x000000a5 => "\xb2",
     0x000000a6 => "\x6a",
     0x000000a7 => "\xb5",
     0x000000a8 => "\xbb",
     0x000000a9 => "\xb4",
     0x000000aa => "\x9a",
     0x000000ab => "\x8a",
     0x000000ac => "\xb0",
     0x000000ad => "\xca",
     0x000000ae => "\xaf",
     0x000000af => "\xbc",
     0x000000b0 => "\x90",
     0x000000b1 => "\x8f",
     0x000000b2 => "\xea",
     0x000000b3 => "\xfa",
     0x000000b4 => "\xbe",
     0x000000b5 => "\xa0",
     0x000000b6 => "\xb6",
     0x000000b7 => "\xb3",
     0x000000b8 => "\x9d",
     0x000000b9 => "\xda",
     0x000000ba => "\x9b",
     0x000000bb => "\x8b",
     0x000000bc => "\xb7",
     0x000000bd => "\xb8",
     0x000000be => "\xb9",
     0x000000bf => "\xab",
     0x000000c0 => "\x64",
     0x000000c1 => "\x65",
     0x000000c2 => "\x62",
     0x000000c3 => "\x66",
     0x000000c4 => "\x63",
     0x000000c5 => "\x67",
     0x000000c6 => "\x9e",
     0x000000c7 => "\x68",
     0x000000c8 => "\x74",
     0x000000c9 => "\x71",
     0x000000ca => "\x72",
     0x000000cb => "\x73",
     0x000000cc => "\x78",
     0x000000cd => "\x75",
     0x000000ce => "\x76",
     0x000000cf => "\x77",
     0x000000d0 => "\xac",
     0x000000d1 => "\x69",
     0x000000d2 => "\xed",
     0x000000d3 => "\xee",
     0x000000d4 => "\xeb",
     0x000000d5 => "\xef",
     0x000000d6 => "\xec",
     0x000000d7 => "\xbf",
     0x000000d8 => "\x80",
     0x000000d9 => "\xfd",
     0x000000da => "\xfe",
     0x000000db => "\xfb",
     0x000000dc => "\xfc",
     0x000000dd => "\xba",
     0x000000de => "\xae",
     0x000000df => "\x59",
     0x000000e0 => "\x44",
     0x000000e1 => "\x45",
     0x000000e2 => "\x42",
     0x000000e3 => "\x46",
     0x000000e4 => "\x43",
     0x000000e5 => "\x47",
     0x000000e6 => "\x9c",
     0x000000e7 => "\x48",
     0x000000e8 => "\x54",
     0x000000e9 => "\x51",
     0x000000ea => "\x52",
     0x000000eb => "\x53",
     0x000000ec => "\x58",
     0x000000ed => "\x55",
     0x000000ee => "\x56",
     0x000000ef => "\x57",
     0x000000f0 => "\x8c",
     0x000000f1 => "\x49",
     0x000000f2 => "\xcd",
     0x000000f3 => "\xce",
     0x000000f4 => "\xcb",
     0x000000f5 => "\xcf",
     0x000000f6 => "\xcc",
     0x000000f7 => "\xe1",
     0x000000f8 => "\x70",
     0x000000f9 => "\xdd",
     0x000000fa => "\xde",
     0x000000fb => "\xdb",
     0x000000fc => "\xdc",
     0x000000fd => "\x8d",
     0x000000fe => "\x8e",
     0x000000ff => "\xdf",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x6f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::IBM1047 - Conversion routines for IBM1047
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for IBM1047.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
   source: IBM Character Data Representation Architecture
   Registry SC09-1391-00 p 150.
  alias CP1047
  alias 1047
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  0000009C | STRING TERMINATOR (ST)
     05 |  00000009 | CHARACTER TABULATION (HT)
     06 |  00000086 | START OF SELECTED AREA (SSA)
     07 |  0000007F | DELETE (DEL)
     08 |  00000097 | END OF GUARDED AREA (EPA)
     09 |  0000008D | REVERSE LINE FEED (RI)
     0A |  0000008E | SINGLE-SHIFT TWO (SS2)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  0000009D | OPERATING SYSTEM COMMAND (OSC)
     15 |  00000085 | NEXT LINE (NEL)
     16 |  00000008 | BACKSPACE (BS)
     17 |  00000087 | END OF SELECTED AREA (ESA)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  00000092 | PRIVATE USE TWO (PU2)
     1B |  0000008F | SINGLE-SHIFT THREE (SS3)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000080 | PADDING CHARACTER (PAD)
     21 |  00000081 | HIGH OCTET PRESET (HOP)
     22 |  00000082 | BREAK PERMITTED HERE (BPH)
     23 |  00000083 | NO BREAK HERE (NBH)
     24 |  00000084 | INDEX (IND)
     25 |  0000000A | LINE FEED (LF)
     26 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     27 |  0000001B | ESCAPE (ESC)
     28 |  00000088 | CHARACTER TABULATION SET (HTS)
     29 |  00000089 | CHARACTER TABULATION WITH JUSTIFICATION (HTJ)
     2A |  0000008A | LINE TABULATION SET (VTS)
     2B |  0000008B | PARTIAL LINE FORWARD (PLD)
     2C |  0000008C | PARTIAL LINE BACKWARD (PLU)
     2D |  00000005 | ENQUIRY (ENQ)
     2E |  00000006 | ACKNOWLEDGE (ACK)
     2F |  00000007 | BELL (BEL)
     30 |  00000090 | DEVICE CONTROL STRING (DCS)
     31 |  00000091 | PRIVATE USE ONE (PU1)
     32 |  00000016 | SYNCHRONOUS IDLE (SYN)
     33 |  00000093 | SET TRANSMIT STATE (STS)
     34 |  00000094 | CANCEL CHARACTER (CCH)
     35 |  00000095 | MESSAGE WAITING (MW)
     36 |  00000096 | START OF GUARDED AREA (SPA)
     37 |  00000004 | END OF TRANSMISSION (EOT)
     38 |  00000098 | START OF STRING (SOS)
     39 |  00000099 | SINGLE GRAPHIC CHARACTER INTRODUCER (SGCI)
     3A |  0000009A | SINGLE CHARACTER INTRODUCER (SCI)
     3B |  0000009B | CONTROL SEQUENCE INTRODUCER (CSI)
     3C |  00000014 | DEVICE CONTROL FOUR (DC4)
     3D |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     3E |  0000009E | PRIVACY MESSAGE (PM)
     3F |  0000001A | SUBSTITUTE (SUB)
     40 |  00000020 | SPACE
     41 |  000000A0 | NO-BREAK SPACE
     42 |  000000E2 | LATIN SMALL LETTER A WITH CIRCUMFLEX
     43 |  000000E4 | LATIN SMALL LETTER A WITH DIAERESIS
     44 |  000000E0 | LATIN SMALL LETTER A WITH GRAVE
     45 |  000000E1 | LATIN SMALL LETTER A WITH ACUTE
     46 |  000000E3 | LATIN SMALL LETTER A WITH TILDE
     47 |  000000E5 | LATIN SMALL LETTER A WITH RING ABOVE
     48 |  000000E7 | LATIN SMALL LETTER C WITH CEDILLA
     49 |  000000F1 | LATIN SMALL LETTER N WITH TILDE
     4A |  000000A2 | CENT SIGN
     4B |  0000002E | FULL STOP
     4C |  0000003C | LESS-THAN SIGN
     4D |  00000028 | LEFT PARENTHESIS
     4E |  0000002B | PLUS SIGN
     4F |  0000007C | VERTICAL LINE
     50 |  00000026 | AMPERSAND
     51 |  000000E9 | LATIN SMALL LETTER E WITH ACUTE
     52 |  000000EA | LATIN SMALL LETTER E WITH CIRCUMFLEX
     53 |  000000EB | LATIN SMALL LETTER E WITH DIAERESIS
     54 |  000000E8 | LATIN SMALL LETTER E WITH GRAVE
     55 |  000000ED | LATIN SMALL LETTER I WITH ACUTE
     56 |  000000EE | LATIN SMALL LETTER I WITH CIRCUMFLEX
     57 |  000000EF | LATIN SMALL LETTER I WITH DIAERESIS
     58 |  000000EC | LATIN SMALL LETTER I WITH GRAVE
     59 |  000000DF | LATIN SMALL LETTER SHARP S (German)
     5A |  00000021 | EXCLAMATION MARK
     5B |  00000024 | DOLLAR SIGN
     5C |  0000002A | ASTERISK
     5D |  00000029 | RIGHT PARENTHESIS
     5E |  0000003B | SEMICOLON
     5F |  0000005E | CIRCUMFLEX ACCENT
     60 |  0000002D | HYPHEN-MINUS
     61 |  0000002F | SOLIDUS
     62 |  000000C2 | LATIN CAPITAL LETTER A WITH CIRCUMFLEX
     63 |  000000C4 | LATIN CAPITAL LETTER A WITH DIAERESIS
     64 |  000000C0 | LATIN CAPITAL LETTER A WITH GRAVE
     65 |  000000C1 | LATIN CAPITAL LETTER A WITH ACUTE
     66 |  000000C3 | LATIN CAPITAL LETTER A WITH TILDE
     67 |  000000C5 | LATIN CAPITAL LETTER A WITH RING ABOVE
     68 |  000000C7 | LATIN CAPITAL LETTER C WITH CEDILLA
     69 |  000000D1 | LATIN CAPITAL LETTER N WITH TILDE
     6A |  000000A6 | BROKEN BAR
     6B |  0000002C | COMMA
     6C |  00000025 | PERCENT SIGN
     6D |  0000005F | LOW LINE
     6E |  0000003E | GREATER-THAN SIGN
     6F |  0000003F | QUESTION MARK
     70 |  000000F8 | LATIN SMALL LETTER O WITH STROKE
     71 |  000000C9 | LATIN CAPITAL LETTER E WITH ACUTE
     72 |  000000CA | LATIN CAPITAL LETTER E WITH CIRCUMFLEX
     73 |  000000CB | LATIN CAPITAL LETTER E WITH DIAERESIS
     74 |  000000C8 | LATIN CAPITAL LETTER E WITH GRAVE
     75 |  000000CD | LATIN CAPITAL LETTER I WITH ACUTE
     76 |  000000CE | LATIN CAPITAL LETTER I WITH CIRCUMFLEX
     77 |  000000CF | LATIN CAPITAL LETTER I WITH DIAERESIS
     78 |  000000CC | LATIN CAPITAL LETTER I WITH GRAVE
     79 |  00000060 | GRAVE ACCENT
     7A |  0000003A | COLON
     7B |  00000023 | NUMBER SIGN
     7C |  00000040 | COMMERCIAL AT
     7D |  00000027 | APOSTROPHE
     7E |  0000003D | EQUALS SIGN
     7F |  00000022 | QUOTATION MARK
     80 |  000000D8 | LATIN CAPITAL LETTER O WITH STROKE
     81 |  00000061 | LATIN SMALL LETTER A
     82 |  00000062 | LATIN SMALL LETTER B
     83 |  00000063 | LATIN SMALL LETTER C
     84 |  00000064 | LATIN SMALL LETTER D
     85 |  00000065 | LATIN SMALL LETTER E
     86 |  00000066 | LATIN SMALL LETTER F
     87 |  00000067 | LATIN SMALL LETTER G
     88 |  00000068 | LATIN SMALL LETTER H
     89 |  00000069 | LATIN SMALL LETTER I
     8A |  000000AB | LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
     8B |  000000BB | RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
     8C |  000000F0 | LATIN SMALL LETTER ETH (Icelandic)
     8D |  000000FD | LATIN SMALL LETTER Y WITH ACUTE
     8E |  000000FE | LATIN SMALL LETTER THORN (Icelandic)
     8F |  000000B1 | PLUS-MINUS SIGN
     90 |  000000B0 | DEGREE SIGN
     91 |  0000006A | LATIN SMALL LETTER J
     92 |  0000006B | LATIN SMALL LETTER K
     93 |  0000006C | LATIN SMALL LETTER L
     94 |  0000006D | LATIN SMALL LETTER M
     95 |  0000006E | LATIN SMALL LETTER N
     96 |  0000006F | LATIN SMALL LETTER O
     97 |  00000070 | LATIN SMALL LETTER P
     98 |  00000071 | LATIN SMALL LETTER Q
     99 |  00000072 | LATIN SMALL LETTER R
     9A |  000000AA | FEMININE ORDINAL INDICATOR
     9B |  000000BA | MASCULINE ORDINAL INDICATOR
     9C |  000000E6 | LATIN SMALL LETTER AE
     9D |  000000B8 | CEDILLA
     9E |  000000C6 | LATIN CAPITAL LETTER AE
     9F |  000000A4 | CURRENCY SIGN
     A0 |  000000B5 | MICRO SIGN
     A1 |  0000007E | TILDE
     A2 |  00000073 | LATIN SMALL LETTER S
     A3 |  00000074 | LATIN SMALL LETTER T
     A4 |  00000075 | LATIN SMALL LETTER U
     A5 |  00000076 | LATIN SMALL LETTER V
     A6 |  00000077 | LATIN SMALL LETTER W
     A7 |  00000078 | LATIN SMALL LETTER X
     A8 |  00000079 | LATIN SMALL LETTER Y
     A9 |  0000007A | LATIN SMALL LETTER Z
     AA |  000000A1 | INVERTED EXCLAMATION MARK
     AB |  000000BF | INVERTED QUESTION MARK
     AC |  000000D0 | LATIN CAPITAL LETTER ETH (Icelandic)
     AD |  0000005B | LEFT SQUARE BRACKET
     AE |  000000DE | LATIN CAPITAL LETTER THORN (Icelandic)
     AF |  000000AE | REGISTERED SIGN
     B0 |  000000AC | NOT SIGN
     B1 |  000000A3 | POUND SIGN
     B2 |  000000A5 | YEN SIGN
     B3 |  000000B7 | MIDDLE DOT
     B4 |  000000A9 | COPYRIGHT SIGN
     B5 |  000000A7 | SECTION SIGN
     B6 |  000000B6 | PILCROW SIGN
     B7 |  000000BC | VULGAR FRACTION ONE QUARTER
     B8 |  000000BD | VULGAR FRACTION ONE HALF
     B9 |  000000BE | VULGAR FRACTION THREE QUARTERS
     BA |  000000DD | LATIN CAPITAL LETTER Y WITH ACUTE
     BB |  000000A8 | DIAERESIS
     BC |  000000AF | MACRON
     BD |  0000005D | RIGHT SQUARE BRACKET
     BE |  000000B4 | ACUTE ACCENT
     BF |  000000D7 | MULTIPLICATION SIGN
     C0 |  0000007B | LEFT CURLY BRACKET
     C1 |  00000041 | LATIN CAPITAL LETTER A
     C2 |  00000042 | LATIN CAPITAL LETTER B
     C3 |  00000043 | LATIN CAPITAL LETTER C
     C4 |  00000044 | LATIN CAPITAL LETTER D
     C5 |  00000045 | LATIN CAPITAL LETTER E
     C6 |  00000046 | LATIN CAPITAL LETTER F
     C7 |  00000047 | LATIN CAPITAL LETTER G
     C8 |  00000048 | LATIN CAPITAL LETTER H
     C9 |  00000049 | LATIN CAPITAL LETTER I
     CA |  000000AD | SOFT HYPHEN
     CB |  000000F4 | LATIN SMALL LETTER O WITH CIRCUMFLEX
     CC |  000000F6 | LATIN SMALL LETTER O WITH DIAERESIS
     CD |  000000F2 | LATIN SMALL LETTER O WITH GRAVE
     CE |  000000F3 | LATIN SMALL LETTER O WITH ACUTE
     CF |  000000F5 | LATIN SMALL LETTER O WITH TILDE
     D0 |  0000007D | RIGHT CURLY BRACKET
     D1 |  0000004A | LATIN CAPITAL LETTER J
     D2 |  0000004B | LATIN CAPITAL LETTER K
     D3 |  0000004C | LATIN CAPITAL LETTER L
     D4 |  0000004D | LATIN CAPITAL LETTER M
     D5 |  0000004E | LATIN CAPITAL LETTER N
     D6 |  0000004F | LATIN CAPITAL LETTER O
     D7 |  00000050 | LATIN CAPITAL LETTER P
     D8 |  00000051 | LATIN CAPITAL LETTER Q
     D9 |  00000052 | LATIN CAPITAL LETTER R
     DA |  000000B9 | SUPERSCRIPT ONE
     DB |  000000FB | LATIN SMALL LETTER U WITH CIRCUMFLEX
     DC |  000000FC | LATIN SMALL LETTER U WITH DIAERESIS
     DD |  000000F9 | LATIN SMALL LETTER U WITH GRAVE
     DE |  000000FA | LATIN SMALL LETTER U WITH ACUTE
     DF |  000000FF | LATIN SMALL LETTER Y WITH DIAERESIS
     E0 |  0000005C | REVERSE SOLIDUS
     E1 |  000000F7 | DIVISION SIGN
     E2 |  00000053 | LATIN CAPITAL LETTER S
     E3 |  00000054 | LATIN CAPITAL LETTER T
     E4 |  00000055 | LATIN CAPITAL LETTER U
     E5 |  00000056 | LATIN CAPITAL LETTER V
     E6 |  00000057 | LATIN CAPITAL LETTER W
     E7 |  00000058 | LATIN CAPITAL LETTER X
     E8 |  00000059 | LATIN CAPITAL LETTER Y
     E9 |  0000005A | LATIN CAPITAL LETTER Z
     EA |  000000B2 | SUPERSCRIPT TWO
     EB |  000000D4 | LATIN CAPITAL LETTER O WITH CIRCUMFLEX
     EC |  000000D6 | LATIN CAPITAL LETTER O WITH DIAERESIS
     ED |  000000D2 | LATIN CAPITAL LETTER O WITH GRAVE
     EE |  000000D3 | LATIN CAPITAL LETTER O WITH ACUTE
     EF |  000000D5 | LATIN CAPITAL LETTER O WITH TILDE
     F0 |  00000030 | DIGIT ZERO
     F1 |  00000031 | DIGIT ONE
     F2 |  00000032 | DIGIT TWO
     F3 |  00000033 | DIGIT THREE
     F4 |  00000034 | DIGIT FOUR
     F5 |  00000035 | DIGIT FIVE
     F6 |  00000036 | DIGIT SIX
     F7 |  00000037 | DIGIT SEVEN
     F8 |  00000038 | DIGIT EIGHT
     F9 |  00000039 | DIGIT NINE
     FA |  000000B3 | SUPERSCRIPT THREE
     FB |  000000DB | LATIN CAPITAL LETTER U WITH CIRCUMFLEX
     FC |  000000DC | LATIN CAPITAL LETTER U WITH DIAERESIS
     FD |  000000D9 | LATIN CAPITAL LETTER U WITH GRAVE
     FE |  000000DA | LATIN CAPITAL LETTER U WITH ACUTE
     FF |  0000009F | APPLICATION PROGRAM COMMAND (APC)
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/IBM256.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for IBM256.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::IBM256;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x009c,
     0x0009,
     0x0086,
     0x007f,
     0x0097,
     0x008d,
     0x008e,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x009d,
     0x0085,
     0x0008,
     0x0087,
     0x0018,
     0x0019,
     0x0092,
     0x008f,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0080,
     0x0081,
     0x0082,
     0x0083,
     0x0084,
     0x000a,
     0x0017,
     0x001b,
     0x0088,
     0x0089,
     0x008a,
     0x008b,
     0x008c,
     0x0005,
     0x0006,
     0x0007,
     0x0090,
     0x0091,
     0x0016,
     0x0093,
     0x0094,
     0x0095,
     0x0096,
     0x0004,
     0x0098,
     0x0099,
     0x009a,
     0x009b,
     0x0014,
     0x0015,
     0x009e,
     0x001a,
     0x0020,
     0x00a0,
     0x00e2,
     0x00e4,
     0x00e0,
     0x00e1,
     0x00e3,
     0x00e5,
     0x00e7,
     0x00f1,
     0x005b,
     0x002e,
     0x003c,
     0x0028,
     0x002b,
     0x0021,
     0x0026,
     0x00e9,
     0x00ea,
     0x00eb,
     0x00e8,
     0x00ed,
     0x00ee,
     0x00ef,
     0x00ec,
     0x00df,
     0x005d,
     0x0024,
     0x002a,
     0x0029,
     0x003b,
     0x005e,
     0x002d,
     0x002f,
     0x00c2,
     0x00c4,
     0x00c0,
     0x00c1,
     0x00c3,
     0x00c5,
     0x00c7,
     0x00d1,
     0x00a6,
     0x002c,
     0x0025,
     0x005f,
     0x003e,
     0x003f,
     0x00f8,
     0x00c9,
     0x00ca,
     0x00cb,
     0x00c8,
     0x00cd,
     0x00ce,
     0x00cf,
     0x00cc,
     0x0060,
     0x003a,
     0x0023,
     0x0040,
     0x0027,
     0x003d,
     0x0022,
     0x00d8,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x00ab,
     0x00bb,
     0x00f0,
     0x00fd,
     0x00fe,
     0x00b1,
     0x00b0,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x00aa,
     0x00ba,
     0x00e6,
     0x00b8,
     0x00c6,
     0x00a4,
     0x00b5,
     0x007e,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x00a1,
     0x00bf,
     0x00d0,
     0x00dd,
     0x00de,
     0x00ae,
     0x00a2,
     0x00a3,
     0x00a5,
     0x20a7,
     0x0192,
     0x00a7,
     0x00b6,
     0x00bc,
     0x00bd,
     0x00be,
     0x00ac,
     0x007c,
     0x203e,
     0x00a8,
     0x00b4,
     0x2017,
     0x007b,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x00ad,
     0x00f4,
     0x00f6,
     0x00f2,
     0x00f3,
     0x00f5,
     0x007d,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x00b9,
     0x00fb,
     0x00fc,
     0x00f9,
     0x00fa,
     0x00ff,
     0x005c,
     0x2003,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x00b2,
     0x00d4,
     0x00d6,
     0x00d2,
     0x00d3,
     0x00d5,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x00b3,
     0x00db,
     0x00dc,
     0x00d9,
     0x00da,
     0x009f,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\xc2\x9c",
     "\x09",
     "\xc2\x86",
     "\x7f",
     "\xc2\x97",
     "\xc2\x8d",
     "\xc2\x8e",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\xc2\x9d",
     "\xc2\x85",
     "\x08",
     "\xc2\x87",
     "\x18",
     "\x19",
     "\xc2\x92",
     "\xc2\x8f",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\xc2\x80",
     "\xc2\x81",
     "\xc2\x82",
     "\xc2\x83",
     "\xc2\x84",
     "\x0a",
     "\x17",
     "\x1b",
     "\xc2\x88",
     "\xc2\x89",
     "\xc2\x8a",
     "\xc2\x8b",
     "\xc2\x8c",
     "\x05",
     "\x06",
     "\x07",
     "\xc2\x90",
     "\xc2\x91",
     "\x16",
     "\xc2\x93",
     "\xc2\x94",
     "\xc2\x95",
     "\xc2\x96",
     "\x04",
     "\xc2\x98",
     "\xc2\x99",
     "\xc2\x9a",
     "\xc2\x9b",
     "\x14",
     "\x15",
     "\xc2\x9e",
     "\x1a",
     "\x20",
     "\xc2\xa0",
     "\xc3\xa2",
     "\xc3\xa4",
     "\xc3\xa0",
     "\xc3\xa1",
     "\xc3\xa3",
     "\xc3\xa5",
     "\xc3\xa7",
     "\xc3\xb1",
     "\x5b",
     "\x2e",
     "\x3c",
     "\x28",
     "\x2b",
     "\x21",
     "\x26",
     "\xc3\xa9",
     "\xc3\xaa",
     "\xc3\xab",
     "\xc3\xa8",
     "\xc3\xad",
     "\xc3\xae",
     "\xc3\xaf",
     "\xc3\xac",
     "\xc3\x9f",
     "\x5d",
     "\x24",
     "\x2a",
     "\x29",
     "\x3b",
     "\x5e",
     "\x2d",
     "\x2f",
     "\xc3\x82",
     "\xc3\x84",
     "\xc3\x80",
     "\xc3\x81",
     "\xc3\x83",
     "\xc3\x85",
     "\xc3\x87",
     "\xc3\x91",
     "\xc2\xa6",
     "\x2c",
     "\x25",
     "\x5f",
     "\x3e",
     "\x3f",
     "\xc3\xb8",
     "\xc3\x89",
     "\xc3\x8a",
     "\xc3\x8b",
     "\xc3\x88",
     "\xc3\x8d",
     "\xc3\x8e",
     "\xc3\x8f",
     "\xc3\x8c",
     "\x60",
     "\x3a",
     "\x23",
     "\x40",
     "\x27",
     "\x3d",
     "\x22",
     "\xc3\x98",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\xc2\xab",
     "\xc2\xbb",
     "\xc3\xb0",
     "\xc3\xbd",
     "\xc3\xbe",
     "\xc2\xb1",
     "\xc2\xb0",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\xc2\xaa",
     "\xc2\xba",
     "\xc3\xa6",
     "\xc2\xb8",
     "\xc3\x86",
     "\xc2\xa4",
     "\xc2\xb5",
     "\x7e",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\xc2\xa1",
     "\xc2\xbf",
     "\xc3\x90",
     "\xc3\x9d",
     "\xc3\x9e",
     "\xc2\xae",
     "\xc2\xa2",
     "\xc2\xa3",
     "\xc2\xa5",
     "\xe2\x82\xa7",
     "\xc6\x92",
     "\xc2\xa7",
     "\xc2\xb6",
     "\xc2\xbc",
     "\xc2\xbd",
     "\xc2\xbe",
     "\xc2\xac",
     "\x7c",
     "\xe2\x80\xbe",
     "\xc2\xa8",
     "\xc2\xb4",
     "\xe2\x80\x97",
     "\x7b",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\xc2\xad",
     "\xc3\xb4",
     "\xc3\xb6",
     "\xc3\xb2",
     "\xc3\xb3",
     "\xc3\xb5",
     "\x7d",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\xc2\xb9",
     "\xc3\xbb",
     "\xc3\xbc",
     "\xc3\xb9",
     "\xc3\xba",
     "\xc3\xbf",
     "\x5c",
     "\xe2\x80\x83",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\xc2\xb2",
     "\xc3\x94",
     "\xc3\x96",
     "\xc3\x92",
     "\xc3\x93",
     "\xc3\x95",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\xc2\xb3",
     "\xc3\x9b",
     "\xc3\x9c",
     "\xc3\x99",
     "\xc3\x9a",
     "\xc2\x9f",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x37",
     0x00000005 => "\x2d",
     0x00000006 => "\x2e",
     0x00000007 => "\x2f",
     0x00000008 => "\x16",
     0x00000009 => "\x05",
     0x0000000a => "\x25",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x3c",
     0x00000015 => "\x3d",
     0x00000016 => "\x32",
     0x00000017 => "\x26",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x3f",
     0x0000001b => "\x27",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x40",
     0x00000021 => "\x4f",
     0x00000022 => "\x7f",
     0x00000023 => "\x7b",
     0x00000024 => "\x5b",
     0x00000025 => "\x6c",
     0x00000026 => "\x50",
     0x00000027 => "\x7d",
     0x00000028 => "\x4d",
     0x00000029 => "\x5d",
     0x0000002a => "\x5c",
     0x0000002b => "\x4e",
     0x0000002c => "\x6b",
     0x0000002d => "\x60",
     0x0000002e => "\x4b",
     0x0000002f => "\x61",
     0x00000030 => "\xf0",
     0x00000031 => "\xf1",
     0x00000032 => "\xf2",
     0x00000033 => "\xf3",
     0x00000034 => "\xf4",
     0x00000035 => "\xf5",
     0x00000036 => "\xf6",
     0x00000037 => "\xf7",
     0x00000038 => "\xf8",
     0x00000039 => "\xf9",
     0x0000003a => "\x7a",
     0x0000003b => "\x5e",
     0x0000003c => "\x4c",
     0x0000003d => "\x7e",
     0x0000003e => "\x6e",
     0x0000003f => "\x6f",
     0x00000040 => "\x7c",
     0x00000041 => "\xc1",
     0x00000042 => "\xc2",
     0x00000043 => "\xc3",
     0x00000044 => "\xc4",
     0x00000045 => "\xc5",
     0x00000046 => "\xc6",
     0x00000047 => "\xc7",
     0x00000048 => "\xc8",
     0x00000049 => "\xc9",
     0x0000004a => "\xd1",
     0x0000004b => "\xd2",
     0x0000004c => "\xd3",
     0x0000004d => "\xd4",
     0x0000004e => "\xd5",
     0x0000004f => "\xd6",
     0x00000050 => "\xd7",
     0x00000051 => "\xd8",
     0x00000052 => "\xd9",
     0x00000053 => "\xe2",
     0x00000054 => "\xe3",
     0x00000055 => "\xe4",
     0x00000056 => "\xe5",
     0x00000057 => "\xe6",
     0x00000058 => "\xe7",
     0x00000059 => "\xe8",
     0x0000005a => "\xe9",
     0x0000005b => "\x4a",
     0x0000005c => "\xe0",
     0x0000005d => "\x5a",
     0x0000005e => "\x5f",
     0x0000005f => "\x6d",
     0x00000060 => "\x79",
     0x00000061 => "\x81",
     0x00000062 => "\x82",
     0x00000063 => "\x83",
     0x00000064 => "\x84",
     0x00000065 => "\x85",
     0x00000066 => "\x86",
     0x00000067 => "\x87",
     0x00000068 => "\x88",
     0x00000069 => "\x89",
     0x0000006a => "\x91",
     0x0000006b => "\x92",
     0x0000006c => "\x93",
     0x0000006d => "\x94",
     0x0000006e => "\x95",
     0x0000006f => "\x96",
     0x00000070 => "\x97",
     0x00000071 => "\x98",
     0x00000072 => "\x99",
     0x00000073 => "\xa2",
     0x00000074 => "\xa3",
     0x00000075 => "\xa4",
     0x00000076 => "\xa5",
     0x00000077 => "\xa6",
     0x00000078 => "\xa7",
     0x00000079 => "\xa8",
     0x0000007a => "\xa9",
     0x0000007b => "\xc0",
     0x0000007c => "\xbb",
     0x0000007d => "\xd0",
     0x0000007e => "\xa1",
     0x0000007f => "\x07",
     0x00000080 => "\x20",
     0x00000081 => "\x21",
     0x00000082 => "\x22",
     0x00000083 => "\x23",
     0x00000084 => "\x24",
     0x00000085 => "\x15",
     0x00000086 => "\x06",
     0x00000087 => "\x17",
     0x00000088 => "\x28",
     0x00000089 => "\x29",
     0x0000008a => "\x2a",
     0x0000008b => "\x2b",
     0x0000008c => "\x2c",
     0x0000008d => "\x09",
     0x0000008e => "\x0a",
     0x0000008f => "\x1b",
     0x00000090 => "\x30",
     0x00000091 => "\x31",
     0x00000092 => "\x1a",
     0x00000093 => "\x33",
     0x00000094 => "\x34",
     0x00000095 => "\x35",
     0x00000096 => "\x36",
     0x00000097 => "\x08",
     0x00000098 => "\x38",
     0x00000099 => "\x39",
     0x0000009a => "\x3a",
     0x0000009b => "\x3b",
     0x0000009c => "\x04",
     0x0000009d => "\x14",
     0x0000009e => "\x3e",
     0x0000009f => "\xff",
     0x000000a0 => "\x41",
     0x000000a1 => "\xaa",
     0x000000a2 => "\xb0",
     0x000000a3 => "\xb1",
     0x000000a4 => "\x9f",
     0x000000a5 => "\xb2",
     0x000000a6 => "\x6a",
     0x000000a7 => "\xb5",
     0x000000a8 => "\xbd",
     0x000000aa => "\x9a",
     0x000000ab => "\x8a",
     0x000000ac => "\xba",
     0x000000ad => "\xca",
     0x000000ae => "\xaf",
     0x000000b0 => "\x90",
     0x000000b1 => "\x8f",
     0x000000b2 => "\xea",
     0x000000b3 => "\xfa",
     0x000000b4 => "\xbe",
     0x000000b5 => "\xa0",
     0x000000b6 => "\xb6",
     0x000000b8 => "\x9d",
     0x000000b9 => "\xda",
     0x000000ba => "\x9b",
     0x000000bb => "\x8b",
     0x000000bc => "\xb7",
     0x000000bd => "\xb8",
     0x000000be => "\xb9",
     0x000000bf => "\xab",
     0x000000c0 => "\x64",
     0x000000c1 => "\x65",
     0x000000c2 => "\x62",
     0x000000c3 => "\x66",
     0x000000c4 => "\x63",
     0x000000c5 => "\x67",
     0x000000c6 => "\x9e",
     0x000000c7 => "\x68",
     0x000000c8 => "\x74",
     0x000000c9 => "\x71",
     0x000000ca => "\x72",
     0x000000cb => "\x73",
     0x000000cc => "\x78",
     0x000000cd => "\x75",
     0x000000ce => "\x76",
     0x000000cf => "\x77",
     0x000000d0 => "\xac",
     0x000000d1 => "\x69",
     0x000000d2 => "\xed",
     0x000000d3 => "\xee",
     0x000000d4 => "\xeb",
     0x000000d5 => "\xef",
     0x000000d6 => "\xec",
     0x000000d8 => "\x80",
     0x000000d9 => "\xfd",
     0x000000da => "\xfe",
     0x000000db => "\xfb",
     0x000000dc => "\xfc",
     0x000000dd => "\xad",
     0x000000de => "\xae",
     0x000000df => "\x59",
     0x000000e0 => "\x44",
     0x000000e1 => "\x45",
     0x000000e2 => "\x42",
     0x000000e3 => "\x46",
     0x000000e4 => "\x43",
     0x000000e5 => "\x47",
     0x000000e6 => "\x9c",
     0x000000e7 => "\x48",
     0x000000e8 => "\x54",
     0x000000e9 => "\x51",
     0x000000ea => "\x52",
     0x000000eb => "\x53",
     0x000000ec => "\x58",
     0x000000ed => "\x55",
     0x000000ee => "\x56",
     0x000000ef => "\x57",
     0x000000f0 => "\x8c",
     0x000000f1 => "\x49",
     0x000000f2 => "\xcd",
     0x000000f3 => "\xce",
     0x000000f4 => "\xcb",
     0x000000f5 => "\xcf",
     0x000000f6 => "\xcc",
     0x000000f8 => "\x70",
     0x000000f9 => "\xdd",
     0x000000fa => "\xde",
     0x000000fb => "\xdb",
     0x000000fc => "\xdc",
     0x000000fd => "\x8d",
     0x000000fe => "\x8e",
     0x000000ff => "\xdf",
     0x00000192 => "\xb4",
     0x00002003 => "\xe1",
     0x00002017 => "\xbf",
     0x0000203e => "\xbc",
     0x000020a7 => "\xb3",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x6f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::IBM256 - Conversion routines for IBM256
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for IBM256.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
   source: IBM Registry C-H 3-3220-050
  alias EBCDIC-INT1
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  0000009C | STRING TERMINATOR (ST)
     05 |  00000009 | CHARACTER TABULATION (HT)
     06 |  00000086 | START OF SELECTED AREA (SSA)
     07 |  0000007F | DELETE (DEL)
     08 |  00000097 | END OF GUARDED AREA (EPA)
     09 |  0000008D | REVERSE LINE FEED (RI)
     0A |  0000008E | SINGLE-SHIFT TWO (SS2)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  0000009D | OPERATING SYSTEM COMMAND (OSC)
     15 |  00000085 | NEXT LINE (NEL)
     16 |  00000008 | BACKSPACE (BS)
     17 |  00000087 | END OF SELECTED AREA (ESA)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  00000092 | PRIVATE USE TWO (PU2)
     1B |  0000008F | SINGLE-SHIFT THREE (SS3)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000080 | PADDING CHARACTER (PAD)
     21 |  00000081 | HIGH OCTET PRESET (HOP)
     22 |  00000082 | BREAK PERMITTED HERE (BPH)
     23 |  00000083 | NO BREAK HERE (NBH)
     24 |  00000084 | INDEX (IND)
     25 |  0000000A | LINE FEED (LF)
     26 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     27 |  0000001B | ESCAPE (ESC)
     28 |  00000088 | CHARACTER TABULATION SET (HTS)
     29 |  00000089 | CHARACTER TABULATION WITH JUSTIFICATION (HTJ)
     2A |  0000008A | LINE TABULATION SET (VTS)
     2B |  0000008B | PARTIAL LINE FORWARD (PLD)
     2C |  0000008C | PARTIAL LINE BACKWARD (PLU)
     2D |  00000005 | ENQUIRY (ENQ)
     2E |  00000006 | ACKNOWLEDGE (ACK)
     2F |  00000007 | BELL (BEL)
     30 |  00000090 | DEVICE CONTROL STRING (DCS)
     31 |  00000091 | PRIVATE USE ONE (PU1)
     32 |  00000016 | SYNCHRONOUS IDLE (SYN)
     33 |  00000093 | SET TRANSMIT STATE (STS)
     34 |  00000094 | CANCEL CHARACTER (CCH)
     35 |  00000095 | MESSAGE WAITING (MW)
     36 |  00000096 | START OF GUARDED AREA (SPA)
     37 |  00000004 | END OF TRANSMISSION (EOT)
     38 |  00000098 | START OF STRING (SOS)
     39 |  00000099 | SINGLE GRAPHIC CHARACTER INTRODUCER (SGCI)
     3A |  0000009A | SINGLE CHARACTER INTRODUCER (SCI)
     3B |  0000009B | CONTROL SEQUENCE INTRODUCER (CSI)
     3C |  00000014 | DEVICE CONTROL FOUR (DC4)
     3D |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     3E |  0000009E | PRIVACY MESSAGE (PM)
     3F |  0000001A | SUBSTITUTE (SUB)
     40 |  00000020 | SPACE
     41 |  000000A0 | NO-BREAK SPACE
     42 |  000000E2 | LATIN SMALL LETTER A WITH CIRCUMFLEX
     43 |  000000E4 | LATIN SMALL LETTER A WITH DIAERESIS
     44 |  000000E0 | LATIN SMALL LETTER A WITH GRAVE
     45 |  000000E1 | LATIN SMALL LETTER A WITH ACUTE
     46 |  000000E3 | LATIN SMALL LETTER A WITH TILDE
     47 |  000000E5 | LATIN SMALL LETTER A WITH RING ABOVE
     48 |  000000E7 | LATIN SMALL LETTER C WITH CEDILLA
     49 |  000000F1 | LATIN SMALL LETTER N WITH TILDE
     4A |  0000005B | LEFT SQUARE BRACKET
     4B |  0000002E | FULL STOP
     4C |  0000003C | LESS-THAN SIGN
     4D |  00000028 | LEFT PARENTHESIS
     4E |  0000002B | PLUS SIGN
     4F |  00000021 | EXCLAMATION MARK
     50 |  00000026 | AMPERSAND
     51 |  000000E9 | LATIN SMALL LETTER E WITH ACUTE
     52 |  000000EA | LATIN SMALL LETTER E WITH CIRCUMFLEX
     53 |  000000EB | LATIN SMALL LETTER E WITH DIAERESIS
     54 |  000000E8 | LATIN SMALL LETTER E WITH GRAVE
     55 |  000000ED | LATIN SMALL LETTER I WITH ACUTE
     56 |  000000EE | LATIN SMALL LETTER I WITH CIRCUMFLEX
     57 |  000000EF | LATIN SMALL LETTER I WITH DIAERESIS
     58 |  000000EC | LATIN SMALL LETTER I WITH GRAVE
     59 |  000000DF | LATIN SMALL LETTER SHARP S (German)
     5A |  0000005D | RIGHT SQUARE BRACKET
     5B |  00000024 | DOLLAR SIGN
     5C |  0000002A | ASTERISK
     5D |  00000029 | RIGHT PARENTHESIS
     5E |  0000003B | SEMICOLON
     5F |  0000005E | CIRCUMFLEX ACCENT
     60 |  0000002D | HYPHEN-MINUS
     61 |  0000002F | SOLIDUS
     62 |  000000C2 | LATIN CAPITAL LETTER A WITH CIRCUMFLEX
     63 |  000000C4 | LATIN CAPITAL LETTER A WITH DIAERESIS
     64 |  000000C0 | LATIN CAPITAL LETTER A WITH GRAVE
     65 |  000000C1 | LATIN CAPITAL LETTER A WITH ACUTE
     66 |  000000C3 | LATIN CAPITAL LETTER A WITH TILDE
     67 |  000000C5 | LATIN CAPITAL LETTER A WITH RING ABOVE
     68 |  000000C7 | LATIN CAPITAL LETTER C WITH CEDILLA
     69 |  000000D1 | LATIN CAPITAL LETTER N WITH TILDE
     6A |  000000A6 | BROKEN BAR
     6B |  0000002C | COMMA
     6C |  00000025 | PERCENT SIGN
     6D |  0000005F | LOW LINE
     6E |  0000003E | GREATER-THAN SIGN
     6F |  0000003F | QUESTION MARK
     70 |  000000F8 | LATIN SMALL LETTER O WITH STROKE
     71 |  000000C9 | LATIN CAPITAL LETTER E WITH ACUTE
     72 |  000000CA | LATIN CAPITAL LETTER E WITH CIRCUMFLEX
     73 |  000000CB | LATIN CAPITAL LETTER E WITH DIAERESIS
     74 |  000000C8 | LATIN CAPITAL LETTER E WITH GRAVE
     75 |  000000CD | LATIN CAPITAL LETTER I WITH ACUTE
     76 |  000000CE | LATIN CAPITAL LETTER I WITH CIRCUMFLEX
     77 |  000000CF | LATIN CAPITAL LETTER I WITH DIAERESIS
     78 |  000000CC | LATIN CAPITAL LETTER I WITH GRAVE
     79 |  00000060 | GRAVE ACCENT
     7A |  0000003A | COLON
     7B |  00000023 | NUMBER SIGN
     7C |  00000040 | COMMERCIAL AT
     7D |  00000027 | APOSTROPHE
     7E |  0000003D | EQUALS SIGN
     7F |  00000022 | QUOTATION MARK
     80 |  000000D8 | LATIN CAPITAL LETTER O WITH STROKE
     81 |  00000061 | LATIN SMALL LETTER A
     82 |  00000062 | LATIN SMALL LETTER B
     83 |  00000063 | LATIN SMALL LETTER C
     84 |  00000064 | LATIN SMALL LETTER D
     85 |  00000065 | LATIN SMALL LETTER E
     86 |  00000066 | LATIN SMALL LETTER F
     87 |  00000067 | LATIN SMALL LETTER G
     88 |  00000068 | LATIN SMALL LETTER H
     89 |  00000069 | LATIN SMALL LETTER I
     8A |  000000AB | LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
     8B |  000000BB | RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
     8C |  000000F0 | LATIN SMALL LETTER ETH (Icelandic)
     8D |  000000FD | LATIN SMALL LETTER Y WITH ACUTE
     8E |  000000FE | LATIN SMALL LETTER THORN (Icelandic)
     8F |  000000B1 | PLUS-MINUS SIGN
     90 |  000000B0 | DEGREE SIGN
     91 |  0000006A | LATIN SMALL LETTER J
     92 |  0000006B | LATIN SMALL LETTER K
     93 |  0000006C | LATIN SMALL LETTER L
     94 |  0000006D | LATIN SMALL LETTER M
     95 |  0000006E | LATIN SMALL LETTER N
     96 |  0000006F | LATIN SMALL LETTER O
     97 |  00000070 | LATIN SMALL LETTER P
     98 |  00000071 | LATIN SMALL LETTER Q
     99 |  00000072 | LATIN SMALL LETTER R
     9A |  000000AA | FEMININE ORDINAL INDICATOR
     9B |  000000BA | MASCULINE ORDINAL INDICATOR
     9C |  000000E6 | LATIN SMALL LETTER AE
     9D |  000000B8 | CEDILLA
     9E |  000000C6 | LATIN CAPITAL LETTER AE
     9F |  000000A4 | CURRENCY SIGN
     A0 |  000000B5 | MICRO SIGN
     A1 |  0000007E | TILDE
     A2 |  00000073 | LATIN SMALL LETTER S
     A3 |  00000074 | LATIN SMALL LETTER T
     A4 |  00000075 | LATIN SMALL LETTER U
     A5 |  00000076 | LATIN SMALL LETTER V
     A6 |  00000077 | LATIN SMALL LETTER W
     A7 |  00000078 | LATIN SMALL LETTER X
     A8 |  00000079 | LATIN SMALL LETTER Y
     A9 |  0000007A | LATIN SMALL LETTER Z
     AA |  000000A1 | INVERTED EXCLAMATION MARK
     AB |  000000BF | INVERTED QUESTION MARK
     AC |  000000D0 | LATIN CAPITAL LETTER ETH (Icelandic)
     AD |  000000DD | LATIN CAPITAL LETTER Y WITH ACUTE
     AE |  000000DE | LATIN CAPITAL LETTER THORN (Icelandic)
     AF |  000000AE | REGISTERED SIGN
     B0 |  000000A2 | CENT SIGN
     B1 |  000000A3 | POUND SIGN
     B2 |  000000A5 | YEN SIGN
     B3 |  000020A7 | PESETA SIGN
     B4 |  00000192 | LATIN SMALL LETTER F WITH HOOK
     B5 |  000000A7 | SECTION SIGN
     B6 |  000000B6 | PILCROW SIGN
     B7 |  000000BC | VULGAR FRACTION ONE QUARTER
     B8 |  000000BD | VULGAR FRACTION ONE HALF
     B9 |  000000BE | VULGAR FRACTION THREE QUARTERS
     BA |  000000AC | NOT SIGN
     BB |  0000007C | VERTICAL LINE
     BC |  0000203E | OVERLINE
     BD |  000000A8 | DIAERESIS
     BE |  000000B4 | ACUTE ACCENT
     BF |  00002017 | DOUBLE LOW LINE
     C0 |  0000007B | LEFT CURLY BRACKET
     C1 |  00000041 | LATIN CAPITAL LETTER A
     C2 |  00000042 | LATIN CAPITAL LETTER B
     C3 |  00000043 | LATIN CAPITAL LETTER C
     C4 |  00000044 | LATIN CAPITAL LETTER D
     C5 |  00000045 | LATIN CAPITAL LETTER E
     C6 |  00000046 | LATIN CAPITAL LETTER F
     C7 |  00000047 | LATIN CAPITAL LETTER G
     C8 |  00000048 | LATIN CAPITAL LETTER H
     C9 |  00000049 | LATIN CAPITAL LETTER I
     CA |  000000AD | SOFT HYPHEN
     CB |  000000F4 | LATIN SMALL LETTER O WITH CIRCUMFLEX
     CC |  000000F6 | LATIN SMALL LETTER O WITH DIAERESIS
     CD |  000000F2 | LATIN SMALL LETTER O WITH GRAVE
     CE |  000000F3 | LATIN SMALL LETTER O WITH ACUTE
     CF |  000000F5 | LATIN SMALL LETTER O WITH TILDE
     D0 |  0000007D | RIGHT CURLY BRACKET
     D1 |  0000004A | LATIN CAPITAL LETTER J
     D2 |  0000004B | LATIN CAPITAL LETTER K
     D3 |  0000004C | LATIN CAPITAL LETTER L
     D4 |  0000004D | LATIN CAPITAL LETTER M
     D5 |  0000004E | LATIN CAPITAL LETTER N
     D6 |  0000004F | LATIN CAPITAL LETTER O
     D7 |  00000050 | LATIN CAPITAL LETTER P
     D8 |  00000051 | LATIN CAPITAL LETTER Q
     D9 |  00000052 | LATIN CAPITAL LETTER R
     DA |  000000B9 | SUPERSCRIPT ONE
     DB |  000000FB | LATIN SMALL LETTER U WITH CIRCUMFLEX
     DC |  000000FC | LATIN SMALL LETTER U WITH DIAERESIS
     DD |  000000F9 | LATIN SMALL LETTER U WITH GRAVE
     DE |  000000FA | LATIN SMALL LETTER U WITH ACUTE
     DF |  000000FF | LATIN SMALL LETTER Y WITH DIAERESIS
     E0 |  0000005C | REVERSE SOLIDUS
     E1 |  00002003 | EM SPACE
     E2 |  00000053 | LATIN CAPITAL LETTER S
     E3 |  00000054 | LATIN CAPITAL LETTER T
     E4 |  00000055 | LATIN CAPITAL LETTER U
     E5 |  00000056 | LATIN CAPITAL LETTER V
     E6 |  00000057 | LATIN CAPITAL LETTER W
     E7 |  00000058 | LATIN CAPITAL LETTER X
     E8 |  00000059 | LATIN CAPITAL LETTER Y
     E9 |  0000005A | LATIN CAPITAL LETTER Z
     EA |  000000B2 | SUPERSCRIPT TWO
     EB |  000000D4 | LATIN CAPITAL LETTER O WITH CIRCUMFLEX
     EC |  000000D6 | LATIN CAPITAL LETTER O WITH DIAERESIS
     ED |  000000D2 | LATIN CAPITAL LETTER O WITH GRAVE
     EE |  000000D3 | LATIN CAPITAL LETTER O WITH ACUTE
     EF |  000000D5 | LATIN CAPITAL LETTER O WITH TILDE
     F0 |  00000030 | DIGIT ZERO
     F1 |  00000031 | DIGIT ONE
     F2 |  00000032 | DIGIT TWO
     F3 |  00000033 | DIGIT THREE
     F4 |  00000034 | DIGIT FOUR
     F5 |  00000035 | DIGIT FIVE
     F6 |  00000036 | DIGIT SIX
     F7 |  00000037 | DIGIT SEVEN
     F8 |  00000038 | DIGIT EIGHT
     F9 |  00000039 | DIGIT NINE
     FA |  000000B3 | SUPERSCRIPT THREE
     FB |  000000DB | LATIN CAPITAL LETTER U WITH CIRCUMFLEX
     FC |  000000DC | LATIN CAPITAL LETTER U WITH DIAERESIS
     FD |  000000D9 | LATIN CAPITAL LETTER U WITH GRAVE
     FE |  000000DA | LATIN CAPITAL LETTER U WITH ACUTE
     FF |  0000009F | APPLICATION PROGRAM COMMAND (APC)
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/IBM273.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for IBM273.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::IBM273;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x009c,
     0x0009,
     0x0086,
     0x007f,
     0x0097,
     0x008d,
     0x008e,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x009d,
     0x0085,
     0x0008,
     0x0087,
     0x0018,
     0x0019,
     0x0092,
     0x008f,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0080,
     0x0081,
     0x0082,
     0x0083,
     0x0084,
     0x000a,
     0x0017,
     0x001b,
     0x0088,
     0x0089,
     0x008a,
     0x008b,
     0x008c,
     0x0005,
     0x0006,
     0x0007,
     0x0090,
     0x0091,
     0x0016,
     0x0093,
     0x0094,
     0x0095,
     0x0096,
     0x0004,
     0x0098,
     0x0099,
     0x009a,
     0x009b,
     0x0014,
     0x0015,
     0x009e,
     0x001a,
     0x0020,
     0x00a0,
     0x00e2,
     0x007b,
     0x00e0,
     0x00e1,
     0x00e3,
     0x00e5,
     0x00e7,
     0x00f1,
     0x00c4,
     0x002e,
     0x003c,
     0x0028,
     0x002b,
     0x0021,
     0x0026,
     0x00e9,
     0x00ea,
     0x00eb,
     0x00e8,
     0x00ed,
     0x00ee,
     0x00ef,
     0x00ec,
     0x007e,
     0x00dc,
     0x0024,
     0x002a,
     0x0029,
     0x003b,
     0x005e,
     0x002d,
     0x002f,
     0x00c2,
     0x005b,
     0x00c0,
     0x00c1,
     0x00c3,
     0x00c5,
     0x00c7,
     0x00d1,
     0x00f6,
     0x002c,
     0x0025,
     0x005f,
     0x003e,
     0x003f,
     0x00f8,
     0x00c9,
     0x00ca,
     0x00cb,
     0x00c8,
     0x00cd,
     0x00ce,
     0x00cf,
     0x00cc,
     0x0060,
     0x003a,
     0x0023,
     0x00a7,
     0x0027,
     0x003d,
     0x0022,
     0x00d8,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x00ab,
     0x00bb,
     0x00f0,
     0x00fd,
     0x00fe,
     0x00b1,
     0x00b0,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x00aa,
     0x00ba,
     0x00e6,
     0x00b8,
     0x00c6,
     0x00a4,
     0x00b5,
     0x00df,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x00a1,
     0x00bf,
     0x00d0,
     0x00dd,
     0x00de,
     0x00ae,
     0x00a2,
     0x00a3,
     0x00a5,
     0x00b7,
     0x00a9,
     0x0040,
     0x00b6,
     0x00bc,
     0x00bd,
     0x00be,
     0x00ac,
     0x007c,
     0x203e,
     0x00a8,
     0x00b4,
     0x00d7,
     0x00e4,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x00ad,
     0x00f4,
     0x00a6,
     0x00f2,
     0x00f3,
     0x00f5,
     0x00fc,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x00b9,
     0x00fb,
     0x007d,
     0x00f9,
     0x00fa,
     0x00ff,
     0x00d6,
     0x00f7,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x00b2,
     0x00d4,
     0x005c,
     0x00d2,
     0x00d3,
     0x00d5,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x00b3,
     0x00db,
     0x005d,
     0x00d9,
     0x00da,
     0x009f,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\xc2\x9c",
     "\x09",
     "\xc2\x86",
     "\x7f",
     "\xc2\x97",
     "\xc2\x8d",
     "\xc2\x8e",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\xc2\x9d",
     "\xc2\x85",
     "\x08",
     "\xc2\x87",
     "\x18",
     "\x19",
     "\xc2\x92",
     "\xc2\x8f",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\xc2\x80",
     "\xc2\x81",
     "\xc2\x82",
     "\xc2\x83",
     "\xc2\x84",
     "\x0a",
     "\x17",
     "\x1b",
     "\xc2\x88",
     "\xc2\x89",
     "\xc2\x8a",
     "\xc2\x8b",
     "\xc2\x8c",
     "\x05",
     "\x06",
     "\x07",
     "\xc2\x90",
     "\xc2\x91",
     "\x16",
     "\xc2\x93",
     "\xc2\x94",
     "\xc2\x95",
     "\xc2\x96",
     "\x04",
     "\xc2\x98",
     "\xc2\x99",
     "\xc2\x9a",
     "\xc2\x9b",
     "\x14",
     "\x15",
     "\xc2\x9e",
     "\x1a",
     "\x20",
     "\xc2\xa0",
     "\xc3\xa2",
     "\x7b",
     "\xc3\xa0",
     "\xc3\xa1",
     "\xc3\xa3",
     "\xc3\xa5",
     "\xc3\xa7",
     "\xc3\xb1",
     "\xc3\x84",
     "\x2e",
     "\x3c",
     "\x28",
     "\x2b",
     "\x21",
     "\x26",
     "\xc3\xa9",
     "\xc3\xaa",
     "\xc3\xab",
     "\xc3\xa8",
     "\xc3\xad",
     "\xc3\xae",
     "\xc3\xaf",
     "\xc3\xac",
     "\x7e",
     "\xc3\x9c",
     "\x24",
     "\x2a",
     "\x29",
     "\x3b",
     "\x5e",
     "\x2d",
     "\x2f",
     "\xc3\x82",
     "\x5b",
     "\xc3\x80",
     "\xc3\x81",
     "\xc3\x83",
     "\xc3\x85",
     "\xc3\x87",
     "\xc3\x91",
     "\xc3\xb6",
     "\x2c",
     "\x25",
     "\x5f",
     "\x3e",
     "\x3f",
     "\xc3\xb8",
     "\xc3\x89",
     "\xc3\x8a",
     "\xc3\x8b",
     "\xc3\x88",
     "\xc3\x8d",
     "\xc3\x8e",
     "\xc3\x8f",
     "\xc3\x8c",
     "\x60",
     "\x3a",
     "\x23",
     "\xc2\xa7",
     "\x27",
     "\x3d",
     "\x22",
     "\xc3\x98",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\xc2\xab",
     "\xc2\xbb",
     "\xc3\xb0",
     "\xc3\xbd",
     "\xc3\xbe",
     "\xc2\xb1",
     "\xc2\xb0",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\xc2\xaa",
     "\xc2\xba",
     "\xc3\xa6",
     "\xc2\xb8",
     "\xc3\x86",
     "\xc2\xa4",
     "\xc2\xb5",
     "\xc3\x9f",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\xc2\xa1",
     "\xc2\xbf",
     "\xc3\x90",
     "\xc3\x9d",
     "\xc3\x9e",
     "\xc2\xae",
     "\xc2\xa2",
     "\xc2\xa3",
     "\xc2\xa5",
     "\xc2\xb7",
     "\xc2\xa9",
     "\x40",
     "\xc2\xb6",
     "\xc2\xbc",
     "\xc2\xbd",
     "\xc2\xbe",
     "\xc2\xac",
     "\x7c",
     "\xe2\x80\xbe",
     "\xc2\xa8",
     "\xc2\xb4",
     "\xc3\x97",
     "\xc3\xa4",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\xc2\xad",
     "\xc3\xb4",
     "\xc2\xa6",
     "\xc3\xb2",
     "\xc3\xb3",
     "\xc3\xb5",
     "\xc3\xbc",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\xc2\xb9",
     "\xc3\xbb",
     "\x7d",
     "\xc3\xb9",
     "\xc3\xba",
     "\xc3\xbf",
     "\xc3\x96",
     "\xc3\xb7",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\xc2\xb2",
     "\xc3\x94",
     "\x5c",
     "\xc3\x92",
     "\xc3\x93",
     "\xc3\x95",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\xc2\xb3",
     "\xc3\x9b",
     "\x5d",
     "\xc3\x99",
     "\xc3\x9a",
     "\xc2\x9f",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x37",
     0x00000005 => "\x2d",
     0x00000006 => "\x2e",
     0x00000007 => "\x2f",
     0x00000008 => "\x16",
     0x00000009 => "\x05",
     0x0000000a => "\x25",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x3c",
     0x00000015 => "\x3d",
     0x00000016 => "\x32",
     0x00000017 => "\x26",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x3f",
     0x0000001b => "\x27",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x40",
     0x00000021 => "\x4f",
     0x00000022 => "\x7f",
     0x00000023 => "\x7b",
     0x00000024 => "\x5b",
     0x00000025 => "\x6c",
     0x00000026 => "\x50",
     0x00000027 => "\x7d",
     0x00000028 => "\x4d",
     0x00000029 => "\x5d",
     0x0000002a => "\x5c",
     0x0000002b => "\x4e",
     0x0000002c => "\x6b",
     0x0000002d => "\x60",
     0x0000002e => "\x4b",
     0x0000002f => "\x61",
     0x00000030 => "\xf0",
     0x00000031 => "\xf1",
     0x00000032 => "\xf2",
     0x00000033 => "\xf3",
     0x00000034 => "\xf4",
     0x00000035 => "\xf5",
     0x00000036 => "\xf6",
     0x00000037 => "\xf7",
     0x00000038 => "\xf8",
     0x00000039 => "\xf9",
     0x0000003a => "\x7a",
     0x0000003b => "\x5e",
     0x0000003c => "\x4c",
     0x0000003d => "\x7e",
     0x0000003e => "\x6e",
     0x0000003f => "\x6f",
     0x00000040 => "\xb5",
     0x00000041 => "\xc1",
     0x00000042 => "\xc2",
     0x00000043 => "\xc3",
     0x00000044 => "\xc4",
     0x00000045 => "\xc5",
     0x00000046 => "\xc6",
     0x00000047 => "\xc7",
     0x00000048 => "\xc8",
     0x00000049 => "\xc9",
     0x0000004a => "\xd1",
     0x0000004b => "\xd2",
     0x0000004c => "\xd3",
     0x0000004d => "\xd4",
     0x0000004e => "\xd5",
     0x0000004f => "\xd6",
     0x00000050 => "\xd7",
     0x00000051 => "\xd8",
     0x00000052 => "\xd9",
     0x00000053 => "\xe2",
     0x00000054 => "\xe3",
     0x00000055 => "\xe4",
     0x00000056 => "\xe5",
     0x00000057 => "\xe6",
     0x00000058 => "\xe7",
     0x00000059 => "\xe8",
     0x0000005a => "\xe9",
     0x0000005b => "\x63",
     0x0000005c => "\xec",
     0x0000005d => "\xfc",
     0x0000005e => "\x5f",
     0x0000005f => "\x6d",
     0x00000060 => "\x79",
     0x00000061 => "\x81",
     0x00000062 => "\x82",
     0x00000063 => "\x83",
     0x00000064 => "\x84",
     0x00000065 => "\x85",
     0x00000066 => "\x86",
     0x00000067 => "\x87",
     0x00000068 => "\x88",
     0x00000069 => "\x89",
     0x0000006a => "\x91",
     0x0000006b => "\x92",
     0x0000006c => "\x93",
     0x0000006d => "\x94",
     0x0000006e => "\x95",
     0x0000006f => "\x96",
     0x00000070 => "\x97",
     0x00000071 => "\x98",
     0x00000072 => "\x99",
     0x00000073 => "\xa2",
     0x00000074 => "\xa3",
     0x00000075 => "\xa4",
     0x00000076 => "\xa5",
     0x00000077 => "\xa6",
     0x00000078 => "\xa7",
     0x00000079 => "\xa8",
     0x0000007a => "\xa9",
     0x0000007b => "\x43",
     0x0000007c => "\xbb",
     0x0000007d => "\xdc",
     0x0000007e => "\x59",
     0x0000007f => "\x07",
     0x00000080 => "\x20",
     0x00000081 => "\x21",
     0x00000082 => "\x22",
     0x00000083 => "\x23",
     0x00000084 => "\x24",
     0x00000085 => "\x15",
     0x00000086 => "\x06",
     0x00000087 => "\x17",
     0x00000088 => "\x28",
     0x00000089 => "\x29",
     0x0000008a => "\x2a",
     0x0000008b => "\x2b",
     0x0000008c => "\x2c",
     0x0000008d => "\x09",
     0x0000008e => "\x0a",
     0x0000008f => "\x1b",
     0x00000090 => "\x30",
     0x00000091 => "\x31",
     0x00000092 => "\x1a",
     0x00000093 => "\x33",
     0x00000094 => "\x34",
     0x00000095 => "\x35",
     0x00000096 => "\x36",
     0x00000097 => "\x08",
     0x00000098 => "\x38",
     0x00000099 => "\x39",
     0x0000009a => "\x3a",
     0x0000009b => "\x3b",
     0x0000009c => "\x04",
     0x0000009d => "\x14",
     0x0000009e => "\x3e",
     0x0000009f => "\xff",
     0x000000a0 => "\x41",
     0x000000a1 => "\xaa",
     0x000000a2 => "\xb0",
     0x000000a3 => "\xb1",
     0x000000a4 => "\x9f",
     0x000000a5 => "\xb2",
     0x000000a6 => "\xcc",
     0x000000a7 => "\x7c",
     0x000000a8 => "\xbd",
     0x000000a9 => "\xb4",
     0x000000aa => "\x9a",
     0x000000ab => "\x8a",
     0x000000ac => "\xba",
     0x000000ad => "\xca",
     0x000000ae => "\xaf",
     0x000000b0 => "\x90",
     0x000000b1 => "\x8f",
     0x000000b2 => "\xea",
     0x000000b3 => "\xfa",
     0x000000b4 => "\xbe",
     0x000000b5 => "\xa0",
     0x000000b6 => "\xb6",
     0x000000b7 => "\xb3",
     0x000000b8 => "\x9d",
     0x000000b9 => "\xda",
     0x000000ba => "\x9b",
     0x000000bb => "\x8b",
     0x000000bc => "\xb7",
     0x000000bd => "\xb8",
     0x000000be => "\xb9",
     0x000000bf => "\xab",
     0x000000c0 => "\x64",
     0x000000c1 => "\x65",
     0x000000c2 => "\x62",
     0x000000c3 => "\x66",
     0x000000c4 => "\x4a",
     0x000000c5 => "\x67",
     0x000000c6 => "\x9e",
     0x000000c7 => "\x68",
     0x000000c8 => "\x74",
     0x000000c9 => "\x71",
     0x000000ca => "\x72",
     0x000000cb => "\x73",
     0x000000cc => "\x78",
     0x000000cd => "\x75",
     0x000000ce => "\x76",
     0x000000cf => "\x77",
     0x000000d0 => "\xac",
     0x000000d1 => "\x69",
     0x000000d2 => "\xed",
     0x000000d3 => "\xee",
     0x000000d4 => "\xeb",
     0x000000d5 => "\xef",
     0x000000d6 => "\xe0",
     0x000000d7 => "\xbf",
     0x000000d8 => "\x80",
     0x000000d9 => "\xfd",
     0x000000da => "\xfe",
     0x000000db => "\xfb",
     0x000000dc => "\x5a",
     0x000000dd => "\xad",
     0x000000de => "\xae",
     0x000000df => "\xa1",
     0x000000e0 => "\x44",
     0x000000e1 => "\x45",
     0x000000e2 => "\x42",
     0x000000e3 => "\x46",
     0x000000e4 => "\xc0",
     0x000000e5 => "\x47",
     0x000000e6 => "\x9c",
     0x000000e7 => "\x48",
     0x000000e8 => "\x54",
     0x000000e9 => "\x51",
     0x000000ea => "\x52",
     0x000000eb => "\x53",
     0x000000ec => "\x58",
     0x000000ed => "\x55",
     0x000000ee => "\x56",
     0x000000ef => "\x57",
     0x000000f0 => "\x8c",
     0x000000f1 => "\x49",
     0x000000f2 => "\xcd",
     0x000000f3 => "\xce",
     0x000000f4 => "\xcb",
     0x000000f5 => "\xcf",
     0x000000f6 => "\x6a",
     0x000000f7 => "\xe1",
     0x000000f8 => "\x70",
     0x000000f9 => "\xdd",
     0x000000fa => "\xde",
     0x000000fb => "\xdb",
     0x000000fc => "\xd0",
     0x000000fd => "\x8d",
     0x000000fe => "\x8e",
     0x000000ff => "\xdf",
     0x0000203e => "\xbc",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x6f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::IBM273 - Conversion routines for IBM273
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for IBM273.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
   source: IBM NLS RM Vol2 SE09-8002-01, March 1990
  alias CP273
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  0000009C | STRING TERMINATOR (ST)
     05 |  00000009 | CHARACTER TABULATION (HT)
     06 |  00000086 | START OF SELECTED AREA (SSA)
     07 |  0000007F | DELETE (DEL)
     08 |  00000097 | END OF GUARDED AREA (EPA)
     09 |  0000008D | REVERSE LINE FEED (RI)
     0A |  0000008E | SINGLE-SHIFT TWO (SS2)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  0000009D | OPERATING SYSTEM COMMAND (OSC)
     15 |  00000085 | NEXT LINE (NEL)
     16 |  00000008 | BACKSPACE (BS)
     17 |  00000087 | END OF SELECTED AREA (ESA)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  00000092 | PRIVATE USE TWO (PU2)
     1B |  0000008F | SINGLE-SHIFT THREE (SS3)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000080 | PADDING CHARACTER (PAD)
     21 |  00000081 | HIGH OCTET PRESET (HOP)
     22 |  00000082 | BREAK PERMITTED HERE (BPH)
     23 |  00000083 | NO BREAK HERE (NBH)
     24 |  00000084 | INDEX (IND)
     25 |  0000000A | LINE FEED (LF)
     26 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     27 |  0000001B | ESCAPE (ESC)
     28 |  00000088 | CHARACTER TABULATION SET (HTS)
     29 |  00000089 | CHARACTER TABULATION WITH JUSTIFICATION (HTJ)
     2A |  0000008A | LINE TABULATION SET (VTS)
     2B |  0000008B | PARTIAL LINE FORWARD (PLD)
     2C |  0000008C | PARTIAL LINE BACKWARD (PLU)
     2D |  00000005 | ENQUIRY (ENQ)
     2E |  00000006 | ACKNOWLEDGE (ACK)
     2F |  00000007 | BELL (BEL)
     30 |  00000090 | DEVICE CONTROL STRING (DCS)
     31 |  00000091 | PRIVATE USE ONE (PU1)
     32 |  00000016 | SYNCHRONOUS IDLE (SYN)
     33 |  00000093 | SET TRANSMIT STATE (STS)
     34 |  00000094 | CANCEL CHARACTER (CCH)
     35 |  00000095 | MESSAGE WAITING (MW)
     36 |  00000096 | START OF GUARDED AREA (SPA)
     37 |  00000004 | END OF TRANSMISSION (EOT)
     38 |  00000098 | START OF STRING (SOS)
     39 |  00000099 | SINGLE GRAPHIC CHARACTER INTRODUCER (SGCI)
     3A |  0000009A | SINGLE CHARACTER INTRODUCER (SCI)
     3B |  0000009B | CONTROL SEQUENCE INTRODUCER (CSI)
     3C |  00000014 | DEVICE CONTROL FOUR (DC4)
     3D |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     3E |  0000009E | PRIVACY MESSAGE (PM)
     3F |  0000001A | SUBSTITUTE (SUB)
     40 |  00000020 | SPACE
     41 |  000000A0 | NO-BREAK SPACE
     42 |  000000E2 | LATIN SMALL LETTER A WITH CIRCUMFLEX
     43 |  0000007B | LEFT CURLY BRACKET
     44 |  000000E0 | LATIN SMALL LETTER A WITH GRAVE
     45 |  000000E1 | LATIN SMALL LETTER A WITH ACUTE
     46 |  000000E3 | LATIN SMALL LETTER A WITH TILDE
     47 |  000000E5 | LATIN SMALL LETTER A WITH RING ABOVE
     48 |  000000E7 | LATIN SMALL LETTER C WITH CEDILLA
     49 |  000000F1 | LATIN SMALL LETTER N WITH TILDE
     4A |  000000C4 | LATIN CAPITAL LETTER A WITH DIAERESIS
     4B |  0000002E | FULL STOP
     4C |  0000003C | LESS-THAN SIGN
     4D |  00000028 | LEFT PARENTHESIS
     4E |  0000002B | PLUS SIGN
     4F |  00000021 | EXCLAMATION MARK
     50 |  00000026 | AMPERSAND
     51 |  000000E9 | LATIN SMALL LETTER E WITH ACUTE
     52 |  000000EA | LATIN SMALL LETTER E WITH CIRCUMFLEX
     53 |  000000EB | LATIN SMALL LETTER E WITH DIAERESIS
     54 |  000000E8 | LATIN SMALL LETTER E WITH GRAVE
     55 |  000000ED | LATIN SMALL LETTER I WITH ACUTE
     56 |  000000EE | LATIN SMALL LETTER I WITH CIRCUMFLEX
     57 |  000000EF | LATIN SMALL LETTER I WITH DIAERESIS
     58 |  000000EC | LATIN SMALL LETTER I WITH GRAVE
     59 |  0000007E | TILDE
     5A |  000000DC | LATIN CAPITAL LETTER U WITH DIAERESIS
     5B |  00000024 | DOLLAR SIGN
     5C |  0000002A | ASTERISK
     5D |  00000029 | RIGHT PARENTHESIS
     5E |  0000003B | SEMICOLON
     5F |  0000005E | CIRCUMFLEX ACCENT
     60 |  0000002D | HYPHEN-MINUS
     61 |  0000002F | SOLIDUS
     62 |  000000C2 | LATIN CAPITAL LETTER A WITH CIRCUMFLEX
     63 |  0000005B | LEFT SQUARE BRACKET
     64 |  000000C0 | LATIN CAPITAL LETTER A WITH GRAVE
     65 |  000000C1 | LATIN CAPITAL LETTER A WITH ACUTE
     66 |  000000C3 | LATIN CAPITAL LETTER A WITH TILDE
     67 |  000000C5 | LATIN CAPITAL LETTER A WITH RING ABOVE
     68 |  000000C7 | LATIN CAPITAL LETTER C WITH CEDILLA
     69 |  000000D1 | LATIN CAPITAL LETTER N WITH TILDE
     6A |  000000F6 | LATIN SMALL LETTER O WITH DIAERESIS
     6B |  0000002C | COMMA
     6C |  00000025 | PERCENT SIGN
     6D |  0000005F | LOW LINE
     6E |  0000003E | GREATER-THAN SIGN
     6F |  0000003F | QUESTION MARK
     70 |  000000F8 | LATIN SMALL LETTER O WITH STROKE
     71 |  000000C9 | LATIN CAPITAL LETTER E WITH ACUTE
     72 |  000000CA | LATIN CAPITAL LETTER E WITH CIRCUMFLEX
     73 |  000000CB | LATIN CAPITAL LETTER E WITH DIAERESIS
     74 |  000000C8 | LATIN CAPITAL LETTER E WITH GRAVE
     75 |  000000CD | LATIN CAPITAL LETTER I WITH ACUTE
     76 |  000000CE | LATIN CAPITAL LETTER I WITH CIRCUMFLEX
     77 |  000000CF | LATIN CAPITAL LETTER I WITH DIAERESIS
     78 |  000000CC | LATIN CAPITAL LETTER I WITH GRAVE
     79 |  00000060 | GRAVE ACCENT
     7A |  0000003A | COLON
     7B |  00000023 | NUMBER SIGN
     7C |  000000A7 | SECTION SIGN
     7D |  00000027 | APOSTROPHE
     7E |  0000003D | EQUALS SIGN
     7F |  00000022 | QUOTATION MARK
     80 |  000000D8 | LATIN CAPITAL LETTER O WITH STROKE
     81 |  00000061 | LATIN SMALL LETTER A
     82 |  00000062 | LATIN SMALL LETTER B
     83 |  00000063 | LATIN SMALL LETTER C
     84 |  00000064 | LATIN SMALL LETTER D
     85 |  00000065 | LATIN SMALL LETTER E
     86 |  00000066 | LATIN SMALL LETTER F
     87 |  00000067 | LATIN SMALL LETTER G
     88 |  00000068 | LATIN SMALL LETTER H
     89 |  00000069 | LATIN SMALL LETTER I
     8A |  000000AB | LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
     8B |  000000BB | RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
     8C |  000000F0 | LATIN SMALL LETTER ETH (Icelandic)
     8D |  000000FD | LATIN SMALL LETTER Y WITH ACUTE
     8E |  000000FE | LATIN SMALL LETTER THORN (Icelandic)
     8F |  000000B1 | PLUS-MINUS SIGN
     90 |  000000B0 | DEGREE SIGN
     91 |  0000006A | LATIN SMALL LETTER J
     92 |  0000006B | LATIN SMALL LETTER K
     93 |  0000006C | LATIN SMALL LETTER L
     94 |  0000006D | LATIN SMALL LETTER M
     95 |  0000006E | LATIN SMALL LETTER N
     96 |  0000006F | LATIN SMALL LETTER O
     97 |  00000070 | LATIN SMALL LETTER P
     98 |  00000071 | LATIN SMALL LETTER Q
     99 |  00000072 | LATIN SMALL LETTER R
     9A |  000000AA | FEMININE ORDINAL INDICATOR
     9B |  000000BA | MASCULINE ORDINAL INDICATOR
     9C |  000000E6 | LATIN SMALL LETTER AE
     9D |  000000B8 | CEDILLA
     9E |  000000C6 | LATIN CAPITAL LETTER AE
     9F |  000000A4 | CURRENCY SIGN
     A0 |  000000B5 | MICRO SIGN
     A1 |  000000DF | LATIN SMALL LETTER SHARP S (German)
     A2 |  00000073 | LATIN SMALL LETTER S
     A3 |  00000074 | LATIN SMALL LETTER T
     A4 |  00000075 | LATIN SMALL LETTER U
     A5 |  00000076 | LATIN SMALL LETTER V
     A6 |  00000077 | LATIN SMALL LETTER W
     A7 |  00000078 | LATIN SMALL LETTER X
     A8 |  00000079 | LATIN SMALL LETTER Y
     A9 |  0000007A | LATIN SMALL LETTER Z
     AA |  000000A1 | INVERTED EXCLAMATION MARK
     AB |  000000BF | INVERTED QUESTION MARK
     AC |  000000D0 | LATIN CAPITAL LETTER ETH (Icelandic)
     AD |  000000DD | LATIN CAPITAL LETTER Y WITH ACUTE
     AE |  000000DE | LATIN CAPITAL LETTER THORN (Icelandic)
     AF |  000000AE | REGISTERED SIGN
     B0 |  000000A2 | CENT SIGN
     B1 |  000000A3 | POUND SIGN
     B2 |  000000A5 | YEN SIGN
     B3 |  000000B7 | MIDDLE DOT
     B4 |  000000A9 | COPYRIGHT SIGN
     B5 |  00000040 | COMMERCIAL AT
     B6 |  000000B6 | PILCROW SIGN
     B7 |  000000BC | VULGAR FRACTION ONE QUARTER
     B8 |  000000BD | VULGAR FRACTION ONE HALF
     B9 |  000000BE | VULGAR FRACTION THREE QUARTERS
     BA |  000000AC | NOT SIGN
     BB |  0000007C | VERTICAL LINE
     BC |  0000203E | OVERLINE
     BD |  000000A8 | DIAERESIS
     BE |  000000B4 | ACUTE ACCENT
     BF |  000000D7 | MULTIPLICATION SIGN
     C0 |  000000E4 | LATIN SMALL LETTER A WITH DIAERESIS
     C1 |  00000041 | LATIN CAPITAL LETTER A
     C2 |  00000042 | LATIN CAPITAL LETTER B
     C3 |  00000043 | LATIN CAPITAL LETTER C
     C4 |  00000044 | LATIN CAPITAL LETTER D
     C5 |  00000045 | LATIN CAPITAL LETTER E
     C6 |  00000046 | LATIN CAPITAL LETTER F
     C7 |  00000047 | LATIN CAPITAL LETTER G
     C8 |  00000048 | LATIN CAPITAL LETTER H
     C9 |  00000049 | LATIN CAPITAL LETTER I
     CA |  000000AD | SOFT HYPHEN
     CB |  000000F4 | LATIN SMALL LETTER O WITH CIRCUMFLEX
     CC |  000000A6 | BROKEN BAR
     CD |  000000F2 | LATIN SMALL LETTER O WITH GRAVE
     CE |  000000F3 | LATIN SMALL LETTER O WITH ACUTE
     CF |  000000F5 | LATIN SMALL LETTER O WITH TILDE
     D0 |  000000FC | LATIN SMALL LETTER U WITH DIAERESIS
     D1 |  0000004A | LATIN CAPITAL LETTER J
     D2 |  0000004B | LATIN CAPITAL LETTER K
     D3 |  0000004C | LATIN CAPITAL LETTER L
     D4 |  0000004D | LATIN CAPITAL LETTER M
     D5 |  0000004E | LATIN CAPITAL LETTER N
     D6 |  0000004F | LATIN CAPITAL LETTER O
     D7 |  00000050 | LATIN CAPITAL LETTER P
     D8 |  00000051 | LATIN CAPITAL LETTER Q
     D9 |  00000052 | LATIN CAPITAL LETTER R
     DA |  000000B9 | SUPERSCRIPT ONE
     DB |  000000FB | LATIN SMALL LETTER U WITH CIRCUMFLEX
     DC |  0000007D | RIGHT CURLY BRACKET
     DD |  000000F9 | LATIN SMALL LETTER U WITH GRAVE
     DE |  000000FA | LATIN SMALL LETTER U WITH ACUTE
     DF |  000000FF | LATIN SMALL LETTER Y WITH DIAERESIS
     E0 |  000000D6 | LATIN CAPITAL LETTER O WITH DIAERESIS
     E1 |  000000F7 | DIVISION SIGN
     E2 |  00000053 | LATIN CAPITAL LETTER S
     E3 |  00000054 | LATIN CAPITAL LETTER T
     E4 |  00000055 | LATIN CAPITAL LETTER U
     E5 |  00000056 | LATIN CAPITAL LETTER V
     E6 |  00000057 | LATIN CAPITAL LETTER W
     E7 |  00000058 | LATIN CAPITAL LETTER X
     E8 |  00000059 | LATIN CAPITAL LETTER Y
     E9 |  0000005A | LATIN CAPITAL LETTER Z
     EA |  000000B2 | SUPERSCRIPT TWO
     EB |  000000D4 | LATIN CAPITAL LETTER O WITH CIRCUMFLEX
     EC |  0000005C | REVERSE SOLIDUS
     ED |  000000D2 | LATIN CAPITAL LETTER O WITH GRAVE
     EE |  000000D3 | LATIN CAPITAL LETTER O WITH ACUTE
     EF |  000000D5 | LATIN CAPITAL LETTER O WITH TILDE
     F0 |  00000030 | DIGIT ZERO
     F1 |  00000031 | DIGIT ONE
     F2 |  00000032 | DIGIT TWO
     F3 |  00000033 | DIGIT THREE
     F4 |  00000034 | DIGIT FOUR
     F5 |  00000035 | DIGIT FIVE
     F6 |  00000036 | DIGIT SIX
     F7 |  00000037 | DIGIT SEVEN
     F8 |  00000038 | DIGIT EIGHT
     F9 |  00000039 | DIGIT NINE
     FA |  000000B3 | SUPERSCRIPT THREE
     FB |  000000DB | LATIN CAPITAL LETTER U WITH CIRCUMFLEX
     FC |  0000005D | RIGHT SQUARE BRACKET
     FD |  000000D9 | LATIN CAPITAL LETTER U WITH GRAVE
     FE |  000000DA | LATIN CAPITAL LETTER U WITH ACUTE
     FF |  0000009F | APPLICATION PROGRAM COMMAND (APC)
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/IBM274.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for IBM274.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::IBM274;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x009c,
     0x0009,
     0x0086,
     0x007f,
     0x0097,
     0x008d,
     0x008e,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x009d,
     0x0085,
     0x0008,
     0x0087,
     0x0018,
     0x0019,
     0x0092,
     0x008f,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0080,
     0x0081,
     0x0082,
     0x0083,
     0x0084,
     0x000a,
     0x0017,
     0x001b,
     0x0088,
     0x0089,
     0x008a,
     0x008b,
     0x008c,
     0x0005,
     0x0006,
     0x0007,
     0x0090,
     0x0091,
     0x0016,
     0x0093,
     0x0094,
     0x0095,
     0x0096,
     0x0004,
     0x0098,
     0x0099,
     0x009a,
     0x009b,
     0x0014,
     0x0015,
     0x009e,
     0x001a,
     0x0020,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x005b,
     0x002e,
     0x003c,
     0x0028,
     0x002b,
     0x0021,
     0x0026,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x005d,
     0x0024,
     0x002a,
     0x0029,
     0x003b,
     0x005e,
     0x002d,
     0x002f,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00f9,
     0x002c,
     0x0025,
     0x005f,
     0x003e,
     0x003f,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x0060,
     0x003a,
     0x0023,
     0x00e0,
     0x0027,
     0x003d,
     0x0022,
     0xfffd,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00a8,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00e9,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00e8,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00e7,
     0xfffd,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x009f,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\xc2\x9c",
     "\x09",
     "\xc2\x86",
     "\x7f",
     "\xc2\x97",
     "\xc2\x8d",
     "\xc2\x8e",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\xc2\x9d",
     "\xc2\x85",
     "\x08",
     "\xc2\x87",
     "\x18",
     "\x19",
     "\xc2\x92",
     "\xc2\x8f",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\xc2\x80",
     "\xc2\x81",
     "\xc2\x82",
     "\xc2\x83",
     "\xc2\x84",
     "\x0a",
     "\x17",
     "\x1b",
     "\xc2\x88",
     "\xc2\x89",
     "\xc2\x8a",
     "\xc2\x8b",
     "\xc2\x8c",
     "\x05",
     "\x06",
     "\x07",
     "\xc2\x90",
     "\xc2\x91",
     "\x16",
     "\xc2\x93",
     "\xc2\x94",
     "\xc2\x95",
     "\xc2\x96",
     "\x04",
     "\xc2\x98",
     "\xc2\x99",
     "\xc2\x9a",
     "\xc2\x9b",
     "\x14",
     "\x15",
     "\xc2\x9e",
     "\x1a",
     "\x20",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x5b",
     "\x2e",
     "\x3c",
     "\x28",
     "\x2b",
     "\x21",
     "\x26",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x5d",
     "\x24",
     "\x2a",
     "\x29",
     "\x3b",
     "\x5e",
     "\x2d",
     "\x2f",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc3\xb9",
     "\x2c",
     "\x25",
     "\x5f",
     "\x3e",
     "\x3f",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x60",
     "\x3a",
     "\x23",
     "\xc3\xa0",
     "\x27",
     "\x3d",
     "\x22",
     "\xef\xbf\xbd",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc2\xa8",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc3\xa9",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc3\xa8",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc3\xa7",
     "\xef\xbf\xbd",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc2\x9f",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x37",
     0x00000005 => "\x2d",
     0x00000006 => "\x2e",
     0x00000007 => "\x2f",
     0x00000008 => "\x16",
     0x00000009 => "\x05",
     0x0000000a => "\x25",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x3c",
     0x00000015 => "\x3d",
     0x00000016 => "\x32",
     0x00000017 => "\x26",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x3f",
     0x0000001b => "\x27",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x40",
     0x00000021 => "\x4f",
     0x00000022 => "\x7f",
     0x00000023 => "\x7b",
     0x00000024 => "\x5b",
     0x00000025 => "\x6c",
     0x00000026 => "\x50",
     0x00000027 => "\x7d",
     0x00000028 => "\x4d",
     0x00000029 => "\x5d",
     0x0000002a => "\x5c",
     0x0000002b => "\x4e",
     0x0000002c => "\x6b",
     0x0000002d => "\x60",
     0x0000002e => "\x4b",
     0x0000002f => "\x61",
     0x00000030 => "\xf0",
     0x00000031 => "\xf1",
     0x00000032 => "\xf2",
     0x00000033 => "\xf3",
     0x00000034 => "\xf4",
     0x00000035 => "\xf5",
     0x00000036 => "\xf6",
     0x00000037 => "\xf7",
     0x00000038 => "\xf8",
     0x00000039 => "\xf9",
     0x0000003a => "\x7a",
     0x0000003b => "\x5e",
     0x0000003c => "\x4c",
     0x0000003d => "\x7e",
     0x0000003e => "\x6e",
     0x0000003f => "\x6f",
     0x00000041 => "\xc1",
     0x00000042 => "\xc2",
     0x00000043 => "\xc3",
     0x00000044 => "\xc4",
     0x00000045 => "\xc5",
     0x00000046 => "\xc6",
     0x00000047 => "\xc7",
     0x00000048 => "\xc8",
     0x00000049 => "\xc9",
     0x0000004a => "\xd1",
     0x0000004b => "\xd2",
     0x0000004c => "\xd3",
     0x0000004d => "\xd4",
     0x0000004e => "\xd5",
     0x0000004f => "\xd6",
     0x00000050 => "\xd7",
     0x00000051 => "\xd8",
     0x00000052 => "\xd9",
     0x00000053 => "\xe2",
     0x00000054 => "\xe3",
     0x00000055 => "\xe4",
     0x00000056 => "\xe5",
     0x00000057 => "\xe6",
     0x00000058 => "\xe7",
     0x00000059 => "\xe8",
     0x0000005a => "\xe9",
     0x0000005b => "\x4a",
     0x0000005d => "\x5a",
     0x0000005e => "\x5f",
     0x0000005f => "\x6d",
     0x00000060 => "\x79",
     0x00000061 => "\x81",
     0x00000062 => "\x82",
     0x00000063 => "\x83",
     0x00000064 => "\x84",
     0x00000065 => "\x85",
     0x00000066 => "\x86",
     0x00000067 => "\x87",
     0x00000068 => "\x88",
     0x00000069 => "\x89",
     0x0000006a => "\x91",
     0x0000006b => "\x92",
     0x0000006c => "\x93",
     0x0000006d => "\x94",
     0x0000006e => "\x95",
     0x0000006f => "\x96",
     0x00000070 => "\x97",
     0x00000071 => "\x98",
     0x00000072 => "\x99",
     0x00000073 => "\xa2",
     0x00000074 => "\xa3",
     0x00000075 => "\xa4",
     0x00000076 => "\xa5",
     0x00000077 => "\xa6",
     0x00000078 => "\xa7",
     0x00000079 => "\xa8",
     0x0000007a => "\xa9",
     0x0000007f => "\x07",
     0x00000080 => "\x20",
     0x00000081 => "\x21",
     0x00000082 => "\x22",
     0x00000083 => "\x23",
     0x00000084 => "\x24",
     0x00000085 => "\x15",
     0x00000086 => "\x06",
     0x00000087 => "\x17",
     0x00000088 => "\x28",
     0x00000089 => "\x29",
     0x0000008a => "\x2a",
     0x0000008b => "\x2b",
     0x0000008c => "\x2c",
     0x0000008d => "\x09",
     0x0000008e => "\x0a",
     0x0000008f => "\x1b",
     0x00000090 => "\x30",
     0x00000091 => "\x31",
     0x00000092 => "\x1a",
     0x00000093 => "\x33",
     0x00000094 => "\x34",
     0x00000095 => "\x35",
     0x00000096 => "\x36",
     0x00000097 => "\x08",
     0x00000098 => "\x38",
     0x00000099 => "\x39",
     0x0000009a => "\x3a",
     0x0000009b => "\x3b",
     0x0000009c => "\x04",
     0x0000009d => "\x14",
     0x0000009e => "\x3e",
     0x0000009f => "\xff",
     0x000000a8 => "\xa1",
     0x000000e0 => "\x7c",
     0x000000e7 => "\xe0",
     0x000000e8 => "\xd0",
     0x000000e9 => "\xc0",
     0x000000f9 => "\x6a",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x6f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::IBM274 - Conversion routines for IBM274
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for IBM274.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
   source: IBM 3174 Character Set Ref, GA27-3831-02, March 1990
  alias EBCDIC-BE
  alias CP274
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  0000009C | STRING TERMINATOR (ST)
     05 |  00000009 | CHARACTER TABULATION (HT)
     06 |  00000086 | START OF SELECTED AREA (SSA)
     07 |  0000007F | DELETE (DEL)
     08 |  00000097 | END OF GUARDED AREA (EPA)
     09 |  0000008D | REVERSE LINE FEED (RI)
     0A |  0000008E | SINGLE-SHIFT TWO (SS2)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  0000009D | OPERATING SYSTEM COMMAND (OSC)
     15 |  00000085 | NEXT LINE (NEL)
     16 |  00000008 | BACKSPACE (BS)
     17 |  00000087 | END OF SELECTED AREA (ESA)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  00000092 | PRIVATE USE TWO (PU2)
     1B |  0000008F | SINGLE-SHIFT THREE (SS3)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000080 | PADDING CHARACTER (PAD)
     21 |  00000081 | HIGH OCTET PRESET (HOP)
     22 |  00000082 | BREAK PERMITTED HERE (BPH)
     23 |  00000083 | NO BREAK HERE (NBH)
     24 |  00000084 | INDEX (IND)
     25 |  0000000A | LINE FEED (LF)
     26 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     27 |  0000001B | ESCAPE (ESC)
     28 |  00000088 | CHARACTER TABULATION SET (HTS)
     29 |  00000089 | CHARACTER TABULATION WITH JUSTIFICATION (HTJ)
     2A |  0000008A | LINE TABULATION SET (VTS)
     2B |  0000008B | PARTIAL LINE FORWARD (PLD)
     2C |  0000008C | PARTIAL LINE BACKWARD (PLU)
     2D |  00000005 | ENQUIRY (ENQ)
     2E |  00000006 | ACKNOWLEDGE (ACK)
     2F |  00000007 | BELL (BEL)
     30 |  00000090 | DEVICE CONTROL STRING (DCS)
     31 |  00000091 | PRIVATE USE ONE (PU1)
     32 |  00000016 | SYNCHRONOUS IDLE (SYN)
     33 |  00000093 | SET TRANSMIT STATE (STS)
     34 |  00000094 | CANCEL CHARACTER (CCH)
     35 |  00000095 | MESSAGE WAITING (MW)
     36 |  00000096 | START OF GUARDED AREA (SPA)
     37 |  00000004 | END OF TRANSMISSION (EOT)
     38 |  00000098 | START OF STRING (SOS)
     39 |  00000099 | SINGLE GRAPHIC CHARACTER INTRODUCER (SGCI)
     3A |  0000009A | SINGLE CHARACTER INTRODUCER (SCI)
     3B |  0000009B | CONTROL SEQUENCE INTRODUCER (CSI)
     3C |  00000014 | DEVICE CONTROL FOUR (DC4)
     3D |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     3E |  0000009E | PRIVACY MESSAGE (PM)
     3F |  0000001A | SUBSTITUTE (SUB)
     40 |  00000020 | SPACE
     4A |  0000005B | LEFT SQUARE BRACKET
     4B |  0000002E | FULL STOP
     4C |  0000003C | LESS-THAN SIGN
     4D |  00000028 | LEFT PARENTHESIS
     4E |  0000002B | PLUS SIGN
     4F |  00000021 | EXCLAMATION MARK
     50 |  00000026 | AMPERSAND
     5A |  0000005D | RIGHT SQUARE BRACKET
     5B |  00000024 | DOLLAR SIGN
     5C |  0000002A | ASTERISK
     5D |  00000029 | RIGHT PARENTHESIS
     5E |  0000003B | SEMICOLON
     5F |  0000005E | CIRCUMFLEX ACCENT
     60 |  0000002D | HYPHEN-MINUS
     61 |  0000002F | SOLIDUS
     6A |  000000F9 | LATIN SMALL LETTER U WITH GRAVE
     6B |  0000002C | COMMA
     6C |  00000025 | PERCENT SIGN
     6D |  0000005F | LOW LINE
     6E |  0000003E | GREATER-THAN SIGN
     6F |  0000003F | QUESTION MARK
     79 |  00000060 | GRAVE ACCENT
     7A |  0000003A | COLON
     7B |  00000023 | NUMBER SIGN
     7C |  000000E0 | LATIN SMALL LETTER A WITH GRAVE
     7D |  00000027 | APOSTROPHE
     7E |  0000003D | EQUALS SIGN
     7F |  00000022 | QUOTATION MARK
     81 |  00000061 | LATIN SMALL LETTER A
     82 |  00000062 | LATIN SMALL LETTER B
     83 |  00000063 | LATIN SMALL LETTER C
     84 |  00000064 | LATIN SMALL LETTER D
     85 |  00000065 | LATIN SMALL LETTER E
     86 |  00000066 | LATIN SMALL LETTER F
     87 |  00000067 | LATIN SMALL LETTER G
     88 |  00000068 | LATIN SMALL LETTER H
     89 |  00000069 | LATIN SMALL LETTER I
     91 |  0000006A | LATIN SMALL LETTER J
     92 |  0000006B | LATIN SMALL LETTER K
     93 |  0000006C | LATIN SMALL LETTER L
     94 |  0000006D | LATIN SMALL LETTER M
     95 |  0000006E | LATIN SMALL LETTER N
     96 |  0000006F | LATIN SMALL LETTER O
     97 |  00000070 | LATIN SMALL LETTER P
     98 |  00000071 | LATIN SMALL LETTER Q
     99 |  00000072 | LATIN SMALL LETTER R
     A1 |  000000A8 | DIAERESIS
     A2 |  00000073 | LATIN SMALL LETTER S
     A3 |  00000074 | LATIN SMALL LETTER T
     A4 |  00000075 | LATIN SMALL LETTER U
     A5 |  00000076 | LATIN SMALL LETTER V
     A6 |  00000077 | LATIN SMALL LETTER W
     A7 |  00000078 | LATIN SMALL LETTER X
     A8 |  00000079 | LATIN SMALL LETTER Y
     A9 |  0000007A | LATIN SMALL LETTER Z
     C0 |  000000E9 | LATIN SMALL LETTER E WITH ACUTE
     C1 |  00000041 | LATIN CAPITAL LETTER A
     C2 |  00000042 | LATIN CAPITAL LETTER B
     C3 |  00000043 | LATIN CAPITAL LETTER C
     C4 |  00000044 | LATIN CAPITAL LETTER D
     C5 |  00000045 | LATIN CAPITAL LETTER E
     C6 |  00000046 | LATIN CAPITAL LETTER F
     C7 |  00000047 | LATIN CAPITAL LETTER G
     C8 |  00000048 | LATIN CAPITAL LETTER H
     C9 |  00000049 | LATIN CAPITAL LETTER I
     D0 |  000000E8 | LATIN SMALL LETTER E WITH GRAVE
     D1 |  0000004A | LATIN CAPITAL LETTER J
     D2 |  0000004B | LATIN CAPITAL LETTER K
     D3 |  0000004C | LATIN CAPITAL LETTER L
     D4 |  0000004D | LATIN CAPITAL LETTER M
     D5 |  0000004E | LATIN CAPITAL LETTER N
     D6 |  0000004F | LATIN CAPITAL LETTER O
     D7 |  00000050 | LATIN CAPITAL LETTER P
     D8 |  00000051 | LATIN CAPITAL LETTER Q
     D9 |  00000052 | LATIN CAPITAL LETTER R
     E0 |  000000E7 | LATIN SMALL LETTER C WITH CEDILLA
     E2 |  00000053 | LATIN CAPITAL LETTER S
     E3 |  00000054 | LATIN CAPITAL LETTER T
     E4 |  00000055 | LATIN CAPITAL LETTER U
     E5 |  00000056 | LATIN CAPITAL LETTER V
     E6 |  00000057 | LATIN CAPITAL LETTER W
     E7 |  00000058 | LATIN CAPITAL LETTER X
     E8 |  00000059 | LATIN CAPITAL LETTER Y
     E9 |  0000005A | LATIN CAPITAL LETTER Z
     F0 |  00000030 | DIGIT ZERO
     F1 |  00000031 | DIGIT ONE
     F2 |  00000032 | DIGIT TWO
     F3 |  00000033 | DIGIT THREE
     F4 |  00000034 | DIGIT FOUR
     F5 |  00000035 | DIGIT FIVE
     F6 |  00000036 | DIGIT SIX
     F7 |  00000037 | DIGIT SEVEN
     F8 |  00000038 | DIGIT EIGHT
     F9 |  00000039 | DIGIT NINE
     FF |  0000009F | APPLICATION PROGRAM COMMAND (APC)
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/IBM275.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for IBM275.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::IBM275;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x009c,
     0x0009,
     0x0086,
     0x007f,
     0x0097,
     0x008d,
     0x008e,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x009d,
     0x0085,
     0x0008,
     0x0087,
     0x0018,
     0x0019,
     0x0092,
     0x008f,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0080,
     0x0081,
     0x0082,
     0x0083,
     0x0084,
     0x000a,
     0x0017,
     0x001b,
     0x0088,
     0x0089,
     0x008a,
     0x008b,
     0x008c,
     0x0005,
     0x0006,
     0x0007,
     0x0090,
     0x0091,
     0x0016,
     0x0093,
     0x0094,
     0x0095,
     0x0096,
     0x0004,
     0x0098,
     0x0099,
     0x009a,
     0x009b,
     0x0014,
     0x0015,
     0x009e,
     0x001a,
     0x0020,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00c9,
     0x002e,
     0x003c,
     0x0028,
     0x002b,
     0x0021,
     0x0026,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x0024,
     0x00c7,
     0x002a,
     0x0029,
     0x003b,
     0x005e,
     0x002d,
     0x002f,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00e7,
     0x002c,
     0x0025,
     0x005f,
     0x003e,
     0x003f,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00e3,
     0x003a,
     0x00d5,
     0x00c3,
     0x0027,
     0x003d,
     0x0022,
     0xfffd,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x007e,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00f5,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00e9,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x005c,
     0xfffd,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x009f,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\xc2\x9c",
     "\x09",
     "\xc2\x86",
     "\x7f",
     "\xc2\x97",
     "\xc2\x8d",
     "\xc2\x8e",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\xc2\x9d",
     "\xc2\x85",
     "\x08",
     "\xc2\x87",
     "\x18",
     "\x19",
     "\xc2\x92",
     "\xc2\x8f",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\xc2\x80",
     "\xc2\x81",
     "\xc2\x82",
     "\xc2\x83",
     "\xc2\x84",
     "\x0a",
     "\x17",
     "\x1b",
     "\xc2\x88",
     "\xc2\x89",
     "\xc2\x8a",
     "\xc2\x8b",
     "\xc2\x8c",
     "\x05",
     "\x06",
     "\x07",
     "\xc2\x90",
     "\xc2\x91",
     "\x16",
     "\xc2\x93",
     "\xc2\x94",
     "\xc2\x95",
     "\xc2\x96",
     "\x04",
     "\xc2\x98",
     "\xc2\x99",
     "\xc2\x9a",
     "\xc2\x9b",
     "\x14",
     "\x15",
     "\xc2\x9e",
     "\x1a",
     "\x20",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc3\x89",
     "\x2e",
     "\x3c",
     "\x28",
     "\x2b",
     "\x21",
     "\x26",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x24",
     "\xc3\x87",
     "\x2a",
     "\x29",
     "\x3b",
     "\x5e",
     "\x2d",
     "\x2f",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc3\xa7",
     "\x2c",
     "\x25",
     "\x5f",
     "\x3e",
     "\x3f",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc3\xa3",
     "\x3a",
     "\xc3\x95",
     "\xc3\x83",
     "\x27",
     "\x3d",
     "\x22",
     "\xef\xbf\xbd",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x7e",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc3\xb5",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc3\xa9",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x5c",
     "\xef\xbf\xbd",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc2\x9f",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x37",
     0x00000005 => "\x2d",
     0x00000006 => "\x2e",
     0x00000007 => "\x2f",
     0x00000008 => "\x16",
     0x00000009 => "\x05",
     0x0000000a => "\x25",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x3c",
     0x00000015 => "\x3d",
     0x00000016 => "\x32",
     0x00000017 => "\x26",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x3f",
     0x0000001b => "\x27",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x40",
     0x00000021 => "\x4f",
     0x00000022 => "\x7f",
     0x00000024 => "\x5a",
     0x00000025 => "\x6c",
     0x00000026 => "\x50",
     0x00000027 => "\x7d",
     0x00000028 => "\x4d",
     0x00000029 => "\x5d",
     0x0000002a => "\x5c",
     0x0000002b => "\x4e",
     0x0000002c => "\x6b",
     0x0000002d => "\x60",
     0x0000002e => "\x4b",
     0x0000002f => "\x61",
     0x00000030 => "\xf0",
     0x00000031 => "\xf1",
     0x00000032 => "\xf2",
     0x00000033 => "\xf3",
     0x00000034 => "\xf4",
     0x00000035 => "\xf5",
     0x00000036 => "\xf6",
     0x00000037 => "\xf7",
     0x00000038 => "\xf8",
     0x00000039 => "\xf9",
     0x0000003a => "\x7a",
     0x0000003b => "\x5e",
     0x0000003c => "\x4c",
     0x0000003d => "\x7e",
     0x0000003e => "\x6e",
     0x0000003f => "\x6f",
     0x00000041 => "\xc1",
     0x00000042 => "\xc2",
     0x00000043 => "\xc3",
     0x00000044 => "\xc4",
     0x00000045 => "\xc5",
     0x00000046 => "\xc6",
     0x00000047 => "\xc7",
     0x00000048 => "\xc8",
     0x00000049 => "\xc9",
     0x0000004a => "\xd1",
     0x0000004b => "\xd2",
     0x0000004c => "\xd3",
     0x0000004d => "\xd4",
     0x0000004e => "\xd5",
     0x0000004f => "\xd6",
     0x00000050 => "\xd7",
     0x00000051 => "\xd8",
     0x00000052 => "\xd9",
     0x00000053 => "\xe2",
     0x00000054 => "\xe3",
     0x00000055 => "\xe4",
     0x00000056 => "\xe5",
     0x00000057 => "\xe6",
     0x00000058 => "\xe7",
     0x00000059 => "\xe8",
     0x0000005a => "\xe9",
     0x0000005c => "\xe0",
     0x0000005e => "\x5f",
     0x0000005f => "\x6d",
     0x00000061 => "\x81",
     0x00000062 => "\x82",
     0x00000063 => "\x83",
     0x00000064 => "\x84",
     0x00000065 => "\x85",
     0x00000066 => "\x86",
     0x00000067 => "\x87",
     0x00000068 => "\x88",
     0x00000069 => "\x89",
     0x0000006a => "\x91",
     0x0000006b => "\x92",
     0x0000006c => "\x93",
     0x0000006d => "\x94",
     0x0000006e => "\x95",
     0x0000006f => "\x96",
     0x00000070 => "\x97",
     0x00000071 => "\x98",
     0x00000072 => "\x99",
     0x00000073 => "\xa2",
     0x00000074 => "\xa3",
     0x00000075 => "\xa4",
     0x00000076 => "\xa5",
     0x00000077 => "\xa6",
     0x00000078 => "\xa7",
     0x00000079 => "\xa8",
     0x0000007a => "\xa9",
     0x0000007e => "\xa1",
     0x0000007f => "\x07",
     0x00000080 => "\x20",
     0x00000081 => "\x21",
     0x00000082 => "\x22",
     0x00000083 => "\x23",
     0x00000084 => "\x24",
     0x00000085 => "\x15",
     0x00000086 => "\x06",
     0x00000087 => "\x17",
     0x00000088 => "\x28",
     0x00000089 => "\x29",
     0x0000008a => "\x2a",
     0x0000008b => "\x2b",
     0x0000008c => "\x2c",
     0x0000008d => "\x09",
     0x0000008e => "\x0a",
     0x0000008f => "\x1b",
     0x00000090 => "\x30",
     0x00000091 => "\x31",
     0x00000092 => "\x1a",
     0x00000093 => "\x33",
     0x00000094 => "\x34",
     0x00000095 => "\x35",
     0x00000096 => "\x36",
     0x00000097 => "\x08",
     0x00000098 => "\x38",
     0x00000099 => "\x39",
     0x0000009a => "\x3a",
     0x0000009b => "\x3b",
     0x0000009c => "\x04",
     0x0000009d => "\x14",
     0x0000009e => "\x3e",
     0x0000009f => "\xff",
     0x000000c3 => "\x7c",
     0x000000c7 => "\x5b",
     0x000000c9 => "\x4a",
     0x000000d5 => "\x7b",
     0x000000e3 => "\x79",
     0x000000e7 => "\x6a",
     0x000000e9 => "\xd0",
     0x000000f5 => "\xc0",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x6f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::IBM275 - Conversion routines for IBM275
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for IBM275.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
   source: IBM NLS RM Vol2 SE09-8002-01, March 1990
  alias EBCDIC-BR
  alias CP275
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  0000009C | STRING TERMINATOR (ST)
     05 |  00000009 | CHARACTER TABULATION (HT)
     06 |  00000086 | START OF SELECTED AREA (SSA)
     07 |  0000007F | DELETE (DEL)
     08 |  00000097 | END OF GUARDED AREA (EPA)
     09 |  0000008D | REVERSE LINE FEED (RI)
     0A |  0000008E | SINGLE-SHIFT TWO (SS2)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  0000009D | OPERATING SYSTEM COMMAND (OSC)
     15 |  00000085 | NEXT LINE (NEL)
     16 |  00000008 | BACKSPACE (BS)
     17 |  00000087 | END OF SELECTED AREA (ESA)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  00000092 | PRIVATE USE TWO (PU2)
     1B |  0000008F | SINGLE-SHIFT THREE (SS3)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000080 | PADDING CHARACTER (PAD)
     21 |  00000081 | HIGH OCTET PRESET (HOP)
     22 |  00000082 | BREAK PERMITTED HERE (BPH)
     23 |  00000083 | NO BREAK HERE (NBH)
     24 |  00000084 | INDEX (IND)
     25 |  0000000A | LINE FEED (LF)
     26 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     27 |  0000001B | ESCAPE (ESC)
     28 |  00000088 | CHARACTER TABULATION SET (HTS)
     29 |  00000089 | CHARACTER TABULATION WITH JUSTIFICATION (HTJ)
     2A |  0000008A | LINE TABULATION SET (VTS)
     2B |  0000008B | PARTIAL LINE FORWARD (PLD)
     2C |  0000008C | PARTIAL LINE BACKWARD (PLU)
     2D |  00000005 | ENQUIRY (ENQ)
     2E |  00000006 | ACKNOWLEDGE (ACK)
     2F |  00000007 | BELL (BEL)
     30 |  00000090 | DEVICE CONTROL STRING (DCS)
     31 |  00000091 | PRIVATE USE ONE (PU1)
     32 |  00000016 | SYNCHRONOUS IDLE (SYN)
     33 |  00000093 | SET TRANSMIT STATE (STS)
     34 |  00000094 | CANCEL CHARACTER (CCH)
     35 |  00000095 | MESSAGE WAITING (MW)
     36 |  00000096 | START OF GUARDED AREA (SPA)
     37 |  00000004 | END OF TRANSMISSION (EOT)
     38 |  00000098 | START OF STRING (SOS)
     39 |  00000099 | SINGLE GRAPHIC CHARACTER INTRODUCER (SGCI)
     3A |  0000009A | SINGLE CHARACTER INTRODUCER (SCI)
     3B |  0000009B | CONTROL SEQUENCE INTRODUCER (CSI)
     3C |  00000014 | DEVICE CONTROL FOUR (DC4)
     3D |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     3E |  0000009E | PRIVACY MESSAGE (PM)
     3F |  0000001A | SUBSTITUTE (SUB)
     40 |  00000020 | SPACE
     4A |  000000C9 | LATIN CAPITAL LETTER E WITH ACUTE
     4B |  0000002E | FULL STOP
     4C |  0000003C | LESS-THAN SIGN
     4D |  00000028 | LEFT PARENTHESIS
     4E |  0000002B | PLUS SIGN
     4F |  00000021 | EXCLAMATION MARK
     50 |  00000026 | AMPERSAND
     5A |  00000024 | DOLLAR SIGN
     5B |  000000C7 | LATIN CAPITAL LETTER C WITH CEDILLA
     5C |  0000002A | ASTERISK
     5D |  00000029 | RIGHT PARENTHESIS
     5E |  0000003B | SEMICOLON
     5F |  0000005E | CIRCUMFLEX ACCENT
     60 |  0000002D | HYPHEN-MINUS
     61 |  0000002F | SOLIDUS
     6A |  000000E7 | LATIN SMALL LETTER C WITH CEDILLA
     6B |  0000002C | COMMA
     6C |  00000025 | PERCENT SIGN
     6D |  0000005F | LOW LINE
     6E |  0000003E | GREATER-THAN SIGN
     6F |  0000003F | QUESTION MARK
     79 |  000000E3 | LATIN SMALL LETTER A WITH TILDE
     7A |  0000003A | COLON
     7B |  000000D5 | LATIN CAPITAL LETTER O WITH TILDE
     7C |  000000C3 | LATIN CAPITAL LETTER A WITH TILDE
     7D |  00000027 | APOSTROPHE
     7E |  0000003D | EQUALS SIGN
     7F |  00000022 | QUOTATION MARK
     81 |  00000061 | LATIN SMALL LETTER A
     82 |  00000062 | LATIN SMALL LETTER B
     83 |  00000063 | LATIN SMALL LETTER C
     84 |  00000064 | LATIN SMALL LETTER D
     85 |  00000065 | LATIN SMALL LETTER E
     86 |  00000066 | LATIN SMALL LETTER F
     87 |  00000067 | LATIN SMALL LETTER G
     88 |  00000068 | LATIN SMALL LETTER H
     89 |  00000069 | LATIN SMALL LETTER I
     91 |  0000006A | LATIN SMALL LETTER J
     92 |  0000006B | LATIN SMALL LETTER K
     93 |  0000006C | LATIN SMALL LETTER L
     94 |  0000006D | LATIN SMALL LETTER M
     95 |  0000006E | LATIN SMALL LETTER N
     96 |  0000006F | LATIN SMALL LETTER O
     97 |  00000070 | LATIN SMALL LETTER P
     98 |  00000071 | LATIN SMALL LETTER Q
     99 |  00000072 | LATIN SMALL LETTER R
     A1 |  0000007E | TILDE
     A2 |  00000073 | LATIN SMALL LETTER S
     A3 |  00000074 | LATIN SMALL LETTER T
     A4 |  00000075 | LATIN SMALL LETTER U
     A5 |  00000076 | LATIN SMALL LETTER V
     A6 |  00000077 | LATIN SMALL LETTER W
     A7 |  00000078 | LATIN SMALL LETTER X
     A8 |  00000079 | LATIN SMALL LETTER Y
     A9 |  0000007A | LATIN SMALL LETTER Z
     C0 |  000000F5 | LATIN SMALL LETTER O WITH TILDE
     C1 |  00000041 | LATIN CAPITAL LETTER A
     C2 |  00000042 | LATIN CAPITAL LETTER B
     C3 |  00000043 | LATIN CAPITAL LETTER C
     C4 |  00000044 | LATIN CAPITAL LETTER D
     C5 |  00000045 | LATIN CAPITAL LETTER E
     C6 |  00000046 | LATIN CAPITAL LETTER F
     C7 |  00000047 | LATIN CAPITAL LETTER G
     C8 |  00000048 | LATIN CAPITAL LETTER H
     C9 |  00000049 | LATIN CAPITAL LETTER I
     D0 |  000000E9 | LATIN SMALL LETTER E WITH ACUTE
     D1 |  0000004A | LATIN CAPITAL LETTER J
     D2 |  0000004B | LATIN CAPITAL LETTER K
     D3 |  0000004C | LATIN CAPITAL LETTER L
     D4 |  0000004D | LATIN CAPITAL LETTER M
     D5 |  0000004E | LATIN CAPITAL LETTER N
     D6 |  0000004F | LATIN CAPITAL LETTER O
     D7 |  00000050 | LATIN CAPITAL LETTER P
     D8 |  00000051 | LATIN CAPITAL LETTER Q
     D9 |  00000052 | LATIN CAPITAL LETTER R
     E0 |  0000005C | REVERSE SOLIDUS
     E2 |  00000053 | LATIN CAPITAL LETTER S
     E3 |  00000054 | LATIN CAPITAL LETTER T
     E4 |  00000055 | LATIN CAPITAL LETTER U
     E5 |  00000056 | LATIN CAPITAL LETTER V
     E6 |  00000057 | LATIN CAPITAL LETTER W
     E7 |  00000058 | LATIN CAPITAL LETTER X
     E8 |  00000059 | LATIN CAPITAL LETTER Y
     E9 |  0000005A | LATIN CAPITAL LETTER Z
     F0 |  00000030 | DIGIT ZERO
     F1 |  00000031 | DIGIT ONE
     F2 |  00000032 | DIGIT TWO
     F3 |  00000033 | DIGIT THREE
     F4 |  00000034 | DIGIT FOUR
     F5 |  00000035 | DIGIT FIVE
     F6 |  00000036 | DIGIT SIX
     F7 |  00000037 | DIGIT SEVEN
     F8 |  00000038 | DIGIT EIGHT
     F9 |  00000039 | DIGIT NINE
     FF |  0000009F | APPLICATION PROGRAM COMMAND (APC)
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/IBM277.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for IBM277.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::IBM277;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x009c,
     0x0009,
     0x0086,
     0x007f,
     0x0097,
     0x008d,
     0x008e,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x009d,
     0x0085,
     0x0008,
     0x0087,
     0x0018,
     0x0019,
     0x0092,
     0x008f,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0080,
     0x0081,
     0x0082,
     0x0083,
     0x0084,
     0x000a,
     0x0017,
     0x001b,
     0x0088,
     0x0089,
     0x008a,
     0x008b,
     0x008c,
     0x0005,
     0x0006,
     0x0007,
     0x0090,
     0x0091,
     0x0016,
     0x0093,
     0x0094,
     0x0095,
     0x0096,
     0x0004,
     0x0098,
     0x0099,
     0x009a,
     0x009b,
     0x0014,
     0x0015,
     0x009e,
     0x001a,
     0x0020,
     0x00a0,
     0x00e2,
     0x00e4,
     0x00e0,
     0x00e1,
     0x00e3,
     0x007d,
     0x00e7,
     0x00f1,
     0x0023,
     0x002e,
     0x003c,
     0x0028,
     0x002b,
     0x0021,
     0x0026,
     0x00e9,
     0x00ea,
     0x00eb,
     0x00e8,
     0x00ed,
     0x00ee,
     0x00ef,
     0x00ec,
     0x00df,
     0x00a4,
     0x00c5,
     0x002a,
     0x0029,
     0x003b,
     0x005e,
     0x002d,
     0x002f,
     0x00c2,
     0x00c4,
     0x00c0,
     0x00c1,
     0x00c3,
     0x0024,
     0x00c7,
     0x00d1,
     0x00f8,
     0x002c,
     0x0025,
     0x005f,
     0x003e,
     0x003f,
     0x00a6,
     0x00c9,
     0x00ca,
     0x00cb,
     0x00c8,
     0x00cd,
     0x00ce,
     0x00cf,
     0x00cc,
     0x0060,
     0x003a,
     0x00c6,
     0x00d8,
     0x0027,
     0x003d,
     0x0022,
     0x0040,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x00ab,
     0x00bb,
     0x00f0,
     0x00fd,
     0x00fe,
     0x00b1,
     0x00b0,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x00aa,
     0x00ba,
     0x007b,
     0x00b8,
     0x005b,
     0x005d,
     0x00b5,
     0x00fc,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x00a1,
     0x00bf,
     0x00d0,
     0x00dd,
     0x00de,
     0x00ae,
     0x00a2,
     0x00a3,
     0x00a5,
     0x00b7,
     0x00a9,
     0x00a7,
     0x00b6,
     0x00bc,
     0x00bd,
     0x00be,
     0x00ac,
     0x007c,
     0x203e,
     0x00a8,
     0x00b4,
     0x00d7,
     0x00e6,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x00ad,
     0x00f4,
     0x00f6,
     0x00f2,
     0x00f3,
     0x00f5,
     0x00e5,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x00b9,
     0x00fb,
     0x007e,
     0x00f9,
     0x00fa,
     0x00ff,
     0x005c,
     0x00f7,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x00b2,
     0x00d4,
     0x00d6,
     0x00d2,
     0x00d3,
     0x00d5,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x00b3,
     0x00db,
     0x00dc,
     0x00d9,
     0x00da,
     0x009f,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\xc2\x9c",
     "\x09",
     "\xc2\x86",
     "\x7f",
     "\xc2\x97",
     "\xc2\x8d",
     "\xc2\x8e",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\xc2\x9d",
     "\xc2\x85",
     "\x08",
     "\xc2\x87",
     "\x18",
     "\x19",
     "\xc2\x92",
     "\xc2\x8f",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\xc2\x80",
     "\xc2\x81",
     "\xc2\x82",
     "\xc2\x83",
     "\xc2\x84",
     "\x0a",
     "\x17",
     "\x1b",
     "\xc2\x88",
     "\xc2\x89",
     "\xc2\x8a",
     "\xc2\x8b",
     "\xc2\x8c",
     "\x05",
     "\x06",
     "\x07",
     "\xc2\x90",
     "\xc2\x91",
     "\x16",
     "\xc2\x93",
     "\xc2\x94",
     "\xc2\x95",
     "\xc2\x96",
     "\x04",
     "\xc2\x98",
     "\xc2\x99",
     "\xc2\x9a",
     "\xc2\x9b",
     "\x14",
     "\x15",
     "\xc2\x9e",
     "\x1a",
     "\x20",
     "\xc2\xa0",
     "\xc3\xa2",
     "\xc3\xa4",
     "\xc3\xa0",
     "\xc3\xa1",
     "\xc3\xa3",
     "\x7d",
     "\xc3\xa7",
     "\xc3\xb1",
     "\x23",
     "\x2e",
     "\x3c",
     "\x28",
     "\x2b",
     "\x21",
     "\x26",
     "\xc3\xa9",
     "\xc3\xaa",
     "\xc3\xab",
     "\xc3\xa8",
     "\xc3\xad",
     "\xc3\xae",
     "\xc3\xaf",
     "\xc3\xac",
     "\xc3\x9f",
     "\xc2\xa4",
     "\xc3\x85",
     "\x2a",
     "\x29",
     "\x3b",
     "\x5e",
     "\x2d",
     "\x2f",
     "\xc3\x82",
     "\xc3\x84",
     "\xc3\x80",
     "\xc3\x81",
     "\xc3\x83",
     "\x24",
     "\xc3\x87",
     "\xc3\x91",
     "\xc3\xb8",
     "\x2c",
     "\x25",
     "\x5f",
     "\x3e",
     "\x3f",
     "\xc2\xa6",
     "\xc3\x89",
     "\xc3\x8a",
     "\xc3\x8b",
     "\xc3\x88",
     "\xc3\x8d",
     "\xc3\x8e",
     "\xc3\x8f",
     "\xc3\x8c",
     "\x60",
     "\x3a",
     "\xc3\x86",
     "\xc3\x98",
     "\x27",
     "\x3d",
     "\x22",
     "\x40",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\xc2\xab",
     "\xc2\xbb",
     "\xc3\xb0",
     "\xc3\xbd",
     "\xc3\xbe",
     "\xc2\xb1",
     "\xc2\xb0",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\xc2\xaa",
     "\xc2\xba",
     "\x7b",
     "\xc2\xb8",
     "\x5b",
     "\x5d",
     "\xc2\xb5",
     "\xc3\xbc",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\xc2\xa1",
     "\xc2\xbf",
     "\xc3\x90",
     "\xc3\x9d",
     "\xc3\x9e",
     "\xc2\xae",
     "\xc2\xa2",
     "\xc2\xa3",
     "\xc2\xa5",
     "\xc2\xb7",
     "\xc2\xa9",
     "\xc2\xa7",
     "\xc2\xb6",
     "\xc2\xbc",
     "\xc2\xbd",
     "\xc2\xbe",
     "\xc2\xac",
     "\x7c",
     "\xe2\x80\xbe",
     "\xc2\xa8",
     "\xc2\xb4",
     "\xc3\x97",
     "\xc3\xa6",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\xc2\xad",
     "\xc3\xb4",
     "\xc3\xb6",
     "\xc3\xb2",
     "\xc3\xb3",
     "\xc3\xb5",
     "\xc3\xa5",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\xc2\xb9",
     "\xc3\xbb",
     "\x7e",
     "\xc3\xb9",
     "\xc3\xba",
     "\xc3\xbf",
     "\x5c",
     "\xc3\xb7",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\xc2\xb2",
     "\xc3\x94",
     "\xc3\x96",
     "\xc3\x92",
     "\xc3\x93",
     "\xc3\x95",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\xc2\xb3",
     "\xc3\x9b",
     "\xc3\x9c",
     "\xc3\x99",
     "\xc3\x9a",
     "\xc2\x9f",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x37",
     0x00000005 => "\x2d",
     0x00000006 => "\x2e",
     0x00000007 => "\x2f",
     0x00000008 => "\x16",
     0x00000009 => "\x05",
     0x0000000a => "\x25",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x3c",
     0x00000015 => "\x3d",
     0x00000016 => "\x32",
     0x00000017 => "\x26",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x3f",
     0x0000001b => "\x27",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x40",
     0x00000021 => "\x4f",
     0x00000022 => "\x7f",
     0x00000023 => "\x4a",
     0x00000024 => "\x67",
     0x00000025 => "\x6c",
     0x00000026 => "\x50",
     0x00000027 => "\x7d",
     0x00000028 => "\x4d",
     0x00000029 => "\x5d",
     0x0000002a => "\x5c",
     0x0000002b => "\x4e",
     0x0000002c => "\x6b",
     0x0000002d => "\x60",
     0x0000002e => "\x4b",
     0x0000002f => "\x61",
     0x00000030 => "\xf0",
     0x00000031 => "\xf1",
     0x00000032 => "\xf2",
     0x00000033 => "\xf3",
     0x00000034 => "\xf4",
     0x00000035 => "\xf5",
     0x00000036 => "\xf6",
     0x00000037 => "\xf7",
     0x00000038 => "\xf8",
     0x00000039 => "\xf9",
     0x0000003a => "\x7a",
     0x0000003b => "\x5e",
     0x0000003c => "\x4c",
     0x0000003d => "\x7e",
     0x0000003e => "\x6e",
     0x0000003f => "\x6f",
     0x00000040 => "\x80",
     0x00000041 => "\xc1",
     0x00000042 => "\xc2",
     0x00000043 => "\xc3",
     0x00000044 => "\xc4",
     0x00000045 => "\xc5",
     0x00000046 => "\xc6",
     0x00000047 => "\xc7",
     0x00000048 => "\xc8",
     0x00000049 => "\xc9",
     0x0000004a => "\xd1",
     0x0000004b => "\xd2",
     0x0000004c => "\xd3",
     0x0000004d => "\xd4",
     0x0000004e => "\xd5",
     0x0000004f => "\xd6",
     0x00000050 => "\xd7",
     0x00000051 => "\xd8",
     0x00000052 => "\xd9",
     0x00000053 => "\xe2",
     0x00000054 => "\xe3",
     0x00000055 => "\xe4",
     0x00000056 => "\xe5",
     0x00000057 => "\xe6",
     0x00000058 => "\xe7",
     0x00000059 => "\xe8",
     0x0000005a => "\xe9",
     0x0000005b => "\x9e",
     0x0000005c => "\xe0",
     0x0000005d => "\x9f",
     0x0000005e => "\x5f",
     0x0000005f => "\x6d",
     0x00000060 => "\x79",
     0x00000061 => "\x81",
     0x00000062 => "\x82",
     0x00000063 => "\x83",
     0x00000064 => "\x84",
     0x00000065 => "\x85",
     0x00000066 => "\x86",
     0x00000067 => "\x87",
     0x00000068 => "\x88",
     0x00000069 => "\x89",
     0x0000006a => "\x91",
     0x0000006b => "\x92",
     0x0000006c => "\x93",
     0x0000006d => "\x94",
     0x0000006e => "\x95",
     0x0000006f => "\x96",
     0x00000070 => "\x97",
     0x00000071 => "\x98",
     0x00000072 => "\x99",
     0x00000073 => "\xa2",
     0x00000074 => "\xa3",
     0x00000075 => "\xa4",
     0x00000076 => "\xa5",
     0x00000077 => "\xa6",
     0x00000078 => "\xa7",
     0x00000079 => "\xa8",
     0x0000007a => "\xa9",
     0x0000007b => "\x9c",
     0x0000007c => "\xbb",
     0x0000007d => "\x47",
     0x0000007e => "\xdc",
     0x0000007f => "\x07",
     0x00000080 => "\x20",
     0x00000081 => "\x21",
     0x00000082 => "\x22",
     0x00000083 => "\x23",
     0x00000084 => "\x24",
     0x00000085 => "\x15",
     0x00000086 => "\x06",
     0x00000087 => "\x17",
     0x00000088 => "\x28",
     0x00000089 => "\x29",
     0x0000008a => "\x2a",
     0x0000008b => "\x2b",
     0x0000008c => "\x2c",
     0x0000008d => "\x09",
     0x0000008e => "\x0a",
     0x0000008f => "\x1b",
     0x00000090 => "\x30",
     0x00000091 => "\x31",
     0x00000092 => "\x1a",
     0x00000093 => "\x33",
     0x00000094 => "\x34",
     0x00000095 => "\x35",
     0x00000096 => "\x36",
     0x00000097 => "\x08",
     0x00000098 => "\x38",
     0x00000099 => "\x39",
     0x0000009a => "\x3a",
     0x0000009b => "\x3b",
     0x0000009c => "\x04",
     0x0000009d => "\x14",
     0x0000009e => "\x3e",
     0x0000009f => "\xff",
     0x000000a0 => "\x41",
     0x000000a1 => "\xaa",
     0x000000a2 => "\xb0",
     0x000000a3 => "\xb1",
     0x000000a4 => "\x5a",
     0x000000a5 => "\xb2",
     0x000000a6 => "\x70",
     0x000000a7 => "\xb5",
     0x000000a8 => "\xbd",
     0x000000a9 => "\xb4",
     0x000000aa => "\x9a",
     0x000000ab => "\x8a",
     0x000000ac => "\xba",
     0x000000ad => "\xca",
     0x000000ae => "\xaf",
     0x000000b0 => "\x90",
     0x000000b1 => "\x8f",
     0x000000b2 => "\xea",
     0x000000b3 => "\xfa",
     0x000000b4 => "\xbe",
     0x000000b5 => "\xa0",
     0x000000b6 => "\xb6",
     0x000000b7 => "\xb3",
     0x000000b8 => "\x9d",
     0x000000b9 => "\xda",
     0x000000ba => "\x9b",
     0x000000bb => "\x8b",
     0x000000bc => "\xb7",
     0x000000bd => "\xb8",
     0x000000be => "\xb9",
     0x000000bf => "\xab",
     0x000000c0 => "\x64",
     0x000000c1 => "\x65",
     0x000000c2 => "\x62",
     0x000000c3 => "\x66",
     0x000000c4 => "\x63",
     0x000000c5 => "\x5b",
     0x000000c6 => "\x7b",
     0x000000c7 => "\x68",
     0x000000c8 => "\x74",
     0x000000c9 => "\x71",
     0x000000ca => "\x72",
     0x000000cb => "\x73",
     0x000000cc => "\x78",
     0x000000cd => "\x75",
     0x000000ce => "\x76",
     0x000000cf => "\x77",
     0x000000d0 => "\xac",
     0x000000d1 => "\x69",
     0x000000d2 => "\xed",
     0x000000d3 => "\xee",
     0x000000d4 => "\xeb",
     0x000000d5 => "\xef",
     0x000000d6 => "\xec",
     0x000000d7 => "\xbf",
     0x000000d8 => "\x7c",
     0x000000d9 => "\xfd",
     0x000000da => "\xfe",
     0x000000db => "\xfb",
     0x000000dc => "\xfc",
     0x000000dd => "\xad",
     0x000000de => "\xae",
     0x000000df => "\x59",
     0x000000e0 => "\x44",
     0x000000e1 => "\x45",
     0x000000e2 => "\x42",
     0x000000e3 => "\x46",
     0x000000e4 => "\x43",
     0x000000e5 => "\xd0",
     0x000000e6 => "\xc0",
     0x000000e7 => "\x48",
     0x000000e8 => "\x54",
     0x000000e9 => "\x51",
     0x000000ea => "\x52",
     0x000000eb => "\x53",
     0x000000ec => "\x58",
     0x000000ed => "\x55",
     0x000000ee => "\x56",
     0x000000ef => "\x57",
     0x000000f0 => "\x8c",
     0x000000f1 => "\x49",
     0x000000f2 => "\xcd",
     0x000000f3 => "\xce",
     0x000000f4 => "\xcb",
     0x000000f5 => "\xcf",
     0x000000f6 => "\xcc",
     0x000000f7 => "\xe1",
     0x000000f8 => "\x6a",
     0x000000f9 => "\xdd",
     0x000000fa => "\xde",
     0x000000fb => "\xdb",
     0x000000fc => "\xa1",
     0x000000fd => "\x8d",
     0x000000fe => "\x8e",
     0x000000ff => "\xdf",
     0x0000203e => "\xbc",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x6f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::IBM277 - Conversion routines for IBM277
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for IBM277.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
   source: IBM NLS RM Vol2 SE09-8002-01, March 1990
  alias EBCDIC-CP-DK
  alias EBCDIC-CP-NO
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  0000009C | STRING TERMINATOR (ST)
     05 |  00000009 | CHARACTER TABULATION (HT)
     06 |  00000086 | START OF SELECTED AREA (SSA)
     07 |  0000007F | DELETE (DEL)
     08 |  00000097 | END OF GUARDED AREA (EPA)
     09 |  0000008D | REVERSE LINE FEED (RI)
     0A |  0000008E | SINGLE-SHIFT TWO (SS2)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  0000009D | OPERATING SYSTEM COMMAND (OSC)
     15 |  00000085 | NEXT LINE (NEL)
     16 |  00000008 | BACKSPACE (BS)
     17 |  00000087 | END OF SELECTED AREA (ESA)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  00000092 | PRIVATE USE TWO (PU2)
     1B |  0000008F | SINGLE-SHIFT THREE (SS3)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000080 | PADDING CHARACTER (PAD)
     21 |  00000081 | HIGH OCTET PRESET (HOP)
     22 |  00000082 | BREAK PERMITTED HERE (BPH)
     23 |  00000083 | NO BREAK HERE (NBH)
     24 |  00000084 | INDEX (IND)
     25 |  0000000A | LINE FEED (LF)
     26 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     27 |  0000001B | ESCAPE (ESC)
     28 |  00000088 | CHARACTER TABULATION SET (HTS)
     29 |  00000089 | CHARACTER TABULATION WITH JUSTIFICATION (HTJ)
     2A |  0000008A | LINE TABULATION SET (VTS)
     2B |  0000008B | PARTIAL LINE FORWARD (PLD)
     2C |  0000008C | PARTIAL LINE BACKWARD (PLU)
     2D |  00000005 | ENQUIRY (ENQ)
     2E |  00000006 | ACKNOWLEDGE (ACK)
     2F |  00000007 | BELL (BEL)
     30 |  00000090 | DEVICE CONTROL STRING (DCS)
     31 |  00000091 | PRIVATE USE ONE (PU1)
     32 |  00000016 | SYNCHRONOUS IDLE (SYN)
     33 |  00000093 | SET TRANSMIT STATE (STS)
     34 |  00000094 | CANCEL CHARACTER (CCH)
     35 |  00000095 | MESSAGE WAITING (MW)
     36 |  00000096 | START OF GUARDED AREA (SPA)
     37 |  00000004 | END OF TRANSMISSION (EOT)
     38 |  00000098 | START OF STRING (SOS)
     39 |  00000099 | SINGLE GRAPHIC CHARACTER INTRODUCER (SGCI)
     3A |  0000009A | SINGLE CHARACTER INTRODUCER (SCI)
     3B |  0000009B | CONTROL SEQUENCE INTRODUCER (CSI)
     3C |  00000014 | DEVICE CONTROL FOUR (DC4)
     3D |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     3E |  0000009E | PRIVACY MESSAGE (PM)
     3F |  0000001A | SUBSTITUTE (SUB)
     40 |  00000020 | SPACE
     41 |  000000A0 | NO-BREAK SPACE
     42 |  000000E2 | LATIN SMALL LETTER A WITH CIRCUMFLEX
     43 |  000000E4 | LATIN SMALL LETTER A WITH DIAERESIS
     44 |  000000E0 | LATIN SMALL LETTER A WITH GRAVE
     45 |  000000E1 | LATIN SMALL LETTER A WITH ACUTE
     46 |  000000E3 | LATIN SMALL LETTER A WITH TILDE
     47 |  0000007D | RIGHT CURLY BRACKET
     48 |  000000E7 | LATIN SMALL LETTER C WITH CEDILLA
     49 |  000000F1 | LATIN SMALL LETTER N WITH TILDE
     4A |  00000023 | NUMBER SIGN
     4B |  0000002E | FULL STOP
     4C |  0000003C | LESS-THAN SIGN
     4D |  00000028 | LEFT PARENTHESIS
     4E |  0000002B | PLUS SIGN
     4F |  00000021 | EXCLAMATION MARK
     50 |  00000026 | AMPERSAND
     51 |  000000E9 | LATIN SMALL LETTER E WITH ACUTE
     52 |  000000EA | LATIN SMALL LETTER E WITH CIRCUMFLEX
     53 |  000000EB | LATIN SMALL LETTER E WITH DIAERESIS
     54 |  000000E8 | LATIN SMALL LETTER E WITH GRAVE
     55 |  000000ED | LATIN SMALL LETTER I WITH ACUTE
     56 |  000000EE | LATIN SMALL LETTER I WITH CIRCUMFLEX
     57 |  000000EF | LATIN SMALL LETTER I WITH DIAERESIS
     58 |  000000EC | LATIN SMALL LETTER I WITH GRAVE
     59 |  000000DF | LATIN SMALL LETTER SHARP S (German)
     5A |  000000A4 | CURRENCY SIGN
     5B |  000000C5 | LATIN CAPITAL LETTER A WITH RING ABOVE
     5C |  0000002A | ASTERISK
     5D |  00000029 | RIGHT PARENTHESIS
     5E |  0000003B | SEMICOLON
     5F |  0000005E | CIRCUMFLEX ACCENT
     60 |  0000002D | HYPHEN-MINUS
     61 |  0000002F | SOLIDUS
     62 |  000000C2 | LATIN CAPITAL LETTER A WITH CIRCUMFLEX
     63 |  000000C4 | LATIN CAPITAL LETTER A WITH DIAERESIS
     64 |  000000C0 | LATIN CAPITAL LETTER A WITH GRAVE
     65 |  000000C1 | LATIN CAPITAL LETTER A WITH ACUTE
     66 |  000000C3 | LATIN CAPITAL LETTER A WITH TILDE
     67 |  00000024 | DOLLAR SIGN
     68 |  000000C7 | LATIN CAPITAL LETTER C WITH CEDILLA
     69 |  000000D1 | LATIN CAPITAL LETTER N WITH TILDE
     6A |  000000F8 | LATIN SMALL LETTER O WITH STROKE
     6B |  0000002C | COMMA
     6C |  00000025 | PERCENT SIGN
     6D |  0000005F | LOW LINE
     6E |  0000003E | GREATER-THAN SIGN
     6F |  0000003F | QUESTION MARK
     70 |  000000A6 | BROKEN BAR
     71 |  000000C9 | LATIN CAPITAL LETTER E WITH ACUTE
     72 |  000000CA | LATIN CAPITAL LETTER E WITH CIRCUMFLEX
     73 |  000000CB | LATIN CAPITAL LETTER E WITH DIAERESIS
     74 |  000000C8 | LATIN CAPITAL LETTER E WITH GRAVE
     75 |  000000CD | LATIN CAPITAL LETTER I WITH ACUTE
     76 |  000000CE | LATIN CAPITAL LETTER I WITH CIRCUMFLEX
     77 |  000000CF | LATIN CAPITAL LETTER I WITH DIAERESIS
     78 |  000000CC | LATIN CAPITAL LETTER I WITH GRAVE
     79 |  00000060 | GRAVE ACCENT
     7A |  0000003A | COLON
     7B |  000000C6 | LATIN CAPITAL LETTER AE
     7C |  000000D8 | LATIN CAPITAL LETTER O WITH STROKE
     7D |  00000027 | APOSTROPHE
     7E |  0000003D | EQUALS SIGN
     7F |  00000022 | QUOTATION MARK
     80 |  00000040 | COMMERCIAL AT
     81 |  00000061 | LATIN SMALL LETTER A
     82 |  00000062 | LATIN SMALL LETTER B
     83 |  00000063 | LATIN SMALL LETTER C
     84 |  00000064 | LATIN SMALL LETTER D
     85 |  00000065 | LATIN SMALL LETTER E
     86 |  00000066 | LATIN SMALL LETTER F
     87 |  00000067 | LATIN SMALL LETTER G
     88 |  00000068 | LATIN SMALL LETTER H
     89 |  00000069 | LATIN SMALL LETTER I
     8A |  000000AB | LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
     8B |  000000BB | RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
     8C |  000000F0 | LATIN SMALL LETTER ETH (Icelandic)
     8D |  000000FD | LATIN SMALL LETTER Y WITH ACUTE
     8E |  000000FE | LATIN SMALL LETTER THORN (Icelandic)
     8F |  000000B1 | PLUS-MINUS SIGN
     90 |  000000B0 | DEGREE SIGN
     91 |  0000006A | LATIN SMALL LETTER J
     92 |  0000006B | LATIN SMALL LETTER K
     93 |  0000006C | LATIN SMALL LETTER L
     94 |  0000006D | LATIN SMALL LETTER M
     95 |  0000006E | LATIN SMALL LETTER N
     96 |  0000006F | LATIN SMALL LETTER O
     97 |  00000070 | LATIN SMALL LETTER P
     98 |  00000071 | LATIN SMALL LETTER Q
     99 |  00000072 | LATIN SMALL LETTER R
     9A |  000000AA | FEMININE ORDINAL INDICATOR
     9B |  000000BA | MASCULINE ORDINAL INDICATOR
     9C |  0000007B | LEFT CURLY BRACKET
     9D |  000000B8 | CEDILLA
     9E |  0000005B | LEFT SQUARE BRACKET
     9F |  0000005D | RIGHT SQUARE BRACKET
     A0 |  000000B5 | MICRO SIGN
     A1 |  000000FC | LATIN SMALL LETTER U WITH DIAERESIS
     A2 |  00000073 | LATIN SMALL LETTER S
     A3 |  00000074 | LATIN SMALL LETTER T
     A4 |  00000075 | LATIN SMALL LETTER U
     A5 |  00000076 | LATIN SMALL LETTER V
     A6 |  00000077 | LATIN SMALL LETTER W
     A7 |  00000078 | LATIN SMALL LETTER X
     A8 |  00000079 | LATIN SMALL LETTER Y
     A9 |  0000007A | LATIN SMALL LETTER Z
     AA |  000000A1 | INVERTED EXCLAMATION MARK
     AB |  000000BF | INVERTED QUESTION MARK
     AC |  000000D0 | LATIN CAPITAL LETTER ETH (Icelandic)
     AD |  000000DD | LATIN CAPITAL LETTER Y WITH ACUTE
     AE |  000000DE | LATIN CAPITAL LETTER THORN (Icelandic)
     AF |  000000AE | REGISTERED SIGN
     B0 |  000000A2 | CENT SIGN
     B1 |  000000A3 | POUND SIGN
     B2 |  000000A5 | YEN SIGN
     B3 |  000000B7 | MIDDLE DOT
     B4 |  000000A9 | COPYRIGHT SIGN
     B5 |  000000A7 | SECTION SIGN
     B6 |  000000B6 | PILCROW SIGN
     B7 |  000000BC | VULGAR FRACTION ONE QUARTER
     B8 |  000000BD | VULGAR FRACTION ONE HALF
     B9 |  000000BE | VULGAR FRACTION THREE QUARTERS
     BA |  000000AC | NOT SIGN
     BB |  0000007C | VERTICAL LINE
     BC |  0000203E | OVERLINE
     BD |  000000A8 | DIAERESIS
     BE |  000000B4 | ACUTE ACCENT
     BF |  000000D7 | MULTIPLICATION SIGN
     C0 |  000000E6 | LATIN SMALL LETTER AE
     C1 |  00000041 | LATIN CAPITAL LETTER A
     C2 |  00000042 | LATIN CAPITAL LETTER B
     C3 |  00000043 | LATIN CAPITAL LETTER C
     C4 |  00000044 | LATIN CAPITAL LETTER D
     C5 |  00000045 | LATIN CAPITAL LETTER E
     C6 |  00000046 | LATIN CAPITAL LETTER F
     C7 |  00000047 | LATIN CAPITAL LETTER G
     C8 |  00000048 | LATIN CAPITAL LETTER H
     C9 |  00000049 | LATIN CAPITAL LETTER I
     CA |  000000AD | SOFT HYPHEN
     CB |  000000F4 | LATIN SMALL LETTER O WITH CIRCUMFLEX
     CC |  000000F6 | LATIN SMALL LETTER O WITH DIAERESIS
     CD |  000000F2 | LATIN SMALL LETTER O WITH GRAVE
     CE |  000000F3 | LATIN SMALL LETTER O WITH ACUTE
     CF |  000000F5 | LATIN SMALL LETTER O WITH TILDE
     D0 |  000000E5 | LATIN SMALL LETTER A WITH RING ABOVE
     D1 |  0000004A | LATIN CAPITAL LETTER J
     D2 |  0000004B | LATIN CAPITAL LETTER K
     D3 |  0000004C | LATIN CAPITAL LETTER L
     D4 |  0000004D | LATIN CAPITAL LETTER M
     D5 |  0000004E | LATIN CAPITAL LETTER N
     D6 |  0000004F | LATIN CAPITAL LETTER O
     D7 |  00000050 | LATIN CAPITAL LETTER P
     D8 |  00000051 | LATIN CAPITAL LETTER Q
     D9 |  00000052 | LATIN CAPITAL LETTER R
     DA |  000000B9 | SUPERSCRIPT ONE
     DB |  000000FB | LATIN SMALL LETTER U WITH CIRCUMFLEX
     DC |  0000007E | TILDE
     DD |  000000F9 | LATIN SMALL LETTER U WITH GRAVE
     DE |  000000FA | LATIN SMALL LETTER U WITH ACUTE
     DF |  000000FF | LATIN SMALL LETTER Y WITH DIAERESIS
     E0 |  0000005C | REVERSE SOLIDUS
     E1 |  000000F7 | DIVISION SIGN
     E2 |  00000053 | LATIN CAPITAL LETTER S
     E3 |  00000054 | LATIN CAPITAL LETTER T
     E4 |  00000055 | LATIN CAPITAL LETTER U
     E5 |  00000056 | LATIN CAPITAL LETTER V
     E6 |  00000057 | LATIN CAPITAL LETTER W
     E7 |  00000058 | LATIN CAPITAL LETTER X
     E8 |  00000059 | LATIN CAPITAL LETTER Y
     E9 |  0000005A | LATIN CAPITAL LETTER Z
     EA |  000000B2 | SUPERSCRIPT TWO
     EB |  000000D4 | LATIN CAPITAL LETTER O WITH CIRCUMFLEX
     EC |  000000D6 | LATIN CAPITAL LETTER O WITH DIAERESIS
     ED |  000000D2 | LATIN CAPITAL LETTER O WITH GRAVE
     EE |  000000D3 | LATIN CAPITAL LETTER O WITH ACUTE
     EF |  000000D5 | LATIN CAPITAL LETTER O WITH TILDE
     F0 |  00000030 | DIGIT ZERO
     F1 |  00000031 | DIGIT ONE
     F2 |  00000032 | DIGIT TWO
     F3 |  00000033 | DIGIT THREE
     F4 |  00000034 | DIGIT FOUR
     F5 |  00000035 | DIGIT FIVE
     F6 |  00000036 | DIGIT SIX
     F7 |  00000037 | DIGIT SEVEN
     F8 |  00000038 | DIGIT EIGHT
     F9 |  00000039 | DIGIT NINE
     FA |  000000B3 | SUPERSCRIPT THREE
     FB |  000000DB | LATIN CAPITAL LETTER U WITH CIRCUMFLEX
     FC |  000000DC | LATIN CAPITAL LETTER U WITH DIAERESIS
     FD |  000000D9 | LATIN CAPITAL LETTER U WITH GRAVE
     FE |  000000DA | LATIN CAPITAL LETTER U WITH ACUTE
     FF |  0000009F | APPLICATION PROGRAM COMMAND (APC)
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/IBM278.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for IBM278.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::IBM278;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x009c,
     0x0009,
     0x0086,
     0x007f,
     0x0097,
     0x008d,
     0x008e,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x009d,
     0x0085,
     0x0008,
     0x0087,
     0x0018,
     0x0019,
     0x0092,
     0x008f,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0080,
     0x0081,
     0x0082,
     0x0083,
     0x0084,
     0x000a,
     0x0017,
     0x001b,
     0x0088,
     0x0089,
     0x008a,
     0x008b,
     0x008c,
     0x0005,
     0x0006,
     0x0007,
     0x0090,
     0x0091,
     0x0016,
     0x0093,
     0x0094,
     0x0095,
     0x0096,
     0x0004,
     0x0098,
     0x0099,
     0x009a,
     0x009b,
     0x0014,
     0x0015,
     0x009e,
     0x001a,
     0x0020,
     0x00a0,
     0x00e2,
     0x007b,
     0x00e0,
     0x00e1,
     0x00e3,
     0x007d,
     0x00e7,
     0x00f1,
     0x00a7,
     0x002e,
     0x003c,
     0x0028,
     0x002b,
     0x0021,
     0x0026,
     0x0060,
     0x00ea,
     0x00eb,
     0x00e8,
     0x00ed,
     0x00ee,
     0x00ef,
     0x00ec,
     0x00df,
     0x00a4,
     0x00c5,
     0x002a,
     0x0029,
     0x003b,
     0x005e,
     0x002d,
     0x002f,
     0x00c2,
     0x0023,
     0x00c0,
     0x00c1,
     0x00c3,
     0x0024,
     0x00c7,
     0x00d1,
     0x00f6,
     0x002c,
     0x0025,
     0x005f,
     0x003e,
     0x003f,
     0x00f8,
     0x00c9,
     0x00ca,
     0x00cb,
     0x00c8,
     0x00cd,
     0x00ce,
     0x00cf,
     0x00cc,
     0x00e9,
     0x003a,
     0x00c4,
     0x00d6,
     0x0027,
     0x003d,
     0x0022,
     0x00d8,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x00ab,
     0x00bb,
     0x00f0,
     0x00fd,
     0x00fe,
     0x00b1,
     0x00b0,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x00aa,
     0x00ba,
     0x00e6,
     0x00b8,
     0x00c6,
     0x005d,
     0x00b5,
     0x00fc,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x00a1,
     0x00bf,
     0x00d0,
     0x00dd,
     0x00de,
     0x00ae,
     0x00a2,
     0x00a3,
     0x00a5,
     0x00b7,
     0x00a9,
     0x005b,
     0x00b6,
     0x00bc,
     0x00bd,
     0x00be,
     0x00ac,
     0x007c,
     0x203e,
     0x00a8,
     0x00b4,
     0x00d7,
     0x00e4,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x00ad,
     0x00f4,
     0x00a6,
     0x00f2,
     0x00f3,
     0x00f5,
     0x00e5,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x00b9,
     0x00fb,
     0x007e,
     0x00f9,
     0x00fa,
     0x00ff,
     0x005c,
     0x00f7,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x00b2,
     0x00d4,
     0x0040,
     0x00d2,
     0x00d3,
     0x00d5,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x00b3,
     0x00db,
     0x00dc,
     0x00d9,
     0x00da,
     0x009f,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\xc2\x9c",
     "\x09",
     "\xc2\x86",
     "\x7f",
     "\xc2\x97",
     "\xc2\x8d",
     "\xc2\x8e",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\xc2\x9d",
     "\xc2\x85",
     "\x08",
     "\xc2\x87",
     "\x18",
     "\x19",
     "\xc2\x92",
     "\xc2\x8f",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\xc2\x80",
     "\xc2\x81",
     "\xc2\x82",
     "\xc2\x83",
     "\xc2\x84",
     "\x0a",
     "\x17",
     "\x1b",
     "\xc2\x88",
     "\xc2\x89",
     "\xc2\x8a",
     "\xc2\x8b",
     "\xc2\x8c",
     "\x05",
     "\x06",
     "\x07",
     "\xc2\x90",
     "\xc2\x91",
     "\x16",
     "\xc2\x93",
     "\xc2\x94",
     "\xc2\x95",
     "\xc2\x96",
     "\x04",
     "\xc2\x98",
     "\xc2\x99",
     "\xc2\x9a",
     "\xc2\x9b",
     "\x14",
     "\x15",
     "\xc2\x9e",
     "\x1a",
     "\x20",
     "\xc2\xa0",
     "\xc3\xa2",
     "\x7b",
     "\xc3\xa0",
     "\xc3\xa1",
     "\xc3\xa3",
     "\x7d",
     "\xc3\xa7",
     "\xc3\xb1",
     "\xc2\xa7",
     "\x2e",
     "\x3c",
     "\x28",
     "\x2b",
     "\x21",
     "\x26",
     "\x60",
     "\xc3\xaa",
     "\xc3\xab",
     "\xc3\xa8",
     "\xc3\xad",
     "\xc3\xae",
     "\xc3\xaf",
     "\xc3\xac",
     "\xc3\x9f",
     "\xc2\xa4",
     "\xc3\x85",
     "\x2a",
     "\x29",
     "\x3b",
     "\x5e",
     "\x2d",
     "\x2f",
     "\xc3\x82",
     "\x23",
     "\xc3\x80",
     "\xc3\x81",
     "\xc3\x83",
     "\x24",
     "\xc3\x87",
     "\xc3\x91",
     "\xc3\xb6",
     "\x2c",
     "\x25",
     "\x5f",
     "\x3e",
     "\x3f",
     "\xc3\xb8",
     "\xc3\x89",
     "\xc3\x8a",
     "\xc3\x8b",
     "\xc3\x88",
     "\xc3\x8d",
     "\xc3\x8e",
     "\xc3\x8f",
     "\xc3\x8c",
     "\xc3\xa9",
     "\x3a",
     "\xc3\x84",
     "\xc3\x96",
     "\x27",
     "\x3d",
     "\x22",
     "\xc3\x98",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\xc2\xab",
     "\xc2\xbb",
     "\xc3\xb0",
     "\xc3\xbd",
     "\xc3\xbe",
     "\xc2\xb1",
     "\xc2\xb0",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\xc2\xaa",
     "\xc2\xba",
     "\xc3\xa6",
     "\xc2\xb8",
     "\xc3\x86",
     "\x5d",
     "\xc2\xb5",
     "\xc3\xbc",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\xc2\xa1",
     "\xc2\xbf",
     "\xc3\x90",
     "\xc3\x9d",
     "\xc3\x9e",
     "\xc2\xae",
     "\xc2\xa2",
     "\xc2\xa3",
     "\xc2\xa5",
     "\xc2\xb7",
     "\xc2\xa9",
     "\x5b",
     "\xc2\xb6",
     "\xc2\xbc",
     "\xc2\xbd",
     "\xc2\xbe",
     "\xc2\xac",
     "\x7c",
     "\xe2\x80\xbe",
     "\xc2\xa8",
     "\xc2\xb4",
     "\xc3\x97",
     "\xc3\xa4",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\xc2\xad",
     "\xc3\xb4",
     "\xc2\xa6",
     "\xc3\xb2",
     "\xc3\xb3",
     "\xc3\xb5",
     "\xc3\xa5",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\xc2\xb9",
     "\xc3\xbb",
     "\x7e",
     "\xc3\xb9",
     "\xc3\xba",
     "\xc3\xbf",
     "\x5c",
     "\xc3\xb7",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\xc2\xb2",
     "\xc3\x94",
     "\x40",
     "\xc3\x92",
     "\xc3\x93",
     "\xc3\x95",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\xc2\xb3",
     "\xc3\x9b",
     "\xc3\x9c",
     "\xc3\x99",
     "\xc3\x9a",
     "\xc2\x9f",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x37",
     0x00000005 => "\x2d",
     0x00000006 => "\x2e",
     0x00000007 => "\x2f",
     0x00000008 => "\x16",
     0x00000009 => "\x05",
     0x0000000a => "\x25",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x3c",
     0x00000015 => "\x3d",
     0x00000016 => "\x32",
     0x00000017 => "\x26",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x3f",
     0x0000001b => "\x27",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x40",
     0x00000021 => "\x4f",
     0x00000022 => "\x7f",
     0x00000023 => "\x63",
     0x00000024 => "\x67",
     0x00000025 => "\x6c",
     0x00000026 => "\x50",
     0x00000027 => "\x7d",
     0x00000028 => "\x4d",
     0x00000029 => "\x5d",
     0x0000002a => "\x5c",
     0x0000002b => "\x4e",
     0x0000002c => "\x6b",
     0x0000002d => "\x60",
     0x0000002e => "\x4b",
     0x0000002f => "\x61",
     0x00000030 => "\xf0",
     0x00000031 => "\xf1",
     0x00000032 => "\xf2",
     0x00000033 => "\xf3",
     0x00000034 => "\xf4",
     0x00000035 => "\xf5",
     0x00000036 => "\xf6",
     0x00000037 => "\xf7",
     0x00000038 => "\xf8",
     0x00000039 => "\xf9",
     0x0000003a => "\x7a",
     0x0000003b => "\x5e",
     0x0000003c => "\x4c",
     0x0000003d => "\x7e",
     0x0000003e => "\x6e",
     0x0000003f => "\x6f",
     0x00000040 => "\xec",
     0x00000041 => "\xc1",
     0x00000042 => "\xc2",
     0x00000043 => "\xc3",
     0x00000044 => "\xc4",
     0x00000045 => "\xc5",
     0x00000046 => "\xc6",
     0x00000047 => "\xc7",
     0x00000048 => "\xc8",
     0x00000049 => "\xc9",
     0x0000004a => "\xd1",
     0x0000004b => "\xd2",
     0x0000004c => "\xd3",
     0x0000004d => "\xd4",
     0x0000004e => "\xd5",
     0x0000004f => "\xd6",
     0x00000050 => "\xd7",
     0x00000051 => "\xd8",
     0x00000052 => "\xd9",
     0x00000053 => "\xe2",
     0x00000054 => "\xe3",
     0x00000055 => "\xe4",
     0x00000056 => "\xe5",
     0x00000057 => "\xe6",
     0x00000058 => "\xe7",
     0x00000059 => "\xe8",
     0x0000005a => "\xe9",
     0x0000005b => "\xb5",
     0x0000005c => "\xe0",
     0x0000005d => "\x9f",
     0x0000005e => "\x5f",
     0x0000005f => "\x6d",
     0x00000060 => "\x51",
     0x00000061 => "\x81",
     0x00000062 => "\x82",
     0x00000063 => "\x83",
     0x00000064 => "\x84",
     0x00000065 => "\x85",
     0x00000066 => "\x86",
     0x00000067 => "\x87",
     0x00000068 => "\x88",
     0x00000069 => "\x89",
     0x0000006a => "\x91",
     0x0000006b => "\x92",
     0x0000006c => "\x93",
     0x0000006d => "\x94",
     0x0000006e => "\x95",
     0x0000006f => "\x96",
     0x00000070 => "\x97",
     0x00000071 => "\x98",
     0x00000072 => "\x99",
     0x00000073 => "\xa2",
     0x00000074 => "\xa3",
     0x00000075 => "\xa4",
     0x00000076 => "\xa5",
     0x00000077 => "\xa6",
     0x00000078 => "\xa7",
     0x00000079 => "\xa8",
     0x0000007a => "\xa9",
     0x0000007b => "\x43",
     0x0000007c => "\xbb",
     0x0000007d => "\x47",
     0x0000007e => "\xdc",
     0x0000007f => "\x07",
     0x00000080 => "\x20",
     0x00000081 => "\x21",
     0x00000082 => "\x22",
     0x00000083 => "\x23",
     0x00000084 => "\x24",
     0x00000085 => "\x15",
     0x00000086 => "\x06",
     0x00000087 => "\x17",
     0x00000088 => "\x28",
     0x00000089 => "\x29",
     0x0000008a => "\x2a",
     0x0000008b => "\x2b",
     0x0000008c => "\x2c",
     0x0000008d => "\x09",
     0x0000008e => "\x0a",
     0x0000008f => "\x1b",
     0x00000090 => "\x30",
     0x00000091 => "\x31",
     0x00000092 => "\x1a",
     0x00000093 => "\x33",
     0x00000094 => "\x34",
     0x00000095 => "\x35",
     0x00000096 => "\x36",
     0x00000097 => "\x08",
     0x00000098 => "\x38",
     0x00000099 => "\x39",
     0x0000009a => "\x3a",
     0x0000009b => "\x3b",
     0x0000009c => "\x04",
     0x0000009d => "\x14",
     0x0000009e => "\x3e",
     0x0000009f => "\xff",
     0x000000a0 => "\x41",
     0x000000a1 => "\xaa",
     0x000000a2 => "\xb0",
     0x000000a3 => "\xb1",
     0x000000a4 => "\x5a",
     0x000000a5 => "\xb2",
     0x000000a6 => "\xcc",
     0x000000a7 => "\x4a",
     0x000000a8 => "\xbd",
     0x000000a9 => "\xb4",
     0x000000aa => "\x9a",
     0x000000ab => "\x8a",
     0x000000ac => "\xba",
     0x000000ad => "\xca",
     0x000000ae => "\xaf",
     0x000000b0 => "\x90",
     0x000000b1 => "\x8f",
     0x000000b2 => "\xea",
     0x000000b3 => "\xfa",
     0x000000b4 => "\xbe",
     0x000000b5 => "\xa0",
     0x000000b6 => "\xb6",
     0x000000b7 => "\xb3",
     0x000000b8 => "\x9d",
     0x000000b9 => "\xda",
     0x000000ba => "\x9b",
     0x000000bb => "\x8b",
     0x000000bc => "\xb7",
     0x000000bd => "\xb8",
     0x000000be => "\xb9",
     0x000000bf => "\xab",
     0x000000c0 => "\x64",
     0x000000c1 => "\x65",
     0x000000c2 => "\x62",
     0x000000c3 => "\x66",
     0x000000c4 => "\x7b",
     0x000000c5 => "\x5b",
     0x000000c6 => "\x9e",
     0x000000c7 => "\x68",
     0x000000c8 => "\x74",
     0x000000c9 => "\x71",
     0x000000ca => "\x72",
     0x000000cb => "\x73",
     0x000000cc => "\x78",
     0x000000cd => "\x75",
     0x000000ce => "\x76",
     0x000000cf => "\x77",
     0x000000d0 => "\xac",
     0x000000d1 => "\x69",
     0x000000d2 => "\xed",
     0x000000d3 => "\xee",
     0x000000d4 => "\xeb",
     0x000000d5 => "\xef",
     0x000000d6 => "\x7c",
     0x000000d7 => "\xbf",
     0x000000d8 => "\x80",
     0x000000d9 => "\xfd",
     0x000000da => "\xfe",
     0x000000db => "\xfb",
     0x000000dc => "\xfc",
     0x000000dd => "\xad",
     0x000000de => "\xae",
     0x000000df => "\x59",
     0x000000e0 => "\x44",
     0x000000e1 => "\x45",
     0x000000e2 => "\x42",
     0x000000e3 => "\x46",
     0x000000e4 => "\xc0",
     0x000000e5 => "\xd0",
     0x000000e6 => "\x9c",
     0x000000e7 => "\x48",
     0x000000e8 => "\x54",
     0x000000e9 => "\x79",
     0x000000ea => "\x52",
     0x000000eb => "\x53",
     0x000000ec => "\x58",
     0x000000ed => "\x55",
     0x000000ee => "\x56",
     0x000000ef => "\x57",
     0x000000f0 => "\x8c",
     0x000000f1 => "\x49",
     0x000000f2 => "\xcd",
     0x000000f3 => "\xce",
     0x000000f4 => "\xcb",
     0x000000f5 => "\xcf",
     0x000000f6 => "\x6a",
     0x000000f7 => "\xe1",
     0x000000f8 => "\x70",
     0x000000f9 => "\xdd",
     0x000000fa => "\xde",
     0x000000fb => "\xdb",
     0x000000fc => "\xa1",
     0x000000fd => "\x8d",
     0x000000fe => "\x8e",
     0x000000ff => "\xdf",
     0x0000203e => "\xbc",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x6f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::IBM278 - Conversion routines for IBM278
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for IBM278.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
   source: IBM NLS RM Vol2 SE09-8002-01, March 1990
  alias CP278
  alias EBCDIC-CP-FI
  alias EBCDIC-CP-SE
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  0000009C | STRING TERMINATOR (ST)
     05 |  00000009 | CHARACTER TABULATION (HT)
     06 |  00000086 | START OF SELECTED AREA (SSA)
     07 |  0000007F | DELETE (DEL)
     08 |  00000097 | END OF GUARDED AREA (EPA)
     09 |  0000008D | REVERSE LINE FEED (RI)
     0A |  0000008E | SINGLE-SHIFT TWO (SS2)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  0000009D | OPERATING SYSTEM COMMAND (OSC)
     15 |  00000085 | NEXT LINE (NEL)
     16 |  00000008 | BACKSPACE (BS)
     17 |  00000087 | END OF SELECTED AREA (ESA)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  00000092 | PRIVATE USE TWO (PU2)
     1B |  0000008F | SINGLE-SHIFT THREE (SS3)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000080 | PADDING CHARACTER (PAD)
     21 |  00000081 | HIGH OCTET PRESET (HOP)
     22 |  00000082 | BREAK PERMITTED HERE (BPH)
     23 |  00000083 | NO BREAK HERE (NBH)
     24 |  00000084 | INDEX (IND)
     25 |  0000000A | LINE FEED (LF)
     26 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     27 |  0000001B | ESCAPE (ESC)
     28 |  00000088 | CHARACTER TABULATION SET (HTS)
     29 |  00000089 | CHARACTER TABULATION WITH JUSTIFICATION (HTJ)
     2A |  0000008A | LINE TABULATION SET (VTS)
     2B |  0000008B | PARTIAL LINE FORWARD (PLD)
     2C |  0000008C | PARTIAL LINE BACKWARD (PLU)
     2D |  00000005 | ENQUIRY (ENQ)
     2E |  00000006 | ACKNOWLEDGE (ACK)
     2F |  00000007 | BELL (BEL)
     30 |  00000090 | DEVICE CONTROL STRING (DCS)
     31 |  00000091 | PRIVATE USE ONE (PU1)
     32 |  00000016 | SYNCHRONOUS IDLE (SYN)
     33 |  00000093 | SET TRANSMIT STATE (STS)
     34 |  00000094 | CANCEL CHARACTER (CCH)
     35 |  00000095 | MESSAGE WAITING (MW)
     36 |  00000096 | START OF GUARDED AREA (SPA)
     37 |  00000004 | END OF TRANSMISSION (EOT)
     38 |  00000098 | START OF STRING (SOS)
     39 |  00000099 | SINGLE GRAPHIC CHARACTER INTRODUCER (SGCI)
     3A |  0000009A | SINGLE CHARACTER INTRODUCER (SCI)
     3B |  0000009B | CONTROL SEQUENCE INTRODUCER (CSI)
     3C |  00000014 | DEVICE CONTROL FOUR (DC4)
     3D |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     3E |  0000009E | PRIVACY MESSAGE (PM)
     3F |  0000001A | SUBSTITUTE (SUB)
     40 |  00000020 | SPACE
     41 |  000000A0 | NO-BREAK SPACE
     42 |  000000E2 | LATIN SMALL LETTER A WITH CIRCUMFLEX
     43 |  0000007B | LEFT CURLY BRACKET
     44 |  000000E0 | LATIN SMALL LETTER A WITH GRAVE
     45 |  000000E1 | LATIN SMALL LETTER A WITH ACUTE
     46 |  000000E3 | LATIN SMALL LETTER A WITH TILDE
     47 |  0000007D | RIGHT CURLY BRACKET
     48 |  000000E7 | LATIN SMALL LETTER C WITH CEDILLA
     49 |  000000F1 | LATIN SMALL LETTER N WITH TILDE
     4A |  000000A7 | SECTION SIGN
     4B |  0000002E | FULL STOP
     4C |  0000003C | LESS-THAN SIGN
     4D |  00000028 | LEFT PARENTHESIS
     4E |  0000002B | PLUS SIGN
     4F |  00000021 | EXCLAMATION MARK
     50 |  00000026 | AMPERSAND
     51 |  00000060 | GRAVE ACCENT
     52 |  000000EA | LATIN SMALL LETTER E WITH CIRCUMFLEX
     53 |  000000EB | LATIN SMALL LETTER E WITH DIAERESIS
     54 |  000000E8 | LATIN SMALL LETTER E WITH GRAVE
     55 |  000000ED | LATIN SMALL LETTER I WITH ACUTE
     56 |  000000EE | LATIN SMALL LETTER I WITH CIRCUMFLEX
     57 |  000000EF | LATIN SMALL LETTER I WITH DIAERESIS
     58 |  000000EC | LATIN SMALL LETTER I WITH GRAVE
     59 |  000000DF | LATIN SMALL LETTER SHARP S (German)
     5A |  000000A4 | CURRENCY SIGN
     5B |  000000C5 | LATIN CAPITAL LETTER A WITH RING ABOVE
     5C |  0000002A | ASTERISK
     5D |  00000029 | RIGHT PARENTHESIS
     5E |  0000003B | SEMICOLON
     5F |  0000005E | CIRCUMFLEX ACCENT
     60 |  0000002D | HYPHEN-MINUS
     61 |  0000002F | SOLIDUS
     62 |  000000C2 | LATIN CAPITAL LETTER A WITH CIRCUMFLEX
     63 |  00000023 | NUMBER SIGN
     64 |  000000C0 | LATIN CAPITAL LETTER A WITH GRAVE
     65 |  000000C1 | LATIN CAPITAL LETTER A WITH ACUTE
     66 |  000000C3 | LATIN CAPITAL LETTER A WITH TILDE
     67 |  00000024 | DOLLAR SIGN
     68 |  000000C7 | LATIN CAPITAL LETTER C WITH CEDILLA
     69 |  000000D1 | LATIN CAPITAL LETTER N WITH TILDE
     6A |  000000F6 | LATIN SMALL LETTER O WITH DIAERESIS
     6B |  0000002C | COMMA
     6C |  00000025 | PERCENT SIGN
     6D |  0000005F | LOW LINE
     6E |  0000003E | GREATER-THAN SIGN
     6F |  0000003F | QUESTION MARK
     70 |  000000F8 | LATIN SMALL LETTER O WITH STROKE
     71 |  000000C9 | LATIN CAPITAL LETTER E WITH ACUTE
     72 |  000000CA | LATIN CAPITAL LETTER E WITH CIRCUMFLEX
     73 |  000000CB | LATIN CAPITAL LETTER E WITH DIAERESIS
     74 |  000000C8 | LATIN CAPITAL LETTER E WITH GRAVE
     75 |  000000CD | LATIN CAPITAL LETTER I WITH ACUTE
     76 |  000000CE | LATIN CAPITAL LETTER I WITH CIRCUMFLEX
     77 |  000000CF | LATIN CAPITAL LETTER I WITH DIAERESIS
     78 |  000000CC | LATIN CAPITAL LETTER I WITH GRAVE
     79 |  000000E9 | LATIN SMALL LETTER E WITH ACUTE
     7A |  0000003A | COLON
     7B |  000000C4 | LATIN CAPITAL LETTER A WITH DIAERESIS
     7C |  000000D6 | LATIN CAPITAL LETTER O WITH DIAERESIS
     7D |  00000027 | APOSTROPHE
     7E |  0000003D | EQUALS SIGN
     7F |  00000022 | QUOTATION MARK
     80 |  000000D8 | LATIN CAPITAL LETTER O WITH STROKE
     81 |  00000061 | LATIN SMALL LETTER A
     82 |  00000062 | LATIN SMALL LETTER B
     83 |  00000063 | LATIN SMALL LETTER C
     84 |  00000064 | LATIN SMALL LETTER D
     85 |  00000065 | LATIN SMALL LETTER E
     86 |  00000066 | LATIN SMALL LETTER F
     87 |  00000067 | LATIN SMALL LETTER G
     88 |  00000068 | LATIN SMALL LETTER H
     89 |  00000069 | LATIN SMALL LETTER I
     8A |  000000AB | LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
     8B |  000000BB | RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
     8C |  000000F0 | LATIN SMALL LETTER ETH (Icelandic)
     8D |  000000FD | LATIN SMALL LETTER Y WITH ACUTE
     8E |  000000FE | LATIN SMALL LETTER THORN (Icelandic)
     8F |  000000B1 | PLUS-MINUS SIGN
     90 |  000000B0 | DEGREE SIGN
     91 |  0000006A | LATIN SMALL LETTER J
     92 |  0000006B | LATIN SMALL LETTER K
     93 |  0000006C | LATIN SMALL LETTER L
     94 |  0000006D | LATIN SMALL LETTER M
     95 |  0000006E | LATIN SMALL LETTER N
     96 |  0000006F | LATIN SMALL LETTER O
     97 |  00000070 | LATIN SMALL LETTER P
     98 |  00000071 | LATIN SMALL LETTER Q
     99 |  00000072 | LATIN SMALL LETTER R
     9A |  000000AA | FEMININE ORDINAL INDICATOR
     9B |  000000BA | MASCULINE ORDINAL INDICATOR
     9C |  000000E6 | LATIN SMALL LETTER AE
     9D |  000000B8 | CEDILLA
     9E |  000000C6 | LATIN CAPITAL LETTER AE
     9F |  0000005D | RIGHT SQUARE BRACKET
     A0 |  000000B5 | MICRO SIGN
     A1 |  000000FC | LATIN SMALL LETTER U WITH DIAERESIS
     A2 |  00000073 | LATIN SMALL LETTER S
     A3 |  00000074 | LATIN SMALL LETTER T
     A4 |  00000075 | LATIN SMALL LETTER U
     A5 |  00000076 | LATIN SMALL LETTER V
     A6 |  00000077 | LATIN SMALL LETTER W
     A7 |  00000078 | LATIN SMALL LETTER X
     A8 |  00000079 | LATIN SMALL LETTER Y
     A9 |  0000007A | LATIN SMALL LETTER Z
     AA |  000000A1 | INVERTED EXCLAMATION MARK
     AB |  000000BF | INVERTED QUESTION MARK
     AC |  000000D0 | LATIN CAPITAL LETTER ETH (Icelandic)
     AD |  000000DD | LATIN CAPITAL LETTER Y WITH ACUTE
     AE |  000000DE | LATIN CAPITAL LETTER THORN (Icelandic)
     AF |  000000AE | REGISTERED SIGN
     B0 |  000000A2 | CENT SIGN
     B1 |  000000A3 | POUND SIGN
     B2 |  000000A5 | YEN SIGN
     B3 |  000000B7 | MIDDLE DOT
     B4 |  000000A9 | COPYRIGHT SIGN
     B5 |  0000005B | LEFT SQUARE BRACKET
     B6 |  000000B6 | PILCROW SIGN
     B7 |  000000BC | VULGAR FRACTION ONE QUARTER
     B8 |  000000BD | VULGAR FRACTION ONE HALF
     B9 |  000000BE | VULGAR FRACTION THREE QUARTERS
     BA |  000000AC | NOT SIGN
     BB |  0000007C | VERTICAL LINE
     BC |  0000203E | OVERLINE
     BD |  000000A8 | DIAERESIS
     BE |  000000B4 | ACUTE ACCENT
     BF |  000000D7 | MULTIPLICATION SIGN
     C0 |  000000E4 | LATIN SMALL LETTER A WITH DIAERESIS
     C1 |  00000041 | LATIN CAPITAL LETTER A
     C2 |  00000042 | LATIN CAPITAL LETTER B
     C3 |  00000043 | LATIN CAPITAL LETTER C
     C4 |  00000044 | LATIN CAPITAL LETTER D
     C5 |  00000045 | LATIN CAPITAL LETTER E
     C6 |  00000046 | LATIN CAPITAL LETTER F
     C7 |  00000047 | LATIN CAPITAL LETTER G
     C8 |  00000048 | LATIN CAPITAL LETTER H
     C9 |  00000049 | LATIN CAPITAL LETTER I
     CA |  000000AD | SOFT HYPHEN
     CB |  000000F4 | LATIN SMALL LETTER O WITH CIRCUMFLEX
     CC |  000000A6 | BROKEN BAR
     CD |  000000F2 | LATIN SMALL LETTER O WITH GRAVE
     CE |  000000F3 | LATIN SMALL LETTER O WITH ACUTE
     CF |  000000F5 | LATIN SMALL LETTER O WITH TILDE
     D0 |  000000E5 | LATIN SMALL LETTER A WITH RING ABOVE
     D1 |  0000004A | LATIN CAPITAL LETTER J
     D2 |  0000004B | LATIN CAPITAL LETTER K
     D3 |  0000004C | LATIN CAPITAL LETTER L
     D4 |  0000004D | LATIN CAPITAL LETTER M
     D5 |  0000004E | LATIN CAPITAL LETTER N
     D6 |  0000004F | LATIN CAPITAL LETTER O
     D7 |  00000050 | LATIN CAPITAL LETTER P
     D8 |  00000051 | LATIN CAPITAL LETTER Q
     D9 |  00000052 | LATIN CAPITAL LETTER R
     DA |  000000B9 | SUPERSCRIPT ONE
     DB |  000000FB | LATIN SMALL LETTER U WITH CIRCUMFLEX
     DC |  0000007E | TILDE
     DD |  000000F9 | LATIN SMALL LETTER U WITH GRAVE
     DE |  000000FA | LATIN SMALL LETTER U WITH ACUTE
     DF |  000000FF | LATIN SMALL LETTER Y WITH DIAERESIS
     E0 |  0000005C | REVERSE SOLIDUS
     E1 |  000000F7 | DIVISION SIGN
     E2 |  00000053 | LATIN CAPITAL LETTER S
     E3 |  00000054 | LATIN CAPITAL LETTER T
     E4 |  00000055 | LATIN CAPITAL LETTER U
     E5 |  00000056 | LATIN CAPITAL LETTER V
     E6 |  00000057 | LATIN CAPITAL LETTER W
     E7 |  00000058 | LATIN CAPITAL LETTER X
     E8 |  00000059 | LATIN CAPITAL LETTER Y
     E9 |  0000005A | LATIN CAPITAL LETTER Z
     EA |  000000B2 | SUPERSCRIPT TWO
     EB |  000000D4 | LATIN CAPITAL LETTER O WITH CIRCUMFLEX
     EC |  00000040 | COMMERCIAL AT
     ED |  000000D2 | LATIN CAPITAL LETTER O WITH GRAVE
     EE |  000000D3 | LATIN CAPITAL LETTER O WITH ACUTE
     EF |  000000D5 | LATIN CAPITAL LETTER O WITH TILDE
     F0 |  00000030 | DIGIT ZERO
     F1 |  00000031 | DIGIT ONE
     F2 |  00000032 | DIGIT TWO
     F3 |  00000033 | DIGIT THREE
     F4 |  00000034 | DIGIT FOUR
     F5 |  00000035 | DIGIT FIVE
     F6 |  00000036 | DIGIT SIX
     F7 |  00000037 | DIGIT SEVEN
     F8 |  00000038 | DIGIT EIGHT
     F9 |  00000039 | DIGIT NINE
     FA |  000000B3 | SUPERSCRIPT THREE
     FB |  000000DB | LATIN CAPITAL LETTER U WITH CIRCUMFLEX
     FC |  000000DC | LATIN CAPITAL LETTER U WITH DIAERESIS
     FD |  000000D9 | LATIN CAPITAL LETTER U WITH GRAVE
     FE |  000000DA | LATIN CAPITAL LETTER U WITH ACUTE
     FF |  0000009F | APPLICATION PROGRAM COMMAND (APC)
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/IBM280.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for IBM280.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::IBM280;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x009c,
     0x0009,
     0x0086,
     0x007f,
     0x0097,
     0x008d,
     0x008e,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x009d,
     0x0085,
     0x0008,
     0x0087,
     0x0018,
     0x0019,
     0x0092,
     0x008f,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0080,
     0x0081,
     0x0082,
     0x0083,
     0x0084,
     0x000a,
     0x0017,
     0x001b,
     0x0088,
     0x0089,
     0x008a,
     0x008b,
     0x008c,
     0x0005,
     0x0006,
     0x0007,
     0x0090,
     0x0091,
     0x0016,
     0x0093,
     0x0094,
     0x0095,
     0x0096,
     0x0004,
     0x0098,
     0x0099,
     0x009a,
     0x009b,
     0x0014,
     0x0015,
     0x009e,
     0x001a,
     0x0020,
     0x00a0,
     0x00e2,
     0x00e4,
     0x007b,
     0x00e1,
     0x00e3,
     0x00e5,
     0x005c,
     0x00f1,
     0x00b0,
     0x002e,
     0x003c,
     0x0028,
     0x002b,
     0x0021,
     0x0026,
     0x005d,
     0x00ea,
     0x00eb,
     0x007d,
     0x00ed,
     0x00ee,
     0x00ef,
     0x007e,
     0x00df,
     0x00e9,
     0x0024,
     0x002a,
     0x0029,
     0x003b,
     0x005e,
     0x002d,
     0x002f,
     0x00c2,
     0x00c4,
     0x00c0,
     0x00c1,
     0x00c3,
     0x00c5,
     0x00c7,
     0x00d1,
     0x00f2,
     0x002c,
     0x0025,
     0x005f,
     0x003e,
     0x003f,
     0x00f8,
     0x00c9,
     0x00ca,
     0x00cb,
     0x00c8,
     0x00cd,
     0x00ce,
     0x00cf,
     0x00cc,
     0x00f9,
     0x003a,
     0x00a3,
     0x00a7,
     0x0027,
     0x003d,
     0x0022,
     0x00d8,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x00ab,
     0x00bb,
     0x00f0,
     0x00fd,
     0x00fe,
     0x00b1,
     0x005b,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x00aa,
     0x00ba,
     0x00e6,
     0x00b8,
     0x00c6,
     0x00a4,
     0x00b5,
     0x00ec,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x00a1,
     0x00bf,
     0x00d0,
     0x00dd,
     0x00de,
     0x00ae,
     0x00a2,
     0x0023,
     0x00a5,
     0x00b7,
     0x00a9,
     0x0040,
     0x00b6,
     0x00bc,
     0x00bd,
     0x00be,
     0x00ac,
     0x007c,
     0x203e,
     0x00a8,
     0x00b4,
     0x00d7,
     0x00e0,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x00ad,
     0x00f4,
     0x00f6,
     0x00a6,
     0x00f3,
     0x00f5,
     0x00e8,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x00b9,
     0x00fb,
     0x00fc,
     0x0060,
     0x00fa,
     0x00ff,
     0x00e7,
     0x00f7,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x00b2,
     0x00d4,
     0x00d6,
     0x00d2,
     0x00d3,
     0x00d5,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x00b3,
     0x00db,
     0x00dc,
     0x00d9,
     0x00da,
     0x009f,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\xc2\x9c",
     "\x09",
     "\xc2\x86",
     "\x7f",
     "\xc2\x97",
     "\xc2\x8d",
     "\xc2\x8e",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\xc2\x9d",
     "\xc2\x85",
     "\x08",
     "\xc2\x87",
     "\x18",
     "\x19",
     "\xc2\x92",
     "\xc2\x8f",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\xc2\x80",
     "\xc2\x81",
     "\xc2\x82",
     "\xc2\x83",
     "\xc2\x84",
     "\x0a",
     "\x17",
     "\x1b",
     "\xc2\x88",
     "\xc2\x89",
     "\xc2\x8a",
     "\xc2\x8b",
     "\xc2\x8c",
     "\x05",
     "\x06",
     "\x07",
     "\xc2\x90",
     "\xc2\x91",
     "\x16",
     "\xc2\x93",
     "\xc2\x94",
     "\xc2\x95",
     "\xc2\x96",
     "\x04",
     "\xc2\x98",
     "\xc2\x99",
     "\xc2\x9a",
     "\xc2\x9b",
     "\x14",
     "\x15",
     "\xc2\x9e",
     "\x1a",
     "\x20",
     "\xc2\xa0",
     "\xc3\xa2",
     "\xc3\xa4",
     "\x7b",
     "\xc3\xa1",
     "\xc3\xa3",
     "\xc3\xa5",
     "\x5c",
     "\xc3\xb1",
     "\xc2\xb0",
     "\x2e",
     "\x3c",
     "\x28",
     "\x2b",
     "\x21",
     "\x26",
     "\x5d",
     "\xc3\xaa",
     "\xc3\xab",
     "\x7d",
     "\xc3\xad",
     "\xc3\xae",
     "\xc3\xaf",
     "\x7e",
     "\xc3\x9f",
     "\xc3\xa9",
     "\x24",
     "\x2a",
     "\x29",
     "\x3b",
     "\x5e",
     "\x2d",
     "\x2f",
     "\xc3\x82",
     "\xc3\x84",
     "\xc3\x80",
     "\xc3\x81",
     "\xc3\x83",
     "\xc3\x85",
     "\xc3\x87",
     "\xc3\x91",
     "\xc3\xb2",
     "\x2c",
     "\x25",
     "\x5f",
     "\x3e",
     "\x3f",
     "\xc3\xb8",
     "\xc3\x89",
     "\xc3\x8a",
     "\xc3\x8b",
     "\xc3\x88",
     "\xc3\x8d",
     "\xc3\x8e",
     "\xc3\x8f",
     "\xc3\x8c",
     "\xc3\xb9",
     "\x3a",
     "\xc2\xa3",
     "\xc2\xa7",
     "\x27",
     "\x3d",
     "\x22",
     "\xc3\x98",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\xc2\xab",
     "\xc2\xbb",
     "\xc3\xb0",
     "\xc3\xbd",
     "\xc3\xbe",
     "\xc2\xb1",
     "\x5b",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\xc2\xaa",
     "\xc2\xba",
     "\xc3\xa6",
     "\xc2\xb8",
     "\xc3\x86",
     "\xc2\xa4",
     "\xc2\xb5",
     "\xc3\xac",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\xc2\xa1",
     "\xc2\xbf",
     "\xc3\x90",
     "\xc3\x9d",
     "\xc3\x9e",
     "\xc2\xae",
     "\xc2\xa2",
     "\x23",
     "\xc2\xa5",
     "\xc2\xb7",
     "\xc2\xa9",
     "\x40",
     "\xc2\xb6",
     "\xc2\xbc",
     "\xc2\xbd",
     "\xc2\xbe",
     "\xc2\xac",
     "\x7c",
     "\xe2\x80\xbe",
     "\xc2\xa8",
     "\xc2\xb4",
     "\xc3\x97",
     "\xc3\xa0",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\xc2\xad",
     "\xc3\xb4",
     "\xc3\xb6",
     "\xc2\xa6",
     "\xc3\xb3",
     "\xc3\xb5",
     "\xc3\xa8",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\xc2\xb9",
     "\xc3\xbb",
     "\xc3\xbc",
     "\x60",
     "\xc3\xba",
     "\xc3\xbf",
     "\xc3\xa7",
     "\xc3\xb7",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\xc2\xb2",
     "\xc3\x94",
     "\xc3\x96",
     "\xc3\x92",
     "\xc3\x93",
     "\xc3\x95",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\xc2\xb3",
     "\xc3\x9b",
     "\xc3\x9c",
     "\xc3\x99",
     "\xc3\x9a",
     "\xc2\x9f",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x37",
     0x00000005 => "\x2d",
     0x00000006 => "\x2e",
     0x00000007 => "\x2f",
     0x00000008 => "\x16",
     0x00000009 => "\x05",
     0x0000000a => "\x25",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x3c",
     0x00000015 => "\x3d",
     0x00000016 => "\x32",
     0x00000017 => "\x26",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x3f",
     0x0000001b => "\x27",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x40",
     0x00000021 => "\x4f",
     0x00000022 => "\x7f",
     0x00000023 => "\xb1",
     0x00000024 => "\x5b",
     0x00000025 => "\x6c",
     0x00000026 => "\x50",
     0x00000027 => "\x7d",
     0x00000028 => "\x4d",
     0x00000029 => "\x5d",
     0x0000002a => "\x5c",
     0x0000002b => "\x4e",
     0x0000002c => "\x6b",
     0x0000002d => "\x60",
     0x0000002e => "\x4b",
     0x0000002f => "\x61",
     0x00000030 => "\xf0",
     0x00000031 => "\xf1",
     0x00000032 => "\xf2",
     0x00000033 => "\xf3",
     0x00000034 => "\xf4",
     0x00000035 => "\xf5",
     0x00000036 => "\xf6",
     0x00000037 => "\xf7",
     0x00000038 => "\xf8",
     0x00000039 => "\xf9",
     0x0000003a => "\x7a",
     0x0000003b => "\x5e",
     0x0000003c => "\x4c",
     0x0000003d => "\x7e",
     0x0000003e => "\x6e",
     0x0000003f => "\x6f",
     0x00000040 => "\xb5",
     0x00000041 => "\xc1",
     0x00000042 => "\xc2",
     0x00000043 => "\xc3",
     0x00000044 => "\xc4",
     0x00000045 => "\xc5",
     0x00000046 => "\xc6",
     0x00000047 => "\xc7",
     0x00000048 => "\xc8",
     0x00000049 => "\xc9",
     0x0000004a => "\xd1",
     0x0000004b => "\xd2",
     0x0000004c => "\xd3",
     0x0000004d => "\xd4",
     0x0000004e => "\xd5",
     0x0000004f => "\xd6",
     0x00000050 => "\xd7",
     0x00000051 => "\xd8",
     0x00000052 => "\xd9",
     0x00000053 => "\xe2",
     0x00000054 => "\xe3",
     0x00000055 => "\xe4",
     0x00000056 => "\xe5",
     0x00000057 => "\xe6",
     0x00000058 => "\xe7",
     0x00000059 => "\xe8",
     0x0000005a => "\xe9",
     0x0000005b => "\x90",
     0x0000005c => "\x48",
     0x0000005d => "\x51",
     0x0000005e => "\x5f",
     0x0000005f => "\x6d",
     0x00000060 => "\xdd",
     0x00000061 => "\x81",
     0x00000062 => "\x82",
     0x00000063 => "\x83",
     0x00000064 => "\x84",
     0x00000065 => "\x85",
     0x00000066 => "\x86",
     0x00000067 => "\x87",
     0x00000068 => "\x88",
     0x00000069 => "\x89",
     0x0000006a => "\x91",
     0x0000006b => "\x92",
     0x0000006c => "\x93",
     0x0000006d => "\x94",
     0x0000006e => "\x95",
     0x0000006f => "\x96",
     0x00000070 => "\x97",
     0x00000071 => "\x98",
     0x00000072 => "\x99",
     0x00000073 => "\xa2",
     0x00000074 => "\xa3",
     0x00000075 => "\xa4",
     0x00000076 => "\xa5",
     0x00000077 => "\xa6",
     0x00000078 => "\xa7",
     0x00000079 => "\xa8",
     0x0000007a => "\xa9",
     0x0000007b => "\x44",
     0x0000007c => "\xbb",
     0x0000007d => "\x54",
     0x0000007e => "\x58",
     0x0000007f => "\x07",
     0x00000080 => "\x20",
     0x00000081 => "\x21",
     0x00000082 => "\x22",
     0x00000083 => "\x23",
     0x00000084 => "\x24",
     0x00000085 => "\x15",
     0x00000086 => "\x06",
     0x00000087 => "\x17",
     0x00000088 => "\x28",
     0x00000089 => "\x29",
     0x0000008a => "\x2a",
     0x0000008b => "\x2b",
     0x0000008c => "\x2c",
     0x0000008d => "\x09",
     0x0000008e => "\x0a",
     0x0000008f => "\x1b",
     0x00000090 => "\x30",
     0x00000091 => "\x31",
     0x00000092 => "\x1a",
     0x00000093 => "\x33",
     0x00000094 => "\x34",
     0x00000095 => "\x35",
     0x00000096 => "\x36",
     0x00000097 => "\x08",
     0x00000098 => "\x38",
     0x00000099 => "\x39",
     0x0000009a => "\x3a",
     0x0000009b => "\x3b",
     0x0000009c => "\x04",
     0x0000009d => "\x14",
     0x0000009e => "\x3e",
     0x0000009f => "\xff",
     0x000000a0 => "\x41",
     0x000000a1 => "\xaa",
     0x000000a2 => "\xb0",
     0x000000a3 => "\x7b",
     0x000000a4 => "\x9f",
     0x000000a5 => "\xb2",
     0x000000a6 => "\xcd",
     0x000000a7 => "\x7c",
     0x000000a8 => "\xbd",
     0x000000a9 => "\xb4",
     0x000000aa => "\x9a",
     0x000000ab => "\x8a",
     0x000000ac => "\xba",
     0x000000ad => "\xca",
     0x000000ae => "\xaf",
     0x000000b0 => "\x4a",
     0x000000b1 => "\x8f",
     0x000000b2 => "\xea",
     0x000000b3 => "\xfa",
     0x000000b4 => "\xbe",
     0x000000b5 => "\xa0",
     0x000000b6 => "\xb6",
     0x000000b7 => "\xb3",
     0x000000b8 => "\x9d",
     0x000000b9 => "\xda",
     0x000000ba => "\x9b",
     0x000000bb => "\x8b",
     0x000000bc => "\xb7",
     0x000000bd => "\xb8",
     0x000000be => "\xb9",
     0x000000bf => "\xab",
     0x000000c0 => "\x64",
     0x000000c1 => "\x65",
     0x000000c2 => "\x62",
     0x000000c3 => "\x66",
     0x000000c4 => "\x63",
     0x000000c5 => "\x67",
     0x000000c6 => "\x9e",
     0x000000c7 => "\x68",
     0x000000c8 => "\x74",
     0x000000c9 => "\x71",
     0x000000ca => "\x72",
     0x000000cb => "\x73",
     0x000000cc => "\x78",
     0x000000cd => "\x75",
     0x000000ce => "\x76",
     0x000000cf => "\x77",
     0x000000d0 => "\xac",
     0x000000d1 => "\x69",
     0x000000d2 => "\xed",
     0x000000d3 => "\xee",
     0x000000d4 => "\xeb",
     0x000000d5 => "\xef",
     0x000000d6 => "\xec",
     0x000000d7 => "\xbf",
     0x000000d8 => "\x80",
     0x000000d9 => "\xfd",
     0x000000da => "\xfe",
     0x000000db => "\xfb",
     0x000000dc => "\xfc",
     0x000000dd => "\xad",
     0x000000de => "\xae",
     0x000000df => "\x59",
     0x000000e0 => "\xc0",
     0x000000e1 => "\x45",
     0x000000e2 => "\x42",
     0x000000e3 => "\x46",
     0x000000e4 => "\x43",
     0x000000e5 => "\x47",
     0x000000e6 => "\x9c",
     0x000000e7 => "\xe0",
     0x000000e8 => "\xd0",
     0x000000e9 => "\x5a",
     0x000000ea => "\x52",
     0x000000eb => "\x53",
     0x000000ec => "\xa1",
     0x000000ed => "\x55",
     0x000000ee => "\x56",
     0x000000ef => "\x57",
     0x000000f0 => "\x8c",
     0x000000f1 => "\x49",
     0x000000f2 => "\x6a",
     0x000000f3 => "\xce",
     0x000000f4 => "\xcb",
     0x000000f5 => "\xcf",
     0x000000f6 => "\xcc",
     0x000000f7 => "\xe1",
     0x000000f8 => "\x70",
     0x000000f9 => "\x79",
     0x000000fa => "\xde",
     0x000000fb => "\xdb",
     0x000000fc => "\xdc",
     0x000000fd => "\x8d",
     0x000000fe => "\x8e",
     0x000000ff => "\xdf",
     0x0000203e => "\xbc",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x6f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::IBM280 - Conversion routines for IBM280
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for IBM280.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
   source: IBM NLS RM Vol2 SE09-8002-01, March 1990
  alias CP280
  alias EBCDIC-CP-IT
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  0000009C | STRING TERMINATOR (ST)
     05 |  00000009 | CHARACTER TABULATION (HT)
     06 |  00000086 | START OF SELECTED AREA (SSA)
     07 |  0000007F | DELETE (DEL)
     08 |  00000097 | END OF GUARDED AREA (EPA)
     09 |  0000008D | REVERSE LINE FEED (RI)
     0A |  0000008E | SINGLE-SHIFT TWO (SS2)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  0000009D | OPERATING SYSTEM COMMAND (OSC)
     15 |  00000085 | NEXT LINE (NEL)
     16 |  00000008 | BACKSPACE (BS)
     17 |  00000087 | END OF SELECTED AREA (ESA)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  00000092 | PRIVATE USE TWO (PU2)
     1B |  0000008F | SINGLE-SHIFT THREE (SS3)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000080 | PADDING CHARACTER (PAD)
     21 |  00000081 | HIGH OCTET PRESET (HOP)
     22 |  00000082 | BREAK PERMITTED HERE (BPH)
     23 |  00000083 | NO BREAK HERE (NBH)
     24 |  00000084 | INDEX (IND)
     25 |  0000000A | LINE FEED (LF)
     26 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     27 |  0000001B | ESCAPE (ESC)
     28 |  00000088 | CHARACTER TABULATION SET (HTS)
     29 |  00000089 | CHARACTER TABULATION WITH JUSTIFICATION (HTJ)
     2A |  0000008A | LINE TABULATION SET (VTS)
     2B |  0000008B | PARTIAL LINE FORWARD (PLD)
     2C |  0000008C | PARTIAL LINE BACKWARD (PLU)
     2D |  00000005 | ENQUIRY (ENQ)
     2E |  00000006 | ACKNOWLEDGE (ACK)
     2F |  00000007 | BELL (BEL)
     30 |  00000090 | DEVICE CONTROL STRING (DCS)
     31 |  00000091 | PRIVATE USE ONE (PU1)
     32 |  00000016 | SYNCHRONOUS IDLE (SYN)
     33 |  00000093 | SET TRANSMIT STATE (STS)
     34 |  00000094 | CANCEL CHARACTER (CCH)
     35 |  00000095 | MESSAGE WAITING (MW)
     36 |  00000096 | START OF GUARDED AREA (SPA)
     37 |  00000004 | END OF TRANSMISSION (EOT)
     38 |  00000098 | START OF STRING (SOS)
     39 |  00000099 | SINGLE GRAPHIC CHARACTER INTRODUCER (SGCI)
     3A |  0000009A | SINGLE CHARACTER INTRODUCER (SCI)
     3B |  0000009B | CONTROL SEQUENCE INTRODUCER (CSI)
     3C |  00000014 | DEVICE CONTROL FOUR (DC4)
     3D |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     3E |  0000009E | PRIVACY MESSAGE (PM)
     3F |  0000001A | SUBSTITUTE (SUB)
     40 |  00000020 | SPACE
     41 |  000000A0 | NO-BREAK SPACE
     42 |  000000E2 | LATIN SMALL LETTER A WITH CIRCUMFLEX
     43 |  000000E4 | LATIN SMALL LETTER A WITH DIAERESIS
     44 |  0000007B | LEFT CURLY BRACKET
     45 |  000000E1 | LATIN SMALL LETTER A WITH ACUTE
     46 |  000000E3 | LATIN SMALL LETTER A WITH TILDE
     47 |  000000E5 | LATIN SMALL LETTER A WITH RING ABOVE
     48 |  0000005C | REVERSE SOLIDUS
     49 |  000000F1 | LATIN SMALL LETTER N WITH TILDE
     4A |  000000B0 | DEGREE SIGN
     4B |  0000002E | FULL STOP
     4C |  0000003C | LESS-THAN SIGN
     4D |  00000028 | LEFT PARENTHESIS
     4E |  0000002B | PLUS SIGN
     4F |  00000021 | EXCLAMATION MARK
     50 |  00000026 | AMPERSAND
     51 |  0000005D | RIGHT SQUARE BRACKET
     52 |  000000EA | LATIN SMALL LETTER E WITH CIRCUMFLEX
     53 |  000000EB | LATIN SMALL LETTER E WITH DIAERESIS
     54 |  0000007D | RIGHT CURLY BRACKET
     55 |  000000ED | LATIN SMALL LETTER I WITH ACUTE
     56 |  000000EE | LATIN SMALL LETTER I WITH CIRCUMFLEX
     57 |  000000EF | LATIN SMALL LETTER I WITH DIAERESIS
     58 |  0000007E | TILDE
     59 |  000000DF | LATIN SMALL LETTER SHARP S (German)
     5A |  000000E9 | LATIN SMALL LETTER E WITH ACUTE
     5B |  00000024 | DOLLAR SIGN
     5C |  0000002A | ASTERISK
     5D |  00000029 | RIGHT PARENTHESIS
     5E |  0000003B | SEMICOLON
     5F |  0000005E | CIRCUMFLEX ACCENT
     60 |  0000002D | HYPHEN-MINUS
     61 |  0000002F | SOLIDUS
     62 |  000000C2 | LATIN CAPITAL LETTER A WITH CIRCUMFLEX
     63 |  000000C4 | LATIN CAPITAL LETTER A WITH DIAERESIS
     64 |  000000C0 | LATIN CAPITAL LETTER A WITH GRAVE
     65 |  000000C1 | LATIN CAPITAL LETTER A WITH ACUTE
     66 |  000000C3 | LATIN CAPITAL LETTER A WITH TILDE
     67 |  000000C5 | LATIN CAPITAL LETTER A WITH RING ABOVE
     68 |  000000C7 | LATIN CAPITAL LETTER C WITH CEDILLA
     69 |  000000D1 | LATIN CAPITAL LETTER N WITH TILDE
     6A |  000000F2 | LATIN SMALL LETTER O WITH GRAVE
     6B |  0000002C | COMMA
     6C |  00000025 | PERCENT SIGN
     6D |  0000005F | LOW LINE
     6E |  0000003E | GREATER-THAN SIGN
     6F |  0000003F | QUESTION MARK
     70 |  000000F8 | LATIN SMALL LETTER O WITH STROKE
     71 |  000000C9 | LATIN CAPITAL LETTER E WITH ACUTE
     72 |  000000CA | LATIN CAPITAL LETTER E WITH CIRCUMFLEX
     73 |  000000CB | LATIN CAPITAL LETTER E WITH DIAERESIS
     74 |  000000C8 | LATIN CAPITAL LETTER E WITH GRAVE
     75 |  000000CD | LATIN CAPITAL LETTER I WITH ACUTE
     76 |  000000CE | LATIN CAPITAL LETTER I WITH CIRCUMFLEX
     77 |  000000CF | LATIN CAPITAL LETTER I WITH DIAERESIS
     78 |  000000CC | LATIN CAPITAL LETTER I WITH GRAVE
     79 |  000000F9 | LATIN SMALL LETTER U WITH GRAVE
     7A |  0000003A | COLON
     7B |  000000A3 | POUND SIGN
     7C |  000000A7 | SECTION SIGN
     7D |  00000027 | APOSTROPHE
     7E |  0000003D | EQUALS SIGN
     7F |  00000022 | QUOTATION MARK
     80 |  000000D8 | LATIN CAPITAL LETTER O WITH STROKE
     81 |  00000061 | LATIN SMALL LETTER A
     82 |  00000062 | LATIN SMALL LETTER B
     83 |  00000063 | LATIN SMALL LETTER C
     84 |  00000064 | LATIN SMALL LETTER D
     85 |  00000065 | LATIN SMALL LETTER E
     86 |  00000066 | LATIN SMALL LETTER F
     87 |  00000067 | LATIN SMALL LETTER G
     88 |  00000068 | LATIN SMALL LETTER H
     89 |  00000069 | LATIN SMALL LETTER I
     8A |  000000AB | LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
     8B |  000000BB | RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
     8C |  000000F0 | LATIN SMALL LETTER ETH (Icelandic)
     8D |  000000FD | LATIN SMALL LETTER Y WITH ACUTE
     8E |  000000FE | LATIN SMALL LETTER THORN (Icelandic)
     8F |  000000B1 | PLUS-MINUS SIGN
     90 |  0000005B | LEFT SQUARE BRACKET
     91 |  0000006A | LATIN SMALL LETTER J
     92 |  0000006B | LATIN SMALL LETTER K
     93 |  0000006C | LATIN SMALL LETTER L
     94 |  0000006D | LATIN SMALL LETTER M
     95 |  0000006E | LATIN SMALL LETTER N
     96 |  0000006F | LATIN SMALL LETTER O
     97 |  00000070 | LATIN SMALL LETTER P
     98 |  00000071 | LATIN SMALL LETTER Q
     99 |  00000072 | LATIN SMALL LETTER R
     9A |  000000AA | FEMININE ORDINAL INDICATOR
     9B |  000000BA | MASCULINE ORDINAL INDICATOR
     9C |  000000E6 | LATIN SMALL LETTER AE
     9D |  000000B8 | CEDILLA
     9E |  000000C6 | LATIN CAPITAL LETTER AE
     9F |  000000A4 | CURRENCY SIGN
     A0 |  000000B5 | MICRO SIGN
     A1 |  000000EC | LATIN SMALL LETTER I WITH GRAVE
     A2 |  00000073 | LATIN SMALL LETTER S
     A3 |  00000074 | LATIN SMALL LETTER T
     A4 |  00000075 | LATIN SMALL LETTER U
     A5 |  00000076 | LATIN SMALL LETTER V
     A6 |  00000077 | LATIN SMALL LETTER W
     A7 |  00000078 | LATIN SMALL LETTER X
     A8 |  00000079 | LATIN SMALL LETTER Y
     A9 |  0000007A | LATIN SMALL LETTER Z
     AA |  000000A1 | INVERTED EXCLAMATION MARK
     AB |  000000BF | INVERTED QUESTION MARK
     AC |  000000D0 | LATIN CAPITAL LETTER ETH (Icelandic)
     AD |  000000DD | LATIN CAPITAL LETTER Y WITH ACUTE
     AE |  000000DE | LATIN CAPITAL LETTER THORN (Icelandic)
     AF |  000000AE | REGISTERED SIGN
     B0 |  000000A2 | CENT SIGN
     B1 |  00000023 | NUMBER SIGN
     B2 |  000000A5 | YEN SIGN
     B3 |  000000B7 | MIDDLE DOT
     B4 |  000000A9 | COPYRIGHT SIGN
     B5 |  00000040 | COMMERCIAL AT
     B6 |  000000B6 | PILCROW SIGN
     B7 |  000000BC | VULGAR FRACTION ONE QUARTER
     B8 |  000000BD | VULGAR FRACTION ONE HALF
     B9 |  000000BE | VULGAR FRACTION THREE QUARTERS
     BA |  000000AC | NOT SIGN
     BB |  0000007C | VERTICAL LINE
     BC |  0000203E | OVERLINE
     BD |  000000A8 | DIAERESIS
     BE |  000000B4 | ACUTE ACCENT
     BF |  000000D7 | MULTIPLICATION SIGN
     C0 |  000000E0 | LATIN SMALL LETTER A WITH GRAVE
     C1 |  00000041 | LATIN CAPITAL LETTER A
     C2 |  00000042 | LATIN CAPITAL LETTER B
     C3 |  00000043 | LATIN CAPITAL LETTER C
     C4 |  00000044 | LATIN CAPITAL LETTER D
     C5 |  00000045 | LATIN CAPITAL LETTER E
     C6 |  00000046 | LATIN CAPITAL LETTER F
     C7 |  00000047 | LATIN CAPITAL LETTER G
     C8 |  00000048 | LATIN CAPITAL LETTER H
     C9 |  00000049 | LATIN CAPITAL LETTER I
     CA |  000000AD | SOFT HYPHEN
     CB |  000000F4 | LATIN SMALL LETTER O WITH CIRCUMFLEX
     CC |  000000F6 | LATIN SMALL LETTER O WITH DIAERESIS
     CD |  000000A6 | BROKEN BAR
     CE |  000000F3 | LATIN SMALL LETTER O WITH ACUTE
     CF |  000000F5 | LATIN SMALL LETTER O WITH TILDE
     D0 |  000000E8 | LATIN SMALL LETTER E WITH GRAVE
     D1 |  0000004A | LATIN CAPITAL LETTER J
     D2 |  0000004B | LATIN CAPITAL LETTER K
     D3 |  0000004C | LATIN CAPITAL LETTER L
     D4 |  0000004D | LATIN CAPITAL LETTER M
     D5 |  0000004E | LATIN CAPITAL LETTER N
     D6 |  0000004F | LATIN CAPITAL LETTER O
     D7 |  00000050 | LATIN CAPITAL LETTER P
     D8 |  00000051 | LATIN CAPITAL LETTER Q
     D9 |  00000052 | LATIN CAPITAL LETTER R
     DA |  000000B9 | SUPERSCRIPT ONE
     DB |  000000FB | LATIN SMALL LETTER U WITH CIRCUMFLEX
     DC |  000000FC | LATIN SMALL LETTER U WITH DIAERESIS
     DD |  00000060 | GRAVE ACCENT
     DE |  000000FA | LATIN SMALL LETTER U WITH ACUTE
     DF |  000000FF | LATIN SMALL LETTER Y WITH DIAERESIS
     E0 |  000000E7 | LATIN SMALL LETTER C WITH CEDILLA
     E1 |  000000F7 | DIVISION SIGN
     E2 |  00000053 | LATIN CAPITAL LETTER S
     E3 |  00000054 | LATIN CAPITAL LETTER T
     E4 |  00000055 | LATIN CAPITAL LETTER U
     E5 |  00000056 | LATIN CAPITAL LETTER V
     E6 |  00000057 | LATIN CAPITAL LETTER W
     E7 |  00000058 | LATIN CAPITAL LETTER X
     E8 |  00000059 | LATIN CAPITAL LETTER Y
     E9 |  0000005A | LATIN CAPITAL LETTER Z
     EA |  000000B2 | SUPERSCRIPT TWO
     EB |  000000D4 | LATIN CAPITAL LETTER O WITH CIRCUMFLEX
     EC |  000000D6 | LATIN CAPITAL LETTER O WITH DIAERESIS
     ED |  000000D2 | LATIN CAPITAL LETTER O WITH GRAVE
     EE |  000000D3 | LATIN CAPITAL LETTER O WITH ACUTE
     EF |  000000D5 | LATIN CAPITAL LETTER O WITH TILDE
     F0 |  00000030 | DIGIT ZERO
     F1 |  00000031 | DIGIT ONE
     F2 |  00000032 | DIGIT TWO
     F3 |  00000033 | DIGIT THREE
     F4 |  00000034 | DIGIT FOUR
     F5 |  00000035 | DIGIT FIVE
     F6 |  00000036 | DIGIT SIX
     F7 |  00000037 | DIGIT SEVEN
     F8 |  00000038 | DIGIT EIGHT
     F9 |  00000039 | DIGIT NINE
     FA |  000000B3 | SUPERSCRIPT THREE
     FB |  000000DB | LATIN CAPITAL LETTER U WITH CIRCUMFLEX
     FC |  000000DC | LATIN CAPITAL LETTER U WITH DIAERESIS
     FD |  000000D9 | LATIN CAPITAL LETTER U WITH GRAVE
     FE |  000000DA | LATIN CAPITAL LETTER U WITH ACUTE
     FF |  0000009F | APPLICATION PROGRAM COMMAND (APC)
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/IBM281.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for IBM281.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::IBM281;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x009c,
     0x0009,
     0x0086,
     0x007f,
     0x0097,
     0x008d,
     0x008e,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x009d,
     0x0085,
     0x0008,
     0x0087,
     0x0018,
     0x0019,
     0x0092,
     0x008f,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0080,
     0x0081,
     0x0082,
     0x0083,
     0x0084,
     0x000a,
     0x0017,
     0x001b,
     0x0088,
     0x0089,
     0x008a,
     0x008b,
     0x008c,
     0x0005,
     0x0006,
     0x0007,
     0x0090,
     0x0091,
     0x0016,
     0x0093,
     0x0094,
     0x0095,
     0x0096,
     0x0004,
     0x0098,
     0x0099,
     0x009a,
     0x009b,
     0x0014,
     0x0015,
     0x009e,
     0x001a,
     0x0020,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00a3,
     0x002e,
     0x003c,
     0x0028,
     0x002b,
     0x007c,
     0x0026,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x0021,
     0x00a5,
     0x002a,
     0x0029,
     0x003b,
     0x00ac,
     0x002d,
     0x002f,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00a6,
     0x002c,
     0x0025,
     0x005f,
     0x003e,
     0x003f,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x0060,
     0x003a,
     0x0023,
     0x0040,
     0x0027,
     0x003d,
     0x0022,
     0xfffd,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x203e,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x007b,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x007d,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x0024,
     0xfffd,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x009f,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\xc2\x9c",
     "\x09",
     "\xc2\x86",
     "\x7f",
     "\xc2\x97",
     "\xc2\x8d",
     "\xc2\x8e",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\xc2\x9d",
     "\xc2\x85",
     "\x08",
     "\xc2\x87",
     "\x18",
     "\x19",
     "\xc2\x92",
     "\xc2\x8f",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\xc2\x80",
     "\xc2\x81",
     "\xc2\x82",
     "\xc2\x83",
     "\xc2\x84",
     "\x0a",
     "\x17",
     "\x1b",
     "\xc2\x88",
     "\xc2\x89",
     "\xc2\x8a",
     "\xc2\x8b",
     "\xc2\x8c",
     "\x05",
     "\x06",
     "\x07",
     "\xc2\x90",
     "\xc2\x91",
     "\x16",
     "\xc2\x93",
     "\xc2\x94",
     "\xc2\x95",
     "\xc2\x96",
     "\x04",
     "\xc2\x98",
     "\xc2\x99",
     "\xc2\x9a",
     "\xc2\x9b",
     "\x14",
     "\x15",
     "\xc2\x9e",
     "\x1a",
     "\x20",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc2\xa3",
     "\x2e",
     "\x3c",
     "\x28",
     "\x2b",
     "\x7c",
     "\x26",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x21",
     "\xc2\xa5",
     "\x2a",
     "\x29",
     "\x3b",
     "\xc2\xac",
     "\x2d",
     "\x2f",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc2\xa6",
     "\x2c",
     "\x25",
     "\x5f",
     "\x3e",
     "\x3f",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x60",
     "\x3a",
     "\x23",
     "\x40",
     "\x27",
     "\x3d",
     "\x22",
     "\xef\xbf\xbd",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xe2\x80\xbe",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x7b",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x7d",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x24",
     "\xef\xbf\xbd",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc2\x9f",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x37",
     0x00000005 => "\x2d",
     0x00000006 => "\x2e",
     0x00000007 => "\x2f",
     0x00000008 => "\x16",
     0x00000009 => "\x05",
     0x0000000a => "\x25",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x3c",
     0x00000015 => "\x3d",
     0x00000016 => "\x32",
     0x00000017 => "\x26",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x3f",
     0x0000001b => "\x27",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x40",
     0x00000021 => "\x5a",
     0x00000022 => "\x7f",
     0x00000023 => "\x7b",
     0x00000024 => "\xe0",
     0x00000025 => "\x6c",
     0x00000026 => "\x50",
     0x00000027 => "\x7d",
     0x00000028 => "\x4d",
     0x00000029 => "\x5d",
     0x0000002a => "\x5c",
     0x0000002b => "\x4e",
     0x0000002c => "\x6b",
     0x0000002d => "\x60",
     0x0000002e => "\x4b",
     0x0000002f => "\x61",
     0x00000030 => "\xf0",
     0x00000031 => "\xf1",
     0x00000032 => "\xf2",
     0x00000033 => "\xf3",
     0x00000034 => "\xf4",
     0x00000035 => "\xf5",
     0x00000036 => "\xf6",
     0x00000037 => "\xf7",
     0x00000038 => "\xf8",
     0x00000039 => "\xf9",
     0x0000003a => "\x7a",
     0x0000003b => "\x5e",
     0x0000003c => "\x4c",
     0x0000003d => "\x7e",
     0x0000003e => "\x6e",
     0x0000003f => "\x6f",
     0x00000040 => "\x7c",
     0x00000041 => "\xc1",
     0x00000042 => "\xc2",
     0x00000043 => "\xc3",
     0x00000044 => "\xc4",
     0x00000045 => "\xc5",
     0x00000046 => "\xc6",
     0x00000047 => "\xc7",
     0x00000048 => "\xc8",
     0x00000049 => "\xc9",
     0x0000004a => "\xd1",
     0x0000004b => "\xd2",
     0x0000004c => "\xd3",
     0x0000004d => "\xd4",
     0x0000004e => "\xd5",
     0x0000004f => "\xd6",
     0x00000050 => "\xd7",
     0x00000051 => "\xd8",
     0x00000052 => "\xd9",
     0x00000053 => "\xe2",
     0x00000054 => "\xe3",
     0x00000055 => "\xe4",
     0x00000056 => "\xe5",
     0x00000057 => "\xe6",
     0x00000058 => "\xe7",
     0x00000059 => "\xe8",
     0x0000005a => "\xe9",
     0x0000005f => "\x6d",
     0x00000060 => "\x79",
     0x00000061 => "\x81",
     0x00000062 => "\x82",
     0x00000063 => "\x83",
     0x00000064 => "\x84",
     0x00000065 => "\x85",
     0x00000066 => "\x86",
     0x00000067 => "\x87",
     0x00000068 => "\x88",
     0x00000069 => "\x89",
     0x0000006a => "\x91",
     0x0000006b => "\x92",
     0x0000006c => "\x93",
     0x0000006d => "\x94",
     0x0000006e => "\x95",
     0x0000006f => "\x96",
     0x00000070 => "\x97",
     0x00000071 => "\x98",
     0x00000072 => "\x99",
     0x00000073 => "\xa2",
     0x00000074 => "\xa3",
     0x00000075 => "\xa4",
     0x00000076 => "\xa5",
     0x00000077 => "\xa6",
     0x00000078 => "\xa7",
     0x00000079 => "\xa8",
     0x0000007a => "\xa9",
     0x0000007b => "\xc0",
     0x0000007c => "\x4f",
     0x0000007d => "\xd0",
     0x0000007f => "\x07",
     0x00000080 => "\x20",
     0x00000081 => "\x21",
     0x00000082 => "\x22",
     0x00000083 => "\x23",
     0x00000084 => "\x24",
     0x00000085 => "\x15",
     0x00000086 => "\x06",
     0x00000087 => "\x17",
     0x00000088 => "\x28",
     0x00000089 => "\x29",
     0x0000008a => "\x2a",
     0x0000008b => "\x2b",
     0x0000008c => "\x2c",
     0x0000008d => "\x09",
     0x0000008e => "\x0a",
     0x0000008f => "\x1b",
     0x00000090 => "\x30",
     0x00000091 => "\x31",
     0x00000092 => "\x1a",
     0x00000093 => "\x33",
     0x00000094 => "\x34",
     0x00000095 => "\x35",
     0x00000096 => "\x36",
     0x00000097 => "\x08",
     0x00000098 => "\x38",
     0x00000099 => "\x39",
     0x0000009a => "\x3a",
     0x0000009b => "\x3b",
     0x0000009c => "\x04",
     0x0000009d => "\x14",
     0x0000009e => "\x3e",
     0x0000009f => "\xff",
     0x000000a3 => "\x4a",
     0x000000a5 => "\x5b",
     0x000000a6 => "\x6a",
     0x000000ac => "\x5f",
     0x0000203e => "\xa1",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x6f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::IBM281 - Conversion routines for IBM281
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for IBM281.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
   source: IBM 3174 Character Set Ref, GA27-3831-02, March 1990
  alias EBCDIC-JP-E
  alias CP281
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  0000009C | STRING TERMINATOR (ST)
     05 |  00000009 | CHARACTER TABULATION (HT)
     06 |  00000086 | START OF SELECTED AREA (SSA)
     07 |  0000007F | DELETE (DEL)
     08 |  00000097 | END OF GUARDED AREA (EPA)
     09 |  0000008D | REVERSE LINE FEED (RI)
     0A |  0000008E | SINGLE-SHIFT TWO (SS2)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  0000009D | OPERATING SYSTEM COMMAND (OSC)
     15 |  00000085 | NEXT LINE (NEL)
     16 |  00000008 | BACKSPACE (BS)
     17 |  00000087 | END OF SELECTED AREA (ESA)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  00000092 | PRIVATE USE TWO (PU2)
     1B |  0000008F | SINGLE-SHIFT THREE (SS3)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000080 | PADDING CHARACTER (PAD)
     21 |  00000081 | HIGH OCTET PRESET (HOP)
     22 |  00000082 | BREAK PERMITTED HERE (BPH)
     23 |  00000083 | NO BREAK HERE (NBH)
     24 |  00000084 | INDEX (IND)
     25 |  0000000A | LINE FEED (LF)
     26 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     27 |  0000001B | ESCAPE (ESC)
     28 |  00000088 | CHARACTER TABULATION SET (HTS)
     29 |  00000089 | CHARACTER TABULATION WITH JUSTIFICATION (HTJ)
     2A |  0000008A | LINE TABULATION SET (VTS)
     2B |  0000008B | PARTIAL LINE FORWARD (PLD)
     2C |  0000008C | PARTIAL LINE BACKWARD (PLU)
     2D |  00000005 | ENQUIRY (ENQ)
     2E |  00000006 | ACKNOWLEDGE (ACK)
     2F |  00000007 | BELL (BEL)
     30 |  00000090 | DEVICE CONTROL STRING (DCS)
     31 |  00000091 | PRIVATE USE ONE (PU1)
     32 |  00000016 | SYNCHRONOUS IDLE (SYN)
     33 |  00000093 | SET TRANSMIT STATE (STS)
     34 |  00000094 | CANCEL CHARACTER (CCH)
     35 |  00000095 | MESSAGE WAITING (MW)
     36 |  00000096 | START OF GUARDED AREA (SPA)
     37 |  00000004 | END OF TRANSMISSION (EOT)
     38 |  00000098 | START OF STRING (SOS)
     39 |  00000099 | SINGLE GRAPHIC CHARACTER INTRODUCER (SGCI)
     3A |  0000009A | SINGLE CHARACTER INTRODUCER (SCI)
     3B |  0000009B | CONTROL SEQUENCE INTRODUCER (CSI)
     3C |  00000014 | DEVICE CONTROL FOUR (DC4)
     3D |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     3E |  0000009E | PRIVACY MESSAGE (PM)
     3F |  0000001A | SUBSTITUTE (SUB)
     40 |  00000020 | SPACE
     4A |  000000A3 | POUND SIGN
     4B |  0000002E | FULL STOP
     4C |  0000003C | LESS-THAN SIGN
     4D |  00000028 | LEFT PARENTHESIS
     4E |  0000002B | PLUS SIGN
     4F |  0000007C | VERTICAL LINE
     50 |  00000026 | AMPERSAND
     5A |  00000021 | EXCLAMATION MARK
     5B |  000000A5 | YEN SIGN
     5C |  0000002A | ASTERISK
     5D |  00000029 | RIGHT PARENTHESIS
     5E |  0000003B | SEMICOLON
     5F |  000000AC | NOT SIGN
     60 |  0000002D | HYPHEN-MINUS
     61 |  0000002F | SOLIDUS
     6A |  000000A6 | BROKEN BAR
     6B |  0000002C | COMMA
     6C |  00000025 | PERCENT SIGN
     6D |  0000005F | LOW LINE
     6E |  0000003E | GREATER-THAN SIGN
     6F |  0000003F | QUESTION MARK
     79 |  00000060 | GRAVE ACCENT
     7A |  0000003A | COLON
     7B |  00000023 | NUMBER SIGN
     7C |  00000040 | COMMERCIAL AT
     7D |  00000027 | APOSTROPHE
     7E |  0000003D | EQUALS SIGN
     7F |  00000022 | QUOTATION MARK
     81 |  00000061 | LATIN SMALL LETTER A
     82 |  00000062 | LATIN SMALL LETTER B
     83 |  00000063 | LATIN SMALL LETTER C
     84 |  00000064 | LATIN SMALL LETTER D
     85 |  00000065 | LATIN SMALL LETTER E
     86 |  00000066 | LATIN SMALL LETTER F
     87 |  00000067 | LATIN SMALL LETTER G
     88 |  00000068 | LATIN SMALL LETTER H
     89 |  00000069 | LATIN SMALL LETTER I
     91 |  0000006A | LATIN SMALL LETTER J
     92 |  0000006B | LATIN SMALL LETTER K
     93 |  0000006C | LATIN SMALL LETTER L
     94 |  0000006D | LATIN SMALL LETTER M
     95 |  0000006E | LATIN SMALL LETTER N
     96 |  0000006F | LATIN SMALL LETTER O
     97 |  00000070 | LATIN SMALL LETTER P
     98 |  00000071 | LATIN SMALL LETTER Q
     99 |  00000072 | LATIN SMALL LETTER R
     A1 |  0000203E | OVERLINE
     A2 |  00000073 | LATIN SMALL LETTER S
     A3 |  00000074 | LATIN SMALL LETTER T
     A4 |  00000075 | LATIN SMALL LETTER U
     A5 |  00000076 | LATIN SMALL LETTER V
     A6 |  00000077 | LATIN SMALL LETTER W
     A7 |  00000078 | LATIN SMALL LETTER X
     A8 |  00000079 | LATIN SMALL LETTER Y
     A9 |  0000007A | LATIN SMALL LETTER Z
     C0 |  0000007B | LEFT CURLY BRACKET
     C1 |  00000041 | LATIN CAPITAL LETTER A
     C2 |  00000042 | LATIN CAPITAL LETTER B
     C3 |  00000043 | LATIN CAPITAL LETTER C
     C4 |  00000044 | LATIN CAPITAL LETTER D
     C5 |  00000045 | LATIN CAPITAL LETTER E
     C6 |  00000046 | LATIN CAPITAL LETTER F
     C7 |  00000047 | LATIN CAPITAL LETTER G
     C8 |  00000048 | LATIN CAPITAL LETTER H
     C9 |  00000049 | LATIN CAPITAL LETTER I
     D0 |  0000007D | RIGHT CURLY BRACKET
     D1 |  0000004A | LATIN CAPITAL LETTER J
     D2 |  0000004B | LATIN CAPITAL LETTER K
     D3 |  0000004C | LATIN CAPITAL LETTER L
     D4 |  0000004D | LATIN CAPITAL LETTER M
     D5 |  0000004E | LATIN CAPITAL LETTER N
     D6 |  0000004F | LATIN CAPITAL LETTER O
     D7 |  00000050 | LATIN CAPITAL LETTER P
     D8 |  00000051 | LATIN CAPITAL LETTER Q
     D9 |  00000052 | LATIN CAPITAL LETTER R
     E0 |  00000024 | DOLLAR SIGN
     E2 |  00000053 | LATIN CAPITAL LETTER S
     E3 |  00000054 | LATIN CAPITAL LETTER T
     E4 |  00000055 | LATIN CAPITAL LETTER U
     E5 |  00000056 | LATIN CAPITAL LETTER V
     E6 |  00000057 | LATIN CAPITAL LETTER W
     E7 |  00000058 | LATIN CAPITAL LETTER X
     E8 |  00000059 | LATIN CAPITAL LETTER Y
     E9 |  0000005A | LATIN CAPITAL LETTER Z
     F0 |  00000030 | DIGIT ZERO
     F1 |  00000031 | DIGIT ONE
     F2 |  00000032 | DIGIT TWO
     F3 |  00000033 | DIGIT THREE
     F4 |  00000034 | DIGIT FOUR
     F5 |  00000035 | DIGIT FIVE
     F6 |  00000036 | DIGIT SIX
     F7 |  00000037 | DIGIT SEVEN
     F8 |  00000038 | DIGIT EIGHT
     F9 |  00000039 | DIGIT NINE
     FF |  0000009F | APPLICATION PROGRAM COMMAND (APC)
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/IBM284.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for IBM284.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::IBM284;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x009c,
     0x0009,
     0x0086,
     0x007f,
     0x0097,
     0x008d,
     0x008e,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x009d,
     0x0085,
     0x0008,
     0x0087,
     0x0018,
     0x0019,
     0x0092,
     0x008f,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0080,
     0x0081,
     0x0082,
     0x0083,
     0x0084,
     0x000a,
     0x0017,
     0x001b,
     0x0088,
     0x0089,
     0x008a,
     0x008b,
     0x008c,
     0x0005,
     0x0006,
     0x0007,
     0x0090,
     0x0091,
     0x0016,
     0x0093,
     0x0094,
     0x0095,
     0x0096,
     0x0004,
     0x0098,
     0x0099,
     0x009a,
     0x009b,
     0x0014,
     0x0015,
     0x009e,
     0x001a,
     0x0020,
     0x00a0,
     0x00e2,
     0x00e4,
     0x00e0,
     0x00e1,
     0x00e3,
     0x00e5,
     0x00e7,
     0x00a6,
     0x005b,
     0x002e,
     0x003c,
     0x0028,
     0x002b,
     0x007c,
     0x0026,
     0x00e9,
     0x00ea,
     0x00eb,
     0x00e8,
     0x00ed,
     0x00ee,
     0x00ef,
     0x00ec,
     0x00df,
     0x005d,
     0x0024,
     0x002a,
     0x0029,
     0x003b,
     0x00ac,
     0x002d,
     0x002f,
     0x00c2,
     0x00c4,
     0x00c0,
     0x00c1,
     0x00c3,
     0x00c5,
     0x00c7,
     0x0023,
     0x00f1,
     0x002c,
     0x0025,
     0x005f,
     0x003e,
     0x003f,
     0x00f8,
     0x00c9,
     0x00ca,
     0x00cb,
     0x00c8,
     0x00cd,
     0x00ce,
     0x00cf,
     0x00cc,
     0x0060,
     0x003a,
     0x00d1,
     0x0040,
     0x0027,
     0x003d,
     0x0022,
     0x00d8,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x00ab,
     0x00bb,
     0x00f0,
     0x00fd,
     0x00fe,
     0x00b1,
     0x00b0,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x00aa,
     0x00ba,
     0x00e6,
     0x00b8,
     0x00c6,
     0x00a4,
     0x00b5,
     0x00a8,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x00a1,
     0x00bf,
     0x00d0,
     0x00dd,
     0x00de,
     0x00ae,
     0x00a2,
     0x00a3,
     0x00a5,
     0x00b7,
     0x00a9,
     0x00a7,
     0x00b6,
     0x00bc,
     0x00bd,
     0x00be,
     0x005e,
     0x0021,
     0x203e,
     0x007e,
     0x00b4,
     0x00d7,
     0x007b,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x00ad,
     0x00f4,
     0x00f6,
     0x00f2,
     0x00f3,
     0x00f5,
     0x007d,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x00b9,
     0x00fb,
     0x00fc,
     0x00f9,
     0x00fa,
     0x00ff,
     0x005c,
     0x00f7,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x00b2,
     0x00d4,
     0x00d6,
     0x00d2,
     0x00d3,
     0x00d5,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x00b3,
     0x00db,
     0x00dc,
     0x00d9,
     0x00da,
     0x009f,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\xc2\x9c",
     "\x09",
     "\xc2\x86",
     "\x7f",
     "\xc2\x97",
     "\xc2\x8d",
     "\xc2\x8e",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\xc2\x9d",
     "\xc2\x85",
     "\x08",
     "\xc2\x87",
     "\x18",
     "\x19",
     "\xc2\x92",
     "\xc2\x8f",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\xc2\x80",
     "\xc2\x81",
     "\xc2\x82",
     "\xc2\x83",
     "\xc2\x84",
     "\x0a",
     "\x17",
     "\x1b",
     "\xc2\x88",
     "\xc2\x89",
     "\xc2\x8a",
     "\xc2\x8b",
     "\xc2\x8c",
     "\x05",
     "\x06",
     "\x07",
     "\xc2\x90",
     "\xc2\x91",
     "\x16",
     "\xc2\x93",
     "\xc2\x94",
     "\xc2\x95",
     "\xc2\x96",
     "\x04",
     "\xc2\x98",
     "\xc2\x99",
     "\xc2\x9a",
     "\xc2\x9b",
     "\x14",
     "\x15",
     "\xc2\x9e",
     "\x1a",
     "\x20",
     "\xc2\xa0",
     "\xc3\xa2",
     "\xc3\xa4",
     "\xc3\xa0",
     "\xc3\xa1",
     "\xc3\xa3",
     "\xc3\xa5",
     "\xc3\xa7",
     "\xc2\xa6",
     "\x5b",
     "\x2e",
     "\x3c",
     "\x28",
     "\x2b",
     "\x7c",
     "\x26",
     "\xc3\xa9",
     "\xc3\xaa",
     "\xc3\xab",
     "\xc3\xa8",
     "\xc3\xad",
     "\xc3\xae",
     "\xc3\xaf",
     "\xc3\xac",
     "\xc3\x9f",
     "\x5d",
     "\x24",
     "\x2a",
     "\x29",
     "\x3b",
     "\xc2\xac",
     "\x2d",
     "\x2f",
     "\xc3\x82",
     "\xc3\x84",
     "\xc3\x80",
     "\xc3\x81",
     "\xc3\x83",
     "\xc3\x85",
     "\xc3\x87",
     "\x23",
     "\xc3\xb1",
     "\x2c",
     "\x25",
     "\x5f",
     "\x3e",
     "\x3f",
     "\xc3\xb8",
     "\xc3\x89",
     "\xc3\x8a",
     "\xc3\x8b",
     "\xc3\x88",
     "\xc3\x8d",
     "\xc3\x8e",
     "\xc3\x8f",
     "\xc3\x8c",
     "\x60",
     "\x3a",
     "\xc3\x91",
     "\x40",
     "\x27",
     "\x3d",
     "\x22",
     "\xc3\x98",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\xc2\xab",
     "\xc2\xbb",
     "\xc3\xb0",
     "\xc3\xbd",
     "\xc3\xbe",
     "\xc2\xb1",
     "\xc2\xb0",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\xc2\xaa",
     "\xc2\xba",
     "\xc3\xa6",
     "\xc2\xb8",
     "\xc3\x86",
     "\xc2\xa4",
     "\xc2\xb5",
     "\xc2\xa8",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\xc2\xa1",
     "\xc2\xbf",
     "\xc3\x90",
     "\xc3\x9d",
     "\xc3\x9e",
     "\xc2\xae",
     "\xc2\xa2",
     "\xc2\xa3",
     "\xc2\xa5",
     "\xc2\xb7",
     "\xc2\xa9",
     "\xc2\xa7",
     "\xc2\xb6",
     "\xc2\xbc",
     "\xc2\xbd",
     "\xc2\xbe",
     "\x5e",
     "\x21",
     "\xe2\x80\xbe",
     "\x7e",
     "\xc2\xb4",
     "\xc3\x97",
     "\x7b",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\xc2\xad",
     "\xc3\xb4",
     "\xc3\xb6",
     "\xc3\xb2",
     "\xc3\xb3",
     "\xc3\xb5",
     "\x7d",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\xc2\xb9",
     "\xc3\xbb",
     "\xc3\xbc",
     "\xc3\xb9",
     "\xc3\xba",
     "\xc3\xbf",
     "\x5c",
     "\xc3\xb7",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\xc2\xb2",
     "\xc3\x94",
     "\xc3\x96",
     "\xc3\x92",
     "\xc3\x93",
     "\xc3\x95",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\xc2\xb3",
     "\xc3\x9b",
     "\xc3\x9c",
     "\xc3\x99",
     "\xc3\x9a",
     "\xc2\x9f",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x37",
     0x00000005 => "\x2d",
     0x00000006 => "\x2e",
     0x00000007 => "\x2f",
     0x00000008 => "\x16",
     0x00000009 => "\x05",
     0x0000000a => "\x25",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x3c",
     0x00000015 => "\x3d",
     0x00000016 => "\x32",
     0x00000017 => "\x26",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x3f",
     0x0000001b => "\x27",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x40",
     0x00000021 => "\xbb",
     0x00000022 => "\x7f",
     0x00000023 => "\x69",
     0x00000024 => "\x5b",
     0x00000025 => "\x6c",
     0x00000026 => "\x50",
     0x00000027 => "\x7d",
     0x00000028 => "\x4d",
     0x00000029 => "\x5d",
     0x0000002a => "\x5c",
     0x0000002b => "\x4e",
     0x0000002c => "\x6b",
     0x0000002d => "\x60",
     0x0000002e => "\x4b",
     0x0000002f => "\x61",
     0x00000030 => "\xf0",
     0x00000031 => "\xf1",
     0x00000032 => "\xf2",
     0x00000033 => "\xf3",
     0x00000034 => "\xf4",
     0x00000035 => "\xf5",
     0x00000036 => "\xf6",
     0x00000037 => "\xf7",
     0x00000038 => "\xf8",
     0x00000039 => "\xf9",
     0x0000003a => "\x7a",
     0x0000003b => "\x5e",
     0x0000003c => "\x4c",
     0x0000003d => "\x7e",
     0x0000003e => "\x6e",
     0x0000003f => "\x6f",
     0x00000040 => "\x7c",
     0x00000041 => "\xc1",
     0x00000042 => "\xc2",
     0x00000043 => "\xc3",
     0x00000044 => "\xc4",
     0x00000045 => "\xc5",
     0x00000046 => "\xc6",
     0x00000047 => "\xc7",
     0x00000048 => "\xc8",
     0x00000049 => "\xc9",
     0x0000004a => "\xd1",
     0x0000004b => "\xd2",
     0x0000004c => "\xd3",
     0x0000004d => "\xd4",
     0x0000004e => "\xd5",
     0x0000004f => "\xd6",
     0x00000050 => "\xd7",
     0x00000051 => "\xd8",
     0x00000052 => "\xd9",
     0x00000053 => "\xe2",
     0x00000054 => "\xe3",
     0x00000055 => "\xe4",
     0x00000056 => "\xe5",
     0x00000057 => "\xe6",
     0x00000058 => "\xe7",
     0x00000059 => "\xe8",
     0x0000005a => "\xe9",
     0x0000005b => "\x4a",
     0x0000005c => "\xe0",
     0x0000005d => "\x5a",
     0x0000005e => "\xba",
     0x0000005f => "\x6d",
     0x00000060 => "\x79",
     0x00000061 => "\x81",
     0x00000062 => "\x82",
     0x00000063 => "\x83",
     0x00000064 => "\x84",
     0x00000065 => "\x85",
     0x00000066 => "\x86",
     0x00000067 => "\x87",
     0x00000068 => "\x88",
     0x00000069 => "\x89",
     0x0000006a => "\x91",
     0x0000006b => "\x92",
     0x0000006c => "\x93",
     0x0000006d => "\x94",
     0x0000006e => "\x95",
     0x0000006f => "\x96",
     0x00000070 => "\x97",
     0x00000071 => "\x98",
     0x00000072 => "\x99",
     0x00000073 => "\xa2",
     0x00000074 => "\xa3",
     0x00000075 => "\xa4",
     0x00000076 => "\xa5",
     0x00000077 => "\xa6",
     0x00000078 => "\xa7",
     0x00000079 => "\xa8",
     0x0000007a => "\xa9",
     0x0000007b => "\xc0",
     0x0000007c => "\x4f",
     0x0000007d => "\xd0",
     0x0000007e => "\xbd",
     0x0000007f => "\x07",
     0x00000080 => "\x20",
     0x00000081 => "\x21",
     0x00000082 => "\x22",
     0x00000083 => "\x23",
     0x00000084 => "\x24",
     0x00000085 => "\x15",
     0x00000086 => "\x06",
     0x00000087 => "\x17",
     0x00000088 => "\x28",
     0x00000089 => "\x29",
     0x0000008a => "\x2a",
     0x0000008b => "\x2b",
     0x0000008c => "\x2c",
     0x0000008d => "\x09",
     0x0000008e => "\x0a",
     0x0000008f => "\x1b",
     0x00000090 => "\x30",
     0x00000091 => "\x31",
     0x00000092 => "\x1a",
     0x00000093 => "\x33",
     0x00000094 => "\x34",
     0x00000095 => "\x35",
     0x00000096 => "\x36",
     0x00000097 => "\x08",
     0x00000098 => "\x38",
     0x00000099 => "\x39",
     0x0000009a => "\x3a",
     0x0000009b => "\x3b",
     0x0000009c => "\x04",
     0x0000009d => "\x14",
     0x0000009e => "\x3e",
     0x0000009f => "\xff",
     0x000000a0 => "\x41",
     0x000000a1 => "\xaa",
     0x000000a2 => "\xb0",
     0x000000a3 => "\xb1",
     0x000000a4 => "\x9f",
     0x000000a5 => "\xb2",
     0x000000a6 => "\x49",
     0x000000a7 => "\xb5",
     0x000000a8 => "\xa1",
     0x000000a9 => "\xb4",
     0x000000aa => "\x9a",
     0x000000ab => "\x8a",
     0x000000ac => "\x5f",
     0x000000ad => "\xca",
     0x000000ae => "\xaf",
     0x000000b0 => "\x90",
     0x000000b1 => "\x8f",
     0x000000b2 => "\xea",
     0x000000b3 => "\xfa",
     0x000000b4 => "\xbe",
     0x000000b5 => "\xa0",
     0x000000b6 => "\xb6",
     0x000000b7 => "\xb3",
     0x000000b8 => "\x9d",
     0x000000b9 => "\xda",
     0x000000ba => "\x9b",
     0x000000bb => "\x8b",
     0x000000bc => "\xb7",
     0x000000bd => "\xb8",
     0x000000be => "\xb9",
     0x000000bf => "\xab",
     0x000000c0 => "\x64",
     0x000000c1 => "\x65",
     0x000000c2 => "\x62",
     0x000000c3 => "\x66",
     0x000000c4 => "\x63",
     0x000000c5 => "\x67",
     0x000000c6 => "\x9e",
     0x000000c7 => "\x68",
     0x000000c8 => "\x74",
     0x000000c9 => "\x71",
     0x000000ca => "\x72",
     0x000000cb => "\x73",
     0x000000cc => "\x78",
     0x000000cd => "\x75",
     0x000000ce => "\x76",
     0x000000cf => "\x77",
     0x000000d0 => "\xac",
     0x000000d1 => "\x7b",
     0x000000d2 => "\xed",
     0x000000d3 => "\xee",
     0x000000d4 => "\xeb",
     0x000000d5 => "\xef",
     0x000000d6 => "\xec",
     0x000000d7 => "\xbf",
     0x000000d8 => "\x80",
     0x000000d9 => "\xfd",
     0x000000da => "\xfe",
     0x000000db => "\xfb",
     0x000000dc => "\xfc",
     0x000000dd => "\xad",
     0x000000de => "\xae",
     0x000000df => "\x59",
     0x000000e0 => "\x44",
     0x000000e1 => "\x45",
     0x000000e2 => "\x42",
     0x000000e3 => "\x46",
     0x000000e4 => "\x43",
     0x000000e5 => "\x47",
     0x000000e6 => "\x9c",
     0x000000e7 => "\x48",
     0x000000e8 => "\x54",
     0x000000e9 => "\x51",
     0x000000ea => "\x52",
     0x000000eb => "\x53",
     0x000000ec => "\x58",
     0x000000ed => "\x55",
     0x000000ee => "\x56",
     0x000000ef => "\x57",
     0x000000f0 => "\x8c",
     0x000000f1 => "\x6a",
     0x000000f2 => "\xcd",
     0x000000f3 => "\xce",
     0x000000f4 => "\xcb",
     0x000000f5 => "\xcf",
     0x000000f6 => "\xcc",
     0x000000f7 => "\xe1",
     0x000000f8 => "\x70",
     0x000000f9 => "\xdd",
     0x000000fa => "\xde",
     0x000000fb => "\xdb",
     0x000000fc => "\xdc",
     0x000000fd => "\x8d",
     0x000000fe => "\x8e",
     0x000000ff => "\xdf",
     0x0000203e => "\xbc",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x6f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::IBM284 - Conversion routines for IBM284
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for IBM284.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
   source: IBM NLS RM Vol2 SE09-8002-01, March 1990
  alias CP284
  alias EBCDIC-CP-ES
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  0000009C | STRING TERMINATOR (ST)
     05 |  00000009 | CHARACTER TABULATION (HT)
     06 |  00000086 | START OF SELECTED AREA (SSA)
     07 |  0000007F | DELETE (DEL)
     08 |  00000097 | END OF GUARDED AREA (EPA)
     09 |  0000008D | REVERSE LINE FEED (RI)
     0A |  0000008E | SINGLE-SHIFT TWO (SS2)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  0000009D | OPERATING SYSTEM COMMAND (OSC)
     15 |  00000085 | NEXT LINE (NEL)
     16 |  00000008 | BACKSPACE (BS)
     17 |  00000087 | END OF SELECTED AREA (ESA)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  00000092 | PRIVATE USE TWO (PU2)
     1B |  0000008F | SINGLE-SHIFT THREE (SS3)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000080 | PADDING CHARACTER (PAD)
     21 |  00000081 | HIGH OCTET PRESET (HOP)
     22 |  00000082 | BREAK PERMITTED HERE (BPH)
     23 |  00000083 | NO BREAK HERE (NBH)
     24 |  00000084 | INDEX (IND)
     25 |  0000000A | LINE FEED (LF)
     26 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     27 |  0000001B | ESCAPE (ESC)
     28 |  00000088 | CHARACTER TABULATION SET (HTS)
     29 |  00000089 | CHARACTER TABULATION WITH JUSTIFICATION (HTJ)
     2A |  0000008A | LINE TABULATION SET (VTS)
     2B |  0000008B | PARTIAL LINE FORWARD (PLD)
     2C |  0000008C | PARTIAL LINE BACKWARD (PLU)
     2D |  00000005 | ENQUIRY (ENQ)
     2E |  00000006 | ACKNOWLEDGE (ACK)
     2F |  00000007 | BELL (BEL)
     30 |  00000090 | DEVICE CONTROL STRING (DCS)
     31 |  00000091 | PRIVATE USE ONE (PU1)
     32 |  00000016 | SYNCHRONOUS IDLE (SYN)
     33 |  00000093 | SET TRANSMIT STATE (STS)
     34 |  00000094 | CANCEL CHARACTER (CCH)
     35 |  00000095 | MESSAGE WAITING (MW)
     36 |  00000096 | START OF GUARDED AREA (SPA)
     37 |  00000004 | END OF TRANSMISSION (EOT)
     38 |  00000098 | START OF STRING (SOS)
     39 |  00000099 | SINGLE GRAPHIC CHARACTER INTRODUCER (SGCI)
     3A |  0000009A | SINGLE CHARACTER INTRODUCER (SCI)
     3B |  0000009B | CONTROL SEQUENCE INTRODUCER (CSI)
     3C |  00000014 | DEVICE CONTROL FOUR (DC4)
     3D |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     3E |  0000009E | PRIVACY MESSAGE (PM)
     3F |  0000001A | SUBSTITUTE (SUB)
     40 |  00000020 | SPACE
     41 |  000000A0 | NO-BREAK SPACE
     42 |  000000E2 | LATIN SMALL LETTER A WITH CIRCUMFLEX
     43 |  000000E4 | LATIN SMALL LETTER A WITH DIAERESIS
     44 |  000000E0 | LATIN SMALL LETTER A WITH GRAVE
     45 |  000000E1 | LATIN SMALL LETTER A WITH ACUTE
     46 |  000000E3 | LATIN SMALL LETTER A WITH TILDE
     47 |  000000E5 | LATIN SMALL LETTER A WITH RING ABOVE
     48 |  000000E7 | LATIN SMALL LETTER C WITH CEDILLA
     49 |  000000A6 | BROKEN BAR
     4A |  0000005B | LEFT SQUARE BRACKET
     4B |  0000002E | FULL STOP
     4C |  0000003C | LESS-THAN SIGN
     4D |  00000028 | LEFT PARENTHESIS
     4E |  0000002B | PLUS SIGN
     4F |  0000007C | VERTICAL LINE
     50 |  00000026 | AMPERSAND
     51 |  000000E9 | LATIN SMALL LETTER E WITH ACUTE
     52 |  000000EA | LATIN SMALL LETTER E WITH CIRCUMFLEX
     53 |  000000EB | LATIN SMALL LETTER E WITH DIAERESIS
     54 |  000000E8 | LATIN SMALL LETTER E WITH GRAVE
     55 |  000000ED | LATIN SMALL LETTER I WITH ACUTE
     56 |  000000EE | LATIN SMALL LETTER I WITH CIRCUMFLEX
     57 |  000000EF | LATIN SMALL LETTER I WITH DIAERESIS
     58 |  000000EC | LATIN SMALL LETTER I WITH GRAVE
     59 |  000000DF | LATIN SMALL LETTER SHARP S (German)
     5A |  0000005D | RIGHT SQUARE BRACKET
     5B |  00000024 | DOLLAR SIGN
     5C |  0000002A | ASTERISK
     5D |  00000029 | RIGHT PARENTHESIS
     5E |  0000003B | SEMICOLON
     5F |  000000AC | NOT SIGN
     60 |  0000002D | HYPHEN-MINUS
     61 |  0000002F | SOLIDUS
     62 |  000000C2 | LATIN CAPITAL LETTER A WITH CIRCUMFLEX
     63 |  000000C4 | LATIN CAPITAL LETTER A WITH DIAERESIS
     64 |  000000C0 | LATIN CAPITAL LETTER A WITH GRAVE
     65 |  000000C1 | LATIN CAPITAL LETTER A WITH ACUTE
     66 |  000000C3 | LATIN CAPITAL LETTER A WITH TILDE
     67 |  000000C5 | LATIN CAPITAL LETTER A WITH RING ABOVE
     68 |  000000C7 | LATIN CAPITAL LETTER C WITH CEDILLA
     69 |  00000023 | NUMBER SIGN
     6A |  000000F1 | LATIN SMALL LETTER N WITH TILDE
     6B |  0000002C | COMMA
     6C |  00000025 | PERCENT SIGN
     6D |  0000005F | LOW LINE
     6E |  0000003E | GREATER-THAN SIGN
     6F |  0000003F | QUESTION MARK
     70 |  000000F8 | LATIN SMALL LETTER O WITH STROKE
     71 |  000000C9 | LATIN CAPITAL LETTER E WITH ACUTE
     72 |  000000CA | LATIN CAPITAL LETTER E WITH CIRCUMFLEX
     73 |  000000CB | LATIN CAPITAL LETTER E WITH DIAERESIS
     74 |  000000C8 | LATIN CAPITAL LETTER E WITH GRAVE
     75 |  000000CD | LATIN CAPITAL LETTER I WITH ACUTE
     76 |  000000CE | LATIN CAPITAL LETTER I WITH CIRCUMFLEX
     77 |  000000CF | LATIN CAPITAL LETTER I WITH DIAERESIS
     78 |  000000CC | LATIN CAPITAL LETTER I WITH GRAVE
     79 |  00000060 | GRAVE ACCENT
     7A |  0000003A | COLON
     7B |  000000D1 | LATIN CAPITAL LETTER N WITH TILDE
     7C |  00000040 | COMMERCIAL AT
     7D |  00000027 | APOSTROPHE
     7E |  0000003D | EQUALS SIGN
     7F |  00000022 | QUOTATION MARK
     80 |  000000D8 | LATIN CAPITAL LETTER O WITH STROKE
     81 |  00000061 | LATIN SMALL LETTER A
     82 |  00000062 | LATIN SMALL LETTER B
     83 |  00000063 | LATIN SMALL LETTER C
     84 |  00000064 | LATIN SMALL LETTER D
     85 |  00000065 | LATIN SMALL LETTER E
     86 |  00000066 | LATIN SMALL LETTER F
     87 |  00000067 | LATIN SMALL LETTER G
     88 |  00000068 | LATIN SMALL LETTER H
     89 |  00000069 | LATIN SMALL LETTER I
     8A |  000000AB | LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
     8B |  000000BB | RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
     8C |  000000F0 | LATIN SMALL LETTER ETH (Icelandic)
     8D |  000000FD | LATIN SMALL LETTER Y WITH ACUTE
     8E |  000000FE | LATIN SMALL LETTER THORN (Icelandic)
     8F |  000000B1 | PLUS-MINUS SIGN
     90 |  000000B0 | DEGREE SIGN
     91 |  0000006A | LATIN SMALL LETTER J
     92 |  0000006B | LATIN SMALL LETTER K
     93 |  0000006C | LATIN SMALL LETTER L
     94 |  0000006D | LATIN SMALL LETTER M
     95 |  0000006E | LATIN SMALL LETTER N
     96 |  0000006F | LATIN SMALL LETTER O
     97 |  00000070 | LATIN SMALL LETTER P
     98 |  00000071 | LATIN SMALL LETTER Q
     99 |  00000072 | LATIN SMALL LETTER R
     9A |  000000AA | FEMININE ORDINAL INDICATOR
     9B |  000000BA | MASCULINE ORDINAL INDICATOR
     9C |  000000E6 | LATIN SMALL LETTER AE
     9D |  000000B8 | CEDILLA
     9E |  000000C6 | LATIN CAPITAL LETTER AE
     9F |  000000A4 | CURRENCY SIGN
     A0 |  000000B5 | MICRO SIGN
     A1 |  000000A8 | DIAERESIS
     A2 |  00000073 | LATIN SMALL LETTER S
     A3 |  00000074 | LATIN SMALL LETTER T
     A4 |  00000075 | LATIN SMALL LETTER U
     A5 |  00000076 | LATIN SMALL LETTER V
     A6 |  00000077 | LATIN SMALL LETTER W
     A7 |  00000078 | LATIN SMALL LETTER X
     A8 |  00000079 | LATIN SMALL LETTER Y
     A9 |  0000007A | LATIN SMALL LETTER Z
     AA |  000000A1 | INVERTED EXCLAMATION MARK
     AB |  000000BF | INVERTED QUESTION MARK
     AC |  000000D0 | LATIN CAPITAL LETTER ETH (Icelandic)
     AD |  000000DD | LATIN CAPITAL LETTER Y WITH ACUTE
     AE |  000000DE | LATIN CAPITAL LETTER THORN (Icelandic)
     AF |  000000AE | REGISTERED SIGN
     B0 |  000000A2 | CENT SIGN
     B1 |  000000A3 | POUND SIGN
     B2 |  000000A5 | YEN SIGN
     B3 |  000000B7 | MIDDLE DOT
     B4 |  000000A9 | COPYRIGHT SIGN
     B5 |  000000A7 | SECTION SIGN
     B6 |  000000B6 | PILCROW SIGN
     B7 |  000000BC | VULGAR FRACTION ONE QUARTER
     B8 |  000000BD | VULGAR FRACTION ONE HALF
     B9 |  000000BE | VULGAR FRACTION THREE QUARTERS
     BA |  0000005E | CIRCUMFLEX ACCENT
     BB |  00000021 | EXCLAMATION MARK
     BC |  0000203E | OVERLINE
     BD |  0000007E | TILDE
     BE |  000000B4 | ACUTE ACCENT
     BF |  000000D7 | MULTIPLICATION SIGN
     C0 |  0000007B | LEFT CURLY BRACKET
     C1 |  00000041 | LATIN CAPITAL LETTER A
     C2 |  00000042 | LATIN CAPITAL LETTER B
     C3 |  00000043 | LATIN CAPITAL LETTER C
     C4 |  00000044 | LATIN CAPITAL LETTER D
     C5 |  00000045 | LATIN CAPITAL LETTER E
     C6 |  00000046 | LATIN CAPITAL LETTER F
     C7 |  00000047 | LATIN CAPITAL LETTER G
     C8 |  00000048 | LATIN CAPITAL LETTER H
     C9 |  00000049 | LATIN CAPITAL LETTER I
     CA |  000000AD | SOFT HYPHEN
     CB |  000000F4 | LATIN SMALL LETTER O WITH CIRCUMFLEX
     CC |  000000F6 | LATIN SMALL LETTER O WITH DIAERESIS
     CD |  000000F2 | LATIN SMALL LETTER O WITH GRAVE
     CE |  000000F3 | LATIN SMALL LETTER O WITH ACUTE
     CF |  000000F5 | LATIN SMALL LETTER O WITH TILDE
     D0 |  0000007D | RIGHT CURLY BRACKET
     D1 |  0000004A | LATIN CAPITAL LETTER J
     D2 |  0000004B | LATIN CAPITAL LETTER K
     D3 |  0000004C | LATIN CAPITAL LETTER L
     D4 |  0000004D | LATIN CAPITAL LETTER M
     D5 |  0000004E | LATIN CAPITAL LETTER N
     D6 |  0000004F | LATIN CAPITAL LETTER O
     D7 |  00000050 | LATIN CAPITAL LETTER P
     D8 |  00000051 | LATIN CAPITAL LETTER Q
     D9 |  00000052 | LATIN CAPITAL LETTER R
     DA |  000000B9 | SUPERSCRIPT ONE
     DB |  000000FB | LATIN SMALL LETTER U WITH CIRCUMFLEX
     DC |  000000FC | LATIN SMALL LETTER U WITH DIAERESIS
     DD |  000000F9 | LATIN SMALL LETTER U WITH GRAVE
     DE |  000000FA | LATIN SMALL LETTER U WITH ACUTE
     DF |  000000FF | LATIN SMALL LETTER Y WITH DIAERESIS
     E0 |  0000005C | REVERSE SOLIDUS
     E1 |  000000F7 | DIVISION SIGN
     E2 |  00000053 | LATIN CAPITAL LETTER S
     E3 |  00000054 | LATIN CAPITAL LETTER T
     E4 |  00000055 | LATIN CAPITAL LETTER U
     E5 |  00000056 | LATIN CAPITAL LETTER V
     E6 |  00000057 | LATIN CAPITAL LETTER W
     E7 |  00000058 | LATIN CAPITAL LETTER X
     E8 |  00000059 | LATIN CAPITAL LETTER Y
     E9 |  0000005A | LATIN CAPITAL LETTER Z
     EA |  000000B2 | SUPERSCRIPT TWO
     EB |  000000D4 | LATIN CAPITAL LETTER O WITH CIRCUMFLEX
     EC |  000000D6 | LATIN CAPITAL LETTER O WITH DIAERESIS
     ED |  000000D2 | LATIN CAPITAL LETTER O WITH GRAVE
     EE |  000000D3 | LATIN CAPITAL LETTER O WITH ACUTE
     EF |  000000D5 | LATIN CAPITAL LETTER O WITH TILDE
     F0 |  00000030 | DIGIT ZERO
     F1 |  00000031 | DIGIT ONE
     F2 |  00000032 | DIGIT TWO
     F3 |  00000033 | DIGIT THREE
     F4 |  00000034 | DIGIT FOUR
     F5 |  00000035 | DIGIT FIVE
     F6 |  00000036 | DIGIT SIX
     F7 |  00000037 | DIGIT SEVEN
     F8 |  00000038 | DIGIT EIGHT
     F9 |  00000039 | DIGIT NINE
     FA |  000000B3 | SUPERSCRIPT THREE
     FB |  000000DB | LATIN CAPITAL LETTER U WITH CIRCUMFLEX
     FC |  000000DC | LATIN CAPITAL LETTER U WITH DIAERESIS
     FD |  000000D9 | LATIN CAPITAL LETTER U WITH GRAVE
     FE |  000000DA | LATIN CAPITAL LETTER U WITH ACUTE
     FF |  0000009F | APPLICATION PROGRAM COMMAND (APC)
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/IBM285.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for IBM285.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::IBM285;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x009c,
     0x0009,
     0x0086,
     0x007f,
     0x0097,
     0x008d,
     0x008e,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x009d,
     0x0085,
     0x0008,
     0x0087,
     0x0018,
     0x0019,
     0x0092,
     0x008f,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0080,
     0x0081,
     0x0082,
     0x0083,
     0x0084,
     0x000a,
     0x0017,
     0x001b,
     0x0088,
     0x0089,
     0x008a,
     0x008b,
     0x008c,
     0x0005,
     0x0006,
     0x0007,
     0x0090,
     0x0091,
     0x0016,
     0x0093,
     0x0094,
     0x0095,
     0x0096,
     0x0004,
     0x0098,
     0x0099,
     0x009a,
     0x009b,
     0x0014,
     0x0015,
     0x009e,
     0x001a,
     0x0020,
     0x00a0,
     0x00e2,
     0x00e4,
     0x00e0,
     0x00e1,
     0x00e3,
     0x00e5,
     0x00e7,
     0x00f1,
     0x0024,
     0x002e,
     0x003c,
     0x0028,
     0x002b,
     0x007c,
     0x0026,
     0x00e9,
     0x00ea,
     0x00eb,
     0x00e8,
     0x00ed,
     0x00ee,
     0x00ef,
     0x00ec,
     0x00df,
     0x0021,
     0x00a3,
     0x002a,
     0x0029,
     0x003b,
     0x00ac,
     0x002d,
     0x002f,
     0x00c2,
     0x00c4,
     0x00c0,
     0x00c1,
     0x00c3,
     0x00c5,
     0x00c7,
     0x00d1,
     0x00a6,
     0x002c,
     0x0025,
     0x005f,
     0x003e,
     0x003f,
     0x00f8,
     0x00c9,
     0x00ca,
     0x00cb,
     0x00c8,
     0x00cd,
     0x00ce,
     0x00cf,
     0x00cc,
     0x0060,
     0x003a,
     0x0023,
     0x0040,
     0x0027,
     0x003d,
     0x0022,
     0x00d8,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x00ab,
     0x00bb,
     0x00f0,
     0x00fd,
     0x00fe,
     0x00b1,
     0x00b0,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x00aa,
     0x00ba,
     0x00e6,
     0x00b8,
     0x00c6,
     0x00a4,
     0x00b5,
     0x203e,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x00a1,
     0x00bf,
     0x00d0,
     0x00dd,
     0x00de,
     0x00ae,
     0x00a2,
     0x005b,
     0x00a5,
     0x00b7,
     0x00a9,
     0x00a7,
     0x00b6,
     0x00bc,
     0x00bd,
     0x00be,
     0x005e,
     0x005d,
     0x007e,
     0x00a8,
     0x00b4,
     0x00d7,
     0x007b,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x00ad,
     0x00f4,
     0x00f6,
     0x00f2,
     0x00f3,
     0x00f5,
     0x007d,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x00b9,
     0x00fb,
     0x00fc,
     0x00f9,
     0x00fa,
     0x00ff,
     0x005c,
     0x00f7,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x00b2,
     0x00d4,
     0x00d6,
     0x00d2,
     0x00d3,
     0x00d5,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x00b3,
     0x00db,
     0x00dc,
     0x00d9,
     0x00da,
     0x009f,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\xc2\x9c",
     "\x09",
     "\xc2\x86",
     "\x7f",
     "\xc2\x97",
     "\xc2\x8d",
     "\xc2\x8e",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\xc2\x9d",
     "\xc2\x85",
     "\x08",
     "\xc2\x87",
     "\x18",
     "\x19",
     "\xc2\x92",
     "\xc2\x8f",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\xc2\x80",
     "\xc2\x81",
     "\xc2\x82",
     "\xc2\x83",
     "\xc2\x84",
     "\x0a",
     "\x17",
     "\x1b",
     "\xc2\x88",
     "\xc2\x89",
     "\xc2\x8a",
     "\xc2\x8b",
     "\xc2\x8c",
     "\x05",
     "\x06",
     "\x07",
     "\xc2\x90",
     "\xc2\x91",
     "\x16",
     "\xc2\x93",
     "\xc2\x94",
     "\xc2\x95",
     "\xc2\x96",
     "\x04",
     "\xc2\x98",
     "\xc2\x99",
     "\xc2\x9a",
     "\xc2\x9b",
     "\x14",
     "\x15",
     "\xc2\x9e",
     "\x1a",
     "\x20",
     "\xc2\xa0",
     "\xc3\xa2",
     "\xc3\xa4",
     "\xc3\xa0",
     "\xc3\xa1",
     "\xc3\xa3",
     "\xc3\xa5",
     "\xc3\xa7",
     "\xc3\xb1",
     "\x24",
     "\x2e",
     "\x3c",
     "\x28",
     "\x2b",
     "\x7c",
     "\x26",
     "\xc3\xa9",
     "\xc3\xaa",
     "\xc3\xab",
     "\xc3\xa8",
     "\xc3\xad",
     "\xc3\xae",
     "\xc3\xaf",
     "\xc3\xac",
     "\xc3\x9f",
     "\x21",
     "\xc2\xa3",
     "\x2a",
     "\x29",
     "\x3b",
     "\xc2\xac",
     "\x2d",
     "\x2f",
     "\xc3\x82",
     "\xc3\x84",
     "\xc3\x80",
     "\xc3\x81",
     "\xc3\x83",
     "\xc3\x85",
     "\xc3\x87",
     "\xc3\x91",
     "\xc2\xa6",
     "\x2c",
     "\x25",
     "\x5f",
     "\x3e",
     "\x3f",
     "\xc3\xb8",
     "\xc3\x89",
     "\xc3\x8a",
     "\xc3\x8b",
     "\xc3\x88",
     "\xc3\x8d",
     "\xc3\x8e",
     "\xc3\x8f",
     "\xc3\x8c",
     "\x60",
     "\x3a",
     "\x23",
     "\x40",
     "\x27",
     "\x3d",
     "\x22",
     "\xc3\x98",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\xc2\xab",
     "\xc2\xbb",
     "\xc3\xb0",
     "\xc3\xbd",
     "\xc3\xbe",
     "\xc2\xb1",
     "\xc2\xb0",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\xc2\xaa",
     "\xc2\xba",
     "\xc3\xa6",
     "\xc2\xb8",
     "\xc3\x86",
     "\xc2\xa4",
     "\xc2\xb5",
     "\xe2\x80\xbe",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\xc2\xa1",
     "\xc2\xbf",
     "\xc3\x90",
     "\xc3\x9d",
     "\xc3\x9e",
     "\xc2\xae",
     "\xc2\xa2",
     "\x5b",
     "\xc2\xa5",
     "\xc2\xb7",
     "\xc2\xa9",
     "\xc2\xa7",
     "\xc2\xb6",
     "\xc2\xbc",
     "\xc2\xbd",
     "\xc2\xbe",
     "\x5e",
     "\x5d",
     "\x7e",
     "\xc2\xa8",
     "\xc2\xb4",
     "\xc3\x97",
     "\x7b",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\xc2\xad",
     "\xc3\xb4",
     "\xc3\xb6",
     "\xc3\xb2",
     "\xc3\xb3",
     "\xc3\xb5",
     "\x7d",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\xc2\xb9",
     "\xc3\xbb",
     "\xc3\xbc",
     "\xc3\xb9",
     "\xc3\xba",
     "\xc3\xbf",
     "\x5c",
     "\xc3\xb7",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\xc2\xb2",
     "\xc3\x94",
     "\xc3\x96",
     "\xc3\x92",
     "\xc3\x93",
     "\xc3\x95",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\xc2\xb3",
     "\xc3\x9b",
     "\xc3\x9c",
     "\xc3\x99",
     "\xc3\x9a",
     "\xc2\x9f",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x37",
     0x00000005 => "\x2d",
     0x00000006 => "\x2e",
     0x00000007 => "\x2f",
     0x00000008 => "\x16",
     0x00000009 => "\x05",
     0x0000000a => "\x25",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x3c",
     0x00000015 => "\x3d",
     0x00000016 => "\x32",
     0x00000017 => "\x26",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x3f",
     0x0000001b => "\x27",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x40",
     0x00000021 => "\x5a",
     0x00000022 => "\x7f",
     0x00000023 => "\x7b",
     0x00000024 => "\x4a",
     0x00000025 => "\x6c",
     0x00000026 => "\x50",
     0x00000027 => "\x7d",
     0x00000028 => "\x4d",
     0x00000029 => "\x5d",
     0x0000002a => "\x5c",
     0x0000002b => "\x4e",
     0x0000002c => "\x6b",
     0x0000002d => "\x60",
     0x0000002e => "\x4b",
     0x0000002f => "\x61",
     0x00000030 => "\xf0",
     0x00000031 => "\xf1",
     0x00000032 => "\xf2",
     0x00000033 => "\xf3",
     0x00000034 => "\xf4",
     0x00000035 => "\xf5",
     0x00000036 => "\xf6",
     0x00000037 => "\xf7",
     0x00000038 => "\xf8",
     0x00000039 => "\xf9",
     0x0000003a => "\x7a",
     0x0000003b => "\x5e",
     0x0000003c => "\x4c",
     0x0000003d => "\x7e",
     0x0000003e => "\x6e",
     0x0000003f => "\x6f",
     0x00000040 => "\x7c",
     0x00000041 => "\xc1",
     0x00000042 => "\xc2",
     0x00000043 => "\xc3",
     0x00000044 => "\xc4",
     0x00000045 => "\xc5",
     0x00000046 => "\xc6",
     0x00000047 => "\xc7",
     0x00000048 => "\xc8",
     0x00000049 => "\xc9",
     0x0000004a => "\xd1",
     0x0000004b => "\xd2",
     0x0000004c => "\xd3",
     0x0000004d => "\xd4",
     0x0000004e => "\xd5",
     0x0000004f => "\xd6",
     0x00000050 => "\xd7",
     0x00000051 => "\xd8",
     0x00000052 => "\xd9",
     0x00000053 => "\xe2",
     0x00000054 => "\xe3",
     0x00000055 => "\xe4",
     0x00000056 => "\xe5",
     0x00000057 => "\xe6",
     0x00000058 => "\xe7",
     0x00000059 => "\xe8",
     0x0000005a => "\xe9",
     0x0000005b => "\xb1",
     0x0000005c => "\xe0",
     0x0000005d => "\xbb",
     0x0000005e => "\xba",
     0x0000005f => "\x6d",
     0x00000060 => "\x79",
     0x00000061 => "\x81",
     0x00000062 => "\x82",
     0x00000063 => "\x83",
     0x00000064 => "\x84",
     0x00000065 => "\x85",
     0x00000066 => "\x86",
     0x00000067 => "\x87",
     0x00000068 => "\x88",
     0x00000069 => "\x89",
     0x0000006a => "\x91",
     0x0000006b => "\x92",
     0x0000006c => "\x93",
     0x0000006d => "\x94",
     0x0000006e => "\x95",
     0x0000006f => "\x96",
     0x00000070 => "\x97",
     0x00000071 => "\x98",
     0x00000072 => "\x99",
     0x00000073 => "\xa2",
     0x00000074 => "\xa3",
     0x00000075 => "\xa4",
     0x00000076 => "\xa5",
     0x00000077 => "\xa6",
     0x00000078 => "\xa7",
     0x00000079 => "\xa8",
     0x0000007a => "\xa9",
     0x0000007b => "\xc0",
     0x0000007c => "\x4f",
     0x0000007d => "\xd0",
     0x0000007e => "\xbc",
     0x0000007f => "\x07",
     0x00000080 => "\x20",
     0x00000081 => "\x21",
     0x00000082 => "\x22",
     0x00000083 => "\x23",
     0x00000084 => "\x24",
     0x00000085 => "\x15",
     0x00000086 => "\x06",
     0x00000087 => "\x17",
     0x00000088 => "\x28",
     0x00000089 => "\x29",
     0x0000008a => "\x2a",
     0x0000008b => "\x2b",
     0x0000008c => "\x2c",
     0x0000008d => "\x09",
     0x0000008e => "\x0a",
     0x0000008f => "\x1b",
     0x00000090 => "\x30",
     0x00000091 => "\x31",
     0x00000092 => "\x1a",
     0x00000093 => "\x33",
     0x00000094 => "\x34",
     0x00000095 => "\x35",
     0x00000096 => "\x36",
     0x00000097 => "\x08",
     0x00000098 => "\x38",
     0x00000099 => "\x39",
     0x0000009a => "\x3a",
     0x0000009b => "\x3b",
     0x0000009c => "\x04",
     0x0000009d => "\x14",
     0x0000009e => "\x3e",
     0x0000009f => "\xff",
     0x000000a0 => "\x41",
     0x000000a1 => "\xaa",
     0x000000a2 => "\xb0",
     0x000000a3 => "\x5b",
     0x000000a4 => "\x9f",
     0x000000a5 => "\xb2",
     0x000000a6 => "\x6a",
     0x000000a7 => "\xb5",
     0x000000a8 => "\xbd",
     0x000000a9 => "\xb4",
     0x000000aa => "\x9a",
     0x000000ab => "\x8a",
     0x000000ac => "\x5f",
     0x000000ad => "\xca",
     0x000000ae => "\xaf",
     0x000000b0 => "\x90",
     0x000000b1 => "\x8f",
     0x000000b2 => "\xea",
     0x000000b3 => "\xfa",
     0x000000b4 => "\xbe",
     0x000000b5 => "\xa0",
     0x000000b6 => "\xb6",
     0x000000b7 => "\xb3",
     0x000000b8 => "\x9d",
     0x000000b9 => "\xda",
     0x000000ba => "\x9b",
     0x000000bb => "\x8b",
     0x000000bc => "\xb7",
     0x000000bd => "\xb8",
     0x000000be => "\xb9",
     0x000000bf => "\xab",
     0x000000c0 => "\x64",
     0x000000c1 => "\x65",
     0x000000c2 => "\x62",
     0x000000c3 => "\x66",
     0x000000c4 => "\x63",
     0x000000c5 => "\x67",
     0x000000c6 => "\x9e",
     0x000000c7 => "\x68",
     0x000000c8 => "\x74",
     0x000000c9 => "\x71",
     0x000000ca => "\x72",
     0x000000cb => "\x73",
     0x000000cc => "\x78",
     0x000000cd => "\x75",
     0x000000ce => "\x76",
     0x000000cf => "\x77",
     0x000000d0 => "\xac",
     0x000000d1 => "\x69",
     0x000000d2 => "\xed",
     0x000000d3 => "\xee",
     0x000000d4 => "\xeb",
     0x000000d5 => "\xef",
     0x000000d6 => "\xec",
     0x000000d7 => "\xbf",
     0x000000d8 => "\x80",
     0x000000d9 => "\xfd",
     0x000000da => "\xfe",
     0x000000db => "\xfb",
     0x000000dc => "\xfc",
     0x000000dd => "\xad",
     0x000000de => "\xae",
     0x000000df => "\x59",
     0x000000e0 => "\x44",
     0x000000e1 => "\x45",
     0x000000e2 => "\x42",
     0x000000e3 => "\x46",
     0x000000e4 => "\x43",
     0x000000e5 => "\x47",
     0x000000e6 => "\x9c",
     0x000000e7 => "\x48",
     0x000000e8 => "\x54",
     0x000000e9 => "\x51",
     0x000000ea => "\x52",
     0x000000eb => "\x53",
     0x000000ec => "\x58",
     0x000000ed => "\x55",
     0x000000ee => "\x56",
     0x000000ef => "\x57",
     0x000000f0 => "\x8c",
     0x000000f1 => "\x49",
     0x000000f2 => "\xcd",
     0x000000f3 => "\xce",
     0x000000f4 => "\xcb",
     0x000000f5 => "\xcf",
     0x000000f6 => "\xcc",
     0x000000f7 => "\xe1",
     0x000000f8 => "\x70",
     0x000000f9 => "\xdd",
     0x000000fa => "\xde",
     0x000000fb => "\xdb",
     0x000000fc => "\xdc",
     0x000000fd => "\x8d",
     0x000000fe => "\x8e",
     0x000000ff => "\xdf",
     0x0000203e => "\xa1",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x6f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::IBM285 - Conversion routines for IBM285
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for IBM285.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
   source: IBM NLS RM Vol2 SE09-8002-01, March 1990
  alias CP285
  alias EBCDIC-CP-GB
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  0000009C | STRING TERMINATOR (ST)
     05 |  00000009 | CHARACTER TABULATION (HT)
     06 |  00000086 | START OF SELECTED AREA (SSA)
     07 |  0000007F | DELETE (DEL)
     08 |  00000097 | END OF GUARDED AREA (EPA)
     09 |  0000008D | REVERSE LINE FEED (RI)
     0A |  0000008E | SINGLE-SHIFT TWO (SS2)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  0000009D | OPERATING SYSTEM COMMAND (OSC)
     15 |  00000085 | NEXT LINE (NEL)
     16 |  00000008 | BACKSPACE (BS)
     17 |  00000087 | END OF SELECTED AREA (ESA)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  00000092 | PRIVATE USE TWO (PU2)
     1B |  0000008F | SINGLE-SHIFT THREE (SS3)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000080 | PADDING CHARACTER (PAD)
     21 |  00000081 | HIGH OCTET PRESET (HOP)
     22 |  00000082 | BREAK PERMITTED HERE (BPH)
     23 |  00000083 | NO BREAK HERE (NBH)
     24 |  00000084 | INDEX (IND)
     25 |  0000000A | LINE FEED (LF)
     26 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     27 |  0000001B | ESCAPE (ESC)
     28 |  00000088 | CHARACTER TABULATION SET (HTS)
     29 |  00000089 | CHARACTER TABULATION WITH JUSTIFICATION (HTJ)
     2A |  0000008A | LINE TABULATION SET (VTS)
     2B |  0000008B | PARTIAL LINE FORWARD (PLD)
     2C |  0000008C | PARTIAL LINE BACKWARD (PLU)
     2D |  00000005 | ENQUIRY (ENQ)
     2E |  00000006 | ACKNOWLEDGE (ACK)
     2F |  00000007 | BELL (BEL)
     30 |  00000090 | DEVICE CONTROL STRING (DCS)
     31 |  00000091 | PRIVATE USE ONE (PU1)
     32 |  00000016 | SYNCHRONOUS IDLE (SYN)
     33 |  00000093 | SET TRANSMIT STATE (STS)
     34 |  00000094 | CANCEL CHARACTER (CCH)
     35 |  00000095 | MESSAGE WAITING (MW)
     36 |  00000096 | START OF GUARDED AREA (SPA)
     37 |  00000004 | END OF TRANSMISSION (EOT)
     38 |  00000098 | START OF STRING (SOS)
     39 |  00000099 | SINGLE GRAPHIC CHARACTER INTRODUCER (SGCI)
     3A |  0000009A | SINGLE CHARACTER INTRODUCER (SCI)
     3B |  0000009B | CONTROL SEQUENCE INTRODUCER (CSI)
     3C |  00000014 | DEVICE CONTROL FOUR (DC4)
     3D |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     3E |  0000009E | PRIVACY MESSAGE (PM)
     3F |  0000001A | SUBSTITUTE (SUB)
     40 |  00000020 | SPACE
     41 |  000000A0 | NO-BREAK SPACE
     42 |  000000E2 | LATIN SMALL LETTER A WITH CIRCUMFLEX
     43 |  000000E4 | LATIN SMALL LETTER A WITH DIAERESIS
     44 |  000000E0 | LATIN SMALL LETTER A WITH GRAVE
     45 |  000000E1 | LATIN SMALL LETTER A WITH ACUTE
     46 |  000000E3 | LATIN SMALL LETTER A WITH TILDE
     47 |  000000E5 | LATIN SMALL LETTER A WITH RING ABOVE
     48 |  000000E7 | LATIN SMALL LETTER C WITH CEDILLA
     49 |  000000F1 | LATIN SMALL LETTER N WITH TILDE
     4A |  00000024 | DOLLAR SIGN
     4B |  0000002E | FULL STOP
     4C |  0000003C | LESS-THAN SIGN
     4D |  00000028 | LEFT PARENTHESIS
     4E |  0000002B | PLUS SIGN
     4F |  0000007C | VERTICAL LINE
     50 |  00000026 | AMPERSAND
     51 |  000000E9 | LATIN SMALL LETTER E WITH ACUTE
     52 |  000000EA | LATIN SMALL LETTER E WITH CIRCUMFLEX
     53 |  000000EB | LATIN SMALL LETTER E WITH DIAERESIS
     54 |  000000E8 | LATIN SMALL LETTER E WITH GRAVE
     55 |  000000ED | LATIN SMALL LETTER I WITH ACUTE
     56 |  000000EE | LATIN SMALL LETTER I WITH CIRCUMFLEX
     57 |  000000EF | LATIN SMALL LETTER I WITH DIAERESIS
     58 |  000000EC | LATIN SMALL LETTER I WITH GRAVE
     59 |  000000DF | LATIN SMALL LETTER SHARP S (German)
     5A |  00000021 | EXCLAMATION MARK
     5B |  000000A3 | POUND SIGN
     5C |  0000002A | ASTERISK
     5D |  00000029 | RIGHT PARENTHESIS
     5E |  0000003B | SEMICOLON
     5F |  000000AC | NOT SIGN
     60 |  0000002D | HYPHEN-MINUS
     61 |  0000002F | SOLIDUS
     62 |  000000C2 | LATIN CAPITAL LETTER A WITH CIRCUMFLEX
     63 |  000000C4 | LATIN CAPITAL LETTER A WITH DIAERESIS
     64 |  000000C0 | LATIN CAPITAL LETTER A WITH GRAVE
     65 |  000000C1 | LATIN CAPITAL LETTER A WITH ACUTE
     66 |  000000C3 | LATIN CAPITAL LETTER A WITH TILDE
     67 |  000000C5 | LATIN CAPITAL LETTER A WITH RING ABOVE
     68 |  000000C7 | LATIN CAPITAL LETTER C WITH CEDILLA
     69 |  000000D1 | LATIN CAPITAL LETTER N WITH TILDE
     6A |  000000A6 | BROKEN BAR
     6B |  0000002C | COMMA
     6C |  00000025 | PERCENT SIGN
     6D |  0000005F | LOW LINE
     6E |  0000003E | GREATER-THAN SIGN
     6F |  0000003F | QUESTION MARK
     70 |  000000F8 | LATIN SMALL LETTER O WITH STROKE
     71 |  000000C9 | LATIN CAPITAL LETTER E WITH ACUTE
     72 |  000000CA | LATIN CAPITAL LETTER E WITH CIRCUMFLEX
     73 |  000000CB | LATIN CAPITAL LETTER E WITH DIAERESIS
     74 |  000000C8 | LATIN CAPITAL LETTER E WITH GRAVE
     75 |  000000CD | LATIN CAPITAL LETTER I WITH ACUTE
     76 |  000000CE | LATIN CAPITAL LETTER I WITH CIRCUMFLEX
     77 |  000000CF | LATIN CAPITAL LETTER I WITH DIAERESIS
     78 |  000000CC | LATIN CAPITAL LETTER I WITH GRAVE
     79 |  00000060 | GRAVE ACCENT
     7A |  0000003A | COLON
     7B |  00000023 | NUMBER SIGN
     7C |  00000040 | COMMERCIAL AT
     7D |  00000027 | APOSTROPHE
     7E |  0000003D | EQUALS SIGN
     7F |  00000022 | QUOTATION MARK
     80 |  000000D8 | LATIN CAPITAL LETTER O WITH STROKE
     81 |  00000061 | LATIN SMALL LETTER A
     82 |  00000062 | LATIN SMALL LETTER B
     83 |  00000063 | LATIN SMALL LETTER C
     84 |  00000064 | LATIN SMALL LETTER D
     85 |  00000065 | LATIN SMALL LETTER E
     86 |  00000066 | LATIN SMALL LETTER F
     87 |  00000067 | LATIN SMALL LETTER G
     88 |  00000068 | LATIN SMALL LETTER H
     89 |  00000069 | LATIN SMALL LETTER I
     8A |  000000AB | LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
     8B |  000000BB | RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
     8C |  000000F0 | LATIN SMALL LETTER ETH (Icelandic)
     8D |  000000FD | LATIN SMALL LETTER Y WITH ACUTE
     8E |  000000FE | LATIN SMALL LETTER THORN (Icelandic)
     8F |  000000B1 | PLUS-MINUS SIGN
     90 |  000000B0 | DEGREE SIGN
     91 |  0000006A | LATIN SMALL LETTER J
     92 |  0000006B | LATIN SMALL LETTER K
     93 |  0000006C | LATIN SMALL LETTER L
     94 |  0000006D | LATIN SMALL LETTER M
     95 |  0000006E | LATIN SMALL LETTER N
     96 |  0000006F | LATIN SMALL LETTER O
     97 |  00000070 | LATIN SMALL LETTER P
     98 |  00000071 | LATIN SMALL LETTER Q
     99 |  00000072 | LATIN SMALL LETTER R
     9A |  000000AA | FEMININE ORDINAL INDICATOR
     9B |  000000BA | MASCULINE ORDINAL INDICATOR
     9C |  000000E6 | LATIN SMALL LETTER AE
     9D |  000000B8 | CEDILLA
     9E |  000000C6 | LATIN CAPITAL LETTER AE
     9F |  000000A4 | CURRENCY SIGN
     A0 |  000000B5 | MICRO SIGN
     A1 |  0000203E | OVERLINE
     A2 |  00000073 | LATIN SMALL LETTER S
     A3 |  00000074 | LATIN SMALL LETTER T
     A4 |  00000075 | LATIN SMALL LETTER U
     A5 |  00000076 | LATIN SMALL LETTER V
     A6 |  00000077 | LATIN SMALL LETTER W
     A7 |  00000078 | LATIN SMALL LETTER X
     A8 |  00000079 | LATIN SMALL LETTER Y
     A9 |  0000007A | LATIN SMALL LETTER Z
     AA |  000000A1 | INVERTED EXCLAMATION MARK
     AB |  000000BF | INVERTED QUESTION MARK
     AC |  000000D0 | LATIN CAPITAL LETTER ETH (Icelandic)
     AD |  000000DD | LATIN CAPITAL LETTER Y WITH ACUTE
     AE |  000000DE | LATIN CAPITAL LETTER THORN (Icelandic)
     AF |  000000AE | REGISTERED SIGN
     B0 |  000000A2 | CENT SIGN
     B1 |  0000005B | LEFT SQUARE BRACKET
     B2 |  000000A5 | YEN SIGN
     B3 |  000000B7 | MIDDLE DOT
     B4 |  000000A9 | COPYRIGHT SIGN
     B5 |  000000A7 | SECTION SIGN
     B6 |  000000B6 | PILCROW SIGN
     B7 |  000000BC | VULGAR FRACTION ONE QUARTER
     B8 |  000000BD | VULGAR FRACTION ONE HALF
     B9 |  000000BE | VULGAR FRACTION THREE QUARTERS
     BA |  0000005E | CIRCUMFLEX ACCENT
     BB |  0000005D | RIGHT SQUARE BRACKET
     BC |  0000007E | TILDE
     BD |  000000A8 | DIAERESIS
     BE |  000000B4 | ACUTE ACCENT
     BF |  000000D7 | MULTIPLICATION SIGN
     C0 |  0000007B | LEFT CURLY BRACKET
     C1 |  00000041 | LATIN CAPITAL LETTER A
     C2 |  00000042 | LATIN CAPITAL LETTER B
     C3 |  00000043 | LATIN CAPITAL LETTER C
     C4 |  00000044 | LATIN CAPITAL LETTER D
     C5 |  00000045 | LATIN CAPITAL LETTER E
     C6 |  00000046 | LATIN CAPITAL LETTER F
     C7 |  00000047 | LATIN CAPITAL LETTER G
     C8 |  00000048 | LATIN CAPITAL LETTER H
     C9 |  00000049 | LATIN CAPITAL LETTER I
     CA |  000000AD | SOFT HYPHEN
     CB |  000000F4 | LATIN SMALL LETTER O WITH CIRCUMFLEX
     CC |  000000F6 | LATIN SMALL LETTER O WITH DIAERESIS
     CD |  000000F2 | LATIN SMALL LETTER O WITH GRAVE
     CE |  000000F3 | LATIN SMALL LETTER O WITH ACUTE
     CF |  000000F5 | LATIN SMALL LETTER O WITH TILDE
     D0 |  0000007D | RIGHT CURLY BRACKET
     D1 |  0000004A | LATIN CAPITAL LETTER J
     D2 |  0000004B | LATIN CAPITAL LETTER K
     D3 |  0000004C | LATIN CAPITAL LETTER L
     D4 |  0000004D | LATIN CAPITAL LETTER M
     D5 |  0000004E | LATIN CAPITAL LETTER N
     D6 |  0000004F | LATIN CAPITAL LETTER O
     D7 |  00000050 | LATIN CAPITAL LETTER P
     D8 |  00000051 | LATIN CAPITAL LETTER Q
     D9 |  00000052 | LATIN CAPITAL LETTER R
     DA |  000000B9 | SUPERSCRIPT ONE
     DB |  000000FB | LATIN SMALL LETTER U WITH CIRCUMFLEX
     DC |  000000FC | LATIN SMALL LETTER U WITH DIAERESIS
     DD |  000000F9 | LATIN SMALL LETTER U WITH GRAVE
     DE |  000000FA | LATIN SMALL LETTER U WITH ACUTE
     DF |  000000FF | LATIN SMALL LETTER Y WITH DIAERESIS
     E0 |  0000005C | REVERSE SOLIDUS
     E1 |  000000F7 | DIVISION SIGN
     E2 |  00000053 | LATIN CAPITAL LETTER S
     E3 |  00000054 | LATIN CAPITAL LETTER T
     E4 |  00000055 | LATIN CAPITAL LETTER U
     E5 |  00000056 | LATIN CAPITAL LETTER V
     E6 |  00000057 | LATIN CAPITAL LETTER W
     E7 |  00000058 | LATIN CAPITAL LETTER X
     E8 |  00000059 | LATIN CAPITAL LETTER Y
     E9 |  0000005A | LATIN CAPITAL LETTER Z
     EA |  000000B2 | SUPERSCRIPT TWO
     EB |  000000D4 | LATIN CAPITAL LETTER O WITH CIRCUMFLEX
     EC |  000000D6 | LATIN CAPITAL LETTER O WITH DIAERESIS
     ED |  000000D2 | LATIN CAPITAL LETTER O WITH GRAVE
     EE |  000000D3 | LATIN CAPITAL LETTER O WITH ACUTE
     EF |  000000D5 | LATIN CAPITAL LETTER O WITH TILDE
     F0 |  00000030 | DIGIT ZERO
     F1 |  00000031 | DIGIT ONE
     F2 |  00000032 | DIGIT TWO
     F3 |  00000033 | DIGIT THREE
     F4 |  00000034 | DIGIT FOUR
     F5 |  00000035 | DIGIT FIVE
     F6 |  00000036 | DIGIT SIX
     F7 |  00000037 | DIGIT SEVEN
     F8 |  00000038 | DIGIT EIGHT
     F9 |  00000039 | DIGIT NINE
     FA |  000000B3 | SUPERSCRIPT THREE
     FB |  000000DB | LATIN CAPITAL LETTER U WITH CIRCUMFLEX
     FC |  000000DC | LATIN CAPITAL LETTER U WITH DIAERESIS
     FD |  000000D9 | LATIN CAPITAL LETTER U WITH GRAVE
     FE |  000000DA | LATIN CAPITAL LETTER U WITH ACUTE
     FF |  0000009F | APPLICATION PROGRAM COMMAND (APC)
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/IBM290.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for IBM290.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::IBM290;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x009c,
     0x0009,
     0x0086,
     0x007f,
     0x0097,
     0x008d,
     0x008e,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x009d,
     0x0085,
     0x0008,
     0x0087,
     0x0018,
     0x0019,
     0x0092,
     0x008f,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0080,
     0x0081,
     0x0082,
     0x0083,
     0x0084,
     0x000a,
     0x0017,
     0x001b,
     0x0088,
     0x0089,
     0x008a,
     0x008b,
     0x008c,
     0x0005,
     0x0006,
     0x0007,
     0x0090,
     0x0091,
     0x0016,
     0x0093,
     0x0094,
     0x0095,
     0x0096,
     0x0004,
     0x0098,
     0x0099,
     0x009a,
     0x009b,
     0x0014,
     0x0015,
     0x009e,
     0x001a,
     0x0020,
     0x3002,
     0x300c,
     0x300d,
     0x3001,
     0x30fb,
     0x30f2,
     0x30a1,
     0x30a3,
     0x30a5,
     0x00a3,
     0x002e,
     0x003c,
     0x0028,
     0x002b,
     0x007c,
     0x0026,
     0x30a7,
     0x30a9,
     0x30e3,
     0x30e5,
     0x30e7,
     0x30c3,
     0xfffd,
     0x30fc,
     0xfffd,
     0x0021,
     0x00a5,
     0x002a,
     0x0029,
     0x003b,
     0x00ac,
     0x002d,
     0x002f,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00a6,
     0x002c,
     0x0025,
     0x005f,
     0x003e,
     0x003f,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x0060,
     0x003a,
     0x0023,
     0x0040,
     0x0027,
     0x003d,
     0x0022,
     0xfffd,
     0x30a2,
     0x30a4,
     0x30a6,
     0x30a8,
     0x30aa,
     0x30ab,
     0x30ad,
     0x30af,
     0x30b1,
     0x30b3,
     0xfffd,
     0x30b5,
     0x30b7,
     0x30b9,
     0x30bb,
     0x30bd,
     0x30bf,
     0x30c1,
     0x30c4,
     0x30c6,
     0x30c8,
     0x30ca,
     0x30cb,
     0x30cc,
     0x30cd,
     0x30ce,
     0xfffd,
     0xfffd,
     0x30cf,
     0x30d2,
     0x30d5,
     0xfffd,
     0x203e,
     0x30d8,
     0x30db,
     0x30de,
     0x30df,
     0x30e0,
     0x30e1,
     0x30e2,
     0x30e4,
     0x30e6,
     0xfffd,
     0x30e8,
     0x30e9,
     0x30ea,
     0x30eb,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x30ec,
     0x30ed,
     0x30ef,
     0x30f3,
     0x309b,
     0x309c,
     0xfffd,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x0024,
     0xfffd,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x009f,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\xc2\x9c",
     "\x09",
     "\xc2\x86",
     "\x7f",
     "\xc2\x97",
     "\xc2\x8d",
     "\xc2\x8e",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\xc2\x9d",
     "\xc2\x85",
     "\x08",
     "\xc2\x87",
     "\x18",
     "\x19",
     "\xc2\x92",
     "\xc2\x8f",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\xc2\x80",
     "\xc2\x81",
     "\xc2\x82",
     "\xc2\x83",
     "\xc2\x84",
     "\x0a",
     "\x17",
     "\x1b",
     "\xc2\x88",
     "\xc2\x89",
     "\xc2\x8a",
     "\xc2\x8b",
     "\xc2\x8c",
     "\x05",
     "\x06",
     "\x07",
     "\xc2\x90",
     "\xc2\x91",
     "\x16",
     "\xc2\x93",
     "\xc2\x94",
     "\xc2\x95",
     "\xc2\x96",
     "\x04",
     "\xc2\x98",
     "\xc2\x99",
     "\xc2\x9a",
     "\xc2\x9b",
     "\x14",
     "\x15",
     "\xc2\x9e",
     "\x1a",
     "\x20",
     "\xe3\x80\x82",
     "\xe3\x80\x8c",
     "\xe3\x80\x8d",
     "\xe3\x80\x81",
     "\xe3\x83\xbb",
     "\xe3\x83\xb2",
     "\xe3\x82\xa1",
     "\xe3\x82\xa3",
     "\xe3\x82\xa5",
     "\xc2\xa3",
     "\x2e",
     "\x3c",
     "\x28",
     "\x2b",
     "\x7c",
     "\x26",
     "\xe3\x82\xa7",
     "\xe3\x82\xa9",
     "\xe3\x83\xa3",
     "\xe3\x83\xa5",
     "\xe3\x83\xa7",
     "\xe3\x83\x83",
     "\xef\xbf\xbd",
     "\xe3\x83\xbc",
     "\xef\xbf\xbd",
     "\x21",
     "\xc2\xa5",
     "\x2a",
     "\x29",
     "\x3b",
     "\xc2\xac",
     "\x2d",
     "\x2f",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc2\xa6",
     "\x2c",
     "\x25",
     "\x5f",
     "\x3e",
     "\x3f",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x60",
     "\x3a",
     "\x23",
     "\x40",
     "\x27",
     "\x3d",
     "\x22",
     "\xef\xbf\xbd",
     "\xe3\x82\xa2",
     "\xe3\x82\xa4",
     "\xe3\x82\xa6",
     "\xe3\x82\xa8",
     "\xe3\x82\xaa",
     "\xe3\x82\xab",
     "\xe3\x82\xad",
     "\xe3\x82\xaf",
     "\xe3\x82\xb1",
     "\xe3\x82\xb3",
     "\xef\xbf\xbd",
     "\xe3\x82\xb5",
     "\xe3\x82\xb7",
     "\xe3\x82\xb9",
     "\xe3\x82\xbb",
     "\xe3\x82\xbd",
     "\xe3\x82\xbf",
     "\xe3\x83\x81",
     "\xe3\x83\x84",
     "\xe3\x83\x86",
     "\xe3\x83\x88",
     "\xe3\x83\x8a",
     "\xe3\x83\x8b",
     "\xe3\x83\x8c",
     "\xe3\x83\x8d",
     "\xe3\x83\x8e",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xe3\x83\x8f",
     "\xe3\x83\x92",
     "\xe3\x83\x95",
     "\xef\xbf\xbd",
     "\xe2\x80\xbe",
     "\xe3\x83\x98",
     "\xe3\x83\x9b",
     "\xe3\x83\x9e",
     "\xe3\x83\x9f",
     "\xe3\x83\xa0",
     "\xe3\x83\xa1",
     "\xe3\x83\xa2",
     "\xe3\x83\xa4",
     "\xe3\x83\xa6",
     "\xef\xbf\xbd",
     "\xe3\x83\xa8",
     "\xe3\x83\xa9",
     "\xe3\x83\xaa",
     "\xe3\x83\xab",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xe3\x83\xac",
     "\xe3\x83\xad",
     "\xe3\x83\xaf",
     "\xe3\x83\xb3",
     "\xe3\x82\x9b",
     "\xe3\x82\x9c",
     "\xef\xbf\xbd",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x24",
     "\xef\xbf\xbd",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc2\x9f",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x37",
     0x00000005 => "\x2d",
     0x00000006 => "\x2e",
     0x00000007 => "\x2f",
     0x00000008 => "\x16",
     0x00000009 => "\x05",
     0x0000000a => "\x25",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x3c",
     0x00000015 => "\x3d",
     0x00000016 => "\x32",
     0x00000017 => "\x26",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x3f",
     0x0000001b => "\x27",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x40",
     0x00000021 => "\x5a",
     0x00000022 => "\x7f",
     0x00000023 => "\x7b",
     0x00000024 => "\xe0",
     0x00000025 => "\x6c",
     0x00000026 => "\x50",
     0x00000027 => "\x7d",
     0x00000028 => "\x4d",
     0x00000029 => "\x5d",
     0x0000002a => "\x5c",
     0x0000002b => "\x4e",
     0x0000002c => "\x6b",
     0x0000002d => "\x60",
     0x0000002e => "\x4b",
     0x0000002f => "\x61",
     0x00000030 => "\xf0",
     0x00000031 => "\xf1",
     0x00000032 => "\xf2",
     0x00000033 => "\xf3",
     0x00000034 => "\xf4",
     0x00000035 => "\xf5",
     0x00000036 => "\xf6",
     0x00000037 => "\xf7",
     0x00000038 => "\xf8",
     0x00000039 => "\xf9",
     0x0000003a => "\x7a",
     0x0000003b => "\x5e",
     0x0000003c => "\x4c",
     0x0000003d => "\x7e",
     0x0000003e => "\x6e",
     0x0000003f => "\x6f",
     0x00000040 => "\x7c",
     0x00000041 => "\xc1",
     0x00000042 => "\xc2",
     0x00000043 => "\xc3",
     0x00000044 => "\xc4",
     0x00000045 => "\xc5",
     0x00000046 => "\xc6",
     0x00000047 => "\xc7",
     0x00000048 => "\xc8",
     0x00000049 => "\xc9",
     0x0000004a => "\xd1",
     0x0000004b => "\xd2",
     0x0000004c => "\xd3",
     0x0000004d => "\xd4",
     0x0000004e => "\xd5",
     0x0000004f => "\xd6",
     0x00000050 => "\xd7",
     0x00000051 => "\xd8",
     0x00000052 => "\xd9",
     0x00000053 => "\xe2",
     0x00000054 => "\xe3",
     0x00000055 => "\xe4",
     0x00000056 => "\xe5",
     0x00000057 => "\xe6",
     0x00000058 => "\xe7",
     0x00000059 => "\xe8",
     0x0000005a => "\xe9",
     0x0000005f => "\x6d",
     0x00000060 => "\x79",
     0x0000007c => "\x4f",
     0x0000007f => "\x07",
     0x00000080 => "\x20",
     0x00000081 => "\x21",
     0x00000082 => "\x22",
     0x00000083 => "\x23",
     0x00000084 => "\x24",
     0x00000085 => "\x15",
     0x00000086 => "\x06",
     0x00000087 => "\x17",
     0x00000088 => "\x28",
     0x00000089 => "\x29",
     0x0000008a => "\x2a",
     0x0000008b => "\x2b",
     0x0000008c => "\x2c",
     0x0000008d => "\x09",
     0x0000008e => "\x0a",
     0x0000008f => "\x1b",
     0x00000090 => "\x30",
     0x00000091 => "\x31",
     0x00000092 => "\x1a",
     0x00000093 => "\x33",
     0x00000094 => "\x34",
     0x00000095 => "\x35",
     0x00000096 => "\x36",
     0x00000097 => "\x08",
     0x00000098 => "\x38",
     0x00000099 => "\x39",
     0x0000009a => "\x3a",
     0x0000009b => "\x3b",
     0x0000009c => "\x04",
     0x0000009d => "\x14",
     0x0000009e => "\x3e",
     0x0000009f => "\xff",
     0x000000a3 => "\x4a",
     0x000000a5 => "\x5b",
     0x000000a6 => "\x6a",
     0x000000ac => "\x5f",
     0x0000203e => "\xa1",
     0x00003001 => "\x44",
     0x00003002 => "\x41",
     0x0000300c => "\x42",
     0x0000300d => "\x43",
     0x0000309b => "\xbe",
     0x0000309c => "\xbf",
     0x000030a1 => "\x47",
     0x000030a2 => "\x81",
     0x000030a3 => "\x48",
     0x000030a4 => "\x82",
     0x000030a5 => "\x49",
     0x000030a6 => "\x83",
     0x000030a7 => "\x51",
     0x000030a8 => "\x84",
     0x000030a9 => "\x52",
     0x000030aa => "\x85",
     0x000030ab => "\x86",
     0x000030ad => "\x87",
     0x000030af => "\x88",
     0x000030b1 => "\x89",
     0x000030b3 => "\x8a",
     0x000030b5 => "\x8c",
     0x000030b7 => "\x8d",
     0x000030b9 => "\x8e",
     0x000030bb => "\x8f",
     0x000030bd => "\x90",
     0x000030bf => "\x91",
     0x000030c1 => "\x92",
     0x000030c3 => "\x56",
     0x000030c4 => "\x93",
     0x000030c6 => "\x94",
     0x000030c8 => "\x95",
     0x000030ca => "\x96",
     0x000030cb => "\x97",
     0x000030cc => "\x98",
     0x000030cd => "\x99",
     0x000030ce => "\x9a",
     0x000030cf => "\x9d",
     0x000030d2 => "\x9e",
     0x000030d5 => "\x9f",
     0x000030d8 => "\xa2",
     0x000030db => "\xa3",
     0x000030de => "\xa4",
     0x000030df => "\xa5",
     0x000030e0 => "\xa6",
     0x000030e1 => "\xa7",
     0x000030e2 => "\xa8",
     0x000030e3 => "\x53",
     0x000030e4 => "\xa9",
     0x000030e5 => "\x54",
     0x000030e6 => "\xaa",
     0x000030e7 => "\x55",
     0x000030e8 => "\xac",
     0x000030e9 => "\xad",
     0x000030ea => "\xae",
     0x000030eb => "\xaf",
     0x000030ec => "\xba",
     0x000030ed => "\xbb",
     0x000030ef => "\xbc",
     0x000030f2 => "\x46",
     0x000030f3 => "\xbd",
     0x000030fb => "\x45",
     0x000030fc => "\x58",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x6f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::IBM290 - Conversion routines for IBM290
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for IBM290.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
   source: IBM 3174 Character Set Ref, GA27-3831-02, March 1990
  alias CP290
  alias EBCDIC-JP-KANA
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  0000009C | STRING TERMINATOR (ST)
     05 |  00000009 | CHARACTER TABULATION (HT)
     06 |  00000086 | START OF SELECTED AREA (SSA)
     07 |  0000007F | DELETE (DEL)
     08 |  00000097 | END OF GUARDED AREA (EPA)
     09 |  0000008D | REVERSE LINE FEED (RI)
     0A |  0000008E | SINGLE-SHIFT TWO (SS2)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  0000009D | OPERATING SYSTEM COMMAND (OSC)
     15 |  00000085 | NEXT LINE (NEL)
     16 |  00000008 | BACKSPACE (BS)
     17 |  00000087 | END OF SELECTED AREA (ESA)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  00000092 | PRIVATE USE TWO (PU2)
     1B |  0000008F | SINGLE-SHIFT THREE (SS3)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000080 | PADDING CHARACTER (PAD)
     21 |  00000081 | HIGH OCTET PRESET (HOP)
     22 |  00000082 | BREAK PERMITTED HERE (BPH)
     23 |  00000083 | NO BREAK HERE (NBH)
     24 |  00000084 | INDEX (IND)
     25 |  0000000A | LINE FEED (LF)
     26 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     27 |  0000001B | ESCAPE (ESC)
     28 |  00000088 | CHARACTER TABULATION SET (HTS)
     29 |  00000089 | CHARACTER TABULATION WITH JUSTIFICATION (HTJ)
     2A |  0000008A | LINE TABULATION SET (VTS)
     2B |  0000008B | PARTIAL LINE FORWARD (PLD)
     2C |  0000008C | PARTIAL LINE BACKWARD (PLU)
     2D |  00000005 | ENQUIRY (ENQ)
     2E |  00000006 | ACKNOWLEDGE (ACK)
     2F |  00000007 | BELL (BEL)
     30 |  00000090 | DEVICE CONTROL STRING (DCS)
     31 |  00000091 | PRIVATE USE ONE (PU1)
     32 |  00000016 | SYNCHRONOUS IDLE (SYN)
     33 |  00000093 | SET TRANSMIT STATE (STS)
     34 |  00000094 | CANCEL CHARACTER (CCH)
     35 |  00000095 | MESSAGE WAITING (MW)
     36 |  00000096 | START OF GUARDED AREA (SPA)
     37 |  00000004 | END OF TRANSMISSION (EOT)
     38 |  00000098 | START OF STRING (SOS)
     39 |  00000099 | SINGLE GRAPHIC CHARACTER INTRODUCER (SGCI)
     3A |  0000009A | SINGLE CHARACTER INTRODUCER (SCI)
     3B |  0000009B | CONTROL SEQUENCE INTRODUCER (CSI)
     3C |  00000014 | DEVICE CONTROL FOUR (DC4)
     3D |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     3E |  0000009E | PRIVACY MESSAGE (PM)
     3F |  0000001A | SUBSTITUTE (SUB)
     40 |  00000020 | SPACE
     41 |  00003002 | IDEOGRAPHIC FULL STOP
     42 |  0000300C | LEFT CORNER BRACKET
     43 |  0000300D | RIGHT CORNER BRACKET
     44 |  00003001 | IDEOGRAPHIC COMMA
     45 |  000030FB | KATAKANA MIDDLE DOT
     46 |  000030F2 | KATAKANA LETTER WO
     47 |  000030A1 | KATAKANA LETTER SMALL A
     48 |  000030A3 | KATAKANA LETTER SMALL I
     49 |  000030A5 | KATAKANA LETTER SMALL U
     4A |  000000A3 | POUND SIGN
     4B |  0000002E | FULL STOP
     4C |  0000003C | LESS-THAN SIGN
     4D |  00000028 | LEFT PARENTHESIS
     4E |  0000002B | PLUS SIGN
     4F |  0000007C | VERTICAL LINE
     50 |  00000026 | AMPERSAND
     51 |  000030A7 | KATAKANA LETTER SMALL E
     52 |  000030A9 | KATAKANA LETTER SMALL O
     53 |  000030E3 | KATAKANA LETTER SMALL YA
     54 |  000030E5 | KATAKANA LETTER SMALL YU
     55 |  000030E7 | KATAKANA LETTER SMALL YO
     56 |  000030C3 | KATAKANA LETTER SMALL TU
     58 |  000030FC | KATAKANA-HIRAGANA PROLONGED SOUND MARK
     5A |  00000021 | EXCLAMATION MARK
     5B |  000000A5 | YEN SIGN
     5C |  0000002A | ASTERISK
     5D |  00000029 | RIGHT PARENTHESIS
     5E |  0000003B | SEMICOLON
     5F |  000000AC | NOT SIGN
     60 |  0000002D | HYPHEN-MINUS
     61 |  0000002F | SOLIDUS
     6A |  000000A6 | BROKEN BAR
     6B |  0000002C | COMMA
     6C |  00000025 | PERCENT SIGN
     6D |  0000005F | LOW LINE
     6E |  0000003E | GREATER-THAN SIGN
     6F |  0000003F | QUESTION MARK
     79 |  00000060 | GRAVE ACCENT
     7A |  0000003A | COLON
     7B |  00000023 | NUMBER SIGN
     7C |  00000040 | COMMERCIAL AT
     7D |  00000027 | APOSTROPHE
     7E |  0000003D | EQUALS SIGN
     7F |  00000022 | QUOTATION MARK
     81 |  000030A2 | KATAKANA LETTER A
     82 |  000030A4 | KATAKANA LETTER I
     83 |  000030A6 | KATAKANA LETTER U
     84 |  000030A8 | KATAKANA LETTER E
     85 |  000030AA | KATAKANA LETTER O
     86 |  000030AB | KATAKANA LETTER KA
     87 |  000030AD | KATAKANA LETTER KI
     88 |  000030AF | KATAKANA LETTER KU
     89 |  000030B1 | KATAKANA LETTER KE
     8A |  000030B3 | KATAKANA LETTER KO
     8C |  000030B5 | KATAKANA LETTER SA
     8D |  000030B7 | KATAKANA LETTER SI
     8E |  000030B9 | KATAKANA LETTER SU
     8F |  000030BB | KATAKANA LETTER SE
     90 |  000030BD | KATAKANA LETTER SO
     91 |  000030BF | KATAKANA LETTER TA
     92 |  000030C1 | KATAKANA LETTER TI
     93 |  000030C4 | KATAKANA LETTER TU
     94 |  000030C6 | KATAKANA LETTER TE
     95 |  000030C8 | KATAKANA LETTER TO
     96 |  000030CA | KATAKANA LETTER NA
     97 |  000030CB | KATAKANA LETTER NI
     98 |  000030CC | KATAKANA LETTER NU
     99 |  000030CD | KATAKANA LETTER NE
     9A |  000030CE | KATAKANA LETTER NO
     9D |  000030CF | KATAKANA LETTER HA
     9E |  000030D2 | KATAKANA LETTER HI
     9F |  000030D5 | KATAKANA LETTER HU
     A1 |  0000203E | OVERLINE
     A2 |  000030D8 | KATAKANA LETTER HE
     A3 |  000030DB | KATAKANA LETTER HO
     A4 |  000030DE | KATAKANA LETTER MA
     A5 |  000030DF | KATAKANA LETTER MI
     A6 |  000030E0 | KATAKANA LETTER MU
     A7 |  000030E1 | KATAKANA LETTER ME
     A8 |  000030E2 | KATAKANA LETTER MO
     A9 |  000030E4 | KATAKANA LETTER YA
     AA |  000030E6 | KATAKANA LETTER YU
     AC |  000030E8 | KATAKANA LETTER YO
     AD |  000030E9 | KATAKANA LETTER RA
     AE |  000030EA | KATAKANA LETTER RI
     AF |  000030EB | KATAKANA LETTER RU
     BA |  000030EC | KATAKANA LETTER RE
     BB |  000030ED | KATAKANA LETTER RO
     BC |  000030EF | KATAKANA LETTER WA
     BD |  000030F3 | KATAKANA LETTER N
     BE |  0000309B | KATAKANA-HIRAGANA VOICED SOUND MARK
     BF |  0000309C | KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK
     C1 |  00000041 | LATIN CAPITAL LETTER A
     C2 |  00000042 | LATIN CAPITAL LETTER B
     C3 |  00000043 | LATIN CAPITAL LETTER C
     C4 |  00000044 | LATIN CAPITAL LETTER D
     C5 |  00000045 | LATIN CAPITAL LETTER E
     C6 |  00000046 | LATIN CAPITAL LETTER F
     C7 |  00000047 | LATIN CAPITAL LETTER G
     C8 |  00000048 | LATIN CAPITAL LETTER H
     C9 |  00000049 | LATIN CAPITAL LETTER I
     D1 |  0000004A | LATIN CAPITAL LETTER J
     D2 |  0000004B | LATIN CAPITAL LETTER K
     D3 |  0000004C | LATIN CAPITAL LETTER L
     D4 |  0000004D | LATIN CAPITAL LETTER M
     D5 |  0000004E | LATIN CAPITAL LETTER N
     D6 |  0000004F | LATIN CAPITAL LETTER O
     D7 |  00000050 | LATIN CAPITAL LETTER P
     D8 |  00000051 | LATIN CAPITAL LETTER Q
     D9 |  00000052 | LATIN CAPITAL LETTER R
     E0 |  00000024 | DOLLAR SIGN
     E2 |  00000053 | LATIN CAPITAL LETTER S
     E3 |  00000054 | LATIN CAPITAL LETTER T
     E4 |  00000055 | LATIN CAPITAL LETTER U
     E5 |  00000056 | LATIN CAPITAL LETTER V
     E6 |  00000057 | LATIN CAPITAL LETTER W
     E7 |  00000058 | LATIN CAPITAL LETTER X
     E8 |  00000059 | LATIN CAPITAL LETTER Y
     E9 |  0000005A | LATIN CAPITAL LETTER Z
     F0 |  00000030 | DIGIT ZERO
     F1 |  00000031 | DIGIT ONE
     F2 |  00000032 | DIGIT TWO
     F3 |  00000033 | DIGIT THREE
     F4 |  00000034 | DIGIT FOUR
     F5 |  00000035 | DIGIT FIVE
     F6 |  00000036 | DIGIT SIX
     F7 |  00000037 | DIGIT SEVEN
     F8 |  00000038 | DIGIT EIGHT
     F9 |  00000039 | DIGIT NINE
     FF |  0000009F | APPLICATION PROGRAM COMMAND (APC)
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/IBM297.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for IBM297.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::IBM297;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x009c,
     0x0009,
     0x0086,
     0x007f,
     0x0097,
     0x008d,
     0x008e,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x009d,
     0x0085,
     0x0008,
     0x0087,
     0x0018,
     0x0019,
     0x0092,
     0x008f,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0080,
     0x0081,
     0x0082,
     0x0083,
     0x0084,
     0x000a,
     0x0017,
     0x001b,
     0x0088,
     0x0089,
     0x008a,
     0x008b,
     0x008c,
     0x0005,
     0x0006,
     0x0007,
     0x0090,
     0x0091,
     0x0016,
     0x0093,
     0x0094,
     0x0095,
     0x0096,
     0x0004,
     0x0098,
     0x0099,
     0x009a,
     0x009b,
     0x0014,
     0x0015,
     0x009e,
     0x001a,
     0x0020,
     0x00a0,
     0x00e2,
     0x00e4,
     0x0040,
     0x00e1,
     0x00e3,
     0x00e5,
     0x005c,
     0x00f1,
     0x00b0,
     0x002e,
     0x003c,
     0x0028,
     0x002b,
     0x0021,
     0x0026,
     0x007b,
     0x00ea,
     0x00eb,
     0x007d,
     0x00ed,
     0x00ee,
     0x00ef,
     0x00ec,
     0x00df,
     0x00a7,
     0x0024,
     0x002a,
     0x0029,
     0x003b,
     0x005e,
     0x002d,
     0x002f,
     0x00c2,
     0x00c4,
     0x00c0,
     0x00c1,
     0x00c3,
     0x00c5,
     0x00c7,
     0x00d1,
     0x00f9,
     0x002c,
     0x0025,
     0x005f,
     0x003e,
     0x003f,
     0x00f8,
     0x00c9,
     0x00ca,
     0x00cb,
     0x00c8,
     0x00cd,
     0x00ce,
     0x00cf,
     0x00cc,
     0x00b5,
     0x003a,
     0x00a3,
     0x00e0,
     0x0027,
     0x003d,
     0x0022,
     0x00d8,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x00ab,
     0x00bb,
     0x00f0,
     0x00fd,
     0x00fe,
     0x00b1,
     0x005b,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x00aa,
     0x00ba,
     0x00e6,
     0x00b8,
     0x00c6,
     0x00a4,
     0x0060,
     0x00a8,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x00a1,
     0x00bf,
     0x00d0,
     0x00dd,
     0x00de,
     0x00ae,
     0x00a2,
     0x0023,
     0x00a5,
     0x00b7,
     0x00a9,
     0x005d,
     0x00b6,
     0x00bc,
     0x00bd,
     0x00be,
     0x00ac,
     0x007c,
     0x203e,
     0x007e,
     0x00b4,
     0x00d7,
     0x00e9,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x00ad,
     0x00f4,
     0x00f6,
     0x00f2,
     0x00f3,
     0x00f5,
     0x00e8,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x00b9,
     0x00fb,
     0x00fc,
     0x00a6,
     0x00fa,
     0x00ff,
     0x00e7,
     0x00f7,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x00b2,
     0x00d4,
     0x00d6,
     0x00d2,
     0x00d3,
     0x00d5,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x00b3,
     0x00db,
     0x00dc,
     0x00d9,
     0x00da,
     0x009f,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\xc2\x9c",
     "\x09",
     "\xc2\x86",
     "\x7f",
     "\xc2\x97",
     "\xc2\x8d",
     "\xc2\x8e",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\xc2\x9d",
     "\xc2\x85",
     "\x08",
     "\xc2\x87",
     "\x18",
     "\x19",
     "\xc2\x92",
     "\xc2\x8f",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\xc2\x80",
     "\xc2\x81",
     "\xc2\x82",
     "\xc2\x83",
     "\xc2\x84",
     "\x0a",
     "\x17",
     "\x1b",
     "\xc2\x88",
     "\xc2\x89",
     "\xc2\x8a",
     "\xc2\x8b",
     "\xc2\x8c",
     "\x05",
     "\x06",
     "\x07",
     "\xc2\x90",
     "\xc2\x91",
     "\x16",
     "\xc2\x93",
     "\xc2\x94",
     "\xc2\x95",
     "\xc2\x96",
     "\x04",
     "\xc2\x98",
     "\xc2\x99",
     "\xc2\x9a",
     "\xc2\x9b",
     "\x14",
     "\x15",
     "\xc2\x9e",
     "\x1a",
     "\x20",
     "\xc2\xa0",
     "\xc3\xa2",
     "\xc3\xa4",
     "\x40",
     "\xc3\xa1",
     "\xc3\xa3",
     "\xc3\xa5",
     "\x5c",
     "\xc3\xb1",
     "\xc2\xb0",
     "\x2e",
     "\x3c",
     "\x28",
     "\x2b",
     "\x21",
     "\x26",
     "\x7b",
     "\xc3\xaa",
     "\xc3\xab",
     "\x7d",
     "\xc3\xad",
     "\xc3\xae",
     "\xc3\xaf",
     "\xc3\xac",
     "\xc3\x9f",
     "\xc2\xa7",
     "\x24",
     "\x2a",
     "\x29",
     "\x3b",
     "\x5e",
     "\x2d",
     "\x2f",
     "\xc3\x82",
     "\xc3\x84",
     "\xc3\x80",
     "\xc3\x81",
     "\xc3\x83",
     "\xc3\x85",
     "\xc3\x87",
     "\xc3\x91",
     "\xc3\xb9",
     "\x2c",
     "\x25",
     "\x5f",
     "\x3e",
     "\x3f",
     "\xc3\xb8",
     "\xc3\x89",
     "\xc3\x8a",
     "\xc3\x8b",
     "\xc3\x88",
     "\xc3\x8d",
     "\xc3\x8e",
     "\xc3\x8f",
     "\xc3\x8c",
     "\xc2\xb5",
     "\x3a",
     "\xc2\xa3",
     "\xc3\xa0",
     "\x27",
     "\x3d",
     "\x22",
     "\xc3\x98",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\xc2\xab",
     "\xc2\xbb",
     "\xc3\xb0",
     "\xc3\xbd",
     "\xc3\xbe",
     "\xc2\xb1",
     "\x5b",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\xc2\xaa",
     "\xc2\xba",
     "\xc3\xa6",
     "\xc2\xb8",
     "\xc3\x86",
     "\xc2\xa4",
     "\x60",
     "\xc2\xa8",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\xc2\xa1",
     "\xc2\xbf",
     "\xc3\x90",
     "\xc3\x9d",
     "\xc3\x9e",
     "\xc2\xae",
     "\xc2\xa2",
     "\x23",
     "\xc2\xa5",
     "\xc2\xb7",
     "\xc2\xa9",
     "\x5d",
     "\xc2\xb6",
     "\xc2\xbc",
     "\xc2\xbd",
     "\xc2\xbe",
     "\xc2\xac",
     "\x7c",
     "\xe2\x80\xbe",
     "\x7e",
     "\xc2\xb4",
     "\xc3\x97",
     "\xc3\xa9",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\xc2\xad",
     "\xc3\xb4",
     "\xc3\xb6",
     "\xc3\xb2",
     "\xc3\xb3",
     "\xc3\xb5",
     "\xc3\xa8",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\xc2\xb9",
     "\xc3\xbb",
     "\xc3\xbc",
     "\xc2\xa6",
     "\xc3\xba",
     "\xc3\xbf",
     "\xc3\xa7",
     "\xc3\xb7",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\xc2\xb2",
     "\xc3\x94",
     "\xc3\x96",
     "\xc3\x92",
     "\xc3\x93",
     "\xc3\x95",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\xc2\xb3",
     "\xc3\x9b",
     "\xc3\x9c",
     "\xc3\x99",
     "\xc3\x9a",
     "\xc2\x9f",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x37",
     0x00000005 => "\x2d",
     0x00000006 => "\x2e",
     0x00000007 => "\x2f",
     0x00000008 => "\x16",
     0x00000009 => "\x05",
     0x0000000a => "\x25",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x3c",
     0x00000015 => "\x3d",
     0x00000016 => "\x32",
     0x00000017 => "\x26",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x3f",
     0x0000001b => "\x27",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x40",
     0x00000021 => "\x4f",
     0x00000022 => "\x7f",
     0x00000023 => "\xb1",
     0x00000024 => "\x5b",
     0x00000025 => "\x6c",
     0x00000026 => "\x50",
     0x00000027 => "\x7d",
     0x00000028 => "\x4d",
     0x00000029 => "\x5d",
     0x0000002a => "\x5c",
     0x0000002b => "\x4e",
     0x0000002c => "\x6b",
     0x0000002d => "\x60",
     0x0000002e => "\x4b",
     0x0000002f => "\x61",
     0x00000030 => "\xf0",
     0x00000031 => "\xf1",
     0x00000032 => "\xf2",
     0x00000033 => "\xf3",
     0x00000034 => "\xf4",
     0x00000035 => "\xf5",
     0x00000036 => "\xf6",
     0x00000037 => "\xf7",
     0x00000038 => "\xf8",
     0x00000039 => "\xf9",
     0x0000003a => "\x7a",
     0x0000003b => "\x5e",
     0x0000003c => "\x4c",
     0x0000003d => "\x7e",
     0x0000003e => "\x6e",
     0x0000003f => "\x6f",
     0x00000040 => "\x44",
     0x00000041 => "\xc1",
     0x00000042 => "\xc2",
     0x00000043 => "\xc3",
     0x00000044 => "\xc4",
     0x00000045 => "\xc5",
     0x00000046 => "\xc6",
     0x00000047 => "\xc7",
     0x00000048 => "\xc8",
     0x00000049 => "\xc9",
     0x0000004a => "\xd1",
     0x0000004b => "\xd2",
     0x0000004c => "\xd3",
     0x0000004d => "\xd4",
     0x0000004e => "\xd5",
     0x0000004f => "\xd6",
     0x00000050 => "\xd7",
     0x00000051 => "\xd8",
     0x00000052 => "\xd9",
     0x00000053 => "\xe2",
     0x00000054 => "\xe3",
     0x00000055 => "\xe4",
     0x00000056 => "\xe5",
     0x00000057 => "\xe6",
     0x00000058 => "\xe7",
     0x00000059 => "\xe8",
     0x0000005a => "\xe9",
     0x0000005b => "\x90",
     0x0000005c => "\x48",
     0x0000005d => "\xb5",
     0x0000005e => "\x5f",
     0x0000005f => "\x6d",
     0x00000060 => "\xa0",
     0x00000061 => "\x81",
     0x00000062 => "\x82",
     0x00000063 => "\x83",
     0x00000064 => "\x84",
     0x00000065 => "\x85",
     0x00000066 => "\x86",
     0x00000067 => "\x87",
     0x00000068 => "\x88",
     0x00000069 => "\x89",
     0x0000006a => "\x91",
     0x0000006b => "\x92",
     0x0000006c => "\x93",
     0x0000006d => "\x94",
     0x0000006e => "\x95",
     0x0000006f => "\x96",
     0x00000070 => "\x97",
     0x00000071 => "\x98",
     0x00000072 => "\x99",
     0x00000073 => "\xa2",
     0x00000074 => "\xa3",
     0x00000075 => "\xa4",
     0x00000076 => "\xa5",
     0x00000077 => "\xa6",
     0x00000078 => "\xa7",
     0x00000079 => "\xa8",
     0x0000007a => "\xa9",
     0x0000007b => "\x51",
     0x0000007c => "\xbb",
     0x0000007d => "\x54",
     0x0000007e => "\xbd",
     0x0000007f => "\x07",
     0x00000080 => "\x20",
     0x00000081 => "\x21",
     0x00000082 => "\x22",
     0x00000083 => "\x23",
     0x00000084 => "\x24",
     0x00000085 => "\x15",
     0x00000086 => "\x06",
     0x00000087 => "\x17",
     0x00000088 => "\x28",
     0x00000089 => "\x29",
     0x0000008a => "\x2a",
     0x0000008b => "\x2b",
     0x0000008c => "\x2c",
     0x0000008d => "\x09",
     0x0000008e => "\x0a",
     0x0000008f => "\x1b",
     0x00000090 => "\x30",
     0x00000091 => "\x31",
     0x00000092 => "\x1a",
     0x00000093 => "\x33",
     0x00000094 => "\x34",
     0x00000095 => "\x35",
     0x00000096 => "\x36",
     0x00000097 => "\x08",
     0x00000098 => "\x38",
     0x00000099 => "\x39",
     0x0000009a => "\x3a",
     0x0000009b => "\x3b",
     0x0000009c => "\x04",
     0x0000009d => "\x14",
     0x0000009e => "\x3e",
     0x0000009f => "\xff",
     0x000000a0 => "\x41",
     0x000000a1 => "\xaa",
     0x000000a2 => "\xb0",
     0x000000a3 => "\x7b",
     0x000000a4 => "\x9f",
     0x000000a5 => "\xb2",
     0x000000a6 => "\xdd",
     0x000000a7 => "\x5a",
     0x000000a8 => "\xa1",
     0x000000a9 => "\xb4",
     0x000000aa => "\x9a",
     0x000000ab => "\x8a",
     0x000000ac => "\xba",
     0x000000ad => "\xca",
     0x000000ae => "\xaf",
     0x000000b0 => "\x4a",
     0x000000b1 => "\x8f",
     0x000000b2 => "\xea",
     0x000000b3 => "\xfa",
     0x000000b4 => "\xbe",
     0x000000b5 => "\x79",
     0x000000b6 => "\xb6",
     0x000000b7 => "\xb3",
     0x000000b8 => "\x9d",
     0x000000b9 => "\xda",
     0x000000ba => "\x9b",
     0x000000bb => "\x8b",
     0x000000bc => "\xb7",
     0x000000bd => "\xb8",
     0x000000be => "\xb9",
     0x000000bf => "\xab",
     0x000000c0 => "\x64",
     0x000000c1 => "\x65",
     0x000000c2 => "\x62",
     0x000000c3 => "\x66",
     0x000000c4 => "\x63",
     0x000000c5 => "\x67",
     0x000000c6 => "\x9e",
     0x000000c7 => "\x68",
     0x000000c8 => "\x74",
     0x000000c9 => "\x71",
     0x000000ca => "\x72",
     0x000000cb => "\x73",
     0x000000cc => "\x78",
     0x000000cd => "\x75",
     0x000000ce => "\x76",
     0x000000cf => "\x77",
     0x000000d0 => "\xac",
     0x000000d1 => "\x69",
     0x000000d2 => "\xed",
     0x000000d3 => "\xee",
     0x000000d4 => "\xeb",
     0x000000d5 => "\xef",
     0x000000d6 => "\xec",
     0x000000d7 => "\xbf",
     0x000000d8 => "\x80",
     0x000000d9 => "\xfd",
     0x000000da => "\xfe",
     0x000000db => "\xfb",
     0x000000dc => "\xfc",
     0x000000dd => "\xad",
     0x000000de => "\xae",
     0x000000df => "\x59",
     0x000000e0 => "\x7c",
     0x000000e1 => "\x45",
     0x000000e2 => "\x42",
     0x000000e3 => "\x46",
     0x000000e4 => "\x43",
     0x000000e5 => "\x47",
     0x000000e6 => "\x9c",
     0x000000e7 => "\xe0",
     0x000000e8 => "\xd0",
     0x000000e9 => "\xc0",
     0x000000ea => "\x52",
     0x000000eb => "\x53",
     0x000000ec => "\x58",
     0x000000ed => "\x55",
     0x000000ee => "\x56",
     0x000000ef => "\x57",
     0x000000f0 => "\x8c",
     0x000000f1 => "\x49",
     0x000000f2 => "\xcd",
     0x000000f3 => "\xce",
     0x000000f4 => "\xcb",
     0x000000f5 => "\xcf",
     0x000000f6 => "\xcc",
     0x000000f7 => "\xe1",
     0x000000f8 => "\x70",
     0x000000f9 => "\x6a",
     0x000000fa => "\xde",
     0x000000fb => "\xdb",
     0x000000fc => "\xdc",
     0x000000fd => "\x8d",
     0x000000fe => "\x8e",
     0x000000ff => "\xdf",
     0x0000203e => "\xbc",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x6f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::IBM297 - Conversion routines for IBM297
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for IBM297.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
   source: IBM NLS RM Vol2 SE09-8002-01, March 1990
  alias CP297
  alias EBCDIC-CP-FR
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  0000009C | STRING TERMINATOR (ST)
     05 |  00000009 | CHARACTER TABULATION (HT)
     06 |  00000086 | START OF SELECTED AREA (SSA)
     07 |  0000007F | DELETE (DEL)
     08 |  00000097 | END OF GUARDED AREA (EPA)
     09 |  0000008D | REVERSE LINE FEED (RI)
     0A |  0000008E | SINGLE-SHIFT TWO (SS2)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  0000009D | OPERATING SYSTEM COMMAND (OSC)
     15 |  00000085 | NEXT LINE (NEL)
     16 |  00000008 | BACKSPACE (BS)
     17 |  00000087 | END OF SELECTED AREA (ESA)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  00000092 | PRIVATE USE TWO (PU2)
     1B |  0000008F | SINGLE-SHIFT THREE (SS3)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000080 | PADDING CHARACTER (PAD)
     21 |  00000081 | HIGH OCTET PRESET (HOP)
     22 |  00000082 | BREAK PERMITTED HERE (BPH)
     23 |  00000083 | NO BREAK HERE (NBH)
     24 |  00000084 | INDEX (IND)
     25 |  0000000A | LINE FEED (LF)
     26 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     27 |  0000001B | ESCAPE (ESC)
     28 |  00000088 | CHARACTER TABULATION SET (HTS)
     29 |  00000089 | CHARACTER TABULATION WITH JUSTIFICATION (HTJ)
     2A |  0000008A | LINE TABULATION SET (VTS)
     2B |  0000008B | PARTIAL LINE FORWARD (PLD)
     2C |  0000008C | PARTIAL LINE BACKWARD (PLU)
     2D |  00000005 | ENQUIRY (ENQ)
     2E |  00000006 | ACKNOWLEDGE (ACK)
     2F |  00000007 | BELL (BEL)
     30 |  00000090 | DEVICE CONTROL STRING (DCS)
     31 |  00000091 | PRIVATE USE ONE (PU1)
     32 |  00000016 | SYNCHRONOUS IDLE (SYN)
     33 |  00000093 | SET TRANSMIT STATE (STS)
     34 |  00000094 | CANCEL CHARACTER (CCH)
     35 |  00000095 | MESSAGE WAITING (MW)
     36 |  00000096 | START OF GUARDED AREA (SPA)
     37 |  00000004 | END OF TRANSMISSION (EOT)
     38 |  00000098 | START OF STRING (SOS)
     39 |  00000099 | SINGLE GRAPHIC CHARACTER INTRODUCER (SGCI)
     3A |  0000009A | SINGLE CHARACTER INTRODUCER (SCI)
     3B |  0000009B | CONTROL SEQUENCE INTRODUCER (CSI)
     3C |  00000014 | DEVICE CONTROL FOUR (DC4)
     3D |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     3E |  0000009E | PRIVACY MESSAGE (PM)
     3F |  0000001A | SUBSTITUTE (SUB)
     40 |  00000020 | SPACE
     41 |  000000A0 | NO-BREAK SPACE
     42 |  000000E2 | LATIN SMALL LETTER A WITH CIRCUMFLEX
     43 |  000000E4 | LATIN SMALL LETTER A WITH DIAERESIS
     44 |  00000040 | COMMERCIAL AT
     45 |  000000E1 | LATIN SMALL LETTER A WITH ACUTE
     46 |  000000E3 | LATIN SMALL LETTER A WITH TILDE
     47 |  000000E5 | LATIN SMALL LETTER A WITH RING ABOVE
     48 |  0000005C | REVERSE SOLIDUS
     49 |  000000F1 | LATIN SMALL LETTER N WITH TILDE
     4A |  000000B0 | DEGREE SIGN
     4B |  0000002E | FULL STOP
     4C |  0000003C | LESS-THAN SIGN
     4D |  00000028 | LEFT PARENTHESIS
     4E |  0000002B | PLUS SIGN
     4F |  00000021 | EXCLAMATION MARK
     50 |  00000026 | AMPERSAND
     51 |  0000007B | LEFT CURLY BRACKET
     52 |  000000EA | LATIN SMALL LETTER E WITH CIRCUMFLEX
     53 |  000000EB | LATIN SMALL LETTER E WITH DIAERESIS
     54 |  0000007D | RIGHT CURLY BRACKET
     55 |  000000ED | LATIN SMALL LETTER I WITH ACUTE
     56 |  000000EE | LATIN SMALL LETTER I WITH CIRCUMFLEX
     57 |  000000EF | LATIN SMALL LETTER I WITH DIAERESIS
     58 |  000000EC | LATIN SMALL LETTER I WITH GRAVE
     59 |  000000DF | LATIN SMALL LETTER SHARP S (German)
     5A |  000000A7 | SECTION SIGN
     5B |  00000024 | DOLLAR SIGN
     5C |  0000002A | ASTERISK
     5D |  00000029 | RIGHT PARENTHESIS
     5E |  0000003B | SEMICOLON
     5F |  0000005E | CIRCUMFLEX ACCENT
     60 |  0000002D | HYPHEN-MINUS
     61 |  0000002F | SOLIDUS
     62 |  000000C2 | LATIN CAPITAL LETTER A WITH CIRCUMFLEX
     63 |  000000C4 | LATIN CAPITAL LETTER A WITH DIAERESIS
     64 |  000000C0 | LATIN CAPITAL LETTER A WITH GRAVE
     65 |  000000C1 | LATIN CAPITAL LETTER A WITH ACUTE
     66 |  000000C3 | LATIN CAPITAL LETTER A WITH TILDE
     67 |  000000C5 | LATIN CAPITAL LETTER A WITH RING ABOVE
     68 |  000000C7 | LATIN CAPITAL LETTER C WITH CEDILLA
     69 |  000000D1 | LATIN CAPITAL LETTER N WITH TILDE
     6A |  000000F9 | LATIN SMALL LETTER U WITH GRAVE
     6B |  0000002C | COMMA
     6C |  00000025 | PERCENT SIGN
     6D |  0000005F | LOW LINE
     6E |  0000003E | GREATER-THAN SIGN
     6F |  0000003F | QUESTION MARK
     70 |  000000F8 | LATIN SMALL LETTER O WITH STROKE
     71 |  000000C9 | LATIN CAPITAL LETTER E WITH ACUTE
     72 |  000000CA | LATIN CAPITAL LETTER E WITH CIRCUMFLEX
     73 |  000000CB | LATIN CAPITAL LETTER E WITH DIAERESIS
     74 |  000000C8 | LATIN CAPITAL LETTER E WITH GRAVE
     75 |  000000CD | LATIN CAPITAL LETTER I WITH ACUTE
     76 |  000000CE | LATIN CAPITAL LETTER I WITH CIRCUMFLEX
     77 |  000000CF | LATIN CAPITAL LETTER I WITH DIAERESIS
     78 |  000000CC | LATIN CAPITAL LETTER I WITH GRAVE
     79 |  000000B5 | MICRO SIGN
     7A |  0000003A | COLON
     7B |  000000A3 | POUND SIGN
     7C |  000000E0 | LATIN SMALL LETTER A WITH GRAVE
     7D |  00000027 | APOSTROPHE
     7E |  0000003D | EQUALS SIGN
     7F |  00000022 | QUOTATION MARK
     80 |  000000D8 | LATIN CAPITAL LETTER O WITH STROKE
     81 |  00000061 | LATIN SMALL LETTER A
     82 |  00000062 | LATIN SMALL LETTER B
     83 |  00000063 | LATIN SMALL LETTER C
     84 |  00000064 | LATIN SMALL LETTER D
     85 |  00000065 | LATIN SMALL LETTER E
     86 |  00000066 | LATIN SMALL LETTER F
     87 |  00000067 | LATIN SMALL LETTER G
     88 |  00000068 | LATIN SMALL LETTER H
     89 |  00000069 | LATIN SMALL LETTER I
     8A |  000000AB | LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
     8B |  000000BB | RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
     8C |  000000F0 | LATIN SMALL LETTER ETH (Icelandic)
     8D |  000000FD | LATIN SMALL LETTER Y WITH ACUTE
     8E |  000000FE | LATIN SMALL LETTER THORN (Icelandic)
     8F |  000000B1 | PLUS-MINUS SIGN
     90 |  0000005B | LEFT SQUARE BRACKET
     91 |  0000006A | LATIN SMALL LETTER J
     92 |  0000006B | LATIN SMALL LETTER K
     93 |  0000006C | LATIN SMALL LETTER L
     94 |  0000006D | LATIN SMALL LETTER M
     95 |  0000006E | LATIN SMALL LETTER N
     96 |  0000006F | LATIN SMALL LETTER O
     97 |  00000070 | LATIN SMALL LETTER P
     98 |  00000071 | LATIN SMALL LETTER Q
     99 |  00000072 | LATIN SMALL LETTER R
     9A |  000000AA | FEMININE ORDINAL INDICATOR
     9B |  000000BA | MASCULINE ORDINAL INDICATOR
     9C |  000000E6 | LATIN SMALL LETTER AE
     9D |  000000B8 | CEDILLA
     9E |  000000C6 | LATIN CAPITAL LETTER AE
     9F |  000000A4 | CURRENCY SIGN
     A0 |  00000060 | GRAVE ACCENT
     A1 |  000000A8 | DIAERESIS
     A2 |  00000073 | LATIN SMALL LETTER S
     A3 |  00000074 | LATIN SMALL LETTER T
     A4 |  00000075 | LATIN SMALL LETTER U
     A5 |  00000076 | LATIN SMALL LETTER V
     A6 |  00000077 | LATIN SMALL LETTER W
     A7 |  00000078 | LATIN SMALL LETTER X
     A8 |  00000079 | LATIN SMALL LETTER Y
     A9 |  0000007A | LATIN SMALL LETTER Z
     AA |  000000A1 | INVERTED EXCLAMATION MARK
     AB |  000000BF | INVERTED QUESTION MARK
     AC |  000000D0 | LATIN CAPITAL LETTER ETH (Icelandic)
     AD |  000000DD | LATIN CAPITAL LETTER Y WITH ACUTE
     AE |  000000DE | LATIN CAPITAL LETTER THORN (Icelandic)
     AF |  000000AE | REGISTERED SIGN
     B0 |  000000A2 | CENT SIGN
     B1 |  00000023 | NUMBER SIGN
     B2 |  000000A5 | YEN SIGN
     B3 |  000000B7 | MIDDLE DOT
     B4 |  000000A9 | COPYRIGHT SIGN
     B5 |  0000005D | RIGHT SQUARE BRACKET
     B6 |  000000B6 | PILCROW SIGN
     B7 |  000000BC | VULGAR FRACTION ONE QUARTER
     B8 |  000000BD | VULGAR FRACTION ONE HALF
     B9 |  000000BE | VULGAR FRACTION THREE QUARTERS
     BA |  000000AC | NOT SIGN
     BB |  0000007C | VERTICAL LINE
     BC |  0000203E | OVERLINE
     BD |  0000007E | TILDE
     BE |  000000B4 | ACUTE ACCENT
     BF |  000000D7 | MULTIPLICATION SIGN
     C0 |  000000E9 | LATIN SMALL LETTER E WITH ACUTE
     C1 |  00000041 | LATIN CAPITAL LETTER A
     C2 |  00000042 | LATIN CAPITAL LETTER B
     C3 |  00000043 | LATIN CAPITAL LETTER C
     C4 |  00000044 | LATIN CAPITAL LETTER D
     C5 |  00000045 | LATIN CAPITAL LETTER E
     C6 |  00000046 | LATIN CAPITAL LETTER F
     C7 |  00000047 | LATIN CAPITAL LETTER G
     C8 |  00000048 | LATIN CAPITAL LETTER H
     C9 |  00000049 | LATIN CAPITAL LETTER I
     CA |  000000AD | SOFT HYPHEN
     CB |  000000F4 | LATIN SMALL LETTER O WITH CIRCUMFLEX
     CC |  000000F6 | LATIN SMALL LETTER O WITH DIAERESIS
     CD |  000000F2 | LATIN SMALL LETTER O WITH GRAVE
     CE |  000000F3 | LATIN SMALL LETTER O WITH ACUTE
     CF |  000000F5 | LATIN SMALL LETTER O WITH TILDE
     D0 |  000000E8 | LATIN SMALL LETTER E WITH GRAVE
     D1 |  0000004A | LATIN CAPITAL LETTER J
     D2 |  0000004B | LATIN CAPITAL LETTER K
     D3 |  0000004C | LATIN CAPITAL LETTER L
     D4 |  0000004D | LATIN CAPITAL LETTER M
     D5 |  0000004E | LATIN CAPITAL LETTER N
     D6 |  0000004F | LATIN CAPITAL LETTER O
     D7 |  00000050 | LATIN CAPITAL LETTER P
     D8 |  00000051 | LATIN CAPITAL LETTER Q
     D9 |  00000052 | LATIN CAPITAL LETTER R
     DA |  000000B9 | SUPERSCRIPT ONE
     DB |  000000FB | LATIN SMALL LETTER U WITH CIRCUMFLEX
     DC |  000000FC | LATIN SMALL LETTER U WITH DIAERESIS
     DD |  000000A6 | BROKEN BAR
     DE |  000000FA | LATIN SMALL LETTER U WITH ACUTE
     DF |  000000FF | LATIN SMALL LETTER Y WITH DIAERESIS
     E0 |  000000E7 | LATIN SMALL LETTER C WITH CEDILLA
     E1 |  000000F7 | DIVISION SIGN
     E2 |  00000053 | LATIN CAPITAL LETTER S
     E3 |  00000054 | LATIN CAPITAL LETTER T
     E4 |  00000055 | LATIN CAPITAL LETTER U
     E5 |  00000056 | LATIN CAPITAL LETTER V
     E6 |  00000057 | LATIN CAPITAL LETTER W
     E7 |  00000058 | LATIN CAPITAL LETTER X
     E8 |  00000059 | LATIN CAPITAL LETTER Y
     E9 |  0000005A | LATIN CAPITAL LETTER Z
     EA |  000000B2 | SUPERSCRIPT TWO
     EB |  000000D4 | LATIN CAPITAL LETTER O WITH CIRCUMFLEX
     EC |  000000D6 | LATIN CAPITAL LETTER O WITH DIAERESIS
     ED |  000000D2 | LATIN CAPITAL LETTER O WITH GRAVE
     EE |  000000D3 | LATIN CAPITAL LETTER O WITH ACUTE
     EF |  000000D5 | LATIN CAPITAL LETTER O WITH TILDE
     F0 |  00000030 | DIGIT ZERO
     F1 |  00000031 | DIGIT ONE
     F2 |  00000032 | DIGIT TWO
     F3 |  00000033 | DIGIT THREE
     F4 |  00000034 | DIGIT FOUR
     F5 |  00000035 | DIGIT FIVE
     F6 |  00000036 | DIGIT SIX
     F7 |  00000037 | DIGIT SEVEN
     F8 |  00000038 | DIGIT EIGHT
     F9 |  00000039 | DIGIT NINE
     FA |  000000B3 | SUPERSCRIPT THREE
     FB |  000000DB | LATIN CAPITAL LETTER U WITH CIRCUMFLEX
     FC |  000000DC | LATIN CAPITAL LETTER U WITH DIAERESIS
     FD |  000000D9 | LATIN CAPITAL LETTER U WITH GRAVE
     FE |  000000DA | LATIN CAPITAL LETTER U WITH ACUTE
     FF |  0000009F | APPLICATION PROGRAM COMMAND (APC)
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/IBM420.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for IBM420.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::IBM420;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x009c,
     0x0009,
     0x0086,
     0x007f,
     0x0097,
     0x008d,
     0x008e,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x009d,
     0x0085,
     0x0008,
     0x0087,
     0x0018,
     0x0019,
     0x0092,
     0x008f,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0080,
     0x0081,
     0x0082,
     0x0083,
     0x0084,
     0x000a,
     0x0017,
     0x001b,
     0x0088,
     0x0089,
     0x008a,
     0x008b,
     0x008c,
     0x0005,
     0x0006,
     0x0007,
     0x0090,
     0x0091,
     0x0016,
     0x0093,
     0x0094,
     0x0095,
     0x0096,
     0x0004,
     0x0098,
     0x0099,
     0x009a,
     0x009b,
     0x0014,
     0x0015,
     0x009e,
     0x001a,
     0x0020,
     0x00a0,
     0x0651,
     0xfe7d,
     0x0640,
     0xfffd,
     0x0621,
     0x0622,
     0xfe82,
     0x0623,
     0x00a2,
     0x002e,
     0x003c,
     0x0028,
     0x002b,
     0x007c,
     0x0026,
     0xfe84,
     0x0624,
     0xfffd,
     0xfffd,
     0x0626,
     0x0627,
     0xfe8e,
     0x0628,
     0xfe91,
     0x0021,
     0x0024,
     0x002a,
     0x0029,
     0x003b,
     0x00ac,
     0x002d,
     0x002f,
     0x0629,
     0x062a,
     0xfe97,
     0x062b,
     0xfe9b,
     0x062c,
     0xfe9f,
     0x062d,
     0x00a6,
     0x002c,
     0x0025,
     0x005f,
     0x003e,
     0x003f,
     0xfea3,
     0x062e,
     0xfea7,
     0x062f,
     0x0630,
     0x0631,
     0x0632,
     0x0633,
     0xfeb3,
     0x060c,
     0x003a,
     0x0023,
     0x0040,
     0x0027,
     0x003d,
     0x0022,
     0x0634,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0xfeb7,
     0x0635,
     0xfebb,
     0x0636,
     0xfebf,
     0x0637,
     0x0638,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x0639,
     0xfeca,
     0xfecb,
     0xfecc,
     0x063a,
     0xfece,
     0xfecf,
     0x00f7,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0xfed0,
     0x0641,
     0xfed3,
     0x0642,
     0xfed7,
     0x0643,
     0xfedb,
     0x0644,
     0xfef5,
     0xfef6,
     0xfef7,
     0xfef8,
     0xfffd,
     0xfffd,
     0xfefb,
     0xfefc,
     0xfedf,
     0x0645,
     0xfee3,
     0x0646,
     0xfee7,
     0x0647,
     0x061b,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x00ad,
     0xfeeb,
     0xfffd,
     0xfeec,
     0xfffd,
     0x0648,
     0x061f,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x0649,
     0xfef0,
     0x064a,
     0xfef2,
     0xfef3,
     0x0660,
     0x00d7,
     0xfffd,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x0661,
     0x0662,
     0xfffd,
     0x0663,
     0x0664,
     0x0665,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0xfffd,
     0x0666,
     0x0667,
     0x0668,
     0x0669,
     0x009f,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\xc2\x9c",
     "\x09",
     "\xc2\x86",
     "\x7f",
     "\xc2\x97",
     "\xc2\x8d",
     "\xc2\x8e",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\xc2\x9d",
     "\xc2\x85",
     "\x08",
     "\xc2\x87",
     "\x18",
     "\x19",
     "\xc2\x92",
     "\xc2\x8f",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\xc2\x80",
     "\xc2\x81",
     "\xc2\x82",
     "\xc2\x83",
     "\xc2\x84",
     "\x0a",
     "\x17",
     "\x1b",
     "\xc2\x88",
     "\xc2\x89",
     "\xc2\x8a",
     "\xc2\x8b",
     "\xc2\x8c",
     "\x05",
     "\x06",
     "\x07",
     "\xc2\x90",
     "\xc2\x91",
     "\x16",
     "\xc2\x93",
     "\xc2\x94",
     "\xc2\x95",
     "\xc2\x96",
     "\x04",
     "\xc2\x98",
     "\xc2\x99",
     "\xc2\x9a",
     "\xc2\x9b",
     "\x14",
     "\x15",
     "\xc2\x9e",
     "\x1a",
     "\x20",
     "\xc2\xa0",
     "\xd9\x91",
     "\xef\xb9\xbd",
     "\xd9\x80",
     "\xef\xbf\xbd",
     "\xd8\xa1",
     "\xd8\xa2",
     "\xef\xba\x82",
     "\xd8\xa3",
     "\xc2\xa2",
     "\x2e",
     "\x3c",
     "\x28",
     "\x2b",
     "\x7c",
     "\x26",
     "\xef\xba\x84",
     "\xd8\xa4",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xd8\xa6",
     "\xd8\xa7",
     "\xef\xba\x8e",
     "\xd8\xa8",
     "\xef\xba\x91",
     "\x21",
     "\x24",
     "\x2a",
     "\x29",
     "\x3b",
     "\xc2\xac",
     "\x2d",
     "\x2f",
     "\xd8\xa9",
     "\xd8\xaa",
     "\xef\xba\x97",
     "\xd8\xab",
     "\xef\xba\x9b",
     "\xd8\xac",
     "\xef\xba\x9f",
     "\xd8\xad",
     "\xc2\xa6",
     "\x2c",
     "\x25",
     "\x5f",
     "\x3e",
     "\x3f",
     "\xef\xba\xa3",
     "\xd8\xae",
     "\xef\xba\xa7",
     "\xd8\xaf",
     "\xd8\xb0",
     "\xd8\xb1",
     "\xd8\xb2",
     "\xd8\xb3",
     "\xef\xba\xb3",
     "\xd8\x8c",
     "\x3a",
     "\x23",
     "\x40",
     "\x27",
     "\x3d",
     "\x22",
     "\xd8\xb4",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\xef\xba\xb7",
     "\xd8\xb5",
     "\xef\xba\xbb",
     "\xd8\xb6",
     "\xef\xba\xbf",
     "\xd8\xb7",
     "\xd8\xb8",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\xd8\xb9",
     "\xef\xbb\x8a",
     "\xef\xbb\x8b",
     "\xef\xbb\x8c",
     "\xd8\xba",
     "\xef\xbb\x8e",
     "\xef\xbb\x8f",
     "\xc3\xb7",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\xef\xbb\x90",
     "\xd9\x81",
     "\xef\xbb\x93",
     "\xd9\x82",
     "\xef\xbb\x97",
     "\xd9\x83",
     "\xef\xbb\x9b",
     "\xd9\x84",
     "\xef\xbb\xb5",
     "\xef\xbb\xb6",
     "\xef\xbb\xb7",
     "\xef\xbb\xb8",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbb\xbb",
     "\xef\xbb\xbc",
     "\xef\xbb\x9f",
     "\xd9\x85",
     "\xef\xbb\xa3",
     "\xd9\x86",
     "\xef\xbb\xa7",
     "\xd9\x87",
     "\xd8\x9b",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\xc2\xad",
     "\xef\xbb\xab",
     "\xef\xbf\xbd",
     "\xef\xbb\xac",
     "\xef\xbf\xbd",
     "\xd9\x88",
     "\xd8\x9f",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\xd9\x89",
     "\xef\xbb\xb0",
     "\xd9\x8a",
     "\xef\xbb\xb2",
     "\xef\xbb\xb3",
     "\xd9\xa0",
     "\xc3\x97",
     "\xef\xbf\xbd",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\xd9\xa1",
     "\xd9\xa2",
     "\xef\xbf\xbd",
     "\xd9\xa3",
     "\xd9\xa4",
     "\xd9\xa5",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\xef\xbf\xbd",
     "\xd9\xa6",
     "\xd9\xa7",
     "\xd9\xa8",
     "\xd9\xa9",
     "\xc2\x9f",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x37",
     0x00000005 => "\x2d",
     0x00000006 => "\x2e",
     0x00000007 => "\x2f",
     0x00000008 => "\x16",
     0x00000009 => "\x05",
     0x0000000a => "\x25",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x3c",
     0x00000015 => "\x3d",
     0x00000016 => "\x32",
     0x00000017 => "\x26",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x3f",
     0x0000001b => "\x27",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x40",
     0x00000021 => "\x5a",
     0x00000022 => "\x7f",
     0x00000023 => "\x7b",
     0x00000024 => "\x5b",
     0x00000025 => "\x6c",
     0x00000026 => "\x50",
     0x00000027 => "\x7d",
     0x00000028 => "\x4d",
     0x00000029 => "\x5d",
     0x0000002a => "\x5c",
     0x0000002b => "\x4e",
     0x0000002c => "\x6b",
     0x0000002d => "\x60",
     0x0000002e => "\x4b",
     0x0000002f => "\x61",
     0x00000030 => "\xf0",
     0x00000031 => "\xf1",
     0x00000032 => "\xf2",
     0x00000033 => "\xf3",
     0x00000034 => "\xf4",
     0x00000035 => "\xf5",
     0x00000036 => "\xf6",
     0x00000037 => "\xf7",
     0x00000038 => "\xf8",
     0x00000039 => "\xf9",
     0x0000003a => "\x7a",
     0x0000003b => "\x5e",
     0x0000003c => "\x4c",
     0x0000003d => "\x7e",
     0x0000003e => "\x6e",
     0x0000003f => "\x6f",
     0x00000040 => "\x7c",
     0x00000041 => "\xc1",
     0x00000042 => "\xc2",
     0x00000043 => "\xc3",
     0x00000044 => "\xc4",
     0x00000045 => "\xc5",
     0x00000046 => "\xc6",
     0x00000047 => "\xc7",
     0x00000048 => "\xc8",
     0x00000049 => "\xc9",
     0x0000004a => "\xd1",
     0x0000004b => "\xd2",
     0x0000004c => "\xd3",
     0x0000004d => "\xd4",
     0x0000004e => "\xd5",
     0x0000004f => "\xd6",
     0x00000050 => "\xd7",
     0x00000051 => "\xd8",
     0x00000052 => "\xd9",
     0x00000053 => "\xe2",
     0x00000054 => "\xe3",
     0x00000055 => "\xe4",
     0x00000056 => "\xe5",
     0x00000057 => "\xe6",
     0x00000058 => "\xe7",
     0x00000059 => "\xe8",
     0x0000005a => "\xe9",
     0x0000005f => "\x6d",
     0x00000061 => "\x81",
     0x00000062 => "\x82",
     0x00000063 => "\x83",
     0x00000064 => "\x84",
     0x00000065 => "\x85",
     0x00000066 => "\x86",
     0x00000067 => "\x87",
     0x00000068 => "\x88",
     0x00000069 => "\x89",
     0x0000006a => "\x91",
     0x0000006b => "\x92",
     0x0000006c => "\x93",
     0x0000006d => "\x94",
     0x0000006e => "\x95",
     0x0000006f => "\x96",
     0x00000070 => "\x97",
     0x00000071 => "\x98",
     0x00000072 => "\x99",
     0x00000073 => "\xa2",
     0x00000074 => "\xa3",
     0x00000075 => "\xa4",
     0x00000076 => "\xa5",
     0x00000077 => "\xa6",
     0x00000078 => "\xa7",
     0x00000079 => "\xa8",
     0x0000007a => "\xa9",
     0x0000007c => "\x4f",
     0x0000007f => "\x07",
     0x00000080 => "\x20",
     0x00000081 => "\x21",
     0x00000082 => "\x22",
     0x00000083 => "\x23",
     0x00000084 => "\x24",
     0x00000085 => "\x15",
     0x00000086 => "\x06",
     0x00000087 => "\x17",
     0x00000088 => "\x28",
     0x00000089 => "\x29",
     0x0000008a => "\x2a",
     0x0000008b => "\x2b",
     0x0000008c => "\x2c",
     0x0000008d => "\x09",
     0x0000008e => "\x0a",
     0x0000008f => "\x1b",
     0x00000090 => "\x30",
     0x00000091 => "\x31",
     0x00000092 => "\x1a",
     0x00000093 => "\x33",
     0x00000094 => "\x34",
     0x00000095 => "\x35",
     0x00000096 => "\x36",
     0x00000097 => "\x08",
     0x00000098 => "\x38",
     0x00000099 => "\x39",
     0x0000009a => "\x3a",
     0x0000009b => "\x3b",
     0x0000009c => "\x04",
     0x0000009d => "\x14",
     0x0000009e => "\x3e",
     0x0000009f => "\xff",
     0x000000a0 => "\x41",
     0x000000a2 => "\x4a",
     0x000000a6 => "\x6a",
     0x000000ac => "\x5f",
     0x000000ad => "\xca",
     0x000000d7 => "\xe0",
     0x000000f7 => "\xa1",
     0x0000060c => "\x79",
     0x0000061b => "\xc0",
     0x0000061f => "\xd0",
     0x00000621 => "\x46",
     0x00000622 => "\x47",
     0x00000623 => "\x49",
     0x00000624 => "\x52",
     0x00000626 => "\x55",
     0x00000627 => "\x56",
     0x00000628 => "\x58",
     0x00000629 => "\x62",
     0x0000062a => "\x63",
     0x0000062b => "\x65",
     0x0000062c => "\x67",
     0x0000062d => "\x69",
     0x0000062e => "\x71",
     0x0000062f => "\x73",
     0x00000630 => "\x74",
     0x00000631 => "\x75",
     0x00000632 => "\x76",
     0x00000633 => "\x77",
     0x00000634 => "\x80",
     0x00000635 => "\x8b",
     0x00000636 => "\x8d",
     0x00000637 => "\x8f",
     0x00000638 => "\x90",
     0x00000639 => "\x9a",
     0x0000063a => "\x9e",
     0x00000640 => "\x44",
     0x00000641 => "\xab",
     0x00000642 => "\xad",
     0x00000643 => "\xaf",
     0x00000644 => "\xb1",
     0x00000645 => "\xbb",
     0x00000646 => "\xbd",
     0x00000647 => "\xbf",
     0x00000648 => "\xcf",
     0x00000649 => "\xda",
     0x0000064a => "\xdc",
     0x00000651 => "\x42",
     0x00000660 => "\xdf",
     0x00000661 => "\xea",
     0x00000662 => "\xeb",
     0x00000663 => "\xed",
     0x00000664 => "\xee",
     0x00000665 => "\xef",
     0x00000666 => "\xfb",
     0x00000667 => "\xfc",
     0x00000668 => "\xfd",
     0x00000669 => "\xfe",
     0x0000fe7d => "\x43",
     0x0000fe82 => "\x48",
     0x0000fe84 => "\x51",
     0x0000fe8e => "\x57",
     0x0000fe91 => "\x59",
     0x0000fe97 => "\x64",
     0x0000fe9b => "\x66",
     0x0000fe9f => "\x68",
     0x0000fea3 => "\x70",
     0x0000fea7 => "\x72",
     0x0000feb3 => "\x78",
     0x0000feb7 => "\x8a",
     0x0000febb => "\x8c",
     0x0000febf => "\x8e",
     0x0000feca => "\x9b",
     0x0000fecb => "\x9c",
     0x0000fecc => "\x9d",
     0x0000fece => "\x9f",
     0x0000fecf => "\xa0",
     0x0000fed0 => "\xaa",
     0x0000fed3 => "\xac",
     0x0000fed7 => "\xae",
     0x0000fedb => "\xb0",
     0x0000fedf => "\xba",
     0x0000fee3 => "\xbc",
     0x0000fee7 => "\xbe",
     0x0000feeb => "\xcb",
     0x0000feec => "\xcd",
     0x0000fef0 => "\xdb",
     0x0000fef2 => "\xdd",
     0x0000fef3 => "\xde",
     0x0000fef5 => "\xb2",
     0x0000fef6 => "\xb3",
     0x0000fef7 => "\xb4",
     0x0000fef8 => "\xb5",
     0x0000fefb => "\xb8",
     0x0000fefc => "\xb9",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\xd0"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::IBM420 - Conversion routines for IBM420
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for IBM420.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
   source: IBM NLS RM Vol2 SE09-8002-01, March 1990
   IBM NLS RM p 11-11
  alias CP420
  alias EBCDIC-CP-AR1
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  0000009C | STRING TERMINATOR (ST)
     05 |  00000009 | CHARACTER TABULATION (HT)
     06 |  00000086 | START OF SELECTED AREA (SSA)
     07 |  0000007F | DELETE (DEL)
     08 |  00000097 | END OF GUARDED AREA (EPA)
     09 |  0000008D | REVERSE LINE FEED (RI)
     0A |  0000008E | SINGLE-SHIFT TWO (SS2)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  0000009D | OPERATING SYSTEM COMMAND (OSC)
     15 |  00000085 | NEXT LINE (NEL)
     16 |  00000008 | BACKSPACE (BS)
     17 |  00000087 | END OF SELECTED AREA (ESA)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  00000092 | PRIVATE USE TWO (PU2)
     1B |  0000008F | SINGLE-SHIFT THREE (SS3)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000080 | PADDING CHARACTER (PAD)
     21 |  00000081 | HIGH OCTET PRESET (HOP)
     22 |  00000082 | BREAK PERMITTED HERE (BPH)
     23 |  00000083 | NO BREAK HERE (NBH)
     24 |  00000084 | INDEX (IND)
     25 |  0000000A | LINE FEED (LF)
     26 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     27 |  0000001B | ESCAPE (ESC)
     28 |  00000088 | CHARACTER TABULATION SET (HTS)
     29 |  00000089 | CHARACTER TABULATION WITH JUSTIFICATION (HTJ)
     2A |  0000008A | LINE TABULATION SET (VTS)
     2B |  0000008B | PARTIAL LINE FORWARD (PLD)
     2C |  0000008C | PARTIAL LINE BACKWARD (PLU)
     2D |  00000005 | ENQUIRY (ENQ)
     2E |  00000006 | ACKNOWLEDGE (ACK)
     2F |  00000007 | BELL (BEL)
     30 |  00000090 | DEVICE CONTROL STRING (DCS)
     31 |  00000091 | PRIVATE USE ONE (PU1)
     32 |  00000016 | SYNCHRONOUS IDLE (SYN)
     33 |  00000093 | SET TRANSMIT STATE (STS)
     34 |  00000094 | CANCEL CHARACTER (CCH)
     35 |  00000095 | MESSAGE WAITING (MW)
     36 |  00000096 | START OF GUARDED AREA (SPA)
     37 |  00000004 | END OF TRANSMISSION (EOT)
     38 |  00000098 | START OF STRING (SOS)
     39 |  00000099 | SINGLE GRAPHIC CHARACTER INTRODUCER (SGCI)
     3A |  0000009A | SINGLE CHARACTER INTRODUCER (SCI)
     3B |  0000009B | CONTROL SEQUENCE INTRODUCER (CSI)
     3C |  00000014 | DEVICE CONTROL FOUR (DC4)
     3D |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     3E |  0000009E | PRIVACY MESSAGE (PM)
     3F |  0000001A | SUBSTITUTE (SUB)
     40 |  00000020 | SPACE
     41 |  000000A0 | NO-BREAK SPACE
     42 |  00000651 | ARABIC SHADDA
     43 |  0000FE7D | ARABIC SHADDA MEDIAL FORM
     44 |  00000640 | ARABIC TATWEEL
     46 |  00000621 | ARABIC LETTER HAMZA
     47 |  00000622 | ARABIC LETTER ALEF WITH MADDA ABOVE
     48 |  0000FE82 | ARABIC LETTER ALEF WITH MADDA ABOVE FINAL FORM
     49 |  00000623 | ARABIC LETTER ALEF WITH HAMZA ABOVE
     4A |  000000A2 | CENT SIGN
     4B |  0000002E | FULL STOP
     4C |  0000003C | LESS-THAN SIGN
     4D |  00000028 | LEFT PARENTHESIS
     4E |  0000002B | PLUS SIGN
     4F |  0000007C | VERTICAL LINE
     50 |  00000026 | AMPERSAND
     51 |  0000FE84 | ARABIC LETTER ALEF WITH HAMZA ABOVE FINAL FORM
     52 |  00000624 | ARABIC LETTER WAW WITH HAMZA ABOVE
     55 |  00000626 | ARABIC LETTER YEH WITH HAMZA ABOVE
     56 |  00000627 | ARABIC LETTER ALEF
     57 |  0000FE8E | ARABIC LETTER ALEF FINAL FORM
     58 |  00000628 | ARABIC LETTER BEH
     59 |  0000FE91 | ARABIC LETTER BEH INITIAL FORM
     5A |  00000021 | EXCLAMATION MARK
     5B |  00000024 | DOLLAR SIGN
     5C |  0000002A | ASTERISK
     5D |  00000029 | RIGHT PARENTHESIS
     5E |  0000003B | SEMICOLON
     5F |  000000AC | NOT SIGN
     60 |  0000002D | HYPHEN-MINUS
     61 |  0000002F | SOLIDUS
     62 |  00000629 | ARABIC LETTER TEH MARBUTA
     63 |  0000062A | ARABIC LETTER TEH
     64 |  0000FE97 | ARABIC LETTER TEH INITIAL FORM
     65 |  0000062B | ARABIC LETTER THEH
     66 |  0000FE9B | ARABIC LETTER THEH INITIAL FORM
     67 |  0000062C | ARABIC LETTER JEEM
     68 |  0000FE9F | ARABIC LETTER JEEM INITIAL FORM
     69 |  0000062D | ARABIC LETTER HAH
     6A |  000000A6 | BROKEN BAR
     6B |  0000002C | COMMA
     6C |  00000025 | PERCENT SIGN
     6D |  0000005F | LOW LINE
     6E |  0000003E | GREATER-THAN SIGN
     6F |  0000003F | QUESTION MARK
     70 |  0000FEA3 | ARABIC LETTER HAH INITIAL FORM
     71 |  0000062E | ARABIC LETTER KHAH
     72 |  0000FEA7 | ARABIC LETTER KHAH INITIAL FORM
     73 |  0000062F | ARABIC LETTER DAL
     74 |  00000630 | ARABIC LETTER THAL
     75 |  00000631 | ARABIC LETTER REH
     76 |  00000632 | ARABIC LETTER ZAIN
     77 |  00000633 | ARABIC LETTER SEEN
     78 |  0000FEB3 | ARABIC LETTER SEEN INITIAL FORM
     79 |  0000060C | ARABIC COMMA
     7A |  0000003A | COLON
     7B |  00000023 | NUMBER SIGN
     7C |  00000040 | COMMERCIAL AT
     7D |  00000027 | APOSTROPHE
     7E |  0000003D | EQUALS SIGN
     7F |  00000022 | QUOTATION MARK
     80 |  00000634 | ARABIC LETTER SHEEN
     81 |  00000061 | LATIN SMALL LETTER A
     82 |  00000062 | LATIN SMALL LETTER B
     83 |  00000063 | LATIN SMALL LETTER C
     84 |  00000064 | LATIN SMALL LETTER D
     85 |  00000065 | LATIN SMALL LETTER E
     86 |  00000066 | LATIN SMALL LETTER F
     87 |  00000067 | LATIN SMALL LETTER G
     88 |  00000068 | LATIN SMALL LETTER H
     89 |  00000069 | LATIN SMALL LETTER I
     8A |  0000FEB7 | ARABIC LETTER SHEEN INITIAL FORM
     8B |  00000635 | ARABIC LETTER SAD
     8C |  0000FEBB | ARABIC LETTER SAD INITIAL FORM
     8D |  00000636 | ARABIC LETTER DAD
     8E |  0000FEBF | ARABIC LETTER DAD INITIAL FORM
     8F |  00000637 | ARABIC LETTER TAH
     90 |  00000638 | ARABIC LETTER ZAH
     91 |  0000006A | LATIN SMALL LETTER J
     92 |  0000006B | LATIN SMALL LETTER K
     93 |  0000006C | LATIN SMALL LETTER L
     94 |  0000006D | LATIN SMALL LETTER M
     95 |  0000006E | LATIN SMALL LETTER N
     96 |  0000006F | LATIN SMALL LETTER O
     97 |  00000070 | LATIN SMALL LETTER P
     98 |  00000071 | LATIN SMALL LETTER Q
     99 |  00000072 | LATIN SMALL LETTER R
     9A |  00000639 | ARABIC LETTER AIN
     9B |  0000FECA | ARABIC LETTER AIN FINAL FORM
     9C |  0000FECB | ARABIC LETTER AIN INITIAL FORM
     9D |  0000FECC | ARABIC LETTER AIN MEDIAL FORM
     9E |  0000063A | ARABIC LETTER GHAIN
     9F |  0000FECE | ARABIC LETTER GHAIN FINAL FORM
     A0 |  0000FECF | ARABIC LETTER GHAIN INITIAL FORM
     A1 |  000000F7 | DIVISION SIGN
     A2 |  00000073 | LATIN SMALL LETTER S
     A3 |  00000074 | LATIN SMALL LETTER T
     A4 |  00000075 | LATIN SMALL LETTER U
     A5 |  00000076 | LATIN SMALL LETTER V
     A6 |  00000077 | LATIN SMALL LETTER W
     A7 |  00000078 | LATIN SMALL LETTER X
     A8 |  00000079 | LATIN SMALL LETTER Y
     A9 |  0000007A | LATIN SMALL LETTER Z
     AA |  0000FED0 | ARABIC LETTER GHAIN MEDIAL FORM
     AB |  00000641 | ARABIC LETTER FEH
     AC |  0000FED3 | ARABIC LETTER FEH INITIAL FORM
     AD |  00000642 | ARABIC LETTER QAF
     AE |  0000FED7 | ARABIC LETTER QAF INITIAL FORM
     AF |  00000643 | ARABIC LETTER KAF
     B0 |  0000FEDB | ARABIC LETTER KAF INITIAL FORM
     B1 |  00000644 | ARABIC LETTER LAM
     B2 |  0000FEF5 | ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE ISOLATED FORM
     B3 |  0000FEF6 | ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE FINAL FORM
     B4 |  0000FEF7 | ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE ISOLATED FORM
     B5 |  0000FEF8 | ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE FINAL FORM
     B8 |  0000FEFB | ARABIC LIGATURE LAM WITH ALEF ISOLATED FORM
     B9 |  0000FEFC | ARABIC LIGATURE LAM WITH ALEF FINAL FORM
     BA |  0000FEDF | ARABIC LETTER LAM INITIAL FORM
     BB |  00000645 | ARABIC LETTER MEEM
     BC |  0000FEE3 | ARABIC LETTER MEEM INITIAL FORM
     BD |  00000646 | ARABIC LETTER NOON
     BE |  0000FEE7 | ARABIC LETTER NOON INITIAL FORM
     BF |  00000647 | ARABIC LETTER HEH
     C0 |  0000061B | ARABIC SEMICOLON
     C1 |  00000041 | LATIN CAPITAL LETTER A
     C2 |  00000042 | LATIN CAPITAL LETTER B
     C3 |  00000043 | LATIN CAPITAL LETTER C
     C4 |  00000044 | LATIN CAPITAL LETTER D
     C5 |  00000045 | LATIN CAPITAL LETTER E
     C6 |  00000046 | LATIN CAPITAL LETTER F
     C7 |  00000047 | LATIN CAPITAL LETTER G
     C8 |  00000048 | LATIN CAPITAL LETTER H
     C9 |  00000049 | LATIN CAPITAL LETTER I
     CA |  000000AD | SOFT HYPHEN
     CB |  0000FEEB | ARABIC LETTER HEH INITIAL FORM
     CD |  0000FEEC | ARABIC LETTER HEH MEDIAL FORM
     CF |  00000648 | ARABIC LETTER WAW
     D0 |  0000061F | ARABIC QUESTION MARK
     D1 |  0000004A | LATIN CAPITAL LETTER J
     D2 |  0000004B | LATIN CAPITAL LETTER K
     D3 |  0000004C | LATIN CAPITAL LETTER L
     D4 |  0000004D | LATIN CAPITAL LETTER M
     D5 |  0000004E | LATIN CAPITAL LETTER N
     D6 |  0000004F | LATIN CAPITAL LETTER O
     D7 |  00000050 | LATIN CAPITAL LETTER P
     D8 |  00000051 | LATIN CAPITAL LETTER Q
     D9 |  00000052 | LATIN CAPITAL LETTER R
     DA |  00000649 | ARABIC LETTER ALEF MAKSURA
     DB |  0000FEF0 | ARABIC LETTER ALEF MAKSURA FINAL FORM
     DC |  0000064A | ARABIC LETTER YEH
     DD |  0000FEF2 | ARABIC LETTER YEH FINAL FORM
     DE |  0000FEF3 | ARABIC LETTER YEH INITIAL FORM
     DF |  00000660 | ARABIC-INDIC DIGIT ZERO
     E0 |  000000D7 | MULTIPLICATION SIGN
     E2 |  00000053 | LATIN CAPITAL LETTER S
     E3 |  00000054 | LATIN CAPITAL LETTER T
     E4 |  00000055 | LATIN CAPITAL LETTER U
     E5 |  00000056 | LATIN CAPITAL LETTER V
     E6 |  00000057 | LATIN CAPITAL LETTER W
     E7 |  00000058 | LATIN CAPITAL LETTER X
     E8 |  00000059 | LATIN CAPITAL LETTER Y
     E9 |  0000005A | LATIN CAPITAL LETTER Z
     EA |  00000661 | ARABIC-INDIC DIGIT ONE
     EB |  00000662 | ARABIC-INDIC DIGIT TWO
     ED |  00000663 | ARABIC-INDIC DIGIT THREE
     EE |  00000664 | ARABIC-INDIC DIGIT FOUR
     EF |  00000665 | ARABIC-INDIC DIGIT FIVE
     F0 |  00000030 | DIGIT ZERO
     F1 |  00000031 | DIGIT ONE
     F2 |  00000032 | DIGIT TWO
     F3 |  00000033 | DIGIT THREE
     F4 |  00000034 | DIGIT FOUR
     F5 |  00000035 | DIGIT FIVE
     F6 |  00000036 | DIGIT SIX
     F7 |  00000037 | DIGIT SEVEN
     F8 |  00000038 | DIGIT EIGHT
     F9 |  00000039 | DIGIT NINE
     FB |  00000666 | ARABIC-INDIC DIGIT SIX
     FC |  00000667 | ARABIC-INDIC DIGIT SEVEN
     FD |  00000668 | ARABIC-INDIC DIGIT EIGHT
     FE |  00000669 | ARABIC-INDIC DIGIT NINE
     FF |  0000009F | APPLICATION PROGRAM COMMAND (APC)
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/IBM423.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for IBM423.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::IBM423;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x009c,
     0x0009,
     0x0086,
     0x007f,
     0x0097,
     0x008d,
     0x008e,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x009d,
     0x0085,
     0x0008,
     0x0087,
     0x0018,
     0x0019,
     0x0092,
     0x008f,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0080,
     0x0081,
     0x0082,
     0x0083,
     0x0084,
     0x000a,
     0x0017,
     0x001b,
     0x0088,
     0x0089,
     0x008a,
     0x008b,
     0x008c,
     0x0005,
     0x0006,
     0x0007,
     0x0090,
     0x0091,
     0x0016,
     0x0093,
     0x0094,
     0x0095,
     0x0096,
     0x0004,
     0x0098,
     0x0099,
     0x009a,
     0x009b,
     0x0014,
     0x0015,
     0x009e,
     0x001a,
     0x0020,
     0x0391,
     0x0392,
     0x0393,
     0x0394,
     0x0395,
     0x0396,
     0x0397,
     0x0398,
     0x0399,
     0x005b,
     0x002e,
     0x003c,
     0x0028,
     0x002b,
     0x0021,
     0x0026,
     0x039a,
     0x039b,
     0x039c,
     0x039d,
     0x039e,
     0x039f,
     0x03a0,
     0x03a1,
     0x03a3,
     0x005d,
     0x0024,
     0x002a,
     0x0029,
     0x003b,
     0x005e,
     0x002d,
     0x002f,
     0x03a4,
     0x03a5,
     0x03a6,
     0x03a7,
     0x03a8,
     0x03a9,
     0xfffd,
     0xfffd,
     0xfffd,
     0x002c,
     0x0025,
     0x005f,
     0x003e,
     0x003f,
     0xfffd,
     0x0386,
     0x0388,
     0x0389,
     0xfffd,
     0x038a,
     0x038c,
     0x038e,
     0x038f,
     0x0060,
     0x003a,
     0x00a3,
     0x00a7,
     0x0027,
     0x003d,
     0x0022,
     0x00c4,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x03b1,
     0x03b2,
     0x03b3,
     0x03b4,
     0x03b5,
     0x03b6,
     0x00d6,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x03b7,
     0x03b8,
     0x03b9,
     0x03ba,
     0x03bb,
     0x03bc,
     0x00dc,
     0x00a8,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x03bd,
     0x03be,
     0x03bf,
     0x03c0,
     0x03c1,
     0x03c2,
     0xfffd,
     0x03ac,
     0x03ad,
     0x03ae,
     0x03ca,
     0x03af,
     0x03cc,
     0x03cd,
     0x03cb,
     0x03ce,
     0x03c3,
     0x03c4,
     0x03c5,
     0x03c6,
     0x03c7,
     0x03c8,
     0x00b8,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0xfffd,
     0x03c9,
     0x00c2,
     0x00e0,
     0x00e4,
     0x00ea,
     0x00b4,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x00b1,
     0x00e9,
     0x00e8,
     0x00eb,
     0x00ee,
     0x00ef,
     0x00b0,
     0xfffd,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x00bd,
     0x00f6,
     0x00f4,
     0x00fb,
     0x00f9,
     0x00fc,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x00ff,
     0x00e7,
     0x00c7,
     0xfffd,
     0xfffd,
     0x009f,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\xc2\x9c",
     "\x09",
     "\xc2\x86",
     "\x7f",
     "\xc2\x97",
     "\xc2\x8d",
     "\xc2\x8e",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\xc2\x9d",
     "\xc2\x85",
     "\x08",
     "\xc2\x87",
     "\x18",
     "\x19",
     "\xc2\x92",
     "\xc2\x8f",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\xc2\x80",
     "\xc2\x81",
     "\xc2\x82",
     "\xc2\x83",
     "\xc2\x84",
     "\x0a",
     "\x17",
     "\x1b",
     "\xc2\x88",
     "\xc2\x89",
     "\xc2\x8a",
     "\xc2\x8b",
     "\xc2\x8c",
     "\x05",
     "\x06",
     "\x07",
     "\xc2\x90",
     "\xc2\x91",
     "\x16",
     "\xc2\x93",
     "\xc2\x94",
     "\xc2\x95",
     "\xc2\x96",
     "\x04",
     "\xc2\x98",
     "\xc2\x99",
     "\xc2\x9a",
     "\xc2\x9b",
     "\x14",
     "\x15",
     "\xc2\x9e",
     "\x1a",
     "\x20",
     "\xce\x91",
     "\xce\x92",
     "\xce\x93",
     "\xce\x94",
     "\xce\x95",
     "\xce\x96",
     "\xce\x97",
     "\xce\x98",
     "\xce\x99",
     "\x5b",
     "\x2e",
     "\x3c",
     "\x28",
     "\x2b",
     "\x21",
     "\x26",
     "\xce\x9a",
     "\xce\x9b",
     "\xce\x9c",
     "\xce\x9d",
     "\xce\x9e",
     "\xce\x9f",
     "\xce\xa0",
     "\xce\xa1",
     "\xce\xa3",
     "\x5d",
     "\x24",
     "\x2a",
     "\x29",
     "\x3b",
     "\x5e",
     "\x2d",
     "\x2f",
     "\xce\xa4",
     "\xce\xa5",
     "\xce\xa6",
     "\xce\xa7",
     "\xce\xa8",
     "\xce\xa9",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x2c",
     "\x25",
     "\x5f",
     "\x3e",
     "\x3f",
     "\xef\xbf\xbd",
     "\xce\x86",
     "\xce\x88",
     "\xce\x89",
     "\xef\xbf\xbd",
     "\xce\x8a",
     "\xce\x8c",
     "\xce\x8e",
     "\xce\x8f",
     "\x60",
     "\x3a",
     "\xc2\xa3",
     "\xc2\xa7",
     "\x27",
     "\x3d",
     "\x22",
     "\xc3\x84",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\xce\xb1",
     "\xce\xb2",
     "\xce\xb3",
     "\xce\xb4",
     "\xce\xb5",
     "\xce\xb6",
     "\xc3\x96",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\xce\xb7",
     "\xce\xb8",
     "\xce\xb9",
     "\xce\xba",
     "\xce\xbb",
     "\xce\xbc",
     "\xc3\x9c",
     "\xc2\xa8",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\xce\xbd",
     "\xce\xbe",
     "\xce\xbf",
     "\xcf\x80",
     "\xcf\x81",
     "\xcf\x82",
     "\xef\xbf\xbd",
     "\xce\xac",
     "\xce\xad",
     "\xce\xae",
     "\xcf\x8a",
     "\xce\xaf",
     "\xcf\x8c",
     "\xcf\x8d",
     "\xcf\x8b",
     "\xcf\x8e",
     "\xcf\x83",
     "\xcf\x84",
     "\xcf\x85",
     "\xcf\x86",
     "\xcf\x87",
     "\xcf\x88",
     "\xc2\xb8",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\xef\xbf\xbd",
     "\xcf\x89",
     "\xc3\x82",
     "\xc3\xa0",
     "\xc3\xa4",
     "\xc3\xaa",
     "\xc2\xb4",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\xc2\xb1",
     "\xc3\xa9",
     "\xc3\xa8",
     "\xc3\xab",
     "\xc3\xae",
     "\xc3\xaf",
     "\xc2\xb0",
     "\xef\xbf\xbd",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\xc2\xbd",
     "\xc3\xb6",
     "\xc3\xb4",
     "\xc3\xbb",
     "\xc3\xb9",
     "\xc3\xbc",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\xc3\xbf",
     "\xc3\xa7",
     "\xc3\x87",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc2\x9f",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x37",
     0x00000005 => "\x2d",
     0x00000006 => "\x2e",
     0x00000007 => "\x2f",
     0x00000008 => "\x16",
     0x00000009 => "\x05",
     0x0000000a => "\x25",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x3c",
     0x00000015 => "\x3d",
     0x00000016 => "\x32",
     0x00000017 => "\x26",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x3f",
     0x0000001b => "\x27",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x40",
     0x00000021 => "\x4f",
     0x00000022 => "\x7f",
     0x00000024 => "\x5b",
     0x00000025 => "\x6c",
     0x00000026 => "\x50",
     0x00000027 => "\x7d",
     0x00000028 => "\x4d",
     0x00000029 => "\x5d",
     0x0000002a => "\x5c",
     0x0000002b => "\x4e",
     0x0000002c => "\x6b",
     0x0000002d => "\x60",
     0x0000002e => "\x4b",
     0x0000002f => "\x61",
     0x00000030 => "\xf0",
     0x00000031 => "\xf1",
     0x00000032 => "\xf2",
     0x00000033 => "\xf3",
     0x00000034 => "\xf4",
     0x00000035 => "\xf5",
     0x00000036 => "\xf6",
     0x00000037 => "\xf7",
     0x00000038 => "\xf8",
     0x00000039 => "\xf9",
     0x0000003a => "\x7a",
     0x0000003b => "\x5e",
     0x0000003c => "\x4c",
     0x0000003d => "\x7e",
     0x0000003e => "\x6e",
     0x0000003f => "\x6f",
     0x00000041 => "\xc1",
     0x00000042 => "\xc2",
     0x00000043 => "\xc3",
     0x00000044 => "\xc4",
     0x00000045 => "\xc5",
     0x00000046 => "\xc6",
     0x00000047 => "\xc7",
     0x00000048 => "\xc8",
     0x00000049 => "\xc9",
     0x0000004a => "\xd1",
     0x0000004b => "\xd2",
     0x0000004c => "\xd3",
     0x0000004d => "\xd4",
     0x0000004e => "\xd5",
     0x0000004f => "\xd6",
     0x00000050 => "\xd7",
     0x00000051 => "\xd8",
     0x00000052 => "\xd9",
     0x00000053 => "\xe2",
     0x00000054 => "\xe3",
     0x00000055 => "\xe4",
     0x00000056 => "\xe5",
     0x00000057 => "\xe6",
     0x00000058 => "\xe7",
     0x00000059 => "\xe8",
     0x0000005a => "\xe9",
     0x0000005b => "\x4a",
     0x0000005d => "\x5a",
     0x0000005e => "\x5f",
     0x0000005f => "\x6d",
     0x00000060 => "\x79",
     0x00000061 => "\x81",
     0x00000062 => "\x82",
     0x00000063 => "\x83",
     0x00000064 => "\x84",
     0x00000065 => "\x85",
     0x00000066 => "\x86",
     0x00000067 => "\x87",
     0x00000068 => "\x88",
     0x00000069 => "\x89",
     0x0000006a => "\x91",
     0x0000006b => "\x92",
     0x0000006c => "\x93",
     0x0000006d => "\x94",
     0x0000006e => "\x95",
     0x0000006f => "\x96",
     0x00000070 => "\x97",
     0x00000071 => "\x98",
     0x00000072 => "\x99",
     0x00000073 => "\xa2",
     0x00000074 => "\xa3",
     0x00000075 => "\xa4",
     0x00000076 => "\xa5",
     0x00000077 => "\xa6",
     0x00000078 => "\xa7",
     0x00000079 => "\xa8",
     0x0000007a => "\xa9",
     0x0000007f => "\x07",
     0x00000080 => "\x20",
     0x00000081 => "\x21",
     0x00000082 => "\x22",
     0x00000083 => "\x23",
     0x00000084 => "\x24",
     0x00000085 => "\x15",
     0x00000086 => "\x06",
     0x00000087 => "\x17",
     0x00000088 => "\x28",
     0x00000089 => "\x29",
     0x0000008a => "\x2a",
     0x0000008b => "\x2b",
     0x0000008c => "\x2c",
     0x0000008d => "\x09",
     0x0000008e => "\x0a",
     0x0000008f => "\x1b",
     0x00000090 => "\x30",
     0x00000091 => "\x31",
     0x00000092 => "\x1a",
     0x00000093 => "\x33",
     0x00000094 => "\x34",
     0x00000095 => "\x35",
     0x00000096 => "\x36",
     0x00000097 => "\x08",
     0x00000098 => "\x38",
     0x00000099 => "\x39",
     0x0000009a => "\x3a",
     0x0000009b => "\x3b",
     0x0000009c => "\x04",
     0x0000009d => "\x14",
     0x0000009e => "\x3e",
     0x0000009f => "\xff",
     0x000000a3 => "\x7b",
     0x000000a7 => "\x7c",
     0x000000a8 => "\xa1",
     0x000000b0 => "\xe0",
     0x000000b1 => "\xda",
     0x000000b4 => "\xd0",
     0x000000b8 => "\xc0",
     0x000000bd => "\xea",
     0x000000c2 => "\xcc",
     0x000000c4 => "\x80",
     0x000000c7 => "\xfc",
     0x000000d6 => "\x90",
     0x000000dc => "\xa0",
     0x000000e0 => "\xcd",
     0x000000e4 => "\xce",
     0x000000e7 => "\xfb",
     0x000000e8 => "\xdc",
     0x000000e9 => "\xdb",
     0x000000ea => "\xcf",
     0x000000eb => "\xdd",
     0x000000ee => "\xde",
     0x000000ef => "\xdf",
     0x000000f4 => "\xec",
     0x000000f6 => "\xeb",
     0x000000f9 => "\xee",
     0x000000fb => "\xed",
     0x000000fc => "\xef",
     0x000000ff => "\xfa",
     0x00000386 => "\x71",
     0x00000388 => "\x72",
     0x00000389 => "\x73",
     0x0000038a => "\x75",
     0x0000038c => "\x76",
     0x0000038e => "\x77",
     0x0000038f => "\x78",
     0x00000391 => "\x41",
     0x00000392 => "\x42",
     0x00000393 => "\x43",
     0x00000394 => "\x44",
     0x00000395 => "\x45",
     0x00000396 => "\x46",
     0x00000397 => "\x47",
     0x00000398 => "\x48",
     0x00000399 => "\x49",
     0x0000039a => "\x51",
     0x0000039b => "\x52",
     0x0000039c => "\x53",
     0x0000039d => "\x54",
     0x0000039e => "\x55",
     0x0000039f => "\x56",
     0x000003a0 => "\x57",
     0x000003a1 => "\x58",
     0x000003a3 => "\x59",
     0x000003a4 => "\x62",
     0x000003a5 => "\x63",
     0x000003a6 => "\x64",
     0x000003a7 => "\x65",
     0x000003a8 => "\x66",
     0x000003a9 => "\x67",
     0x000003ac => "\xb1",
     0x000003ad => "\xb2",
     0x000003ae => "\xb3",
     0x000003af => "\xb5",
     0x000003b1 => "\x8a",
     0x000003b2 => "\x8b",
     0x000003b3 => "\x8c",
     0x000003b4 => "\x8d",
     0x000003b5 => "\x8e",
     0x000003b6 => "\x8f",
     0x000003b7 => "\x9a",
     0x000003b8 => "\x9b",
     0x000003b9 => "\x9c",
     0x000003ba => "\x9d",
     0x000003bb => "\x9e",
     0x000003bc => "\x9f",
     0x000003bd => "\xaa",
     0x000003be => "\xab",
     0x000003bf => "\xac",
     0x000003c0 => "\xad",
     0x000003c1 => "\xae",
     0x000003c2 => "\xaf",
     0x000003c3 => "\xba",
     0x000003c4 => "\xbb",
     0x000003c5 => "\xbc",
     0x000003c6 => "\xbd",
     0x000003c7 => "\xbe",
     0x000003c8 => "\xbf",
     0x000003c9 => "\xcb",
     0x000003ca => "\xb4",
     0x000003cb => "\xb8",
     0x000003cc => "\xb6",
     0x000003cd => "\xb7",
     0x000003ce => "\xb9",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x6f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::IBM423 - Conversion routines for IBM423
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for IBM423.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
   source: IBM NLS RM Vol2 SE09-8002-01, March 1990
  alias CP423
  alias EBCDIC-CP-GR
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  0000009C | STRING TERMINATOR (ST)
     05 |  00000009 | CHARACTER TABULATION (HT)
     06 |  00000086 | START OF SELECTED AREA (SSA)
     07 |  0000007F | DELETE (DEL)
     08 |  00000097 | END OF GUARDED AREA (EPA)
     09 |  0000008D | REVERSE LINE FEED (RI)
     0A |  0000008E | SINGLE-SHIFT TWO (SS2)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  0000009D | OPERATING SYSTEM COMMAND (OSC)
     15 |  00000085 | NEXT LINE (NEL)
     16 |  00000008 | BACKSPACE (BS)
     17 |  00000087 | END OF SELECTED AREA (ESA)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  00000092 | PRIVATE USE TWO (PU2)
     1B |  0000008F | SINGLE-SHIFT THREE (SS3)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000080 | PADDING CHARACTER (PAD)
     21 |  00000081 | HIGH OCTET PRESET (HOP)
     22 |  00000082 | BREAK PERMITTED HERE (BPH)
     23 |  00000083 | NO BREAK HERE (NBH)
     24 |  00000084 | INDEX (IND)
     25 |  0000000A | LINE FEED (LF)
     26 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     27 |  0000001B | ESCAPE (ESC)
     28 |  00000088 | CHARACTER TABULATION SET (HTS)
     29 |  00000089 | CHARACTER TABULATION WITH JUSTIFICATION (HTJ)
     2A |  0000008A | LINE TABULATION SET (VTS)
     2B |  0000008B | PARTIAL LINE FORWARD (PLD)
     2C |  0000008C | PARTIAL LINE BACKWARD (PLU)
     2D |  00000005 | ENQUIRY (ENQ)
     2E |  00000006 | ACKNOWLEDGE (ACK)
     2F |  00000007 | BELL (BEL)
     30 |  00000090 | DEVICE CONTROL STRING (DCS)
     31 |  00000091 | PRIVATE USE ONE (PU1)
     32 |  00000016 | SYNCHRONOUS IDLE (SYN)
     33 |  00000093 | SET TRANSMIT STATE (STS)
     34 |  00000094 | CANCEL CHARACTER (CCH)
     35 |  00000095 | MESSAGE WAITING (MW)
     36 |  00000096 | START OF GUARDED AREA (SPA)
     37 |  00000004 | END OF TRANSMISSION (EOT)
     38 |  00000098 | START OF STRING (SOS)
     39 |  00000099 | SINGLE GRAPHIC CHARACTER INTRODUCER (SGCI)
     3A |  0000009A | SINGLE CHARACTER INTRODUCER (SCI)
     3B |  0000009B | CONTROL SEQUENCE INTRODUCER (CSI)
     3C |  00000014 | DEVICE CONTROL FOUR (DC4)
     3D |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     3E |  0000009E | PRIVACY MESSAGE (PM)
     3F |  0000001A | SUBSTITUTE (SUB)
     40 |  00000020 | SPACE
     41 |  00000391 | GREEK CAPITAL LETTER ALPHA
     42 |  00000392 | GREEK CAPITAL LETTER BETA
     43 |  00000393 | GREEK CAPITAL LETTER GAMMA
     44 |  00000394 | GREEK CAPITAL LETTER DELTA
     45 |  00000395 | GREEK CAPITAL LETTER EPSILON
     46 |  00000396 | GREEK CAPITAL LETTER ZETA
     47 |  00000397 | GREEK CAPITAL LETTER ETA
     48 |  00000398 | GREEK CAPITAL LETTER THETA
     49 |  00000399 | GREEK CAPITAL LETTER IOTA
     4A |  0000005B | LEFT SQUARE BRACKET
     4B |  0000002E | FULL STOP
     4C |  0000003C | LESS-THAN SIGN
     4D |  00000028 | LEFT PARENTHESIS
     4E |  0000002B | PLUS SIGN
     4F |  00000021 | EXCLAMATION MARK
     50 |  00000026 | AMPERSAND
     51 |  0000039A | GREEK CAPITAL LETTER KAPPA
     52 |  0000039B | GREEK CAPITAL LETTER LAMDA
     53 |  0000039C | GREEK CAPITAL LETTER MU
     54 |  0000039D | GREEK CAPITAL LETTER NU
     55 |  0000039E | GREEK CAPITAL LETTER XI
     56 |  0000039F | GREEK CAPITAL LETTER OMICRON
     57 |  000003A0 | GREEK CAPITAL LETTER PI
     58 |  000003A1 | GREEK CAPITAL LETTER RHO
     59 |  000003A3 | GREEK CAPITAL LETTER SIGMA
     5A |  0000005D | RIGHT SQUARE BRACKET
     5B |  00000024 | DOLLAR SIGN
     5C |  0000002A | ASTERISK
     5D |  00000029 | RIGHT PARENTHESIS
     5E |  0000003B | SEMICOLON
     5F |  0000005E | CIRCUMFLEX ACCENT
     60 |  0000002D | HYPHEN-MINUS
     61 |  0000002F | SOLIDUS
     62 |  000003A4 | GREEK CAPITAL LETTER TAU
     63 |  000003A5 | GREEK CAPITAL LETTER UPSILON
     64 |  000003A6 | GREEK CAPITAL LETTER PHI
     65 |  000003A7 | GREEK CAPITAL LETTER CHI
     66 |  000003A8 | GREEK CAPITAL LETTER PSI
     67 |  000003A9 | GREEK CAPITAL LETTER OMEGA
     6B |  0000002C | COMMA
     6C |  00000025 | PERCENT SIGN
     6D |  0000005F | LOW LINE
     6E |  0000003E | GREATER-THAN SIGN
     6F |  0000003F | QUESTION MARK
     71 |  00000386 | GREEK CAPITAL LETTER ALPHA WITH TONOS
     72 |  00000388 | GREEK CAPITAL LETTER EPSILON WITH TONOS
     73 |  00000389 | GREEK CAPITAL LETTER ETA WITH TONOS
     75 |  0000038A | GREEK CAPITAL LETTER IOTA WITH TONOS
     76 |  0000038C | GREEK CAPITAL LETTER OMICRON WITH TONOS
     77 |  0000038E | GREEK CAPITAL LETTER UPSILON WITH TONOS
     78 |  0000038F | GREEK CAPITAL LETTER OMEGA WITH TONOS
     79 |  00000060 | GRAVE ACCENT
     7A |  0000003A | COLON
     7B |  000000A3 | POUND SIGN
     7C |  000000A7 | SECTION SIGN
     7D |  00000027 | APOSTROPHE
     7E |  0000003D | EQUALS SIGN
     7F |  00000022 | QUOTATION MARK
     80 |  000000C4 | LATIN CAPITAL LETTER A WITH DIAERESIS
     81 |  00000061 | LATIN SMALL LETTER A
     82 |  00000062 | LATIN SMALL LETTER B
     83 |  00000063 | LATIN SMALL LETTER C
     84 |  00000064 | LATIN SMALL LETTER D
     85 |  00000065 | LATIN SMALL LETTER E
     86 |  00000066 | LATIN SMALL LETTER F
     87 |  00000067 | LATIN SMALL LETTER G
     88 |  00000068 | LATIN SMALL LETTER H
     89 |  00000069 | LATIN SMALL LETTER I
     8A |  000003B1 | GREEK SMALL LETTER ALPHA
     8B |  000003B2 | GREEK SMALL LETTER BETA
     8C |  000003B3 | GREEK SMALL LETTER GAMMA
     8D |  000003B4 | GREEK SMALL LETTER DELTA
     8E |  000003B5 | GREEK SMALL LETTER EPSILON
     8F |  000003B6 | GREEK SMALL LETTER ZETA
     90 |  000000D6 | LATIN CAPITAL LETTER O WITH DIAERESIS
     91 |  0000006A | LATIN SMALL LETTER J
     92 |  0000006B | LATIN SMALL LETTER K
     93 |  0000006C | LATIN SMALL LETTER L
     94 |  0000006D | LATIN SMALL LETTER M
     95 |  0000006E | LATIN SMALL LETTER N
     96 |  0000006F | LATIN SMALL LETTER O
     97 |  00000070 | LATIN SMALL LETTER P
     98 |  00000071 | LATIN SMALL LETTER Q
     99 |  00000072 | LATIN SMALL LETTER R
     9A |  000003B7 | GREEK SMALL LETTER ETA
     9B |  000003B8 | GREEK SMALL LETTER THETA
     9C |  000003B9 | GREEK SMALL LETTER IOTA
     9D |  000003BA | GREEK SMALL LETTER KAPPA
     9E |  000003BB | GREEK SMALL LETTER LAMDA
     9F |  000003BC | GREEK SMALL LETTER MU
     A0 |  000000DC | LATIN CAPITAL LETTER U WITH DIAERESIS
     A1 |  000000A8 | DIAERESIS
     A2 |  00000073 | LATIN SMALL LETTER S
     A3 |  00000074 | LATIN SMALL LETTER T
     A4 |  00000075 | LATIN SMALL LETTER U
     A5 |  00000076 | LATIN SMALL LETTER V
     A6 |  00000077 | LATIN SMALL LETTER W
     A7 |  00000078 | LATIN SMALL LETTER X
     A8 |  00000079 | LATIN SMALL LETTER Y
     A9 |  0000007A | LATIN SMALL LETTER Z
     AA |  000003BD | GREEK SMALL LETTER NU
     AB |  000003BE | GREEK SMALL LETTER XI
     AC |  000003BF | GREEK SMALL LETTER OMICRON
     AD |  000003C0 | GREEK SMALL LETTER PI
     AE |  000003C1 | GREEK SMALL LETTER RHO
     AF |  000003C2 | GREEK SMALL LETTER FINAL SIGMA
     B1 |  000003AC | GREEK SMALL LETTER ALPHA WITH TONOS
     B2 |  000003AD | GREEK SMALL LETTER EPSILON WITH TONOS
     B3 |  000003AE | GREEK SMALL LETTER ETA WITH TONOS
     B4 |  000003CA | GREEK SMALL LETTER IOTA WITH DIALYTIKA
     B5 |  000003AF | GREEK SMALL LETTER IOTA WITH TONOS
     B6 |  000003CC | GREEK SMALL LETTER OMICRON WITH TONOS
     B7 |  000003CD | GREEK SMALL LETTER UPSILON WITH TONOS
     B8 |  000003CB | GREEK SMALL LETTER UPSILON WITH DIALYTIKA
     B9 |  000003CE | GREEK SMALL LETTER OMEGA WITH TONOS
     BA |  000003C3 | GREEK SMALL LETTER SIGMA
     BB |  000003C4 | GREEK SMALL LETTER TAU
     BC |  000003C5 | GREEK SMALL LETTER UPSILON
     BD |  000003C6 | GREEK SMALL LETTER PHI
     BE |  000003C7 | GREEK SMALL LETTER CHI
     BF |  000003C8 | GREEK SMALL LETTER PSI
     C0 |  000000B8 | CEDILLA
     C1 |  00000041 | LATIN CAPITAL LETTER A
     C2 |  00000042 | LATIN CAPITAL LETTER B
     C3 |  00000043 | LATIN CAPITAL LETTER C
     C4 |  00000044 | LATIN CAPITAL LETTER D
     C5 |  00000045 | LATIN CAPITAL LETTER E
     C6 |  00000046 | LATIN CAPITAL LETTER F
     C7 |  00000047 | LATIN CAPITAL LETTER G
     C8 |  00000048 | LATIN CAPITAL LETTER H
     C9 |  00000049 | LATIN CAPITAL LETTER I
     CB |  000003C9 | GREEK SMALL LETTER OMEGA
     CC |  000000C2 | LATIN CAPITAL LETTER A WITH CIRCUMFLEX
     CD |  000000E0 | LATIN SMALL LETTER A WITH GRAVE
     CE |  000000E4 | LATIN SMALL LETTER A WITH DIAERESIS
     CF |  000000EA | LATIN SMALL LETTER E WITH CIRCUMFLEX
     D0 |  000000B4 | ACUTE ACCENT
     D1 |  0000004A | LATIN CAPITAL LETTER J
     D2 |  0000004B | LATIN CAPITAL LETTER K
     D3 |  0000004C | LATIN CAPITAL LETTER L
     D4 |  0000004D | LATIN CAPITAL LETTER M
     D5 |  0000004E | LATIN CAPITAL LETTER N
     D6 |  0000004F | LATIN CAPITAL LETTER O
     D7 |  00000050 | LATIN CAPITAL LETTER P
     D8 |  00000051 | LATIN CAPITAL LETTER Q
     D9 |  00000052 | LATIN CAPITAL LETTER R
     DA |  000000B1 | PLUS-MINUS SIGN
     DB |  000000E9 | LATIN SMALL LETTER E WITH ACUTE
     DC |  000000E8 | LATIN SMALL LETTER E WITH GRAVE
     DD |  000000EB | LATIN SMALL LETTER E WITH DIAERESIS
     DE |  000000EE | LATIN SMALL LETTER I WITH CIRCUMFLEX
     DF |  000000EF | LATIN SMALL LETTER I WITH DIAERESIS
     E0 |  000000B0 | DEGREE SIGN
     E2 |  00000053 | LATIN CAPITAL LETTER S
     E3 |  00000054 | LATIN CAPITAL LETTER T
     E4 |  00000055 | LATIN CAPITAL LETTER U
     E5 |  00000056 | LATIN CAPITAL LETTER V
     E6 |  00000057 | LATIN CAPITAL LETTER W
     E7 |  00000058 | LATIN CAPITAL LETTER X
     E8 |  00000059 | LATIN CAPITAL LETTER Y
     E9 |  0000005A | LATIN CAPITAL LETTER Z
     EA |  000000BD | VULGAR FRACTION ONE HALF
     EB |  000000F6 | LATIN SMALL LETTER O WITH DIAERESIS
     EC |  000000F4 | LATIN SMALL LETTER O WITH CIRCUMFLEX
     ED |  000000FB | LATIN SMALL LETTER U WITH CIRCUMFLEX
     EE |  000000F9 | LATIN SMALL LETTER U WITH GRAVE
     EF |  000000FC | LATIN SMALL LETTER U WITH DIAERESIS
     F0 |  00000030 | DIGIT ZERO
     F1 |  00000031 | DIGIT ONE
     F2 |  00000032 | DIGIT TWO
     F3 |  00000033 | DIGIT THREE
     F4 |  00000034 | DIGIT FOUR
     F5 |  00000035 | DIGIT FIVE
     F6 |  00000036 | DIGIT SIX
     F7 |  00000037 | DIGIT SEVEN
     F8 |  00000038 | DIGIT EIGHT
     F9 |  00000039 | DIGIT NINE
     FA |  000000FF | LATIN SMALL LETTER Y WITH DIAERESIS
     FB |  000000E7 | LATIN SMALL LETTER C WITH CEDILLA
     FC |  000000C7 | LATIN CAPITAL LETTER C WITH CEDILLA
     FF |  0000009F | APPLICATION PROGRAM COMMAND (APC)
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/IBM424.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for IBM424.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::IBM424;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x009c,
     0x0009,
     0x0086,
     0x007f,
     0x0097,
     0x008d,
     0x008e,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x009d,
     0x0085,
     0x0008,
     0x0087,
     0x0018,
     0x0019,
     0x0092,
     0x008f,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0080,
     0x0081,
     0x0082,
     0x0083,
     0x0084,
     0x000a,
     0x0017,
     0x001b,
     0x0088,
     0x0089,
     0x008a,
     0x008b,
     0x008c,
     0x0005,
     0x0006,
     0x0007,
     0x0090,
     0x0091,
     0x0016,
     0x0093,
     0x0094,
     0x0095,
     0x0096,
     0x0004,
     0x0098,
     0x0099,
     0x009a,
     0x009b,
     0x0014,
     0x0015,
     0x009e,
     0x001a,
     0x0020,
     0x05d0,
     0x05d1,
     0x05d2,
     0x05d3,
     0x05d4,
     0x05d5,
     0x05d6,
     0x05d7,
     0x05d8,
     0x00a2,
     0x002e,
     0x003c,
     0x0028,
     0x002b,
     0x007c,
     0x0026,
     0x05d9,
     0x05da,
     0x05db,
     0x05dc,
     0x05dd,
     0x05de,
     0x05df,
     0x05e0,
     0x05e1,
     0x0021,
     0x0024,
     0x002a,
     0x0029,
     0x003b,
     0x00ac,
     0x002d,
     0x002f,
     0x05e2,
     0x05e3,
     0x05e4,
     0x05e5,
     0x05e6,
     0x05e7,
     0x05e8,
     0x05e9,
     0x00a6,
     0x002c,
     0x0025,
     0x005f,
     0x003e,
     0x003f,
     0xfffd,
     0x05ea,
     0xfffd,
     0xfffd,
     0x00a0,
     0xfffd,
     0xfffd,
     0xfffd,
     0x21d4,
     0x0060,
     0x003a,
     0x0023,
     0x0040,
     0x0027,
     0x003d,
     0x0022,
     0xfffd,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x00ab,
     0x00bb,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00b0,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00b8,
     0xfffd,
     0x00a4,
     0x00b5,
     0x007e,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00ae,
     0x005e,
     0x00a3,
     0x00a5,
     0x00b7,
     0x00a9,
     0x00a7,
     0x00b6,
     0x00bc,
     0x00bd,
     0x00be,
     0x005b,
     0x005d,
     0x203e,
     0x00a8,
     0x00b4,
     0x00d7,
     0x007b,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x00ad,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x007d,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x00b9,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x005c,
     0x00f7,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x00b2,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x00b3,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x009f,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\xc2\x9c",
     "\x09",
     "\xc2\x86",
     "\x7f",
     "\xc2\x97",
     "\xc2\x8d",
     "\xc2\x8e",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\xc2\x9d",
     "\xc2\x85",
     "\x08",
     "\xc2\x87",
     "\x18",
     "\x19",
     "\xc2\x92",
     "\xc2\x8f",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\xc2\x80",
     "\xc2\x81",
     "\xc2\x82",
     "\xc2\x83",
     "\xc2\x84",
     "\x0a",
     "\x17",
     "\x1b",
     "\xc2\x88",
     "\xc2\x89",
     "\xc2\x8a",
     "\xc2\x8b",
     "\xc2\x8c",
     "\x05",
     "\x06",
     "\x07",
     "\xc2\x90",
     "\xc2\x91",
     "\x16",
     "\xc2\x93",
     "\xc2\x94",
     "\xc2\x95",
     "\xc2\x96",
     "\x04",
     "\xc2\x98",
     "\xc2\x99",
     "\xc2\x9a",
     "\xc2\x9b",
     "\x14",
     "\x15",
     "\xc2\x9e",
     "\x1a",
     "\x20",
     "\xd7\x90",
     "\xd7\x91",
     "\xd7\x92",
     "\xd7\x93",
     "\xd7\x94",
     "\xd7\x95",
     "\xd7\x96",
     "\xd7\x97",
     "\xd7\x98",
     "\xc2\xa2",
     "\x2e",
     "\x3c",
     "\x28",
     "\x2b",
     "\x7c",
     "\x26",
     "\xd7\x99",
     "\xd7\x9a",
     "\xd7\x9b",
     "\xd7\x9c",
     "\xd7\x9d",
     "\xd7\x9e",
     "\xd7\x9f",
     "\xd7\xa0",
     "\xd7\xa1",
     "\x21",
     "\x24",
     "\x2a",
     "\x29",
     "\x3b",
     "\xc2\xac",
     "\x2d",
     "\x2f",
     "\xd7\xa2",
     "\xd7\xa3",
     "\xd7\xa4",
     "\xd7\xa5",
     "\xd7\xa6",
     "\xd7\xa7",
     "\xd7\xa8",
     "\xd7\xa9",
     "\xc2\xa6",
     "\x2c",
     "\x25",
     "\x5f",
     "\x3e",
     "\x3f",
     "\xef\xbf\xbd",
     "\xd7\xaa",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc2\xa0",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xe2\x87\x94",
     "\x60",
     "\x3a",
     "\x23",
     "\x40",
     "\x27",
     "\x3d",
     "\x22",
     "\xef\xbf\xbd",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\xc2\xab",
     "\xc2\xbb",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc2\xb0",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc2\xb8",
     "\xef\xbf\xbd",
     "\xc2\xa4",
     "\xc2\xb5",
     "\x7e",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc2\xae",
     "\x5e",
     "\xc2\xa3",
     "\xc2\xa5",
     "\xc2\xb7",
     "\xc2\xa9",
     "\xc2\xa7",
     "\xc2\xb6",
     "\xc2\xbc",
     "\xc2\xbd",
     "\xc2\xbe",
     "\x5b",
     "\x5d",
     "\xe2\x80\xbe",
     "\xc2\xa8",
     "\xc2\xb4",
     "\xc3\x97",
     "\x7b",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\xc2\xad",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x7d",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\xc2\xb9",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x5c",
     "\xc3\xb7",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\xc2\xb2",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\xc2\xb3",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc2\x9f",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x37",
     0x00000005 => "\x2d",
     0x00000006 => "\x2e",
     0x00000007 => "\x2f",
     0x00000008 => "\x16",
     0x00000009 => "\x05",
     0x0000000a => "\x25",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x3c",
     0x00000015 => "\x3d",
     0x00000016 => "\x32",
     0x00000017 => "\x26",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x3f",
     0x0000001b => "\x27",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x40",
     0x00000021 => "\x5a",
     0x00000022 => "\x7f",
     0x00000023 => "\x7b",
     0x00000024 => "\x5b",
     0x00000025 => "\x6c",
     0x00000026 => "\x50",
     0x00000027 => "\x7d",
     0x00000028 => "\x4d",
     0x00000029 => "\x5d",
     0x0000002a => "\x5c",
     0x0000002b => "\x4e",
     0x0000002c => "\x6b",
     0x0000002d => "\x60",
     0x0000002e => "\x4b",
     0x0000002f => "\x61",
     0x00000030 => "\xf0",
     0x00000031 => "\xf1",
     0x00000032 => "\xf2",
     0x00000033 => "\xf3",
     0x00000034 => "\xf4",
     0x00000035 => "\xf5",
     0x00000036 => "\xf6",
     0x00000037 => "\xf7",
     0x00000038 => "\xf8",
     0x00000039 => "\xf9",
     0x0000003a => "\x7a",
     0x0000003b => "\x5e",
     0x0000003c => "\x4c",
     0x0000003d => "\x7e",
     0x0000003e => "\x6e",
     0x0000003f => "\x6f",
     0x00000040 => "\x7c",
     0x00000041 => "\xc1",
     0x00000042 => "\xc2",
     0x00000043 => "\xc3",
     0x00000044 => "\xc4",
     0x00000045 => "\xc5",
     0x00000046 => "\xc6",
     0x00000047 => "\xc7",
     0x00000048 => "\xc8",
     0x00000049 => "\xc9",
     0x0000004a => "\xd1",
     0x0000004b => "\xd2",
     0x0000004c => "\xd3",
     0x0000004d => "\xd4",
     0x0000004e => "\xd5",
     0x0000004f => "\xd6",
     0x00000050 => "\xd7",
     0x00000051 => "\xd8",
     0x00000052 => "\xd9",
     0x00000053 => "\xe2",
     0x00000054 => "\xe3",
     0x00000055 => "\xe4",
     0x00000056 => "\xe5",
     0x00000057 => "\xe6",
     0x00000058 => "\xe7",
     0x00000059 => "\xe8",
     0x0000005a => "\xe9",
     0x0000005b => "\xba",
     0x0000005c => "\xe0",
     0x0000005d => "\xbb",
     0x0000005e => "\xb0",
     0x0000005f => "\x6d",
     0x00000060 => "\x79",
     0x00000061 => "\x81",
     0x00000062 => "\x82",
     0x00000063 => "\x83",
     0x00000064 => "\x84",
     0x00000065 => "\x85",
     0x00000066 => "\x86",
     0x00000067 => "\x87",
     0x00000068 => "\x88",
     0x00000069 => "\x89",
     0x0000006a => "\x91",
     0x0000006b => "\x92",
     0x0000006c => "\x93",
     0x0000006d => "\x94",
     0x0000006e => "\x95",
     0x0000006f => "\x96",
     0x00000070 => "\x97",
     0x00000071 => "\x98",
     0x00000072 => "\x99",
     0x00000073 => "\xa2",
     0x00000074 => "\xa3",
     0x00000075 => "\xa4",
     0x00000076 => "\xa5",
     0x00000077 => "\xa6",
     0x00000078 => "\xa7",
     0x00000079 => "\xa8",
     0x0000007a => "\xa9",
     0x0000007b => "\xc0",
     0x0000007c => "\x4f",
     0x0000007d => "\xd0",
     0x0000007e => "\xa1",
     0x0000007f => "\x07",
     0x00000080 => "\x20",
     0x00000081 => "\x21",
     0x00000082 => "\x22",
     0x00000083 => "\x23",
     0x00000084 => "\x24",
     0x00000085 => "\x15",
     0x00000086 => "\x06",
     0x00000087 => "\x17",
     0x00000088 => "\x28",
     0x00000089 => "\x29",
     0x0000008a => "\x2a",
     0x0000008b => "\x2b",
     0x0000008c => "\x2c",
     0x0000008d => "\x09",
     0x0000008e => "\x0a",
     0x0000008f => "\x1b",
     0x00000090 => "\x30",
     0x00000091 => "\x31",
     0x00000092 => "\x1a",
     0x00000093 => "\x33",
     0x00000094 => "\x34",
     0x00000095 => "\x35",
     0x00000096 => "\x36",
     0x00000097 => "\x08",
     0x00000098 => "\x38",
     0x00000099 => "\x39",
     0x0000009a => "\x3a",
     0x0000009b => "\x3b",
     0x0000009c => "\x04",
     0x0000009d => "\x14",
     0x0000009e => "\x3e",
     0x0000009f => "\xff",
     0x000000a0 => "\x74",
     0x000000a2 => "\x4a",
     0x000000a3 => "\xb1",
     0x000000a4 => "\x9f",
     0x000000a5 => "\xb2",
     0x000000a6 => "\x6a",
     0x000000a7 => "\xb5",
     0x000000a8 => "\xbd",
     0x000000a9 => "\xb4",
     0x000000ab => "\x8a",
     0x000000ac => "\x5f",
     0x000000ad => "\xca",
     0x000000ae => "\xaf",
     0x000000b0 => "\x90",
     0x000000b2 => "\xea",
     0x000000b3 => "\xfa",
     0x000000b4 => "\xbe",
     0x000000b5 => "\xa0",
     0x000000b6 => "\xb6",
     0x000000b7 => "\xb3",
     0x000000b8 => "\x9d",
     0x000000b9 => "\xda",
     0x000000bb => "\x8b",
     0x000000bc => "\xb7",
     0x000000bd => "\xb8",
     0x000000be => "\xb9",
     0x000000d7 => "\xbf",
     0x000000f7 => "\xe1",
     0x000005d0 => "\x41",
     0x000005d1 => "\x42",
     0x000005d2 => "\x43",
     0x000005d3 => "\x44",
     0x000005d4 => "\x45",
     0x000005d5 => "\x46",
     0x000005d6 => "\x47",
     0x000005d7 => "\x48",
     0x000005d8 => "\x49",
     0x000005d9 => "\x51",
     0x000005da => "\x52",
     0x000005db => "\x53",
     0x000005dc => "\x54",
     0x000005dd => "\x55",
     0x000005de => "\x56",
     0x000005df => "\x57",
     0x000005e0 => "\x58",
     0x000005e1 => "\x59",
     0x000005e2 => "\x62",
     0x000005e3 => "\x63",
     0x000005e4 => "\x64",
     0x000005e5 => "\x65",
     0x000005e6 => "\x66",
     0x000005e7 => "\x67",
     0x000005e8 => "\x68",
     0x000005e9 => "\x69",
     0x000005ea => "\x71",
     0x0000203e => "\xbc",
     0x000021d4 => "\x78",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x6f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::IBM424 - Conversion routines for IBM424
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for IBM424.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
   source: IBM NLS RM Vol2 SE09-8002-01, March 1990
  alias CP424
  alias EBCDIC-CP-HE
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  0000009C | STRING TERMINATOR (ST)
     05 |  00000009 | CHARACTER TABULATION (HT)
     06 |  00000086 | START OF SELECTED AREA (SSA)
     07 |  0000007F | DELETE (DEL)
     08 |  00000097 | END OF GUARDED AREA (EPA)
     09 |  0000008D | REVERSE LINE FEED (RI)
     0A |  0000008E | SINGLE-SHIFT TWO (SS2)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  0000009D | OPERATING SYSTEM COMMAND (OSC)
     15 |  00000085 | NEXT LINE (NEL)
     16 |  00000008 | BACKSPACE (BS)
     17 |  00000087 | END OF SELECTED AREA (ESA)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  00000092 | PRIVATE USE TWO (PU2)
     1B |  0000008F | SINGLE-SHIFT THREE (SS3)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000080 | PADDING CHARACTER (PAD)
     21 |  00000081 | HIGH OCTET PRESET (HOP)
     22 |  00000082 | BREAK PERMITTED HERE (BPH)
     23 |  00000083 | NO BREAK HERE (NBH)
     24 |  00000084 | INDEX (IND)
     25 |  0000000A | LINE FEED (LF)
     26 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     27 |  0000001B | ESCAPE (ESC)
     28 |  00000088 | CHARACTER TABULATION SET (HTS)
     29 |  00000089 | CHARACTER TABULATION WITH JUSTIFICATION (HTJ)
     2A |  0000008A | LINE TABULATION SET (VTS)
     2B |  0000008B | PARTIAL LINE FORWARD (PLD)
     2C |  0000008C | PARTIAL LINE BACKWARD (PLU)
     2D |  00000005 | ENQUIRY (ENQ)
     2E |  00000006 | ACKNOWLEDGE (ACK)
     2F |  00000007 | BELL (BEL)
     30 |  00000090 | DEVICE CONTROL STRING (DCS)
     31 |  00000091 | PRIVATE USE ONE (PU1)
     32 |  00000016 | SYNCHRONOUS IDLE (SYN)
     33 |  00000093 | SET TRANSMIT STATE (STS)
     34 |  00000094 | CANCEL CHARACTER (CCH)
     35 |  00000095 | MESSAGE WAITING (MW)
     36 |  00000096 | START OF GUARDED AREA (SPA)
     37 |  00000004 | END OF TRANSMISSION (EOT)
     38 |  00000098 | START OF STRING (SOS)
     39 |  00000099 | SINGLE GRAPHIC CHARACTER INTRODUCER (SGCI)
     3A |  0000009A | SINGLE CHARACTER INTRODUCER (SCI)
     3B |  0000009B | CONTROL SEQUENCE INTRODUCER (CSI)
     3C |  00000014 | DEVICE CONTROL FOUR (DC4)
     3D |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     3E |  0000009E | PRIVACY MESSAGE (PM)
     3F |  0000001A | SUBSTITUTE (SUB)
     40 |  00000020 | SPACE
     41 |  000005D0 | HEBREW LETTER ALEF
     42 |  000005D1 | HEBREW LETTER BET
     43 |  000005D2 | HEBREW LETTER GIMEL
     44 |  000005D3 | HEBREW LETTER DALET
     45 |  000005D4 | HEBREW LETTER HE
     46 |  000005D5 | HEBREW LETTER VAV
     47 |  000005D6 | HEBREW LETTER ZAYIN
     48 |  000005D7 | HEBREW LETTER HET
     49 |  000005D8 | HEBREW LETTER TET
     4A |  000000A2 | CENT SIGN
     4B |  0000002E | FULL STOP
     4C |  0000003C | LESS-THAN SIGN
     4D |  00000028 | LEFT PARENTHESIS
     4E |  0000002B | PLUS SIGN
     4F |  0000007C | VERTICAL LINE
     50 |  00000026 | AMPERSAND
     51 |  000005D9 | HEBREW LETTER YOD
     52 |  000005DA | HEBREW LETTER FINAL KAF
     53 |  000005DB | HEBREW LETTER KAF
     54 |  000005DC | HEBREW LETTER LAMED
     55 |  000005DD | HEBREW LETTER FINAL MEM
     56 |  000005DE | HEBREW LETTER MEM
     57 |  000005DF | HEBREW LETTER FINAL NUN
     58 |  000005E0 | HEBREW LETTER NUN
     59 |  000005E1 | HEBREW LETTER SAMEKH
     5A |  00000021 | EXCLAMATION MARK
     5B |  00000024 | DOLLAR SIGN
     5C |  0000002A | ASTERISK
     5D |  00000029 | RIGHT PARENTHESIS
     5E |  0000003B | SEMICOLON
     5F |  000000AC | NOT SIGN
     60 |  0000002D | HYPHEN-MINUS
     61 |  0000002F | SOLIDUS
     62 |  000005E2 | HEBREW LETTER AYIN
     63 |  000005E3 | HEBREW LETTER FINAL PE
     64 |  000005E4 | HEBREW LETTER PE
     65 |  000005E5 | HEBREW LETTER FINAL TSADI
     66 |  000005E6 | HEBREW LETTER TSADI
     67 |  000005E7 | HEBREW LETTER QOF
     68 |  000005E8 | HEBREW LETTER RESH
     69 |  000005E9 | HEBREW LETTER SHIN
     6A |  000000A6 | BROKEN BAR
     6B |  0000002C | COMMA
     6C |  00000025 | PERCENT SIGN
     6D |  0000005F | LOW LINE
     6E |  0000003E | GREATER-THAN SIGN
     6F |  0000003F | QUESTION MARK
     71 |  000005EA | HEBREW LETTER TAV
     74 |  000000A0 | NO-BREAK SPACE
     78 |  000021D4 | LEFT RIGHT DOUBLE ARROW
     79 |  00000060 | GRAVE ACCENT
     7A |  0000003A | COLON
     7B |  00000023 | NUMBER SIGN
     7C |  00000040 | COMMERCIAL AT
     7D |  00000027 | APOSTROPHE
     7E |  0000003D | EQUALS SIGN
     7F |  00000022 | QUOTATION MARK
     81 |  00000061 | LATIN SMALL LETTER A
     82 |  00000062 | LATIN SMALL LETTER B
     83 |  00000063 | LATIN SMALL LETTER C
     84 |  00000064 | LATIN SMALL LETTER D
     85 |  00000065 | LATIN SMALL LETTER E
     86 |  00000066 | LATIN SMALL LETTER F
     87 |  00000067 | LATIN SMALL LETTER G
     88 |  00000068 | LATIN SMALL LETTER H
     89 |  00000069 | LATIN SMALL LETTER I
     8A |  000000AB | LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
     8B |  000000BB | RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
     90 |  000000B0 | DEGREE SIGN
     91 |  0000006A | LATIN SMALL LETTER J
     92 |  0000006B | LATIN SMALL LETTER K
     93 |  0000006C | LATIN SMALL LETTER L
     94 |  0000006D | LATIN SMALL LETTER M
     95 |  0000006E | LATIN SMALL LETTER N
     96 |  0000006F | LATIN SMALL LETTER O
     97 |  00000070 | LATIN SMALL LETTER P
     98 |  00000071 | LATIN SMALL LETTER Q
     99 |  00000072 | LATIN SMALL LETTER R
     9D |  000000B8 | CEDILLA
     9F |  000000A4 | CURRENCY SIGN
     A0 |  000000B5 | MICRO SIGN
     A1 |  0000007E | TILDE
     A2 |  00000073 | LATIN SMALL LETTER S
     A3 |  00000074 | LATIN SMALL LETTER T
     A4 |  00000075 | LATIN SMALL LETTER U
     A5 |  00000076 | LATIN SMALL LETTER V
     A6 |  00000077 | LATIN SMALL LETTER W
     A7 |  00000078 | LATIN SMALL LETTER X
     A8 |  00000079 | LATIN SMALL LETTER Y
     A9 |  0000007A | LATIN SMALL LETTER Z
     AF |  000000AE | REGISTERED SIGN
     B0 |  0000005E | CIRCUMFLEX ACCENT
     B1 |  000000A3 | POUND SIGN
     B2 |  000000A5 | YEN SIGN
     B3 |  000000B7 | MIDDLE DOT
     B4 |  000000A9 | COPYRIGHT SIGN
     B5 |  000000A7 | SECTION SIGN
     B6 |  000000B6 | PILCROW SIGN
     B7 |  000000BC | VULGAR FRACTION ONE QUARTER
     B8 |  000000BD | VULGAR FRACTION ONE HALF
     B9 |  000000BE | VULGAR FRACTION THREE QUARTERS
     BA |  0000005B | LEFT SQUARE BRACKET
     BB |  0000005D | RIGHT SQUARE BRACKET
     BC |  0000203E | OVERLINE
     BD |  000000A8 | DIAERESIS
     BE |  000000B4 | ACUTE ACCENT
     BF |  000000D7 | MULTIPLICATION SIGN
     C0 |  0000007B | LEFT CURLY BRACKET
     C1 |  00000041 | LATIN CAPITAL LETTER A
     C2 |  00000042 | LATIN CAPITAL LETTER B
     C3 |  00000043 | LATIN CAPITAL LETTER C
     C4 |  00000044 | LATIN CAPITAL LETTER D
     C5 |  00000045 | LATIN CAPITAL LETTER E
     C6 |  00000046 | LATIN CAPITAL LETTER F
     C7 |  00000047 | LATIN CAPITAL LETTER G
     C8 |  00000048 | LATIN CAPITAL LETTER H
     C9 |  00000049 | LATIN CAPITAL LETTER I
     CA |  000000AD | SOFT HYPHEN
     D0 |  0000007D | RIGHT CURLY BRACKET
     D1 |  0000004A | LATIN CAPITAL LETTER J
     D2 |  0000004B | LATIN CAPITAL LETTER K
     D3 |  0000004C | LATIN CAPITAL LETTER L
     D4 |  0000004D | LATIN CAPITAL LETTER M
     D5 |  0000004E | LATIN CAPITAL LETTER N
     D6 |  0000004F | LATIN CAPITAL LETTER O
     D7 |  00000050 | LATIN CAPITAL LETTER P
     D8 |  00000051 | LATIN CAPITAL LETTER Q
     D9 |  00000052 | LATIN CAPITAL LETTER R
     DA |  000000B9 | SUPERSCRIPT ONE
     E0 |  0000005C | REVERSE SOLIDUS
     E1 |  000000F7 | DIVISION SIGN
     E2 |  00000053 | LATIN CAPITAL LETTER S
     E3 |  00000054 | LATIN CAPITAL LETTER T
     E4 |  00000055 | LATIN CAPITAL LETTER U
     E5 |  00000056 | LATIN CAPITAL LETTER V
     E6 |  00000057 | LATIN CAPITAL LETTER W
     E7 |  00000058 | LATIN CAPITAL LETTER X
     E8 |  00000059 | LATIN CAPITAL LETTER Y
     E9 |  0000005A | LATIN CAPITAL LETTER Z
     EA |  000000B2 | SUPERSCRIPT TWO
     F0 |  00000030 | DIGIT ZERO
     F1 |  00000031 | DIGIT ONE
     F2 |  00000032 | DIGIT TWO
     F3 |  00000033 | DIGIT THREE
     F4 |  00000034 | DIGIT FOUR
     F5 |  00000035 | DIGIT FIVE
     F6 |  00000036 | DIGIT SIX
     F7 |  00000037 | DIGIT SEVEN
     F8 |  00000038 | DIGIT EIGHT
     F9 |  00000039 | DIGIT NINE
     FA |  000000B3 | SUPERSCRIPT THREE
     FF |  0000009F | APPLICATION PROGRAM COMMAND (APC)
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/IBM437.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for IBM437.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::IBM437;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x0004,
     0x0005,
     0x0006,
     0x0007,
     0x0008,
     0x0009,
     0x000a,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x0014,
     0x0015,
     0x0016,
     0x0017,
     0x0018,
     0x0019,
     0x001a,
     0x001b,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0020,
     0x0021,
     0x0022,
     0x0023,
     0x0024,
     0x0025,
     0x0026,
     0x0027,
     0x0028,
     0x0029,
     0x002a,
     0x002b,
     0x002c,
     0x002d,
     0x002e,
     0x002f,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x003a,
     0x003b,
     0x003c,
     0x003d,
     0x003e,
     0x003f,
     0x0040,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x005b,
     0x005c,
     0x005d,
     0x005e,
     0x005f,
     0x0060,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x007b,
     0x007c,
     0x007d,
     0x007e,
     0x007f,
     0x00c7,
     0x00fc,
     0x00e9,
     0x00e2,
     0x00e4,
     0x00e0,
     0x00e5,
     0x00e7,
     0x00ea,
     0x00eb,
     0x00e8,
     0x00ef,
     0x00ee,
     0x00ec,
     0x00c4,
     0x00c5,
     0x00c9,
     0x00e6,
     0x00c6,
     0x00f4,
     0x00f6,
     0x00f2,
     0x00fb,
     0x00f9,
     0x00ff,
     0x00d6,
     0x00dc,
     0x00a2,
     0x00a3,
     0x00a5,
     0x20a7,
     0x0192,
     0x00e1,
     0x00ed,
     0x00f3,
     0x00fa,
     0x00f1,
     0x00d1,
     0x00aa,
     0x00ba,
     0x00bf,
     0x2310,
     0x00ac,
     0x00bd,
     0x00bc,
     0x00a1,
     0x00ab,
     0x00bb,
     0x2591,
     0x2592,
     0x2593,
     0x2502,
     0x2524,
     0x2561,
     0x2562,
     0x2556,
     0x2555,
     0x2563,
     0x2551,
     0x2557,
     0x255d,
     0x255c,
     0x255b,
     0x2510,
     0x2514,
     0x2534,
     0x252c,
     0x251c,
     0x2500,
     0x253c,
     0x255e,
     0x255f,
     0x255a,
     0x2554,
     0x2569,
     0x2566,
     0x2560,
     0x2550,
     0x256c,
     0x2567,
     0x2568,
     0x2564,
     0x2565,
     0x2559,
     0x2558,
     0x2552,
     0x2553,
     0x256b,
     0x256a,
     0x2518,
     0x250c,
     0x2588,
     0x2584,
     0x258c,
     0x2590,
     0x2580,
     0x03b1,
     0x00df,
     0x0393,
     0x03c0,
     0x03a3,
     0x03c3,
     0x00b5,
     0x03c4,
     0x03a6,
     0x0398,
     0x03a9,
     0x03b4,
     0x221e,
     0x03c6,
     0x03b5,
     0x2229,
     0x2261,
     0x00b1,
     0x2265,
     0x2264,
     0x2320,
     0x2321,
     0x00f7,
     0x2248,
     0x00b0,
     0x2219,
     0x00b7,
     0x221a,
     0x207f,
     0x00b2,
     0x25a0,
     0x00a0,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\x04",
     "\x05",
     "\x06",
     "\x07",
     "\x08",
     "\x09",
     "\x0a",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\x14",
     "\x15",
     "\x16",
     "\x17",
     "\x18",
     "\x19",
     "\x1a",
     "\x1b",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\x20",
     "\x21",
     "\x22",
     "\x23",
     "\x24",
     "\x25",
     "\x26",
     "\x27",
     "\x28",
     "\x29",
     "\x2a",
     "\x2b",
     "\x2c",
     "\x2d",
     "\x2e",
     "\x2f",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\x3a",
     "\x3b",
     "\x3c",
     "\x3d",
     "\x3e",
     "\x3f",
     "\x40",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\x5b",
     "\x5c",
     "\x5d",
     "\x5e",
     "\x5f",
     "\x60",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\x7b",
     "\x7c",
     "\x7d",
     "\x7e",
     "\x7f",
     "\xc3\x87",
     "\xc3\xbc",
     "\xc3\xa9",
     "\xc3\xa2",
     "\xc3\xa4",
     "\xc3\xa0",
     "\xc3\xa5",
     "\xc3\xa7",
     "\xc3\xaa",
     "\xc3\xab",
     "\xc3\xa8",
     "\xc3\xaf",
     "\xc3\xae",
     "\xc3\xac",
     "\xc3\x84",
     "\xc3\x85",
     "\xc3\x89",
     "\xc3\xa6",
     "\xc3\x86",
     "\xc3\xb4",
     "\xc3\xb6",
     "\xc3\xb2",
     "\xc3\xbb",
     "\xc3\xb9",
     "\xc3\xbf",
     "\xc3\x96",
     "\xc3\x9c",
     "\xc2\xa2",
     "\xc2\xa3",
     "\xc2\xa5",
     "\xe2\x82\xa7",
     "\xc6\x92",
     "\xc3\xa1",
     "\xc3\xad",
     "\xc3\xb3",
     "\xc3\xba",
     "\xc3\xb1",
     "\xc3\x91",
     "\xc2\xaa",
     "\xc2\xba",
     "\xc2\xbf",
     "\xe2\x8c\x90",
     "\xc2\xac",
     "\xc2\xbd",
     "\xc2\xbc",
     "\xc2\xa1",
     "\xc2\xab",
     "\xc2\xbb",
     "\xe2\x96\x91",
     "\xe2\x96\x92",
     "\xe2\x96\x93",
     "\xe2\x94\x82",
     "\xe2\x94\xa4",
     "\xe2\x95\xa1",
     "\xe2\x95\xa2",
     "\xe2\x95\x96",
     "\xe2\x95\x95",
     "\xe2\x95\xa3",
     "\xe2\x95\x91",
     "\xe2\x95\x97",
     "\xe2\x95\x9d",
     "\xe2\x95\x9c",
     "\xe2\x95\x9b",
     "\xe2\x94\x90",
     "\xe2\x94\x94",
     "\xe2\x94\xb4",
     "\xe2\x94\xac",
     "\xe2\x94\x9c",
     "\xe2\x94\x80",
     "\xe2\x94\xbc",
     "\xe2\x95\x9e",
     "\xe2\x95\x9f",
     "\xe2\x95\x9a",
     "\xe2\x95\x94",
     "\xe2\x95\xa9",
     "\xe2\x95\xa6",
     "\xe2\x95\xa0",
     "\xe2\x95\x90",
     "\xe2\x95\xac",
     "\xe2\x95\xa7",
     "\xe2\x95\xa8",
     "\xe2\x95\xa4",
     "\xe2\x95\xa5",
     "\xe2\x95\x99",
     "\xe2\x95\x98",
     "\xe2\x95\x92",
     "\xe2\x95\x93",
     "\xe2\x95\xab",
     "\xe2\x95\xaa",
     "\xe2\x94\x98",
     "\xe2\x94\x8c",
     "\xe2\x96\x88",
     "\xe2\x96\x84",
     "\xe2\x96\x8c",
     "\xe2\x96\x90",
     "\xe2\x96\x80",
     "\xce\xb1",
     "\xc3\x9f",
     "\xce\x93",
     "\xcf\x80",
     "\xce\xa3",
     "\xcf\x83",
     "\xc2\xb5",
     "\xcf\x84",
     "\xce\xa6",
     "\xce\x98",
     "\xce\xa9",
     "\xce\xb4",
     "\xe2\x88\x9e",
     "\xcf\x86",
     "\xce\xb5",
     "\xe2\x88\xa9",
     "\xe2\x89\xa1",
     "\xc2\xb1",
     "\xe2\x89\xa5",
     "\xe2\x89\xa4",
     "\xe2\x8c\xa0",
     "\xe2\x8c\xa1",
     "\xc3\xb7",
     "\xe2\x89\x88",
     "\xc2\xb0",
     "\xe2\x88\x99",
     "\xc2\xb7",
     "\xe2\x88\x9a",
     "\xe2\x81\xbf",
     "\xc2\xb2",
     "\xe2\x96\xa0",
     "\xc2\xa0",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x04",
     0x00000005 => "\x05",
     0x00000006 => "\x06",
     0x00000007 => "\x07",
     0x00000008 => "\x08",
     0x00000009 => "\x09",
     0x0000000a => "\x0a",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x14",
     0x00000015 => "\x15",
     0x00000016 => "\x16",
     0x00000017 => "\x17",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x1a",
     0x0000001b => "\x1b",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x20",
     0x00000021 => "\x21",
     0x00000022 => "\x22",
     0x00000023 => "\x23",
     0x00000024 => "\x24",
     0x00000025 => "\x25",
     0x00000026 => "\x26",
     0x00000027 => "\x27",
     0x00000028 => "\x28",
     0x00000029 => "\x29",
     0x0000002a => "\x2a",
     0x0000002b => "\x2b",
     0x0000002c => "\x2c",
     0x0000002d => "\x2d",
     0x0000002e => "\x2e",
     0x0000002f => "\x2f",
     0x00000030 => "\x30",
     0x00000031 => "\x31",
     0x00000032 => "\x32",
     0x00000033 => "\x33",
     0x00000034 => "\x34",
     0x00000035 => "\x35",
     0x00000036 => "\x36",
     0x00000037 => "\x37",
     0x00000038 => "\x38",
     0x00000039 => "\x39",
     0x0000003a => "\x3a",
     0x0000003b => "\x3b",
     0x0000003c => "\x3c",
     0x0000003d => "\x3d",
     0x0000003e => "\x3e",
     0x0000003f => "\x3f",
     0x00000040 => "\x40",
     0x00000041 => "\x41",
     0x00000042 => "\x42",
     0x00000043 => "\x43",
     0x00000044 => "\x44",
     0x00000045 => "\x45",
     0x00000046 => "\x46",
     0x00000047 => "\x47",
     0x00000048 => "\x48",
     0x00000049 => "\x49",
     0x0000004a => "\x4a",
     0x0000004b => "\x4b",
     0x0000004c => "\x4c",
     0x0000004d => "\x4d",
     0x0000004e => "\x4e",
     0x0000004f => "\x4f",
     0x00000050 => "\x50",
     0x00000051 => "\x51",
     0x00000052 => "\x52",
     0x00000053 => "\x53",
     0x00000054 => "\x54",
     0x00000055 => "\x55",
     0x00000056 => "\x56",
     0x00000057 => "\x57",
     0x00000058 => "\x58",
     0x00000059 => "\x59",
     0x0000005a => "\x5a",
     0x0000005b => "\x5b",
     0x0000005c => "\x5c",
     0x0000005d => "\x5d",
     0x0000005e => "\x5e",
     0x0000005f => "\x5f",
     0x00000060 => "\x60",
     0x00000061 => "\x61",
     0x00000062 => "\x62",
     0x00000063 => "\x63",
     0x00000064 => "\x64",
     0x00000065 => "\x65",
     0x00000066 => "\x66",
     0x00000067 => "\x67",
     0x00000068 => "\x68",
     0x00000069 => "\x69",
     0x0000006a => "\x6a",
     0x0000006b => "\x6b",
     0x0000006c => "\x6c",
     0x0000006d => "\x6d",
     0x0000006e => "\x6e",
     0x0000006f => "\x6f",
     0x00000070 => "\x70",
     0x00000071 => "\x71",
     0x00000072 => "\x72",
     0x00000073 => "\x73",
     0x00000074 => "\x74",
     0x00000075 => "\x75",
     0x00000076 => "\x76",
     0x00000077 => "\x77",
     0x00000078 => "\x78",
     0x00000079 => "\x79",
     0x0000007a => "\x7a",
     0x0000007b => "\x7b",
     0x0000007c => "\x7c",
     0x0000007d => "\x7d",
     0x0000007e => "\x7e",
     0x0000007f => "\x7f",
     0x000000a0 => "\xff",
     0x000000a1 => "\xad",
     0x000000a2 => "\x9b",
     0x000000a3 => "\x9c",
     0x000000a5 => "\x9d",
     0x000000aa => "\xa6",
     0x000000ab => "\xae",
     0x000000ac => "\xaa",
     0x000000b0 => "\xf8",
     0x000000b1 => "\xf1",
     0x000000b2 => "\xfd",
     0x000000b5 => "\xe6",
     0x000000b7 => "\xfa",
     0x000000ba => "\xa7",
     0x000000bb => "\xaf",
     0x000000bc => "\xac",
     0x000000bd => "\xab",
     0x000000bf => "\xa8",
     0x000000c4 => "\x8e",
     0x000000c5 => "\x8f",
     0x000000c6 => "\x92",
     0x000000c7 => "\x80",
     0x000000c9 => "\x90",
     0x000000d1 => "\xa5",
     0x000000d6 => "\x99",
     0x000000dc => "\x9a",
     0x000000df => "\xe1",
     0x000000e0 => "\x85",
     0x000000e1 => "\xa0",
     0x000000e2 => "\x83",
     0x000000e4 => "\x84",
     0x000000e5 => "\x86",
     0x000000e6 => "\x91",
     0x000000e7 => "\x87",
     0x000000e8 => "\x8a",
     0x000000e9 => "\x82",
     0x000000ea => "\x88",
     0x000000eb => "\x89",
     0x000000ec => "\x8d",
     0x000000ed => "\xa1",
     0x000000ee => "\x8c",
     0x000000ef => "\x8b",
     0x000000f1 => "\xa4",
     0x000000f2 => "\x95",
     0x000000f3 => "\xa2",
     0x000000f4 => "\x93",
     0x000000f6 => "\x94",
     0x000000f7 => "\xf6",
     0x000000f9 => "\x97",
     0x000000fa => "\xa3",
     0x000000fb => "\x96",
     0x000000fc => "\x81",
     0x000000ff => "\x98",
     0x00000192 => "\x9f",
     0x00000393 => "\xe2",
     0x00000398 => "\xe9",
     0x000003a3 => "\xe4",
     0x000003a6 => "\xe8",
     0x000003a9 => "\xea",
     0x000003b1 => "\xe0",
     0x000003b4 => "\xeb",
     0x000003b5 => "\xee",
     0x000003c0 => "\xe3",
     0x000003c3 => "\xe5",
     0x000003c4 => "\xe7",
     0x000003c6 => "\xed",
     0x0000207f => "\xfc",
     0x000020a7 => "\x9e",
     0x00002219 => "\xf9",
     0x0000221a => "\xfb",
     0x0000221e => "\xec",
     0x00002229 => "\xef",
     0x00002248 => "\xf7",
     0x00002261 => "\xf0",
     0x00002264 => "\xf3",
     0x00002265 => "\xf2",
     0x00002310 => "\xa9",
     0x00002320 => "\xf4",
     0x00002321 => "\xf5",
     0x00002500 => "\xc4",
     0x00002502 => "\xb3",
     0x0000250c => "\xda",
     0x00002510 => "\xbf",
     0x00002514 => "\xc0",
     0x00002518 => "\xd9",
     0x0000251c => "\xc3",
     0x00002524 => "\xb4",
     0x0000252c => "\xc2",
     0x00002534 => "\xc1",
     0x0000253c => "\xc5",
     0x00002550 => "\xcd",
     0x00002551 => "\xba",
     0x00002552 => "\xd5",
     0x00002553 => "\xd6",
     0x00002554 => "\xc9",
     0x00002555 => "\xb8",
     0x00002556 => "\xb7",
     0x00002557 => "\xbb",
     0x00002558 => "\xd4",
     0x00002559 => "\xd3",
     0x0000255a => "\xc8",
     0x0000255b => "\xbe",
     0x0000255c => "\xbd",
     0x0000255d => "\xbc",
     0x0000255e => "\xc6",
     0x0000255f => "\xc7",
     0x00002560 => "\xcc",
     0x00002561 => "\xb5",
     0x00002562 => "\xb6",
     0x00002563 => "\xb9",
     0x00002564 => "\xd1",
     0x00002565 => "\xd2",
     0x00002566 => "\xcb",
     0x00002567 => "\xcf",
     0x00002568 => "\xd0",
     0x00002569 => "\xca",
     0x0000256a => "\xd8",
     0x0000256b => "\xd7",
     0x0000256c => "\xce",
     0x00002580 => "\xdf",
     0x00002584 => "\xdc",
     0x00002588 => "\xdb",
     0x0000258c => "\xdd",
     0x00002590 => "\xde",
     0x00002591 => "\xb0",
     0x00002592 => "\xb1",
     0x00002593 => "\xb2",
     0x000025a0 => "\xfe",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::IBM437 - Conversion routines for IBM437
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for IBM437.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
   source: IBM NLS RM Vol2 SE09-8002-01, March 1990
  alias CP437
  alias 437
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  00000004 | END OF TRANSMISSION (EOT)
     05 |  00000005 | ENQUIRY (ENQ)
     06 |  00000006 | ACKNOWLEDGE (ACK)
     07 |  00000007 | BELL (BEL)
     08 |  00000008 | BACKSPACE (BS)
     09 |  00000009 | CHARACTER TABULATION (HT)
     0A |  0000000A | LINE FEED (LF)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  00000014 | DEVICE CONTROL FOUR (DC4)
     15 |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     16 |  00000016 | SYNCHRONOUS IDLE (SYN)
     17 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  0000001A | SUBSTITUTE (SUB)
     1B |  0000001B | ESCAPE (ESC)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000020 | SPACE
     21 |  00000021 | EXCLAMATION MARK
     22 |  00000022 | QUOTATION MARK
     23 |  00000023 | NUMBER SIGN
     24 |  00000024 | DOLLAR SIGN
     25 |  00000025 | PERCENT SIGN
     26 |  00000026 | AMPERSAND
     27 |  00000027 | APOSTROPHE
     28 |  00000028 | LEFT PARENTHESIS
     29 |  00000029 | RIGHT PARENTHESIS
     2A |  0000002A | ASTERISK
     2B |  0000002B | PLUS SIGN
     2C |  0000002C | COMMA
     2D |  0000002D | HYPHEN-MINUS
     2E |  0000002E | FULL STOP
     2F |  0000002F | SOLIDUS
     30 |  00000030 | DIGIT ZERO
     31 |  00000031 | DIGIT ONE
     32 |  00000032 | DIGIT TWO
     33 |  00000033 | DIGIT THREE
     34 |  00000034 | DIGIT FOUR
     35 |  00000035 | DIGIT FIVE
     36 |  00000036 | DIGIT SIX
     37 |  00000037 | DIGIT SEVEN
     38 |  00000038 | DIGIT EIGHT
     39 |  00000039 | DIGIT NINE
     3A |  0000003A | COLON
     3B |  0000003B | SEMICOLON
     3C |  0000003C | LESS-THAN SIGN
     3D |  0000003D | EQUALS SIGN
     3E |  0000003E | GREATER-THAN SIGN
     3F |  0000003F | QUESTION MARK
     40 |  00000040 | COMMERCIAL AT
     41 |  00000041 | LATIN CAPITAL LETTER A
     42 |  00000042 | LATIN CAPITAL LETTER B
     43 |  00000043 | LATIN CAPITAL LETTER C
     44 |  00000044 | LATIN CAPITAL LETTER D
     45 |  00000045 | LATIN CAPITAL LETTER E
     46 |  00000046 | LATIN CAPITAL LETTER F
     47 |  00000047 | LATIN CAPITAL LETTER G
     48 |  00000048 | LATIN CAPITAL LETTER H
     49 |  00000049 | LATIN CAPITAL LETTER I
     4A |  0000004A | LATIN CAPITAL LETTER J
     4B |  0000004B | LATIN CAPITAL LETTER K
     4C |  0000004C | LATIN CAPITAL LETTER L
     4D |  0000004D | LATIN CAPITAL LETTER M
     4E |  0000004E | LATIN CAPITAL LETTER N
     4F |  0000004F | LATIN CAPITAL LETTER O
     50 |  00000050 | LATIN CAPITAL LETTER P
     51 |  00000051 | LATIN CAPITAL LETTER Q
     52 |  00000052 | LATIN CAPITAL LETTER R
     53 |  00000053 | LATIN CAPITAL LETTER S
     54 |  00000054 | LATIN CAPITAL LETTER T
     55 |  00000055 | LATIN CAPITAL LETTER U
     56 |  00000056 | LATIN CAPITAL LETTER V
     57 |  00000057 | LATIN CAPITAL LETTER W
     58 |  00000058 | LATIN CAPITAL LETTER X
     59 |  00000059 | LATIN CAPITAL LETTER Y
     5A |  0000005A | LATIN CAPITAL LETTER Z
     5B |  0000005B | LEFT SQUARE BRACKET
     5C |  0000005C | REVERSE SOLIDUS
     5D |  0000005D | RIGHT SQUARE BRACKET
     5E |  0000005E | CIRCUMFLEX ACCENT
     5F |  0000005F | LOW LINE
     60 |  00000060 | GRAVE ACCENT
     61 |  00000061 | LATIN SMALL LETTER A
     62 |  00000062 | LATIN SMALL LETTER B
     63 |  00000063 | LATIN SMALL LETTER C
     64 |  00000064 | LATIN SMALL LETTER D
     65 |  00000065 | LATIN SMALL LETTER E
     66 |  00000066 | LATIN SMALL LETTER F
     67 |  00000067 | LATIN SMALL LETTER G
     68 |  00000068 | LATIN SMALL LETTER H
     69 |  00000069 | LATIN SMALL LETTER I
     6A |  0000006A | LATIN SMALL LETTER J
     6B |  0000006B | LATIN SMALL LETTER K
     6C |  0000006C | LATIN SMALL LETTER L
     6D |  0000006D | LATIN SMALL LETTER M
     6E |  0000006E | LATIN SMALL LETTER N
     6F |  0000006F | LATIN SMALL LETTER O
     70 |  00000070 | LATIN SMALL LETTER P
     71 |  00000071 | LATIN SMALL LETTER Q
     72 |  00000072 | LATIN SMALL LETTER R
     73 |  00000073 | LATIN SMALL LETTER S
     74 |  00000074 | LATIN SMALL LETTER T
     75 |  00000075 | LATIN SMALL LETTER U
     76 |  00000076 | LATIN SMALL LETTER V
     77 |  00000077 | LATIN SMALL LETTER W
     78 |  00000078 | LATIN SMALL LETTER X
     79 |  00000079 | LATIN SMALL LETTER Y
     7A |  0000007A | LATIN SMALL LETTER Z
     7B |  0000007B | LEFT CURLY BRACKET
     7C |  0000007C | VERTICAL LINE
     7D |  0000007D | RIGHT CURLY BRACKET
     7E |  0000007E | TILDE
     7F |  0000007F | DELETE (DEL)
     80 |  000000C7 | LATIN CAPITAL LETTER C WITH CEDILLA
     81 |  000000FC | LATIN SMALL LETTER U WITH DIAERESIS
     82 |  000000E9 | LATIN SMALL LETTER E WITH ACUTE
     83 |  000000E2 | LATIN SMALL LETTER A WITH CIRCUMFLEX
     84 |  000000E4 | LATIN SMALL LETTER A WITH DIAERESIS
     85 |  000000E0 | LATIN SMALL LETTER A WITH GRAVE
     86 |  000000E5 | LATIN SMALL LETTER A WITH RING ABOVE
     87 |  000000E7 | LATIN SMALL LETTER C WITH CEDILLA
     88 |  000000EA | LATIN SMALL LETTER E WITH CIRCUMFLEX
     89 |  000000EB | LATIN SMALL LETTER E WITH DIAERESIS
     8A |  000000E8 | LATIN SMALL LETTER E WITH GRAVE
     8B |  000000EF | LATIN SMALL LETTER I WITH DIAERESIS
     8C |  000000EE | LATIN SMALL LETTER I WITH CIRCUMFLEX
     8D |  000000EC | LATIN SMALL LETTER I WITH GRAVE
     8E |  000000C4 | LATIN CAPITAL LETTER A WITH DIAERESIS
     8F |  000000C5 | LATIN CAPITAL LETTER A WITH RING ABOVE
     90 |  000000C9 | LATIN CAPITAL LETTER E WITH ACUTE
     91 |  000000E6 | LATIN SMALL LETTER AE
     92 |  000000C6 | LATIN CAPITAL LETTER AE
     93 |  000000F4 | LATIN SMALL LETTER O WITH CIRCUMFLEX
     94 |  000000F6 | LATIN SMALL LETTER O WITH DIAERESIS
     95 |  000000F2 | LATIN SMALL LETTER O WITH GRAVE
     96 |  000000FB | LATIN SMALL LETTER U WITH CIRCUMFLEX
     97 |  000000F9 | LATIN SMALL LETTER U WITH GRAVE
     98 |  000000FF | LATIN SMALL LETTER Y WITH DIAERESIS
     99 |  000000D6 | LATIN CAPITAL LETTER O WITH DIAERESIS
     9A |  000000DC | LATIN CAPITAL LETTER U WITH DIAERESIS
     9B |  000000A2 | CENT SIGN
     9C |  000000A3 | POUND SIGN
     9D |  000000A5 | YEN SIGN
     9E |  000020A7 | PESETA SIGN
     9F |  00000192 | LATIN SMALL LETTER F WITH HOOK
     A0 |  000000E1 | LATIN SMALL LETTER A WITH ACUTE
     A1 |  000000ED | LATIN SMALL LETTER I WITH ACUTE
     A2 |  000000F3 | LATIN SMALL LETTER O WITH ACUTE
     A3 |  000000FA | LATIN SMALL LETTER U WITH ACUTE
     A4 |  000000F1 | LATIN SMALL LETTER N WITH TILDE
     A5 |  000000D1 | LATIN CAPITAL LETTER N WITH TILDE
     A6 |  000000AA | FEMININE ORDINAL INDICATOR
     A7 |  000000BA | MASCULINE ORDINAL INDICATOR
     A8 |  000000BF | INVERTED QUESTION MARK
     A9 |  00002310 | REVERSED NOT SIGN
     AA |  000000AC | NOT SIGN
     AB |  000000BD | VULGAR FRACTION ONE HALF
     AC |  000000BC | VULGAR FRACTION ONE QUARTER
     AD |  000000A1 | INVERTED EXCLAMATION MARK
     AE |  000000AB | LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
     AF |  000000BB | RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
     B0 |  00002591 | LIGHT SHADE
     B1 |  00002592 | MEDIUM SHADE
     B2 |  00002593 | DARK SHADE
     B3 |  00002502 | BOX DRAWINGS LIGHT VERTICAL
     B4 |  00002524 | BOX DRAWINGS LIGHT VERTICAL AND LEFT
     B5 |  00002561 | BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE
     B6 |  00002562 | BOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLE
     B7 |  00002556 | BOX DRAWINGS DOWN DOUBLE AND LEFT SINGLE
     B8 |  00002555 | BOX DRAWINGS DOWN SINGLE AND LEFT DOUBLE
     B9 |  00002563 | BOX DRAWINGS DOUBLE VERTICAL AND LEFT
     BA |  00002551 | BOX DRAWINGS DOUBLE VERTICAL
     BB |  00002557 | BOX DRAWINGS DOUBLE DOWN AND LEFT
     BC |  0000255D | BOX DRAWINGS DOUBLE UP AND LEFT
     BD |  0000255C | BOX DRAWINGS UP DOUBLE AND LEFT SINGLE
     BE |  0000255B | BOX DRAWINGS UP SINGLE AND LEFT DOUBLE
     BF |  00002510 | BOX DRAWINGS LIGHT DOWN AND LEFT
     C0 |  00002514 | BOX DRAWINGS LIGHT UP AND RIGHT
     C1 |  00002534 | BOX DRAWINGS LIGHT UP AND HORIZONTAL
     C2 |  0000252C | BOX DRAWINGS LIGHT DOWN AND HORIZONTAL
     C3 |  0000251C | BOX DRAWINGS LIGHT VERTICAL AND RIGHT
     C4 |  00002500 | BOX DRAWINGS LIGHT HORIZONTAL
     C5 |  0000253C | BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL
     C6 |  0000255E | BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE
     C7 |  0000255F | BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE
     C8 |  0000255A | BOX DRAWINGS DOUBLE UP AND RIGHT
     C9 |  00002554 | BOX DRAWINGS DOUBLE DOWN AND RIGHT
     CA |  00002569 | BOX DRAWINGS DOUBLE UP AND HORIZONTAL
     CB |  00002566 | BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL
     CC |  00002560 | BOX DRAWINGS DOUBLE VERTICAL AND RIGHT
     CD |  00002550 | BOX DRAWINGS DOUBLE HORIZONTAL
     CE |  0000256C | BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL
     CF |  00002567 | BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE
     D0 |  00002568 | BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE
     D1 |  00002564 | BOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLE
     D2 |  00002565 | BOX DRAWINGS DOWN DOUBLE AND HORIZONTAL SINGLE
     D3 |  00002559 | BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE
     D4 |  00002558 | BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE
     D5 |  00002552 | BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE
     D6 |  00002553 | BOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLE
     D7 |  0000256B | BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLE
     D8 |  0000256A | BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE
     D9 |  00002518 | BOX DRAWINGS LIGHT UP AND LEFT
     DA |  0000250C | BOX DRAWINGS LIGHT DOWN AND RIGHT
     DB |  00002588 | FULL BLOCK
     DC |  00002584 | LOWER HALF BLOCK
     DD |  0000258C | LEFT HALF BLOCK
     DE |  00002590 | RIGHT HALF BLOCK
     DF |  00002580 | UPPER HALF BLOCK
     E0 |  000003B1 | GREEK SMALL LETTER ALPHA
     E1 |  000000DF | LATIN SMALL LETTER SHARP S (German)
     E2 |  00000393 | GREEK CAPITAL LETTER GAMMA
     E3 |  000003C0 | GREEK SMALL LETTER PI
     E4 |  000003A3 | GREEK CAPITAL LETTER SIGMA
     E5 |  000003C3 | GREEK SMALL LETTER SIGMA
     E6 |  000000B5 | MICRO SIGN
     E7 |  000003C4 | GREEK SMALL LETTER TAU
     E8 |  000003A6 | GREEK CAPITAL LETTER PHI
     E9 |  00000398 | GREEK CAPITAL LETTER THETA
     EA |  000003A9 | GREEK CAPITAL LETTER OMEGA
     EB |  000003B4 | GREEK SMALL LETTER DELTA
     EC |  0000221E | INFINITY
     ED |  000003C6 | GREEK SMALL LETTER PHI
     EE |  000003B5 | GREEK SMALL LETTER EPSILON
     EF |  00002229 | INTERSECTION
     F0 |  00002261 | IDENTICAL TO
     F1 |  000000B1 | PLUS-MINUS SIGN
     F2 |  00002265 | GREATER-THAN OR EQUAL TO
     F3 |  00002264 | LESS-THAN OR EQUAL TO
     F4 |  00002320 | TOP HALF INTEGRAL
     F5 |  00002321 | BOTTOM HALF INTEGRAL
     F6 |  000000F7 | DIVISION SIGN
     F7 |  00002248 | ALMOST EQUAL TO
     F8 |  000000B0 | DEGREE SIGN
     F9 |  00002219 | BULLET OPERATOR
     FA |  000000B7 | MIDDLE DOT
     FB |  0000221A | SQUARE ROOT
     FC |  0000207F | SUPERSCRIPT LATIN SMALL LETTER N
     FD |  000000B2 | SUPERSCRIPT TWO
     FE |  000025A0 | BLACK SQUARE
     FF |  000000A0 | NO-BREAK SPACE
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/IBM500.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for IBM500.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::IBM500;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x009c,
     0x0009,
     0x0086,
     0x007f,
     0x0097,
     0x008d,
     0x008e,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x009d,
     0x0085,
     0x0008,
     0x0087,
     0x0018,
     0x0019,
     0x0092,
     0x008f,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0080,
     0x0081,
     0x0082,
     0x0083,
     0x0084,
     0x000a,
     0x0017,
     0x001b,
     0x0088,
     0x0089,
     0x008a,
     0x008b,
     0x008c,
     0x0005,
     0x0006,
     0x0007,
     0x0090,
     0x0091,
     0x0016,
     0x0093,
     0x0094,
     0x0095,
     0x0096,
     0x0004,
     0x0098,
     0x0099,
     0x009a,
     0x009b,
     0x0014,
     0x0015,
     0x009e,
     0x001a,
     0x0020,
     0x00a0,
     0x00e2,
     0x00e4,
     0x00e0,
     0x00e1,
     0x00e3,
     0x00e5,
     0x00e7,
     0x00f1,
     0x005b,
     0x002e,
     0x003c,
     0x0028,
     0x002b,
     0x0021,
     0x0026,
     0x00e9,
     0x00ea,
     0x00eb,
     0x00e8,
     0x00ed,
     0x00ee,
     0x00ef,
     0x00ec,
     0x00df,
     0x005d,
     0x0024,
     0x002a,
     0x0029,
     0x003b,
     0x005e,
     0x002d,
     0x002f,
     0x00c2,
     0x00c4,
     0x00c0,
     0x00c1,
     0x00c3,
     0x00c5,
     0x00c7,
     0x00d1,
     0x00a6,
     0x002c,
     0x0025,
     0x005f,
     0x003e,
     0x003f,
     0x00f8,
     0x00c9,
     0x00ca,
     0x00cb,
     0x00c8,
     0x00cd,
     0x00ce,
     0x00cf,
     0x00cc,
     0x0060,
     0x003a,
     0x0023,
     0x0040,
     0x0027,
     0x003d,
     0x0022,
     0x00d8,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x00ab,
     0x00bb,
     0x00f0,
     0x00fd,
     0x00fe,
     0x00b1,
     0x00b0,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x00aa,
     0x00ba,
     0x00e6,
     0x00b8,
     0x00c6,
     0x00a4,
     0x00b5,
     0x007e,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x00a1,
     0x00bf,
     0x00d0,
     0x00dd,
     0x00de,
     0x00ae,
     0x00a2,
     0x00a3,
     0x00a5,
     0x00b7,
     0x00a9,
     0x00a7,
     0x00b6,
     0x00bc,
     0x00bd,
     0x00be,
     0x00ac,
     0x007c,
     0x00af,
     0x00a8,
     0x00b4,
     0x00d7,
     0x007b,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x00ad,
     0x00f4,
     0x00f6,
     0x00f2,
     0x00f3,
     0x00f5,
     0x007d,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x00b9,
     0x00fb,
     0x00fc,
     0x00f9,
     0x00fa,
     0x00ff,
     0x005c,
     0x00f7,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x00b2,
     0x00d4,
     0x00d6,
     0x00d2,
     0x00d3,
     0x00d5,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x00b3,
     0x00db,
     0x00dc,
     0x00d9,
     0x00da,
     0x009f,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\xc2\x9c",
     "\x09",
     "\xc2\x86",
     "\x7f",
     "\xc2\x97",
     "\xc2\x8d",
     "\xc2\x8e",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\xc2\x9d",
     "\xc2\x85",
     "\x08",
     "\xc2\x87",
     "\x18",
     "\x19",
     "\xc2\x92",
     "\xc2\x8f",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\xc2\x80",
     "\xc2\x81",
     "\xc2\x82",
     "\xc2\x83",
     "\xc2\x84",
     "\x0a",
     "\x17",
     "\x1b",
     "\xc2\x88",
     "\xc2\x89",
     "\xc2\x8a",
     "\xc2\x8b",
     "\xc2\x8c",
     "\x05",
     "\x06",
     "\x07",
     "\xc2\x90",
     "\xc2\x91",
     "\x16",
     "\xc2\x93",
     "\xc2\x94",
     "\xc2\x95",
     "\xc2\x96",
     "\x04",
     "\xc2\x98",
     "\xc2\x99",
     "\xc2\x9a",
     "\xc2\x9b",
     "\x14",
     "\x15",
     "\xc2\x9e",
     "\x1a",
     "\x20",
     "\xc2\xa0",
     "\xc3\xa2",
     "\xc3\xa4",
     "\xc3\xa0",
     "\xc3\xa1",
     "\xc3\xa3",
     "\xc3\xa5",
     "\xc3\xa7",
     "\xc3\xb1",
     "\x5b",
     "\x2e",
     "\x3c",
     "\x28",
     "\x2b",
     "\x21",
     "\x26",
     "\xc3\xa9",
     "\xc3\xaa",
     "\xc3\xab",
     "\xc3\xa8",
     "\xc3\xad",
     "\xc3\xae",
     "\xc3\xaf",
     "\xc3\xac",
     "\xc3\x9f",
     "\x5d",
     "\x24",
     "\x2a",
     "\x29",
     "\x3b",
     "\x5e",
     "\x2d",
     "\x2f",
     "\xc3\x82",
     "\xc3\x84",
     "\xc3\x80",
     "\xc3\x81",
     "\xc3\x83",
     "\xc3\x85",
     "\xc3\x87",
     "\xc3\x91",
     "\xc2\xa6",
     "\x2c",
     "\x25",
     "\x5f",
     "\x3e",
     "\x3f",
     "\xc3\xb8",
     "\xc3\x89",
     "\xc3\x8a",
     "\xc3\x8b",
     "\xc3\x88",
     "\xc3\x8d",
     "\xc3\x8e",
     "\xc3\x8f",
     "\xc3\x8c",
     "\x60",
     "\x3a",
     "\x23",
     "\x40",
     "\x27",
     "\x3d",
     "\x22",
     "\xc3\x98",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\xc2\xab",
     "\xc2\xbb",
     "\xc3\xb0",
     "\xc3\xbd",
     "\xc3\xbe",
     "\xc2\xb1",
     "\xc2\xb0",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\xc2\xaa",
     "\xc2\xba",
     "\xc3\xa6",
     "\xc2\xb8",
     "\xc3\x86",
     "\xc2\xa4",
     "\xc2\xb5",
     "\x7e",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\xc2\xa1",
     "\xc2\xbf",
     "\xc3\x90",
     "\xc3\x9d",
     "\xc3\x9e",
     "\xc2\xae",
     "\xc2\xa2",
     "\xc2\xa3",
     "\xc2\xa5",
     "\xc2\xb7",
     "\xc2\xa9",
     "\xc2\xa7",
     "\xc2\xb6",
     "\xc2\xbc",
     "\xc2\xbd",
     "\xc2\xbe",
     "\xc2\xac",
     "\x7c",
     "\xc2\xaf",
     "\xc2\xa8",
     "\xc2\xb4",
     "\xc3\x97",
     "\x7b",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\xc2\xad",
     "\xc3\xb4",
     "\xc3\xb6",
     "\xc3\xb2",
     "\xc3\xb3",
     "\xc3\xb5",
     "\x7d",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\xc2\xb9",
     "\xc3\xbb",
     "\xc3\xbc",
     "\xc3\xb9",
     "\xc3\xba",
     "\xc3\xbf",
     "\x5c",
     "\xc3\xb7",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\xc2\xb2",
     "\xc3\x94",
     "\xc3\x96",
     "\xc3\x92",
     "\xc3\x93",
     "\xc3\x95",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\xc2\xb3",
     "\xc3\x9b",
     "\xc3\x9c",
     "\xc3\x99",
     "\xc3\x9a",
     "\xc2\x9f",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x37",
     0x00000005 => "\x2d",
     0x00000006 => "\x2e",
     0x00000007 => "\x2f",
     0x00000008 => "\x16",
     0x00000009 => "\x05",
     0x0000000a => "\x25",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x3c",
     0x00000015 => "\x3d",
     0x00000016 => "\x32",
     0x00000017 => "\x26",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x3f",
     0x0000001b => "\x27",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x40",
     0x00000021 => "\x4f",
     0x00000022 => "\x7f",
     0x00000023 => "\x7b",
     0x00000024 => "\x5b",
     0x00000025 => "\x6c",
     0x00000026 => "\x50",
     0x00000027 => "\x7d",
     0x00000028 => "\x4d",
     0x00000029 => "\x5d",
     0x0000002a => "\x5c",
     0x0000002b => "\x4e",
     0x0000002c => "\x6b",
     0x0000002d => "\x60",
     0x0000002e => "\x4b",
     0x0000002f => "\x61",
     0x00000030 => "\xf0",
     0x00000031 => "\xf1",
     0x00000032 => "\xf2",
     0x00000033 => "\xf3",
     0x00000034 => "\xf4",
     0x00000035 => "\xf5",
     0x00000036 => "\xf6",
     0x00000037 => "\xf7",
     0x00000038 => "\xf8",
     0x00000039 => "\xf9",
     0x0000003a => "\x7a",
     0x0000003b => "\x5e",
     0x0000003c => "\x4c",
     0x0000003d => "\x7e",
     0x0000003e => "\x6e",
     0x0000003f => "\x6f",
     0x00000040 => "\x7c",
     0x00000041 => "\xc1",
     0x00000042 => "\xc2",
     0x00000043 => "\xc3",
     0x00000044 => "\xc4",
     0x00000045 => "\xc5",
     0x00000046 => "\xc6",
     0x00000047 => "\xc7",
     0x00000048 => "\xc8",
     0x00000049 => "\xc9",
     0x0000004a => "\xd1",
     0x0000004b => "\xd2",
     0x0000004c => "\xd3",
     0x0000004d => "\xd4",
     0x0000004e => "\xd5",
     0x0000004f => "\xd6",
     0x00000050 => "\xd7",
     0x00000051 => "\xd8",
     0x00000052 => "\xd9",
     0x00000053 => "\xe2",
     0x00000054 => "\xe3",
     0x00000055 => "\xe4",
     0x00000056 => "\xe5",
     0x00000057 => "\xe6",
     0x00000058 => "\xe7",
     0x00000059 => "\xe8",
     0x0000005a => "\xe9",
     0x0000005b => "\x4a",
     0x0000005c => "\xe0",
     0x0000005d => "\x5a",
     0x0000005e => "\x5f",
     0x0000005f => "\x6d",
     0x00000060 => "\x79",
     0x00000061 => "\x81",
     0x00000062 => "\x82",
     0x00000063 => "\x83",
     0x00000064 => "\x84",
     0x00000065 => "\x85",
     0x00000066 => "\x86",
     0x00000067 => "\x87",
     0x00000068 => "\x88",
     0x00000069 => "\x89",
     0x0000006a => "\x91",
     0x0000006b => "\x92",
     0x0000006c => "\x93",
     0x0000006d => "\x94",
     0x0000006e => "\x95",
     0x0000006f => "\x96",
     0x00000070 => "\x97",
     0x00000071 => "\x98",
     0x00000072 => "\x99",
     0x00000073 => "\xa2",
     0x00000074 => "\xa3",
     0x00000075 => "\xa4",
     0x00000076 => "\xa5",
     0x00000077 => "\xa6",
     0x00000078 => "\xa7",
     0x00000079 => "\xa8",
     0x0000007a => "\xa9",
     0x0000007b => "\xc0",
     0x0000007c => "\xbb",
     0x0000007d => "\xd0",
     0x0000007e => "\xa1",
     0x0000007f => "\x07",
     0x00000080 => "\x20",
     0x00000081 => "\x21",
     0x00000082 => "\x22",
     0x00000083 => "\x23",
     0x00000084 => "\x24",
     0x00000085 => "\x15",
     0x00000086 => "\x06",
     0x00000087 => "\x17",
     0x00000088 => "\x28",
     0x00000089 => "\x29",
     0x0000008a => "\x2a",
     0x0000008b => "\x2b",
     0x0000008c => "\x2c",
     0x0000008d => "\x09",
     0x0000008e => "\x0a",
     0x0000008f => "\x1b",
     0x00000090 => "\x30",
     0x00000091 => "\x31",
     0x00000092 => "\x1a",
     0x00000093 => "\x33",
     0x00000094 => "\x34",
     0x00000095 => "\x35",
     0x00000096 => "\x36",
     0x00000097 => "\x08",
     0x00000098 => "\x38",
     0x00000099 => "\x39",
     0x0000009a => "\x3a",
     0x0000009b => "\x3b",
     0x0000009c => "\x04",
     0x0000009d => "\x14",
     0x0000009e => "\x3e",
     0x0000009f => "\xff",
     0x000000a0 => "\x41",
     0x000000a1 => "\xaa",
     0x000000a2 => "\xb0",
     0x000000a3 => "\xb1",
     0x000000a4 => "\x9f",
     0x000000a5 => "\xb2",
     0x000000a6 => "\x6a",
     0x000000a7 => "\xb5",
     0x000000a8 => "\xbd",
     0x000000a9 => "\xb4",
     0x000000aa => "\x9a",
     0x000000ab => "\x8a",
     0x000000ac => "\xba",
     0x000000ad => "\xca",
     0x000000ae => "\xaf",
     0x000000af => "\xbc",
     0x000000b0 => "\x90",
     0x000000b1 => "\x8f",
     0x000000b2 => "\xea",
     0x000000b3 => "\xfa",
     0x000000b4 => "\xbe",
     0x000000b5 => "\xa0",
     0x000000b6 => "\xb6",
     0x000000b7 => "\xb3",
     0x000000b8 => "\x9d",
     0x000000b9 => "\xda",
     0x000000ba => "\x9b",
     0x000000bb => "\x8b",
     0x000000bc => "\xb7",
     0x000000bd => "\xb8",
     0x000000be => "\xb9",
     0x000000bf => "\xab",
     0x000000c0 => "\x64",
     0x000000c1 => "\x65",
     0x000000c2 => "\x62",
     0x000000c3 => "\x66",
     0x000000c4 => "\x63",
     0x000000c5 => "\x67",
     0x000000c6 => "\x9e",
     0x000000c7 => "\x68",
     0x000000c8 => "\x74",
     0x000000c9 => "\x71",
     0x000000ca => "\x72",
     0x000000cb => "\x73",
     0x000000cc => "\x78",
     0x000000cd => "\x75",
     0x000000ce => "\x76",
     0x000000cf => "\x77",
     0x000000d0 => "\xac",
     0x000000d1 => "\x69",
     0x000000d2 => "\xed",
     0x000000d3 => "\xee",
     0x000000d4 => "\xeb",
     0x000000d5 => "\xef",
     0x000000d6 => "\xec",
     0x000000d7 => "\xbf",
     0x000000d8 => "\x80",
     0x000000d9 => "\xfd",
     0x000000da => "\xfe",
     0x000000db => "\xfb",
     0x000000dc => "\xfc",
     0x000000dd => "\xad",
     0x000000de => "\xae",
     0x000000df => "\x59",
     0x000000e0 => "\x44",
     0x000000e1 => "\x45",
     0x000000e2 => "\x42",
     0x000000e3 => "\x46",
     0x000000e4 => "\x43",
     0x000000e5 => "\x47",
     0x000000e6 => "\x9c",
     0x000000e7 => "\x48",
     0x000000e8 => "\x54",
     0x000000e9 => "\x51",
     0x000000ea => "\x52",
     0x000000eb => "\x53",
     0x000000ec => "\x58",
     0x000000ed => "\x55",
     0x000000ee => "\x56",
     0x000000ef => "\x57",
     0x000000f0 => "\x8c",
     0x000000f1 => "\x49",
     0x000000f2 => "\xcd",
     0x000000f3 => "\xce",
     0x000000f4 => "\xcb",
     0x000000f5 => "\xcf",
     0x000000f6 => "\xcc",
     0x000000f7 => "\xe1",
     0x000000f8 => "\x70",
     0x000000f9 => "\xdd",
     0x000000fa => "\xde",
     0x000000fb => "\xdb",
     0x000000fc => "\xdc",
     0x000000fd => "\x8d",
     0x000000fe => "\x8e",
     0x000000ff => "\xdf",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x6f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::IBM500 - Conversion routines for IBM500
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for IBM500.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
   source: IBM NLS RM Vol2 SE09-8002-01, March 1990
  alias CP500
  alias 500
  alias 500V1
  alias EBCDIC-CP-BE
  alias EBCDIC-CP-CH
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  0000009C | STRING TERMINATOR (ST)
     05 |  00000009 | CHARACTER TABULATION (HT)
     06 |  00000086 | START OF SELECTED AREA (SSA)
     07 |  0000007F | DELETE (DEL)
     08 |  00000097 | END OF GUARDED AREA (EPA)
     09 |  0000008D | REVERSE LINE FEED (RI)
     0A |  0000008E | SINGLE-SHIFT TWO (SS2)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  0000009D | OPERATING SYSTEM COMMAND (OSC)
     15 |  00000085 | NEXT LINE (NEL)
     16 |  00000008 | BACKSPACE (BS)
     17 |  00000087 | END OF SELECTED AREA (ESA)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  00000092 | PRIVATE USE TWO (PU2)
     1B |  0000008F | SINGLE-SHIFT THREE (SS3)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000080 | PADDING CHARACTER (PAD)
     21 |  00000081 | HIGH OCTET PRESET (HOP)
     22 |  00000082 | BREAK PERMITTED HERE (BPH)
     23 |  00000083 | NO BREAK HERE (NBH)
     24 |  00000084 | INDEX (IND)
     25 |  0000000A | LINE FEED (LF)
     26 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     27 |  0000001B | ESCAPE (ESC)
     28 |  00000088 | CHARACTER TABULATION SET (HTS)
     29 |  00000089 | CHARACTER TABULATION WITH JUSTIFICATION (HTJ)
     2A |  0000008A | LINE TABULATION SET (VTS)
     2B |  0000008B | PARTIAL LINE FORWARD (PLD)
     2C |  0000008C | PARTIAL LINE BACKWARD (PLU)
     2D |  00000005 | ENQUIRY (ENQ)
     2E |  00000006 | ACKNOWLEDGE (ACK)
     2F |  00000007 | BELL (BEL)
     30 |  00000090 | DEVICE CONTROL STRING (DCS)
     31 |  00000091 | PRIVATE USE ONE (PU1)
     32 |  00000016 | SYNCHRONOUS IDLE (SYN)
     33 |  00000093 | SET TRANSMIT STATE (STS)
     34 |  00000094 | CANCEL CHARACTER (CCH)
     35 |  00000095 | MESSAGE WAITING (MW)
     36 |  00000096 | START OF GUARDED AREA (SPA)
     37 |  00000004 | END OF TRANSMISSION (EOT)
     38 |  00000098 | START OF STRING (SOS)
     39 |  00000099 | SINGLE GRAPHIC CHARACTER INTRODUCER (SGCI)
     3A |  0000009A | SINGLE CHARACTER INTRODUCER (SCI)
     3B |  0000009B | CONTROL SEQUENCE INTRODUCER (CSI)
     3C |  00000014 | DEVICE CONTROL FOUR (DC4)
     3D |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     3E |  0000009E | PRIVACY MESSAGE (PM)
     3F |  0000001A | SUBSTITUTE (SUB)
     40 |  00000020 | SPACE
     41 |  000000A0 | NO-BREAK SPACE
     42 |  000000E2 | LATIN SMALL LETTER A WITH CIRCUMFLEX
     43 |  000000E4 | LATIN SMALL LETTER A WITH DIAERESIS
     44 |  000000E0 | LATIN SMALL LETTER A WITH GRAVE
     45 |  000000E1 | LATIN SMALL LETTER A WITH ACUTE
     46 |  000000E3 | LATIN SMALL LETTER A WITH TILDE
     47 |  000000E5 | LATIN SMALL LETTER A WITH RING ABOVE
     48 |  000000E7 | LATIN SMALL LETTER C WITH CEDILLA
     49 |  000000F1 | LATIN SMALL LETTER N WITH TILDE
     4A |  0000005B | LEFT SQUARE BRACKET
     4B |  0000002E | FULL STOP
     4C |  0000003C | LESS-THAN SIGN
     4D |  00000028 | LEFT PARENTHESIS
     4E |  0000002B | PLUS SIGN
     4F |  00000021 | EXCLAMATION MARK
     50 |  00000026 | AMPERSAND
     51 |  000000E9 | LATIN SMALL LETTER E WITH ACUTE
     52 |  000000EA | LATIN SMALL LETTER E WITH CIRCUMFLEX
     53 |  000000EB | LATIN SMALL LETTER E WITH DIAERESIS
     54 |  000000E8 | LATIN SMALL LETTER E WITH GRAVE
     55 |  000000ED | LATIN SMALL LETTER I WITH ACUTE
     56 |  000000EE | LATIN SMALL LETTER I WITH CIRCUMFLEX
     57 |  000000EF | LATIN SMALL LETTER I WITH DIAERESIS
     58 |  000000EC | LATIN SMALL LETTER I WITH GRAVE
     59 |  000000DF | LATIN SMALL LETTER SHARP S (German)
     5A |  0000005D | RIGHT SQUARE BRACKET
     5B |  00000024 | DOLLAR SIGN
     5C |  0000002A | ASTERISK
     5D |  00000029 | RIGHT PARENTHESIS
     5E |  0000003B | SEMICOLON
     5F |  0000005E | CIRCUMFLEX ACCENT
     60 |  0000002D | HYPHEN-MINUS
     61 |  0000002F | SOLIDUS
     62 |  000000C2 | LATIN CAPITAL LETTER A WITH CIRCUMFLEX
     63 |  000000C4 | LATIN CAPITAL LETTER A WITH DIAERESIS
     64 |  000000C0 | LATIN CAPITAL LETTER A WITH GRAVE
     65 |  000000C1 | LATIN CAPITAL LETTER A WITH ACUTE
     66 |  000000C3 | LATIN CAPITAL LETTER A WITH TILDE
     67 |  000000C5 | LATIN CAPITAL LETTER A WITH RING ABOVE
     68 |  000000C7 | LATIN CAPITAL LETTER C WITH CEDILLA
     69 |  000000D1 | LATIN CAPITAL LETTER N WITH TILDE
     6A |  000000A6 | BROKEN BAR
     6B |  0000002C | COMMA
     6C |  00000025 | PERCENT SIGN
     6D |  0000005F | LOW LINE
     6E |  0000003E | GREATER-THAN SIGN
     6F |  0000003F | QUESTION MARK
     70 |  000000F8 | LATIN SMALL LETTER O WITH STROKE
     71 |  000000C9 | LATIN CAPITAL LETTER E WITH ACUTE
     72 |  000000CA | LATIN CAPITAL LETTER E WITH CIRCUMFLEX
     73 |  000000CB | LATIN CAPITAL LETTER E WITH DIAERESIS
     74 |  000000C8 | LATIN CAPITAL LETTER E WITH GRAVE
     75 |  000000CD | LATIN CAPITAL LETTER I WITH ACUTE
     76 |  000000CE | LATIN CAPITAL LETTER I WITH CIRCUMFLEX
     77 |  000000CF | LATIN CAPITAL LETTER I WITH DIAERESIS
     78 |  000000CC | LATIN CAPITAL LETTER I WITH GRAVE
     79 |  00000060 | GRAVE ACCENT
     7A |  0000003A | COLON
     7B |  00000023 | NUMBER SIGN
     7C |  00000040 | COMMERCIAL AT
     7D |  00000027 | APOSTROPHE
     7E |  0000003D | EQUALS SIGN
     7F |  00000022 | QUOTATION MARK
     80 |  000000D8 | LATIN CAPITAL LETTER O WITH STROKE
     81 |  00000061 | LATIN SMALL LETTER A
     82 |  00000062 | LATIN SMALL LETTER B
     83 |  00000063 | LATIN SMALL LETTER C
     84 |  00000064 | LATIN SMALL LETTER D
     85 |  00000065 | LATIN SMALL LETTER E
     86 |  00000066 | LATIN SMALL LETTER F
     87 |  00000067 | LATIN SMALL LETTER G
     88 |  00000068 | LATIN SMALL LETTER H
     89 |  00000069 | LATIN SMALL LETTER I
     8A |  000000AB | LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
     8B |  000000BB | RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
     8C |  000000F0 | LATIN SMALL LETTER ETH (Icelandic)
     8D |  000000FD | LATIN SMALL LETTER Y WITH ACUTE
     8E |  000000FE | LATIN SMALL LETTER THORN (Icelandic)
     8F |  000000B1 | PLUS-MINUS SIGN
     90 |  000000B0 | DEGREE SIGN
     91 |  0000006A | LATIN SMALL LETTER J
     92 |  0000006B | LATIN SMALL LETTER K
     93 |  0000006C | LATIN SMALL LETTER L
     94 |  0000006D | LATIN SMALL LETTER M
     95 |  0000006E | LATIN SMALL LETTER N
     96 |  0000006F | LATIN SMALL LETTER O
     97 |  00000070 | LATIN SMALL LETTER P
     98 |  00000071 | LATIN SMALL LETTER Q
     99 |  00000072 | LATIN SMALL LETTER R
     9A |  000000AA | FEMININE ORDINAL INDICATOR
     9B |  000000BA | MASCULINE ORDINAL INDICATOR
     9C |  000000E6 | LATIN SMALL LETTER AE
     9D |  000000B8 | CEDILLA
     9E |  000000C6 | LATIN CAPITAL LETTER AE
     9F |  000000A4 | CURRENCY SIGN
     A0 |  000000B5 | MICRO SIGN
     A1 |  0000007E | TILDE
     A2 |  00000073 | LATIN SMALL LETTER S
     A3 |  00000074 | LATIN SMALL LETTER T
     A4 |  00000075 | LATIN SMALL LETTER U
     A5 |  00000076 | LATIN SMALL LETTER V
     A6 |  00000077 | LATIN SMALL LETTER W
     A7 |  00000078 | LATIN SMALL LETTER X
     A8 |  00000079 | LATIN SMALL LETTER Y
     A9 |  0000007A | LATIN SMALL LETTER Z
     AA |  000000A1 | INVERTED EXCLAMATION MARK
     AB |  000000BF | INVERTED QUESTION MARK
     AC |  000000D0 | LATIN CAPITAL LETTER ETH (Icelandic)
     AD |  000000DD | LATIN CAPITAL LETTER Y WITH ACUTE
     AE |  000000DE | LATIN CAPITAL LETTER THORN (Icelandic)
     AF |  000000AE | REGISTERED SIGN
     B0 |  000000A2 | CENT SIGN
     B1 |  000000A3 | POUND SIGN
     B2 |  000000A5 | YEN SIGN
     B3 |  000000B7 | MIDDLE DOT
     B4 |  000000A9 | COPYRIGHT SIGN
     B5 |  000000A7 | SECTION SIGN
     B6 |  000000B6 | PILCROW SIGN
     B7 |  000000BC | VULGAR FRACTION ONE QUARTER
     B8 |  000000BD | VULGAR FRACTION ONE HALF
     B9 |  000000BE | VULGAR FRACTION THREE QUARTERS
     BA |  000000AC | NOT SIGN
     BB |  0000007C | VERTICAL LINE
     BC |  000000AF | MACRON
     BD |  000000A8 | DIAERESIS
     BE |  000000B4 | ACUTE ACCENT
     BF |  000000D7 | MULTIPLICATION SIGN
     C0 |  0000007B | LEFT CURLY BRACKET
     C1 |  00000041 | LATIN CAPITAL LETTER A
     C2 |  00000042 | LATIN CAPITAL LETTER B
     C3 |  00000043 | LATIN CAPITAL LETTER C
     C4 |  00000044 | LATIN CAPITAL LETTER D
     C5 |  00000045 | LATIN CAPITAL LETTER E
     C6 |  00000046 | LATIN CAPITAL LETTER F
     C7 |  00000047 | LATIN CAPITAL LETTER G
     C8 |  00000048 | LATIN CAPITAL LETTER H
     C9 |  00000049 | LATIN CAPITAL LETTER I
     CA |  000000AD | SOFT HYPHEN
     CB |  000000F4 | LATIN SMALL LETTER O WITH CIRCUMFLEX
     CC |  000000F6 | LATIN SMALL LETTER O WITH DIAERESIS
     CD |  000000F2 | LATIN SMALL LETTER O WITH GRAVE
     CE |  000000F3 | LATIN SMALL LETTER O WITH ACUTE
     CF |  000000F5 | LATIN SMALL LETTER O WITH TILDE
     D0 |  0000007D | RIGHT CURLY BRACKET
     D1 |  0000004A | LATIN CAPITAL LETTER J
     D2 |  0000004B | LATIN CAPITAL LETTER K
     D3 |  0000004C | LATIN CAPITAL LETTER L
     D4 |  0000004D | LATIN CAPITAL LETTER M
     D5 |  0000004E | LATIN CAPITAL LETTER N
     D6 |  0000004F | LATIN CAPITAL LETTER O
     D7 |  00000050 | LATIN CAPITAL LETTER P
     D8 |  00000051 | LATIN CAPITAL LETTER Q
     D9 |  00000052 | LATIN CAPITAL LETTER R
     DA |  000000B9 | SUPERSCRIPT ONE
     DB |  000000FB | LATIN SMALL LETTER U WITH CIRCUMFLEX
     DC |  000000FC | LATIN SMALL LETTER U WITH DIAERESIS
     DD |  000000F9 | LATIN SMALL LETTER U WITH GRAVE
     DE |  000000FA | LATIN SMALL LETTER U WITH ACUTE
     DF |  000000FF | LATIN SMALL LETTER Y WITH DIAERESIS
     E0 |  0000005C | REVERSE SOLIDUS
     E1 |  000000F7 | DIVISION SIGN
     E2 |  00000053 | LATIN CAPITAL LETTER S
     E3 |  00000054 | LATIN CAPITAL LETTER T
     E4 |  00000055 | LATIN CAPITAL LETTER U
     E5 |  00000056 | LATIN CAPITAL LETTER V
     E6 |  00000057 | LATIN CAPITAL LETTER W
     E7 |  00000058 | LATIN CAPITAL LETTER X
     E8 |  00000059 | LATIN CAPITAL LETTER Y
     E9 |  0000005A | LATIN CAPITAL LETTER Z
     EA |  000000B2 | SUPERSCRIPT TWO
     EB |  000000D4 | LATIN CAPITAL LETTER O WITH CIRCUMFLEX
     EC |  000000D6 | LATIN CAPITAL LETTER O WITH DIAERESIS
     ED |  000000D2 | LATIN CAPITAL LETTER O WITH GRAVE
     EE |  000000D3 | LATIN CAPITAL LETTER O WITH ACUTE
     EF |  000000D5 | LATIN CAPITAL LETTER O WITH TILDE
     F0 |  00000030 | DIGIT ZERO
     F1 |  00000031 | DIGIT ONE
     F2 |  00000032 | DIGIT TWO
     F3 |  00000033 | DIGIT THREE
     F4 |  00000034 | DIGIT FOUR
     F5 |  00000035 | DIGIT FIVE
     F6 |  00000036 | DIGIT SIX
     F7 |  00000037 | DIGIT SEVEN
     F8 |  00000038 | DIGIT EIGHT
     F9 |  00000039 | DIGIT NINE
     FA |  000000B3 | SUPERSCRIPT THREE
     FB |  000000DB | LATIN CAPITAL LETTER U WITH CIRCUMFLEX
     FC |  000000DC | LATIN CAPITAL LETTER U WITH DIAERESIS
     FD |  000000D9 | LATIN CAPITAL LETTER U WITH GRAVE
     FE |  000000DA | LATIN CAPITAL LETTER U WITH ACUTE
     FF |  0000009F | APPLICATION PROGRAM COMMAND (APC)
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/IBM850.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for IBM850.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::IBM850;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x0004,
     0x0005,
     0x0006,
     0x0007,
     0x0008,
     0x0009,
     0x000a,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x0014,
     0x0015,
     0x0016,
     0x0017,
     0x0018,
     0x0019,
     0x001a,
     0x001b,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0020,
     0x0021,
     0x0022,
     0x0023,
     0x0024,
     0x0025,
     0x0026,
     0x0027,
     0x0028,
     0x0029,
     0x002a,
     0x002b,
     0x002c,
     0x002d,
     0x002e,
     0x002f,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x003a,
     0x003b,
     0x003c,
     0x003d,
     0x003e,
     0x003f,
     0x0040,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x005b,
     0x005c,
     0x005d,
     0x005e,
     0x005f,
     0x0060,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x007b,
     0x007c,
     0x007d,
     0x007e,
     0x007f,
     0x00c7,
     0x00fc,
     0x00e9,
     0x00e2,
     0x00e4,
     0x00e0,
     0x00e5,
     0x00e7,
     0x00ea,
     0x00eb,
     0x00e8,
     0x00ef,
     0x00ee,
     0x00ec,
     0x00c4,
     0x00c5,
     0x00c9,
     0x00e6,
     0x00c6,
     0x00f4,
     0x00f6,
     0x00f2,
     0x00fb,
     0x00f9,
     0x00ff,
     0x00d6,
     0x00dc,
     0x00f8,
     0x00a3,
     0x00d8,
     0x00d7,
     0x0192,
     0x00e1,
     0x00ed,
     0x00f3,
     0x00fa,
     0x00f1,
     0x00d1,
     0x00aa,
     0x00ba,
     0x00bf,
     0x00ae,
     0x00ac,
     0x00bd,
     0x00bc,
     0x00a1,
     0x00ab,
     0x00bb,
     0x2591,
     0x2592,
     0x2593,
     0x2502,
     0x2524,
     0x00c1,
     0x00c2,
     0x00c0,
     0x00a9,
     0x2563,
     0x2551,
     0x2557,
     0x255d,
     0x00a2,
     0x00a5,
     0x2510,
     0x2514,
     0x2534,
     0x252c,
     0x251c,
     0x2500,
     0x253c,
     0x00e3,
     0x00c3,
     0x255a,
     0x2554,
     0x2569,
     0x2566,
     0x2560,
     0x2550,
     0x256c,
     0x00a4,
     0x00f0,
     0x00d0,
     0x00ca,
     0x00cb,
     0x00c8,
     0x0131,
     0x00cd,
     0x00ce,
     0x00cf,
     0x2518,
     0x250c,
     0x2588,
     0x2584,
     0x00a6,
     0x00cc,
     0x2580,
     0x00d3,
     0x00df,
     0x00d4,
     0x00d2,
     0x00f5,
     0x00d5,
     0x00b5,
     0x00fe,
     0x00de,
     0x00da,
     0x00db,
     0x00d9,
     0x00fd,
     0x00dd,
     0x00af,
     0x00b4,
     0x00ad,
     0x00b1,
     0x2017,
     0x00be,
     0x00b6,
     0x00a7,
     0x00f7,
     0x00b8,
     0x00b0,
     0x00a8,
     0x00b7,
     0x00b9,
     0x00b3,
     0x00b2,
     0x25a0,
     0x00a0,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\x04",
     "\x05",
     "\x06",
     "\x07",
     "\x08",
     "\x09",
     "\x0a",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\x14",
     "\x15",
     "\x16",
     "\x17",
     "\x18",
     "\x19",
     "\x1a",
     "\x1b",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\x20",
     "\x21",
     "\x22",
     "\x23",
     "\x24",
     "\x25",
     "\x26",
     "\x27",
     "\x28",
     "\x29",
     "\x2a",
     "\x2b",
     "\x2c",
     "\x2d",
     "\x2e",
     "\x2f",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\x3a",
     "\x3b",
     "\x3c",
     "\x3d",
     "\x3e",
     "\x3f",
     "\x40",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\x5b",
     "\x5c",
     "\x5d",
     "\x5e",
     "\x5f",
     "\x60",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\x7b",
     "\x7c",
     "\x7d",
     "\x7e",
     "\x7f",
     "\xc3\x87",
     "\xc3\xbc",
     "\xc3\xa9",
     "\xc3\xa2",
     "\xc3\xa4",
     "\xc3\xa0",
     "\xc3\xa5",
     "\xc3\xa7",
     "\xc3\xaa",
     "\xc3\xab",
     "\xc3\xa8",
     "\xc3\xaf",
     "\xc3\xae",
     "\xc3\xac",
     "\xc3\x84",
     "\xc3\x85",
     "\xc3\x89",
     "\xc3\xa6",
     "\xc3\x86",
     "\xc3\xb4",
     "\xc3\xb6",
     "\xc3\xb2",
     "\xc3\xbb",
     "\xc3\xb9",
     "\xc3\xbf",
     "\xc3\x96",
     "\xc3\x9c",
     "\xc3\xb8",
     "\xc2\xa3",
     "\xc3\x98",
     "\xc3\x97",
     "\xc6\x92",
     "\xc3\xa1",
     "\xc3\xad",
     "\xc3\xb3",
     "\xc3\xba",
     "\xc3\xb1",
     "\xc3\x91",
     "\xc2\xaa",
     "\xc2\xba",
     "\xc2\xbf",
     "\xc2\xae",
     "\xc2\xac",
     "\xc2\xbd",
     "\xc2\xbc",
     "\xc2\xa1",
     "\xc2\xab",
     "\xc2\xbb",
     "\xe2\x96\x91",
     "\xe2\x96\x92",
     "\xe2\x96\x93",
     "\xe2\x94\x82",
     "\xe2\x94\xa4",
     "\xc3\x81",
     "\xc3\x82",
     "\xc3\x80",
     "\xc2\xa9",
     "\xe2\x95\xa3",
     "\xe2\x95\x91",
     "\xe2\x95\x97",
     "\xe2\x95\x9d",
     "\xc2\xa2",
     "\xc2\xa5",
     "\xe2\x94\x90",
     "\xe2\x94\x94",
     "\xe2\x94\xb4",
     "\xe2\x94\xac",
     "\xe2\x94\x9c",
     "\xe2\x94\x80",
     "\xe2\x94\xbc",
     "\xc3\xa3",
     "\xc3\x83",
     "\xe2\x95\x9a",
     "\xe2\x95\x94",
     "\xe2\x95\xa9",
     "\xe2\x95\xa6",
     "\xe2\x95\xa0",
     "\xe2\x95\x90",
     "\xe2\x95\xac",
     "\xc2\xa4",
     "\xc3\xb0",
     "\xc3\x90",
     "\xc3\x8a",
     "\xc3\x8b",
     "\xc3\x88",
     "\xc4\xb1",
     "\xc3\x8d",
     "\xc3\x8e",
     "\xc3\x8f",
     "\xe2\x94\x98",
     "\xe2\x94\x8c",
     "\xe2\x96\x88",
     "\xe2\x96\x84",
     "\xc2\xa6",
     "\xc3\x8c",
     "\xe2\x96\x80",
     "\xc3\x93",
     "\xc3\x9f",
     "\xc3\x94",
     "\xc3\x92",
     "\xc3\xb5",
     "\xc3\x95",
     "\xc2\xb5",
     "\xc3\xbe",
     "\xc3\x9e",
     "\xc3\x9a",
     "\xc3\x9b",
     "\xc3\x99",
     "\xc3\xbd",
     "\xc3\x9d",
     "\xc2\xaf",
     "\xc2\xb4",
     "\xc2\xad",
     "\xc2\xb1",
     "\xe2\x80\x97",
     "\xc2\xbe",
     "\xc2\xb6",
     "\xc2\xa7",
     "\xc3\xb7",
     "\xc2\xb8",
     "\xc2\xb0",
     "\xc2\xa8",
     "\xc2\xb7",
     "\xc2\xb9",
     "\xc2\xb3",
     "\xc2\xb2",
     "\xe2\x96\xa0",
     "\xc2\xa0",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x04",
     0x00000005 => "\x05",
     0x00000006 => "\x06",
     0x00000007 => "\x07",
     0x00000008 => "\x08",
     0x00000009 => "\x09",
     0x0000000a => "\x0a",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x14",
     0x00000015 => "\x15",
     0x00000016 => "\x16",
     0x00000017 => "\x17",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x1a",
     0x0000001b => "\x1b",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x20",
     0x00000021 => "\x21",
     0x00000022 => "\x22",
     0x00000023 => "\x23",
     0x00000024 => "\x24",
     0x00000025 => "\x25",
     0x00000026 => "\x26",
     0x00000027 => "\x27",
     0x00000028 => "\x28",
     0x00000029 => "\x29",
     0x0000002a => "\x2a",
     0x0000002b => "\x2b",
     0x0000002c => "\x2c",
     0x0000002d => "\x2d",
     0x0000002e => "\x2e",
     0x0000002f => "\x2f",
     0x00000030 => "\x30",
     0x00000031 => "\x31",
     0x00000032 => "\x32",
     0x00000033 => "\x33",
     0x00000034 => "\x34",
     0x00000035 => "\x35",
     0x00000036 => "\x36",
     0x00000037 => "\x37",
     0x00000038 => "\x38",
     0x00000039 => "\x39",
     0x0000003a => "\x3a",
     0x0000003b => "\x3b",
     0x0000003c => "\x3c",
     0x0000003d => "\x3d",
     0x0000003e => "\x3e",
     0x0000003f => "\x3f",
     0x00000040 => "\x40",
     0x00000041 => "\x41",
     0x00000042 => "\x42",
     0x00000043 => "\x43",
     0x00000044 => "\x44",
     0x00000045 => "\x45",
     0x00000046 => "\x46",
     0x00000047 => "\x47",
     0x00000048 => "\x48",
     0x00000049 => "\x49",
     0x0000004a => "\x4a",
     0x0000004b => "\x4b",
     0x0000004c => "\x4c",
     0x0000004d => "\x4d",
     0x0000004e => "\x4e",
     0x0000004f => "\x4f",
     0x00000050 => "\x50",
     0x00000051 => "\x51",
     0x00000052 => "\x52",
     0x00000053 => "\x53",
     0x00000054 => "\x54",
     0x00000055 => "\x55",
     0x00000056 => "\x56",
     0x00000057 => "\x57",
     0x00000058 => "\x58",
     0x00000059 => "\x59",
     0x0000005a => "\x5a",
     0x0000005b => "\x5b",
     0x0000005c => "\x5c",
     0x0000005d => "\x5d",
     0x0000005e => "\x5e",
     0x0000005f => "\x5f",
     0x00000060 => "\x60",
     0x00000061 => "\x61",
     0x00000062 => "\x62",
     0x00000063 => "\x63",
     0x00000064 => "\x64",
     0x00000065 => "\x65",
     0x00000066 => "\x66",
     0x00000067 => "\x67",
     0x00000068 => "\x68",
     0x00000069 => "\x69",
     0x0000006a => "\x6a",
     0x0000006b => "\x6b",
     0x0000006c => "\x6c",
     0x0000006d => "\x6d",
     0x0000006e => "\x6e",
     0x0000006f => "\x6f",
     0x00000070 => "\x70",
     0x00000071 => "\x71",
     0x00000072 => "\x72",
     0x00000073 => "\x73",
     0x00000074 => "\x74",
     0x00000075 => "\x75",
     0x00000076 => "\x76",
     0x00000077 => "\x77",
     0x00000078 => "\x78",
     0x00000079 => "\x79",
     0x0000007a => "\x7a",
     0x0000007b => "\x7b",
     0x0000007c => "\x7c",
     0x0000007d => "\x7d",
     0x0000007e => "\x7e",
     0x0000007f => "\x7f",
     0x000000a0 => "\xff",
     0x000000a1 => "\xad",
     0x000000a2 => "\xbd",
     0x000000a3 => "\x9c",
     0x000000a4 => "\xcf",
     0x000000a5 => "\xbe",
     0x000000a6 => "\xdd",
     0x000000a7 => "\xf5",
     0x000000a8 => "\xf9",
     0x000000a9 => "\xb8",
     0x000000aa => "\xa6",
     0x000000ab => "\xae",
     0x000000ac => "\xaa",
     0x000000ad => "\xf0",
     0x000000ae => "\xa9",
     0x000000af => "\xee",
     0x000000b0 => "\xf8",
     0x000000b1 => "\xf1",
     0x000000b2 => "\xfd",
     0x000000b3 => "\xfc",
     0x000000b4 => "\xef",
     0x000000b5 => "\xe6",
     0x000000b6 => "\xf4",
     0x000000b7 => "\xfa",
     0x000000b8 => "\xf7",
     0x000000b9 => "\xfb",
     0x000000ba => "\xa7",
     0x000000bb => "\xaf",
     0x000000bc => "\xac",
     0x000000bd => "\xab",
     0x000000be => "\xf3",
     0x000000bf => "\xa8",
     0x000000c0 => "\xb7",
     0x000000c1 => "\xb5",
     0x000000c2 => "\xb6",
     0x000000c3 => "\xc7",
     0x000000c4 => "\x8e",
     0x000000c5 => "\x8f",
     0x000000c6 => "\x92",
     0x000000c7 => "\x80",
     0x000000c8 => "\xd4",
     0x000000c9 => "\x90",
     0x000000ca => "\xd2",
     0x000000cb => "\xd3",
     0x000000cc => "\xde",
     0x000000cd => "\xd6",
     0x000000ce => "\xd7",
     0x000000cf => "\xd8",
     0x000000d0 => "\xd1",
     0x000000d1 => "\xa5",
     0x000000d2 => "\xe3",
     0x000000d3 => "\xe0",
     0x000000d4 => "\xe2",
     0x000000d5 => "\xe5",
     0x000000d6 => "\x99",
     0x000000d7 => "\x9e",
     0x000000d8 => "\x9d",
     0x000000d9 => "\xeb",
     0x000000da => "\xe9",
     0x000000db => "\xea",
     0x000000dc => "\x9a",
     0x000000dd => "\xed",
     0x000000de => "\xe8",
     0x000000df => "\xe1",
     0x000000e0 => "\x85",
     0x000000e1 => "\xa0",
     0x000000e2 => "\x83",
     0x000000e3 => "\xc6",
     0x000000e4 => "\x84",
     0x000000e5 => "\x86",
     0x000000e6 => "\x91",
     0x000000e7 => "\x87",
     0x000000e8 => "\x8a",
     0x000000e9 => "\x82",
     0x000000ea => "\x88",
     0x000000eb => "\x89",
     0x000000ec => "\x8d",
     0x000000ed => "\xa1",
     0x000000ee => "\x8c",
     0x000000ef => "\x8b",
     0x000000f0 => "\xd0",
     0x000000f1 => "\xa4",
     0x000000f2 => "\x95",
     0x000000f3 => "\xa2",
     0x000000f4 => "\x93",
     0x000000f5 => "\xe4",
     0x000000f6 => "\x94",
     0x000000f7 => "\xf6",
     0x000000f8 => "\x9b",
     0x000000f9 => "\x97",
     0x000000fa => "\xa3",
     0x000000fb => "\x96",
     0x000000fc => "\x81",
     0x000000fd => "\xec",
     0x000000fe => "\xe7",
     0x000000ff => "\x98",
     0x00000131 => "\xd5",
     0x00000192 => "\x9f",
     0x00002017 => "\xf2",
     0x00002500 => "\xc4",
     0x00002502 => "\xb3",
     0x0000250c => "\xda",
     0x00002510 => "\xbf",
     0x00002514 => "\xc0",
     0x00002518 => "\xd9",
     0x0000251c => "\xc3",
     0x00002524 => "\xb4",
     0x0000252c => "\xc2",
     0x00002534 => "\xc1",
     0x0000253c => "\xc5",
     0x00002550 => "\xcd",
     0x00002551 => "\xba",
     0x00002554 => "\xc9",
     0x00002557 => "\xbb",
     0x0000255a => "\xc8",
     0x0000255d => "\xbc",
     0x00002560 => "\xcc",
     0x00002563 => "\xb9",
     0x00002566 => "\xcb",
     0x00002569 => "\xca",
     0x0000256c => "\xce",
     0x00002580 => "\xdf",
     0x00002584 => "\xdc",
     0x00002588 => "\xdb",
     0x00002591 => "\xb0",
     0x00002592 => "\xb1",
     0x00002593 => "\xb2",
     0x000025a0 => "\xfe",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::IBM850 - Conversion routines for IBM850
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for IBM850.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
   source: IBM NLS RM Vol2 SE09-8002-01, March 1990
   source: UNICODE 1.0
  alias CP850
  alias 850
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  00000004 | END OF TRANSMISSION (EOT)
     05 |  00000005 | ENQUIRY (ENQ)
     06 |  00000006 | ACKNOWLEDGE (ACK)
     07 |  00000007 | BELL (BEL)
     08 |  00000008 | BACKSPACE (BS)
     09 |  00000009 | CHARACTER TABULATION (HT)
     0A |  0000000A | LINE FEED (LF)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  00000014 | DEVICE CONTROL FOUR (DC4)
     15 |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     16 |  00000016 | SYNCHRONOUS IDLE (SYN)
     17 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  0000001A | SUBSTITUTE (SUB)
     1B |  0000001B | ESCAPE (ESC)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000020 | SPACE
     21 |  00000021 | EXCLAMATION MARK
     22 |  00000022 | QUOTATION MARK
     23 |  00000023 | NUMBER SIGN
     24 |  00000024 | DOLLAR SIGN
     25 |  00000025 | PERCENT SIGN
     26 |  00000026 | AMPERSAND
     27 |  00000027 | APOSTROPHE
     28 |  00000028 | LEFT PARENTHESIS
     29 |  00000029 | RIGHT PARENTHESIS
     2A |  0000002A | ASTERISK
     2B |  0000002B | PLUS SIGN
     2C |  0000002C | COMMA
     2D |  0000002D | HYPHEN-MINUS
     2E |  0000002E | FULL STOP
     2F |  0000002F | SOLIDUS
     30 |  00000030 | DIGIT ZERO
     31 |  00000031 | DIGIT ONE
     32 |  00000032 | DIGIT TWO
     33 |  00000033 | DIGIT THREE
     34 |  00000034 | DIGIT FOUR
     35 |  00000035 | DIGIT FIVE
     36 |  00000036 | DIGIT SIX
     37 |  00000037 | DIGIT SEVEN
     38 |  00000038 | DIGIT EIGHT
     39 |  00000039 | DIGIT NINE
     3A |  0000003A | COLON
     3B |  0000003B | SEMICOLON
     3C |  0000003C | LESS-THAN SIGN
     3D |  0000003D | EQUALS SIGN
     3E |  0000003E | GREATER-THAN SIGN
     3F |  0000003F | QUESTION MARK
     40 |  00000040 | COMMERCIAL AT
     41 |  00000041 | LATIN CAPITAL LETTER A
     42 |  00000042 | LATIN CAPITAL LETTER B
     43 |  00000043 | LATIN CAPITAL LETTER C
     44 |  00000044 | LATIN CAPITAL LETTER D
     45 |  00000045 | LATIN CAPITAL LETTER E
     46 |  00000046 | LATIN CAPITAL LETTER F
     47 |  00000047 | LATIN CAPITAL LETTER G
     48 |  00000048 | LATIN CAPITAL LETTER H
     49 |  00000049 | LATIN CAPITAL LETTER I
     4A |  0000004A | LATIN CAPITAL LETTER J
     4B |  0000004B | LATIN CAPITAL LETTER K
     4C |  0000004C | LATIN CAPITAL LETTER L
     4D |  0000004D | LATIN CAPITAL LETTER M
     4E |  0000004E | LATIN CAPITAL LETTER N
     4F |  0000004F | LATIN CAPITAL LETTER O
     50 |  00000050 | LATIN CAPITAL LETTER P
     51 |  00000051 | LATIN CAPITAL LETTER Q
     52 |  00000052 | LATIN CAPITAL LETTER R
     53 |  00000053 | LATIN CAPITAL LETTER S
     54 |  00000054 | LATIN CAPITAL LETTER T
     55 |  00000055 | LATIN CAPITAL LETTER U
     56 |  00000056 | LATIN CAPITAL LETTER V
     57 |  00000057 | LATIN CAPITAL LETTER W
     58 |  00000058 | LATIN CAPITAL LETTER X
     59 |  00000059 | LATIN CAPITAL LETTER Y
     5A |  0000005A | LATIN CAPITAL LETTER Z
     5B |  0000005B | LEFT SQUARE BRACKET
     5C |  0000005C | REVERSE SOLIDUS
     5D |  0000005D | RIGHT SQUARE BRACKET
     5E |  0000005E | CIRCUMFLEX ACCENT
     5F |  0000005F | LOW LINE
     60 |  00000060 | GRAVE ACCENT
     61 |  00000061 | LATIN SMALL LETTER A
     62 |  00000062 | LATIN SMALL LETTER B
     63 |  00000063 | LATIN SMALL LETTER C
     64 |  00000064 | LATIN SMALL LETTER D
     65 |  00000065 | LATIN SMALL LETTER E
     66 |  00000066 | LATIN SMALL LETTER F
     67 |  00000067 | LATIN SMALL LETTER G
     68 |  00000068 | LATIN SMALL LETTER H
     69 |  00000069 | LATIN SMALL LETTER I
     6A |  0000006A | LATIN SMALL LETTER J
     6B |  0000006B | LATIN SMALL LETTER K
     6C |  0000006C | LATIN SMALL LETTER L
     6D |  0000006D | LATIN SMALL LETTER M
     6E |  0000006E | LATIN SMALL LETTER N
     6F |  0000006F | LATIN SMALL LETTER O
     70 |  00000070 | LATIN SMALL LETTER P
     71 |  00000071 | LATIN SMALL LETTER Q
     72 |  00000072 | LATIN SMALL LETTER R
     73 |  00000073 | LATIN SMALL LETTER S
     74 |  00000074 | LATIN SMALL LETTER T
     75 |  00000075 | LATIN SMALL LETTER U
     76 |  00000076 | LATIN SMALL LETTER V
     77 |  00000077 | LATIN SMALL LETTER W
     78 |  00000078 | LATIN SMALL LETTER X
     79 |  00000079 | LATIN SMALL LETTER Y
     7A |  0000007A | LATIN SMALL LETTER Z
     7B |  0000007B | LEFT CURLY BRACKET
     7C |  0000007C | VERTICAL LINE
     7D |  0000007D | RIGHT CURLY BRACKET
     7E |  0000007E | TILDE
     7F |  0000007F | DELETE (DEL)
     80 |  000000C7 | LATIN CAPITAL LETTER C WITH CEDILLA
     81 |  000000FC | LATIN SMALL LETTER U WITH DIAERESIS
     82 |  000000E9 | LATIN SMALL LETTER E WITH ACUTE
     83 |  000000E2 | LATIN SMALL LETTER A WITH CIRCUMFLEX
     84 |  000000E4 | LATIN SMALL LETTER A WITH DIAERESIS
     85 |  000000E0 | LATIN SMALL LETTER A WITH GRAVE
     86 |  000000E5 | LATIN SMALL LETTER A WITH RING ABOVE
     87 |  000000E7 | LATIN SMALL LETTER C WITH CEDILLA
     88 |  000000EA | LATIN SMALL LETTER E WITH CIRCUMFLEX
     89 |  000000EB | LATIN SMALL LETTER E WITH DIAERESIS
     8A |  000000E8 | LATIN SMALL LETTER E WITH GRAVE
     8B |  000000EF | LATIN SMALL LETTER I WITH DIAERESIS
     8C |  000000EE | LATIN SMALL LETTER I WITH CIRCUMFLEX
     8D |  000000EC | LATIN SMALL LETTER I WITH GRAVE
     8E |  000000C4 | LATIN CAPITAL LETTER A WITH DIAERESIS
     8F |  000000C5 | LATIN CAPITAL LETTER A WITH RING ABOVE
     90 |  000000C9 | LATIN CAPITAL LETTER E WITH ACUTE
     91 |  000000E6 | LATIN SMALL LETTER AE
     92 |  000000C6 | LATIN CAPITAL LETTER AE
     93 |  000000F4 | LATIN SMALL LETTER O WITH CIRCUMFLEX
     94 |  000000F6 | LATIN SMALL LETTER O WITH DIAERESIS
     95 |  000000F2 | LATIN SMALL LETTER O WITH GRAVE
     96 |  000000FB | LATIN SMALL LETTER U WITH CIRCUMFLEX
     97 |  000000F9 | LATIN SMALL LETTER U WITH GRAVE
     98 |  000000FF | LATIN SMALL LETTER Y WITH DIAERESIS
     99 |  000000D6 | LATIN CAPITAL LETTER O WITH DIAERESIS
     9A |  000000DC | LATIN CAPITAL LETTER U WITH DIAERESIS
     9B |  000000F8 | LATIN SMALL LETTER O WITH STROKE
     9C |  000000A3 | POUND SIGN
     9D |  000000D8 | LATIN CAPITAL LETTER O WITH STROKE
     9E |  000000D7 | MULTIPLICATION SIGN
     9F |  00000192 | LATIN SMALL LETTER F WITH HOOK
     A0 |  000000E1 | LATIN SMALL LETTER A WITH ACUTE
     A1 |  000000ED | LATIN SMALL LETTER I WITH ACUTE
     A2 |  000000F3 | LATIN SMALL LETTER O WITH ACUTE
     A3 |  000000FA | LATIN SMALL LETTER U WITH ACUTE
     A4 |  000000F1 | LATIN SMALL LETTER N WITH TILDE
     A5 |  000000D1 | LATIN CAPITAL LETTER N WITH TILDE
     A6 |  000000AA | FEMININE ORDINAL INDICATOR
     A7 |  000000BA | MASCULINE ORDINAL INDICATOR
     A8 |  000000BF | INVERTED QUESTION MARK
     A9 |  000000AE | REGISTERED SIGN
     AA |  000000AC | NOT SIGN
     AB |  000000BD | VULGAR FRACTION ONE HALF
     AC |  000000BC | VULGAR FRACTION ONE QUARTER
     AD |  000000A1 | INVERTED EXCLAMATION MARK
     AE |  000000AB | LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
     AF |  000000BB | RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
     B0 |  00002591 | LIGHT SHADE
     B1 |  00002592 | MEDIUM SHADE
     B2 |  00002593 | DARK SHADE
     B3 |  00002502 | BOX DRAWINGS LIGHT VERTICAL
     B4 |  00002524 | BOX DRAWINGS LIGHT VERTICAL AND LEFT
     B5 |  000000C1 | LATIN CAPITAL LETTER A WITH ACUTE
     B6 |  000000C2 | LATIN CAPITAL LETTER A WITH CIRCUMFLEX
     B7 |  000000C0 | LATIN CAPITAL LETTER A WITH GRAVE
     B8 |  000000A9 | COPYRIGHT SIGN
     B9 |  00002563 | BOX DRAWINGS DOUBLE VERTICAL AND LEFT
     BA |  00002551 | BOX DRAWINGS DOUBLE VERTICAL
     BB |  00002557 | BOX DRAWINGS DOUBLE DOWN AND LEFT
     BC |  0000255D | BOX DRAWINGS DOUBLE UP AND LEFT
     BD |  000000A2 | CENT SIGN
     BE |  000000A5 | YEN SIGN
     BF |  00002510 | BOX DRAWINGS LIGHT DOWN AND LEFT
     C0 |  00002514 | BOX DRAWINGS LIGHT UP AND RIGHT
     C1 |  00002534 | BOX DRAWINGS LIGHT UP AND HORIZONTAL
     C2 |  0000252C | BOX DRAWINGS LIGHT DOWN AND HORIZONTAL
     C3 |  0000251C | BOX DRAWINGS LIGHT VERTICAL AND RIGHT
     C4 |  00002500 | BOX DRAWINGS LIGHT HORIZONTAL
     C5 |  0000253C | BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL
     C6 |  000000E3 | LATIN SMALL LETTER A WITH TILDE
     C7 |  000000C3 | LATIN CAPITAL LETTER A WITH TILDE
     C8 |  0000255A | BOX DRAWINGS DOUBLE UP AND RIGHT
     C9 |  00002554 | BOX DRAWINGS DOUBLE DOWN AND RIGHT
     CA |  00002569 | BOX DRAWINGS DOUBLE UP AND HORIZONTAL
     CB |  00002566 | BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL
     CC |  00002560 | BOX DRAWINGS DOUBLE VERTICAL AND RIGHT
     CD |  00002550 | BOX DRAWINGS DOUBLE HORIZONTAL
     CE |  0000256C | BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL
     CF |  000000A4 | CURRENCY SIGN
     D0 |  000000F0 | LATIN SMALL LETTER ETH (Icelandic)
     D1 |  000000D0 | LATIN CAPITAL LETTER ETH (Icelandic)
     D2 |  000000CA | LATIN CAPITAL LETTER E WITH CIRCUMFLEX
     D3 |  000000CB | LATIN CAPITAL LETTER E WITH DIAERESIS
     D4 |  000000C8 | LATIN CAPITAL LETTER E WITH GRAVE
     D5 |  00000131 | LATIN SMALL LETTER DOTLESS I
     D6 |  000000CD | LATIN CAPITAL LETTER I WITH ACUTE
     D7 |  000000CE | LATIN CAPITAL LETTER I WITH CIRCUMFLEX
     D8 |  000000CF | LATIN CAPITAL LETTER I WITH DIAERESIS
     D9 |  00002518 | BOX DRAWINGS LIGHT UP AND LEFT
     DA |  0000250C | BOX DRAWINGS LIGHT DOWN AND RIGHT
     DB |  00002588 | FULL BLOCK
     DC |  00002584 | LOWER HALF BLOCK
     DD |  000000A6 | BROKEN BAR
     DE |  000000CC | LATIN CAPITAL LETTER I WITH GRAVE
     DF |  00002580 | UPPER HALF BLOCK
     E0 |  000000D3 | LATIN CAPITAL LETTER O WITH ACUTE
     E1 |  000000DF | LATIN SMALL LETTER SHARP S (German)
     E2 |  000000D4 | LATIN CAPITAL LETTER O WITH CIRCUMFLEX
     E3 |  000000D2 | LATIN CAPITAL LETTER O WITH GRAVE
     E4 |  000000F5 | LATIN SMALL LETTER O WITH TILDE
     E5 |  000000D5 | LATIN CAPITAL LETTER O WITH TILDE
     E6 |  000000B5 | MICRO SIGN
     E7 |  000000FE | LATIN SMALL LETTER THORN (Icelandic)
     E8 |  000000DE | LATIN CAPITAL LETTER THORN (Icelandic)
     E9 |  000000DA | LATIN CAPITAL LETTER U WITH ACUTE
     EA |  000000DB | LATIN CAPITAL LETTER U WITH CIRCUMFLEX
     EB |  000000D9 | LATIN CAPITAL LETTER U WITH GRAVE
     EC |  000000FD | LATIN SMALL LETTER Y WITH ACUTE
     ED |  000000DD | LATIN CAPITAL LETTER Y WITH ACUTE
     EE |  000000AF | MACRON
     EF |  000000B4 | ACUTE ACCENT
     F0 |  000000AD | SOFT HYPHEN
     F1 |  000000B1 | PLUS-MINUS SIGN
     F2 |  00002017 | DOUBLE LOW LINE
     F3 |  000000BE | VULGAR FRACTION THREE QUARTERS
     F4 |  000000B6 | PILCROW SIGN
     F5 |  000000A7 | SECTION SIGN
     F6 |  000000F7 | DIVISION SIGN
     F7 |  000000B8 | CEDILLA
     F8 |  000000B0 | DEGREE SIGN
     F9 |  000000A8 | DIAERESIS
     FA |  000000B7 | MIDDLE DOT
     FB |  000000B9 | SUPERSCRIPT ONE
     FC |  000000B3 | SUPERSCRIPT THREE
     FD |  000000B2 | SUPERSCRIPT TWO
     FE |  000025A0 | BLACK SQUARE
     FF |  000000A0 | NO-BREAK SPACE
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/IBM851.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for IBM851.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::IBM851;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x0004,
     0x0005,
     0x0006,
     0x0007,
     0x0008,
     0x0009,
     0x000a,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x0014,
     0x0015,
     0x0016,
     0x0017,
     0x0018,
     0x0019,
     0x001a,
     0x001b,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0020,
     0x0021,
     0x0022,
     0x0023,
     0x0024,
     0x0025,
     0x0026,
     0x0027,
     0x0028,
     0x0029,
     0x002a,
     0x002b,
     0x002c,
     0x002d,
     0x002e,
     0x002f,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x003a,
     0x003b,
     0x003c,
     0x003d,
     0x003e,
     0x003f,
     0x0040,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x005b,
     0x005c,
     0x005d,
     0x005e,
     0x005f,
     0x0060,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x007b,
     0x007c,
     0x007d,
     0x007e,
     0x007f,
     0x00c7,
     0x00fc,
     0x00e9,
     0x00e2,
     0x00e4,
     0x00e0,
     0x0386,
     0x00e7,
     0x00ea,
     0x00eb,
     0x00e8,
     0x00ef,
     0x00ee,
     0x0388,
     0x00c4,
     0x0389,
     0x038a,
     0xfffd,
     0x038c,
     0x00f4,
     0x00f6,
     0x038e,
     0x00fb,
     0x00f9,
     0x038f,
     0x00d6,
     0x00dc,
     0x03ac,
     0x00a3,
     0x03ad,
     0x03ae,
     0x03af,
     0x03ca,
     0x0390,
     0x03cc,
     0x03cd,
     0x0391,
     0x0392,
     0x0393,
     0x0394,
     0x0395,
     0x0396,
     0x0397,
     0x00bd,
     0x0398,
     0x0399,
     0x00ab,
     0x00bb,
     0x2591,
     0x2592,
     0x2593,
     0x2502,
     0x2524,
     0x039a,
     0x039b,
     0x039d,
     0x039c,
     0x2563,
     0x2551,
     0x2557,
     0x255d,
     0x039e,
     0x039f,
     0x2510,
     0x2514,
     0x2534,
     0x252c,
     0x251c,
     0x2500,
     0x253c,
     0x03a0,
     0x03a1,
     0x255a,
     0x2554,
     0x2569,
     0x2566,
     0x2560,
     0x2550,
     0x256c,
     0x03a3,
     0x03a4,
     0x03a5,
     0x03a6,
     0x03a7,
     0x03a8,
     0x03a9,
     0x03b1,
     0x03b2,
     0x03b3,
     0x2518,
     0x250c,
     0x2588,
     0x2584,
     0x03b4,
     0x03b5,
     0x2580,
     0x03b6,
     0x03b7,
     0x03b8,
     0x03b9,
     0x03ba,
     0x03bb,
     0x03bc,
     0x03bd,
     0x03be,
     0x03bf,
     0x03c0,
     0x03c1,
     0x03c3,
     0x03c2,
     0x03c4,
     0x00b4,
     0x00ad,
     0x00b1,
     0x03c5,
     0x03c6,
     0x03c7,
     0x00a7,
     0x03c8,
     0x02db,
     0x00b0,
     0x00a8,
     0x03c9,
     0x03cb,
     0x03b0,
     0x03ce,
     0x25a0,
     0x00a0,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\x04",
     "\x05",
     "\x06",
     "\x07",
     "\x08",
     "\x09",
     "\x0a",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\x14",
     "\x15",
     "\x16",
     "\x17",
     "\x18",
     "\x19",
     "\x1a",
     "\x1b",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\x20",
     "\x21",
     "\x22",
     "\x23",
     "\x24",
     "\x25",
     "\x26",
     "\x27",
     "\x28",
     "\x29",
     "\x2a",
     "\x2b",
     "\x2c",
     "\x2d",
     "\x2e",
     "\x2f",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\x3a",
     "\x3b",
     "\x3c",
     "\x3d",
     "\x3e",
     "\x3f",
     "\x40",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\x5b",
     "\x5c",
     "\x5d",
     "\x5e",
     "\x5f",
     "\x60",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\x7b",
     "\x7c",
     "\x7d",
     "\x7e",
     "\x7f",
     "\xc3\x87",
     "\xc3\xbc",
     "\xc3\xa9",
     "\xc3\xa2",
     "\xc3\xa4",
     "\xc3\xa0",
     "\xce\x86",
     "\xc3\xa7",
     "\xc3\xaa",
     "\xc3\xab",
     "\xc3\xa8",
     "\xc3\xaf",
     "\xc3\xae",
     "\xce\x88",
     "\xc3\x84",
     "\xce\x89",
     "\xce\x8a",
     "\xef\xbf\xbd",
     "\xce\x8c",
     "\xc3\xb4",
     "\xc3\xb6",
     "\xce\x8e",
     "\xc3\xbb",
     "\xc3\xb9",
     "\xce\x8f",
     "\xc3\x96",
     "\xc3\x9c",
     "\xce\xac",
     "\xc2\xa3",
     "\xce\xad",
     "\xce\xae",
     "\xce\xaf",
     "\xcf\x8a",
     "\xce\x90",
     "\xcf\x8c",
     "\xcf\x8d",
     "\xce\x91",
     "\xce\x92",
     "\xce\x93",
     "\xce\x94",
     "\xce\x95",
     "\xce\x96",
     "\xce\x97",
     "\xc2\xbd",
     "\xce\x98",
     "\xce\x99",
     "\xc2\xab",
     "\xc2\xbb",
     "\xe2\x96\x91",
     "\xe2\x96\x92",
     "\xe2\x96\x93",
     "\xe2\x94\x82",
     "\xe2\x94\xa4",
     "\xce\x9a",
     "\xce\x9b",
     "\xce\x9d",
     "\xce\x9c",
     "\xe2\x95\xa3",
     "\xe2\x95\x91",
     "\xe2\x95\x97",
     "\xe2\x95\x9d",
     "\xce\x9e",
     "\xce\x9f",
     "\xe2\x94\x90",
     "\xe2\x94\x94",
     "\xe2\x94\xb4",
     "\xe2\x94\xac",
     "\xe2\x94\x9c",
     "\xe2\x94\x80",
     "\xe2\x94\xbc",
     "\xce\xa0",
     "\xce\xa1",
     "\xe2\x95\x9a",
     "\xe2\x95\x94",
     "\xe2\x95\xa9",
     "\xe2\x95\xa6",
     "\xe2\x95\xa0",
     "\xe2\x95\x90",
     "\xe2\x95\xac",
     "\xce\xa3",
     "\xce\xa4",
     "\xce\xa5",
     "\xce\xa6",
     "\xce\xa7",
     "\xce\xa8",
     "\xce\xa9",
     "\xce\xb1",
     "\xce\xb2",
     "\xce\xb3",
     "\xe2\x94\x98",
     "\xe2\x94\x8c",
     "\xe2\x96\x88",
     "\xe2\x96\x84",
     "\xce\xb4",
     "\xce\xb5",
     "\xe2\x96\x80",
     "\xce\xb6",
     "\xce\xb7",
     "\xce\xb8",
     "\xce\xb9",
     "\xce\xba",
     "\xce\xbb",
     "\xce\xbc",
     "\xce\xbd",
     "\xce\xbe",
     "\xce\xbf",
     "\xcf\x80",
     "\xcf\x81",
     "\xcf\x83",
     "\xcf\x82",
     "\xcf\x84",
     "\xc2\xb4",
     "\xc2\xad",
     "\xc2\xb1",
     "\xcf\x85",
     "\xcf\x86",
     "\xcf\x87",
     "\xc2\xa7",
     "\xcf\x88",
     "\xcb\x9b",
     "\xc2\xb0",
     "\xc2\xa8",
     "\xcf\x89",
     "\xcf\x8b",
     "\xce\xb0",
     "\xcf\x8e",
     "\xe2\x96\xa0",
     "\xc2\xa0",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x04",
     0x00000005 => "\x05",
     0x00000006 => "\x06",
     0x00000007 => "\x07",
     0x00000008 => "\x08",
     0x00000009 => "\x09",
     0x0000000a => "\x0a",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x14",
     0x00000015 => "\x15",
     0x00000016 => "\x16",
     0x00000017 => "\x17",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x1a",
     0x0000001b => "\x1b",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x20",
     0x00000021 => "\x21",
     0x00000022 => "\x22",
     0x00000023 => "\x23",
     0x00000024 => "\x24",
     0x00000025 => "\x25",
     0x00000026 => "\x26",
     0x00000027 => "\x27",
     0x00000028 => "\x28",
     0x00000029 => "\x29",
     0x0000002a => "\x2a",
     0x0000002b => "\x2b",
     0x0000002c => "\x2c",
     0x0000002d => "\x2d",
     0x0000002e => "\x2e",
     0x0000002f => "\x2f",
     0x00000030 => "\x30",
     0x00000031 => "\x31",
     0x00000032 => "\x32",
     0x00000033 => "\x33",
     0x00000034 => "\x34",
     0x00000035 => "\x35",
     0x00000036 => "\x36",
     0x00000037 => "\x37",
     0x00000038 => "\x38",
     0x00000039 => "\x39",
     0x0000003a => "\x3a",
     0x0000003b => "\x3b",
     0x0000003c => "\x3c",
     0x0000003d => "\x3d",
     0x0000003e => "\x3e",
     0x0000003f => "\x3f",
     0x00000040 => "\x40",
     0x00000041 => "\x41",
     0x00000042 => "\x42",
     0x00000043 => "\x43",
     0x00000044 => "\x44",
     0x00000045 => "\x45",
     0x00000046 => "\x46",
     0x00000047 => "\x47",
     0x00000048 => "\x48",
     0x00000049 => "\x49",
     0x0000004a => "\x4a",
     0x0000004b => "\x4b",
     0x0000004c => "\x4c",
     0x0000004d => "\x4d",
     0x0000004e => "\x4e",
     0x0000004f => "\x4f",
     0x00000050 => "\x50",
     0x00000051 => "\x51",
     0x00000052 => "\x52",
     0x00000053 => "\x53",
     0x00000054 => "\x54",
     0x00000055 => "\x55",
     0x00000056 => "\x56",
     0x00000057 => "\x57",
     0x00000058 => "\x58",
     0x00000059 => "\x59",
     0x0000005a => "\x5a",
     0x0000005b => "\x5b",
     0x0000005c => "\x5c",
     0x0000005d => "\x5d",
     0x0000005e => "\x5e",
     0x0000005f => "\x5f",
     0x00000060 => "\x60",
     0x00000061 => "\x61",
     0x00000062 => "\x62",
     0x00000063 => "\x63",
     0x00000064 => "\x64",
     0x00000065 => "\x65",
     0x00000066 => "\x66",
     0x00000067 => "\x67",
     0x00000068 => "\x68",
     0x00000069 => "\x69",
     0x0000006a => "\x6a",
     0x0000006b => "\x6b",
     0x0000006c => "\x6c",
     0x0000006d => "\x6d",
     0x0000006e => "\x6e",
     0x0000006f => "\x6f",
     0x00000070 => "\x70",
     0x00000071 => "\x71",
     0x00000072 => "\x72",
     0x00000073 => "\x73",
     0x00000074 => "\x74",
     0x00000075 => "\x75",
     0x00000076 => "\x76",
     0x00000077 => "\x77",
     0x00000078 => "\x78",
     0x00000079 => "\x79",
     0x0000007a => "\x7a",
     0x0000007b => "\x7b",
     0x0000007c => "\x7c",
     0x0000007d => "\x7d",
     0x0000007e => "\x7e",
     0x0000007f => "\x7f",
     0x000000a0 => "\xff",
     0x000000a3 => "\x9c",
     0x000000a7 => "\xf5",
     0x000000a8 => "\xf9",
     0x000000ab => "\xae",
     0x000000ad => "\xf0",
     0x000000b0 => "\xf8",
     0x000000b1 => "\xf1",
     0x000000b4 => "\xef",
     0x000000bb => "\xaf",
     0x000000bd => "\xab",
     0x000000c4 => "\x8e",
     0x000000c7 => "\x80",
     0x000000d6 => "\x99",
     0x000000dc => "\x9a",
     0x000000e0 => "\x85",
     0x000000e2 => "\x83",
     0x000000e4 => "\x84",
     0x000000e7 => "\x87",
     0x000000e8 => "\x8a",
     0x000000e9 => "\x82",
     0x000000ea => "\x88",
     0x000000eb => "\x89",
     0x000000ee => "\x8c",
     0x000000ef => "\x8b",
     0x000000f4 => "\x93",
     0x000000f6 => "\x94",
     0x000000f9 => "\x97",
     0x000000fb => "\x96",
     0x000000fc => "\x81",
     0x000002db => "\xf7",
     0x00000386 => "\x86",
     0x00000388 => "\x8d",
     0x00000389 => "\x8f",
     0x0000038a => "\x90",
     0x0000038c => "\x92",
     0x0000038e => "\x95",
     0x0000038f => "\x98",
     0x00000390 => "\xa1",
     0x00000391 => "\xa4",
     0x00000392 => "\xa5",
     0x00000393 => "\xa6",
     0x00000394 => "\xa7",
     0x00000395 => "\xa8",
     0x00000396 => "\xa9",
     0x00000397 => "\xaa",
     0x00000398 => "\xac",
     0x00000399 => "\xad",
     0x0000039a => "\xb5",
     0x0000039b => "\xb6",
     0x0000039c => "\xb8",
     0x0000039d => "\xb7",
     0x0000039e => "\xbd",
     0x0000039f => "\xbe",
     0x000003a0 => "\xc6",
     0x000003a1 => "\xc7",
     0x000003a3 => "\xcf",
     0x000003a4 => "\xd0",
     0x000003a5 => "\xd1",
     0x000003a6 => "\xd2",
     0x000003a7 => "\xd3",
     0x000003a8 => "\xd4",
     0x000003a9 => "\xd5",
     0x000003ac => "\x9b",
     0x000003ad => "\x9d",
     0x000003ae => "\x9e",
     0x000003af => "\x9f",
     0x000003b0 => "\xfc",
     0x000003b1 => "\xd6",
     0x000003b2 => "\xd7",
     0x000003b3 => "\xd8",
     0x000003b4 => "\xdd",
     0x000003b5 => "\xde",
     0x000003b6 => "\xe0",
     0x000003b7 => "\xe1",
     0x000003b8 => "\xe2",
     0x000003b9 => "\xe3",
     0x000003ba => "\xe4",
     0x000003bb => "\xe5",
     0x000003bc => "\xe6",
     0x000003bd => "\xe7",
     0x000003be => "\xe8",
     0x000003bf => "\xe9",
     0x000003c0 => "\xea",
     0x000003c1 => "\xeb",
     0x000003c2 => "\xed",
     0x000003c3 => "\xec",
     0x000003c4 => "\xee",
     0x000003c5 => "\xf2",
     0x000003c6 => "\xf3",
     0x000003c7 => "\xf4",
     0x000003c8 => "\xf6",
     0x000003c9 => "\xfa",
     0x000003ca => "\xa0",
     0x000003cb => "\xfb",
     0x000003cc => "\xa2",
     0x000003cd => "\xa3",
     0x000003ce => "\xfd",
     0x00002500 => "\xc4",
     0x00002502 => "\xb3",
     0x0000250c => "\xda",
     0x00002510 => "\xbf",
     0x00002514 => "\xc0",
     0x00002518 => "\xd9",
     0x0000251c => "\xc3",
     0x00002524 => "\xb4",
     0x0000252c => "\xc2",
     0x00002534 => "\xc1",
     0x0000253c => "\xc5",
     0x00002550 => "\xcd",
     0x00002551 => "\xba",
     0x00002554 => "\xc9",
     0x00002557 => "\xbb",
     0x0000255a => "\xc8",
     0x0000255d => "\xbc",
     0x00002560 => "\xcc",
     0x00002563 => "\xb9",
     0x00002566 => "\xcb",
     0x00002569 => "\xca",
     0x0000256c => "\xce",
     0x00002580 => "\xdf",
     0x00002584 => "\xdc",
     0x00002588 => "\xdb",
     0x00002591 => "\xb0",
     0x00002592 => "\xb1",
     0x00002593 => "\xb2",
     0x000025a0 => "\xfe",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::IBM851 - Conversion routines for IBM851
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for IBM851.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
   source: IBM NLS RM Vol2 SE09-8002-01, March 1990
  alias CP851
  alias 851
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  00000004 | END OF TRANSMISSION (EOT)
     05 |  00000005 | ENQUIRY (ENQ)
     06 |  00000006 | ACKNOWLEDGE (ACK)
     07 |  00000007 | BELL (BEL)
     08 |  00000008 | BACKSPACE (BS)
     09 |  00000009 | CHARACTER TABULATION (HT)
     0A |  0000000A | LINE FEED (LF)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  00000014 | DEVICE CONTROL FOUR (DC4)
     15 |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     16 |  00000016 | SYNCHRONOUS IDLE (SYN)
     17 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  0000001A | SUBSTITUTE (SUB)
     1B |  0000001B | ESCAPE (ESC)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000020 | SPACE
     21 |  00000021 | EXCLAMATION MARK
     22 |  00000022 | QUOTATION MARK
     23 |  00000023 | NUMBER SIGN
     24 |  00000024 | DOLLAR SIGN
     25 |  00000025 | PERCENT SIGN
     26 |  00000026 | AMPERSAND
     27 |  00000027 | APOSTROPHE
     28 |  00000028 | LEFT PARENTHESIS
     29 |  00000029 | RIGHT PARENTHESIS
     2A |  0000002A | ASTERISK
     2B |  0000002B | PLUS SIGN
     2C |  0000002C | COMMA
     2D |  0000002D | HYPHEN-MINUS
     2E |  0000002E | FULL STOP
     2F |  0000002F | SOLIDUS
     30 |  00000030 | DIGIT ZERO
     31 |  00000031 | DIGIT ONE
     32 |  00000032 | DIGIT TWO
     33 |  00000033 | DIGIT THREE
     34 |  00000034 | DIGIT FOUR
     35 |  00000035 | DIGIT FIVE
     36 |  00000036 | DIGIT SIX
     37 |  00000037 | DIGIT SEVEN
     38 |  00000038 | DIGIT EIGHT
     39 |  00000039 | DIGIT NINE
     3A |  0000003A | COLON
     3B |  0000003B | SEMICOLON
     3C |  0000003C | LESS-THAN SIGN
     3D |  0000003D | EQUALS SIGN
     3E |  0000003E | GREATER-THAN SIGN
     3F |  0000003F | QUESTION MARK
     40 |  00000040 | COMMERCIAL AT
     41 |  00000041 | LATIN CAPITAL LETTER A
     42 |  00000042 | LATIN CAPITAL LETTER B
     43 |  00000043 | LATIN CAPITAL LETTER C
     44 |  00000044 | LATIN CAPITAL LETTER D
     45 |  00000045 | LATIN CAPITAL LETTER E
     46 |  00000046 | LATIN CAPITAL LETTER F
     47 |  00000047 | LATIN CAPITAL LETTER G
     48 |  00000048 | LATIN CAPITAL LETTER H
     49 |  00000049 | LATIN CAPITAL LETTER I
     4A |  0000004A | LATIN CAPITAL LETTER J
     4B |  0000004B | LATIN CAPITAL LETTER K
     4C |  0000004C | LATIN CAPITAL LETTER L
     4D |  0000004D | LATIN CAPITAL LETTER M
     4E |  0000004E | LATIN CAPITAL LETTER N
     4F |  0000004F | LATIN CAPITAL LETTER O
     50 |  00000050 | LATIN CAPITAL LETTER P
     51 |  00000051 | LATIN CAPITAL LETTER Q
     52 |  00000052 | LATIN CAPITAL LETTER R
     53 |  00000053 | LATIN CAPITAL LETTER S
     54 |  00000054 | LATIN CAPITAL LETTER T
     55 |  00000055 | LATIN CAPITAL LETTER U
     56 |  00000056 | LATIN CAPITAL LETTER V
     57 |  00000057 | LATIN CAPITAL LETTER W
     58 |  00000058 | LATIN CAPITAL LETTER X
     59 |  00000059 | LATIN CAPITAL LETTER Y
     5A |  0000005A | LATIN CAPITAL LETTER Z
     5B |  0000005B | LEFT SQUARE BRACKET
     5C |  0000005C | REVERSE SOLIDUS
     5D |  0000005D | RIGHT SQUARE BRACKET
     5E |  0000005E | CIRCUMFLEX ACCENT
     5F |  0000005F | LOW LINE
     60 |  00000060 | GRAVE ACCENT
     61 |  00000061 | LATIN SMALL LETTER A
     62 |  00000062 | LATIN SMALL LETTER B
     63 |  00000063 | LATIN SMALL LETTER C
     64 |  00000064 | LATIN SMALL LETTER D
     65 |  00000065 | LATIN SMALL LETTER E
     66 |  00000066 | LATIN SMALL LETTER F
     67 |  00000067 | LATIN SMALL LETTER G
     68 |  00000068 | LATIN SMALL LETTER H
     69 |  00000069 | LATIN SMALL LETTER I
     6A |  0000006A | LATIN SMALL LETTER J
     6B |  0000006B | LATIN SMALL LETTER K
     6C |  0000006C | LATIN SMALL LETTER L
     6D |  0000006D | LATIN SMALL LETTER M
     6E |  0000006E | LATIN SMALL LETTER N
     6F |  0000006F | LATIN SMALL LETTER O
     70 |  00000070 | LATIN SMALL LETTER P
     71 |  00000071 | LATIN SMALL LETTER Q
     72 |  00000072 | LATIN SMALL LETTER R
     73 |  00000073 | LATIN SMALL LETTER S
     74 |  00000074 | LATIN SMALL LETTER T
     75 |  00000075 | LATIN SMALL LETTER U
     76 |  00000076 | LATIN SMALL LETTER V
     77 |  00000077 | LATIN SMALL LETTER W
     78 |  00000078 | LATIN SMALL LETTER X
     79 |  00000079 | LATIN SMALL LETTER Y
     7A |  0000007A | LATIN SMALL LETTER Z
     7B |  0000007B | LEFT CURLY BRACKET
     7C |  0000007C | VERTICAL LINE
     7D |  0000007D | RIGHT CURLY BRACKET
     7E |  0000007E | TILDE
     7F |  0000007F | DELETE (DEL)
     80 |  000000C7 | LATIN CAPITAL LETTER C WITH CEDILLA
     81 |  000000FC | LATIN SMALL LETTER U WITH DIAERESIS
     82 |  000000E9 | LATIN SMALL LETTER E WITH ACUTE
     83 |  000000E2 | LATIN SMALL LETTER A WITH CIRCUMFLEX
     84 |  000000E4 | LATIN SMALL LETTER A WITH DIAERESIS
     85 |  000000E0 | LATIN SMALL LETTER A WITH GRAVE
     86 |  00000386 | GREEK CAPITAL LETTER ALPHA WITH TONOS
     87 |  000000E7 | LATIN SMALL LETTER C WITH CEDILLA
     88 |  000000EA | LATIN SMALL LETTER E WITH CIRCUMFLEX
     89 |  000000EB | LATIN SMALL LETTER E WITH DIAERESIS
     8A |  000000E8 | LATIN SMALL LETTER E WITH GRAVE
     8B |  000000EF | LATIN SMALL LETTER I WITH DIAERESIS
     8C |  000000EE | LATIN SMALL LETTER I WITH CIRCUMFLEX
     8D |  00000388 | GREEK CAPITAL LETTER EPSILON WITH TONOS
     8E |  000000C4 | LATIN CAPITAL LETTER A WITH DIAERESIS
     8F |  00000389 | GREEK CAPITAL LETTER ETA WITH TONOS
     90 |  0000038A | GREEK CAPITAL LETTER IOTA WITH TONOS
     92 |  0000038C | GREEK CAPITAL LETTER OMICRON WITH TONOS
     93 |  000000F4 | LATIN SMALL LETTER O WITH CIRCUMFLEX
     94 |  000000F6 | LATIN SMALL LETTER O WITH DIAERESIS
     95 |  0000038E | GREEK CAPITAL LETTER UPSILON WITH TONOS
     96 |  000000FB | LATIN SMALL LETTER U WITH CIRCUMFLEX
     97 |  000000F9 | LATIN SMALL LETTER U WITH GRAVE
     98 |  0000038F | GREEK CAPITAL LETTER OMEGA WITH TONOS
     99 |  000000D6 | LATIN CAPITAL LETTER O WITH DIAERESIS
     9A |  000000DC | LATIN CAPITAL LETTER U WITH DIAERESIS
     9B |  000003AC | GREEK SMALL LETTER ALPHA WITH TONOS
     9C |  000000A3 | POUND SIGN
     9D |  000003AD | GREEK SMALL LETTER EPSILON WITH TONOS
     9E |  000003AE | GREEK SMALL LETTER ETA WITH TONOS
     9F |  000003AF | GREEK SMALL LETTER IOTA WITH TONOS
     A0 |  000003CA | GREEK SMALL LETTER IOTA WITH DIALYTIKA
     A1 |  00000390 | GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS
     A2 |  000003CC | GREEK SMALL LETTER OMICRON WITH TONOS
     A3 |  000003CD | GREEK SMALL LETTER UPSILON WITH TONOS
     A4 |  00000391 | GREEK CAPITAL LETTER ALPHA
     A5 |  00000392 | GREEK CAPITAL LETTER BETA
     A6 |  00000393 | GREEK CAPITAL LETTER GAMMA
     A7 |  00000394 | GREEK CAPITAL LETTER DELTA
     A8 |  00000395 | GREEK CAPITAL LETTER EPSILON
     A9 |  00000396 | GREEK CAPITAL LETTER ZETA
     AA |  00000397 | GREEK CAPITAL LETTER ETA
     AB |  000000BD | VULGAR FRACTION ONE HALF
     AC |  00000398 | GREEK CAPITAL LETTER THETA
     AD |  00000399 | GREEK CAPITAL LETTER IOTA
     AE |  000000AB | LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
     AF |  000000BB | RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
     B0 |  00002591 | LIGHT SHADE
     B1 |  00002592 | MEDIUM SHADE
     B2 |  00002593 | DARK SHADE
     B3 |  00002502 | BOX DRAWINGS LIGHT VERTICAL
     B4 |  00002524 | BOX DRAWINGS LIGHT VERTICAL AND LEFT
     B5 |  0000039A | GREEK CAPITAL LETTER KAPPA
     B6 |  0000039B | GREEK CAPITAL LETTER LAMDA
     B7 |  0000039D | GREEK CAPITAL LETTER NU
     B8 |  0000039C | GREEK CAPITAL LETTER MU
     B9 |  00002563 | BOX DRAWINGS DOUBLE VERTICAL AND LEFT
     BA |  00002551 | BOX DRAWINGS DOUBLE VERTICAL
     BB |  00002557 | BOX DRAWINGS DOUBLE DOWN AND LEFT
     BC |  0000255D | BOX DRAWINGS DOUBLE UP AND LEFT
     BD |  0000039E | GREEK CAPITAL LETTER XI
     BE |  0000039F | GREEK CAPITAL LETTER OMICRON
     BF |  00002510 | BOX DRAWINGS LIGHT DOWN AND LEFT
     C0 |  00002514 | BOX DRAWINGS LIGHT UP AND RIGHT
     C1 |  00002534 | BOX DRAWINGS LIGHT UP AND HORIZONTAL
     C2 |  0000252C | BOX DRAWINGS LIGHT DOWN AND HORIZONTAL
     C3 |  0000251C | BOX DRAWINGS LIGHT VERTICAL AND RIGHT
     C4 |  00002500 | BOX DRAWINGS LIGHT HORIZONTAL
     C5 |  0000253C | BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL
     C6 |  000003A0 | GREEK CAPITAL LETTER PI
     C7 |  000003A1 | GREEK CAPITAL LETTER RHO
     C8 |  0000255A | BOX DRAWINGS DOUBLE UP AND RIGHT
     C9 |  00002554 | BOX DRAWINGS DOUBLE DOWN AND RIGHT
     CA |  00002569 | BOX DRAWINGS DOUBLE UP AND HORIZONTAL
     CB |  00002566 | BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL
     CC |  00002560 | BOX DRAWINGS DOUBLE VERTICAL AND RIGHT
     CD |  00002550 | BOX DRAWINGS DOUBLE HORIZONTAL
     CE |  0000256C | BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL
     CF |  000003A3 | GREEK CAPITAL LETTER SIGMA
     D0 |  000003A4 | GREEK CAPITAL LETTER TAU
     D1 |  000003A5 | GREEK CAPITAL LETTER UPSILON
     D2 |  000003A6 | GREEK CAPITAL LETTER PHI
     D3 |  000003A7 | GREEK CAPITAL LETTER CHI
     D4 |  000003A8 | GREEK CAPITAL LETTER PSI
     D5 |  000003A9 | GREEK CAPITAL LETTER OMEGA
     D6 |  000003B1 | GREEK SMALL LETTER ALPHA
     D7 |  000003B2 | GREEK SMALL LETTER BETA
     D8 |  000003B3 | GREEK SMALL LETTER GAMMA
     D9 |  00002518 | BOX DRAWINGS LIGHT UP AND LEFT
     DA |  0000250C | BOX DRAWINGS LIGHT DOWN AND RIGHT
     DB |  00002588 | FULL BLOCK
     DC |  00002584 | LOWER HALF BLOCK
     DD |  000003B4 | GREEK SMALL LETTER DELTA
     DE |  000003B5 | GREEK SMALL LETTER EPSILON
     DF |  00002580 | UPPER HALF BLOCK
     E0 |  000003B6 | GREEK SMALL LETTER ZETA
     E1 |  000003B7 | GREEK SMALL LETTER ETA
     E2 |  000003B8 | GREEK SMALL LETTER THETA
     E3 |  000003B9 | GREEK SMALL LETTER IOTA
     E4 |  000003BA | GREEK SMALL LETTER KAPPA
     E5 |  000003BB | GREEK SMALL LETTER LAMDA
     E6 |  000003BC | GREEK SMALL LETTER MU
     E7 |  000003BD | GREEK SMALL LETTER NU
     E8 |  000003BE | GREEK SMALL LETTER XI
     E9 |  000003BF | GREEK SMALL LETTER OMICRON
     EA |  000003C0 | GREEK SMALL LETTER PI
     EB |  000003C1 | GREEK SMALL LETTER RHO
     EC |  000003C3 | GREEK SMALL LETTER SIGMA
     ED |  000003C2 | GREEK SMALL LETTER FINAL SIGMA
     EE |  000003C4 | GREEK SMALL LETTER TAU
     EF |  000000B4 | ACUTE ACCENT
     F0 |  000000AD | SOFT HYPHEN
     F1 |  000000B1 | PLUS-MINUS SIGN
     F2 |  000003C5 | GREEK SMALL LETTER UPSILON
     F3 |  000003C6 | GREEK SMALL LETTER PHI
     F4 |  000003C7 | GREEK SMALL LETTER CHI
     F5 |  000000A7 | SECTION SIGN
     F6 |  000003C8 | GREEK SMALL LETTER PSI
     F7 |  000002DB | OGONEK
     F8 |  000000B0 | DEGREE SIGN
     F9 |  000000A8 | DIAERESIS
     FA |  000003C9 | GREEK SMALL LETTER OMEGA
     FB |  000003CB | GREEK SMALL LETTER UPSILON WITH DIALYTIKA
     FC |  000003B0 | GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS
     FD |  000003CE | GREEK SMALL LETTER OMEGA WITH TONOS
     FE |  000025A0 | BLACK SQUARE
     FF |  000000A0 | NO-BREAK SPACE
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/IBM852.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for IBM852.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::IBM852;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x0004,
     0x0005,
     0x0006,
     0x0007,
     0x0008,
     0x0009,
     0x000a,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x0014,
     0x0015,
     0x0016,
     0x0017,
     0x0018,
     0x0019,
     0x001a,
     0x001b,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0020,
     0x0021,
     0x0022,
     0x0023,
     0x0024,
     0x0025,
     0x0026,
     0x0027,
     0x0028,
     0x0029,
     0x002a,
     0x002b,
     0x002c,
     0x002d,
     0x002e,
     0x002f,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x003a,
     0x003b,
     0x003c,
     0x003d,
     0x003e,
     0x003f,
     0x0040,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x005b,
     0x005c,
     0x005d,
     0x005e,
     0x005f,
     0x0060,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x007b,
     0x007c,
     0x007d,
     0x007e,
     0x007f,
     0x00c7,
     0x00fc,
     0x00e9,
     0x00e2,
     0x00e4,
     0x016f,
     0x0107,
     0x00e7,
     0x0142,
     0x00eb,
     0x0150,
     0x0151,
     0x00ee,
     0x0179,
     0x00c4,
     0x0106,
     0x00c9,
     0x0139,
     0x013a,
     0x00f4,
     0x00f6,
     0x013d,
     0x013e,
     0x015a,
     0x015b,
     0x00d6,
     0x00dc,
     0x0164,
     0x0165,
     0x0141,
     0x00d7,
     0x010d,
     0x00e1,
     0x00ed,
     0x00f3,
     0x00fa,
     0x0104,
     0x0105,
     0x017d,
     0x017e,
     0x0118,
     0x0119,
     0x00ac,
     0x017a,
     0x010c,
     0x015f,
     0x00ab,
     0x00bb,
     0x2591,
     0x2592,
     0x2593,
     0x2502,
     0x2524,
     0x00c1,
     0x00c2,
     0x011a,
     0x015e,
     0x2563,
     0x2551,
     0x2557,
     0x255d,
     0x017b,
     0x017c,
     0x2510,
     0x2514,
     0x2534,
     0x252c,
     0x251c,
     0x2500,
     0x253c,
     0x0102,
     0x0103,
     0x255a,
     0x2554,
     0x2569,
     0x2566,
     0x2560,
     0x2550,
     0x256c,
     0x00a4,
     0x0111,
     0x0110,
     0x010e,
     0x00cb,
     0x010f,
     0x0147,
     0x00cd,
     0x00ce,
     0x011b,
     0x2518,
     0x250c,
     0x2588,
     0x2584,
     0x0162,
     0x016e,
     0x2580,
     0x00d3,
     0x00df,
     0x00d4,
     0x0143,
     0x0144,
     0x0148,
     0x0160,
     0x0161,
     0x0154,
     0x00da,
     0x0155,
     0x0170,
     0x00fd,
     0x00dd,
     0x0163,
     0x00b4,
     0x00ad,
     0x02dd,
     0x02db,
     0x02c7,
     0x02d8,
     0x00a7,
     0x00f7,
     0x00b8,
     0x00b0,
     0x00a8,
     0x02d9,
     0x0171,
     0x0158,
     0x0159,
     0x25a0,
     0x00a0,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\x04",
     "\x05",
     "\x06",
     "\x07",
     "\x08",
     "\x09",
     "\x0a",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\x14",
     "\x15",
     "\x16",
     "\x17",
     "\x18",
     "\x19",
     "\x1a",
     "\x1b",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\x20",
     "\x21",
     "\x22",
     "\x23",
     "\x24",
     "\x25",
     "\x26",
     "\x27",
     "\x28",
     "\x29",
     "\x2a",
     "\x2b",
     "\x2c",
     "\x2d",
     "\x2e",
     "\x2f",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\x3a",
     "\x3b",
     "\x3c",
     "\x3d",
     "\x3e",
     "\x3f",
     "\x40",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\x5b",
     "\x5c",
     "\x5d",
     "\x5e",
     "\x5f",
     "\x60",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\x7b",
     "\x7c",
     "\x7d",
     "\x7e",
     "\x7f",
     "\xc3\x87",
     "\xc3\xbc",
     "\xc3\xa9",
     "\xc3\xa2",
     "\xc3\xa4",
     "\xc5\xaf",
     "\xc4\x87",
     "\xc3\xa7",
     "\xc5\x82",
     "\xc3\xab",
     "\xc5\x90",
     "\xc5\x91",
     "\xc3\xae",
     "\xc5\xb9",
     "\xc3\x84",
     "\xc4\x86",
     "\xc3\x89",
     "\xc4\xb9",
     "\xc4\xba",
     "\xc3\xb4",
     "\xc3\xb6",
     "\xc4\xbd",
     "\xc4\xbe",
     "\xc5\x9a",
     "\xc5\x9b",
     "\xc3\x96",
     "\xc3\x9c",
     "\xc5\xa4",
     "\xc5\xa5",
     "\xc5\x81",
     "\xc3\x97",
     "\xc4\x8d",
     "\xc3\xa1",
     "\xc3\xad",
     "\xc3\xb3",
     "\xc3\xba",
     "\xc4\x84",
     "\xc4\x85",
     "\xc5\xbd",
     "\xc5\xbe",
     "\xc4\x98",
     "\xc4\x99",
     "\xc2\xac",
     "\xc5\xba",
     "\xc4\x8c",
     "\xc5\x9f",
     "\xc2\xab",
     "\xc2\xbb",
     "\xe2\x96\x91",
     "\xe2\x96\x92",
     "\xe2\x96\x93",
     "\xe2\x94\x82",
     "\xe2\x94\xa4",
     "\xc3\x81",
     "\xc3\x82",
     "\xc4\x9a",
     "\xc5\x9e",
     "\xe2\x95\xa3",
     "\xe2\x95\x91",
     "\xe2\x95\x97",
     "\xe2\x95\x9d",
     "\xc5\xbb",
     "\xc5\xbc",
     "\xe2\x94\x90",
     "\xe2\x94\x94",
     "\xe2\x94\xb4",
     "\xe2\x94\xac",
     "\xe2\x94\x9c",
     "\xe2\x94\x80",
     "\xe2\x94\xbc",
     "\xc4\x82",
     "\xc4\x83",
     "\xe2\x95\x9a",
     "\xe2\x95\x94",
     "\xe2\x95\xa9",
     "\xe2\x95\xa6",
     "\xe2\x95\xa0",
     "\xe2\x95\x90",
     "\xe2\x95\xac",
     "\xc2\xa4",
     "\xc4\x91",
     "\xc4\x90",
     "\xc4\x8e",
     "\xc3\x8b",
     "\xc4\x8f",
     "\xc5\x87",
     "\xc3\x8d",
     "\xc3\x8e",
     "\xc4\x9b",
     "\xe2\x94\x98",
     "\xe2\x94\x8c",
     "\xe2\x96\x88",
     "\xe2\x96\x84",
     "\xc5\xa2",
     "\xc5\xae",
     "\xe2\x96\x80",
     "\xc3\x93",
     "\xc3\x9f",
     "\xc3\x94",
     "\xc5\x83",
     "\xc5\x84",
     "\xc5\x88",
     "\xc5\xa0",
     "\xc5\xa1",
     "\xc5\x94",
     "\xc3\x9a",
     "\xc5\x95",
     "\xc5\xb0",
     "\xc3\xbd",
     "\xc3\x9d",
     "\xc5\xa3",
     "\xc2\xb4",
     "\xc2\xad",
     "\xcb\x9d",
     "\xcb\x9b",
     "\xcb\x87",
     "\xcb\x98",
     "\xc2\xa7",
     "\xc3\xb7",
     "\xc2\xb8",
     "\xc2\xb0",
     "\xc2\xa8",
     "\xcb\x99",
     "\xc5\xb1",
     "\xc5\x98",
     "\xc5\x99",
     "\xe2\x96\xa0",
     "\xc2\xa0",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x04",
     0x00000005 => "\x05",
     0x00000006 => "\x06",
     0x00000007 => "\x07",
     0x00000008 => "\x08",
     0x00000009 => "\x09",
     0x0000000a => "\x0a",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x14",
     0x00000015 => "\x15",
     0x00000016 => "\x16",
     0x00000017 => "\x17",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x1a",
     0x0000001b => "\x1b",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x20",
     0x00000021 => "\x21",
     0x00000022 => "\x22",
     0x00000023 => "\x23",
     0x00000024 => "\x24",
     0x00000025 => "\x25",
     0x00000026 => "\x26",
     0x00000027 => "\x27",
     0x00000028 => "\x28",
     0x00000029 => "\x29",
     0x0000002a => "\x2a",
     0x0000002b => "\x2b",
     0x0000002c => "\x2c",
     0x0000002d => "\x2d",
     0x0000002e => "\x2e",
     0x0000002f => "\x2f",
     0x00000030 => "\x30",
     0x00000031 => "\x31",
     0x00000032 => "\x32",
     0x00000033 => "\x33",
     0x00000034 => "\x34",
     0x00000035 => "\x35",
     0x00000036 => "\x36",
     0x00000037 => "\x37",
     0x00000038 => "\x38",
     0x00000039 => "\x39",
     0x0000003a => "\x3a",
     0x0000003b => "\x3b",
     0x0000003c => "\x3c",
     0x0000003d => "\x3d",
     0x0000003e => "\x3e",
     0x0000003f => "\x3f",
     0x00000040 => "\x40",
     0x00000041 => "\x41",
     0x00000042 => "\x42",
     0x00000043 => "\x43",
     0x00000044 => "\x44",
     0x00000045 => "\x45",
     0x00000046 => "\x46",
     0x00000047 => "\x47",
     0x00000048 => "\x48",
     0x00000049 => "\x49",
     0x0000004a => "\x4a",
     0x0000004b => "\x4b",
     0x0000004c => "\x4c",
     0x0000004d => "\x4d",
     0x0000004e => "\x4e",
     0x0000004f => "\x4f",
     0x00000050 => "\x50",
     0x00000051 => "\x51",
     0x00000052 => "\x52",
     0x00000053 => "\x53",
     0x00000054 => "\x54",
     0x00000055 => "\x55",
     0x00000056 => "\x56",
     0x00000057 => "\x57",
     0x00000058 => "\x58",
     0x00000059 => "\x59",
     0x0000005a => "\x5a",
     0x0000005b => "\x5b",
     0x0000005c => "\x5c",
     0x0000005d => "\x5d",
     0x0000005e => "\x5e",
     0x0000005f => "\x5f",
     0x00000060 => "\x60",
     0x00000061 => "\x61",
     0x00000062 => "\x62",
     0x00000063 => "\x63",
     0x00000064 => "\x64",
     0x00000065 => "\x65",
     0x00000066 => "\x66",
     0x00000067 => "\x67",
     0x00000068 => "\x68",
     0x00000069 => "\x69",
     0x0000006a => "\x6a",
     0x0000006b => "\x6b",
     0x0000006c => "\x6c",
     0x0000006d => "\x6d",
     0x0000006e => "\x6e",
     0x0000006f => "\x6f",
     0x00000070 => "\x70",
     0x00000071 => "\x71",
     0x00000072 => "\x72",
     0x00000073 => "\x73",
     0x00000074 => "\x74",
     0x00000075 => "\x75",
     0x00000076 => "\x76",
     0x00000077 => "\x77",
     0x00000078 => "\x78",
     0x00000079 => "\x79",
     0x0000007a => "\x7a",
     0x0000007b => "\x7b",
     0x0000007c => "\x7c",
     0x0000007d => "\x7d",
     0x0000007e => "\x7e",
     0x0000007f => "\x7f",
     0x000000a0 => "\xff",
     0x000000a4 => "\xcf",
     0x000000a7 => "\xf5",
     0x000000a8 => "\xf9",
     0x000000ab => "\xae",
     0x000000ac => "\xaa",
     0x000000ad => "\xf0",
     0x000000b0 => "\xf8",
     0x000000b4 => "\xef",
     0x000000b8 => "\xf7",
     0x000000bb => "\xaf",
     0x000000c1 => "\xb5",
     0x000000c2 => "\xb6",
     0x000000c4 => "\x8e",
     0x000000c7 => "\x80",
     0x000000c9 => "\x90",
     0x000000cb => "\xd3",
     0x000000cd => "\xd6",
     0x000000ce => "\xd7",
     0x000000d3 => "\xe0",
     0x000000d4 => "\xe2",
     0x000000d6 => "\x99",
     0x000000d7 => "\x9e",
     0x000000da => "\xe9",
     0x000000dc => "\x9a",
     0x000000dd => "\xed",
     0x000000df => "\xe1",
     0x000000e1 => "\xa0",
     0x000000e2 => "\x83",
     0x000000e4 => "\x84",
     0x000000e7 => "\x87",
     0x000000e9 => "\x82",
     0x000000eb => "\x89",
     0x000000ed => "\xa1",
     0x000000ee => "\x8c",
     0x000000f3 => "\xa2",
     0x000000f4 => "\x93",
     0x000000f6 => "\x94",
     0x000000f7 => "\xf6",
     0x000000fa => "\xa3",
     0x000000fc => "\x81",
     0x000000fd => "\xec",
     0x00000102 => "\xc6",
     0x00000103 => "\xc7",
     0x00000104 => "\xa4",
     0x00000105 => "\xa5",
     0x00000106 => "\x8f",
     0x00000107 => "\x86",
     0x0000010c => "\xac",
     0x0000010d => "\x9f",
     0x0000010e => "\xd2",
     0x0000010f => "\xd4",
     0x00000110 => "\xd1",
     0x00000111 => "\xd0",
     0x00000118 => "\xa8",
     0x00000119 => "\xa9",
     0x0000011a => "\xb7",
     0x0000011b => "\xd8",
     0x00000139 => "\x91",
     0x0000013a => "\x92",
     0x0000013d => "\x95",
     0x0000013e => "\x96",
     0x00000141 => "\x9d",
     0x00000142 => "\x88",
     0x00000143 => "\xe3",
     0x00000144 => "\xe4",
     0x00000147 => "\xd5",
     0x00000148 => "\xe5",
     0x00000150 => "\x8a",
     0x00000151 => "\x8b",
     0x00000154 => "\xe8",
     0x00000155 => "\xea",
     0x00000158 => "\xfc",
     0x00000159 => "\xfd",
     0x0000015a => "\x97",
     0x0000015b => "\x98",
     0x0000015e => "\xb8",
     0x0000015f => "\xad",
     0x00000160 => "\xe6",
     0x00000161 => "\xe7",
     0x00000162 => "\xdd",
     0x00000163 => "\xee",
     0x00000164 => "\x9b",
     0x00000165 => "\x9c",
     0x0000016e => "\xde",
     0x0000016f => "\x85",
     0x00000170 => "\xeb",
     0x00000171 => "\xfb",
     0x00000179 => "\x8d",
     0x0000017a => "\xab",
     0x0000017b => "\xbd",
     0x0000017c => "\xbe",
     0x0000017d => "\xa6",
     0x0000017e => "\xa7",
     0x000002c7 => "\xf3",
     0x000002d8 => "\xf4",
     0x000002d9 => "\xfa",
     0x000002db => "\xf2",
     0x000002dd => "\xf1",
     0x00002500 => "\xc4",
     0x00002502 => "\xb3",
     0x0000250c => "\xda",
     0x00002510 => "\xbf",
     0x00002514 => "\xc0",
     0x00002518 => "\xd9",
     0x0000251c => "\xc3",
     0x00002524 => "\xb4",
     0x0000252c => "\xc2",
     0x00002534 => "\xc1",
     0x0000253c => "\xc5",
     0x00002550 => "\xcd",
     0x00002551 => "\xba",
     0x00002554 => "\xc9",
     0x00002557 => "\xbb",
     0x0000255a => "\xc8",
     0x0000255d => "\xbc",
     0x00002560 => "\xcc",
     0x00002563 => "\xb9",
     0x00002566 => "\xcb",
     0x00002569 => "\xca",
     0x0000256c => "\xce",
     0x00002580 => "\xdf",
     0x00002584 => "\xdc",
     0x00002588 => "\xdb",
     0x00002591 => "\xb0",
     0x00002592 => "\xb1",
     0x00002593 => "\xb2",
     0x000025a0 => "\xfe",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::IBM852 - Conversion routines for IBM852
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for IBM852.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
   source: IBM NLS RM Vol2 SE09-8002-01, March 1990
  alias CP852
  alias 852
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  00000004 | END OF TRANSMISSION (EOT)
     05 |  00000005 | ENQUIRY (ENQ)
     06 |  00000006 | ACKNOWLEDGE (ACK)
     07 |  00000007 | BELL (BEL)
     08 |  00000008 | BACKSPACE (BS)
     09 |  00000009 | CHARACTER TABULATION (HT)
     0A |  0000000A | LINE FEED (LF)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  00000014 | DEVICE CONTROL FOUR (DC4)
     15 |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     16 |  00000016 | SYNCHRONOUS IDLE (SYN)
     17 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  0000001A | SUBSTITUTE (SUB)
     1B |  0000001B | ESCAPE (ESC)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000020 | SPACE
     21 |  00000021 | EXCLAMATION MARK
     22 |  00000022 | QUOTATION MARK
     23 |  00000023 | NUMBER SIGN
     24 |  00000024 | DOLLAR SIGN
     25 |  00000025 | PERCENT SIGN
     26 |  00000026 | AMPERSAND
     27 |  00000027 | APOSTROPHE
     28 |  00000028 | LEFT PARENTHESIS
     29 |  00000029 | RIGHT PARENTHESIS
     2A |  0000002A | ASTERISK
     2B |  0000002B | PLUS SIGN
     2C |  0000002C | COMMA
     2D |  0000002D | HYPHEN-MINUS
     2E |  0000002E | FULL STOP
     2F |  0000002F | SOLIDUS
     30 |  00000030 | DIGIT ZERO
     31 |  00000031 | DIGIT ONE
     32 |  00000032 | DIGIT TWO
     33 |  00000033 | DIGIT THREE
     34 |  00000034 | DIGIT FOUR
     35 |  00000035 | DIGIT FIVE
     36 |  00000036 | DIGIT SIX
     37 |  00000037 | DIGIT SEVEN
     38 |  00000038 | DIGIT EIGHT
     39 |  00000039 | DIGIT NINE
     3A |  0000003A | COLON
     3B |  0000003B | SEMICOLON
     3C |  0000003C | LESS-THAN SIGN
     3D |  0000003D | EQUALS SIGN
     3E |  0000003E | GREATER-THAN SIGN
     3F |  0000003F | QUESTION MARK
     40 |  00000040 | COMMERCIAL AT
     41 |  00000041 | LATIN CAPITAL LETTER A
     42 |  00000042 | LATIN CAPITAL LETTER B
     43 |  00000043 | LATIN CAPITAL LETTER C
     44 |  00000044 | LATIN CAPITAL LETTER D
     45 |  00000045 | LATIN CAPITAL LETTER E
     46 |  00000046 | LATIN CAPITAL LETTER F
     47 |  00000047 | LATIN CAPITAL LETTER G
     48 |  00000048 | LATIN CAPITAL LETTER H
     49 |  00000049 | LATIN CAPITAL LETTER I
     4A |  0000004A | LATIN CAPITAL LETTER J
     4B |  0000004B | LATIN CAPITAL LETTER K
     4C |  0000004C | LATIN CAPITAL LETTER L
     4D |  0000004D | LATIN CAPITAL LETTER M
     4E |  0000004E | LATIN CAPITAL LETTER N
     4F |  0000004F | LATIN CAPITAL LETTER O
     50 |  00000050 | LATIN CAPITAL LETTER P
     51 |  00000051 | LATIN CAPITAL LETTER Q
     52 |  00000052 | LATIN CAPITAL LETTER R
     53 |  00000053 | LATIN CAPITAL LETTER S
     54 |  00000054 | LATIN CAPITAL LETTER T
     55 |  00000055 | LATIN CAPITAL LETTER U
     56 |  00000056 | LATIN CAPITAL LETTER V
     57 |  00000057 | LATIN CAPITAL LETTER W
     58 |  00000058 | LATIN CAPITAL LETTER X
     59 |  00000059 | LATIN CAPITAL LETTER Y
     5A |  0000005A | LATIN CAPITAL LETTER Z
     5B |  0000005B | LEFT SQUARE BRACKET
     5C |  0000005C | REVERSE SOLIDUS
     5D |  0000005D | RIGHT SQUARE BRACKET
     5E |  0000005E | CIRCUMFLEX ACCENT
     5F |  0000005F | LOW LINE
     60 |  00000060 | GRAVE ACCENT
     61 |  00000061 | LATIN SMALL LETTER A
     62 |  00000062 | LATIN SMALL LETTER B
     63 |  00000063 | LATIN SMALL LETTER C
     64 |  00000064 | LATIN SMALL LETTER D
     65 |  00000065 | LATIN SMALL LETTER E
     66 |  00000066 | LATIN SMALL LETTER F
     67 |  00000067 | LATIN SMALL LETTER G
     68 |  00000068 | LATIN SMALL LETTER H
     69 |  00000069 | LATIN SMALL LETTER I
     6A |  0000006A | LATIN SMALL LETTER J
     6B |  0000006B | LATIN SMALL LETTER K
     6C |  0000006C | LATIN SMALL LETTER L
     6D |  0000006D | LATIN SMALL LETTER M
     6E |  0000006E | LATIN SMALL LETTER N
     6F |  0000006F | LATIN SMALL LETTER O
     70 |  00000070 | LATIN SMALL LETTER P
     71 |  00000071 | LATIN SMALL LETTER Q
     72 |  00000072 | LATIN SMALL LETTER R
     73 |  00000073 | LATIN SMALL LETTER S
     74 |  00000074 | LATIN SMALL LETTER T
     75 |  00000075 | LATIN SMALL LETTER U
     76 |  00000076 | LATIN SMALL LETTER V
     77 |  00000077 | LATIN SMALL LETTER W
     78 |  00000078 | LATIN SMALL LETTER X
     79 |  00000079 | LATIN SMALL LETTER Y
     7A |  0000007A | LATIN SMALL LETTER Z
     7B |  0000007B | LEFT CURLY BRACKET
     7C |  0000007C | VERTICAL LINE
     7D |  0000007D | RIGHT CURLY BRACKET
     7E |  0000007E | TILDE
     7F |  0000007F | DELETE (DEL)
     80 |  000000C7 | LATIN CAPITAL LETTER C WITH CEDILLA
     81 |  000000FC | LATIN SMALL LETTER U WITH DIAERESIS
     82 |  000000E9 | LATIN SMALL LETTER E WITH ACUTE
     83 |  000000E2 | LATIN SMALL LETTER A WITH CIRCUMFLEX
     84 |  000000E4 | LATIN SMALL LETTER A WITH DIAERESIS
     85 |  0000016F | LATIN SMALL LETTER U WITH RING ABOVE
     86 |  00000107 | LATIN SMALL LETTER C WITH ACUTE
     87 |  000000E7 | LATIN SMALL LETTER C WITH CEDILLA
     88 |  00000142 | LATIN SMALL LETTER L WITH STROKE
     89 |  000000EB | LATIN SMALL LETTER E WITH DIAERESIS
     8A |  00000150 | LATIN CAPITAL LETTER O WITH DOUBLE ACUTE
     8B |  00000151 | LATIN SMALL LETTER O WITH DOUBLE ACUTE
     8C |  000000EE | LATIN SMALL LETTER I WITH CIRCUMFLEX
     8D |  00000179 | LATIN CAPITAL LETTER Z WITH ACUTE
     8E |  000000C4 | LATIN CAPITAL LETTER A WITH DIAERESIS
     8F |  00000106 | LATIN CAPITAL LETTER C WITH ACUTE
     90 |  000000C9 | LATIN CAPITAL LETTER E WITH ACUTE
     91 |  00000139 | LATIN CAPITAL LETTER L WITH ACUTE
     92 |  0000013A | LATIN SMALL LETTER L WITH ACUTE
     93 |  000000F4 | LATIN SMALL LETTER O WITH CIRCUMFLEX
     94 |  000000F6 | LATIN SMALL LETTER O WITH DIAERESIS
     95 |  0000013D | LATIN CAPITAL LETTER L WITH CARON
     96 |  0000013E | LATIN SMALL LETTER L WITH CARON
     97 |  0000015A | LATIN CAPITAL LETTER S WITH ACUTE
     98 |  0000015B | LATIN SMALL LETTER S WITH ACUTE
     99 |  000000D6 | LATIN CAPITAL LETTER O WITH DIAERESIS
     9A |  000000DC | LATIN CAPITAL LETTER U WITH DIAERESIS
     9B |  00000164 | LATIN CAPITAL LETTER T WITH CARON
     9C |  00000165 | LATIN SMALL LETTER T WITH CARON
     9D |  00000141 | LATIN CAPITAL LETTER L WITH STROKE
     9E |  000000D7 | MULTIPLICATION SIGN
     9F |  0000010D | LATIN SMALL LETTER C WITH CARON
     A0 |  000000E1 | LATIN SMALL LETTER A WITH ACUTE
     A1 |  000000ED | LATIN SMALL LETTER I WITH ACUTE
     A2 |  000000F3 | LATIN SMALL LETTER O WITH ACUTE
     A3 |  000000FA | LATIN SMALL LETTER U WITH ACUTE
     A4 |  00000104 | LATIN CAPITAL LETTER A WITH OGONEK
     A5 |  00000105 | LATIN SMALL LETTER A WITH OGONEK
     A6 |  0000017D | LATIN CAPITAL LETTER Z WITH CARON
     A7 |  0000017E | LATIN SMALL LETTER Z WITH CARON
     A8 |  00000118 | LATIN CAPITAL LETTER E WITH OGONEK
     A9 |  00000119 | LATIN SMALL LETTER E WITH OGONEK
     AA |  000000AC | NOT SIGN
     AB |  0000017A | LATIN SMALL LETTER Z WITH ACUTE
     AC |  0000010C | LATIN CAPITAL LETTER C WITH CARON
     AD |  0000015F | LATIN SMALL LETTER S WITH CEDILLA
     AE |  000000AB | LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
     AF |  000000BB | RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
     B0 |  00002591 | LIGHT SHADE
     B1 |  00002592 | MEDIUM SHADE
     B2 |  00002593 | DARK SHADE
     B3 |  00002502 | BOX DRAWINGS LIGHT VERTICAL
     B4 |  00002524 | BOX DRAWINGS LIGHT VERTICAL AND LEFT
     B5 |  000000C1 | LATIN CAPITAL LETTER A WITH ACUTE
     B6 |  000000C2 | LATIN CAPITAL LETTER A WITH CIRCUMFLEX
     B7 |  0000011A | LATIN CAPITAL LETTER E WITH CARON
     B8 |  0000015E | LATIN CAPITAL LETTER S WITH CEDILLA
     B9 |  00002563 | BOX DRAWINGS DOUBLE VERTICAL AND LEFT
     BA |  00002551 | BOX DRAWINGS DOUBLE VERTICAL
     BB |  00002557 | BOX DRAWINGS DOUBLE DOWN AND LEFT
     BC |  0000255D | BOX DRAWINGS DOUBLE UP AND LEFT
     BD |  0000017B | LATIN CAPITAL LETTER Z WITH DOT ABOVE
     BE |  0000017C | LATIN SMALL LETTER Z WITH DOT ABOVE
     BF |  00002510 | BOX DRAWINGS LIGHT DOWN AND LEFT
     C0 |  00002514 | BOX DRAWINGS LIGHT UP AND RIGHT
     C1 |  00002534 | BOX DRAWINGS LIGHT UP AND HORIZONTAL
     C2 |  0000252C | BOX DRAWINGS LIGHT DOWN AND HORIZONTAL
     C3 |  0000251C | BOX DRAWINGS LIGHT VERTICAL AND RIGHT
     C4 |  00002500 | BOX DRAWINGS LIGHT HORIZONTAL
     C5 |  0000253C | BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL
     C6 |  00000102 | LATIN CAPITAL LETTER A WITH BREVE
     C7 |  00000103 | LATIN SMALL LETTER A WITH BREVE
     C8 |  0000255A | BOX DRAWINGS DOUBLE UP AND RIGHT
     C9 |  00002554 | BOX DRAWINGS DOUBLE DOWN AND RIGHT
     CA |  00002569 | BOX DRAWINGS DOUBLE UP AND HORIZONTAL
     CB |  00002566 | BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL
     CC |  00002560 | BOX DRAWINGS DOUBLE VERTICAL AND RIGHT
     CD |  00002550 | BOX DRAWINGS DOUBLE HORIZONTAL
     CE |  0000256C | BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL
     CF |  000000A4 | CURRENCY SIGN
     D0 |  00000111 | LATIN SMALL LETTER D WITH STROKE
     D1 |  00000110 | LATIN CAPITAL LETTER D WITH STROKE
     D2 |  0000010E | LATIN CAPITAL LETTER D WITH CARON
     D3 |  000000CB | LATIN CAPITAL LETTER E WITH DIAERESIS
     D4 |  0000010F | LATIN SMALL LETTER D WITH CARON
     D5 |  00000147 | LATIN CAPITAL LETTER N WITH CARON
     D6 |  000000CD | LATIN CAPITAL LETTER I WITH ACUTE
     D7 |  000000CE | LATIN CAPITAL LETTER I WITH CIRCUMFLEX
     D8 |  0000011B | LATIN SMALL LETTER E WITH CARON
     D9 |  00002518 | BOX DRAWINGS LIGHT UP AND LEFT
     DA |  0000250C | BOX DRAWINGS LIGHT DOWN AND RIGHT
     DB |  00002588 | FULL BLOCK
     DC |  00002584 | LOWER HALF BLOCK
     DD |  00000162 | LATIN CAPITAL LETTER T WITH CEDILLA
     DE |  0000016E | LATIN CAPITAL LETTER U WITH RING ABOVE
     DF |  00002580 | UPPER HALF BLOCK
     E0 |  000000D3 | LATIN CAPITAL LETTER O WITH ACUTE
     E1 |  000000DF | LATIN SMALL LETTER SHARP S (German)
     E2 |  000000D4 | LATIN CAPITAL LETTER O WITH CIRCUMFLEX
     E3 |  00000143 | LATIN CAPITAL LETTER N WITH ACUTE
     E4 |  00000144 | LATIN SMALL LETTER N WITH ACUTE
     E5 |  00000148 | LATIN SMALL LETTER N WITH CARON
     E6 |  00000160 | LATIN CAPITAL LETTER S WITH CARON
     E7 |  00000161 | LATIN SMALL LETTER S WITH CARON
     E8 |  00000154 | LATIN CAPITAL LETTER R WITH ACUTE
     E9 |  000000DA | LATIN CAPITAL LETTER U WITH ACUTE
     EA |  00000155 | LATIN SMALL LETTER R WITH ACUTE
     EB |  00000170 | LATIN CAPITAL LETTER U WITH DOUBLE ACUTE
     EC |  000000FD | LATIN SMALL LETTER Y WITH ACUTE
     ED |  000000DD | LATIN CAPITAL LETTER Y WITH ACUTE
     EE |  00000163 | LATIN SMALL LETTER T WITH CEDILLA
     EF |  000000B4 | ACUTE ACCENT
     F0 |  000000AD | SOFT HYPHEN
     F1 |  000002DD | DOUBLE ACUTE ACCENT
     F2 |  000002DB | OGONEK
     F3 |  000002C7 | CARON (Mandarin Chinese third tone)
     F4 |  000002D8 | BREVE
     F5 |  000000A7 | SECTION SIGN
     F6 |  000000F7 | DIVISION SIGN
     F7 |  000000B8 | CEDILLA
     F8 |  000000B0 | DEGREE SIGN
     F9 |  000000A8 | DIAERESIS
     FA |  000002D9 | DOT ABOVE (Mandarin Chinese light tone)
     FB |  00000171 | LATIN SMALL LETTER U WITH DOUBLE ACUTE
     FC |  00000158 | LATIN CAPITAL LETTER R WITH CARON
     FD |  00000159 | LATIN SMALL LETTER R WITH CARON
     FE |  000025A0 | BLACK SQUARE
     FF |  000000A0 | NO-BREAK SPACE
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/IBM855.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for IBM855.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::IBM855;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x0004,
     0x0005,
     0x0006,
     0x0007,
     0x0008,
     0x0009,
     0x000a,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x0014,
     0x0015,
     0x0016,
     0x0017,
     0x0018,
     0x0019,
     0x001a,
     0x001b,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0020,
     0x0021,
     0x0022,
     0x0023,
     0x0024,
     0x0025,
     0x0026,
     0x0027,
     0x0028,
     0x0029,
     0x002a,
     0x002b,
     0x002c,
     0x002d,
     0x002e,
     0x002f,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x003a,
     0x003b,
     0x003c,
     0x003d,
     0x003e,
     0x003f,
     0x0040,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x005b,
     0x005c,
     0x005d,
     0x005e,
     0x005f,
     0x0060,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x007b,
     0x007c,
     0x007d,
     0x007e,
     0x007f,
     0x0452,
     0x0402,
     0x0453,
     0x0403,
     0x0451,
     0x0401,
     0x0454,
     0x0404,
     0x0455,
     0x0405,
     0x0456,
     0x0406,
     0x0457,
     0x0407,
     0x0458,
     0x0408,
     0x0459,
     0x0409,
     0x045a,
     0x040a,
     0x045b,
     0x040b,
     0x045c,
     0x040c,
     0x045e,
     0x040e,
     0x045f,
     0x040f,
     0x044e,
     0x042e,
     0x044a,
     0x042a,
     0x0430,
     0x0410,
     0x0431,
     0x0411,
     0x0446,
     0x0426,
     0x0434,
     0x0414,
     0x0435,
     0x0415,
     0x0444,
     0x0424,
     0x0433,
     0x0413,
     0x00ab,
     0x00bb,
     0x2591,
     0x2592,
     0x2593,
     0x2502,
     0x2524,
     0x0445,
     0x0425,
     0x0438,
     0x0418,
     0x2563,
     0x2551,
     0x2557,
     0x255d,
     0x0439,
     0x0419,
     0x2510,
     0x2514,
     0x2534,
     0x252c,
     0x251c,
     0x2500,
     0x253c,
     0x043a,
     0x041a,
     0x255a,
     0x2554,
     0x2569,
     0x2566,
     0x2560,
     0x2550,
     0x256c,
     0x00a4,
     0x043b,
     0x041b,
     0x043c,
     0x041c,
     0x043d,
     0x041d,
     0x043e,
     0x041e,
     0x043f,
     0x2518,
     0x250c,
     0x2588,
     0x2584,
     0x041f,
     0x044f,
     0x2580,
     0x042f,
     0x0440,
     0x0420,
     0x0441,
     0x0421,
     0x0442,
     0x0422,
     0x0443,
     0x0423,
     0x0436,
     0x0416,
     0x0432,
     0x0412,
     0x044c,
     0x042c,
     0x2116,
     0x00ad,
     0x044b,
     0x042b,
     0x0437,
     0x0417,
     0x0448,
     0x0428,
     0x044d,
     0x042d,
     0x0449,
     0x0429,
     0x0447,
     0x0427,
     0x00a7,
     0x25a0,
     0x00a0,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\x04",
     "\x05",
     "\x06",
     "\x07",
     "\x08",
     "\x09",
     "\x0a",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\x14",
     "\x15",
     "\x16",
     "\x17",
     "\x18",
     "\x19",
     "\x1a",
     "\x1b",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\x20",
     "\x21",
     "\x22",
     "\x23",
     "\x24",
     "\x25",
     "\x26",
     "\x27",
     "\x28",
     "\x29",
     "\x2a",
     "\x2b",
     "\x2c",
     "\x2d",
     "\x2e",
     "\x2f",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\x3a",
     "\x3b",
     "\x3c",
     "\x3d",
     "\x3e",
     "\x3f",
     "\x40",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\x5b",
     "\x5c",
     "\x5d",
     "\x5e",
     "\x5f",
     "\x60",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\x7b",
     "\x7c",
     "\x7d",
     "\x7e",
     "\x7f",
     "\xd1\x92",
     "\xd0\x82",
     "\xd1\x93",
     "\xd0\x83",
     "\xd1\x91",
     "\xd0\x81",
     "\xd1\x94",
     "\xd0\x84",
     "\xd1\x95",
     "\xd0\x85",
     "\xd1\x96",
     "\xd0\x86",
     "\xd1\x97",
     "\xd0\x87",
     "\xd1\x98",
     "\xd0\x88",
     "\xd1\x99",
     "\xd0\x89",
     "\xd1\x9a",
     "\xd0\x8a",
     "\xd1\x9b",
     "\xd0\x8b",
     "\xd1\x9c",
     "\xd0\x8c",
     "\xd1\x9e",
     "\xd0\x8e",
     "\xd1\x9f",
     "\xd0\x8f",
     "\xd1\x8e",
     "\xd0\xae",
     "\xd1\x8a",
     "\xd0\xaa",
     "\xd0\xb0",
     "\xd0\x90",
     "\xd0\xb1",
     "\xd0\x91",
     "\xd1\x86",
     "\xd0\xa6",
     "\xd0\xb4",
     "\xd0\x94",
     "\xd0\xb5",
     "\xd0\x95",
     "\xd1\x84",
     "\xd0\xa4",
     "\xd0\xb3",
     "\xd0\x93",
     "\xc2\xab",
     "\xc2\xbb",
     "\xe2\x96\x91",
     "\xe2\x96\x92",
     "\xe2\x96\x93",
     "\xe2\x94\x82",
     "\xe2\x94\xa4",
     "\xd1\x85",
     "\xd0\xa5",
     "\xd0\xb8",
     "\xd0\x98",
     "\xe2\x95\xa3",
     "\xe2\x95\x91",
     "\xe2\x95\x97",
     "\xe2\x95\x9d",
     "\xd0\xb9",
     "\xd0\x99",
     "\xe2\x94\x90",
     "\xe2\x94\x94",
     "\xe2\x94\xb4",
     "\xe2\x94\xac",
     "\xe2\x94\x9c",
     "\xe2\x94\x80",
     "\xe2\x94\xbc",
     "\xd0\xba",
     "\xd0\x9a",
     "\xe2\x95\x9a",
     "\xe2\x95\x94",
     "\xe2\x95\xa9",
     "\xe2\x95\xa6",
     "\xe2\x95\xa0",
     "\xe2\x95\x90",
     "\xe2\x95\xac",
     "\xc2\xa4",
     "\xd0\xbb",
     "\xd0\x9b",
     "\xd0\xbc",
     "\xd0\x9c",
     "\xd0\xbd",
     "\xd0\x9d",
     "\xd0\xbe",
     "\xd0\x9e",
     "\xd0\xbf",
     "\xe2\x94\x98",
     "\xe2\x94\x8c",
     "\xe2\x96\x88",
     "\xe2\x96\x84",
     "\xd0\x9f",
     "\xd1\x8f",
     "\xe2\x96\x80",
     "\xd0\xaf",
     "\xd1\x80",
     "\xd0\xa0",
     "\xd1\x81",
     "\xd0\xa1",
     "\xd1\x82",
     "\xd0\xa2",
     "\xd1\x83",
     "\xd0\xa3",
     "\xd0\xb6",
     "\xd0\x96",
     "\xd0\xb2",
     "\xd0\x92",
     "\xd1\x8c",
     "\xd0\xac",
     "\xe2\x84\x96",
     "\xc2\xad",
     "\xd1\x8b",
     "\xd0\xab",
     "\xd0\xb7",
     "\xd0\x97",
     "\xd1\x88",
     "\xd0\xa8",
     "\xd1\x8d",
     "\xd0\xad",
     "\xd1\x89",
     "\xd0\xa9",
     "\xd1\x87",
     "\xd0\xa7",
     "\xc2\xa7",
     "\xe2\x96\xa0",
     "\xc2\xa0",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x04",
     0x00000005 => "\x05",
     0x00000006 => "\x06",
     0x00000007 => "\x07",
     0x00000008 => "\x08",
     0x00000009 => "\x09",
     0x0000000a => "\x0a",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x14",
     0x00000015 => "\x15",
     0x00000016 => "\x16",
     0x00000017 => "\x17",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x1a",
     0x0000001b => "\x1b",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x20",
     0x00000021 => "\x21",
     0x00000022 => "\x22",
     0x00000023 => "\x23",
     0x00000024 => "\x24",
     0x00000025 => "\x25",
     0x00000026 => "\x26",
     0x00000027 => "\x27",
     0x00000028 => "\x28",
     0x00000029 => "\x29",
     0x0000002a => "\x2a",
     0x0000002b => "\x2b",
     0x0000002c => "\x2c",
     0x0000002d => "\x2d",
     0x0000002e => "\x2e",
     0x0000002f => "\x2f",
     0x00000030 => "\x30",
     0x00000031 => "\x31",
     0x00000032 => "\x32",
     0x00000033 => "\x33",
     0x00000034 => "\x34",
     0x00000035 => "\x35",
     0x00000036 => "\x36",
     0x00000037 => "\x37",
     0x00000038 => "\x38",
     0x00000039 => "\x39",
     0x0000003a => "\x3a",
     0x0000003b => "\x3b",
     0x0000003c => "\x3c",
     0x0000003d => "\x3d",
     0x0000003e => "\x3e",
     0x0000003f => "\x3f",
     0x00000040 => "\x40",
     0x00000041 => "\x41",
     0x00000042 => "\x42",
     0x00000043 => "\x43",
     0x00000044 => "\x44",
     0x00000045 => "\x45",
     0x00000046 => "\x46",
     0x00000047 => "\x47",
     0x00000048 => "\x48",
     0x00000049 => "\x49",
     0x0000004a => "\x4a",
     0x0000004b => "\x4b",
     0x0000004c => "\x4c",
     0x0000004d => "\x4d",
     0x0000004e => "\x4e",
     0x0000004f => "\x4f",
     0x00000050 => "\x50",
     0x00000051 => "\x51",
     0x00000052 => "\x52",
     0x00000053 => "\x53",
     0x00000054 => "\x54",
     0x00000055 => "\x55",
     0x00000056 => "\x56",
     0x00000057 => "\x57",
     0x00000058 => "\x58",
     0x00000059 => "\x59",
     0x0000005a => "\x5a",
     0x0000005b => "\x5b",
     0x0000005c => "\x5c",
     0x0000005d => "\x5d",
     0x0000005e => "\x5e",
     0x0000005f => "\x5f",
     0x00000060 => "\x60",
     0x00000061 => "\x61",
     0x00000062 => "\x62",
     0x00000063 => "\x63",
     0x00000064 => "\x64",
     0x00000065 => "\x65",
     0x00000066 => "\x66",
     0x00000067 => "\x67",
     0x00000068 => "\x68",
     0x00000069 => "\x69",
     0x0000006a => "\x6a",
     0x0000006b => "\x6b",
     0x0000006c => "\x6c",
     0x0000006d => "\x6d",
     0x0000006e => "\x6e",
     0x0000006f => "\x6f",
     0x00000070 => "\x70",
     0x00000071 => "\x71",
     0x00000072 => "\x72",
     0x00000073 => "\x73",
     0x00000074 => "\x74",
     0x00000075 => "\x75",
     0x00000076 => "\x76",
     0x00000077 => "\x77",
     0x00000078 => "\x78",
     0x00000079 => "\x79",
     0x0000007a => "\x7a",
     0x0000007b => "\x7b",
     0x0000007c => "\x7c",
     0x0000007d => "\x7d",
     0x0000007e => "\x7e",
     0x0000007f => "\x7f",
     0x000000a0 => "\xff",
     0x000000a4 => "\xcf",
     0x000000a7 => "\xfd",
     0x000000ab => "\xae",
     0x000000ad => "\xf0",
     0x000000bb => "\xaf",
     0x00000401 => "\x85",
     0x00000402 => "\x81",
     0x00000403 => "\x83",
     0x00000404 => "\x87",
     0x00000405 => "\x89",
     0x00000406 => "\x8b",
     0x00000407 => "\x8d",
     0x00000408 => "\x8f",
     0x00000409 => "\x91",
     0x0000040a => "\x93",
     0x0000040b => "\x95",
     0x0000040c => "\x97",
     0x0000040e => "\x99",
     0x0000040f => "\x9b",
     0x00000410 => "\xa1",
     0x00000411 => "\xa3",
     0x00000412 => "\xec",
     0x00000413 => "\xad",
     0x00000414 => "\xa7",
     0x00000415 => "\xa9",
     0x00000416 => "\xea",
     0x00000417 => "\xf4",
     0x00000418 => "\xb8",
     0x00000419 => "\xbe",
     0x0000041a => "\xc7",
     0x0000041b => "\xd1",
     0x0000041c => "\xd3",
     0x0000041d => "\xd5",
     0x0000041e => "\xd7",
     0x0000041f => "\xdd",
     0x00000420 => "\xe2",
     0x00000421 => "\xe4",
     0x00000422 => "\xe6",
     0x00000423 => "\xe8",
     0x00000424 => "\xab",
     0x00000425 => "\xb6",
     0x00000426 => "\xa5",
     0x00000427 => "\xfc",
     0x00000428 => "\xf6",
     0x00000429 => "\xfa",
     0x0000042a => "\x9f",
     0x0000042b => "\xf2",
     0x0000042c => "\xee",
     0x0000042d => "\xf8",
     0x0000042e => "\x9d",
     0x0000042f => "\xe0",
     0x00000430 => "\xa0",
     0x00000431 => "\xa2",
     0x00000432 => "\xeb",
     0x00000433 => "\xac",
     0x00000434 => "\xa6",
     0x00000435 => "\xa8",
     0x00000436 => "\xe9",
     0x00000437 => "\xf3",
     0x00000438 => "\xb7",
     0x00000439 => "\xbd",
     0x0000043a => "\xc6",
     0x0000043b => "\xd0",
     0x0000043c => "\xd2",
     0x0000043d => "\xd4",
     0x0000043e => "\xd6",
     0x0000043f => "\xd8",
     0x00000440 => "\xe1",
     0x00000441 => "\xe3",
     0x00000442 => "\xe5",
     0x00000443 => "\xe7",
     0x00000444 => "\xaa",
     0x00000445 => "\xb5",
     0x00000446 => "\xa4",
     0x00000447 => "\xfb",
     0x00000448 => "\xf5",
     0x00000449 => "\xf9",
     0x0000044a => "\x9e",
     0x0000044b => "\xf1",
     0x0000044c => "\xed",
     0x0000044d => "\xf7",
     0x0000044e => "\x9c",
     0x0000044f => "\xde",
     0x00000451 => "\x84",
     0x00000452 => "\x80",
     0x00000453 => "\x82",
     0x00000454 => "\x86",
     0x00000455 => "\x88",
     0x00000456 => "\x8a",
     0x00000457 => "\x8c",
     0x00000458 => "\x8e",
     0x00000459 => "\x90",
     0x0000045a => "\x92",
     0x0000045b => "\x94",
     0x0000045c => "\x96",
     0x0000045e => "\x98",
     0x0000045f => "\x9a",
     0x00002116 => "\xef",
     0x00002500 => "\xc4",
     0x00002502 => "\xb3",
     0x0000250c => "\xda",
     0x00002510 => "\xbf",
     0x00002514 => "\xc0",
     0x00002518 => "\xd9",
     0x0000251c => "\xc3",
     0x00002524 => "\xb4",
     0x0000252c => "\xc2",
     0x00002534 => "\xc1",
     0x0000253c => "\xc5",
     0x00002550 => "\xcd",
     0x00002551 => "\xba",
     0x00002554 => "\xc9",
     0x00002557 => "\xbb",
     0x0000255a => "\xc8",
     0x0000255d => "\xbc",
     0x00002560 => "\xcc",
     0x00002563 => "\xb9",
     0x00002566 => "\xcb",
     0x00002569 => "\xca",
     0x0000256c => "\xce",
     0x00002580 => "\xdf",
     0x00002584 => "\xdc",
     0x00002588 => "\xdb",
     0x00002591 => "\xb0",
     0x00002592 => "\xb1",
     0x00002593 => "\xb2",
     0x000025a0 => "\xfe",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::IBM855 - Conversion routines for IBM855
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for IBM855.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
   source: IBM NLS RM Vol2 SE09-8002-01, March 1990
  alias CP855
  alias 855
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  00000004 | END OF TRANSMISSION (EOT)
     05 |  00000005 | ENQUIRY (ENQ)
     06 |  00000006 | ACKNOWLEDGE (ACK)
     07 |  00000007 | BELL (BEL)
     08 |  00000008 | BACKSPACE (BS)
     09 |  00000009 | CHARACTER TABULATION (HT)
     0A |  0000000A | LINE FEED (LF)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  00000014 | DEVICE CONTROL FOUR (DC4)
     15 |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     16 |  00000016 | SYNCHRONOUS IDLE (SYN)
     17 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  0000001A | SUBSTITUTE (SUB)
     1B |  0000001B | ESCAPE (ESC)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000020 | SPACE
     21 |  00000021 | EXCLAMATION MARK
     22 |  00000022 | QUOTATION MARK
     23 |  00000023 | NUMBER SIGN
     24 |  00000024 | DOLLAR SIGN
     25 |  00000025 | PERCENT SIGN
     26 |  00000026 | AMPERSAND
     27 |  00000027 | APOSTROPHE
     28 |  00000028 | LEFT PARENTHESIS
     29 |  00000029 | RIGHT PARENTHESIS
     2A |  0000002A | ASTERISK
     2B |  0000002B | PLUS SIGN
     2C |  0000002C | COMMA
     2D |  0000002D | HYPHEN-MINUS
     2E |  0000002E | FULL STOP
     2F |  0000002F | SOLIDUS
     30 |  00000030 | DIGIT ZERO
     31 |  00000031 | DIGIT ONE
     32 |  00000032 | DIGIT TWO
     33 |  00000033 | DIGIT THREE
     34 |  00000034 | DIGIT FOUR
     35 |  00000035 | DIGIT FIVE
     36 |  00000036 | DIGIT SIX
     37 |  00000037 | DIGIT SEVEN
     38 |  00000038 | DIGIT EIGHT
     39 |  00000039 | DIGIT NINE
     3A |  0000003A | COLON
     3B |  0000003B | SEMICOLON
     3C |  0000003C | LESS-THAN SIGN
     3D |  0000003D | EQUALS SIGN
     3E |  0000003E | GREATER-THAN SIGN
     3F |  0000003F | QUESTION MARK
     40 |  00000040 | COMMERCIAL AT
     41 |  00000041 | LATIN CAPITAL LETTER A
     42 |  00000042 | LATIN CAPITAL LETTER B
     43 |  00000043 | LATIN CAPITAL LETTER C
     44 |  00000044 | LATIN CAPITAL LETTER D
     45 |  00000045 | LATIN CAPITAL LETTER E
     46 |  00000046 | LATIN CAPITAL LETTER F
     47 |  00000047 | LATIN CAPITAL LETTER G
     48 |  00000048 | LATIN CAPITAL LETTER H
     49 |  00000049 | LATIN CAPITAL LETTER I
     4A |  0000004A | LATIN CAPITAL LETTER J
     4B |  0000004B | LATIN CAPITAL LETTER K
     4C |  0000004C | LATIN CAPITAL LETTER L
     4D |  0000004D | LATIN CAPITAL LETTER M
     4E |  0000004E | LATIN CAPITAL LETTER N
     4F |  0000004F | LATIN CAPITAL LETTER O
     50 |  00000050 | LATIN CAPITAL LETTER P
     51 |  00000051 | LATIN CAPITAL LETTER Q
     52 |  00000052 | LATIN CAPITAL LETTER R
     53 |  00000053 | LATIN CAPITAL LETTER S
     54 |  00000054 | LATIN CAPITAL LETTER T
     55 |  00000055 | LATIN CAPITAL LETTER U
     56 |  00000056 | LATIN CAPITAL LETTER V
     57 |  00000057 | LATIN CAPITAL LETTER W
     58 |  00000058 | LATIN CAPITAL LETTER X
     59 |  00000059 | LATIN CAPITAL LETTER Y
     5A |  0000005A | LATIN CAPITAL LETTER Z
     5B |  0000005B | LEFT SQUARE BRACKET
     5C |  0000005C | REVERSE SOLIDUS
     5D |  0000005D | RIGHT SQUARE BRACKET
     5E |  0000005E | CIRCUMFLEX ACCENT
     5F |  0000005F | LOW LINE
     60 |  00000060 | GRAVE ACCENT
     61 |  00000061 | LATIN SMALL LETTER A
     62 |  00000062 | LATIN SMALL LETTER B
     63 |  00000063 | LATIN SMALL LETTER C
     64 |  00000064 | LATIN SMALL LETTER D
     65 |  00000065 | LATIN SMALL LETTER E
     66 |  00000066 | LATIN SMALL LETTER F
     67 |  00000067 | LATIN SMALL LETTER G
     68 |  00000068 | LATIN SMALL LETTER H
     69 |  00000069 | LATIN SMALL LETTER I
     6A |  0000006A | LATIN SMALL LETTER J
     6B |  0000006B | LATIN SMALL LETTER K
     6C |  0000006C | LATIN SMALL LETTER L
     6D |  0000006D | LATIN SMALL LETTER M
     6E |  0000006E | LATIN SMALL LETTER N
     6F |  0000006F | LATIN SMALL LETTER O
     70 |  00000070 | LATIN SMALL LETTER P
     71 |  00000071 | LATIN SMALL LETTER Q
     72 |  00000072 | LATIN SMALL LETTER R
     73 |  00000073 | LATIN SMALL LETTER S
     74 |  00000074 | LATIN SMALL LETTER T
     75 |  00000075 | LATIN SMALL LETTER U
     76 |  00000076 | LATIN SMALL LETTER V
     77 |  00000077 | LATIN SMALL LETTER W
     78 |  00000078 | LATIN SMALL LETTER X
     79 |  00000079 | LATIN SMALL LETTER Y
     7A |  0000007A | LATIN SMALL LETTER Z
     7B |  0000007B | LEFT CURLY BRACKET
     7C |  0000007C | VERTICAL LINE
     7D |  0000007D | RIGHT CURLY BRACKET
     7E |  0000007E | TILDE
     7F |  0000007F | DELETE (DEL)
     80 |  00000452 | CYRILLIC SMALL LETTER DJE (Serbocroatian)
     81 |  00000402 | CYRILLIC CAPITAL LETTER DJE (Serbocroatian)
     82 |  00000453 | CYRILLIC SMALL LETTER GJE
     83 |  00000403 | CYRILLIC CAPITAL LETTER GJE
     84 |  00000451 | CYRILLIC SMALL LETTER IO
     85 |  00000401 | CYRILLIC CAPITAL LETTER IO
     86 |  00000454 | CYRILLIC SMALL LETTER UKRAINIAN IE
     87 |  00000404 | CYRILLIC CAPITAL LETTER UKRAINIAN IE
     88 |  00000455 | CYRILLIC SMALL LETTER DZE
     89 |  00000405 | CYRILLIC CAPITAL LETTER DZE
     8A |  00000456 | CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I
     8B |  00000406 | CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I
     8C |  00000457 | CYRILLIC SMALL LETTER YI (Ukrainian)
     8D |  00000407 | CYRILLIC CAPITAL LETTER YI (Ukrainian)
     8E |  00000458 | CYRILLIC SMALL LETTER JE
     8F |  00000408 | CYRILLIC CAPITAL LETTER JE
     90 |  00000459 | CYRILLIC SMALL LETTER LJE
     91 |  00000409 | CYRILLIC CAPITAL LETTER LJE
     92 |  0000045A | CYRILLIC SMALL LETTER NJE
     93 |  0000040A | CYRILLIC CAPITAL LETTER NJE
     94 |  0000045B | CYRILLIC SMALL LETTER TSHE (Serbocroatian)
     95 |  0000040B | CYRILLIC CAPITAL LETTER TSHE
     96 |  0000045C | CYRILLIC SMALL LETTER KJE
     97 |  0000040C | CYRILLIC CAPITAL LETTER KJE
     98 |  0000045E | CYRILLIC SMALL LETTER SHORT U (Byelorussian)
     99 |  0000040E | CYRILLIC CAPITAL LETTER SHORT U (Byelorussian)
     9A |  0000045F | CYRILLIC SMALL LETTER DZHE
     9B |  0000040F | CYRILLIC CAPITAL LETTER DZHE
     9C |  0000044E | CYRILLIC SMALL LETTER YU
     9D |  0000042E | CYRILLIC CAPITAL LETTER YU
     9E |  0000044A | CYRILLIC SMALL LETTER HARD SIGN
     9F |  0000042A | CYRILLIC CAPITAL LETTER HARD SIGN
     A0 |  00000430 | CYRILLIC SMALL LETTER A
     A1 |  00000410 | CYRILLIC CAPITAL LETTER A
     A2 |  00000431 | CYRILLIC SMALL LETTER BE
     A3 |  00000411 | CYRILLIC CAPITAL LETTER BE
     A4 |  00000446 | CYRILLIC SMALL LETTER TSE
     A5 |  00000426 | CYRILLIC CAPITAL LETTER TSE
     A6 |  00000434 | CYRILLIC SMALL LETTER DE
     A7 |  00000414 | CYRILLIC CAPITAL LETTER DE
     A8 |  00000435 | CYRILLIC SMALL LETTER IE
     A9 |  00000415 | CYRILLIC CAPITAL LETTER IE
     AA |  00000444 | CYRILLIC SMALL LETTER EF
     AB |  00000424 | CYRILLIC CAPITAL LETTER EF
     AC |  00000433 | CYRILLIC SMALL LETTER GHE
     AD |  00000413 | CYRILLIC CAPITAL LETTER GHE
     AE |  000000AB | LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
     AF |  000000BB | RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
     B0 |  00002591 | LIGHT SHADE
     B1 |  00002592 | MEDIUM SHADE
     B2 |  00002593 | DARK SHADE
     B3 |  00002502 | BOX DRAWINGS LIGHT VERTICAL
     B4 |  00002524 | BOX DRAWINGS LIGHT VERTICAL AND LEFT
     B5 |  00000445 | CYRILLIC SMALL LETTER HA
     B6 |  00000425 | CYRILLIC CAPITAL LETTER HA
     B7 |  00000438 | CYRILLIC SMALL LETTER I
     B8 |  00000418 | CYRILLIC CAPITAL LETTER I
     B9 |  00002563 | BOX DRAWINGS DOUBLE VERTICAL AND LEFT
     BA |  00002551 | BOX DRAWINGS DOUBLE VERTICAL
     BB |  00002557 | BOX DRAWINGS DOUBLE DOWN AND LEFT
     BC |  0000255D | BOX DRAWINGS DOUBLE UP AND LEFT
     BD |  00000439 | CYRILLIC SMALL LETTER SHORT I
     BE |  00000419 | CYRILLIC CAPITAL LETTER SHORT I
     BF |  00002510 | BOX DRAWINGS LIGHT DOWN AND LEFT
     C0 |  00002514 | BOX DRAWINGS LIGHT UP AND RIGHT
     C1 |  00002534 | BOX DRAWINGS LIGHT UP AND HORIZONTAL
     C2 |  0000252C | BOX DRAWINGS LIGHT DOWN AND HORIZONTAL
     C3 |  0000251C | BOX DRAWINGS LIGHT VERTICAL AND RIGHT
     C4 |  00002500 | BOX DRAWINGS LIGHT HORIZONTAL
     C5 |  0000253C | BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL
     C6 |  0000043A | CYRILLIC SMALL LETTER KA
     C7 |  0000041A | CYRILLIC CAPITAL LETTER KA
     C8 |  0000255A | BOX DRAWINGS DOUBLE UP AND RIGHT
     C9 |  00002554 | BOX DRAWINGS DOUBLE DOWN AND RIGHT
     CA |  00002569 | BOX DRAWINGS DOUBLE UP AND HORIZONTAL
     CB |  00002566 | BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL
     CC |  00002560 | BOX DRAWINGS DOUBLE VERTICAL AND RIGHT
     CD |  00002550 | BOX DRAWINGS DOUBLE HORIZONTAL
     CE |  0000256C | BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL
     CF |  000000A4 | CURRENCY SIGN
     D0 |  0000043B | CYRILLIC SMALL LETTER EL
     D1 |  0000041B | CYRILLIC CAPITAL LETTER EL
     D2 |  0000043C | CYRILLIC SMALL LETTER EM
     D3 |  0000041C | CYRILLIC CAPITAL LETTER EM
     D4 |  0000043D | CYRILLIC SMALL LETTER EN
     D5 |  0000041D | CYRILLIC CAPITAL LETTER EN
     D6 |  0000043E | CYRILLIC SMALL LETTER O
     D7 |  0000041E | CYRILLIC CAPITAL LETTER O
     D8 |  0000043F | CYRILLIC SMALL LETTER PE
     D9 |  00002518 | BOX DRAWINGS LIGHT UP AND LEFT
     DA |  0000250C | BOX DRAWINGS LIGHT DOWN AND RIGHT
     DB |  00002588 | FULL BLOCK
     DC |  00002584 | LOWER HALF BLOCK
     DD |  0000041F | CYRILLIC CAPITAL LETTER PE
     DE |  0000044F | CYRILLIC SMALL LETTER YA
     DF |  00002580 | UPPER HALF BLOCK
     E0 |  0000042F | CYRILLIC CAPITAL LETTER YA
     E1 |  00000440 | CYRILLIC SMALL LETTER ER
     E2 |  00000420 | CYRILLIC CAPITAL LETTER ER
     E3 |  00000441 | CYRILLIC SMALL LETTER ES
     E4 |  00000421 | CYRILLIC CAPITAL LETTER ES
     E5 |  00000442 | CYRILLIC SMALL LETTER TE
     E6 |  00000422 | CYRILLIC CAPITAL LETTER TE
     E7 |  00000443 | CYRILLIC SMALL LETTER U
     E8 |  00000423 | CYRILLIC CAPITAL LETTER U
     E9 |  00000436 | CYRILLIC SMALL LETTER ZHE
     EA |  00000416 | CYRILLIC CAPITAL LETTER ZHE
     EB |  00000432 | CYRILLIC SMALL LETTER VE
     EC |  00000412 | CYRILLIC CAPITAL LETTER VE
     ED |  0000044C | CYRILLIC SMALL LETTER SOFT SIGN
     EE |  0000042C | CYRILLIC CAPITAL LETTER SOFT SIGN
     EF |  00002116 | NUMERO SIGN
     F0 |  000000AD | SOFT HYPHEN
     F1 |  0000044B | CYRILLIC SMALL LETTER YERU
     F2 |  0000042B | CYRILLIC CAPITAL LETTER YERU
     F3 |  00000437 | CYRILLIC SMALL LETTER ZE
     F4 |  00000417 | CYRILLIC CAPITAL LETTER ZE
     F5 |  00000448 | CYRILLIC SMALL LETTER SHA
     F6 |  00000428 | CYRILLIC CAPITAL LETTER SHA
     F7 |  0000044D | CYRILLIC SMALL LETTER E
     F8 |  0000042D | CYRILLIC CAPITAL LETTER E
     F9 |  00000449 | CYRILLIC SMALL LETTER SHCHA
     FA |  00000429 | CYRILLIC CAPITAL LETTER SHCHA
     FB |  00000447 | CYRILLIC SMALL LETTER CHE
     FC |  00000427 | CYRILLIC CAPITAL LETTER CHE
     FD |  000000A7 | SECTION SIGN
     FE |  000025A0 | BLACK SQUARE
     FF |  000000A0 | NO-BREAK SPACE
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/IBM857.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for IBM857.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::IBM857;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x0004,
     0x0005,
     0x0006,
     0x0007,
     0x0008,
     0x0009,
     0x000a,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x0014,
     0x0015,
     0x0016,
     0x0017,
     0x0018,
     0x0019,
     0x001a,
     0x001b,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0020,
     0x0021,
     0x0022,
     0x0023,
     0x0024,
     0x0025,
     0x0026,
     0x0027,
     0x0028,
     0x0029,
     0x002a,
     0x002b,
     0x002c,
     0x002d,
     0x002e,
     0x002f,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x003a,
     0x003b,
     0x003c,
     0x003d,
     0x003e,
     0x003f,
     0x0040,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x005b,
     0x005c,
     0x005d,
     0x005e,
     0x005f,
     0x0060,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x007b,
     0x007c,
     0x007d,
     0x007e,
     0x007f,
     0x00c7,
     0x00fc,
     0x00e9,
     0x00e2,
     0x00e4,
     0x00e0,
     0x00e5,
     0x00e7,
     0x00ea,
     0x00eb,
     0x00e8,
     0x00ef,
     0x00ee,
     0x0131,
     0x00c4,
     0x00c5,
     0x00c9,
     0x00e6,
     0x00c6,
     0x00f4,
     0x00f6,
     0x00f2,
     0x00fb,
     0x00f9,
     0x0130,
     0x00d6,
     0x00dc,
     0x00f8,
     0x00a3,
     0x00d8,
     0x015e,
     0x015f,
     0x00e1,
     0x00ed,
     0x00f3,
     0x00fa,
     0x00f1,
     0x00d1,
     0x011e,
     0x011f,
     0x00bf,
     0x00ae,
     0x00ac,
     0x00bd,
     0x00bc,
     0x00a1,
     0x00ab,
     0x00bb,
     0x2591,
     0x2592,
     0x2593,
     0x2502,
     0x2524,
     0x00c1,
     0x00c2,
     0x00c0,
     0x00a9,
     0x2563,
     0x2551,
     0x2557,
     0x255d,
     0x00a2,
     0x00a5,
     0x2510,
     0x2514,
     0x2534,
     0x252c,
     0x251c,
     0x2500,
     0x253c,
     0x00e3,
     0x00c3,
     0x255a,
     0x2554,
     0x2569,
     0x2566,
     0x2560,
     0x2550,
     0x256c,
     0x00a4,
     0x00ba,
     0x00aa,
     0x00ca,
     0x00cb,
     0x00c8,
     0xfffd,
     0x00cd,
     0x00ce,
     0x00cf,
     0x2518,
     0x250c,
     0x2588,
     0x2584,
     0x00a6,
     0x00cc,
     0x2580,
     0x00d3,
     0x00df,
     0x00d4,
     0x00d2,
     0x00f5,
     0x00d5,
     0x00b5,
     0xfffd,
     0x00d7,
     0x00da,
     0x00db,
     0x00d9,
     0x00ec,
     0x00ff,
     0x00af,
     0x00b4,
     0x00ad,
     0x00b1,
     0xfffd,
     0x00be,
     0x00b6,
     0x00a7,
     0x00f7,
     0x00b8,
     0x00b0,
     0x00a8,
     0x00b7,
     0x00b9,
     0x00b3,
     0x00b2,
     0x25a0,
     0x00a0,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\x04",
     "\x05",
     "\x06",
     "\x07",
     "\x08",
     "\x09",
     "\x0a",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\x14",
     "\x15",
     "\x16",
     "\x17",
     "\x18",
     "\x19",
     "\x1a",
     "\x1b",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\x20",
     "\x21",
     "\x22",
     "\x23",
     "\x24",
     "\x25",
     "\x26",
     "\x27",
     "\x28",
     "\x29",
     "\x2a",
     "\x2b",
     "\x2c",
     "\x2d",
     "\x2e",
     "\x2f",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\x3a",
     "\x3b",
     "\x3c",
     "\x3d",
     "\x3e",
     "\x3f",
     "\x40",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\x5b",
     "\x5c",
     "\x5d",
     "\x5e",
     "\x5f",
     "\x60",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\x7b",
     "\x7c",
     "\x7d",
     "\x7e",
     "\x7f",
     "\xc3\x87",
     "\xc3\xbc",
     "\xc3\xa9",
     "\xc3\xa2",
     "\xc3\xa4",
     "\xc3\xa0",
     "\xc3\xa5",
     "\xc3\xa7",
     "\xc3\xaa",
     "\xc3\xab",
     "\xc3\xa8",
     "\xc3\xaf",
     "\xc3\xae",
     "\xc4\xb1",
     "\xc3\x84",
     "\xc3\x85",
     "\xc3\x89",
     "\xc3\xa6",
     "\xc3\x86",
     "\xc3\xb4",
     "\xc3\xb6",
     "\xc3\xb2",
     "\xc3\xbb",
     "\xc3\xb9",
     "\xc4\xb0",
     "\xc3\x96",
     "\xc3\x9c",
     "\xc3\xb8",
     "\xc2\xa3",
     "\xc3\x98",
     "\xc5\x9e",
     "\xc5\x9f",
     "\xc3\xa1",
     "\xc3\xad",
     "\xc3\xb3",
     "\xc3\xba",
     "\xc3\xb1",
     "\xc3\x91",
     "\xc4\x9e",
     "\xc4\x9f",
     "\xc2\xbf",
     "\xc2\xae",
     "\xc2\xac",
     "\xc2\xbd",
     "\xc2\xbc",
     "\xc2\xa1",
     "\xc2\xab",
     "\xc2\xbb",
     "\xe2\x96\x91",
     "\xe2\x96\x92",
     "\xe2\x96\x93",
     "\xe2\x94\x82",
     "\xe2\x94\xa4",
     "\xc3\x81",
     "\xc3\x82",
     "\xc3\x80",
     "\xc2\xa9",
     "\xe2\x95\xa3",
     "\xe2\x95\x91",
     "\xe2\x95\x97",
     "\xe2\x95\x9d",
     "\xc2\xa2",
     "\xc2\xa5",
     "\xe2\x94\x90",
     "\xe2\x94\x94",
     "\xe2\x94\xb4",
     "\xe2\x94\xac",
     "\xe2\x94\x9c",
     "\xe2\x94\x80",
     "\xe2\x94\xbc",
     "\xc3\xa3",
     "\xc3\x83",
     "\xe2\x95\x9a",
     "\xe2\x95\x94",
     "\xe2\x95\xa9",
     "\xe2\x95\xa6",
     "\xe2\x95\xa0",
     "\xe2\x95\x90",
     "\xe2\x95\xac",
     "\xc2\xa4",
     "\xc2\xba",
     "\xc2\xaa",
     "\xc3\x8a",
     "\xc3\x8b",
     "\xc3\x88",
     "\xef\xbf\xbd",
     "\xc3\x8d",
     "\xc3\x8e",
     "\xc3\x8f",
     "\xe2\x94\x98",
     "\xe2\x94\x8c",
     "\xe2\x96\x88",
     "\xe2\x96\x84",
     "\xc2\xa6",
     "\xc3\x8c",
     "\xe2\x96\x80",
     "\xc3\x93",
     "\xc3\x9f",
     "\xc3\x94",
     "\xc3\x92",
     "\xc3\xb5",
     "\xc3\x95",
     "\xc2\xb5",
     "\xef\xbf\xbd",
     "\xc3\x97",
     "\xc3\x9a",
     "\xc3\x9b",
     "\xc3\x99",
     "\xc3\xac",
     "\xc3\xbf",
     "\xc2\xaf",
     "\xc2\xb4",
     "\xc2\xad",
     "\xc2\xb1",
     "\xef\xbf\xbd",
     "\xc2\xbe",
     "\xc2\xb6",
     "\xc2\xa7",
     "\xc3\xb7",
     "\xc2\xb8",
     "\xc2\xb0",
     "\xc2\xa8",
     "\xc2\xb7",
     "\xc2\xb9",
     "\xc2\xb3",
     "\xc2\xb2",
     "\xe2\x96\xa0",
     "\xc2\xa0",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x04",
     0x00000005 => "\x05",
     0x00000006 => "\x06",
     0x00000007 => "\x07",
     0x00000008 => "\x08",
     0x00000009 => "\x09",
     0x0000000a => "\x0a",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x14",
     0x00000015 => "\x15",
     0x00000016 => "\x16",
     0x00000017 => "\x17",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x1a",
     0x0000001b => "\x1b",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x20",
     0x00000021 => "\x21",
     0x00000022 => "\x22",
     0x00000023 => "\x23",
     0x00000024 => "\x24",
     0x00000025 => "\x25",
     0x00000026 => "\x26",
     0x00000027 => "\x27",
     0x00000028 => "\x28",
     0x00000029 => "\x29",
     0x0000002a => "\x2a",
     0x0000002b => "\x2b",
     0x0000002c => "\x2c",
     0x0000002d => "\x2d",
     0x0000002e => "\x2e",
     0x0000002f => "\x2f",
     0x00000030 => "\x30",
     0x00000031 => "\x31",
     0x00000032 => "\x32",
     0x00000033 => "\x33",
     0x00000034 => "\x34",
     0x00000035 => "\x35",
     0x00000036 => "\x36",
     0x00000037 => "\x37",
     0x00000038 => "\x38",
     0x00000039 => "\x39",
     0x0000003a => "\x3a",
     0x0000003b => "\x3b",
     0x0000003c => "\x3c",
     0x0000003d => "\x3d",
     0x0000003e => "\x3e",
     0x0000003f => "\x3f",
     0x00000040 => "\x40",
     0x00000041 => "\x41",
     0x00000042 => "\x42",
     0x00000043 => "\x43",
     0x00000044 => "\x44",
     0x00000045 => "\x45",
     0x00000046 => "\x46",
     0x00000047 => "\x47",
     0x00000048 => "\x48",
     0x00000049 => "\x49",
     0x0000004a => "\x4a",
     0x0000004b => "\x4b",
     0x0000004c => "\x4c",
     0x0000004d => "\x4d",
     0x0000004e => "\x4e",
     0x0000004f => "\x4f",
     0x00000050 => "\x50",
     0x00000051 => "\x51",
     0x00000052 => "\x52",
     0x00000053 => "\x53",
     0x00000054 => "\x54",
     0x00000055 => "\x55",
     0x00000056 => "\x56",
     0x00000057 => "\x57",
     0x00000058 => "\x58",
     0x00000059 => "\x59",
     0x0000005a => "\x5a",
     0x0000005b => "\x5b",
     0x0000005c => "\x5c",
     0x0000005d => "\x5d",
     0x0000005e => "\x5e",
     0x0000005f => "\x5f",
     0x00000060 => "\x60",
     0x00000061 => "\x61",
     0x00000062 => "\x62",
     0x00000063 => "\x63",
     0x00000064 => "\x64",
     0x00000065 => "\x65",
     0x00000066 => "\x66",
     0x00000067 => "\x67",
     0x00000068 => "\x68",
     0x00000069 => "\x69",
     0x0000006a => "\x6a",
     0x0000006b => "\x6b",
     0x0000006c => "\x6c",
     0x0000006d => "\x6d",
     0x0000006e => "\x6e",
     0x0000006f => "\x6f",
     0x00000070 => "\x70",
     0x00000071 => "\x71",
     0x00000072 => "\x72",
     0x00000073 => "\x73",
     0x00000074 => "\x74",
     0x00000075 => "\x75",
     0x00000076 => "\x76",
     0x00000077 => "\x77",
     0x00000078 => "\x78",
     0x00000079 => "\x79",
     0x0000007a => "\x7a",
     0x0000007b => "\x7b",
     0x0000007c => "\x7c",
     0x0000007d => "\x7d",
     0x0000007e => "\x7e",
     0x0000007f => "\x7f",
     0x000000a0 => "\xff",
     0x000000a1 => "\xad",
     0x000000a2 => "\xbd",
     0x000000a3 => "\x9c",
     0x000000a4 => "\xcf",
     0x000000a5 => "\xbe",
     0x000000a6 => "\xdd",
     0x000000a7 => "\xf5",
     0x000000a8 => "\xf9",
     0x000000a9 => "\xb8",
     0x000000aa => "\xd1",
     0x000000ab => "\xae",
     0x000000ac => "\xaa",
     0x000000ad => "\xf0",
     0x000000ae => "\xa9",
     0x000000af => "\xee",
     0x000000b0 => "\xf8",
     0x000000b1 => "\xf1",
     0x000000b2 => "\xfd",
     0x000000b3 => "\xfc",
     0x000000b4 => "\xef",
     0x000000b5 => "\xe6",
     0x000000b6 => "\xf4",
     0x000000b7 => "\xfa",
     0x000000b8 => "\xf7",
     0x000000b9 => "\xfb",
     0x000000ba => "\xd0",
     0x000000bb => "\xaf",
     0x000000bc => "\xac",
     0x000000bd => "\xab",
     0x000000be => "\xf3",
     0x000000bf => "\xa8",
     0x000000c0 => "\xb7",
     0x000000c1 => "\xb5",
     0x000000c2 => "\xb6",
     0x000000c3 => "\xc7",
     0x000000c4 => "\x8e",
     0x000000c5 => "\x8f",
     0x000000c6 => "\x92",
     0x000000c7 => "\x80",
     0x000000c8 => "\xd4",
     0x000000c9 => "\x90",
     0x000000ca => "\xd2",
     0x000000cb => "\xd3",
     0x000000cc => "\xde",
     0x000000cd => "\xd6",
     0x000000ce => "\xd7",
     0x000000cf => "\xd8",
     0x000000d1 => "\xa5",
     0x000000d2 => "\xe3",
     0x000000d3 => "\xe0",
     0x000000d4 => "\xe2",
     0x000000d5 => "\xe5",
     0x000000d6 => "\x99",
     0x000000d7 => "\xe8",
     0x000000d8 => "\x9d",
     0x000000d9 => "\xeb",
     0x000000da => "\xe9",
     0x000000db => "\xea",
     0x000000dc => "\x9a",
     0x000000df => "\xe1",
     0x000000e0 => "\x85",
     0x000000e1 => "\xa0",
     0x000000e2 => "\x83",
     0x000000e3 => "\xc6",
     0x000000e4 => "\x84",
     0x000000e5 => "\x86",
     0x000000e6 => "\x91",
     0x000000e7 => "\x87",
     0x000000e8 => "\x8a",
     0x000000e9 => "\x82",
     0x000000ea => "\x88",
     0x000000eb => "\x89",
     0x000000ec => "\xec",
     0x000000ed => "\xa1",
     0x000000ee => "\x8c",
     0x000000ef => "\x8b",
     0x000000f1 => "\xa4",
     0x000000f2 => "\x95",
     0x000000f3 => "\xa2",
     0x000000f4 => "\x93",
     0x000000f5 => "\xe4",
     0x000000f6 => "\x94",
     0x000000f7 => "\xf6",
     0x000000f8 => "\x9b",
     0x000000f9 => "\x97",
     0x000000fa => "\xa3",
     0x000000fb => "\x96",
     0x000000fc => "\x81",
     0x000000ff => "\xed",
     0x0000011e => "\xa6",
     0x0000011f => "\xa7",
     0x00000130 => "\x98",
     0x00000131 => "\x8d",
     0x0000015e => "\x9e",
     0x0000015f => "\x9f",
     0x00002500 => "\xc4",
     0x00002502 => "\xb3",
     0x0000250c => "\xda",
     0x00002510 => "\xbf",
     0x00002514 => "\xc0",
     0x00002518 => "\xd9",
     0x0000251c => "\xc3",
     0x00002524 => "\xb4",
     0x0000252c => "\xc2",
     0x00002534 => "\xc1",
     0x0000253c => "\xc5",
     0x00002550 => "\xcd",
     0x00002551 => "\xba",
     0x00002554 => "\xc9",
     0x00002557 => "\xbb",
     0x0000255a => "\xc8",
     0x0000255d => "\xbc",
     0x00002560 => "\xcc",
     0x00002563 => "\xb9",
     0x00002566 => "\xcb",
     0x00002569 => "\xca",
     0x0000256c => "\xce",
     0x00002580 => "\xdf",
     0x00002584 => "\xdc",
     0x00002588 => "\xdb",
     0x00002591 => "\xb0",
     0x00002592 => "\xb1",
     0x00002593 => "\xb2",
     0x000025a0 => "\xfe",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::IBM857 - Conversion routines for IBM857
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for IBM857.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
   source: IBM NLS RM Vol2 SE09-8002-01, March 1990
  alias CP857
  alias 857
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  00000004 | END OF TRANSMISSION (EOT)
     05 |  00000005 | ENQUIRY (ENQ)
     06 |  00000006 | ACKNOWLEDGE (ACK)
     07 |  00000007 | BELL (BEL)
     08 |  00000008 | BACKSPACE (BS)
     09 |  00000009 | CHARACTER TABULATION (HT)
     0A |  0000000A | LINE FEED (LF)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  00000014 | DEVICE CONTROL FOUR (DC4)
     15 |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     16 |  00000016 | SYNCHRONOUS IDLE (SYN)
     17 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  0000001A | SUBSTITUTE (SUB)
     1B |  0000001B | ESCAPE (ESC)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000020 | SPACE
     21 |  00000021 | EXCLAMATION MARK
     22 |  00000022 | QUOTATION MARK
     23 |  00000023 | NUMBER SIGN
     24 |  00000024 | DOLLAR SIGN
     25 |  00000025 | PERCENT SIGN
     26 |  00000026 | AMPERSAND
     27 |  00000027 | APOSTROPHE
     28 |  00000028 | LEFT PARENTHESIS
     29 |  00000029 | RIGHT PARENTHESIS
     2A |  0000002A | ASTERISK
     2B |  0000002B | PLUS SIGN
     2C |  0000002C | COMMA
     2D |  0000002D | HYPHEN-MINUS
     2E |  0000002E | FULL STOP
     2F |  0000002F | SOLIDUS
     30 |  00000030 | DIGIT ZERO
     31 |  00000031 | DIGIT ONE
     32 |  00000032 | DIGIT TWO
     33 |  00000033 | DIGIT THREE
     34 |  00000034 | DIGIT FOUR
     35 |  00000035 | DIGIT FIVE
     36 |  00000036 | DIGIT SIX
     37 |  00000037 | DIGIT SEVEN
     38 |  00000038 | DIGIT EIGHT
     39 |  00000039 | DIGIT NINE
     3A |  0000003A | COLON
     3B |  0000003B | SEMICOLON
     3C |  0000003C | LESS-THAN SIGN
     3D |  0000003D | EQUALS SIGN
     3E |  0000003E | GREATER-THAN SIGN
     3F |  0000003F | QUESTION MARK
     40 |  00000040 | COMMERCIAL AT
     41 |  00000041 | LATIN CAPITAL LETTER A
     42 |  00000042 | LATIN CAPITAL LETTER B
     43 |  00000043 | LATIN CAPITAL LETTER C
     44 |  00000044 | LATIN CAPITAL LETTER D
     45 |  00000045 | LATIN CAPITAL LETTER E
     46 |  00000046 | LATIN CAPITAL LETTER F
     47 |  00000047 | LATIN CAPITAL LETTER G
     48 |  00000048 | LATIN CAPITAL LETTER H
     49 |  00000049 | LATIN CAPITAL LETTER I
     4A |  0000004A | LATIN CAPITAL LETTER J
     4B |  0000004B | LATIN CAPITAL LETTER K
     4C |  0000004C | LATIN CAPITAL LETTER L
     4D |  0000004D | LATIN CAPITAL LETTER M
     4E |  0000004E | LATIN CAPITAL LETTER N
     4F |  0000004F | LATIN CAPITAL LETTER O
     50 |  00000050 | LATIN CAPITAL LETTER P
     51 |  00000051 | LATIN CAPITAL LETTER Q
     52 |  00000052 | LATIN CAPITAL LETTER R
     53 |  00000053 | LATIN CAPITAL LETTER S
     54 |  00000054 | LATIN CAPITAL LETTER T
     55 |  00000055 | LATIN CAPITAL LETTER U
     56 |  00000056 | LATIN CAPITAL LETTER V
     57 |  00000057 | LATIN CAPITAL LETTER W
     58 |  00000058 | LATIN CAPITAL LETTER X
     59 |  00000059 | LATIN CAPITAL LETTER Y
     5A |  0000005A | LATIN CAPITAL LETTER Z
     5B |  0000005B | LEFT SQUARE BRACKET
     5C |  0000005C | REVERSE SOLIDUS
     5D |  0000005D | RIGHT SQUARE BRACKET
     5E |  0000005E | CIRCUMFLEX ACCENT
     5F |  0000005F | LOW LINE
     60 |  00000060 | GRAVE ACCENT
     61 |  00000061 | LATIN SMALL LETTER A
     62 |  00000062 | LATIN SMALL LETTER B
     63 |  00000063 | LATIN SMALL LETTER C
     64 |  00000064 | LATIN SMALL LETTER D
     65 |  00000065 | LATIN SMALL LETTER E
     66 |  00000066 | LATIN SMALL LETTER F
     67 |  00000067 | LATIN SMALL LETTER G
     68 |  00000068 | LATIN SMALL LETTER H
     69 |  00000069 | LATIN SMALL LETTER I
     6A |  0000006A | LATIN SMALL LETTER J
     6B |  0000006B | LATIN SMALL LETTER K
     6C |  0000006C | LATIN SMALL LETTER L
     6D |  0000006D | LATIN SMALL LETTER M
     6E |  0000006E | LATIN SMALL LETTER N
     6F |  0000006F | LATIN SMALL LETTER O
     70 |  00000070 | LATIN SMALL LETTER P
     71 |  00000071 | LATIN SMALL LETTER Q
     72 |  00000072 | LATIN SMALL LETTER R
     73 |  00000073 | LATIN SMALL LETTER S
     74 |  00000074 | LATIN SMALL LETTER T
     75 |  00000075 | LATIN SMALL LETTER U
     76 |  00000076 | LATIN SMALL LETTER V
     77 |  00000077 | LATIN SMALL LETTER W
     78 |  00000078 | LATIN SMALL LETTER X
     79 |  00000079 | LATIN SMALL LETTER Y
     7A |  0000007A | LATIN SMALL LETTER Z
     7B |  0000007B | LEFT CURLY BRACKET
     7C |  0000007C | VERTICAL LINE
     7D |  0000007D | RIGHT CURLY BRACKET
     7E |  0000007E | TILDE
     7F |  0000007F | DELETE (DEL)
     80 |  000000C7 | LATIN CAPITAL LETTER C WITH CEDILLA
     81 |  000000FC | LATIN SMALL LETTER U WITH DIAERESIS
     82 |  000000E9 | LATIN SMALL LETTER E WITH ACUTE
     83 |  000000E2 | LATIN SMALL LETTER A WITH CIRCUMFLEX
     84 |  000000E4 | LATIN SMALL LETTER A WITH DIAERESIS
     85 |  000000E0 | LATIN SMALL LETTER A WITH GRAVE
     86 |  000000E5 | LATIN SMALL LETTER A WITH RING ABOVE
     87 |  000000E7 | LATIN SMALL LETTER C WITH CEDILLA
     88 |  000000EA | LATIN SMALL LETTER E WITH CIRCUMFLEX
     89 |  000000EB | LATIN SMALL LETTER E WITH DIAERESIS
     8A |  000000E8 | LATIN SMALL LETTER E WITH GRAVE
     8B |  000000EF | LATIN SMALL LETTER I WITH DIAERESIS
     8C |  000000EE | LATIN SMALL LETTER I WITH CIRCUMFLEX
     8D |  00000131 | LATIN SMALL LETTER DOTLESS I
     8E |  000000C4 | LATIN CAPITAL LETTER A WITH DIAERESIS
     8F |  000000C5 | LATIN CAPITAL LETTER A WITH RING ABOVE
     90 |  000000C9 | LATIN CAPITAL LETTER E WITH ACUTE
     91 |  000000E6 | LATIN SMALL LETTER AE
     92 |  000000C6 | LATIN CAPITAL LETTER AE
     93 |  000000F4 | LATIN SMALL LETTER O WITH CIRCUMFLEX
     94 |  000000F6 | LATIN SMALL LETTER O WITH DIAERESIS
     95 |  000000F2 | LATIN SMALL LETTER O WITH GRAVE
     96 |  000000FB | LATIN SMALL LETTER U WITH CIRCUMFLEX
     97 |  000000F9 | LATIN SMALL LETTER U WITH GRAVE
     98 |  00000130 | LATIN CAPITAL LETTER I WITH DOT ABOVE
     99 |  000000D6 | LATIN CAPITAL LETTER O WITH DIAERESIS
     9A |  000000DC | LATIN CAPITAL LETTER U WITH DIAERESIS
     9B |  000000F8 | LATIN SMALL LETTER O WITH STROKE
     9C |  000000A3 | POUND SIGN
     9D |  000000D8 | LATIN CAPITAL LETTER O WITH STROKE
     9E |  0000015E | LATIN CAPITAL LETTER S WITH CEDILLA
     9F |  0000015F | LATIN SMALL LETTER S WITH CEDILLA
     A0 |  000000E1 | LATIN SMALL LETTER A WITH ACUTE
     A1 |  000000ED | LATIN SMALL LETTER I WITH ACUTE
     A2 |  000000F3 | LATIN SMALL LETTER O WITH ACUTE
     A3 |  000000FA | LATIN SMALL LETTER U WITH ACUTE
     A4 |  000000F1 | LATIN SMALL LETTER N WITH TILDE
     A5 |  000000D1 | LATIN CAPITAL LETTER N WITH TILDE
     A6 |  0000011E | LATIN CAPITAL LETTER G WITH BREVE
     A7 |  0000011F | LATIN SMALL LETTER G WITH BREVE
     A8 |  000000BF | INVERTED QUESTION MARK
     A9 |  000000AE | REGISTERED SIGN
     AA |  000000AC | NOT SIGN
     AB |  000000BD | VULGAR FRACTION ONE HALF
     AC |  000000BC | VULGAR FRACTION ONE QUARTER
     AD |  000000A1 | INVERTED EXCLAMATION MARK
     AE |  000000AB | LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
     AF |  000000BB | RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
     B0 |  00002591 | LIGHT SHADE
     B1 |  00002592 | MEDIUM SHADE
     B2 |  00002593 | DARK SHADE
     B3 |  00002502 | BOX DRAWINGS LIGHT VERTICAL
     B4 |  00002524 | BOX DRAWINGS LIGHT VERTICAL AND LEFT
     B5 |  000000C1 | LATIN CAPITAL LETTER A WITH ACUTE
     B6 |  000000C2 | LATIN CAPITAL LETTER A WITH CIRCUMFLEX
     B7 |  000000C0 | LATIN CAPITAL LETTER A WITH GRAVE
     B8 |  000000A9 | COPYRIGHT SIGN
     B9 |  00002563 | BOX DRAWINGS DOUBLE VERTICAL AND LEFT
     BA |  00002551 | BOX DRAWINGS DOUBLE VERTICAL
     BB |  00002557 | BOX DRAWINGS DOUBLE DOWN AND LEFT
     BC |  0000255D | BOX DRAWINGS DOUBLE UP AND LEFT
     BD |  000000A2 | CENT SIGN
     BE |  000000A5 | YEN SIGN
     BF |  00002510 | BOX DRAWINGS LIGHT DOWN AND LEFT
     C0 |  00002514 | BOX DRAWINGS LIGHT UP AND RIGHT
     C1 |  00002534 | BOX DRAWINGS LIGHT UP AND HORIZONTAL
     C2 |  0000252C | BOX DRAWINGS LIGHT DOWN AND HORIZONTAL
     C3 |  0000251C | BOX DRAWINGS LIGHT VERTICAL AND RIGHT
     C4 |  00002500 | BOX DRAWINGS LIGHT HORIZONTAL
     C5 |  0000253C | BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL
     C6 |  000000E3 | LATIN SMALL LETTER A WITH TILDE
     C7 |  000000C3 | LATIN CAPITAL LETTER A WITH TILDE
     C8 |  0000255A | BOX DRAWINGS DOUBLE UP AND RIGHT
     C9 |  00002554 | BOX DRAWINGS DOUBLE DOWN AND RIGHT
     CA |  00002569 | BOX DRAWINGS DOUBLE UP AND HORIZONTAL
     CB |  00002566 | BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL
     CC |  00002560 | BOX DRAWINGS DOUBLE VERTICAL AND RIGHT
     CD |  00002550 | BOX DRAWINGS DOUBLE HORIZONTAL
     CE |  0000256C | BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL
     CF |  000000A4 | CURRENCY SIGN
     D0 |  000000BA | MASCULINE ORDINAL INDICATOR
     D1 |  000000AA | FEMININE ORDINAL INDICATOR
     D2 |  000000CA | LATIN CAPITAL LETTER E WITH CIRCUMFLEX
     D3 |  000000CB | LATIN CAPITAL LETTER E WITH DIAERESIS
     D4 |  000000C8 | LATIN CAPITAL LETTER E WITH GRAVE
     D6 |  000000CD | LATIN CAPITAL LETTER I WITH ACUTE
     D7 |  000000CE | LATIN CAPITAL LETTER I WITH CIRCUMFLEX
     D8 |  000000CF | LATIN CAPITAL LETTER I WITH DIAERESIS
     D9 |  00002518 | BOX DRAWINGS LIGHT UP AND LEFT
     DA |  0000250C | BOX DRAWINGS LIGHT DOWN AND RIGHT
     DB |  00002588 | FULL BLOCK
     DC |  00002584 | LOWER HALF BLOCK
     DD |  000000A6 | BROKEN BAR
     DE |  000000CC | LATIN CAPITAL LETTER I WITH GRAVE
     DF |  00002580 | UPPER HALF BLOCK
     E0 |  000000D3 | LATIN CAPITAL LETTER O WITH ACUTE
     E1 |  000000DF | LATIN SMALL LETTER SHARP S (German)
     E2 |  000000D4 | LATIN CAPITAL LETTER O WITH CIRCUMFLEX
     E3 |  000000D2 | LATIN CAPITAL LETTER O WITH GRAVE
     E4 |  000000F5 | LATIN SMALL LETTER O WITH TILDE
     E5 |  000000D5 | LATIN CAPITAL LETTER O WITH TILDE
     E6 |  000000B5 | MICRO SIGN
     E8 |  000000D7 | MULTIPLICATION SIGN
     E9 |  000000DA | LATIN CAPITAL LETTER U WITH ACUTE
     EA |  000000DB | LATIN CAPITAL LETTER U WITH CIRCUMFLEX
     EB |  000000D9 | LATIN CAPITAL LETTER U WITH GRAVE
     EC |  000000EC | LATIN SMALL LETTER I WITH GRAVE
     ED |  000000FF | LATIN SMALL LETTER Y WITH DIAERESIS
     EE |  000000AF | MACRON
     EF |  000000B4 | ACUTE ACCENT
     F0 |  000000AD | SOFT HYPHEN
     F1 |  000000B1 | PLUS-MINUS SIGN
     F3 |  000000BE | VULGAR FRACTION THREE QUARTERS
     F4 |  000000B6 | PILCROW SIGN
     F5 |  000000A7 | SECTION SIGN
     F6 |  000000F7 | DIVISION SIGN
     F7 |  000000B8 | CEDILLA
     F8 |  000000B0 | DEGREE SIGN
     F9 |  000000A8 | DIAERESIS
     FA |  000000B7 | MIDDLE DOT
     FB |  000000B9 | SUPERSCRIPT ONE
     FC |  000000B3 | SUPERSCRIPT THREE
     FD |  000000B2 | SUPERSCRIPT TWO
     FE |  000025A0 | BLACK SQUARE
     FF |  000000A0 | NO-BREAK SPACE
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/IBM860.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for IBM860.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::IBM860;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x0004,
     0x0005,
     0x0006,
     0x0007,
     0x0008,
     0x0009,
     0x000a,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x0014,
     0x0015,
     0x0016,
     0x0017,
     0x0018,
     0x0019,
     0x001a,
     0x001b,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0020,
     0x0021,
     0x0022,
     0x0023,
     0x0024,
     0x0025,
     0x0026,
     0x0027,
     0x0028,
     0x0029,
     0x002a,
     0x002b,
     0x002c,
     0x002d,
     0x002e,
     0x002f,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x003a,
     0x003b,
     0x003c,
     0x003d,
     0x003e,
     0x003f,
     0x0040,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x005b,
     0x005c,
     0x005d,
     0x005e,
     0x005f,
     0x0060,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x007b,
     0x007c,
     0x007d,
     0x007e,
     0x007f,
     0x00c7,
     0x00fc,
     0x00e9,
     0x00e2,
     0x00e3,
     0x00e0,
     0x00c1,
     0x00e7,
     0x00ea,
     0x00ca,
     0x00e8,
     0x00cd,
     0x00d4,
     0x00ec,
     0x00c3,
     0x00c2,
     0x00c9,
     0x00c0,
     0x00c8,
     0x00f4,
     0x00f5,
     0x00f2,
     0x00da,
     0x00f9,
     0x00cc,
     0x00d5,
     0x00dc,
     0x00a2,
     0x00a3,
     0x00d9,
     0x20a7,
     0x00d3,
     0x00e1,
     0x00ed,
     0x00f3,
     0x00fa,
     0x00f1,
     0x00d1,
     0x00aa,
     0x00ba,
     0x00bf,
     0x00d2,
     0x00ac,
     0x00bd,
     0x00bc,
     0x00a1,
     0x00ab,
     0x00bb,
     0x2591,
     0x2592,
     0x2593,
     0x2502,
     0x2524,
     0x2561,
     0x2562,
     0x2556,
     0x2555,
     0x2563,
     0x2551,
     0x2557,
     0x255d,
     0x255c,
     0x255b,
     0x2510,
     0x2514,
     0x2534,
     0x252c,
     0x251c,
     0x2500,
     0x253c,
     0x255e,
     0x255f,
     0x255a,
     0x2554,
     0x2569,
     0x2566,
     0x2560,
     0x2550,
     0x256c,
     0x2567,
     0x2568,
     0x2564,
     0x2565,
     0x2559,
     0x2558,
     0x2552,
     0x2553,
     0x256b,
     0x256a,
     0x2518,
     0x250c,
     0x2588,
     0x2584,
     0x258c,
     0x2590,
     0x2580,
     0x03b1,
     0x00df,
     0x0393,
     0x03c0,
     0x03a3,
     0x03c3,
     0x00b5,
     0x03c4,
     0x03a6,
     0x0398,
     0x03a9,
     0x03b4,
     0x221e,
     0x03c6,
     0x03b5,
     0x2229,
     0x2261,
     0x00b1,
     0x2265,
     0x2264,
     0x2320,
     0x2321,
     0x00f7,
     0x2248,
     0x00b0,
     0x2219,
     0x00b7,
     0x221a,
     0x207f,
     0x00b2,
     0x25a0,
     0x00a0,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\x04",
     "\x05",
     "\x06",
     "\x07",
     "\x08",
     "\x09",
     "\x0a",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\x14",
     "\x15",
     "\x16",
     "\x17",
     "\x18",
     "\x19",
     "\x1a",
     "\x1b",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\x20",
     "\x21",
     "\x22",
     "\x23",
     "\x24",
     "\x25",
     "\x26",
     "\x27",
     "\x28",
     "\x29",
     "\x2a",
     "\x2b",
     "\x2c",
     "\x2d",
     "\x2e",
     "\x2f",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\x3a",
     "\x3b",
     "\x3c",
     "\x3d",
     "\x3e",
     "\x3f",
     "\x40",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\x5b",
     "\x5c",
     "\x5d",
     "\x5e",
     "\x5f",
     "\x60",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\x7b",
     "\x7c",
     "\x7d",
     "\x7e",
     "\x7f",
     "\xc3\x87",
     "\xc3\xbc",
     "\xc3\xa9",
     "\xc3\xa2",
     "\xc3\xa3",
     "\xc3\xa0",
     "\xc3\x81",
     "\xc3\xa7",
     "\xc3\xaa",
     "\xc3\x8a",
     "\xc3\xa8",
     "\xc3\x8d",
     "\xc3\x94",
     "\xc3\xac",
     "\xc3\x83",
     "\xc3\x82",
     "\xc3\x89",
     "\xc3\x80",
     "\xc3\x88",
     "\xc3\xb4",
     "\xc3\xb5",
     "\xc3\xb2",
     "\xc3\x9a",
     "\xc3\xb9",
     "\xc3\x8c",
     "\xc3\x95",
     "\xc3\x9c",
     "\xc2\xa2",
     "\xc2\xa3",
     "\xc3\x99",
     "\xe2\x82\xa7",
     "\xc3\x93",
     "\xc3\xa1",
     "\xc3\xad",
     "\xc3\xb3",
     "\xc3\xba",
     "\xc3\xb1",
     "\xc3\x91",
     "\xc2\xaa",
     "\xc2\xba",
     "\xc2\xbf",
     "\xc3\x92",
     "\xc2\xac",
     "\xc2\xbd",
     "\xc2\xbc",
     "\xc2\xa1",
     "\xc2\xab",
     "\xc2\xbb",
     "\xe2\x96\x91",
     "\xe2\x96\x92",
     "\xe2\x96\x93",
     "\xe2\x94\x82",
     "\xe2\x94\xa4",
     "\xe2\x95\xa1",
     "\xe2\x95\xa2",
     "\xe2\x95\x96",
     "\xe2\x95\x95",
     "\xe2\x95\xa3",
     "\xe2\x95\x91",
     "\xe2\x95\x97",
     "\xe2\x95\x9d",
     "\xe2\x95\x9c",
     "\xe2\x95\x9b",
     "\xe2\x94\x90",
     "\xe2\x94\x94",
     "\xe2\x94\xb4",
     "\xe2\x94\xac",
     "\xe2\x94\x9c",
     "\xe2\x94\x80",
     "\xe2\x94\xbc",
     "\xe2\x95\x9e",
     "\xe2\x95\x9f",
     "\xe2\x95\x9a",
     "\xe2\x95\x94",
     "\xe2\x95\xa9",
     "\xe2\x95\xa6",
     "\xe2\x95\xa0",
     "\xe2\x95\x90",
     "\xe2\x95\xac",
     "\xe2\x95\xa7",
     "\xe2\x95\xa8",
     "\xe2\x95\xa4",
     "\xe2\x95\xa5",
     "\xe2\x95\x99",
     "\xe2\x95\x98",
     "\xe2\x95\x92",
     "\xe2\x95\x93",
     "\xe2\x95\xab",
     "\xe2\x95\xaa",
     "\xe2\x94\x98",
     "\xe2\x94\x8c",
     "\xe2\x96\x88",
     "\xe2\x96\x84",
     "\xe2\x96\x8c",
     "\xe2\x96\x90",
     "\xe2\x96\x80",
     "\xce\xb1",
     "\xc3\x9f",
     "\xce\x93",
     "\xcf\x80",
     "\xce\xa3",
     "\xcf\x83",
     "\xc2\xb5",
     "\xcf\x84",
     "\xce\xa6",
     "\xce\x98",
     "\xce\xa9",
     "\xce\xb4",
     "\xe2\x88\x9e",
     "\xcf\x86",
     "\xce\xb5",
     "\xe2\x88\xa9",
     "\xe2\x89\xa1",
     "\xc2\xb1",
     "\xe2\x89\xa5",
     "\xe2\x89\xa4",
     "\xe2\x8c\xa0",
     "\xe2\x8c\xa1",
     "\xc3\xb7",
     "\xe2\x89\x88",
     "\xc2\xb0",
     "\xe2\x88\x99",
     "\xc2\xb7",
     "\xe2\x88\x9a",
     "\xe2\x81\xbf",
     "\xc2\xb2",
     "\xe2\x96\xa0",
     "\xc2\xa0",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x04",
     0x00000005 => "\x05",
     0x00000006 => "\x06",
     0x00000007 => "\x07",
     0x00000008 => "\x08",
     0x00000009 => "\x09",
     0x0000000a => "\x0a",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x14",
     0x00000015 => "\x15",
     0x00000016 => "\x16",
     0x00000017 => "\x17",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x1a",
     0x0000001b => "\x1b",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x20",
     0x00000021 => "\x21",
     0x00000022 => "\x22",
     0x00000023 => "\x23",
     0x00000024 => "\x24",
     0x00000025 => "\x25",
     0x00000026 => "\x26",
     0x00000027 => "\x27",
     0x00000028 => "\x28",
     0x00000029 => "\x29",
     0x0000002a => "\x2a",
     0x0000002b => "\x2b",
     0x0000002c => "\x2c",
     0x0000002d => "\x2d",
     0x0000002e => "\x2e",
     0x0000002f => "\x2f",
     0x00000030 => "\x30",
     0x00000031 => "\x31",
     0x00000032 => "\x32",
     0x00000033 => "\x33",
     0x00000034 => "\x34",
     0x00000035 => "\x35",
     0x00000036 => "\x36",
     0x00000037 => "\x37",
     0x00000038 => "\x38",
     0x00000039 => "\x39",
     0x0000003a => "\x3a",
     0x0000003b => "\x3b",
     0x0000003c => "\x3c",
     0x0000003d => "\x3d",
     0x0000003e => "\x3e",
     0x0000003f => "\x3f",
     0x00000040 => "\x40",
     0x00000041 => "\x41",
     0x00000042 => "\x42",
     0x00000043 => "\x43",
     0x00000044 => "\x44",
     0x00000045 => "\x45",
     0x00000046 => "\x46",
     0x00000047 => "\x47",
     0x00000048 => "\x48",
     0x00000049 => "\x49",
     0x0000004a => "\x4a",
     0x0000004b => "\x4b",
     0x0000004c => "\x4c",
     0x0000004d => "\x4d",
     0x0000004e => "\x4e",
     0x0000004f => "\x4f",
     0x00000050 => "\x50",
     0x00000051 => "\x51",
     0x00000052 => "\x52",
     0x00000053 => "\x53",
     0x00000054 => "\x54",
     0x00000055 => "\x55",
     0x00000056 => "\x56",
     0x00000057 => "\x57",
     0x00000058 => "\x58",
     0x00000059 => "\x59",
     0x0000005a => "\x5a",
     0x0000005b => "\x5b",
     0x0000005c => "\x5c",
     0x0000005d => "\x5d",
     0x0000005e => "\x5e",
     0x0000005f => "\x5f",
     0x00000060 => "\x60",
     0x00000061 => "\x61",
     0x00000062 => "\x62",
     0x00000063 => "\x63",
     0x00000064 => "\x64",
     0x00000065 => "\x65",
     0x00000066 => "\x66",
     0x00000067 => "\x67",
     0x00000068 => "\x68",
     0x00000069 => "\x69",
     0x0000006a => "\x6a",
     0x0000006b => "\x6b",
     0x0000006c => "\x6c",
     0x0000006d => "\x6d",
     0x0000006e => "\x6e",
     0x0000006f => "\x6f",
     0x00000070 => "\x70",
     0x00000071 => "\x71",
     0x00000072 => "\x72",
     0x00000073 => "\x73",
     0x00000074 => "\x74",
     0x00000075 => "\x75",
     0x00000076 => "\x76",
     0x00000077 => "\x77",
     0x00000078 => "\x78",
     0x00000079 => "\x79",
     0x0000007a => "\x7a",
     0x0000007b => "\x7b",
     0x0000007c => "\x7c",
     0x0000007d => "\x7d",
     0x0000007e => "\x7e",
     0x0000007f => "\x7f",
     0x000000a0 => "\xff",
     0x000000a1 => "\xad",
     0x000000a2 => "\x9b",
     0x000000a3 => "\x9c",
     0x000000aa => "\xa6",
     0x000000ab => "\xae",
     0x000000ac => "\xaa",
     0x000000b0 => "\xf8",
     0x000000b1 => "\xf1",
     0x000000b2 => "\xfd",
     0x000000b5 => "\xe6",
     0x000000b7 => "\xfa",
     0x000000ba => "\xa7",
     0x000000bb => "\xaf",
     0x000000bc => "\xac",
     0x000000bd => "\xab",
     0x000000bf => "\xa8",
     0x000000c0 => "\x91",
     0x000000c1 => "\x86",
     0x000000c2 => "\x8f",
     0x000000c3 => "\x8e",
     0x000000c7 => "\x80",
     0x000000c8 => "\x92",
     0x000000c9 => "\x90",
     0x000000ca => "\x89",
     0x000000cc => "\x98",
     0x000000cd => "\x8b",
     0x000000d1 => "\xa5",
     0x000000d2 => "\xa9",
     0x000000d3 => "\x9f",
     0x000000d4 => "\x8c",
     0x000000d5 => "\x99",
     0x000000d9 => "\x9d",
     0x000000da => "\x96",
     0x000000dc => "\x9a",
     0x000000df => "\xe1",
     0x000000e0 => "\x85",
     0x000000e1 => "\xa0",
     0x000000e2 => "\x83",
     0x000000e3 => "\x84",
     0x000000e7 => "\x87",
     0x000000e8 => "\x8a",
     0x000000e9 => "\x82",
     0x000000ea => "\x88",
     0x000000ec => "\x8d",
     0x000000ed => "\xa1",
     0x000000f1 => "\xa4",
     0x000000f2 => "\x95",
     0x000000f3 => "\xa2",
     0x000000f4 => "\x93",
     0x000000f5 => "\x94",
     0x000000f7 => "\xf6",
     0x000000f9 => "\x97",
     0x000000fa => "\xa3",
     0x000000fc => "\x81",
     0x00000393 => "\xe2",
     0x00000398 => "\xe9",
     0x000003a3 => "\xe4",
     0x000003a6 => "\xe8",
     0x000003a9 => "\xea",
     0x000003b1 => "\xe0",
     0x000003b4 => "\xeb",
     0x000003b5 => "\xee",
     0x000003c0 => "\xe3",
     0x000003c3 => "\xe5",
     0x000003c4 => "\xe7",
     0x000003c6 => "\xed",
     0x0000207f => "\xfc",
     0x000020a7 => "\x9e",
     0x00002219 => "\xf9",
     0x0000221a => "\xfb",
     0x0000221e => "\xec",
     0x00002229 => "\xef",
     0x00002248 => "\xf7",
     0x00002261 => "\xf0",
     0x00002264 => "\xf3",
     0x00002265 => "\xf2",
     0x00002320 => "\xf4",
     0x00002321 => "\xf5",
     0x00002500 => "\xc4",
     0x00002502 => "\xb3",
     0x0000250c => "\xda",
     0x00002510 => "\xbf",
     0x00002514 => "\xc0",
     0x00002518 => "\xd9",
     0x0000251c => "\xc3",
     0x00002524 => "\xb4",
     0x0000252c => "\xc2",
     0x00002534 => "\xc1",
     0x0000253c => "\xc5",
     0x00002550 => "\xcd",
     0x00002551 => "\xba",
     0x00002552 => "\xd5",
     0x00002553 => "\xd6",
     0x00002554 => "\xc9",
     0x00002555 => "\xb8",
     0x00002556 => "\xb7",
     0x00002557 => "\xbb",
     0x00002558 => "\xd4",
     0x00002559 => "\xd3",
     0x0000255a => "\xc8",
     0x0000255b => "\xbe",
     0x0000255c => "\xbd",
     0x0000255d => "\xbc",
     0x0000255e => "\xc6",
     0x0000255f => "\xc7",
     0x00002560 => "\xcc",
     0x00002561 => "\xb5",
     0x00002562 => "\xb6",
     0x00002563 => "\xb9",
     0x00002564 => "\xd1",
     0x00002565 => "\xd2",
     0x00002566 => "\xcb",
     0x00002567 => "\xcf",
     0x00002568 => "\xd0",
     0x00002569 => "\xca",
     0x0000256a => "\xd8",
     0x0000256b => "\xd7",
     0x0000256c => "\xce",
     0x00002580 => "\xdf",
     0x00002584 => "\xdc",
     0x00002588 => "\xdb",
     0x0000258c => "\xdd",
     0x00002590 => "\xde",
     0x00002591 => "\xb0",
     0x00002592 => "\xb1",
     0x00002593 => "\xb2",
     0x000025a0 => "\xfe",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::IBM860 - Conversion routines for IBM860
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for IBM860.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
   source: IBM NLS RM Vol2 SE09-8002-01, March 1990
  alias CP860
  alias 860
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  00000004 | END OF TRANSMISSION (EOT)
     05 |  00000005 | ENQUIRY (ENQ)
     06 |  00000006 | ACKNOWLEDGE (ACK)
     07 |  00000007 | BELL (BEL)
     08 |  00000008 | BACKSPACE (BS)
     09 |  00000009 | CHARACTER TABULATION (HT)
     0A |  0000000A | LINE FEED (LF)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  00000014 | DEVICE CONTROL FOUR (DC4)
     15 |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     16 |  00000016 | SYNCHRONOUS IDLE (SYN)
     17 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  0000001A | SUBSTITUTE (SUB)
     1B |  0000001B | ESCAPE (ESC)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000020 | SPACE
     21 |  00000021 | EXCLAMATION MARK
     22 |  00000022 | QUOTATION MARK
     23 |  00000023 | NUMBER SIGN
     24 |  00000024 | DOLLAR SIGN
     25 |  00000025 | PERCENT SIGN
     26 |  00000026 | AMPERSAND
     27 |  00000027 | APOSTROPHE
     28 |  00000028 | LEFT PARENTHESIS
     29 |  00000029 | RIGHT PARENTHESIS
     2A |  0000002A | ASTERISK
     2B |  0000002B | PLUS SIGN
     2C |  0000002C | COMMA
     2D |  0000002D | HYPHEN-MINUS
     2E |  0000002E | FULL STOP
     2F |  0000002F | SOLIDUS
     30 |  00000030 | DIGIT ZERO
     31 |  00000031 | DIGIT ONE
     32 |  00000032 | DIGIT TWO
     33 |  00000033 | DIGIT THREE
     34 |  00000034 | DIGIT FOUR
     35 |  00000035 | DIGIT FIVE
     36 |  00000036 | DIGIT SIX
     37 |  00000037 | DIGIT SEVEN
     38 |  00000038 | DIGIT EIGHT
     39 |  00000039 | DIGIT NINE
     3A |  0000003A | COLON
     3B |  0000003B | SEMICOLON
     3C |  0000003C | LESS-THAN SIGN
     3D |  0000003D | EQUALS SIGN
     3E |  0000003E | GREATER-THAN SIGN
     3F |  0000003F | QUESTION MARK
     40 |  00000040 | COMMERCIAL AT
     41 |  00000041 | LATIN CAPITAL LETTER A
     42 |  00000042 | LATIN CAPITAL LETTER B
     43 |  00000043 | LATIN CAPITAL LETTER C
     44 |  00000044 | LATIN CAPITAL LETTER D
     45 |  00000045 | LATIN CAPITAL LETTER E
     46 |  00000046 | LATIN CAPITAL LETTER F
     47 |  00000047 | LATIN CAPITAL LETTER G
     48 |  00000048 | LATIN CAPITAL LETTER H
     49 |  00000049 | LATIN CAPITAL LETTER I
     4A |  0000004A | LATIN CAPITAL LETTER J
     4B |  0000004B | LATIN CAPITAL LETTER K
     4C |  0000004C | LATIN CAPITAL LETTER L
     4D |  0000004D | LATIN CAPITAL LETTER M
     4E |  0000004E | LATIN CAPITAL LETTER N
     4F |  0000004F | LATIN CAPITAL LETTER O
     50 |  00000050 | LATIN CAPITAL LETTER P
     51 |  00000051 | LATIN CAPITAL LETTER Q
     52 |  00000052 | LATIN CAPITAL LETTER R
     53 |  00000053 | LATIN CAPITAL LETTER S
     54 |  00000054 | LATIN CAPITAL LETTER T
     55 |  00000055 | LATIN CAPITAL LETTER U
     56 |  00000056 | LATIN CAPITAL LETTER V
     57 |  00000057 | LATIN CAPITAL LETTER W
     58 |  00000058 | LATIN CAPITAL LETTER X
     59 |  00000059 | LATIN CAPITAL LETTER Y
     5A |  0000005A | LATIN CAPITAL LETTER Z
     5B |  0000005B | LEFT SQUARE BRACKET
     5C |  0000005C | REVERSE SOLIDUS
     5D |  0000005D | RIGHT SQUARE BRACKET
     5E |  0000005E | CIRCUMFLEX ACCENT
     5F |  0000005F | LOW LINE
     60 |  00000060 | GRAVE ACCENT
     61 |  00000061 | LATIN SMALL LETTER A
     62 |  00000062 | LATIN SMALL LETTER B
     63 |  00000063 | LATIN SMALL LETTER C
     64 |  00000064 | LATIN SMALL LETTER D
     65 |  00000065 | LATIN SMALL LETTER E
     66 |  00000066 | LATIN SMALL LETTER F
     67 |  00000067 | LATIN SMALL LETTER G
     68 |  00000068 | LATIN SMALL LETTER H
     69 |  00000069 | LATIN SMALL LETTER I
     6A |  0000006A | LATIN SMALL LETTER J
     6B |  0000006B | LATIN SMALL LETTER K
     6C |  0000006C | LATIN SMALL LETTER L
     6D |  0000006D | LATIN SMALL LETTER M
     6E |  0000006E | LATIN SMALL LETTER N
     6F |  0000006F | LATIN SMALL LETTER O
     70 |  00000070 | LATIN SMALL LETTER P
     71 |  00000071 | LATIN SMALL LETTER Q
     72 |  00000072 | LATIN SMALL LETTER R
     73 |  00000073 | LATIN SMALL LETTER S
     74 |  00000074 | LATIN SMALL LETTER T
     75 |  00000075 | LATIN SMALL LETTER U
     76 |  00000076 | LATIN SMALL LETTER V
     77 |  00000077 | LATIN SMALL LETTER W
     78 |  00000078 | LATIN SMALL LETTER X
     79 |  00000079 | LATIN SMALL LETTER Y
     7A |  0000007A | LATIN SMALL LETTER Z
     7B |  0000007B | LEFT CURLY BRACKET
     7C |  0000007C | VERTICAL LINE
     7D |  0000007D | RIGHT CURLY BRACKET
     7E |  0000007E | TILDE
     7F |  0000007F | DELETE (DEL)
     80 |  000000C7 | LATIN CAPITAL LETTER C WITH CEDILLA
     81 |  000000FC | LATIN SMALL LETTER U WITH DIAERESIS
     82 |  000000E9 | LATIN SMALL LETTER E WITH ACUTE
     83 |  000000E2 | LATIN SMALL LETTER A WITH CIRCUMFLEX
     84 |  000000E3 | LATIN SMALL LETTER A WITH TILDE
     85 |  000000E0 | LATIN SMALL LETTER A WITH GRAVE
     86 |  000000C1 | LATIN CAPITAL LETTER A WITH ACUTE
     87 |  000000E7 | LATIN SMALL LETTER C WITH CEDILLA
     88 |  000000EA | LATIN SMALL LETTER E WITH CIRCUMFLEX
     89 |  000000CA | LATIN CAPITAL LETTER E WITH CIRCUMFLEX
     8A |  000000E8 | LATIN SMALL LETTER E WITH GRAVE
     8B |  000000CD | LATIN CAPITAL LETTER I WITH ACUTE
     8C |  000000D4 | LATIN CAPITAL LETTER O WITH CIRCUMFLEX
     8D |  000000EC | LATIN SMALL LETTER I WITH GRAVE
     8E |  000000C3 | LATIN CAPITAL LETTER A WITH TILDE
     8F |  000000C2 | LATIN CAPITAL LETTER A WITH CIRCUMFLEX
     90 |  000000C9 | LATIN CAPITAL LETTER E WITH ACUTE
     91 |  000000C0 | LATIN CAPITAL LETTER A WITH GRAVE
     92 |  000000C8 | LATIN CAPITAL LETTER E WITH GRAVE
     93 |  000000F4 | LATIN SMALL LETTER O WITH CIRCUMFLEX
     94 |  000000F5 | LATIN SMALL LETTER O WITH TILDE
     95 |  000000F2 | LATIN SMALL LETTER O WITH GRAVE
     96 |  000000DA | LATIN CAPITAL LETTER U WITH ACUTE
     97 |  000000F9 | LATIN SMALL LETTER U WITH GRAVE
     98 |  000000CC | LATIN CAPITAL LETTER I WITH GRAVE
     99 |  000000D5 | LATIN CAPITAL LETTER O WITH TILDE
     9A |  000000DC | LATIN CAPITAL LETTER U WITH DIAERESIS
     9B |  000000A2 | CENT SIGN
     9C |  000000A3 | POUND SIGN
     9D |  000000D9 | LATIN CAPITAL LETTER U WITH GRAVE
     9E |  000020A7 | PESETA SIGN
     9F |  000000D3 | LATIN CAPITAL LETTER O WITH ACUTE
     A0 |  000000E1 | LATIN SMALL LETTER A WITH ACUTE
     A1 |  000000ED | LATIN SMALL LETTER I WITH ACUTE
     A2 |  000000F3 | LATIN SMALL LETTER O WITH ACUTE
     A3 |  000000FA | LATIN SMALL LETTER U WITH ACUTE
     A4 |  000000F1 | LATIN SMALL LETTER N WITH TILDE
     A5 |  000000D1 | LATIN CAPITAL LETTER N WITH TILDE
     A6 |  000000AA | FEMININE ORDINAL INDICATOR
     A7 |  000000BA | MASCULINE ORDINAL INDICATOR
     A8 |  000000BF | INVERTED QUESTION MARK
     A9 |  000000D2 | LATIN CAPITAL LETTER O WITH GRAVE
     AA |  000000AC | NOT SIGN
     AB |  000000BD | VULGAR FRACTION ONE HALF
     AC |  000000BC | VULGAR FRACTION ONE QUARTER
     AD |  000000A1 | INVERTED EXCLAMATION MARK
     AE |  000000AB | LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
     AF |  000000BB | RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
     B0 |  00002591 | LIGHT SHADE
     B1 |  00002592 | MEDIUM SHADE
     B2 |  00002593 | DARK SHADE
     B3 |  00002502 | BOX DRAWINGS LIGHT VERTICAL
     B4 |  00002524 | BOX DRAWINGS LIGHT VERTICAL AND LEFT
     B5 |  00002561 | BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE
     B6 |  00002562 | BOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLE
     B7 |  00002556 | BOX DRAWINGS DOWN DOUBLE AND LEFT SINGLE
     B8 |  00002555 | BOX DRAWINGS DOWN SINGLE AND LEFT DOUBLE
     B9 |  00002563 | BOX DRAWINGS DOUBLE VERTICAL AND LEFT
     BA |  00002551 | BOX DRAWINGS DOUBLE VERTICAL
     BB |  00002557 | BOX DRAWINGS DOUBLE DOWN AND LEFT
     BC |  0000255D | BOX DRAWINGS DOUBLE UP AND LEFT
     BD |  0000255C | BOX DRAWINGS UP DOUBLE AND LEFT SINGLE
     BE |  0000255B | BOX DRAWINGS UP SINGLE AND LEFT DOUBLE
     BF |  00002510 | BOX DRAWINGS LIGHT DOWN AND LEFT
     C0 |  00002514 | BOX DRAWINGS LIGHT UP AND RIGHT
     C1 |  00002534 | BOX DRAWINGS LIGHT UP AND HORIZONTAL
     C2 |  0000252C | BOX DRAWINGS LIGHT DOWN AND HORIZONTAL
     C3 |  0000251C | BOX DRAWINGS LIGHT VERTICAL AND RIGHT
     C4 |  00002500 | BOX DRAWINGS LIGHT HORIZONTAL
     C5 |  0000253C | BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL
     C6 |  0000255E | BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE
     C7 |  0000255F | BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE
     C8 |  0000255A | BOX DRAWINGS DOUBLE UP AND RIGHT
     C9 |  00002554 | BOX DRAWINGS DOUBLE DOWN AND RIGHT
     CA |  00002569 | BOX DRAWINGS DOUBLE UP AND HORIZONTAL
     CB |  00002566 | BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL
     CC |  00002560 | BOX DRAWINGS DOUBLE VERTICAL AND RIGHT
     CD |  00002550 | BOX DRAWINGS DOUBLE HORIZONTAL
     CE |  0000256C | BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL
     CF |  00002567 | BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE
     D0 |  00002568 | BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE
     D1 |  00002564 | BOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLE
     D2 |  00002565 | BOX DRAWINGS DOWN DOUBLE AND HORIZONTAL SINGLE
     D3 |  00002559 | BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE
     D4 |  00002558 | BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE
     D5 |  00002552 | BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE
     D6 |  00002553 | BOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLE
     D7 |  0000256B | BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLE
     D8 |  0000256A | BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE
     D9 |  00002518 | BOX DRAWINGS LIGHT UP AND LEFT
     DA |  0000250C | BOX DRAWINGS LIGHT DOWN AND RIGHT
     DB |  00002588 | FULL BLOCK
     DC |  00002584 | LOWER HALF BLOCK
     DD |  0000258C | LEFT HALF BLOCK
     DE |  00002590 | RIGHT HALF BLOCK
     DF |  00002580 | UPPER HALF BLOCK
     E0 |  000003B1 | GREEK SMALL LETTER ALPHA
     E1 |  000000DF | LATIN SMALL LETTER SHARP S (German)
     E2 |  00000393 | GREEK CAPITAL LETTER GAMMA
     E3 |  000003C0 | GREEK SMALL LETTER PI
     E4 |  000003A3 | GREEK CAPITAL LETTER SIGMA
     E5 |  000003C3 | GREEK SMALL LETTER SIGMA
     E6 |  000000B5 | MICRO SIGN
     E7 |  000003C4 | GREEK SMALL LETTER TAU
     E8 |  000003A6 | GREEK CAPITAL LETTER PHI
     E9 |  00000398 | GREEK CAPITAL LETTER THETA
     EA |  000003A9 | GREEK CAPITAL LETTER OMEGA
     EB |  000003B4 | GREEK SMALL LETTER DELTA
     EC |  0000221E | INFINITY
     ED |  000003C6 | GREEK SMALL LETTER PHI
     EE |  000003B5 | GREEK SMALL LETTER EPSILON
     EF |  00002229 | INTERSECTION
     F0 |  00002261 | IDENTICAL TO
     F1 |  000000B1 | PLUS-MINUS SIGN
     F2 |  00002265 | GREATER-THAN OR EQUAL TO
     F3 |  00002264 | LESS-THAN OR EQUAL TO
     F4 |  00002320 | TOP HALF INTEGRAL
     F5 |  00002321 | BOTTOM HALF INTEGRAL
     F6 |  000000F7 | DIVISION SIGN
     F7 |  00002248 | ALMOST EQUAL TO
     F8 |  000000B0 | DEGREE SIGN
     F9 |  00002219 | BULLET OPERATOR
     FA |  000000B7 | MIDDLE DOT
     FB |  0000221A | SQUARE ROOT
     FC |  0000207F | SUPERSCRIPT LATIN SMALL LETTER N
     FD |  000000B2 | SUPERSCRIPT TWO
     FE |  000025A0 | BLACK SQUARE
     FF |  000000A0 | NO-BREAK SPACE
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/IBM861.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for IBM861.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::IBM861;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x0004,
     0x0005,
     0x0006,
     0x0007,
     0x0008,
     0x0009,
     0x000a,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x0014,
     0x0015,
     0x0016,
     0x0017,
     0x0018,
     0x0019,
     0x001a,
     0x001b,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0020,
     0x0021,
     0x0022,
     0x0023,
     0x0024,
     0x0025,
     0x0026,
     0x0027,
     0x0028,
     0x0029,
     0x002a,
     0x002b,
     0x002c,
     0x002d,
     0x002e,
     0x002f,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x003a,
     0x003b,
     0x003c,
     0x003d,
     0x003e,
     0x003f,
     0x0040,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x005b,
     0x005c,
     0x005d,
     0x005e,
     0x005f,
     0x0060,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x007b,
     0x007c,
     0x007d,
     0x007e,
     0x007f,
     0x00c7,
     0x00fc,
     0x00e9,
     0x00e2,
     0x00e4,
     0x00e0,
     0x00e5,
     0x00e7,
     0x00ea,
     0x00eb,
     0x00e8,
     0x00d0,
     0x00f0,
     0x00de,
     0x00c4,
     0x00c5,
     0x00c9,
     0x00e6,
     0x00c6,
     0x00f4,
     0x00f6,
     0x00fe,
     0x00fb,
     0x00dd,
     0x00fd,
     0x00d6,
     0x00dc,
     0x00f8,
     0x00a3,
     0x00d8,
     0x20a7,
     0x0192,
     0x00e1,
     0x00ed,
     0x00f3,
     0x00fa,
     0x00c1,
     0x00cd,
     0x00d3,
     0x00da,
     0x00bf,
     0x2310,
     0x00ac,
     0x00bd,
     0x00bc,
     0x00a1,
     0x00ab,
     0x00bb,
     0x2591,
     0x2592,
     0x2593,
     0x2502,
     0x2524,
     0x2561,
     0x2562,
     0x2556,
     0x2555,
     0x2563,
     0x2551,
     0x2557,
     0x255d,
     0x255c,
     0x255b,
     0x2510,
     0x2514,
     0x2534,
     0x252c,
     0x251c,
     0x2500,
     0x253c,
     0x255e,
     0x255f,
     0x255a,
     0x2554,
     0x2569,
     0x2566,
     0x2560,
     0x2550,
     0x256c,
     0x2567,
     0x2568,
     0x2564,
     0x2565,
     0x2559,
     0x2558,
     0x2552,
     0x2553,
     0x256b,
     0x256a,
     0x2518,
     0x250c,
     0x2588,
     0x2584,
     0x258c,
     0x2590,
     0x2580,
     0x03b1,
     0x00df,
     0x0393,
     0x03c0,
     0x03a3,
     0x03c3,
     0x00b5,
     0x03c4,
     0x03a6,
     0x0398,
     0x03a9,
     0x03b4,
     0x221e,
     0x03c6,
     0x03b5,
     0x2229,
     0x2261,
     0x00b1,
     0x2265,
     0x2264,
     0x2320,
     0x2321,
     0x00f7,
     0x2248,
     0x00b0,
     0x2219,
     0x00b7,
     0x221a,
     0x207f,
     0x00b2,
     0x25a0,
     0x00a0,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\x04",
     "\x05",
     "\x06",
     "\x07",
     "\x08",
     "\x09",
     "\x0a",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\x14",
     "\x15",
     "\x16",
     "\x17",
     "\x18",
     "\x19",
     "\x1a",
     "\x1b",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\x20",
     "\x21",
     "\x22",
     "\x23",
     "\x24",
     "\x25",
     "\x26",
     "\x27",
     "\x28",
     "\x29",
     "\x2a",
     "\x2b",
     "\x2c",
     "\x2d",
     "\x2e",
     "\x2f",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\x3a",
     "\x3b",
     "\x3c",
     "\x3d",
     "\x3e",
     "\x3f",
     "\x40",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\x5b",
     "\x5c",
     "\x5d",
     "\x5e",
     "\x5f",
     "\x60",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\x7b",
     "\x7c",
     "\x7d",
     "\x7e",
     "\x7f",
     "\xc3\x87",
     "\xc3\xbc",
     "\xc3\xa9",
     "\xc3\xa2",
     "\xc3\xa4",
     "\xc3\xa0",
     "\xc3\xa5",
     "\xc3\xa7",
     "\xc3\xaa",
     "\xc3\xab",
     "\xc3\xa8",
     "\xc3\x90",
     "\xc3\xb0",
     "\xc3\x9e",
     "\xc3\x84",
     "\xc3\x85",
     "\xc3\x89",
     "\xc3\xa6",
     "\xc3\x86",
     "\xc3\xb4",
     "\xc3\xb6",
     "\xc3\xbe",
     "\xc3\xbb",
     "\xc3\x9d",
     "\xc3\xbd",
     "\xc3\x96",
     "\xc3\x9c",
     "\xc3\xb8",
     "\xc2\xa3",
     "\xc3\x98",
     "\xe2\x82\xa7",
     "\xc6\x92",
     "\xc3\xa1",
     "\xc3\xad",
     "\xc3\xb3",
     "\xc3\xba",
     "\xc3\x81",
     "\xc3\x8d",
     "\xc3\x93",
     "\xc3\x9a",
     "\xc2\xbf",
     "\xe2\x8c\x90",
     "\xc2\xac",
     "\xc2\xbd",
     "\xc2\xbc",
     "\xc2\xa1",
     "\xc2\xab",
     "\xc2\xbb",
     "\xe2\x96\x91",
     "\xe2\x96\x92",
     "\xe2\x96\x93",
     "\xe2\x94\x82",
     "\xe2\x94\xa4",
     "\xe2\x95\xa1",
     "\xe2\x95\xa2",
     "\xe2\x95\x96",
     "\xe2\x95\x95",
     "\xe2\x95\xa3",
     "\xe2\x95\x91",
     "\xe2\x95\x97",
     "\xe2\x95\x9d",
     "\xe2\x95\x9c",
     "\xe2\x95\x9b",
     "\xe2\x94\x90",
     "\xe2\x94\x94",
     "\xe2\x94\xb4",
     "\xe2\x94\xac",
     "\xe2\x94\x9c",
     "\xe2\x94\x80",
     "\xe2\x94\xbc",
     "\xe2\x95\x9e",
     "\xe2\x95\x9f",
     "\xe2\x95\x9a",
     "\xe2\x95\x94",
     "\xe2\x95\xa9",
     "\xe2\x95\xa6",
     "\xe2\x95\xa0",
     "\xe2\x95\x90",
     "\xe2\x95\xac",
     "\xe2\x95\xa7",
     "\xe2\x95\xa8",
     "\xe2\x95\xa4",
     "\xe2\x95\xa5",
     "\xe2\x95\x99",
     "\xe2\x95\x98",
     "\xe2\x95\x92",
     "\xe2\x95\x93",
     "\xe2\x95\xab",
     "\xe2\x95\xaa",
     "\xe2\x94\x98",
     "\xe2\x94\x8c",
     "\xe2\x96\x88",
     "\xe2\x96\x84",
     "\xe2\x96\x8c",
     "\xe2\x96\x90",
     "\xe2\x96\x80",
     "\xce\xb1",
     "\xc3\x9f",
     "\xce\x93",
     "\xcf\x80",
     "\xce\xa3",
     "\xcf\x83",
     "\xc2\xb5",
     "\xcf\x84",
     "\xce\xa6",
     "\xce\x98",
     "\xce\xa9",
     "\xce\xb4",
     "\xe2\x88\x9e",
     "\xcf\x86",
     "\xce\xb5",
     "\xe2\x88\xa9",
     "\xe2\x89\xa1",
     "\xc2\xb1",
     "\xe2\x89\xa5",
     "\xe2\x89\xa4",
     "\xe2\x8c\xa0",
     "\xe2\x8c\xa1",
     "\xc3\xb7",
     "\xe2\x89\x88",
     "\xc2\xb0",
     "\xe2\x88\x99",
     "\xc2\xb7",
     "\xe2\x88\x9a",
     "\xe2\x81\xbf",
     "\xc2\xb2",
     "\xe2\x96\xa0",
     "\xc2\xa0",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x04",
     0x00000005 => "\x05",
     0x00000006 => "\x06",
     0x00000007 => "\x07",
     0x00000008 => "\x08",
     0x00000009 => "\x09",
     0x0000000a => "\x0a",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x14",
     0x00000015 => "\x15",
     0x00000016 => "\x16",
     0x00000017 => "\x17",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x1a",
     0x0000001b => "\x1b",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x20",
     0x00000021 => "\x21",
     0x00000022 => "\x22",
     0x00000023 => "\x23",
     0x00000024 => "\x24",
     0x00000025 => "\x25",
     0x00000026 => "\x26",
     0x00000027 => "\x27",
     0x00000028 => "\x28",
     0x00000029 => "\x29",
     0x0000002a => "\x2a",
     0x0000002b => "\x2b",
     0x0000002c => "\x2c",
     0x0000002d => "\x2d",
     0x0000002e => "\x2e",
     0x0000002f => "\x2f",
     0x00000030 => "\x30",
     0x00000031 => "\x31",
     0x00000032 => "\x32",
     0x00000033 => "\x33",
     0x00000034 => "\x34",
     0x00000035 => "\x35",
     0x00000036 => "\x36",
     0x00000037 => "\x37",
     0x00000038 => "\x38",
     0x00000039 => "\x39",
     0x0000003a => "\x3a",
     0x0000003b => "\x3b",
     0x0000003c => "\x3c",
     0x0000003d => "\x3d",
     0x0000003e => "\x3e",
     0x0000003f => "\x3f",
     0x00000040 => "\x40",
     0x00000041 => "\x41",
     0x00000042 => "\x42",
     0x00000043 => "\x43",
     0x00000044 => "\x44",
     0x00000045 => "\x45",
     0x00000046 => "\x46",
     0x00000047 => "\x47",
     0x00000048 => "\x48",
     0x00000049 => "\x49",
     0x0000004a => "\x4a",
     0x0000004b => "\x4b",
     0x0000004c => "\x4c",
     0x0000004d => "\x4d",
     0x0000004e => "\x4e",
     0x0000004f => "\x4f",
     0x00000050 => "\x50",
     0x00000051 => "\x51",
     0x00000052 => "\x52",
     0x00000053 => "\x53",
     0x00000054 => "\x54",
     0x00000055 => "\x55",
     0x00000056 => "\x56",
     0x00000057 => "\x57",
     0x00000058 => "\x58",
     0x00000059 => "\x59",
     0x0000005a => "\x5a",
     0x0000005b => "\x5b",
     0x0000005c => "\x5c",
     0x0000005d => "\x5d",
     0x0000005e => "\x5e",
     0x0000005f => "\x5f",
     0x00000060 => "\x60",
     0x00000061 => "\x61",
     0x00000062 => "\x62",
     0x00000063 => "\x63",
     0x00000064 => "\x64",
     0x00000065 => "\x65",
     0x00000066 => "\x66",
     0x00000067 => "\x67",
     0x00000068 => "\x68",
     0x00000069 => "\x69",
     0x0000006a => "\x6a",
     0x0000006b => "\x6b",
     0x0000006c => "\x6c",
     0x0000006d => "\x6d",
     0x0000006e => "\x6e",
     0x0000006f => "\x6f",
     0x00000070 => "\x70",
     0x00000071 => "\x71",
     0x00000072 => "\x72",
     0x00000073 => "\x73",
     0x00000074 => "\x74",
     0x00000075 => "\x75",
     0x00000076 => "\x76",
     0x00000077 => "\x77",
     0x00000078 => "\x78",
     0x00000079 => "\x79",
     0x0000007a => "\x7a",
     0x0000007b => "\x7b",
     0x0000007c => "\x7c",
     0x0000007d => "\x7d",
     0x0000007e => "\x7e",
     0x0000007f => "\x7f",
     0x000000a0 => "\xff",
     0x000000a1 => "\xad",
     0x000000a3 => "\x9c",
     0x000000ab => "\xae",
     0x000000ac => "\xaa",
     0x000000b0 => "\xf8",
     0x000000b1 => "\xf1",
     0x000000b2 => "\xfd",
     0x000000b5 => "\xe6",
     0x000000b7 => "\xfa",
     0x000000bb => "\xaf",
     0x000000bc => "\xac",
     0x000000bd => "\xab",
     0x000000bf => "\xa8",
     0x000000c1 => "\xa4",
     0x000000c4 => "\x8e",
     0x000000c5 => "\x8f",
     0x000000c6 => "\x92",
     0x000000c7 => "\x80",
     0x000000c9 => "\x90",
     0x000000cd => "\xa5",
     0x000000d0 => "\x8b",
     0x000000d3 => "\xa6",
     0x000000d6 => "\x99",
     0x000000d8 => "\x9d",
     0x000000da => "\xa7",
     0x000000dc => "\x9a",
     0x000000dd => "\x97",
     0x000000de => "\x8d",
     0x000000df => "\xe1",
     0x000000e0 => "\x85",
     0x000000e1 => "\xa0",
     0x000000e2 => "\x83",
     0x000000e4 => "\x84",
     0x000000e5 => "\x86",
     0x000000e6 => "\x91",
     0x000000e7 => "\x87",
     0x000000e8 => "\x8a",
     0x000000e9 => "\x82",
     0x000000ea => "\x88",
     0x000000eb => "\x89",
     0x000000ed => "\xa1",
     0x000000f0 => "\x8c",
     0x000000f3 => "\xa2",
     0x000000f4 => "\x93",
     0x000000f6 => "\x94",
     0x000000f7 => "\xf6",
     0x000000f8 => "\x9b",
     0x000000fa => "\xa3",
     0x000000fb => "\x96",
     0x000000fc => "\x81",
     0x000000fd => "\x98",
     0x000000fe => "\x95",
     0x00000192 => "\x9f",
     0x00000393 => "\xe2",
     0x00000398 => "\xe9",
     0x000003a3 => "\xe4",
     0x000003a6 => "\xe8",
     0x000003a9 => "\xea",
     0x000003b1 => "\xe0",
     0x000003b4 => "\xeb",
     0x000003b5 => "\xee",
     0x000003c0 => "\xe3",
     0x000003c3 => "\xe5",
     0x000003c4 => "\xe7",
     0x000003c6 => "\xed",
     0x0000207f => "\xfc",
     0x000020a7 => "\x9e",
     0x00002219 => "\xf9",
     0x0000221a => "\xfb",
     0x0000221e => "\xec",
     0x00002229 => "\xef",
     0x00002248 => "\xf7",
     0x00002261 => "\xf0",
     0x00002264 => "\xf3",
     0x00002265 => "\xf2",
     0x00002310 => "\xa9",
     0x00002320 => "\xf4",
     0x00002321 => "\xf5",
     0x00002500 => "\xc4",
     0x00002502 => "\xb3",
     0x0000250c => "\xda",
     0x00002510 => "\xbf",
     0x00002514 => "\xc0",
     0x00002518 => "\xd9",
     0x0000251c => "\xc3",
     0x00002524 => "\xb4",
     0x0000252c => "\xc2",
     0x00002534 => "\xc1",
     0x0000253c => "\xc5",
     0x00002550 => "\xcd",
     0x00002551 => "\xba",
     0x00002552 => "\xd5",
     0x00002553 => "\xd6",
     0x00002554 => "\xc9",
     0x00002555 => "\xb8",
     0x00002556 => "\xb7",
     0x00002557 => "\xbb",
     0x00002558 => "\xd4",
     0x00002559 => "\xd3",
     0x0000255a => "\xc8",
     0x0000255b => "\xbe",
     0x0000255c => "\xbd",
     0x0000255d => "\xbc",
     0x0000255e => "\xc6",
     0x0000255f => "\xc7",
     0x00002560 => "\xcc",
     0x00002561 => "\xb5",
     0x00002562 => "\xb6",
     0x00002563 => "\xb9",
     0x00002564 => "\xd1",
     0x00002565 => "\xd2",
     0x00002566 => "\xcb",
     0x00002567 => "\xcf",
     0x00002568 => "\xd0",
     0x00002569 => "\xca",
     0x0000256a => "\xd8",
     0x0000256b => "\xd7",
     0x0000256c => "\xce",
     0x00002580 => "\xdf",
     0x00002584 => "\xdc",
     0x00002588 => "\xdb",
     0x0000258c => "\xdd",
     0x00002590 => "\xde",
     0x00002591 => "\xb0",
     0x00002592 => "\xb1",
     0x00002593 => "\xb2",
     0x000025a0 => "\xfe",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::IBM861 - Conversion routines for IBM861
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for IBM861.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
   source: IBM NLS RM Vol2 SE09-8002-01, March 1990
  alias CP861
  alias 861
  alias CP-IS
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  00000004 | END OF TRANSMISSION (EOT)
     05 |  00000005 | ENQUIRY (ENQ)
     06 |  00000006 | ACKNOWLEDGE (ACK)
     07 |  00000007 | BELL (BEL)
     08 |  00000008 | BACKSPACE (BS)
     09 |  00000009 | CHARACTER TABULATION (HT)
     0A |  0000000A | LINE FEED (LF)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  00000014 | DEVICE CONTROL FOUR (DC4)
     15 |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     16 |  00000016 | SYNCHRONOUS IDLE (SYN)
     17 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  0000001A | SUBSTITUTE (SUB)
     1B |  0000001B | ESCAPE (ESC)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000020 | SPACE
     21 |  00000021 | EXCLAMATION MARK
     22 |  00000022 | QUOTATION MARK
     23 |  00000023 | NUMBER SIGN
     24 |  00000024 | DOLLAR SIGN
     25 |  00000025 | PERCENT SIGN
     26 |  00000026 | AMPERSAND
     27 |  00000027 | APOSTROPHE
     28 |  00000028 | LEFT PARENTHESIS
     29 |  00000029 | RIGHT PARENTHESIS
     2A |  0000002A | ASTERISK
     2B |  0000002B | PLUS SIGN
     2C |  0000002C | COMMA
     2D |  0000002D | HYPHEN-MINUS
     2E |  0000002E | FULL STOP
     2F |  0000002F | SOLIDUS
     30 |  00000030 | DIGIT ZERO
     31 |  00000031 | DIGIT ONE
     32 |  00000032 | DIGIT TWO
     33 |  00000033 | DIGIT THREE
     34 |  00000034 | DIGIT FOUR
     35 |  00000035 | DIGIT FIVE
     36 |  00000036 | DIGIT SIX
     37 |  00000037 | DIGIT SEVEN
     38 |  00000038 | DIGIT EIGHT
     39 |  00000039 | DIGIT NINE
     3A |  0000003A | COLON
     3B |  0000003B | SEMICOLON
     3C |  0000003C | LESS-THAN SIGN
     3D |  0000003D | EQUALS SIGN
     3E |  0000003E | GREATER-THAN SIGN
     3F |  0000003F | QUESTION MARK
     40 |  00000040 | COMMERCIAL AT
     41 |  00000041 | LATIN CAPITAL LETTER A
     42 |  00000042 | LATIN CAPITAL LETTER B
     43 |  00000043 | LATIN CAPITAL LETTER C
     44 |  00000044 | LATIN CAPITAL LETTER D
     45 |  00000045 | LATIN CAPITAL LETTER E
     46 |  00000046 | LATIN CAPITAL LETTER F
     47 |  00000047 | LATIN CAPITAL LETTER G
     48 |  00000048 | LATIN CAPITAL LETTER H
     49 |  00000049 | LATIN CAPITAL LETTER I
     4A |  0000004A | LATIN CAPITAL LETTER J
     4B |  0000004B | LATIN CAPITAL LETTER K
     4C |  0000004C | LATIN CAPITAL LETTER L
     4D |  0000004D | LATIN CAPITAL LETTER M
     4E |  0000004E | LATIN CAPITAL LETTER N
     4F |  0000004F | LATIN CAPITAL LETTER O
     50 |  00000050 | LATIN CAPITAL LETTER P
     51 |  00000051 | LATIN CAPITAL LETTER Q
     52 |  00000052 | LATIN CAPITAL LETTER R
     53 |  00000053 | LATIN CAPITAL LETTER S
     54 |  00000054 | LATIN CAPITAL LETTER T
     55 |  00000055 | LATIN CAPITAL LETTER U
     56 |  00000056 | LATIN CAPITAL LETTER V
     57 |  00000057 | LATIN CAPITAL LETTER W
     58 |  00000058 | LATIN CAPITAL LETTER X
     59 |  00000059 | LATIN CAPITAL LETTER Y
     5A |  0000005A | LATIN CAPITAL LETTER Z
     5B |  0000005B | LEFT SQUARE BRACKET
     5C |  0000005C | REVERSE SOLIDUS
     5D |  0000005D | RIGHT SQUARE BRACKET
     5E |  0000005E | CIRCUMFLEX ACCENT
     5F |  0000005F | LOW LINE
     60 |  00000060 | GRAVE ACCENT
     61 |  00000061 | LATIN SMALL LETTER A
     62 |  00000062 | LATIN SMALL LETTER B
     63 |  00000063 | LATIN SMALL LETTER C
     64 |  00000064 | LATIN SMALL LETTER D
     65 |  00000065 | LATIN SMALL LETTER E
     66 |  00000066 | LATIN SMALL LETTER F
     67 |  00000067 | LATIN SMALL LETTER G
     68 |  00000068 | LATIN SMALL LETTER H
     69 |  00000069 | LATIN SMALL LETTER I
     6A |  0000006A | LATIN SMALL LETTER J
     6B |  0000006B | LATIN SMALL LETTER K
     6C |  0000006C | LATIN SMALL LETTER L
     6D |  0000006D | LATIN SMALL LETTER M
     6E |  0000006E | LATIN SMALL LETTER N
     6F |  0000006F | LATIN SMALL LETTER O
     70 |  00000070 | LATIN SMALL LETTER P
     71 |  00000071 | LATIN SMALL LETTER Q
     72 |  00000072 | LATIN SMALL LETTER R
     73 |  00000073 | LATIN SMALL LETTER S
     74 |  00000074 | LATIN SMALL LETTER T
     75 |  00000075 | LATIN SMALL LETTER U
     76 |  00000076 | LATIN SMALL LETTER V
     77 |  00000077 | LATIN SMALL LETTER W
     78 |  00000078 | LATIN SMALL LETTER X
     79 |  00000079 | LATIN SMALL LETTER Y
     7A |  0000007A | LATIN SMALL LETTER Z
     7B |  0000007B | LEFT CURLY BRACKET
     7C |  0000007C | VERTICAL LINE
     7D |  0000007D | RIGHT CURLY BRACKET
     7E |  0000007E | TILDE
     7F |  0000007F | DELETE (DEL)
     80 |  000000C7 | LATIN CAPITAL LETTER C WITH CEDILLA
     81 |  000000FC | LATIN SMALL LETTER U WITH DIAERESIS
     82 |  000000E9 | LATIN SMALL LETTER E WITH ACUTE
     83 |  000000E2 | LATIN SMALL LETTER A WITH CIRCUMFLEX
     84 |  000000E4 | LATIN SMALL LETTER A WITH DIAERESIS
     85 |  000000E0 | LATIN SMALL LETTER A WITH GRAVE
     86 |  000000E5 | LATIN SMALL LETTER A WITH RING ABOVE
     87 |  000000E7 | LATIN SMALL LETTER C WITH CEDILLA
     88 |  000000EA | LATIN SMALL LETTER E WITH CIRCUMFLEX
     89 |  000000EB | LATIN SMALL LETTER E WITH DIAERESIS
     8A |  000000E8 | LATIN SMALL LETTER E WITH GRAVE
     8B |  000000D0 | LATIN CAPITAL LETTER ETH (Icelandic)
     8C |  000000F0 | LATIN SMALL LETTER ETH (Icelandic)
     8D |  000000DE | LATIN CAPITAL LETTER THORN (Icelandic)
     8E |  000000C4 | LATIN CAPITAL LETTER A WITH DIAERESIS
     8F |  000000C5 | LATIN CAPITAL LETTER A WITH RING ABOVE
     90 |  000000C9 | LATIN CAPITAL LETTER E WITH ACUTE
     91 |  000000E6 | LATIN SMALL LETTER AE
     92 |  000000C6 | LATIN CAPITAL LETTER AE
     93 |  000000F4 | LATIN SMALL LETTER O WITH CIRCUMFLEX
     94 |  000000F6 | LATIN SMALL LETTER O WITH DIAERESIS
     95 |  000000FE | LATIN SMALL LETTER THORN (Icelandic)
     96 |  000000FB | LATIN SMALL LETTER U WITH CIRCUMFLEX
     97 |  000000DD | LATIN CAPITAL LETTER Y WITH ACUTE
     98 |  000000FD | LATIN SMALL LETTER Y WITH ACUTE
     99 |  000000D6 | LATIN CAPITAL LETTER O WITH DIAERESIS
     9A |  000000DC | LATIN CAPITAL LETTER U WITH DIAERESIS
     9B |  000000F8 | LATIN SMALL LETTER O WITH STROKE
     9C |  000000A3 | POUND SIGN
     9D |  000000D8 | LATIN CAPITAL LETTER O WITH STROKE
     9E |  000020A7 | PESETA SIGN
     9F |  00000192 | LATIN SMALL LETTER F WITH HOOK
     A0 |  000000E1 | LATIN SMALL LETTER A WITH ACUTE
     A1 |  000000ED | LATIN SMALL LETTER I WITH ACUTE
     A2 |  000000F3 | LATIN SMALL LETTER O WITH ACUTE
     A3 |  000000FA | LATIN SMALL LETTER U WITH ACUTE
     A4 |  000000C1 | LATIN CAPITAL LETTER A WITH ACUTE
     A5 |  000000CD | LATIN CAPITAL LETTER I WITH ACUTE
     A6 |  000000D3 | LATIN CAPITAL LETTER O WITH ACUTE
     A7 |  000000DA | LATIN CAPITAL LETTER U WITH ACUTE
     A8 |  000000BF | INVERTED QUESTION MARK
     A9 |  00002310 | REVERSED NOT SIGN
     AA |  000000AC | NOT SIGN
     AB |  000000BD | VULGAR FRACTION ONE HALF
     AC |  000000BC | VULGAR FRACTION ONE QUARTER
     AD |  000000A1 | INVERTED EXCLAMATION MARK
     AE |  000000AB | LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
     AF |  000000BB | RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
     B0 |  00002591 | LIGHT SHADE
     B1 |  00002592 | MEDIUM SHADE
     B2 |  00002593 | DARK SHADE
     B3 |  00002502 | BOX DRAWINGS LIGHT VERTICAL
     B4 |  00002524 | BOX DRAWINGS LIGHT VERTICAL AND LEFT
     B5 |  00002561 | BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE
     B6 |  00002562 | BOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLE
     B7 |  00002556 | BOX DRAWINGS DOWN DOUBLE AND LEFT SINGLE
     B8 |  00002555 | BOX DRAWINGS DOWN SINGLE AND LEFT DOUBLE
     B9 |  00002563 | BOX DRAWINGS DOUBLE VERTICAL AND LEFT
     BA |  00002551 | BOX DRAWINGS DOUBLE VERTICAL
     BB |  00002557 | BOX DRAWINGS DOUBLE DOWN AND LEFT
     BC |  0000255D | BOX DRAWINGS DOUBLE UP AND LEFT
     BD |  0000255C | BOX DRAWINGS UP DOUBLE AND LEFT SINGLE
     BE |  0000255B | BOX DRAWINGS UP SINGLE AND LEFT DOUBLE
     BF |  00002510 | BOX DRAWINGS LIGHT DOWN AND LEFT
     C0 |  00002514 | BOX DRAWINGS LIGHT UP AND RIGHT
     C1 |  00002534 | BOX DRAWINGS LIGHT UP AND HORIZONTAL
     C2 |  0000252C | BOX DRAWINGS LIGHT DOWN AND HORIZONTAL
     C3 |  0000251C | BOX DRAWINGS LIGHT VERTICAL AND RIGHT
     C4 |  00002500 | BOX DRAWINGS LIGHT HORIZONTAL
     C5 |  0000253C | BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL
     C6 |  0000255E | BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE
     C7 |  0000255F | BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE
     C8 |  0000255A | BOX DRAWINGS DOUBLE UP AND RIGHT
     C9 |  00002554 | BOX DRAWINGS DOUBLE DOWN AND RIGHT
     CA |  00002569 | BOX DRAWINGS DOUBLE UP AND HORIZONTAL
     CB |  00002566 | BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL
     CC |  00002560 | BOX DRAWINGS DOUBLE VERTICAL AND RIGHT
     CD |  00002550 | BOX DRAWINGS DOUBLE HORIZONTAL
     CE |  0000256C | BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL
     CF |  00002567 | BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE
     D0 |  00002568 | BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE
     D1 |  00002564 | BOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLE
     D2 |  00002565 | BOX DRAWINGS DOWN DOUBLE AND HORIZONTAL SINGLE
     D3 |  00002559 | BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE
     D4 |  00002558 | BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE
     D5 |  00002552 | BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE
     D6 |  00002553 | BOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLE
     D7 |  0000256B | BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLE
     D8 |  0000256A | BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE
     D9 |  00002518 | BOX DRAWINGS LIGHT UP AND LEFT
     DA |  0000250C | BOX DRAWINGS LIGHT DOWN AND RIGHT
     DB |  00002588 | FULL BLOCK
     DC |  00002584 | LOWER HALF BLOCK
     DD |  0000258C | LEFT HALF BLOCK
     DE |  00002590 | RIGHT HALF BLOCK
     DF |  00002580 | UPPER HALF BLOCK
     E0 |  000003B1 | GREEK SMALL LETTER ALPHA
     E1 |  000000DF | LATIN SMALL LETTER SHARP S (German)
     E2 |  00000393 | GREEK CAPITAL LETTER GAMMA
     E3 |  000003C0 | GREEK SMALL LETTER PI
     E4 |  000003A3 | GREEK CAPITAL LETTER SIGMA
     E5 |  000003C3 | GREEK SMALL LETTER SIGMA
     E6 |  000000B5 | MICRO SIGN
     E7 |  000003C4 | GREEK SMALL LETTER TAU
     E8 |  000003A6 | GREEK CAPITAL LETTER PHI
     E9 |  00000398 | GREEK CAPITAL LETTER THETA
     EA |  000003A9 | GREEK CAPITAL LETTER OMEGA
     EB |  000003B4 | GREEK SMALL LETTER DELTA
     EC |  0000221E | INFINITY
     ED |  000003C6 | GREEK SMALL LETTER PHI
     EE |  000003B5 | GREEK SMALL LETTER EPSILON
     EF |  00002229 | INTERSECTION
     F0 |  00002261 | IDENTICAL TO
     F1 |  000000B1 | PLUS-MINUS SIGN
     F2 |  00002265 | GREATER-THAN OR EQUAL TO
     F3 |  00002264 | LESS-THAN OR EQUAL TO
     F4 |  00002320 | TOP HALF INTEGRAL
     F5 |  00002321 | BOTTOM HALF INTEGRAL
     F6 |  000000F7 | DIVISION SIGN
     F7 |  00002248 | ALMOST EQUAL TO
     F8 |  000000B0 | DEGREE SIGN
     F9 |  00002219 | BULLET OPERATOR
     FA |  000000B7 | MIDDLE DOT
     FB |  0000221A | SQUARE ROOT
     FC |  0000207F | SUPERSCRIPT LATIN SMALL LETTER N
     FD |  000000B2 | SUPERSCRIPT TWO
     FE |  000025A0 | BLACK SQUARE
     FF |  000000A0 | NO-BREAK SPACE
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/IBM862.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for IBM862.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::IBM862;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x0004,
     0x0005,
     0x0006,
     0x0007,
     0x0008,
     0x0009,
     0x000a,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x0014,
     0x0015,
     0x0016,
     0x0017,
     0x0018,
     0x0019,
     0x001a,
     0x001b,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0020,
     0x0021,
     0x0022,
     0x0023,
     0x0024,
     0x0025,
     0x0026,
     0x0027,
     0x0028,
     0x0029,
     0x002a,
     0x002b,
     0x002c,
     0x002d,
     0x002e,
     0x002f,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x003a,
     0x003b,
     0x003c,
     0x003d,
     0x003e,
     0x003f,
     0x0040,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x005b,
     0x005c,
     0x005d,
     0x005e,
     0x005f,
     0x0060,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x007b,
     0x007c,
     0x007d,
     0x007e,
     0x007f,
     0x05d0,
     0x05d1,
     0x05d2,
     0x05d3,
     0x05d4,
     0x05d5,
     0x05d6,
     0x05d7,
     0x05d8,
     0x05d9,
     0x05da,
     0x05db,
     0x05dc,
     0x05dd,
     0x05de,
     0x05df,
     0x05e0,
     0x05e1,
     0x05e2,
     0x05e3,
     0x05e4,
     0x05e5,
     0x05e6,
     0x05e7,
     0x05e8,
     0x05e9,
     0x05ea,
     0x00a2,
     0x00a3,
     0x00a5,
     0x20a7,
     0x0192,
     0x00e1,
     0x00ed,
     0x00f3,
     0x00fa,
     0x00f1,
     0x00d1,
     0x00aa,
     0x00ba,
     0x00bf,
     0x2310,
     0x00ac,
     0x00bd,
     0x00bc,
     0x00a1,
     0x00ab,
     0x00bb,
     0x2591,
     0x2592,
     0x2593,
     0x2502,
     0x2524,
     0x2561,
     0x2562,
     0x2556,
     0x2555,
     0x2563,
     0x2551,
     0x2557,
     0x255d,
     0x255c,
     0x255b,
     0x2510,
     0x2514,
     0x2534,
     0x252c,
     0x251c,
     0x2500,
     0x253c,
     0x255e,
     0x255f,
     0x255a,
     0x2554,
     0x2569,
     0x2566,
     0x2560,
     0x2550,
     0x256c,
     0x2567,
     0x2568,
     0x2564,
     0x2565,
     0x2559,
     0x2558,
     0x2552,
     0x2553,
     0x256b,
     0x256a,
     0x2518,
     0x250c,
     0x2588,
     0x2584,
     0x258c,
     0x2590,
     0x2580,
     0x03b1,
     0x00df,
     0x0393,
     0x03c0,
     0x03a3,
     0x03c3,
     0x00b5,
     0x03c4,
     0x03a6,
     0x0398,
     0x03a9,
     0x03b4,
     0x221e,
     0x03c6,
     0x03b5,
     0x2229,
     0x2261,
     0x00b1,
     0x2265,
     0x2264,
     0x2320,
     0x2321,
     0x00f7,
     0x2248,
     0x00b0,
     0x2219,
     0x00b7,
     0x221a,
     0x207f,
     0x00b2,
     0x25a0,
     0x00a0,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\x04",
     "\x05",
     "\x06",
     "\x07",
     "\x08",
     "\x09",
     "\x0a",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\x14",
     "\x15",
     "\x16",
     "\x17",
     "\x18",
     "\x19",
     "\x1a",
     "\x1b",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\x20",
     "\x21",
     "\x22",
     "\x23",
     "\x24",
     "\x25",
     "\x26",
     "\x27",
     "\x28",
     "\x29",
     "\x2a",
     "\x2b",
     "\x2c",
     "\x2d",
     "\x2e",
     "\x2f",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\x3a",
     "\x3b",
     "\x3c",
     "\x3d",
     "\x3e",
     "\x3f",
     "\x40",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\x5b",
     "\x5c",
     "\x5d",
     "\x5e",
     "\x5f",
     "\x60",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\x7b",
     "\x7c",
     "\x7d",
     "\x7e",
     "\x7f",
     "\xd7\x90",
     "\xd7\x91",
     "\xd7\x92",
     "\xd7\x93",
     "\xd7\x94",
     "\xd7\x95",
     "\xd7\x96",
     "\xd7\x97",
     "\xd7\x98",
     "\xd7\x99",
     "\xd7\x9a",
     "\xd7\x9b",
     "\xd7\x9c",
     "\xd7\x9d",
     "\xd7\x9e",
     "\xd7\x9f",
     "\xd7\xa0",
     "\xd7\xa1",
     "\xd7\xa2",
     "\xd7\xa3",
     "\xd7\xa4",
     "\xd7\xa5",
     "\xd7\xa6",
     "\xd7\xa7",
     "\xd7\xa8",
     "\xd7\xa9",
     "\xd7\xaa",
     "\xc2\xa2",
     "\xc2\xa3",
     "\xc2\xa5",
     "\xe2\x82\xa7",
     "\xc6\x92",
     "\xc3\xa1",
     "\xc3\xad",
     "\xc3\xb3",
     "\xc3\xba",
     "\xc3\xb1",
     "\xc3\x91",
     "\xc2\xaa",
     "\xc2\xba",
     "\xc2\xbf",
     "\xe2\x8c\x90",
     "\xc2\xac",
     "\xc2\xbd",
     "\xc2\xbc",
     "\xc2\xa1",
     "\xc2\xab",
     "\xc2\xbb",
     "\xe2\x96\x91",
     "\xe2\x96\x92",
     "\xe2\x96\x93",
     "\xe2\x94\x82",
     "\xe2\x94\xa4",
     "\xe2\x95\xa1",
     "\xe2\x95\xa2",
     "\xe2\x95\x96",
     "\xe2\x95\x95",
     "\xe2\x95\xa3",
     "\xe2\x95\x91",
     "\xe2\x95\x97",
     "\xe2\x95\x9d",
     "\xe2\x95\x9c",
     "\xe2\x95\x9b",
     "\xe2\x94\x90",
     "\xe2\x94\x94",
     "\xe2\x94\xb4",
     "\xe2\x94\xac",
     "\xe2\x94\x9c",
     "\xe2\x94\x80",
     "\xe2\x94\xbc",
     "\xe2\x95\x9e",
     "\xe2\x95\x9f",
     "\xe2\x95\x9a",
     "\xe2\x95\x94",
     "\xe2\x95\xa9",
     "\xe2\x95\xa6",
     "\xe2\x95\xa0",
     "\xe2\x95\x90",
     "\xe2\x95\xac",
     "\xe2\x95\xa7",
     "\xe2\x95\xa8",
     "\xe2\x95\xa4",
     "\xe2\x95\xa5",
     "\xe2\x95\x99",
     "\xe2\x95\x98",
     "\xe2\x95\x92",
     "\xe2\x95\x93",
     "\xe2\x95\xab",
     "\xe2\x95\xaa",
     "\xe2\x94\x98",
     "\xe2\x94\x8c",
     "\xe2\x96\x88",
     "\xe2\x96\x84",
     "\xe2\x96\x8c",
     "\xe2\x96\x90",
     "\xe2\x96\x80",
     "\xce\xb1",
     "\xc3\x9f",
     "\xce\x93",
     "\xcf\x80",
     "\xce\xa3",
     "\xcf\x83",
     "\xc2\xb5",
     "\xcf\x84",
     "\xce\xa6",
     "\xce\x98",
     "\xce\xa9",
     "\xce\xb4",
     "\xe2\x88\x9e",
     "\xcf\x86",
     "\xce\xb5",
     "\xe2\x88\xa9",
     "\xe2\x89\xa1",
     "\xc2\xb1",
     "\xe2\x89\xa5",
     "\xe2\x89\xa4",
     "\xe2\x8c\xa0",
     "\xe2\x8c\xa1",
     "\xc3\xb7",
     "\xe2\x89\x88",
     "\xc2\xb0",
     "\xe2\x88\x99",
     "\xc2\xb7",
     "\xe2\x88\x9a",
     "\xe2\x81\xbf",
     "\xc2\xb2",
     "\xe2\x96\xa0",
     "\xc2\xa0",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x04",
     0x00000005 => "\x05",
     0x00000006 => "\x06",
     0x00000007 => "\x07",
     0x00000008 => "\x08",
     0x00000009 => "\x09",
     0x0000000a => "\x0a",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x14",
     0x00000015 => "\x15",
     0x00000016 => "\x16",
     0x00000017 => "\x17",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x1a",
     0x0000001b => "\x1b",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x20",
     0x00000021 => "\x21",
     0x00000022 => "\x22",
     0x00000023 => "\x23",
     0x00000024 => "\x24",
     0x00000025 => "\x25",
     0x00000026 => "\x26",
     0x00000027 => "\x27",
     0x00000028 => "\x28",
     0x00000029 => "\x29",
     0x0000002a => "\x2a",
     0x0000002b => "\x2b",
     0x0000002c => "\x2c",
     0x0000002d => "\x2d",
     0x0000002e => "\x2e",
     0x0000002f => "\x2f",
     0x00000030 => "\x30",
     0x00000031 => "\x31",
     0x00000032 => "\x32",
     0x00000033 => "\x33",
     0x00000034 => "\x34",
     0x00000035 => "\x35",
     0x00000036 => "\x36",
     0x00000037 => "\x37",
     0x00000038 => "\x38",
     0x00000039 => "\x39",
     0x0000003a => "\x3a",
     0x0000003b => "\x3b",
     0x0000003c => "\x3c",
     0x0000003d => "\x3d",
     0x0000003e => "\x3e",
     0x0000003f => "\x3f",
     0x00000040 => "\x40",
     0x00000041 => "\x41",
     0x00000042 => "\x42",
     0x00000043 => "\x43",
     0x00000044 => "\x44",
     0x00000045 => "\x45",
     0x00000046 => "\x46",
     0x00000047 => "\x47",
     0x00000048 => "\x48",
     0x00000049 => "\x49",
     0x0000004a => "\x4a",
     0x0000004b => "\x4b",
     0x0000004c => "\x4c",
     0x0000004d => "\x4d",
     0x0000004e => "\x4e",
     0x0000004f => "\x4f",
     0x00000050 => "\x50",
     0x00000051 => "\x51",
     0x00000052 => "\x52",
     0x00000053 => "\x53",
     0x00000054 => "\x54",
     0x00000055 => "\x55",
     0x00000056 => "\x56",
     0x00000057 => "\x57",
     0x00000058 => "\x58",
     0x00000059 => "\x59",
     0x0000005a => "\x5a",
     0x0000005b => "\x5b",
     0x0000005c => "\x5c",
     0x0000005d => "\x5d",
     0x0000005e => "\x5e",
     0x0000005f => "\x5f",
     0x00000060 => "\x60",
     0x00000061 => "\x61",
     0x00000062 => "\x62",
     0x00000063 => "\x63",
     0x00000064 => "\x64",
     0x00000065 => "\x65",
     0x00000066 => "\x66",
     0x00000067 => "\x67",
     0x00000068 => "\x68",
     0x00000069 => "\x69",
     0x0000006a => "\x6a",
     0x0000006b => "\x6b",
     0x0000006c => "\x6c",
     0x0000006d => "\x6d",
     0x0000006e => "\x6e",
     0x0000006f => "\x6f",
     0x00000070 => "\x70",
     0x00000071 => "\x71",
     0x00000072 => "\x72",
     0x00000073 => "\x73",
     0x00000074 => "\x74",
     0x00000075 => "\x75",
     0x00000076 => "\x76",
     0x00000077 => "\x77",
     0x00000078 => "\x78",
     0x00000079 => "\x79",
     0x0000007a => "\x7a",
     0x0000007b => "\x7b",
     0x0000007c => "\x7c",
     0x0000007d => "\x7d",
     0x0000007e => "\x7e",
     0x0000007f => "\x7f",
     0x000000a0 => "\xff",
     0x000000a1 => "\xad",
     0x000000a2 => "\x9b",
     0x000000a3 => "\x9c",
     0x000000a5 => "\x9d",
     0x000000aa => "\xa6",
     0x000000ab => "\xae",
     0x000000ac => "\xaa",
     0x000000b0 => "\xf8",
     0x000000b1 => "\xf1",
     0x000000b2 => "\xfd",
     0x000000b5 => "\xe6",
     0x000000b7 => "\xfa",
     0x000000ba => "\xa7",
     0x000000bb => "\xaf",
     0x000000bc => "\xac",
     0x000000bd => "\xab",
     0x000000bf => "\xa8",
     0x000000d1 => "\xa5",
     0x000000df => "\xe1",
     0x000000e1 => "\xa0",
     0x000000ed => "\xa1",
     0x000000f1 => "\xa4",
     0x000000f3 => "\xa2",
     0x000000f7 => "\xf6",
     0x000000fa => "\xa3",
     0x00000192 => "\x9f",
     0x00000393 => "\xe2",
     0x00000398 => "\xe9",
     0x000003a3 => "\xe4",
     0x000003a6 => "\xe8",
     0x000003a9 => "\xea",
     0x000003b1 => "\xe0",
     0x000003b4 => "\xeb",
     0x000003b5 => "\xee",
     0x000003c0 => "\xe3",
     0x000003c3 => "\xe5",
     0x000003c4 => "\xe7",
     0x000003c6 => "\xed",
     0x000005d0 => "\x80",
     0x000005d1 => "\x81",
     0x000005d2 => "\x82",
     0x000005d3 => "\x83",
     0x000005d4 => "\x84",
     0x000005d5 => "\x85",
     0x000005d6 => "\x86",
     0x000005d7 => "\x87",
     0x000005d8 => "\x88",
     0x000005d9 => "\x89",
     0x000005da => "\x8a",
     0x000005db => "\x8b",
     0x000005dc => "\x8c",
     0x000005dd => "\x8d",
     0x000005de => "\x8e",
     0x000005df => "\x8f",
     0x000005e0 => "\x90",
     0x000005e1 => "\x91",
     0x000005e2 => "\x92",
     0x000005e3 => "\x93",
     0x000005e4 => "\x94",
     0x000005e5 => "\x95",
     0x000005e6 => "\x96",
     0x000005e7 => "\x97",
     0x000005e8 => "\x98",
     0x000005e9 => "\x99",
     0x000005ea => "\x9a",
     0x0000207f => "\xfc",
     0x000020a7 => "\x9e",
     0x00002219 => "\xf9",
     0x0000221a => "\xfb",
     0x0000221e => "\xec",
     0x00002229 => "\xef",
     0x00002248 => "\xf7",
     0x00002261 => "\xf0",
     0x00002264 => "\xf3",
     0x00002265 => "\xf2",
     0x00002310 => "\xa9",
     0x00002320 => "\xf4",
     0x00002321 => "\xf5",
     0x00002500 => "\xc4",
     0x00002502 => "\xb3",
     0x0000250c => "\xda",
     0x00002510 => "\xbf",
     0x00002514 => "\xc0",
     0x00002518 => "\xd9",
     0x0000251c => "\xc3",
     0x00002524 => "\xb4",
     0x0000252c => "\xc2",
     0x00002534 => "\xc1",
     0x0000253c => "\xc5",
     0x00002550 => "\xcd",
     0x00002551 => "\xba",
     0x00002552 => "\xd5",
     0x00002553 => "\xd6",
     0x00002554 => "\xc9",
     0x00002555 => "\xb8",
     0x00002556 => "\xb7",
     0x00002557 => "\xbb",
     0x00002558 => "\xd4",
     0x00002559 => "\xd3",
     0x0000255a => "\xc8",
     0x0000255b => "\xbe",
     0x0000255c => "\xbd",
     0x0000255d => "\xbc",
     0x0000255e => "\xc6",
     0x0000255f => "\xc7",
     0x00002560 => "\xcc",
     0x00002561 => "\xb5",
     0x00002562 => "\xb6",
     0x00002563 => "\xb9",
     0x00002564 => "\xd1",
     0x00002565 => "\xd2",
     0x00002566 => "\xcb",
     0x00002567 => "\xcf",
     0x00002568 => "\xd0",
     0x00002569 => "\xca",
     0x0000256a => "\xd8",
     0x0000256b => "\xd7",
     0x0000256c => "\xce",
     0x00002580 => "\xdf",
     0x00002584 => "\xdc",
     0x00002588 => "\xdb",
     0x0000258c => "\xdd",
     0x00002590 => "\xde",
     0x00002591 => "\xb0",
     0x00002592 => "\xb1",
     0x00002593 => "\xb2",
     0x000025a0 => "\xfe",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::IBM862 - Conversion routines for IBM862
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for IBM862.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
   source: IBM NLS RM Vol2 SE09-8002-01, March 1990
  alias CP862
  alias 862
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  00000004 | END OF TRANSMISSION (EOT)
     05 |  00000005 | ENQUIRY (ENQ)
     06 |  00000006 | ACKNOWLEDGE (ACK)
     07 |  00000007 | BELL (BEL)
     08 |  00000008 | BACKSPACE (BS)
     09 |  00000009 | CHARACTER TABULATION (HT)
     0A |  0000000A | LINE FEED (LF)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  00000014 | DEVICE CONTROL FOUR (DC4)
     15 |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     16 |  00000016 | SYNCHRONOUS IDLE (SYN)
     17 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  0000001A | SUBSTITUTE (SUB)
     1B |  0000001B | ESCAPE (ESC)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000020 | SPACE
     21 |  00000021 | EXCLAMATION MARK
     22 |  00000022 | QUOTATION MARK
     23 |  00000023 | NUMBER SIGN
     24 |  00000024 | DOLLAR SIGN
     25 |  00000025 | PERCENT SIGN
     26 |  00000026 | AMPERSAND
     27 |  00000027 | APOSTROPHE
     28 |  00000028 | LEFT PARENTHESIS
     29 |  00000029 | RIGHT PARENTHESIS
     2A |  0000002A | ASTERISK
     2B |  0000002B | PLUS SIGN
     2C |  0000002C | COMMA
     2D |  0000002D | HYPHEN-MINUS
     2E |  0000002E | FULL STOP
     2F |  0000002F | SOLIDUS
     30 |  00000030 | DIGIT ZERO
     31 |  00000031 | DIGIT ONE
     32 |  00000032 | DIGIT TWO
     33 |  00000033 | DIGIT THREE
     34 |  00000034 | DIGIT FOUR
     35 |  00000035 | DIGIT FIVE
     36 |  00000036 | DIGIT SIX
     37 |  00000037 | DIGIT SEVEN
     38 |  00000038 | DIGIT EIGHT
     39 |  00000039 | DIGIT NINE
     3A |  0000003A | COLON
     3B |  0000003B | SEMICOLON
     3C |  0000003C | LESS-THAN SIGN
     3D |  0000003D | EQUALS SIGN
     3E |  0000003E | GREATER-THAN SIGN
     3F |  0000003F | QUESTION MARK
     40 |  00000040 | COMMERCIAL AT
     41 |  00000041 | LATIN CAPITAL LETTER A
     42 |  00000042 | LATIN CAPITAL LETTER B
     43 |  00000043 | LATIN CAPITAL LETTER C
     44 |  00000044 | LATIN CAPITAL LETTER D
     45 |  00000045 | LATIN CAPITAL LETTER E
     46 |  00000046 | LATIN CAPITAL LETTER F
     47 |  00000047 | LATIN CAPITAL LETTER G
     48 |  00000048 | LATIN CAPITAL LETTER H
     49 |  00000049 | LATIN CAPITAL LETTER I
     4A |  0000004A | LATIN CAPITAL LETTER J
     4B |  0000004B | LATIN CAPITAL LETTER K
     4C |  0000004C | LATIN CAPITAL LETTER L
     4D |  0000004D | LATIN CAPITAL LETTER M
     4E |  0000004E | LATIN CAPITAL LETTER N
     4F |  0000004F | LATIN CAPITAL LETTER O
     50 |  00000050 | LATIN CAPITAL LETTER P
     51 |  00000051 | LATIN CAPITAL LETTER Q
     52 |  00000052 | LATIN CAPITAL LETTER R
     53 |  00000053 | LATIN CAPITAL LETTER S
     54 |  00000054 | LATIN CAPITAL LETTER T
     55 |  00000055 | LATIN CAPITAL LETTER U
     56 |  00000056 | LATIN CAPITAL LETTER V
     57 |  00000057 | LATIN CAPITAL LETTER W
     58 |  00000058 | LATIN CAPITAL LETTER X
     59 |  00000059 | LATIN CAPITAL LETTER Y
     5A |  0000005A | LATIN CAPITAL LETTER Z
     5B |  0000005B | LEFT SQUARE BRACKET
     5C |  0000005C | REVERSE SOLIDUS
     5D |  0000005D | RIGHT SQUARE BRACKET
     5E |  0000005E | CIRCUMFLEX ACCENT
     5F |  0000005F | LOW LINE
     60 |  00000060 | GRAVE ACCENT
     61 |  00000061 | LATIN SMALL LETTER A
     62 |  00000062 | LATIN SMALL LETTER B
     63 |  00000063 | LATIN SMALL LETTER C
     64 |  00000064 | LATIN SMALL LETTER D
     65 |  00000065 | LATIN SMALL LETTER E
     66 |  00000066 | LATIN SMALL LETTER F
     67 |  00000067 | LATIN SMALL LETTER G
     68 |  00000068 | LATIN SMALL LETTER H
     69 |  00000069 | LATIN SMALL LETTER I
     6A |  0000006A | LATIN SMALL LETTER J
     6B |  0000006B | LATIN SMALL LETTER K
     6C |  0000006C | LATIN SMALL LETTER L
     6D |  0000006D | LATIN SMALL LETTER M
     6E |  0000006E | LATIN SMALL LETTER N
     6F |  0000006F | LATIN SMALL LETTER O
     70 |  00000070 | LATIN SMALL LETTER P
     71 |  00000071 | LATIN SMALL LETTER Q
     72 |  00000072 | LATIN SMALL LETTER R
     73 |  00000073 | LATIN SMALL LETTER S
     74 |  00000074 | LATIN SMALL LETTER T
     75 |  00000075 | LATIN SMALL LETTER U
     76 |  00000076 | LATIN SMALL LETTER V
     77 |  00000077 | LATIN SMALL LETTER W
     78 |  00000078 | LATIN SMALL LETTER X
     79 |  00000079 | LATIN SMALL LETTER Y
     7A |  0000007A | LATIN SMALL LETTER Z
     7B |  0000007B | LEFT CURLY BRACKET
     7C |  0000007C | VERTICAL LINE
     7D |  0000007D | RIGHT CURLY BRACKET
     7E |  0000007E | TILDE
     7F |  0000007F | DELETE (DEL)
     80 |  000005D0 | HEBREW LETTER ALEF
     81 |  000005D1 | HEBREW LETTER BET
     82 |  000005D2 | HEBREW LETTER GIMEL
     83 |  000005D3 | HEBREW LETTER DALET
     84 |  000005D4 | HEBREW LETTER HE
     85 |  000005D5 | HEBREW LETTER VAV
     86 |  000005D6 | HEBREW LETTER ZAYIN
     87 |  000005D7 | HEBREW LETTER HET
     88 |  000005D8 | HEBREW LETTER TET
     89 |  000005D9 | HEBREW LETTER YOD
     8A |  000005DA | HEBREW LETTER FINAL KAF
     8B |  000005DB | HEBREW LETTER KAF
     8C |  000005DC | HEBREW LETTER LAMED
     8D |  000005DD | HEBREW LETTER FINAL MEM
     8E |  000005DE | HEBREW LETTER MEM
     8F |  000005DF | HEBREW LETTER FINAL NUN
     90 |  000005E0 | HEBREW LETTER NUN
     91 |  000005E1 | HEBREW LETTER SAMEKH
     92 |  000005E2 | HEBREW LETTER AYIN
     93 |  000005E3 | HEBREW LETTER FINAL PE
     94 |  000005E4 | HEBREW LETTER PE
     95 |  000005E5 | HEBREW LETTER FINAL TSADI
     96 |  000005E6 | HEBREW LETTER TSADI
     97 |  000005E7 | HEBREW LETTER QOF
     98 |  000005E8 | HEBREW LETTER RESH
     99 |  000005E9 | HEBREW LETTER SHIN
     9A |  000005EA | HEBREW LETTER TAV
     9B |  000000A2 | CENT SIGN
     9C |  000000A3 | POUND SIGN
     9D |  000000A5 | YEN SIGN
     9E |  000020A7 | PESETA SIGN
     9F |  00000192 | LATIN SMALL LETTER F WITH HOOK
     A0 |  000000E1 | LATIN SMALL LETTER A WITH ACUTE
     A1 |  000000ED | LATIN SMALL LETTER I WITH ACUTE
     A2 |  000000F3 | LATIN SMALL LETTER O WITH ACUTE
     A3 |  000000FA | LATIN SMALL LETTER U WITH ACUTE
     A4 |  000000F1 | LATIN SMALL LETTER N WITH TILDE
     A5 |  000000D1 | LATIN CAPITAL LETTER N WITH TILDE
     A6 |  000000AA | FEMININE ORDINAL INDICATOR
     A7 |  000000BA | MASCULINE ORDINAL INDICATOR
     A8 |  000000BF | INVERTED QUESTION MARK
     A9 |  00002310 | REVERSED NOT SIGN
     AA |  000000AC | NOT SIGN
     AB |  000000BD | VULGAR FRACTION ONE HALF
     AC |  000000BC | VULGAR FRACTION ONE QUARTER
     AD |  000000A1 | INVERTED EXCLAMATION MARK
     AE |  000000AB | LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
     AF |  000000BB | RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
     B0 |  00002591 | LIGHT SHADE
     B1 |  00002592 | MEDIUM SHADE
     B2 |  00002593 | DARK SHADE
     B3 |  00002502 | BOX DRAWINGS LIGHT VERTICAL
     B4 |  00002524 | BOX DRAWINGS LIGHT VERTICAL AND LEFT
     B5 |  00002561 | BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE
     B6 |  00002562 | BOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLE
     B7 |  00002556 | BOX DRAWINGS DOWN DOUBLE AND LEFT SINGLE
     B8 |  00002555 | BOX DRAWINGS DOWN SINGLE AND LEFT DOUBLE
     B9 |  00002563 | BOX DRAWINGS DOUBLE VERTICAL AND LEFT
     BA |  00002551 | BOX DRAWINGS DOUBLE VERTICAL
     BB |  00002557 | BOX DRAWINGS DOUBLE DOWN AND LEFT
     BC |  0000255D | BOX DRAWINGS DOUBLE UP AND LEFT
     BD |  0000255C | BOX DRAWINGS UP DOUBLE AND LEFT SINGLE
     BE |  0000255B | BOX DRAWINGS UP SINGLE AND LEFT DOUBLE
     BF |  00002510 | BOX DRAWINGS LIGHT DOWN AND LEFT
     C0 |  00002514 | BOX DRAWINGS LIGHT UP AND RIGHT
     C1 |  00002534 | BOX DRAWINGS LIGHT UP AND HORIZONTAL
     C2 |  0000252C | BOX DRAWINGS LIGHT DOWN AND HORIZONTAL
     C3 |  0000251C | BOX DRAWINGS LIGHT VERTICAL AND RIGHT
     C4 |  00002500 | BOX DRAWINGS LIGHT HORIZONTAL
     C5 |  0000253C | BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL
     C6 |  0000255E | BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE
     C7 |  0000255F | BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE
     C8 |  0000255A | BOX DRAWINGS DOUBLE UP AND RIGHT
     C9 |  00002554 | BOX DRAWINGS DOUBLE DOWN AND RIGHT
     CA |  00002569 | BOX DRAWINGS DOUBLE UP AND HORIZONTAL
     CB |  00002566 | BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL
     CC |  00002560 | BOX DRAWINGS DOUBLE VERTICAL AND RIGHT
     CD |  00002550 | BOX DRAWINGS DOUBLE HORIZONTAL
     CE |  0000256C | BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL
     CF |  00002567 | BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE
     D0 |  00002568 | BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE
     D1 |  00002564 | BOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLE
     D2 |  00002565 | BOX DRAWINGS DOWN DOUBLE AND HORIZONTAL SINGLE
     D3 |  00002559 | BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE
     D4 |  00002558 | BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE
     D5 |  00002552 | BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE
     D6 |  00002553 | BOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLE
     D7 |  0000256B | BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLE
     D8 |  0000256A | BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE
     D9 |  00002518 | BOX DRAWINGS LIGHT UP AND LEFT
     DA |  0000250C | BOX DRAWINGS LIGHT DOWN AND RIGHT
     DB |  00002588 | FULL BLOCK
     DC |  00002584 | LOWER HALF BLOCK
     DD |  0000258C | LEFT HALF BLOCK
     DE |  00002590 | RIGHT HALF BLOCK
     DF |  00002580 | UPPER HALF BLOCK
     E0 |  000003B1 | GREEK SMALL LETTER ALPHA
     E1 |  000000DF | LATIN SMALL LETTER SHARP S (German)
     E2 |  00000393 | GREEK CAPITAL LETTER GAMMA
     E3 |  000003C0 | GREEK SMALL LETTER PI
     E4 |  000003A3 | GREEK CAPITAL LETTER SIGMA
     E5 |  000003C3 | GREEK SMALL LETTER SIGMA
     E6 |  000000B5 | MICRO SIGN
     E7 |  000003C4 | GREEK SMALL LETTER TAU
     E8 |  000003A6 | GREEK CAPITAL LETTER PHI
     E9 |  00000398 | GREEK CAPITAL LETTER THETA
     EA |  000003A9 | GREEK CAPITAL LETTER OMEGA
     EB |  000003B4 | GREEK SMALL LETTER DELTA
     EC |  0000221E | INFINITY
     ED |  000003C6 | GREEK SMALL LETTER PHI
     EE |  000003B5 | GREEK SMALL LETTER EPSILON
     EF |  00002229 | INTERSECTION
     F0 |  00002261 | IDENTICAL TO
     F1 |  000000B1 | PLUS-MINUS SIGN
     F2 |  00002265 | GREATER-THAN OR EQUAL TO
     F3 |  00002264 | LESS-THAN OR EQUAL TO
     F4 |  00002320 | TOP HALF INTEGRAL
     F5 |  00002321 | BOTTOM HALF INTEGRAL
     F6 |  000000F7 | DIVISION SIGN
     F7 |  00002248 | ALMOST EQUAL TO
     F8 |  000000B0 | DEGREE SIGN
     F9 |  00002219 | BULLET OPERATOR
     FA |  000000B7 | MIDDLE DOT
     FB |  0000221A | SQUARE ROOT
     FC |  0000207F | SUPERSCRIPT LATIN SMALL LETTER N
     FD |  000000B2 | SUPERSCRIPT TWO
     FE |  000025A0 | BLACK SQUARE
     FF |  000000A0 | NO-BREAK SPACE
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/IBM863.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for IBM863.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::IBM863;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x0004,
     0x0005,
     0x0006,
     0x0007,
     0x0008,
     0x0009,
     0x000a,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x0014,
     0x0015,
     0x0016,
     0x0017,
     0x0018,
     0x0019,
     0x001a,
     0x001b,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0020,
     0x0021,
     0x0022,
     0x0023,
     0x0024,
     0x0025,
     0x0026,
     0x0027,
     0x0028,
     0x0029,
     0x002a,
     0x002b,
     0x002c,
     0x002d,
     0x002e,
     0x002f,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x003a,
     0x003b,
     0x003c,
     0x003d,
     0x003e,
     0x003f,
     0x0040,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x005b,
     0x005c,
     0x005d,
     0x005e,
     0x005f,
     0x0060,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x007b,
     0x007c,
     0x007d,
     0x007e,
     0x007f,
     0x00c7,
     0x00fc,
     0x00e9,
     0x00e2,
     0x00c2,
     0x00e0,
     0x00b6,
     0x00e7,
     0x00ea,
     0x00eb,
     0x00e8,
     0x00ef,
     0x00ee,
     0x2017,
     0x00c0,
     0x00a7,
     0x00c9,
     0x00c8,
     0x00ca,
     0x00f4,
     0x00cb,
     0x00cf,
     0x00fb,
     0x00f9,
     0x00a4,
     0x00d4,
     0x00dc,
     0x00a2,
     0x00a3,
     0x00d9,
     0x00db,
     0x0192,
     0x00a6,
     0x00b4,
     0x00f3,
     0x00fa,
     0x00a8,
     0x00b8,
     0x00b3,
     0x00af,
     0x00ce,
     0x2310,
     0x00ac,
     0x00bd,
     0x00bc,
     0x00be,
     0x00ab,
     0x00bb,
     0x2591,
     0x2592,
     0x2593,
     0x2502,
     0x2524,
     0x2561,
     0x2562,
     0x2556,
     0x2555,
     0x2563,
     0x2551,
     0x2557,
     0x255d,
     0x255c,
     0x255b,
     0x2510,
     0x2514,
     0x2534,
     0x252c,
     0x251c,
     0x2500,
     0x253c,
     0x255e,
     0x255f,
     0x255a,
     0x2554,
     0x2569,
     0x2566,
     0x2560,
     0x2550,
     0x256c,
     0x2567,
     0x2568,
     0x2564,
     0x2565,
     0x2559,
     0x2558,
     0x2552,
     0x2553,
     0x256b,
     0x256a,
     0x2518,
     0x250c,
     0x2588,
     0x2584,
     0x258c,
     0x2590,
     0x2580,
     0x03b1,
     0x00df,
     0x0393,
     0x03c0,
     0x03a3,
     0x03c3,
     0x00b5,
     0x03c4,
     0x03a6,
     0x0398,
     0x03a9,
     0x03b4,
     0x221e,
     0x03c6,
     0x03b5,
     0x2229,
     0x2261,
     0x00b1,
     0x2265,
     0x2264,
     0x2320,
     0x2321,
     0x00f7,
     0x2248,
     0x00b0,
     0x2219,
     0x00b7,
     0x221a,
     0x207f,
     0x00b2,
     0x25a0,
     0x00a0,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\x04",
     "\x05",
     "\x06",
     "\x07",
     "\x08",
     "\x09",
     "\x0a",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\x14",
     "\x15",
     "\x16",
     "\x17",
     "\x18",
     "\x19",
     "\x1a",
     "\x1b",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\x20",
     "\x21",
     "\x22",
     "\x23",
     "\x24",
     "\x25",
     "\x26",
     "\x27",
     "\x28",
     "\x29",
     "\x2a",
     "\x2b",
     "\x2c",
     "\x2d",
     "\x2e",
     "\x2f",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\x3a",
     "\x3b",
     "\x3c",
     "\x3d",
     "\x3e",
     "\x3f",
     "\x40",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\x5b",
     "\x5c",
     "\x5d",
     "\x5e",
     "\x5f",
     "\x60",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\x7b",
     "\x7c",
     "\x7d",
     "\x7e",
     "\x7f",
     "\xc3\x87",
     "\xc3\xbc",
     "\xc3\xa9",
     "\xc3\xa2",
     "\xc3\x82",
     "\xc3\xa0",
     "\xc2\xb6",
     "\xc3\xa7",
     "\xc3\xaa",
     "\xc3\xab",
     "\xc3\xa8",
     "\xc3\xaf",
     "\xc3\xae",
     "\xe2\x80\x97",
     "\xc3\x80",
     "\xc2\xa7",
     "\xc3\x89",
     "\xc3\x88",
     "\xc3\x8a",
     "\xc3\xb4",
     "\xc3\x8b",
     "\xc3\x8f",
     "\xc3\xbb",
     "\xc3\xb9",
     "\xc2\xa4",
     "\xc3\x94",
     "\xc3\x9c",
     "\xc2\xa2",
     "\xc2\xa3",
     "\xc3\x99",
     "\xc3\x9b",
     "\xc6\x92",
     "\xc2\xa6",
     "\xc2\xb4",
     "\xc3\xb3",
     "\xc3\xba",
     "\xc2\xa8",
     "\xc2\xb8",
     "\xc2\xb3",
     "\xc2\xaf",
     "\xc3\x8e",
     "\xe2\x8c\x90",
     "\xc2\xac",
     "\xc2\xbd",
     "\xc2\xbc",
     "\xc2\xbe",
     "\xc2\xab",
     "\xc2\xbb",
     "\xe2\x96\x91",
     "\xe2\x96\x92",
     "\xe2\x96\x93",
     "\xe2\x94\x82",
     "\xe2\x94\xa4",
     "\xe2\x95\xa1",
     "\xe2\x95\xa2",
     "\xe2\x95\x96",
     "\xe2\x95\x95",
     "\xe2\x95\xa3",
     "\xe2\x95\x91",
     "\xe2\x95\x97",
     "\xe2\x95\x9d",
     "\xe2\x95\x9c",
     "\xe2\x95\x9b",
     "\xe2\x94\x90",
     "\xe2\x94\x94",
     "\xe2\x94\xb4",
     "\xe2\x94\xac",
     "\xe2\x94\x9c",
     "\xe2\x94\x80",
     "\xe2\x94\xbc",
     "\xe2\x95\x9e",
     "\xe2\x95\x9f",
     "\xe2\x95\x9a",
     "\xe2\x95\x94",
     "\xe2\x95\xa9",
     "\xe2\x95\xa6",
     "\xe2\x95\xa0",
     "\xe2\x95\x90",
     "\xe2\x95\xac",
     "\xe2\x95\xa7",
     "\xe2\x95\xa8",
     "\xe2\x95\xa4",
     "\xe2\x95\xa5",
     "\xe2\x95\x99",
     "\xe2\x95\x98",
     "\xe2\x95\x92",
     "\xe2\x95\x93",
     "\xe2\x95\xab",
     "\xe2\x95\xaa",
     "\xe2\x94\x98",
     "\xe2\x94\x8c",
     "\xe2\x96\x88",
     "\xe2\x96\x84",
     "\xe2\x96\x8c",
     "\xe2\x96\x90",
     "\xe2\x96\x80",
     "\xce\xb1",
     "\xc3\x9f",
     "\xce\x93",
     "\xcf\x80",
     "\xce\xa3",
     "\xcf\x83",
     "\xc2\xb5",
     "\xcf\x84",
     "\xce\xa6",
     "\xce\x98",
     "\xce\xa9",
     "\xce\xb4",
     "\xe2\x88\x9e",
     "\xcf\x86",
     "\xce\xb5",
     "\xe2\x88\xa9",
     "\xe2\x89\xa1",
     "\xc2\xb1",
     "\xe2\x89\xa5",
     "\xe2\x89\xa4",
     "\xe2\x8c\xa0",
     "\xe2\x8c\xa1",
     "\xc3\xb7",
     "\xe2\x89\x88",
     "\xc2\xb0",
     "\xe2\x88\x99",
     "\xc2\xb7",
     "\xe2\x88\x9a",
     "\xe2\x81\xbf",
     "\xc2\xb2",
     "\xe2\x96\xa0",
     "\xc2\xa0",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x04",
     0x00000005 => "\x05",
     0x00000006 => "\x06",
     0x00000007 => "\x07",
     0x00000008 => "\x08",
     0x00000009 => "\x09",
     0x0000000a => "\x0a",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x14",
     0x00000015 => "\x15",
     0x00000016 => "\x16",
     0x00000017 => "\x17",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x1a",
     0x0000001b => "\x1b",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x20",
     0x00000021 => "\x21",
     0x00000022 => "\x22",
     0x00000023 => "\x23",
     0x00000024 => "\x24",
     0x00000025 => "\x25",
     0x00000026 => "\x26",
     0x00000027 => "\x27",
     0x00000028 => "\x28",
     0x00000029 => "\x29",
     0x0000002a => "\x2a",
     0x0000002b => "\x2b",
     0x0000002c => "\x2c",
     0x0000002d => "\x2d",
     0x0000002e => "\x2e",
     0x0000002f => "\x2f",
     0x00000030 => "\x30",
     0x00000031 => "\x31",
     0x00000032 => "\x32",
     0x00000033 => "\x33",
     0x00000034 => "\x34",
     0x00000035 => "\x35",
     0x00000036 => "\x36",
     0x00000037 => "\x37",
     0x00000038 => "\x38",
     0x00000039 => "\x39",
     0x0000003a => "\x3a",
     0x0000003b => "\x3b",
     0x0000003c => "\x3c",
     0x0000003d => "\x3d",
     0x0000003e => "\x3e",
     0x0000003f => "\x3f",
     0x00000040 => "\x40",
     0x00000041 => "\x41",
     0x00000042 => "\x42",
     0x00000043 => "\x43",
     0x00000044 => "\x44",
     0x00000045 => "\x45",
     0x00000046 => "\x46",
     0x00000047 => "\x47",
     0x00000048 => "\x48",
     0x00000049 => "\x49",
     0x0000004a => "\x4a",
     0x0000004b => "\x4b",
     0x0000004c => "\x4c",
     0x0000004d => "\x4d",
     0x0000004e => "\x4e",
     0x0000004f => "\x4f",
     0x00000050 => "\x50",
     0x00000051 => "\x51",
     0x00000052 => "\x52",
     0x00000053 => "\x53",
     0x00000054 => "\x54",
     0x00000055 => "\x55",
     0x00000056 => "\x56",
     0x00000057 => "\x57",
     0x00000058 => "\x58",
     0x00000059 => "\x59",
     0x0000005a => "\x5a",
     0x0000005b => "\x5b",
     0x0000005c => "\x5c",
     0x0000005d => "\x5d",
     0x0000005e => "\x5e",
     0x0000005f => "\x5f",
     0x00000060 => "\x60",
     0x00000061 => "\x61",
     0x00000062 => "\x62",
     0x00000063 => "\x63",
     0x00000064 => "\x64",
     0x00000065 => "\x65",
     0x00000066 => "\x66",
     0x00000067 => "\x67",
     0x00000068 => "\x68",
     0x00000069 => "\x69",
     0x0000006a => "\x6a",
     0x0000006b => "\x6b",
     0x0000006c => "\x6c",
     0x0000006d => "\x6d",
     0x0000006e => "\x6e",
     0x0000006f => "\x6f",
     0x00000070 => "\x70",
     0x00000071 => "\x71",
     0x00000072 => "\x72",
     0x00000073 => "\x73",
     0x00000074 => "\x74",
     0x00000075 => "\x75",
     0x00000076 => "\x76",
     0x00000077 => "\x77",
     0x00000078 => "\x78",
     0x00000079 => "\x79",
     0x0000007a => "\x7a",
     0x0000007b => "\x7b",
     0x0000007c => "\x7c",
     0x0000007d => "\x7d",
     0x0000007e => "\x7e",
     0x0000007f => "\x7f",
     0x000000a0 => "\xff",
     0x000000a2 => "\x9b",
     0x000000a3 => "\x9c",
     0x000000a4 => "\x98",
     0x000000a6 => "\xa0",
     0x000000a7 => "\x8f",
     0x000000a8 => "\xa4",
     0x000000ab => "\xae",
     0x000000ac => "\xaa",
     0x000000af => "\xa7",
     0x000000b0 => "\xf8",
     0x000000b1 => "\xf1",
     0x000000b2 => "\xfd",
     0x000000b3 => "\xa6",
     0x000000b4 => "\xa1",
     0x000000b5 => "\xe6",
     0x000000b6 => "\x86",
     0x000000b7 => "\xfa",
     0x000000b8 => "\xa5",
     0x000000bb => "\xaf",
     0x000000bc => "\xac",
     0x000000bd => "\xab",
     0x000000be => "\xad",
     0x000000c0 => "\x8e",
     0x000000c2 => "\x84",
     0x000000c7 => "\x80",
     0x000000c8 => "\x91",
     0x000000c9 => "\x90",
     0x000000ca => "\x92",
     0x000000cb => "\x94",
     0x000000ce => "\xa8",
     0x000000cf => "\x95",
     0x000000d4 => "\x99",
     0x000000d9 => "\x9d",
     0x000000db => "\x9e",
     0x000000dc => "\x9a",
     0x000000df => "\xe1",
     0x000000e0 => "\x85",
     0x000000e2 => "\x83",
     0x000000e7 => "\x87",
     0x000000e8 => "\x8a",
     0x000000e9 => "\x82",
     0x000000ea => "\x88",
     0x000000eb => "\x89",
     0x000000ee => "\x8c",
     0x000000ef => "\x8b",
     0x000000f3 => "\xa2",
     0x000000f4 => "\x93",
     0x000000f7 => "\xf6",
     0x000000f9 => "\x97",
     0x000000fa => "\xa3",
     0x000000fb => "\x96",
     0x000000fc => "\x81",
     0x00000192 => "\x9f",
     0x00000393 => "\xe2",
     0x00000398 => "\xe9",
     0x000003a3 => "\xe4",
     0x000003a6 => "\xe8",
     0x000003a9 => "\xea",
     0x000003b1 => "\xe0",
     0x000003b4 => "\xeb",
     0x000003b5 => "\xee",
     0x000003c0 => "\xe3",
     0x000003c3 => "\xe5",
     0x000003c4 => "\xe7",
     0x000003c6 => "\xed",
     0x00002017 => "\x8d",
     0x0000207f => "\xfc",
     0x00002219 => "\xf9",
     0x0000221a => "\xfb",
     0x0000221e => "\xec",
     0x00002229 => "\xef",
     0x00002248 => "\xf7",
     0x00002261 => "\xf0",
     0x00002264 => "\xf3",
     0x00002265 => "\xf2",
     0x00002310 => "\xa9",
     0x00002320 => "\xf4",
     0x00002321 => "\xf5",
     0x00002500 => "\xc4",
     0x00002502 => "\xb3",
     0x0000250c => "\xda",
     0x00002510 => "\xbf",
     0x00002514 => "\xc0",
     0x00002518 => "\xd9",
     0x0000251c => "\xc3",
     0x00002524 => "\xb4",
     0x0000252c => "\xc2",
     0x00002534 => "\xc1",
     0x0000253c => "\xc5",
     0x00002550 => "\xcd",
     0x00002551 => "\xba",
     0x00002552 => "\xd5",
     0x00002553 => "\xd6",
     0x00002554 => "\xc9",
     0x00002555 => "\xb8",
     0x00002556 => "\xb7",
     0x00002557 => "\xbb",
     0x00002558 => "\xd4",
     0x00002559 => "\xd3",
     0x0000255a => "\xc8",
     0x0000255b => "\xbe",
     0x0000255c => "\xbd",
     0x0000255d => "\xbc",
     0x0000255e => "\xc6",
     0x0000255f => "\xc7",
     0x00002560 => "\xcc",
     0x00002561 => "\xb5",
     0x00002562 => "\xb6",
     0x00002563 => "\xb9",
     0x00002564 => "\xd1",
     0x00002565 => "\xd2",
     0x00002566 => "\xcb",
     0x00002567 => "\xcf",
     0x00002568 => "\xd0",
     0x00002569 => "\xca",
     0x0000256a => "\xd8",
     0x0000256b => "\xd7",
     0x0000256c => "\xce",
     0x00002580 => "\xdf",
     0x00002584 => "\xdc",
     0x00002588 => "\xdb",
     0x0000258c => "\xdd",
     0x00002590 => "\xde",
     0x00002591 => "\xb0",
     0x00002592 => "\xb1",
     0x00002593 => "\xb2",
     0x000025a0 => "\xfe",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::IBM863 - Conversion routines for IBM863
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for IBM863.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
   source: IBM Keyboard layouts and code pages, PN 07G4586 June 1991
  alias CP863
  alias 863
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  00000004 | END OF TRANSMISSION (EOT)
     05 |  00000005 | ENQUIRY (ENQ)
     06 |  00000006 | ACKNOWLEDGE (ACK)
     07 |  00000007 | BELL (BEL)
     08 |  00000008 | BACKSPACE (BS)
     09 |  00000009 | CHARACTER TABULATION (HT)
     0A |  0000000A | LINE FEED (LF)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  00000014 | DEVICE CONTROL FOUR (DC4)
     15 |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     16 |  00000016 | SYNCHRONOUS IDLE (SYN)
     17 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  0000001A | SUBSTITUTE (SUB)
     1B |  0000001B | ESCAPE (ESC)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000020 | SPACE
     21 |  00000021 | EXCLAMATION MARK
     22 |  00000022 | QUOTATION MARK
     23 |  00000023 | NUMBER SIGN
     24 |  00000024 | DOLLAR SIGN
     25 |  00000025 | PERCENT SIGN
     26 |  00000026 | AMPERSAND
     27 |  00000027 | APOSTROPHE
     28 |  00000028 | LEFT PARENTHESIS
     29 |  00000029 | RIGHT PARENTHESIS
     2A |  0000002A | ASTERISK
     2B |  0000002B | PLUS SIGN
     2C |  0000002C | COMMA
     2D |  0000002D | HYPHEN-MINUS
     2E |  0000002E | FULL STOP
     2F |  0000002F | SOLIDUS
     30 |  00000030 | DIGIT ZERO
     31 |  00000031 | DIGIT ONE
     32 |  00000032 | DIGIT TWO
     33 |  00000033 | DIGIT THREE
     34 |  00000034 | DIGIT FOUR
     35 |  00000035 | DIGIT FIVE
     36 |  00000036 | DIGIT SIX
     37 |  00000037 | DIGIT SEVEN
     38 |  00000038 | DIGIT EIGHT
     39 |  00000039 | DIGIT NINE
     3A |  0000003A | COLON
     3B |  0000003B | SEMICOLON
     3C |  0000003C | LESS-THAN SIGN
     3D |  0000003D | EQUALS SIGN
     3E |  0000003E | GREATER-THAN SIGN
     3F |  0000003F | QUESTION MARK
     40 |  00000040 | COMMERCIAL AT
     41 |  00000041 | LATIN CAPITAL LETTER A
     42 |  00000042 | LATIN CAPITAL LETTER B
     43 |  00000043 | LATIN CAPITAL LETTER C
     44 |  00000044 | LATIN CAPITAL LETTER D
     45 |  00000045 | LATIN CAPITAL LETTER E
     46 |  00000046 | LATIN CAPITAL LETTER F
     47 |  00000047 | LATIN CAPITAL LETTER G
     48 |  00000048 | LATIN CAPITAL LETTER H
     49 |  00000049 | LATIN CAPITAL LETTER I
     4A |  0000004A | LATIN CAPITAL LETTER J
     4B |  0000004B | LATIN CAPITAL LETTER K
     4C |  0000004C | LATIN CAPITAL LETTER L
     4D |  0000004D | LATIN CAPITAL LETTER M
     4E |  0000004E | LATIN CAPITAL LETTER N
     4F |  0000004F | LATIN CAPITAL LETTER O
     50 |  00000050 | LATIN CAPITAL LETTER P
     51 |  00000051 | LATIN CAPITAL LETTER Q
     52 |  00000052 | LATIN CAPITAL LETTER R
     53 |  00000053 | LATIN CAPITAL LETTER S
     54 |  00000054 | LATIN CAPITAL LETTER T
     55 |  00000055 | LATIN CAPITAL LETTER U
     56 |  00000056 | LATIN CAPITAL LETTER V
     57 |  00000057 | LATIN CAPITAL LETTER W
     58 |  00000058 | LATIN CAPITAL LETTER X
     59 |  00000059 | LATIN CAPITAL LETTER Y
     5A |  0000005A | LATIN CAPITAL LETTER Z
     5B |  0000005B | LEFT SQUARE BRACKET
     5C |  0000005C | REVERSE SOLIDUS
     5D |  0000005D | RIGHT SQUARE BRACKET
     5E |  0000005E | CIRCUMFLEX ACCENT
     5F |  0000005F | LOW LINE
     60 |  00000060 | GRAVE ACCENT
     61 |  00000061 | LATIN SMALL LETTER A
     62 |  00000062 | LATIN SMALL LETTER B
     63 |  00000063 | LATIN SMALL LETTER C
     64 |  00000064 | LATIN SMALL LETTER D
     65 |  00000065 | LATIN SMALL LETTER E
     66 |  00000066 | LATIN SMALL LETTER F
     67 |  00000067 | LATIN SMALL LETTER G
     68 |  00000068 | LATIN SMALL LETTER H
     69 |  00000069 | LATIN SMALL LETTER I
     6A |  0000006A | LATIN SMALL LETTER J
     6B |  0000006B | LATIN SMALL LETTER K
     6C |  0000006C | LATIN SMALL LETTER L
     6D |  0000006D | LATIN SMALL LETTER M
     6E |  0000006E | LATIN SMALL LETTER N
     6F |  0000006F | LATIN SMALL LETTER O
     70 |  00000070 | LATIN SMALL LETTER P
     71 |  00000071 | LATIN SMALL LETTER Q
     72 |  00000072 | LATIN SMALL LETTER R
     73 |  00000073 | LATIN SMALL LETTER S
     74 |  00000074 | LATIN SMALL LETTER T
     75 |  00000075 | LATIN SMALL LETTER U
     76 |  00000076 | LATIN SMALL LETTER V
     77 |  00000077 | LATIN SMALL LETTER W
     78 |  00000078 | LATIN SMALL LETTER X
     79 |  00000079 | LATIN SMALL LETTER Y
     7A |  0000007A | LATIN SMALL LETTER Z
     7B |  0000007B | LEFT CURLY BRACKET
     7C |  0000007C | VERTICAL LINE
     7D |  0000007D | RIGHT CURLY BRACKET
     7E |  0000007E | TILDE
     7F |  0000007F | DELETE (DEL)
     80 |  000000C7 | LATIN CAPITAL LETTER C WITH CEDILLA
     81 |  000000FC | LATIN SMALL LETTER U WITH DIAERESIS
     82 |  000000E9 | LATIN SMALL LETTER E WITH ACUTE
     83 |  000000E2 | LATIN SMALL LETTER A WITH CIRCUMFLEX
     84 |  000000C2 | LATIN CAPITAL LETTER A WITH CIRCUMFLEX
     85 |  000000E0 | LATIN SMALL LETTER A WITH GRAVE
     86 |  000000B6 | PILCROW SIGN
     87 |  000000E7 | LATIN SMALL LETTER C WITH CEDILLA
     88 |  000000EA | LATIN SMALL LETTER E WITH CIRCUMFLEX
     89 |  000000EB | LATIN SMALL LETTER E WITH DIAERESIS
     8A |  000000E8 | LATIN SMALL LETTER E WITH GRAVE
     8B |  000000EF | LATIN SMALL LETTER I WITH DIAERESIS
     8C |  000000EE | LATIN SMALL LETTER I WITH CIRCUMFLEX
     8D |  00002017 | DOUBLE LOW LINE
     8E |  000000C0 | LATIN CAPITAL LETTER A WITH GRAVE
     8F |  000000A7 | SECTION SIGN
     90 |  000000C9 | LATIN CAPITAL LETTER E WITH ACUTE
     91 |  000000C8 | LATIN CAPITAL LETTER E WITH GRAVE
     92 |  000000CA | LATIN CAPITAL LETTER E WITH CIRCUMFLEX
     93 |  000000F4 | LATIN SMALL LETTER O WITH CIRCUMFLEX
     94 |  000000CB | LATIN CAPITAL LETTER E WITH DIAERESIS
     95 |  000000CF | LATIN CAPITAL LETTER I WITH DIAERESIS
     96 |  000000FB | LATIN SMALL LETTER U WITH CIRCUMFLEX
     97 |  000000F9 | LATIN SMALL LETTER U WITH GRAVE
     98 |  000000A4 | CURRENCY SIGN
     99 |  000000D4 | LATIN CAPITAL LETTER O WITH CIRCUMFLEX
     9A |  000000DC | LATIN CAPITAL LETTER U WITH DIAERESIS
     9B |  000000A2 | CENT SIGN
     9C |  000000A3 | POUND SIGN
     9D |  000000D9 | LATIN CAPITAL LETTER U WITH GRAVE
     9E |  000000DB | LATIN CAPITAL LETTER U WITH CIRCUMFLEX
     9F |  00000192 | LATIN SMALL LETTER F WITH HOOK
     A0 |  000000A6 | BROKEN BAR
     A1 |  000000B4 | ACUTE ACCENT
     A2 |  000000F3 | LATIN SMALL LETTER O WITH ACUTE
     A3 |  000000FA | LATIN SMALL LETTER U WITH ACUTE
     A4 |  000000A8 | DIAERESIS
     A5 |  000000B8 | CEDILLA
     A6 |  000000B3 | SUPERSCRIPT THREE
     A7 |  000000AF | MACRON
     A8 |  000000CE | LATIN CAPITAL LETTER I WITH CIRCUMFLEX
     A9 |  00002310 | REVERSED NOT SIGN
     AA |  000000AC | NOT SIGN
     AB |  000000BD | VULGAR FRACTION ONE HALF
     AC |  000000BC | VULGAR FRACTION ONE QUARTER
     AD |  000000BE | VULGAR FRACTION THREE QUARTERS
     AE |  000000AB | LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
     AF |  000000BB | RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
     B0 |  00002591 | LIGHT SHADE
     B1 |  00002592 | MEDIUM SHADE
     B2 |  00002593 | DARK SHADE
     B3 |  00002502 | BOX DRAWINGS LIGHT VERTICAL
     B4 |  00002524 | BOX DRAWINGS LIGHT VERTICAL AND LEFT
     B5 |  00002561 | BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE
     B6 |  00002562 | BOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLE
     B7 |  00002556 | BOX DRAWINGS DOWN DOUBLE AND LEFT SINGLE
     B8 |  00002555 | BOX DRAWINGS DOWN SINGLE AND LEFT DOUBLE
     B9 |  00002563 | BOX DRAWINGS DOUBLE VERTICAL AND LEFT
     BA |  00002551 | BOX DRAWINGS DOUBLE VERTICAL
     BB |  00002557 | BOX DRAWINGS DOUBLE DOWN AND LEFT
     BC |  0000255D | BOX DRAWINGS DOUBLE UP AND LEFT
     BD |  0000255C | BOX DRAWINGS UP DOUBLE AND LEFT SINGLE
     BE |  0000255B | BOX DRAWINGS UP SINGLE AND LEFT DOUBLE
     BF |  00002510 | BOX DRAWINGS LIGHT DOWN AND LEFT
     C0 |  00002514 | BOX DRAWINGS LIGHT UP AND RIGHT
     C1 |  00002534 | BOX DRAWINGS LIGHT UP AND HORIZONTAL
     C2 |  0000252C | BOX DRAWINGS LIGHT DOWN AND HORIZONTAL
     C3 |  0000251C | BOX DRAWINGS LIGHT VERTICAL AND RIGHT
     C4 |  00002500 | BOX DRAWINGS LIGHT HORIZONTAL
     C5 |  0000253C | BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL
     C6 |  0000255E | BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE
     C7 |  0000255F | BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE
     C8 |  0000255A | BOX DRAWINGS DOUBLE UP AND RIGHT
     C9 |  00002554 | BOX DRAWINGS DOUBLE DOWN AND RIGHT
     CA |  00002569 | BOX DRAWINGS DOUBLE UP AND HORIZONTAL
     CB |  00002566 | BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL
     CC |  00002560 | BOX DRAWINGS DOUBLE VERTICAL AND RIGHT
     CD |  00002550 | BOX DRAWINGS DOUBLE HORIZONTAL
     CE |  0000256C | BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL
     CF |  00002567 | BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE
     D0 |  00002568 | BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE
     D1 |  00002564 | BOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLE
     D2 |  00002565 | BOX DRAWINGS DOWN DOUBLE AND HORIZONTAL SINGLE
     D3 |  00002559 | BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE
     D4 |  00002558 | BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE
     D5 |  00002552 | BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE
     D6 |  00002553 | BOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLE
     D7 |  0000256B | BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLE
     D8 |  0000256A | BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE
     D9 |  00002518 | BOX DRAWINGS LIGHT UP AND LEFT
     DA |  0000250C | BOX DRAWINGS LIGHT DOWN AND RIGHT
     DB |  00002588 | FULL BLOCK
     DC |  00002584 | LOWER HALF BLOCK
     DD |  0000258C | LEFT HALF BLOCK
     DE |  00002590 | RIGHT HALF BLOCK
     DF |  00002580 | UPPER HALF BLOCK
     E0 |  000003B1 | GREEK SMALL LETTER ALPHA
     E1 |  000000DF | LATIN SMALL LETTER SHARP S (German)
     E2 |  00000393 | GREEK CAPITAL LETTER GAMMA
     E3 |  000003C0 | GREEK SMALL LETTER PI
     E4 |  000003A3 | GREEK CAPITAL LETTER SIGMA
     E5 |  000003C3 | GREEK SMALL LETTER SIGMA
     E6 |  000000B5 | MICRO SIGN
     E7 |  000003C4 | GREEK SMALL LETTER TAU
     E8 |  000003A6 | GREEK CAPITAL LETTER PHI
     E9 |  00000398 | GREEK CAPITAL LETTER THETA
     EA |  000003A9 | GREEK CAPITAL LETTER OMEGA
     EB |  000003B4 | GREEK SMALL LETTER DELTA
     EC |  0000221E | INFINITY
     ED |  000003C6 | GREEK SMALL LETTER PHI
     EE |  000003B5 | GREEK SMALL LETTER EPSILON
     EF |  00002229 | INTERSECTION
     F0 |  00002261 | IDENTICAL TO
     F1 |  000000B1 | PLUS-MINUS SIGN
     F2 |  00002265 | GREATER-THAN OR EQUAL TO
     F3 |  00002264 | LESS-THAN OR EQUAL TO
     F4 |  00002320 | TOP HALF INTEGRAL
     F5 |  00002321 | BOTTOM HALF INTEGRAL
     F6 |  000000F7 | DIVISION SIGN
     F7 |  00002248 | ALMOST EQUAL TO
     F8 |  000000B0 | DEGREE SIGN
     F9 |  00002219 | BULLET OPERATOR
     FA |  000000B7 | MIDDLE DOT
     FB |  0000221A | SQUARE ROOT
     FC |  0000207F | SUPERSCRIPT LATIN SMALL LETTER N
     FD |  000000B2 | SUPERSCRIPT TWO
     FE |  000025A0 | BLACK SQUARE
     FF |  000000A0 | NO-BREAK SPACE
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/IBM864.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for IBM864.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::IBM864;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x0004,
     0x0005,
     0x0006,
     0x0007,
     0x0008,
     0x0009,
     0x000a,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x0014,
     0x0015,
     0x0016,
     0x0017,
     0x0018,
     0x0019,
     0x001a,
     0x001b,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0020,
     0x0021,
     0x0022,
     0x0023,
     0x0024,
     0x066a,
     0x0026,
     0x0027,
     0x0028,
     0x0029,
     0x002a,
     0x002b,
     0x002c,
     0x002d,
     0x002e,
     0x002f,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x003a,
     0x003b,
     0x003c,
     0x003d,
     0x003e,
     0x003f,
     0x0040,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x005b,
     0x005c,
     0x005d,
     0x005e,
     0x005f,
     0x0060,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x007b,
     0x007c,
     0x007d,
     0x007e,
     0x007f,
     0x00b0,
     0x00b7,
     0x2219,
     0x221a,
     0x2592,
     0x2500,
     0x2502,
     0x253c,
     0x2524,
     0x252c,
     0x251c,
     0x2534,
     0x2510,
     0x250c,
     0x2514,
     0x2518,
     0x03b2,
     0x221e,
     0x03c6,
     0x00b1,
     0x00bd,
     0x00bc,
     0x2248,
     0x00ab,
     0x00bb,
     0xfef7,
     0xfef8,
     0xfffd,
     0xfffd,
     0xfefb,
     0xfefc,
     0xfffd,
     0x00a0,
     0x00ad,
     0xfe82,
     0x00a3,
     0x00a4,
     0xfe84,
     0xfffd,
     0xfffd,
     0xfe8e,
     0xfe8f,
     0xfe95,
     0xfe99,
     0x060c,
     0xfe9d,
     0xfea1,
     0xfea5,
     0x0660,
     0x0661,
     0x0662,
     0x0663,
     0x0664,
     0x0665,
     0x0666,
     0x0667,
     0x0668,
     0x0669,
     0xfed1,
     0x061b,
     0xfeb1,
     0xfeb5,
     0xfeb9,
     0x061f,
     0x00a2,
     0xfe80,
     0xfe81,
     0xfe83,
     0xfe85,
     0xfeca,
     0xfe8b,
     0xfe8d,
     0xfe91,
     0xfe93,
     0xfe97,
     0xfe9b,
     0xfe9f,
     0xfea3,
     0xfea7,
     0xfea9,
     0xfeab,
     0xfead,
     0xfeaf,
     0xfeb3,
     0xfeb7,
     0xfebb,
     0xfebf,
     0xfec1,
     0xfec5,
     0xfecb,
     0xfecf,
     0x00a6,
     0x00ac,
     0x00f7,
     0x00d7,
     0xfec9,
     0x0640,
     0xfed3,
     0xfed7,
     0xfedb,
     0xfedf,
     0xfee3,
     0xfee7,
     0xfeeb,
     0xfeed,
     0xfeef,
     0xfef3,
     0xfebd,
     0xfecc,
     0xfece,
     0xfecd,
     0xfee1,
     0xfe7d,
     0x0651,
     0xfee5,
     0xfee9,
     0xfeec,
     0xfef0,
     0xfef2,
     0xfed0,
     0xfed5,
     0xfef5,
     0xfef6,
     0xfedd,
     0xfed9,
     0xfef1,
     0x25a0,
     0xfffd,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\x04",
     "\x05",
     "\x06",
     "\x07",
     "\x08",
     "\x09",
     "\x0a",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\x14",
     "\x15",
     "\x16",
     "\x17",
     "\x18",
     "\x19",
     "\x1a",
     "\x1b",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\x20",
     "\x21",
     "\x22",
     "\x23",
     "\x24",
     "\xd9\xaa",
     "\x26",
     "\x27",
     "\x28",
     "\x29",
     "\x2a",
     "\x2b",
     "\x2c",
     "\x2d",
     "\x2e",
     "\x2f",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\x3a",
     "\x3b",
     "\x3c",
     "\x3d",
     "\x3e",
     "\x3f",
     "\x40",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\x5b",
     "\x5c",
     "\x5d",
     "\x5e",
     "\x5f",
     "\x60",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\x7b",
     "\x7c",
     "\x7d",
     "\x7e",
     "\x7f",
     "\xc2\xb0",
     "\xc2\xb7",
     "\xe2\x88\x99",
     "\xe2\x88\x9a",
     "\xe2\x96\x92",
     "\xe2\x94\x80",
     "\xe2\x94\x82",
     "\xe2\x94\xbc",
     "\xe2\x94\xa4",
     "\xe2\x94\xac",
     "\xe2\x94\x9c",
     "\xe2\x94\xb4",
     "\xe2\x94\x90",
     "\xe2\x94\x8c",
     "\xe2\x94\x94",
     "\xe2\x94\x98",
     "\xce\xb2",
     "\xe2\x88\x9e",
     "\xcf\x86",
     "\xc2\xb1",
     "\xc2\xbd",
     "\xc2\xbc",
     "\xe2\x89\x88",
     "\xc2\xab",
     "\xc2\xbb",
     "\xef\xbb\xb7",
     "\xef\xbb\xb8",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbb\xbb",
     "\xef\xbb\xbc",
     "\xef\xbf\xbd",
     "\xc2\xa0",
     "\xc2\xad",
     "\xef\xba\x82",
     "\xc2\xa3",
     "\xc2\xa4",
     "\xef\xba\x84",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xba\x8e",
     "\xef\xba\x8f",
     "\xef\xba\x95",
     "\xef\xba\x99",
     "\xd8\x8c",
     "\xef\xba\x9d",
     "\xef\xba\xa1",
     "\xef\xba\xa5",
     "\xd9\xa0",
     "\xd9\xa1",
     "\xd9\xa2",
     "\xd9\xa3",
     "\xd9\xa4",
     "\xd9\xa5",
     "\xd9\xa6",
     "\xd9\xa7",
     "\xd9\xa8",
     "\xd9\xa9",
     "\xef\xbb\x91",
     "\xd8\x9b",
     "\xef\xba\xb1",
     "\xef\xba\xb5",
     "\xef\xba\xb9",
     "\xd8\x9f",
     "\xc2\xa2",
     "\xef\xba\x80",
     "\xef\xba\x81",
     "\xef\xba\x83",
     "\xef\xba\x85",
     "\xef\xbb\x8a",
     "\xef\xba\x8b",
     "\xef\xba\x8d",
     "\xef\xba\x91",
     "\xef\xba\x93",
     "\xef\xba\x97",
     "\xef\xba\x9b",
     "\xef\xba\x9f",
     "\xef\xba\xa3",
     "\xef\xba\xa7",
     "\xef\xba\xa9",
     "\xef\xba\xab",
     "\xef\xba\xad",
     "\xef\xba\xaf",
     "\xef\xba\xb3",
     "\xef\xba\xb7",
     "\xef\xba\xbb",
     "\xef\xba\xbf",
     "\xef\xbb\x81",
     "\xef\xbb\x85",
     "\xef\xbb\x8b",
     "\xef\xbb\x8f",
     "\xc2\xa6",
     "\xc2\xac",
     "\xc3\xb7",
     "\xc3\x97",
     "\xef\xbb\x89",
     "\xd9\x80",
     "\xef\xbb\x93",
     "\xef\xbb\x97",
     "\xef\xbb\x9b",
     "\xef\xbb\x9f",
     "\xef\xbb\xa3",
     "\xef\xbb\xa7",
     "\xef\xbb\xab",
     "\xef\xbb\xad",
     "\xef\xbb\xaf",
     "\xef\xbb\xb3",
     "\xef\xba\xbd",
     "\xef\xbb\x8c",
     "\xef\xbb\x8e",
     "\xef\xbb\x8d",
     "\xef\xbb\xa1",
     "\xef\xb9\xbd",
     "\xd9\x91",
     "\xef\xbb\xa5",
     "\xef\xbb\xa9",
     "\xef\xbb\xac",
     "\xef\xbb\xb0",
     "\xef\xbb\xb2",
     "\xef\xbb\x90",
     "\xef\xbb\x95",
     "\xef\xbb\xb5",
     "\xef\xbb\xb6",
     "\xef\xbb\x9d",
     "\xef\xbb\x99",
     "\xef\xbb\xb1",
     "\xe2\x96\xa0",
     "\xef\xbf\xbd",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x04",
     0x00000005 => "\x05",
     0x00000006 => "\x06",
     0x00000007 => "\x07",
     0x00000008 => "\x08",
     0x00000009 => "\x09",
     0x0000000a => "\x0a",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x14",
     0x00000015 => "\x15",
     0x00000016 => "\x16",
     0x00000017 => "\x17",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x1a",
     0x0000001b => "\x1b",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x20",
     0x00000021 => "\x21",
     0x00000022 => "\x22",
     0x00000023 => "\x23",
     0x00000024 => "\x24",
     0x00000026 => "\x26",
     0x00000027 => "\x27",
     0x00000028 => "\x28",
     0x00000029 => "\x29",
     0x0000002a => "\x2a",
     0x0000002b => "\x2b",
     0x0000002c => "\x2c",
     0x0000002d => "\x2d",
     0x0000002e => "\x2e",
     0x0000002f => "\x2f",
     0x00000030 => "\x30",
     0x00000031 => "\x31",
     0x00000032 => "\x32",
     0x00000033 => "\x33",
     0x00000034 => "\x34",
     0x00000035 => "\x35",
     0x00000036 => "\x36",
     0x00000037 => "\x37",
     0x00000038 => "\x38",
     0x00000039 => "\x39",
     0x0000003a => "\x3a",
     0x0000003b => "\x3b",
     0x0000003c => "\x3c",
     0x0000003d => "\x3d",
     0x0000003e => "\x3e",
     0x0000003f => "\x3f",
     0x00000040 => "\x40",
     0x00000041 => "\x41",
     0x00000042 => "\x42",
     0x00000043 => "\x43",
     0x00000044 => "\x44",
     0x00000045 => "\x45",
     0x00000046 => "\x46",
     0x00000047 => "\x47",
     0x00000048 => "\x48",
     0x00000049 => "\x49",
     0x0000004a => "\x4a",
     0x0000004b => "\x4b",
     0x0000004c => "\x4c",
     0x0000004d => "\x4d",
     0x0000004e => "\x4e",
     0x0000004f => "\x4f",
     0x00000050 => "\x50",
     0x00000051 => "\x51",
     0x00000052 => "\x52",
     0x00000053 => "\x53",
     0x00000054 => "\x54",
     0x00000055 => "\x55",
     0x00000056 => "\x56",
     0x00000057 => "\x57",
     0x00000058 => "\x58",
     0x00000059 => "\x59",
     0x0000005a => "\x5a",
     0x0000005b => "\x5b",
     0x0000005c => "\x5c",
     0x0000005d => "\x5d",
     0x0000005e => "\x5e",
     0x0000005f => "\x5f",
     0x00000060 => "\x60",
     0x00000061 => "\x61",
     0x00000062 => "\x62",
     0x00000063 => "\x63",
     0x00000064 => "\x64",
     0x00000065 => "\x65",
     0x00000066 => "\x66",
     0x00000067 => "\x67",
     0x00000068 => "\x68",
     0x00000069 => "\x69",
     0x0000006a => "\x6a",
     0x0000006b => "\x6b",
     0x0000006c => "\x6c",
     0x0000006d => "\x6d",
     0x0000006e => "\x6e",
     0x0000006f => "\x6f",
     0x00000070 => "\x70",
     0x00000071 => "\x71",
     0x00000072 => "\x72",
     0x00000073 => "\x73",
     0x00000074 => "\x74",
     0x00000075 => "\x75",
     0x00000076 => "\x76",
     0x00000077 => "\x77",
     0x00000078 => "\x78",
     0x00000079 => "\x79",
     0x0000007a => "\x7a",
     0x0000007b => "\x7b",
     0x0000007c => "\x7c",
     0x0000007d => "\x7d",
     0x0000007e => "\x7e",
     0x0000007f => "\x7f",
     0x000000a0 => "\xa0",
     0x000000a2 => "\xc0",
     0x000000a3 => "\xa3",
     0x000000a4 => "\xa4",
     0x000000a6 => "\xdb",
     0x000000ab => "\x97",
     0x000000ac => "\xdc",
     0x000000ad => "\xa1",
     0x000000b0 => "\x80",
     0x000000b1 => "\x93",
     0x000000b7 => "\x81",
     0x000000bb => "\x98",
     0x000000bc => "\x95",
     0x000000bd => "\x94",
     0x000000d7 => "\xde",
     0x000000f7 => "\xdd",
     0x000003b2 => "\x90",
     0x000003c6 => "\x92",
     0x0000060c => "\xac",
     0x0000061b => "\xbb",
     0x0000061f => "\xbf",
     0x00000640 => "\xe0",
     0x00000651 => "\xf1",
     0x00000660 => "\xb0",
     0x00000661 => "\xb1",
     0x00000662 => "\xb2",
     0x00000663 => "\xb3",
     0x00000664 => "\xb4",
     0x00000665 => "\xb5",
     0x00000666 => "\xb6",
     0x00000667 => "\xb7",
     0x00000668 => "\xb8",
     0x00000669 => "\xb9",
     0x0000066a => "\x25",
     0x00002219 => "\x82",
     0x0000221a => "\x83",
     0x0000221e => "\x91",
     0x00002248 => "\x96",
     0x00002500 => "\x85",
     0x00002502 => "\x86",
     0x0000250c => "\x8d",
     0x00002510 => "\x8c",
     0x00002514 => "\x8e",
     0x00002518 => "\x8f",
     0x0000251c => "\x8a",
     0x00002524 => "\x88",
     0x0000252c => "\x89",
     0x00002534 => "\x8b",
     0x0000253c => "\x87",
     0x00002592 => "\x84",
     0x000025a0 => "\xfe",
     0x0000fe7d => "\xf0",
     0x0000fe80 => "\xc1",
     0x0000fe81 => "\xc2",
     0x0000fe82 => "\xa2",
     0x0000fe83 => "\xc3",
     0x0000fe84 => "\xa5",
     0x0000fe85 => "\xc4",
     0x0000fe8b => "\xc6",
     0x0000fe8d => "\xc7",
     0x0000fe8e => "\xa8",
     0x0000fe8f => "\xa9",
     0x0000fe91 => "\xc8",
     0x0000fe93 => "\xc9",
     0x0000fe95 => "\xaa",
     0x0000fe97 => "\xca",
     0x0000fe99 => "\xab",
     0x0000fe9b => "\xcb",
     0x0000fe9d => "\xad",
     0x0000fe9f => "\xcc",
     0x0000fea1 => "\xae",
     0x0000fea3 => "\xcd",
     0x0000fea5 => "\xaf",
     0x0000fea7 => "\xce",
     0x0000fea9 => "\xcf",
     0x0000feab => "\xd0",
     0x0000fead => "\xd1",
     0x0000feaf => "\xd2",
     0x0000feb1 => "\xbc",
     0x0000feb3 => "\xd3",
     0x0000feb5 => "\xbd",
     0x0000feb7 => "\xd4",
     0x0000feb9 => "\xbe",
     0x0000febb => "\xd5",
     0x0000febd => "\xeb",
     0x0000febf => "\xd6",
     0x0000fec1 => "\xd7",
     0x0000fec5 => "\xd8",
     0x0000fec9 => "\xdf",
     0x0000feca => "\xc5",
     0x0000fecb => "\xd9",
     0x0000fecc => "\xec",
     0x0000fecd => "\xee",
     0x0000fece => "\xed",
     0x0000fecf => "\xda",
     0x0000fed0 => "\xf7",
     0x0000fed1 => "\xba",
     0x0000fed3 => "\xe1",
     0x0000fed5 => "\xf8",
     0x0000fed7 => "\xe2",
     0x0000fed9 => "\xfc",
     0x0000fedb => "\xe3",
     0x0000fedd => "\xfb",
     0x0000fedf => "\xe4",
     0x0000fee1 => "\xef",
     0x0000fee3 => "\xe5",
     0x0000fee5 => "\xf2",
     0x0000fee7 => "\xe6",
     0x0000fee9 => "\xf3",
     0x0000feeb => "\xe7",
     0x0000feec => "\xf4",
     0x0000feed => "\xe8",
     0x0000feef => "\xe9",
     0x0000fef0 => "\xf5",
     0x0000fef1 => "\xfd",
     0x0000fef2 => "\xf6",
     0x0000fef3 => "\xea",
     0x0000fef5 => "\xf9",
     0x0000fef6 => "\xfa",
     0x0000fef7 => "\x99",
     0x0000fef8 => "\x9a",
     0x0000fefb => "\x9d",
     0x0000fefc => "\x9e",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::IBM864 - Conversion routines for IBM864
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for IBM864.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  automatically generated from the charDB
  alias CP864
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL
     01 |  00000001 | START OF HEADING
     02 |  00000002 | START OF TEXT
     03 |  00000003 | END OF TEXT
     04 |  00000004 | END OF TRANSMISSION
     05 |  00000005 | ENQUIRY
     06 |  00000006 | ACKNOWLEDGE
     07 |  00000007 | BELL
     08 |  00000008 | BACKSPACE
     09 |  00000009 | HORIZONTAL TABULATION
     0A |  0000000A | LINE FEED
     0B |  0000000B | VERTICAL TABULATION
     0C |  0000000C | FORM FEED
     0D |  0000000D | CARRIAGE RETURN
     0E |  0000000E | SHIFT OUT
     0F |  0000000F | SHIFT IN
     10 |  00000010 | DATA LINK ESCAPE
     11 |  00000011 | DEVICE CONTROL ONE
     12 |  00000012 | DEVICE CONTROL TWO
     13 |  00000013 | DEVICE CONTROL THREE
     14 |  00000014 | DEVICE CONTROL FOUR
     15 |  00000015 | NEGATIVE ACKNOWLEDGE
     16 |  00000016 | SYNCHRONOUS IDLE
     17 |  00000017 | END OF TRANSMISSION BLOCK
     18 |  00000018 | CANCEL
     19 |  00000019 | END OF MEDIUM
     1A |  0000001A | SUBSTITUTE
     1B |  0000001B | ESCAPE
     1C |  0000001C | FILE SEPARATOR
     1D |  0000001D | GROUP SEPARATOR
     1E |  0000001E | RECORD SEPARATOR
     1F |  0000001F | UNIT SEPARATOR
     20 |  00000020 | SPACE
     21 |  00000021 | EXCLAMATION MARK
     22 |  00000022 | QUOTATION MARK
     23 |  00000023 | NUMBER SIGN
     24 |  00000024 | DOLLAR SIGN
     25 |  0000066A | ARABIC PERCENT SIGN
     26 |  00000026 | AMPERSAND
     27 |  00000027 | APOSTROPHE
     28 |  00000028 | LEFT PARENTHESIS
     29 |  00000029 | RIGHT PARENTHESIS
     2A |  0000002A | ASTERISK
     2B |  0000002B | PLUS SIGN
     2C |  0000002C | COMMA
     2D |  0000002D | HYPHEN-MINUS
     2E |  0000002E | FULL STOP
     2F |  0000002F | SOLIDUS
     30 |  00000030 | DIGIT ZERO
     31 |  00000031 | DIGIT ONE
     32 |  00000032 | DIGIT TWO
     33 |  00000033 | DIGIT THREE
     34 |  00000034 | DIGIT FOUR
     35 |  00000035 | DIGIT FIVE
     36 |  00000036 | DIGIT SIX
     37 |  00000037 | DIGIT SEVEN
     38 |  00000038 | DIGIT EIGHT
     39 |  00000039 | DIGIT NINE
     3A |  0000003A | COLON
     3B |  0000003B | SEMICOLON
     3C |  0000003C | LESS-THAN SIGN
     3D |  0000003D | EQUALS SIGN
     3E |  0000003E | GREATER-THAN SIGN
     3F |  0000003F | QUESTION MARK
     40 |  00000040 | COMMERCIAL AT
     41 |  00000041 | LATIN CAPITAL LETTER A
     42 |  00000042 | LATIN CAPITAL LETTER B
     43 |  00000043 | LATIN CAPITAL LETTER C
     44 |  00000044 | LATIN CAPITAL LETTER D
     45 |  00000045 | LATIN CAPITAL LETTER E
     46 |  00000046 | LATIN CAPITAL LETTER F
     47 |  00000047 | LATIN CAPITAL LETTER G
     48 |  00000048 | LATIN CAPITAL LETTER H
     49 |  00000049 | LATIN CAPITAL LETTER I
     4A |  0000004A | LATIN CAPITAL LETTER J
     4B |  0000004B | LATIN CAPITAL LETTER K
     4C |  0000004C | LATIN CAPITAL LETTER L
     4D |  0000004D | LATIN CAPITAL LETTER M
     4E |  0000004E | LATIN CAPITAL LETTER N
     4F |  0000004F | LATIN CAPITAL LETTER O
     50 |  00000050 | LATIN CAPITAL LETTER P
     51 |  00000051 | LATIN CAPITAL LETTER Q
     52 |  00000052 | LATIN CAPITAL LETTER R
     53 |  00000053 | LATIN CAPITAL LETTER S
     54 |  00000054 | LATIN CAPITAL LETTER T
     55 |  00000055 | LATIN CAPITAL LETTER U
     56 |  00000056 | LATIN CAPITAL LETTER V
     57 |  00000057 | LATIN CAPITAL LETTER W
     58 |  00000058 | LATIN CAPITAL LETTER X
     59 |  00000059 | LATIN CAPITAL LETTER Y
     5A |  0000005A | LATIN CAPITAL LETTER Z
     5B |  0000005B | LEFT SQUARE BRACKET
     5C |  0000005C | REVERSE SOLIDUS
     5D |  0000005D | RIGHT SQUARE BRACKET
     5E |  0000005E | CIRCUMFLEX ACCENT
     5F |  0000005F | LOW LINE
     60 |  00000060 | GRAVE ACCENT
     61 |  00000061 | LATIN SMALL LETTER A
     62 |  00000062 | LATIN SMALL LETTER B
     63 |  00000063 | LATIN SMALL LETTER C
     64 |  00000064 | LATIN SMALL LETTER D
     65 |  00000065 | LATIN SMALL LETTER E
     66 |  00000066 | LATIN SMALL LETTER F
     67 |  00000067 | LATIN SMALL LETTER G
     68 |  00000068 | LATIN SMALL LETTER H
     69 |  00000069 | LATIN SMALL LETTER I
     6A |  0000006A | LATIN SMALL LETTER J
     6B |  0000006B | LATIN SMALL LETTER K
     6C |  0000006C | LATIN SMALL LETTER L
     6D |  0000006D | LATIN SMALL LETTER M
     6E |  0000006E | LATIN SMALL LETTER N
     6F |  0000006F | LATIN SMALL LETTER O
     70 |  00000070 | LATIN SMALL LETTER P
     71 |  00000071 | LATIN SMALL LETTER Q
     72 |  00000072 | LATIN SMALL LETTER R
     73 |  00000073 | LATIN SMALL LETTER S
     74 |  00000074 | LATIN SMALL LETTER T
     75 |  00000075 | LATIN SMALL LETTER U
     76 |  00000076 | LATIN SMALL LETTER V
     77 |  00000077 | LATIN SMALL LETTER W
     78 |  00000078 | LATIN SMALL LETTER X
     79 |  00000079 | LATIN SMALL LETTER Y
     7A |  0000007A | LATIN SMALL LETTER Z
     7B |  0000007B | LEFT CURLY BRACKET
     7C |  0000007C | VERTICAL LINE
     7D |  0000007D | RIGHT CURLY BRACKET
     7E |  0000007E | TILDE
     7F |  0000007F | DELETE
     80 |  000000B0 | DEGREE SIGN
     81 |  000000B7 | MIDDLE DOT
     82 |  00002219 | BULLET OPERATOR
     83 |  0000221A | SQUARE ROOT
     84 |  00002592 | MEDIUM SHADE
     85 |  00002500 | BOX DRAWINGS LIGHT HORIZONTAL
     86 |  00002502 | BOX DRAWINGS LIGHT VERTICAL
     87 |  0000253C | BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL
     88 |  00002524 | BOX DRAWINGS LIGHT VERTICAL AND LEFT
     89 |  0000252C | BOX DRAWINGS LIGHT DOWN AND HORIZONTAL
     8A |  0000251C | BOX DRAWINGS LIGHT VERTICAL AND RIGHT
     8B |  00002534 | BOX DRAWINGS LIGHT UP AND HORIZONTAL
     8C |  00002510 | BOX DRAWINGS LIGHT DOWN AND LEFT
     8D |  0000250C | BOX DRAWINGS LIGHT DOWN AND RIGHT
     8E |  00002514 | BOX DRAWINGS LIGHT UP AND RIGHT
     8F |  00002518 | BOX DRAWINGS LIGHT UP AND LEFT
     90 |  000003B2 | GREEK SMALL LETTER BETA
     91 |  0000221E | INFINITY
     92 |  000003C6 | GREEK SMALL LETTER PHI
     93 |  000000B1 | PLUS-MINUS SIGN
     94 |  000000BD | VULGAR FRACTION ONE HALF
     95 |  000000BC | VULGAR FRACTION ONE QUARTER
     96 |  00002248 | ALMOST EQUAL TO
     97 |  000000AB | LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
     98 |  000000BB | RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
     99 |  0000FEF7 | ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE ISOLATED FORM
     9A |  0000FEF8 | ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE FINAL FORM
     9D |  0000FEFB | ARABIC LIGATURE LAM WITH ALEF ISOLATED FORM
     9E |  0000FEFC | ARABIC LIGATURE LAM WITH ALEF FINAL FORM
     A0 |  000000A0 | NO-BREAK SPACE
     A1 |  000000AD | SOFT HYPHEN
     A2 |  0000FE82 | ARABIC LETTER ALEF WITH MADDA ABOVE FINAL FORM
     A3 |  000000A3 | POUND SIGN
     A4 |  000000A4 | CURRENCY SIGN
     A5 |  0000FE84 | ARABIC LETTER ALEF WITH HAMZA ABOVE FINAL FORM
     A8 |  0000FE8E | ARABIC LETTER ALEF FINAL FORM
     A9 |  0000FE8F | ARABIC LETTER BEH ISOLATED FORM
     AA |  0000FE95 | ARABIC LETTER TEH ISOLATED FORM
     AB |  0000FE99 | ARABIC LETTER THEH ISOLATED FORM
     AC |  0000060C | ARABIC COMMA
     AD |  0000FE9D | ARABIC LETTER JEEM ISOLATED FORM
     AE |  0000FEA1 | ARABIC LETTER HAH ISOLATED FORM
     AF |  0000FEA5 | ARABIC LETTER KHAH ISOLATED FORM
     B0 |  00000660 | ARABIC-INDIC DIGIT ZERO
     B1 |  00000661 | ARABIC-INDIC DIGIT ONE
     B2 |  00000662 | ARABIC-INDIC DIGIT TWO
     B3 |  00000663 | ARABIC-INDIC DIGIT THREE
     B4 |  00000664 | ARABIC-INDIC DIGIT FOUR
     B5 |  00000665 | ARABIC-INDIC DIGIT FIVE
     B6 |  00000666 | ARABIC-INDIC DIGIT SIX
     B7 |  00000667 | ARABIC-INDIC DIGIT SEVEN
     B8 |  00000668 | ARABIC-INDIC DIGIT EIGHT
     B9 |  00000669 | ARABIC-INDIC DIGIT NINE
     BA |  0000FED1 | ARABIC LETTER FEH ISOLATED FORM
     BB |  0000061B | ARABIC SEMICOLON
     BC |  0000FEB1 | ARABIC LETTER SEEN ISOLATED FORM
     BD |  0000FEB5 | ARABIC LETTER SHEEN ISOLATED FORM
     BE |  0000FEB9 | ARABIC LETTER SAD ISOLATED FORM
     BF |  0000061F | ARABIC QUESTION MARK
     C0 |  000000A2 | CENT SIGN
     C1 |  0000FE80 | ARABIC LETTER HAMZA ISOLATED FORM
     C2 |  0000FE81 | ARABIC LETTER ALEF WITH MADDA ABOVE ISOLATED FORM
     C3 |  0000FE83 | ARABIC LETTER ALEF WITH HAMZA ABOVE ISOLATED FORM
     C4 |  0000FE85 | ARABIC LETTER WAW WITH HAMZA ABOVE ISOLATED FORM
     C5 |  0000FECA | ARABIC LETTER AIN FINAL FORM
     C6 |  0000FE8B | ARABIC LETTER YEH WITH HAMZA ABOVE INITIAL FORM
     C7 |  0000FE8D | ARABIC LETTER ALEF ISOLATED FORM
     C8 |  0000FE91 | ARABIC LETTER BEH INITIAL FORM
     C9 |  0000FE93 | ARABIC LETTER TEH MARBUTA ISOLATED FORM
     CA |  0000FE97 | ARABIC LETTER TEH INITIAL FORM
     CB |  0000FE9B | ARABIC LETTER THEH INITIAL FORM
     CC |  0000FE9F | ARABIC LETTER JEEM INITIAL FORM
     CD |  0000FEA3 | ARABIC LETTER HAH INITIAL FORM
     CE |  0000FEA7 | ARABIC LETTER KHAH INITIAL FORM
     CF |  0000FEA9 | ARABIC LETTER DAL ISOLATED FORM
     D0 |  0000FEAB | ARABIC LETTER THAL ISOLATED FORM
     D1 |  0000FEAD | ARABIC LETTER REH ISOLATED FORM
     D2 |  0000FEAF | ARABIC LETTER ZAIN ISOLATED FORM
     D3 |  0000FEB3 | ARABIC LETTER SEEN INITIAL FORM
     D4 |  0000FEB7 | ARABIC LETTER SHEEN INITIAL FORM
     D5 |  0000FEBB | ARABIC LETTER SAD INITIAL FORM
     D6 |  0000FEBF | ARABIC LETTER DAD INITIAL FORM
     D7 |  0000FEC1 | ARABIC LETTER TAH ISOLATED FORM
     D8 |  0000FEC5 | ARABIC LETTER ZAH ISOLATED FORM
     D9 |  0000FECB | ARABIC LETTER AIN INITIAL FORM
     DA |  0000FECF | ARABIC LETTER GHAIN INITIAL FORM
     DB |  000000A6 | BROKEN BAR
     DC |  000000AC | NOT SIGN
     DD |  000000F7 | DIVISION SIGN
     DE |  000000D7 | MULTIPLICATION SIGN
     DF |  0000FEC9 | ARABIC LETTER AIN ISOLATED FORM
     E0 |  00000640 | ARABIC TATWEEL
     E1 |  0000FED3 | ARABIC LETTER FEH INITIAL FORM
     E2 |  0000FED7 | ARABIC LETTER QAF INITIAL FORM
     E3 |  0000FEDB | ARABIC LETTER KAF INITIAL FORM
     E4 |  0000FEDF | ARABIC LETTER LAM INITIAL FORM
     E5 |  0000FEE3 | ARABIC LETTER MEEM INITIAL FORM
     E6 |  0000FEE7 | ARABIC LETTER NOON INITIAL FORM
     E7 |  0000FEEB | ARABIC LETTER HEH INITIAL FORM
     E8 |  0000FEED | ARABIC LETTER WAW ISOLATED FORM
     E9 |  0000FEEF | ARABIC LETTER ALEF MAKSURA ISOLATED FORM
     EA |  0000FEF3 | ARABIC LETTER YEH INITIAL FORM
     EB |  0000FEBD | ARABIC LETTER DAD ISOLATED FORM
     EC |  0000FECC | ARABIC LETTER AIN MEDIAL FORM
     ED |  0000FECE | ARABIC LETTER GHAIN FINAL FORM
     EE |  0000FECD | ARABIC LETTER GHAIN ISOLATED FORM
     EF |  0000FEE1 | ARABIC LETTER MEEM ISOLATED FORM
     F0 |  0000FE7D | ARABIC SHADDA MEDIAL FORM
     F1 |  00000651 | ARABIC SHADDA
     F2 |  0000FEE5 | ARABIC LETTER NOON ISOLATED FORM
     F3 |  0000FEE9 | ARABIC LETTER HEH ISOLATED FORM
     F4 |  0000FEEC | ARABIC LETTER HEH MEDIAL FORM
     F5 |  0000FEF0 | ARABIC LETTER ALEF MAKSURA FINAL FORM
     F6 |  0000FEF2 | ARABIC LETTER YEH FINAL FORM
     F7 |  0000FED0 | ARABIC LETTER GHAIN MEDIAL FORM
     F8 |  0000FED5 | ARABIC LETTER QAF ISOLATED FORM
     F9 |  0000FEF5 | ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE ISOLATED FORM
     FA |  0000FEF6 | ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE FINAL FORM
     FB |  0000FEDD | ARABIC LETTER LAM ISOLATED FORM
     FC |  0000FED9 | ARABIC LETTER KAF ISOLATED FORM
     FD |  0000FEF1 | ARABIC LETTER YEH ISOLATED FORM
     FE |  000025A0 | BLACK SQUARE
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/IBM865.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for IBM865.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::IBM865;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x0004,
     0x0005,
     0x0006,
     0x0007,
     0x0008,
     0x0009,
     0x000a,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x0014,
     0x0015,
     0x0016,
     0x0017,
     0x0018,
     0x0019,
     0x001a,
     0x001b,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0020,
     0x0021,
     0x0022,
     0x0023,
     0x0024,
     0x0025,
     0x0026,
     0x0027,
     0x0028,
     0x0029,
     0x002a,
     0x002b,
     0x002c,
     0x002d,
     0x002e,
     0x002f,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x003a,
     0x003b,
     0x003c,
     0x003d,
     0x003e,
     0x003f,
     0x0040,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x005b,
     0x005c,
     0x005d,
     0x005e,
     0x005f,
     0x0060,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x007b,
     0x007c,
     0x007d,
     0x007e,
     0x007f,
     0x00c7,
     0x00fc,
     0x00e9,
     0x00e2,
     0x00e4,
     0x00e0,
     0x00e5,
     0x00e7,
     0x00ea,
     0x00eb,
     0x00e8,
     0x00ef,
     0x00ee,
     0x00ec,
     0x00c4,
     0x00c5,
     0x00c9,
     0x00e6,
     0x00c6,
     0x00f4,
     0x00f6,
     0x00f2,
     0x00fb,
     0x00f9,
     0x00ff,
     0x00d6,
     0x00dc,
     0x00f8,
     0x00a3,
     0x00d8,
     0x20a7,
     0x0192,
     0x00e1,
     0x00ed,
     0x00f3,
     0x00fa,
     0x00f1,
     0x00d1,
     0x00aa,
     0x00ba,
     0x00bf,
     0x2310,
     0x00ac,
     0x00bd,
     0x00bc,
     0x00a1,
     0x00ab,
     0x00a4,
     0x2591,
     0x2592,
     0x2593,
     0x2502,
     0x2524,
     0x2561,
     0x2562,
     0x2556,
     0x2555,
     0x2563,
     0x2551,
     0x2557,
     0x255d,
     0x255c,
     0x255b,
     0x2510,
     0x2514,
     0x2534,
     0x252c,
     0x251c,
     0x2500,
     0x253c,
     0x255e,
     0x255f,
     0x255a,
     0x2554,
     0x2569,
     0x2566,
     0x2560,
     0x2550,
     0x256c,
     0x2567,
     0x2568,
     0x2564,
     0x2565,
     0x2559,
     0x2558,
     0x2552,
     0x2553,
     0x256b,
     0x256a,
     0x2518,
     0x250c,
     0x2588,
     0x2584,
     0x258c,
     0x2590,
     0x2580,
     0x03b1,
     0x00df,
     0x0393,
     0x03c0,
     0x03a3,
     0x03c3,
     0x00b5,
     0x03c4,
     0x03a6,
     0x0398,
     0x03a9,
     0x03b4,
     0x221e,
     0x03c6,
     0x03b5,
     0x2229,
     0x2261,
     0x00b1,
     0x2265,
     0x2264,
     0x2320,
     0x2321,
     0x00f7,
     0x2248,
     0x00b0,
     0x2219,
     0x00b7,
     0x221a,
     0x207f,
     0x00b2,
     0x25a0,
     0x00a0,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\x04",
     "\x05",
     "\x06",
     "\x07",
     "\x08",
     "\x09",
     "\x0a",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\x14",
     "\x15",
     "\x16",
     "\x17",
     "\x18",
     "\x19",
     "\x1a",
     "\x1b",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\x20",
     "\x21",
     "\x22",
     "\x23",
     "\x24",
     "\x25",
     "\x26",
     "\x27",
     "\x28",
     "\x29",
     "\x2a",
     "\x2b",
     "\x2c",
     "\x2d",
     "\x2e",
     "\x2f",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\x3a",
     "\x3b",
     "\x3c",
     "\x3d",
     "\x3e",
     "\x3f",
     "\x40",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\x5b",
     "\x5c",
     "\x5d",
     "\x5e",
     "\x5f",
     "\x60",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\x7b",
     "\x7c",
     "\x7d",
     "\x7e",
     "\x7f",
     "\xc3\x87",
     "\xc3\xbc",
     "\xc3\xa9",
     "\xc3\xa2",
     "\xc3\xa4",
     "\xc3\xa0",
     "\xc3\xa5",
     "\xc3\xa7",
     "\xc3\xaa",
     "\xc3\xab",
     "\xc3\xa8",
     "\xc3\xaf",
     "\xc3\xae",
     "\xc3\xac",
     "\xc3\x84",
     "\xc3\x85",
     "\xc3\x89",
     "\xc3\xa6",
     "\xc3\x86",
     "\xc3\xb4",
     "\xc3\xb6",
     "\xc3\xb2",
     "\xc3\xbb",
     "\xc3\xb9",
     "\xc3\xbf",
     "\xc3\x96",
     "\xc3\x9c",
     "\xc3\xb8",
     "\xc2\xa3",
     "\xc3\x98",
     "\xe2\x82\xa7",
     "\xc6\x92",
     "\xc3\xa1",
     "\xc3\xad",
     "\xc3\xb3",
     "\xc3\xba",
     "\xc3\xb1",
     "\xc3\x91",
     "\xc2\xaa",
     "\xc2\xba",
     "\xc2\xbf",
     "\xe2\x8c\x90",
     "\xc2\xac",
     "\xc2\xbd",
     "\xc2\xbc",
     "\xc2\xa1",
     "\xc2\xab",
     "\xc2\xa4",
     "\xe2\x96\x91",
     "\xe2\x96\x92",
     "\xe2\x96\x93",
     "\xe2\x94\x82",
     "\xe2\x94\xa4",
     "\xe2\x95\xa1",
     "\xe2\x95\xa2",
     "\xe2\x95\x96",
     "\xe2\x95\x95",
     "\xe2\x95\xa3",
     "\xe2\x95\x91",
     "\xe2\x95\x97",
     "\xe2\x95\x9d",
     "\xe2\x95\x9c",
     "\xe2\x95\x9b",
     "\xe2\x94\x90",
     "\xe2\x94\x94",
     "\xe2\x94\xb4",
     "\xe2\x94\xac",
     "\xe2\x94\x9c",
     "\xe2\x94\x80",
     "\xe2\x94\xbc",
     "\xe2\x95\x9e",
     "\xe2\x95\x9f",
     "\xe2\x95\x9a",
     "\xe2\x95\x94",
     "\xe2\x95\xa9",
     "\xe2\x95\xa6",
     "\xe2\x95\xa0",
     "\xe2\x95\x90",
     "\xe2\x95\xac",
     "\xe2\x95\xa7",
     "\xe2\x95\xa8",
     "\xe2\x95\xa4",
     "\xe2\x95\xa5",
     "\xe2\x95\x99",
     "\xe2\x95\x98",
     "\xe2\x95\x92",
     "\xe2\x95\x93",
     "\xe2\x95\xab",
     "\xe2\x95\xaa",
     "\xe2\x94\x98",
     "\xe2\x94\x8c",
     "\xe2\x96\x88",
     "\xe2\x96\x84",
     "\xe2\x96\x8c",
     "\xe2\x96\x90",
     "\xe2\x96\x80",
     "\xce\xb1",
     "\xc3\x9f",
     "\xce\x93",
     "\xcf\x80",
     "\xce\xa3",
     "\xcf\x83",
     "\xc2\xb5",
     "\xcf\x84",
     "\xce\xa6",
     "\xce\x98",
     "\xce\xa9",
     "\xce\xb4",
     "\xe2\x88\x9e",
     "\xcf\x86",
     "\xce\xb5",
     "\xe2\x88\xa9",
     "\xe2\x89\xa1",
     "\xc2\xb1",
     "\xe2\x89\xa5",
     "\xe2\x89\xa4",
     "\xe2\x8c\xa0",
     "\xe2\x8c\xa1",
     "\xc3\xb7",
     "\xe2\x89\x88",
     "\xc2\xb0",
     "\xe2\x88\x99",
     "\xc2\xb7",
     "\xe2\x88\x9a",
     "\xe2\x81\xbf",
     "\xc2\xb2",
     "\xe2\x96\xa0",
     "\xc2\xa0",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x04",
     0x00000005 => "\x05",
     0x00000006 => "\x06",
     0x00000007 => "\x07",
     0x00000008 => "\x08",
     0x00000009 => "\x09",
     0x0000000a => "\x0a",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x14",
     0x00000015 => "\x15",
     0x00000016 => "\x16",
     0x00000017 => "\x17",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x1a",
     0x0000001b => "\x1b",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x20",
     0x00000021 => "\x21",
     0x00000022 => "\x22",
     0x00000023 => "\x23",
     0x00000024 => "\x24",
     0x00000025 => "\x25",
     0x00000026 => "\x26",
     0x00000027 => "\x27",
     0x00000028 => "\x28",
     0x00000029 => "\x29",
     0x0000002a => "\x2a",
     0x0000002b => "\x2b",
     0x0000002c => "\x2c",
     0x0000002d => "\x2d",
     0x0000002e => "\x2e",
     0x0000002f => "\x2f",
     0x00000030 => "\x30",
     0x00000031 => "\x31",
     0x00000032 => "\x32",
     0x00000033 => "\x33",
     0x00000034 => "\x34",
     0x00000035 => "\x35",
     0x00000036 => "\x36",
     0x00000037 => "\x37",
     0x00000038 => "\x38",
     0x00000039 => "\x39",
     0x0000003a => "\x3a",
     0x0000003b => "\x3b",
     0x0000003c => "\x3c",
     0x0000003d => "\x3d",
     0x0000003e => "\x3e",
     0x0000003f => "\x3f",
     0x00000040 => "\x40",
     0x00000041 => "\x41",
     0x00000042 => "\x42",
     0x00000043 => "\x43",
     0x00000044 => "\x44",
     0x00000045 => "\x45",
     0x00000046 => "\x46",
     0x00000047 => "\x47",
     0x00000048 => "\x48",
     0x00000049 => "\x49",
     0x0000004a => "\x4a",
     0x0000004b => "\x4b",
     0x0000004c => "\x4c",
     0x0000004d => "\x4d",
     0x0000004e => "\x4e",
     0x0000004f => "\x4f",
     0x00000050 => "\x50",
     0x00000051 => "\x51",
     0x00000052 => "\x52",
     0x00000053 => "\x53",
     0x00000054 => "\x54",
     0x00000055 => "\x55",
     0x00000056 => "\x56",
     0x00000057 => "\x57",
     0x00000058 => "\x58",
     0x00000059 => "\x59",
     0x0000005a => "\x5a",
     0x0000005b => "\x5b",
     0x0000005c => "\x5c",
     0x0000005d => "\x5d",
     0x0000005e => "\x5e",
     0x0000005f => "\x5f",
     0x00000060 => "\x60",
     0x00000061 => "\x61",
     0x00000062 => "\x62",
     0x00000063 => "\x63",
     0x00000064 => "\x64",
     0x00000065 => "\x65",
     0x00000066 => "\x66",
     0x00000067 => "\x67",
     0x00000068 => "\x68",
     0x00000069 => "\x69",
     0x0000006a => "\x6a",
     0x0000006b => "\x6b",
     0x0000006c => "\x6c",
     0x0000006d => "\x6d",
     0x0000006e => "\x6e",
     0x0000006f => "\x6f",
     0x00000070 => "\x70",
     0x00000071 => "\x71",
     0x00000072 => "\x72",
     0x00000073 => "\x73",
     0x00000074 => "\x74",
     0x00000075 => "\x75",
     0x00000076 => "\x76",
     0x00000077 => "\x77",
     0x00000078 => "\x78",
     0x00000079 => "\x79",
     0x0000007a => "\x7a",
     0x0000007b => "\x7b",
     0x0000007c => "\x7c",
     0x0000007d => "\x7d",
     0x0000007e => "\x7e",
     0x0000007f => "\x7f",
     0x000000a0 => "\xff",
     0x000000a1 => "\xad",
     0x000000a3 => "\x9c",
     0x000000a4 => "\xaf",
     0x000000aa => "\xa6",
     0x000000ab => "\xae",
     0x000000ac => "\xaa",
     0x000000b0 => "\xf8",
     0x000000b1 => "\xf1",
     0x000000b2 => "\xfd",
     0x000000b5 => "\xe6",
     0x000000b7 => "\xfa",
     0x000000ba => "\xa7",
     0x000000bc => "\xac",
     0x000000bd => "\xab",
     0x000000bf => "\xa8",
     0x000000c4 => "\x8e",
     0x000000c5 => "\x8f",
     0x000000c6 => "\x92",
     0x000000c7 => "\x80",
     0x000000c9 => "\x90",
     0x000000d1 => "\xa5",
     0x000000d6 => "\x99",
     0x000000d8 => "\x9d",
     0x000000dc => "\x9a",
     0x000000df => "\xe1",
     0x000000e0 => "\x85",
     0x000000e1 => "\xa0",
     0x000000e2 => "\x83",
     0x000000e4 => "\x84",
     0x000000e5 => "\x86",
     0x000000e6 => "\x91",
     0x000000e7 => "\x87",
     0x000000e8 => "\x8a",
     0x000000e9 => "\x82",
     0x000000ea => "\x88",
     0x000000eb => "\x89",
     0x000000ec => "\x8d",
     0x000000ed => "\xa1",
     0x000000ee => "\x8c",
     0x000000ef => "\x8b",
     0x000000f1 => "\xa4",
     0x000000f2 => "\x95",
     0x000000f3 => "\xa2",
     0x000000f4 => "\x93",
     0x000000f6 => "\x94",
     0x000000f7 => "\xf6",
     0x000000f8 => "\x9b",
     0x000000f9 => "\x97",
     0x000000fa => "\xa3",
     0x000000fb => "\x96",
     0x000000fc => "\x81",
     0x000000ff => "\x98",
     0x00000192 => "\x9f",
     0x00000393 => "\xe2",
     0x00000398 => "\xe9",
     0x000003a3 => "\xe4",
     0x000003a6 => "\xe8",
     0x000003a9 => "\xea",
     0x000003b1 => "\xe0",
     0x000003b4 => "\xeb",
     0x000003b5 => "\xee",
     0x000003c0 => "\xe3",
     0x000003c3 => "\xe5",
     0x000003c4 => "\xe7",
     0x000003c6 => "\xed",
     0x0000207f => "\xfc",
     0x000020a7 => "\x9e",
     0x00002219 => "\xf9",
     0x0000221a => "\xfb",
     0x0000221e => "\xec",
     0x00002229 => "\xef",
     0x00002248 => "\xf7",
     0x00002261 => "\xf0",
     0x00002264 => "\xf3",
     0x00002265 => "\xf2",
     0x00002310 => "\xa9",
     0x00002320 => "\xf4",
     0x00002321 => "\xf5",
     0x00002500 => "\xc4",
     0x00002502 => "\xb3",
     0x0000250c => "\xda",
     0x00002510 => "\xbf",
     0x00002514 => "\xc0",
     0x00002518 => "\xd9",
     0x0000251c => "\xc3",
     0x00002524 => "\xb4",
     0x0000252c => "\xc2",
     0x00002534 => "\xc1",
     0x0000253c => "\xc5",
     0x00002550 => "\xcd",
     0x00002551 => "\xba",
     0x00002552 => "\xd5",
     0x00002553 => "\xd6",
     0x00002554 => "\xc9",
     0x00002555 => "\xb8",
     0x00002556 => "\xb7",
     0x00002557 => "\xbb",
     0x00002558 => "\xd4",
     0x00002559 => "\xd3",
     0x0000255a => "\xc8",
     0x0000255b => "\xbe",
     0x0000255c => "\xbd",
     0x0000255d => "\xbc",
     0x0000255e => "\xc6",
     0x0000255f => "\xc7",
     0x00002560 => "\xcc",
     0x00002561 => "\xb5",
     0x00002562 => "\xb6",
     0x00002563 => "\xb9",
     0x00002564 => "\xd1",
     0x00002565 => "\xd2",
     0x00002566 => "\xcb",
     0x00002567 => "\xcf",
     0x00002568 => "\xd0",
     0x00002569 => "\xca",
     0x0000256a => "\xd8",
     0x0000256b => "\xd7",
     0x0000256c => "\xce",
     0x00002580 => "\xdf",
     0x00002584 => "\xdc",
     0x00002588 => "\xdb",
     0x0000258c => "\xdd",
     0x00002590 => "\xde",
     0x00002591 => "\xb0",
     0x00002592 => "\xb1",
     0x00002593 => "\xb2",
     0x000025a0 => "\xfe",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::IBM865 - Conversion routines for IBM865
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for IBM865.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
   source: IBM DOS 3.3 Ref (Abridged), 94X9575 (Feb 1987)
  alias CP865
  alias 865
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  00000004 | END OF TRANSMISSION (EOT)
     05 |  00000005 | ENQUIRY (ENQ)
     06 |  00000006 | ACKNOWLEDGE (ACK)
     07 |  00000007 | BELL (BEL)
     08 |  00000008 | BACKSPACE (BS)
     09 |  00000009 | CHARACTER TABULATION (HT)
     0A |  0000000A | LINE FEED (LF)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  00000014 | DEVICE CONTROL FOUR (DC4)
     15 |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     16 |  00000016 | SYNCHRONOUS IDLE (SYN)
     17 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  0000001A | SUBSTITUTE (SUB)
     1B |  0000001B | ESCAPE (ESC)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000020 | SPACE
     21 |  00000021 | EXCLAMATION MARK
     22 |  00000022 | QUOTATION MARK
     23 |  00000023 | NUMBER SIGN
     24 |  00000024 | DOLLAR SIGN
     25 |  00000025 | PERCENT SIGN
     26 |  00000026 | AMPERSAND
     27 |  00000027 | APOSTROPHE
     28 |  00000028 | LEFT PARENTHESIS
     29 |  00000029 | RIGHT PARENTHESIS
     2A |  0000002A | ASTERISK
     2B |  0000002B | PLUS SIGN
     2C |  0000002C | COMMA
     2D |  0000002D | HYPHEN-MINUS
     2E |  0000002E | FULL STOP
     2F |  0000002F | SOLIDUS
     30 |  00000030 | DIGIT ZERO
     31 |  00000031 | DIGIT ONE
     32 |  00000032 | DIGIT TWO
     33 |  00000033 | DIGIT THREE
     34 |  00000034 | DIGIT FOUR
     35 |  00000035 | DIGIT FIVE
     36 |  00000036 | DIGIT SIX
     37 |  00000037 | DIGIT SEVEN
     38 |  00000038 | DIGIT EIGHT
     39 |  00000039 | DIGIT NINE
     3A |  0000003A | COLON
     3B |  0000003B | SEMICOLON
     3C |  0000003C | LESS-THAN SIGN
     3D |  0000003D | EQUALS SIGN
     3E |  0000003E | GREATER-THAN SIGN
     3F |  0000003F | QUESTION MARK
     40 |  00000040 | COMMERCIAL AT
     41 |  00000041 | LATIN CAPITAL LETTER A
     42 |  00000042 | LATIN CAPITAL LETTER B
     43 |  00000043 | LATIN CAPITAL LETTER C
     44 |  00000044 | LATIN CAPITAL LETTER D
     45 |  00000045 | LATIN CAPITAL LETTER E
     46 |  00000046 | LATIN CAPITAL LETTER F
     47 |  00000047 | LATIN CAPITAL LETTER G
     48 |  00000048 | LATIN CAPITAL LETTER H
     49 |  00000049 | LATIN CAPITAL LETTER I
     4A |  0000004A | LATIN CAPITAL LETTER J
     4B |  0000004B | LATIN CAPITAL LETTER K
     4C |  0000004C | LATIN CAPITAL LETTER L
     4D |  0000004D | LATIN CAPITAL LETTER M
     4E |  0000004E | LATIN CAPITAL LETTER N
     4F |  0000004F | LATIN CAPITAL LETTER O
     50 |  00000050 | LATIN CAPITAL LETTER P
     51 |  00000051 | LATIN CAPITAL LETTER Q
     52 |  00000052 | LATIN CAPITAL LETTER R
     53 |  00000053 | LATIN CAPITAL LETTER S
     54 |  00000054 | LATIN CAPITAL LETTER T
     55 |  00000055 | LATIN CAPITAL LETTER U
     56 |  00000056 | LATIN CAPITAL LETTER V
     57 |  00000057 | LATIN CAPITAL LETTER W
     58 |  00000058 | LATIN CAPITAL LETTER X
     59 |  00000059 | LATIN CAPITAL LETTER Y
     5A |  0000005A | LATIN CAPITAL LETTER Z
     5B |  0000005B | LEFT SQUARE BRACKET
     5C |  0000005C | REVERSE SOLIDUS
     5D |  0000005D | RIGHT SQUARE BRACKET
     5E |  0000005E | CIRCUMFLEX ACCENT
     5F |  0000005F | LOW LINE
     60 |  00000060 | GRAVE ACCENT
     61 |  00000061 | LATIN SMALL LETTER A
     62 |  00000062 | LATIN SMALL LETTER B
     63 |  00000063 | LATIN SMALL LETTER C
     64 |  00000064 | LATIN SMALL LETTER D
     65 |  00000065 | LATIN SMALL LETTER E
     66 |  00000066 | LATIN SMALL LETTER F
     67 |  00000067 | LATIN SMALL LETTER G
     68 |  00000068 | LATIN SMALL LETTER H
     69 |  00000069 | LATIN SMALL LETTER I
     6A |  0000006A | LATIN SMALL LETTER J
     6B |  0000006B | LATIN SMALL LETTER K
     6C |  0000006C | LATIN SMALL LETTER L
     6D |  0000006D | LATIN SMALL LETTER M
     6E |  0000006E | LATIN SMALL LETTER N
     6F |  0000006F | LATIN SMALL LETTER O
     70 |  00000070 | LATIN SMALL LETTER P
     71 |  00000071 | LATIN SMALL LETTER Q
     72 |  00000072 | LATIN SMALL LETTER R
     73 |  00000073 | LATIN SMALL LETTER S
     74 |  00000074 | LATIN SMALL LETTER T
     75 |  00000075 | LATIN SMALL LETTER U
     76 |  00000076 | LATIN SMALL LETTER V
     77 |  00000077 | LATIN SMALL LETTER W
     78 |  00000078 | LATIN SMALL LETTER X
     79 |  00000079 | LATIN SMALL LETTER Y
     7A |  0000007A | LATIN SMALL LETTER Z
     7B |  0000007B | LEFT CURLY BRACKET
     7C |  0000007C | VERTICAL LINE
     7D |  0000007D | RIGHT CURLY BRACKET
     7E |  0000007E | TILDE
     7F |  0000007F | DELETE (DEL)
     80 |  000000C7 | LATIN CAPITAL LETTER C WITH CEDILLA
     81 |  000000FC | LATIN SMALL LETTER U WITH DIAERESIS
     82 |  000000E9 | LATIN SMALL LETTER E WITH ACUTE
     83 |  000000E2 | LATIN SMALL LETTER A WITH CIRCUMFLEX
     84 |  000000E4 | LATIN SMALL LETTER A WITH DIAERESIS
     85 |  000000E0 | LATIN SMALL LETTER A WITH GRAVE
     86 |  000000E5 | LATIN SMALL LETTER A WITH RING ABOVE
     87 |  000000E7 | LATIN SMALL LETTER C WITH CEDILLA
     88 |  000000EA | LATIN SMALL LETTER E WITH CIRCUMFLEX
     89 |  000000EB | LATIN SMALL LETTER E WITH DIAERESIS
     8A |  000000E8 | LATIN SMALL LETTER E WITH GRAVE
     8B |  000000EF | LATIN SMALL LETTER I WITH DIAERESIS
     8C |  000000EE | LATIN SMALL LETTER I WITH CIRCUMFLEX
     8D |  000000EC | LATIN SMALL LETTER I WITH GRAVE
     8E |  000000C4 | LATIN CAPITAL LETTER A WITH DIAERESIS
     8F |  000000C5 | LATIN CAPITAL LETTER A WITH RING ABOVE
     90 |  000000C9 | LATIN CAPITAL LETTER E WITH ACUTE
     91 |  000000E6 | LATIN SMALL LETTER AE
     92 |  000000C6 | LATIN CAPITAL LETTER AE
     93 |  000000F4 | LATIN SMALL LETTER O WITH CIRCUMFLEX
     94 |  000000F6 | LATIN SMALL LETTER O WITH DIAERESIS
     95 |  000000F2 | LATIN SMALL LETTER O WITH GRAVE
     96 |  000000FB | LATIN SMALL LETTER U WITH CIRCUMFLEX
     97 |  000000F9 | LATIN SMALL LETTER U WITH GRAVE
     98 |  000000FF | LATIN SMALL LETTER Y WITH DIAERESIS
     99 |  000000D6 | LATIN CAPITAL LETTER O WITH DIAERESIS
     9A |  000000DC | LATIN CAPITAL LETTER U WITH DIAERESIS
     9B |  000000F8 | LATIN SMALL LETTER O WITH STROKE
     9C |  000000A3 | POUND SIGN
     9D |  000000D8 | LATIN CAPITAL LETTER O WITH STROKE
     9E |  000020A7 | PESETA SIGN
     9F |  00000192 | LATIN SMALL LETTER F WITH HOOK
     A0 |  000000E1 | LATIN SMALL LETTER A WITH ACUTE
     A1 |  000000ED | LATIN SMALL LETTER I WITH ACUTE
     A2 |  000000F3 | LATIN SMALL LETTER O WITH ACUTE
     A3 |  000000FA | LATIN SMALL LETTER U WITH ACUTE
     A4 |  000000F1 | LATIN SMALL LETTER N WITH TILDE
     A5 |  000000D1 | LATIN CAPITAL LETTER N WITH TILDE
     A6 |  000000AA | FEMININE ORDINAL INDICATOR
     A7 |  000000BA | MASCULINE ORDINAL INDICATOR
     A8 |  000000BF | INVERTED QUESTION MARK
     A9 |  00002310 | REVERSED NOT SIGN
     AA |  000000AC | NOT SIGN
     AB |  000000BD | VULGAR FRACTION ONE HALF
     AC |  000000BC | VULGAR FRACTION ONE QUARTER
     AD |  000000A1 | INVERTED EXCLAMATION MARK
     AE |  000000AB | LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
     AF |  000000A4 | CURRENCY SIGN
     B0 |  00002591 | LIGHT SHADE
     B1 |  00002592 | MEDIUM SHADE
     B2 |  00002593 | DARK SHADE
     B3 |  00002502 | BOX DRAWINGS LIGHT VERTICAL
     B4 |  00002524 | BOX DRAWINGS LIGHT VERTICAL AND LEFT
     B5 |  00002561 | BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE
     B6 |  00002562 | BOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLE
     B7 |  00002556 | BOX DRAWINGS DOWN DOUBLE AND LEFT SINGLE
     B8 |  00002555 | BOX DRAWINGS DOWN SINGLE AND LEFT DOUBLE
     B9 |  00002563 | BOX DRAWINGS DOUBLE VERTICAL AND LEFT
     BA |  00002551 | BOX DRAWINGS DOUBLE VERTICAL
     BB |  00002557 | BOX DRAWINGS DOUBLE DOWN AND LEFT
     BC |  0000255D | BOX DRAWINGS DOUBLE UP AND LEFT
     BD |  0000255C | BOX DRAWINGS UP DOUBLE AND LEFT SINGLE
     BE |  0000255B | BOX DRAWINGS UP SINGLE AND LEFT DOUBLE
     BF |  00002510 | BOX DRAWINGS LIGHT DOWN AND LEFT
     C0 |  00002514 | BOX DRAWINGS LIGHT UP AND RIGHT
     C1 |  00002534 | BOX DRAWINGS LIGHT UP AND HORIZONTAL
     C2 |  0000252C | BOX DRAWINGS LIGHT DOWN AND HORIZONTAL
     C3 |  0000251C | BOX DRAWINGS LIGHT VERTICAL AND RIGHT
     C4 |  00002500 | BOX DRAWINGS LIGHT HORIZONTAL
     C5 |  0000253C | BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL
     C6 |  0000255E | BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE
     C7 |  0000255F | BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE
     C8 |  0000255A | BOX DRAWINGS DOUBLE UP AND RIGHT
     C9 |  00002554 | BOX DRAWINGS DOUBLE DOWN AND RIGHT
     CA |  00002569 | BOX DRAWINGS DOUBLE UP AND HORIZONTAL
     CB |  00002566 | BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL
     CC |  00002560 | BOX DRAWINGS DOUBLE VERTICAL AND RIGHT
     CD |  00002550 | BOX DRAWINGS DOUBLE HORIZONTAL
     CE |  0000256C | BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL
     CF |  00002567 | BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE
     D0 |  00002568 | BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE
     D1 |  00002564 | BOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLE
     D2 |  00002565 | BOX DRAWINGS DOWN DOUBLE AND HORIZONTAL SINGLE
     D3 |  00002559 | BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE
     D4 |  00002558 | BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE
     D5 |  00002552 | BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE
     D6 |  00002553 | BOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLE
     D7 |  0000256B | BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLE
     D8 |  0000256A | BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE
     D9 |  00002518 | BOX DRAWINGS LIGHT UP AND LEFT
     DA |  0000250C | BOX DRAWINGS LIGHT DOWN AND RIGHT
     DB |  00002588 | FULL BLOCK
     DC |  00002584 | LOWER HALF BLOCK
     DD |  0000258C | LEFT HALF BLOCK
     DE |  00002590 | RIGHT HALF BLOCK
     DF |  00002580 | UPPER HALF BLOCK
     E0 |  000003B1 | GREEK SMALL LETTER ALPHA
     E1 |  000000DF | LATIN SMALL LETTER SHARP S (German)
     E2 |  00000393 | GREEK CAPITAL LETTER GAMMA
     E3 |  000003C0 | GREEK SMALL LETTER PI
     E4 |  000003A3 | GREEK CAPITAL LETTER SIGMA
     E5 |  000003C3 | GREEK SMALL LETTER SIGMA
     E6 |  000000B5 | MICRO SIGN
     E7 |  000003C4 | GREEK SMALL LETTER TAU
     E8 |  000003A6 | GREEK CAPITAL LETTER PHI
     E9 |  00000398 | GREEK CAPITAL LETTER THETA
     EA |  000003A9 | GREEK CAPITAL LETTER OMEGA
     EB |  000003B4 | GREEK SMALL LETTER DELTA
     EC |  0000221E | INFINITY
     ED |  000003C6 | GREEK SMALL LETTER PHI
     EE |  000003B5 | GREEK SMALL LETTER EPSILON
     EF |  00002229 | INTERSECTION
     F0 |  00002261 | IDENTICAL TO
     F1 |  000000B1 | PLUS-MINUS SIGN
     F2 |  00002265 | GREATER-THAN OR EQUAL TO
     F3 |  00002264 | LESS-THAN OR EQUAL TO
     F4 |  00002320 | TOP HALF INTEGRAL
     F5 |  00002321 | BOTTOM HALF INTEGRAL
     F6 |  000000F7 | DIVISION SIGN
     F7 |  00002248 | ALMOST EQUAL TO
     F8 |  000000B0 | DEGREE SIGN
     F9 |  00002219 | BULLET OPERATOR
     FA |  000000B7 | MIDDLE DOT
     FB |  0000221A | SQUARE ROOT
     FC |  0000207F | SUPERSCRIPT LATIN SMALL LETTER N
     FD |  000000B2 | SUPERSCRIPT TWO
     FE |  000025A0 | BLACK SQUARE
     FF |  000000A0 | NO-BREAK SPACE
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/IBM866.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for IBM866.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::IBM866;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x0004,
     0x0005,
     0x0006,
     0x0007,
     0x0008,
     0x0009,
     0x000a,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x0014,
     0x0015,
     0x0016,
     0x0017,
     0x0018,
     0x0019,
     0x001a,
     0x001b,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0020,
     0x0021,
     0x0022,
     0x0023,
     0x0024,
     0x0025,
     0x0026,
     0x0027,
     0x0028,
     0x0029,
     0x002a,
     0x002b,
     0x002c,
     0x002d,
     0x002e,
     0x002f,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x003a,
     0x003b,
     0x003c,
     0x003d,
     0x003e,
     0x003f,
     0x0040,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x005b,
     0x005c,
     0x005d,
     0x005e,
     0x005f,
     0x0060,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x007b,
     0x007c,
     0x007d,
     0x007e,
     0x007f,
     0x0410,
     0x0411,
     0x0412,
     0x0413,
     0x0414,
     0x0415,
     0x0416,
     0x0417,
     0x0418,
     0x0419,
     0x041a,
     0x041b,
     0x041c,
     0x041d,
     0x041e,
     0x041f,
     0x0420,
     0x0421,
     0x0422,
     0x0423,
     0x0424,
     0x0425,
     0x0426,
     0x0427,
     0x0428,
     0x0429,
     0x042a,
     0x042b,
     0x042c,
     0x042d,
     0x042e,
     0x042f,
     0x0430,
     0x0431,
     0x0432,
     0x0433,
     0x0434,
     0x0435,
     0x0436,
     0x0437,
     0x0438,
     0x0439,
     0x043a,
     0x043b,
     0x043c,
     0x043d,
     0x043e,
     0x043f,
     0x2591,
     0x2592,
     0x2593,
     0x2502,
     0x2524,
     0x2561,
     0x2562,
     0x2556,
     0x2555,
     0x2563,
     0x2551,
     0x2557,
     0x255d,
     0x255c,
     0x255b,
     0x2510,
     0x2514,
     0x2534,
     0x252c,
     0x251c,
     0x2500,
     0x253c,
     0x255e,
     0x255f,
     0x255a,
     0x2554,
     0x2569,
     0x2566,
     0x2560,
     0x2550,
     0x256c,
     0x2567,
     0x2568,
     0x2564,
     0x2565,
     0x2559,
     0x2558,
     0x2552,
     0x2553,
     0x256b,
     0x256a,
     0x2518,
     0x250c,
     0x2588,
     0x2584,
     0x258c,
     0x2590,
     0x2580,
     0x0440,
     0x0441,
     0x0442,
     0x0443,
     0x0444,
     0x0445,
     0x0446,
     0x0447,
     0x0448,
     0x0449,
     0x044a,
     0x044b,
     0x044c,
     0x044d,
     0x044e,
     0x044f,
     0x0401,
     0x0451,
     0x0404,
     0x0454,
     0x0407,
     0x0457,
     0x040e,
     0x045e,
     0x00b0,
     0x2219,
     0x00b7,
     0x221a,
     0x2116,
     0x00a4,
     0x25a0,
     0x00a0,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\x04",
     "\x05",
     "\x06",
     "\x07",
     "\x08",
     "\x09",
     "\x0a",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\x14",
     "\x15",
     "\x16",
     "\x17",
     "\x18",
     "\x19",
     "\x1a",
     "\x1b",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\x20",
     "\x21",
     "\x22",
     "\x23",
     "\x24",
     "\x25",
     "\x26",
     "\x27",
     "\x28",
     "\x29",
     "\x2a",
     "\x2b",
     "\x2c",
     "\x2d",
     "\x2e",
     "\x2f",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\x3a",
     "\x3b",
     "\x3c",
     "\x3d",
     "\x3e",
     "\x3f",
     "\x40",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\x5b",
     "\x5c",
     "\x5d",
     "\x5e",
     "\x5f",
     "\x60",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\x7b",
     "\x7c",
     "\x7d",
     "\x7e",
     "\x7f",
     "\xd0\x90",
     "\xd0\x91",
     "\xd0\x92",
     "\xd0\x93",
     "\xd0\x94",
     "\xd0\x95",
     "\xd0\x96",
     "\xd0\x97",
     "\xd0\x98",
     "\xd0\x99",
     "\xd0\x9a",
     "\xd0\x9b",
     "\xd0\x9c",
     "\xd0\x9d",
     "\xd0\x9e",
     "\xd0\x9f",
     "\xd0\xa0",
     "\xd0\xa1",
     "\xd0\xa2",
     "\xd0\xa3",
     "\xd0\xa4",
     "\xd0\xa5",
     "\xd0\xa6",
     "\xd0\xa7",
     "\xd0\xa8",
     "\xd0\xa9",
     "\xd0\xaa",
     "\xd0\xab",
     "\xd0\xac",
     "\xd0\xad",
     "\xd0\xae",
     "\xd0\xaf",
     "\xd0\xb0",
     "\xd0\xb1",
     "\xd0\xb2",
     "\xd0\xb3",
     "\xd0\xb4",
     "\xd0\xb5",
     "\xd0\xb6",
     "\xd0\xb7",
     "\xd0\xb8",
     "\xd0\xb9",
     "\xd0\xba",
     "\xd0\xbb",
     "\xd0\xbc",
     "\xd0\xbd",
     "\xd0\xbe",
     "\xd0\xbf",
     "\xe2\x96\x91",
     "\xe2\x96\x92",
     "\xe2\x96\x93",
     "\xe2\x94\x82",
     "\xe2\x94\xa4",
     "\xe2\x95\xa1",
     "\xe2\x95\xa2",
     "\xe2\x95\x96",
     "\xe2\x95\x95",
     "\xe2\x95\xa3",
     "\xe2\x95\x91",
     "\xe2\x95\x97",
     "\xe2\x95\x9d",
     "\xe2\x95\x9c",
     "\xe2\x95\x9b",
     "\xe2\x94\x90",
     "\xe2\x94\x94",
     "\xe2\x94\xb4",
     "\xe2\x94\xac",
     "\xe2\x94\x9c",
     "\xe2\x94\x80",
     "\xe2\x94\xbc",
     "\xe2\x95\x9e",
     "\xe2\x95\x9f",
     "\xe2\x95\x9a",
     "\xe2\x95\x94",
     "\xe2\x95\xa9",
     "\xe2\x95\xa6",
     "\xe2\x95\xa0",
     "\xe2\x95\x90",
     "\xe2\x95\xac",
     "\xe2\x95\xa7",
     "\xe2\x95\xa8",
     "\xe2\x95\xa4",
     "\xe2\x95\xa5",
     "\xe2\x95\x99",
     "\xe2\x95\x98",
     "\xe2\x95\x92",
     "\xe2\x95\x93",
     "\xe2\x95\xab",
     "\xe2\x95\xaa",
     "\xe2\x94\x98",
     "\xe2\x94\x8c",
     "\xe2\x96\x88",
     "\xe2\x96\x84",
     "\xe2\x96\x8c",
     "\xe2\x96\x90",
     "\xe2\x96\x80",
     "\xd1\x80",
     "\xd1\x81",
     "\xd1\x82",
     "\xd1\x83",
     "\xd1\x84",
     "\xd1\x85",
     "\xd1\x86",
     "\xd1\x87",
     "\xd1\x88",
     "\xd1\x89",
     "\xd1\x8a",
     "\xd1\x8b",
     "\xd1\x8c",
     "\xd1\x8d",
     "\xd1\x8e",
     "\xd1\x8f",
     "\xd0\x81",
     "\xd1\x91",
     "\xd0\x84",
     "\xd1\x94",
     "\xd0\x87",
     "\xd1\x97",
     "\xd0\x8e",
     "\xd1\x9e",
     "\xc2\xb0",
     "\xe2\x88\x99",
     "\xc2\xb7",
     "\xe2\x88\x9a",
     "\xe2\x84\x96",
     "\xc2\xa4",
     "\xe2\x96\xa0",
     "\xc2\xa0",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x04",
     0x00000005 => "\x05",
     0x00000006 => "\x06",
     0x00000007 => "\x07",
     0x00000008 => "\x08",
     0x00000009 => "\x09",
     0x0000000a => "\x0a",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x14",
     0x00000015 => "\x15",
     0x00000016 => "\x16",
     0x00000017 => "\x17",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x1a",
     0x0000001b => "\x1b",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x20",
     0x00000021 => "\x21",
     0x00000022 => "\x22",
     0x00000023 => "\x23",
     0x00000024 => "\x24",
     0x00000025 => "\x25",
     0x00000026 => "\x26",
     0x00000027 => "\x27",
     0x00000028 => "\x28",
     0x00000029 => "\x29",
     0x0000002a => "\x2a",
     0x0000002b => "\x2b",
     0x0000002c => "\x2c",
     0x0000002d => "\x2d",
     0x0000002e => "\x2e",
     0x0000002f => "\x2f",
     0x00000030 => "\x30",
     0x00000031 => "\x31",
     0x00000032 => "\x32",
     0x00000033 => "\x33",
     0x00000034 => "\x34",
     0x00000035 => "\x35",
     0x00000036 => "\x36",
     0x00000037 => "\x37",
     0x00000038 => "\x38",
     0x00000039 => "\x39",
     0x0000003a => "\x3a",
     0x0000003b => "\x3b",
     0x0000003c => "\x3c",
     0x0000003d => "\x3d",
     0x0000003e => "\x3e",
     0x0000003f => "\x3f",
     0x00000040 => "\x40",
     0x00000041 => "\x41",
     0x00000042 => "\x42",
     0x00000043 => "\x43",
     0x00000044 => "\x44",
     0x00000045 => "\x45",
     0x00000046 => "\x46",
     0x00000047 => "\x47",
     0x00000048 => "\x48",
     0x00000049 => "\x49",
     0x0000004a => "\x4a",
     0x0000004b => "\x4b",
     0x0000004c => "\x4c",
     0x0000004d => "\x4d",
     0x0000004e => "\x4e",
     0x0000004f => "\x4f",
     0x00000050 => "\x50",
     0x00000051 => "\x51",
     0x00000052 => "\x52",
     0x00000053 => "\x53",
     0x00000054 => "\x54",
     0x00000055 => "\x55",
     0x00000056 => "\x56",
     0x00000057 => "\x57",
     0x00000058 => "\x58",
     0x00000059 => "\x59",
     0x0000005a => "\x5a",
     0x0000005b => "\x5b",
     0x0000005c => "\x5c",
     0x0000005d => "\x5d",
     0x0000005e => "\x5e",
     0x0000005f => "\x5f",
     0x00000060 => "\x60",
     0x00000061 => "\x61",
     0x00000062 => "\x62",
     0x00000063 => "\x63",
     0x00000064 => "\x64",
     0x00000065 => "\x65",
     0x00000066 => "\x66",
     0x00000067 => "\x67",
     0x00000068 => "\x68",
     0x00000069 => "\x69",
     0x0000006a => "\x6a",
     0x0000006b => "\x6b",
     0x0000006c => "\x6c",
     0x0000006d => "\x6d",
     0x0000006e => "\x6e",
     0x0000006f => "\x6f",
     0x00000070 => "\x70",
     0x00000071 => "\x71",
     0x00000072 => "\x72",
     0x00000073 => "\x73",
     0x00000074 => "\x74",
     0x00000075 => "\x75",
     0x00000076 => "\x76",
     0x00000077 => "\x77",
     0x00000078 => "\x78",
     0x00000079 => "\x79",
     0x0000007a => "\x7a",
     0x0000007b => "\x7b",
     0x0000007c => "\x7c",
     0x0000007d => "\x7d",
     0x0000007e => "\x7e",
     0x0000007f => "\x7f",
     0x000000a0 => "\xff",
     0x000000a4 => "\xfd",
     0x000000b0 => "\xf8",
     0x000000b7 => "\xfa",
     0x00000401 => "\xf0",
     0x00000404 => "\xf2",
     0x00000407 => "\xf4",
     0x0000040e => "\xf6",
     0x00000410 => "\x80",
     0x00000411 => "\x81",
     0x00000412 => "\x82",
     0x00000413 => "\x83",
     0x00000414 => "\x84",
     0x00000415 => "\x85",
     0x00000416 => "\x86",
     0x00000417 => "\x87",
     0x00000418 => "\x88",
     0x00000419 => "\x89",
     0x0000041a => "\x8a",
     0x0000041b => "\x8b",
     0x0000041c => "\x8c",
     0x0000041d => "\x8d",
     0x0000041e => "\x8e",
     0x0000041f => "\x8f",
     0x00000420 => "\x90",
     0x00000421 => "\x91",
     0x00000422 => "\x92",
     0x00000423 => "\x93",
     0x00000424 => "\x94",
     0x00000425 => "\x95",
     0x00000426 => "\x96",
     0x00000427 => "\x97",
     0x00000428 => "\x98",
     0x00000429 => "\x99",
     0x0000042a => "\x9a",
     0x0000042b => "\x9b",
     0x0000042c => "\x9c",
     0x0000042d => "\x9d",
     0x0000042e => "\x9e",
     0x0000042f => "\x9f",
     0x00000430 => "\xa0",
     0x00000431 => "\xa1",
     0x00000432 => "\xa2",
     0x00000433 => "\xa3",
     0x00000434 => "\xa4",
     0x00000435 => "\xa5",
     0x00000436 => "\xa6",
     0x00000437 => "\xa7",
     0x00000438 => "\xa8",
     0x00000439 => "\xa9",
     0x0000043a => "\xaa",
     0x0000043b => "\xab",
     0x0000043c => "\xac",
     0x0000043d => "\xad",
     0x0000043e => "\xae",
     0x0000043f => "\xaf",
     0x00000440 => "\xe0",
     0x00000441 => "\xe1",
     0x00000442 => "\xe2",
     0x00000443 => "\xe3",
     0x00000444 => "\xe4",
     0x00000445 => "\xe5",
     0x00000446 => "\xe6",
     0x00000447 => "\xe7",
     0x00000448 => "\xe8",
     0x00000449 => "\xe9",
     0x0000044a => "\xea",
     0x0000044b => "\xeb",
     0x0000044c => "\xec",
     0x0000044d => "\xed",
     0x0000044e => "\xee",
     0x0000044f => "\xef",
     0x00000451 => "\xf1",
     0x00000454 => "\xf3",
     0x00000457 => "\xf5",
     0x0000045e => "\xf7",
     0x00002116 => "\xfc",
     0x00002219 => "\xf9",
     0x0000221a => "\xfb",
     0x00002500 => "\xc4",
     0x00002502 => "\xb3",
     0x0000250c => "\xda",
     0x00002510 => "\xbf",
     0x00002514 => "\xc0",
     0x00002518 => "\xd9",
     0x0000251c => "\xc3",
     0x00002524 => "\xb4",
     0x0000252c => "\xc2",
     0x00002534 => "\xc1",
     0x0000253c => "\xc5",
     0x00002550 => "\xcd",
     0x00002551 => "\xba",
     0x00002552 => "\xd5",
     0x00002553 => "\xd6",
     0x00002554 => "\xc9",
     0x00002555 => "\xb8",
     0x00002556 => "\xb7",
     0x00002557 => "\xbb",
     0x00002558 => "\xd4",
     0x00002559 => "\xd3",
     0x0000255a => "\xc8",
     0x0000255b => "\xbe",
     0x0000255c => "\xbd",
     0x0000255d => "\xbc",
     0x0000255e => "\xc6",
     0x0000255f => "\xc7",
     0x00002560 => "\xcc",
     0x00002561 => "\xb5",
     0x00002562 => "\xb6",
     0x00002563 => "\xb9",
     0x00002564 => "\xd1",
     0x00002565 => "\xd2",
     0x00002566 => "\xcb",
     0x00002567 => "\xcf",
     0x00002568 => "\xd0",
     0x00002569 => "\xca",
     0x0000256a => "\xd8",
     0x0000256b => "\xd7",
     0x0000256c => "\xce",
     0x00002580 => "\xdf",
     0x00002584 => "\xdc",
     0x00002588 => "\xdb",
     0x0000258c => "\xdd",
     0x00002590 => "\xde",
     0x00002591 => "\xb0",
     0x00002592 => "\xb1",
     0x00002593 => "\xb2",
     0x000025a0 => "\xfe",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::IBM866 - Conversion routines for IBM866
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for IBM866.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  automatically generated from the charDB
  alias CP866
  alias 866
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL
     01 |  00000001 | START OF HEADING
     02 |  00000002 | START OF TEXT
     03 |  00000003 | END OF TEXT
     04 |  00000004 | END OF TRANSMISSION
     05 |  00000005 | ENQUIRY
     06 |  00000006 | ACKNOWLEDGE
     07 |  00000007 | BELL
     08 |  00000008 | BACKSPACE
     09 |  00000009 | HORIZONTAL TABULATION
     0A |  0000000A | LINE FEED
     0B |  0000000B | VERTICAL TABULATION
     0C |  0000000C | FORM FEED
     0D |  0000000D | CARRIAGE RETURN
     0E |  0000000E | SHIFT OUT
     0F |  0000000F | SHIFT IN
     10 |  00000010 | DATA LINK ESCAPE
     11 |  00000011 | DEVICE CONTROL ONE
     12 |  00000012 | DEVICE CONTROL TWO
     13 |  00000013 | DEVICE CONTROL THREE
     14 |  00000014 | DEVICE CONTROL FOUR
     15 |  00000015 | NEGATIVE ACKNOWLEDGE
     16 |  00000016 | SYNCHRONOUS IDLE
     17 |  00000017 | END OF TRANSMISSION BLOCK
     18 |  00000018 | CANCEL
     19 |  00000019 | END OF MEDIUM
     1A |  0000001A | SUBSTITUTE
     1B |  0000001B | ESCAPE
     1C |  0000001C | FILE SEPARATOR
     1D |  0000001D | GROUP SEPARATOR
     1E |  0000001E | RECORD SEPARATOR
     1F |  0000001F | UNIT SEPARATOR
     20 |  00000020 | SPACE
     21 |  00000021 | EXCLAMATION MARK
     22 |  00000022 | QUOTATION MARK
     23 |  00000023 | NUMBER SIGN
     24 |  00000024 | DOLLAR SIGN
     25 |  00000025 | PERCENT SIGN
     26 |  00000026 | AMPERSAND
     27 |  00000027 | APOSTROPHE
     28 |  00000028 | LEFT PARENTHESIS
     29 |  00000029 | RIGHT PARENTHESIS
     2A |  0000002A | ASTERISK
     2B |  0000002B | PLUS SIGN
     2C |  0000002C | COMMA
     2D |  0000002D | HYPHEN-MINUS
     2E |  0000002E | FULL STOP
     2F |  0000002F | SOLIDUS
     30 |  00000030 | DIGIT ZERO
     31 |  00000031 | DIGIT ONE
     32 |  00000032 | DIGIT TWO
     33 |  00000033 | DIGIT THREE
     34 |  00000034 | DIGIT FOUR
     35 |  00000035 | DIGIT FIVE
     36 |  00000036 | DIGIT SIX
     37 |  00000037 | DIGIT SEVEN
     38 |  00000038 | DIGIT EIGHT
     39 |  00000039 | DIGIT NINE
     3A |  0000003A | COLON
     3B |  0000003B | SEMICOLON
     3C |  0000003C | LESS-THAN SIGN
     3D |  0000003D | EQUALS SIGN
     3E |  0000003E | GREATER-THAN SIGN
     3F |  0000003F | QUESTION MARK
     40 |  00000040 | COMMERCIAL AT
     41 |  00000041 | LATIN CAPITAL LETTER A
     42 |  00000042 | LATIN CAPITAL LETTER B
     43 |  00000043 | LATIN CAPITAL LETTER C
     44 |  00000044 | LATIN CAPITAL LETTER D
     45 |  00000045 | LATIN CAPITAL LETTER E
     46 |  00000046 | LATIN CAPITAL LETTER F
     47 |  00000047 | LATIN CAPITAL LETTER G
     48 |  00000048 | LATIN CAPITAL LETTER H
     49 |  00000049 | LATIN CAPITAL LETTER I
     4A |  0000004A | LATIN CAPITAL LETTER J
     4B |  0000004B | LATIN CAPITAL LETTER K
     4C |  0000004C | LATIN CAPITAL LETTER L
     4D |  0000004D | LATIN CAPITAL LETTER M
     4E |  0000004E | LATIN CAPITAL LETTER N
     4F |  0000004F | LATIN CAPITAL LETTER O
     50 |  00000050 | LATIN CAPITAL LETTER P
     51 |  00000051 | LATIN CAPITAL LETTER Q
     52 |  00000052 | LATIN CAPITAL LETTER R
     53 |  00000053 | LATIN CAPITAL LETTER S
     54 |  00000054 | LATIN CAPITAL LETTER T
     55 |  00000055 | LATIN CAPITAL LETTER U
     56 |  00000056 | LATIN CAPITAL LETTER V
     57 |  00000057 | LATIN CAPITAL LETTER W
     58 |  00000058 | LATIN CAPITAL LETTER X
     59 |  00000059 | LATIN CAPITAL LETTER Y
     5A |  0000005A | LATIN CAPITAL LETTER Z
     5B |  0000005B | LEFT SQUARE BRACKET
     5C |  0000005C | REVERSE SOLIDUS
     5D |  0000005D | RIGHT SQUARE BRACKET
     5E |  0000005E | CIRCUMFLEX ACCENT
     5F |  0000005F | LOW LINE
     60 |  00000060 | GRAVE ACCENT
     61 |  00000061 | LATIN SMALL LETTER A
     62 |  00000062 | LATIN SMALL LETTER B
     63 |  00000063 | LATIN SMALL LETTER C
     64 |  00000064 | LATIN SMALL LETTER D
     65 |  00000065 | LATIN SMALL LETTER E
     66 |  00000066 | LATIN SMALL LETTER F
     67 |  00000067 | LATIN SMALL LETTER G
     68 |  00000068 | LATIN SMALL LETTER H
     69 |  00000069 | LATIN SMALL LETTER I
     6A |  0000006A | LATIN SMALL LETTER J
     6B |  0000006B | LATIN SMALL LETTER K
     6C |  0000006C | LATIN SMALL LETTER L
     6D |  0000006D | LATIN SMALL LETTER M
     6E |  0000006E | LATIN SMALL LETTER N
     6F |  0000006F | LATIN SMALL LETTER O
     70 |  00000070 | LATIN SMALL LETTER P
     71 |  00000071 | LATIN SMALL LETTER Q
     72 |  00000072 | LATIN SMALL LETTER R
     73 |  00000073 | LATIN SMALL LETTER S
     74 |  00000074 | LATIN SMALL LETTER T
     75 |  00000075 | LATIN SMALL LETTER U
     76 |  00000076 | LATIN SMALL LETTER V
     77 |  00000077 | LATIN SMALL LETTER W
     78 |  00000078 | LATIN SMALL LETTER X
     79 |  00000079 | LATIN SMALL LETTER Y
     7A |  0000007A | LATIN SMALL LETTER Z
     7B |  0000007B | LEFT CURLY BRACKET
     7C |  0000007C | VERTICAL LINE
     7D |  0000007D | RIGHT CURLY BRACKET
     7E |  0000007E | TILDE
     7F |  0000007F | DELETE
     80 |  00000410 | CYRILLIC CAPITAL LETTER A
     81 |  00000411 | CYRILLIC CAPITAL LETTER BE
     82 |  00000412 | CYRILLIC CAPITAL LETTER VE
     83 |  00000413 | CYRILLIC CAPITAL LETTER GHE
     84 |  00000414 | CYRILLIC CAPITAL LETTER DE
     85 |  00000415 | CYRILLIC CAPITAL LETTER IE
     86 |  00000416 | CYRILLIC CAPITAL LETTER ZHE
     87 |  00000417 | CYRILLIC CAPITAL LETTER ZE
     88 |  00000418 | CYRILLIC CAPITAL LETTER I
     89 |  00000419 | CYRILLIC CAPITAL LETTER SHORT I
     8A |  0000041A | CYRILLIC CAPITAL LETTER KA
     8B |  0000041B | CYRILLIC CAPITAL LETTER EL
     8C |  0000041C | CYRILLIC CAPITAL LETTER EM
     8D |  0000041D | CYRILLIC CAPITAL LETTER EN
     8E |  0000041E | CYRILLIC CAPITAL LETTER O
     8F |  0000041F | CYRILLIC CAPITAL LETTER PE
     90 |  00000420 | CYRILLIC CAPITAL LETTER ER
     91 |  00000421 | CYRILLIC CAPITAL LETTER ES
     92 |  00000422 | CYRILLIC CAPITAL LETTER TE
     93 |  00000423 | CYRILLIC CAPITAL LETTER U
     94 |  00000424 | CYRILLIC CAPITAL LETTER EF
     95 |  00000425 | CYRILLIC CAPITAL LETTER HA
     96 |  00000426 | CYRILLIC CAPITAL LETTER TSE
     97 |  00000427 | CYRILLIC CAPITAL LETTER CHE
     98 |  00000428 | CYRILLIC CAPITAL LETTER SHA
     99 |  00000429 | CYRILLIC CAPITAL LETTER SHCHA
     9A |  0000042A | CYRILLIC CAPITAL LETTER HARD SIGN
     9B |  0000042B | CYRILLIC CAPITAL LETTER YERU
     9C |  0000042C | CYRILLIC CAPITAL LETTER SOFT SIGN
     9D |  0000042D | CYRILLIC CAPITAL LETTER E
     9E |  0000042E | CYRILLIC CAPITAL LETTER YU
     9F |  0000042F | CYRILLIC CAPITAL LETTER YA
     A0 |  00000430 | CYRILLIC SMALL LETTER A
     A1 |  00000431 | CYRILLIC SMALL LETTER BE
     A2 |  00000432 | CYRILLIC SMALL LETTER VE
     A3 |  00000433 | CYRILLIC SMALL LETTER GHE
     A4 |  00000434 | CYRILLIC SMALL LETTER DE
     A5 |  00000435 | CYRILLIC SMALL LETTER IE
     A6 |  00000436 | CYRILLIC SMALL LETTER ZHE
     A7 |  00000437 | CYRILLIC SMALL LETTER ZE
     A8 |  00000438 | CYRILLIC SMALL LETTER I
     A9 |  00000439 | CYRILLIC SMALL LETTER SHORT I
     AA |  0000043A | CYRILLIC SMALL LETTER KA
     AB |  0000043B | CYRILLIC SMALL LETTER EL
     AC |  0000043C | CYRILLIC SMALL LETTER EM
     AD |  0000043D | CYRILLIC SMALL LETTER EN
     AE |  0000043E | CYRILLIC SMALL LETTER O
     AF |  0000043F | CYRILLIC SMALL LETTER PE
     B0 |  00002591 | LIGHT SHADE
     B1 |  00002592 | MEDIUM SHADE
     B2 |  00002593 | DARK SHADE
     B3 |  00002502 | BOX DRAWINGS LIGHT VERTICAL
     B4 |  00002524 | BOX DRAWINGS LIGHT VERTICAL AND LEFT
     B5 |  00002561 | BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE
     B6 |  00002562 | BOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLE
     B7 |  00002556 | BOX DRAWINGS DOWN DOUBLE AND LEFT SINGLE
     B8 |  00002555 | BOX DRAWINGS DOWN SINGLE AND LEFT DOUBLE
     B9 |  00002563 | BOX DRAWINGS DOUBLE VERTICAL AND LEFT
     BA |  00002551 | BOX DRAWINGS DOUBLE VERTICAL
     BB |  00002557 | BOX DRAWINGS DOUBLE DOWN AND LEFT
     BC |  0000255D | BOX DRAWINGS DOUBLE UP AND LEFT
     BD |  0000255C | BOX DRAWINGS UP DOUBLE AND LEFT SINGLE
     BE |  0000255B | BOX DRAWINGS UP SINGLE AND LEFT DOUBLE
     BF |  00002510 | BOX DRAWINGS LIGHT DOWN AND LEFT
     C0 |  00002514 | BOX DRAWINGS LIGHT UP AND RIGHT
     C1 |  00002534 | BOX DRAWINGS LIGHT UP AND HORIZONTAL
     C2 |  0000252C | BOX DRAWINGS LIGHT DOWN AND HORIZONTAL
     C3 |  0000251C | BOX DRAWINGS LIGHT VERTICAL AND RIGHT
     C4 |  00002500 | BOX DRAWINGS LIGHT HORIZONTAL
     C5 |  0000253C | BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL
     C6 |  0000255E | BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE
     C7 |  0000255F | BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE
     C8 |  0000255A | BOX DRAWINGS DOUBLE UP AND RIGHT
     C9 |  00002554 | BOX DRAWINGS DOUBLE DOWN AND RIGHT
     CA |  00002569 | BOX DRAWINGS DOUBLE UP AND HORIZONTAL
     CB |  00002566 | BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL
     CC |  00002560 | BOX DRAWINGS DOUBLE VERTICAL AND RIGHT
     CD |  00002550 | BOX DRAWINGS DOUBLE HORIZONTAL
     CE |  0000256C | BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL
     CF |  00002567 | BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE
     D0 |  00002568 | BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE
     D1 |  00002564 | BOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLE
     D2 |  00002565 | BOX DRAWINGS DOWN DOUBLE AND HORIZONTAL SINGLE
     D3 |  00002559 | BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE
     D4 |  00002558 | BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE
     D5 |  00002552 | BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE
     D6 |  00002553 | BOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLE
     D7 |  0000256B | BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLE
     D8 |  0000256A | BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE
     D9 |  00002518 | BOX DRAWINGS LIGHT UP AND LEFT
     DA |  0000250C | BOX DRAWINGS LIGHT DOWN AND RIGHT
     DB |  00002588 | FULL BLOCK
     DC |  00002584 | LOWER HALF BLOCK
     DD |  0000258C | LEFT HALF BLOCK
     DE |  00002590 | RIGHT HALF BLOCK
     DF |  00002580 | UPPER HALF BLOCK
     E0 |  00000440 | CYRILLIC SMALL LETTER ER
     E1 |  00000441 | CYRILLIC SMALL LETTER ES
     E2 |  00000442 | CYRILLIC SMALL LETTER TE
     E3 |  00000443 | CYRILLIC SMALL LETTER U
     E4 |  00000444 | CYRILLIC SMALL LETTER EF
     E5 |  00000445 | CYRILLIC SMALL LETTER HA
     E6 |  00000446 | CYRILLIC SMALL LETTER TSE
     E7 |  00000447 | CYRILLIC SMALL LETTER CHE
     E8 |  00000448 | CYRILLIC SMALL LETTER SHA
     E9 |  00000449 | CYRILLIC SMALL LETTER SHCHA
     EA |  0000044A | CYRILLIC SMALL LETTER HARD SIGN
     EB |  0000044B | CYRILLIC SMALL LETTER YERU
     EC |  0000044C | CYRILLIC SMALL LETTER SOFT SIGN
     ED |  0000044D | CYRILLIC SMALL LETTER E
     EE |  0000044E | CYRILLIC SMALL LETTER YU
     EF |  0000044F | CYRILLIC SMALL LETTER YA
     F0 |  00000401 | CYRILLIC CAPITAL LETTER IO
     F1 |  00000451 | CYRILLIC SMALL LETTER IO
     F2 |  00000404 | CYRILLIC CAPITAL LETTER UKRAINIAN IE
     F3 |  00000454 | CYRILLIC SMALL LETTER UKRAINIAN IE
     F4 |  00000407 | CYRILLIC CAPITAL LETTER YI
     F5 |  00000457 | CYRILLIC SMALL LETTER YI
     F6 |  0000040E | CYRILLIC CAPITAL LETTER SHORT U
     F7 |  0000045E | CYRILLIC SMALL LETTER SHORT U
     F8 |  000000B0 | DEGREE SIGN
     F9 |  00002219 | BULLET OPERATOR
     FA |  000000B7 | MIDDLE DOT
     FB |  0000221A | SQUARE ROOT
     FC |  00002116 | NUMERO SIGN
     FD |  000000A4 | CURRENCY SIGN
     FE |  000025A0 | BLACK SQUARE
     FF |  000000A0 | NO-BREAK SPACE
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/IBM868.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for IBM868.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::IBM868;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x0004,
     0x0005,
     0x0006,
     0x0007,
     0x0008,
     0x0009,
     0x000a,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x0014,
     0x0015,
     0x0016,
     0x0017,
     0x0018,
     0x0019,
     0x001a,
     0x001b,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0020,
     0x0021,
     0x0022,
     0x0023,
     0x0024,
     0x0025,
     0x0026,
     0x0027,
     0x0028,
     0x0029,
     0x002a,
     0x002b,
     0x002c,
     0x002d,
     0x002e,
     0x002f,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x003a,
     0x003b,
     0x003c,
     0x003d,
     0x003e,
     0x003f,
     0x0040,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x005b,
     0x005c,
     0x005d,
     0x005e,
     0x005f,
     0x0060,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x007b,
     0x007c,
     0x007d,
     0x007e,
     0x007f,
     0x0660,
     0x0661,
     0x0662,
     0x0663,
     0x0664,
     0x0665,
     0x0666,
     0x0667,
     0x0668,
     0x0669,
     0x060c,
     0x061b,
     0x061f,
     0x0622,
     0x0627,
     0xfe8e,
     0xe016,
     0x0628,
     0xfe91,
     0x067e,
     0xfffd,
     0x0629,
     0x062a,
     0xfe97,
     0xfffd,
     0xfffd,
     0x062b,
     0xfe9b,
     0x062c,
     0xfe9f,
     0xfffd,
     0xfffd,
     0x062d,
     0xfea3,
     0x062e,
     0xfea7,
     0x062f,
     0xfffd,
     0x0630,
     0x0631,
     0xfffd,
     0x0632,
     0xfffd,
     0x0633,
     0xfeb3,
     0x0634,
     0x00ab,
     0x00bb,
     0xfeb7,
     0x0635,
     0x2591,
     0x2592,
     0x2593,
     0x2502,
     0x2524,
     0xfebb,
     0x0636,
     0xfebf,
     0x0637,
     0x2563,
     0x2551,
     0x2557,
     0x255d,
     0x0638,
     0x0639,
     0x2510,
     0x2514,
     0x2534,
     0x252c,
     0x251c,
     0x2500,
     0x253c,
     0xfeca,
     0xfecb,
     0x255a,
     0x2554,
     0x2569,
     0x2566,
     0x2560,
     0x2550,
     0x256c,
     0xfecc,
     0x063a,
     0xfece,
     0xfecf,
     0xfed0,
     0x0641,
     0xfed3,
     0x0642,
     0xfed7,
     0xfeda,
     0x2518,
     0x250c,
     0x2588,
     0x2580,
     0xfedb,
     0xfffd,
     0x2584,
     0xfffd,
     0x0644,
     0xfede,
     0xfee0,
     0x0645,
     0xfee3,
     0xfffd,
     0x0646,
     0xfee7,
     0xfffd,
     0x0648,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x0621,
     0x00ad,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x0651,
     0xfe7d,
     0xfffd,
     0x25a0,
     0x00a0,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\x04",
     "\x05",
     "\x06",
     "\x07",
     "\x08",
     "\x09",
     "\x0a",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\x14",
     "\x15",
     "\x16",
     "\x17",
     "\x18",
     "\x19",
     "\x1a",
     "\x1b",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\x20",
     "\x21",
     "\x22",
     "\x23",
     "\x24",
     "\x25",
     "\x26",
     "\x27",
     "\x28",
     "\x29",
     "\x2a",
     "\x2b",
     "\x2c",
     "\x2d",
     "\x2e",
     "\x2f",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\x3a",
     "\x3b",
     "\x3c",
     "\x3d",
     "\x3e",
     "\x3f",
     "\x40",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\x5b",
     "\x5c",
     "\x5d",
     "\x5e",
     "\x5f",
     "\x60",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\x7b",
     "\x7c",
     "\x7d",
     "\x7e",
     "\x7f",
     "\xd9\xa0",
     "\xd9\xa1",
     "\xd9\xa2",
     "\xd9\xa3",
     "\xd9\xa4",
     "\xd9\xa5",
     "\xd9\xa6",
     "\xd9\xa7",
     "\xd9\xa8",
     "\xd9\xa9",
     "\xd8\x8c",
     "\xd8\x9b",
     "\xd8\x9f",
     "\xd8\xa2",
     "\xd8\xa7",
     "\xef\xba\x8e",
     "\xee\x80\x96",
     "\xd8\xa8",
     "\xef\xba\x91",
     "\xd9\xbe",
     "\xef\xbf\xbd",
     "\xd8\xa9",
     "\xd8\xaa",
     "\xef\xba\x97",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xd8\xab",
     "\xef\xba\x9b",
     "\xd8\xac",
     "\xef\xba\x9f",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xd8\xad",
     "\xef\xba\xa3",
     "\xd8\xae",
     "\xef\xba\xa7",
     "\xd8\xaf",
     "\xef\xbf\xbd",
     "\xd8\xb0",
     "\xd8\xb1",
     "\xef\xbf\xbd",
     "\xd8\xb2",
     "\xef\xbf\xbd",
     "\xd8\xb3",
     "\xef\xba\xb3",
     "\xd8\xb4",
     "\xc2\xab",
     "\xc2\xbb",
     "\xef\xba\xb7",
     "\xd8\xb5",
     "\xe2\x96\x91",
     "\xe2\x96\x92",
     "\xe2\x96\x93",
     "\xe2\x94\x82",
     "\xe2\x94\xa4",
     "\xef\xba\xbb",
     "\xd8\xb6",
     "\xef\xba\xbf",
     "\xd8\xb7",
     "\xe2\x95\xa3",
     "\xe2\x95\x91",
     "\xe2\x95\x97",
     "\xe2\x95\x9d",
     "\xd8\xb8",
     "\xd8\xb9",
     "\xe2\x94\x90",
     "\xe2\x94\x94",
     "\xe2\x94\xb4",
     "\xe2\x94\xac",
     "\xe2\x94\x9c",
     "\xe2\x94\x80",
     "\xe2\x94\xbc",
     "\xef\xbb\x8a",
     "\xef\xbb\x8b",
     "\xe2\x95\x9a",
     "\xe2\x95\x94",
     "\xe2\x95\xa9",
     "\xe2\x95\xa6",
     "\xe2\x95\xa0",
     "\xe2\x95\x90",
     "\xe2\x95\xac",
     "\xef\xbb\x8c",
     "\xd8\xba",
     "\xef\xbb\x8e",
     "\xef\xbb\x8f",
     "\xef\xbb\x90",
     "\xd9\x81",
     "\xef\xbb\x93",
     "\xd9\x82",
     "\xef\xbb\x97",
     "\xef\xbb\x9a",
     "\xe2\x94\x98",
     "\xe2\x94\x8c",
     "\xe2\x96\x88",
     "\xe2\x96\x80",
     "\xef\xbb\x9b",
     "\xef\xbf\xbd",
     "\xe2\x96\x84",
     "\xef\xbf\xbd",
     "\xd9\x84",
     "\xef\xbb\x9e",
     "\xef\xbb\xa0",
     "\xd9\x85",
     "\xef\xbb\xa3",
     "\xef\xbf\xbd",
     "\xd9\x86",
     "\xef\xbb\xa7",
     "\xef\xbf\xbd",
     "\xd9\x88",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xd8\xa1",
     "\xc2\xad",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xd9\x91",
     "\xef\xb9\xbd",
     "\xef\xbf\xbd",
     "\xe2\x96\xa0",
     "\xc2\xa0",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x04",
     0x00000005 => "\x05",
     0x00000006 => "\x06",
     0x00000007 => "\x07",
     0x00000008 => "\x08",
     0x00000009 => "\x09",
     0x0000000a => "\x0a",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x14",
     0x00000015 => "\x15",
     0x00000016 => "\x16",
     0x00000017 => "\x17",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x1a",
     0x0000001b => "\x1b",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x20",
     0x00000021 => "\x21",
     0x00000022 => "\x22",
     0x00000023 => "\x23",
     0x00000024 => "\x24",
     0x00000025 => "\x25",
     0x00000026 => "\x26",
     0x00000027 => "\x27",
     0x00000028 => "\x28",
     0x00000029 => "\x29",
     0x0000002a => "\x2a",
     0x0000002b => "\x2b",
     0x0000002c => "\x2c",
     0x0000002d => "\x2d",
     0x0000002e => "\x2e",
     0x0000002f => "\x2f",
     0x00000030 => "\x30",
     0x00000031 => "\x31",
     0x00000032 => "\x32",
     0x00000033 => "\x33",
     0x00000034 => "\x34",
     0x00000035 => "\x35",
     0x00000036 => "\x36",
     0x00000037 => "\x37",
     0x00000038 => "\x38",
     0x00000039 => "\x39",
     0x0000003a => "\x3a",
     0x0000003b => "\x3b",
     0x0000003c => "\x3c",
     0x0000003d => "\x3d",
     0x0000003e => "\x3e",
     0x0000003f => "\x3f",
     0x00000040 => "\x40",
     0x00000041 => "\x41",
     0x00000042 => "\x42",
     0x00000043 => "\x43",
     0x00000044 => "\x44",
     0x00000045 => "\x45",
     0x00000046 => "\x46",
     0x00000047 => "\x47",
     0x00000048 => "\x48",
     0x00000049 => "\x49",
     0x0000004a => "\x4a",
     0x0000004b => "\x4b",
     0x0000004c => "\x4c",
     0x0000004d => "\x4d",
     0x0000004e => "\x4e",
     0x0000004f => "\x4f",
     0x00000050 => "\x50",
     0x00000051 => "\x51",
     0x00000052 => "\x52",
     0x00000053 => "\x53",
     0x00000054 => "\x54",
     0x00000055 => "\x55",
     0x00000056 => "\x56",
     0x00000057 => "\x57",
     0x00000058 => "\x58",
     0x00000059 => "\x59",
     0x0000005a => "\x5a",
     0x0000005b => "\x5b",
     0x0000005c => "\x5c",
     0x0000005d => "\x5d",
     0x0000005e => "\x5e",
     0x0000005f => "\x5f",
     0x00000060 => "\x60",
     0x00000061 => "\x61",
     0x00000062 => "\x62",
     0x00000063 => "\x63",
     0x00000064 => "\x64",
     0x00000065 => "\x65",
     0x00000066 => "\x66",
     0x00000067 => "\x67",
     0x00000068 => "\x68",
     0x00000069 => "\x69",
     0x0000006a => "\x6a",
     0x0000006b => "\x6b",
     0x0000006c => "\x6c",
     0x0000006d => "\x6d",
     0x0000006e => "\x6e",
     0x0000006f => "\x6f",
     0x00000070 => "\x70",
     0x00000071 => "\x71",
     0x00000072 => "\x72",
     0x00000073 => "\x73",
     0x00000074 => "\x74",
     0x00000075 => "\x75",
     0x00000076 => "\x76",
     0x00000077 => "\x77",
     0x00000078 => "\x78",
     0x00000079 => "\x79",
     0x0000007a => "\x7a",
     0x0000007b => "\x7b",
     0x0000007c => "\x7c",
     0x0000007d => "\x7d",
     0x0000007e => "\x7e",
     0x0000007f => "\x7f",
     0x000000a0 => "\xff",
     0x000000ab => "\xae",
     0x000000ad => "\xf2",
     0x000000bb => "\xaf",
     0x0000060c => "\x8a",
     0x0000061b => "\x8b",
     0x0000061f => "\x8c",
     0x00000621 => "\xf1",
     0x00000622 => "\x8d",
     0x00000627 => "\x8e",
     0x00000628 => "\x91",
     0x00000629 => "\x95",
     0x0000062a => "\x96",
     0x0000062b => "\x9a",
     0x0000062c => "\x9c",
     0x0000062d => "\xa0",
     0x0000062e => "\xa2",
     0x0000062f => "\xa4",
     0x00000630 => "\xa6",
     0x00000631 => "\xa7",
     0x00000632 => "\xa9",
     0x00000633 => "\xab",
     0x00000634 => "\xad",
     0x00000635 => "\xb1",
     0x00000636 => "\xb8",
     0x00000637 => "\xba",
     0x00000638 => "\xbf",
     0x00000639 => "\xc0",
     0x0000063a => "\xd2",
     0x00000641 => "\xd6",
     0x00000642 => "\xd8",
     0x00000644 => "\xe3",
     0x00000645 => "\xe6",
     0x00000646 => "\xe9",
     0x00000648 => "\xec",
     0x00000651 => "\xfb",
     0x00000660 => "\x80",
     0x00000661 => "\x81",
     0x00000662 => "\x82",
     0x00000663 => "\x83",
     0x00000664 => "\x84",
     0x00000665 => "\x85",
     0x00000666 => "\x86",
     0x00000667 => "\x87",
     0x00000668 => "\x88",
     0x00000669 => "\x89",
     0x0000067e => "\x93",
     0x00002500 => "\xc6",
     0x00002502 => "\xb5",
     0x0000250c => "\xdc",
     0x00002510 => "\xc1",
     0x00002514 => "\xc2",
     0x00002518 => "\xdb",
     0x0000251c => "\xc5",
     0x00002524 => "\xb6",
     0x0000252c => "\xc4",
     0x00002534 => "\xc3",
     0x0000253c => "\xc7",
     0x00002550 => "\xcf",
     0x00002551 => "\xbc",
     0x00002554 => "\xcb",
     0x00002557 => "\xbd",
     0x0000255a => "\xca",
     0x0000255d => "\xbe",
     0x00002560 => "\xce",
     0x00002563 => "\xbb",
     0x00002566 => "\xcd",
     0x00002569 => "\xcc",
     0x0000256c => "\xd0",
     0x00002580 => "\xde",
     0x00002584 => "\xe1",
     0x00002588 => "\xdd",
     0x00002591 => "\xb2",
     0x00002592 => "\xb3",
     0x00002593 => "\xb4",
     0x000025a0 => "\xfe",
     0x0000e016 => "\x90",
     0x0000fe7d => "\xfc",
     0x0000fe8e => "\x8f",
     0x0000fe91 => "\x92",
     0x0000fe97 => "\x97",
     0x0000fe9b => "\x9b",
     0x0000fe9f => "\x9d",
     0x0000fea3 => "\xa1",
     0x0000fea7 => "\xa3",
     0x0000feb3 => "\xac",
     0x0000feb7 => "\xb0",
     0x0000febb => "\xb7",
     0x0000febf => "\xb9",
     0x0000feca => "\xc8",
     0x0000fecb => "\xc9",
     0x0000fecc => "\xd1",
     0x0000fece => "\xd3",
     0x0000fecf => "\xd4",
     0x0000fed0 => "\xd5",
     0x0000fed3 => "\xd7",
     0x0000fed7 => "\xd9",
     0x0000feda => "\xda",
     0x0000fedb => "\xdf",
     0x0000fede => "\xe4",
     0x0000fee0 => "\xe5",
     0x0000fee3 => "\xe7",
     0x0000fee7 => "\xea",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x8c"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::IBM868 - Conversion routines for IBM868
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for IBM868.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
   source: IBM NLS RM Vol2 SE09-8002-01, March 1990
  alias CP868
  alias CP-AR
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  00000004 | END OF TRANSMISSION (EOT)
     05 |  00000005 | ENQUIRY (ENQ)
     06 |  00000006 | ACKNOWLEDGE (ACK)
     07 |  00000007 | BELL (BEL)
     08 |  00000008 | BACKSPACE (BS)
     09 |  00000009 | CHARACTER TABULATION (HT)
     0A |  0000000A | LINE FEED (LF)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  00000014 | DEVICE CONTROL FOUR (DC4)
     15 |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     16 |  00000016 | SYNCHRONOUS IDLE (SYN)
     17 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  0000001A | SUBSTITUTE (SUB)
     1B |  0000001B | ESCAPE (ESC)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000020 | SPACE
     21 |  00000021 | EXCLAMATION MARK
     22 |  00000022 | QUOTATION MARK
     23 |  00000023 | NUMBER SIGN
     24 |  00000024 | DOLLAR SIGN
     25 |  00000025 | PERCENT SIGN
     26 |  00000026 | AMPERSAND
     27 |  00000027 | APOSTROPHE
     28 |  00000028 | LEFT PARENTHESIS
     29 |  00000029 | RIGHT PARENTHESIS
     2A |  0000002A | ASTERISK
     2B |  0000002B | PLUS SIGN
     2C |  0000002C | COMMA
     2D |  0000002D | HYPHEN-MINUS
     2E |  0000002E | FULL STOP
     2F |  0000002F | SOLIDUS
     30 |  00000030 | DIGIT ZERO
     31 |  00000031 | DIGIT ONE
     32 |  00000032 | DIGIT TWO
     33 |  00000033 | DIGIT THREE
     34 |  00000034 | DIGIT FOUR
     35 |  00000035 | DIGIT FIVE
     36 |  00000036 | DIGIT SIX
     37 |  00000037 | DIGIT SEVEN
     38 |  00000038 | DIGIT EIGHT
     39 |  00000039 | DIGIT NINE
     3A |  0000003A | COLON
     3B |  0000003B | SEMICOLON
     3C |  0000003C | LESS-THAN SIGN
     3D |  0000003D | EQUALS SIGN
     3E |  0000003E | GREATER-THAN SIGN
     3F |  0000003F | QUESTION MARK
     40 |  00000040 | COMMERCIAL AT
     41 |  00000041 | LATIN CAPITAL LETTER A
     42 |  00000042 | LATIN CAPITAL LETTER B
     43 |  00000043 | LATIN CAPITAL LETTER C
     44 |  00000044 | LATIN CAPITAL LETTER D
     45 |  00000045 | LATIN CAPITAL LETTER E
     46 |  00000046 | LATIN CAPITAL LETTER F
     47 |  00000047 | LATIN CAPITAL LETTER G
     48 |  00000048 | LATIN CAPITAL LETTER H
     49 |  00000049 | LATIN CAPITAL LETTER I
     4A |  0000004A | LATIN CAPITAL LETTER J
     4B |  0000004B | LATIN CAPITAL LETTER K
     4C |  0000004C | LATIN CAPITAL LETTER L
     4D |  0000004D | LATIN CAPITAL LETTER M
     4E |  0000004E | LATIN CAPITAL LETTER N
     4F |  0000004F | LATIN CAPITAL LETTER O
     50 |  00000050 | LATIN CAPITAL LETTER P
     51 |  00000051 | LATIN CAPITAL LETTER Q
     52 |  00000052 | LATIN CAPITAL LETTER R
     53 |  00000053 | LATIN CAPITAL LETTER S
     54 |  00000054 | LATIN CAPITAL LETTER T
     55 |  00000055 | LATIN CAPITAL LETTER U
     56 |  00000056 | LATIN CAPITAL LETTER V
     57 |  00000057 | LATIN CAPITAL LETTER W
     58 |  00000058 | LATIN CAPITAL LETTER X
     59 |  00000059 | LATIN CAPITAL LETTER Y
     5A |  0000005A | LATIN CAPITAL LETTER Z
     5B |  0000005B | LEFT SQUARE BRACKET
     5C |  0000005C | REVERSE SOLIDUS
     5D |  0000005D | RIGHT SQUARE BRACKET
     5E |  0000005E | CIRCUMFLEX ACCENT
     5F |  0000005F | LOW LINE
     60 |  00000060 | GRAVE ACCENT
     61 |  00000061 | LATIN SMALL LETTER A
     62 |  00000062 | LATIN SMALL LETTER B
     63 |  00000063 | LATIN SMALL LETTER C
     64 |  00000064 | LATIN SMALL LETTER D
     65 |  00000065 | LATIN SMALL LETTER E
     66 |  00000066 | LATIN SMALL LETTER F
     67 |  00000067 | LATIN SMALL LETTER G
     68 |  00000068 | LATIN SMALL LETTER H
     69 |  00000069 | LATIN SMALL LETTER I
     6A |  0000006A | LATIN SMALL LETTER J
     6B |  0000006B | LATIN SMALL LETTER K
     6C |  0000006C | LATIN SMALL LETTER L
     6D |  0000006D | LATIN SMALL LETTER M
     6E |  0000006E | LATIN SMALL LETTER N
     6F |  0000006F | LATIN SMALL LETTER O
     70 |  00000070 | LATIN SMALL LETTER P
     71 |  00000071 | LATIN SMALL LETTER Q
     72 |  00000072 | LATIN SMALL LETTER R
     73 |  00000073 | LATIN SMALL LETTER S
     74 |  00000074 | LATIN SMALL LETTER T
     75 |  00000075 | LATIN SMALL LETTER U
     76 |  00000076 | LATIN SMALL LETTER V
     77 |  00000077 | LATIN SMALL LETTER W
     78 |  00000078 | LATIN SMALL LETTER X
     79 |  00000079 | LATIN SMALL LETTER Y
     7A |  0000007A | LATIN SMALL LETTER Z
     7B |  0000007B | LEFT CURLY BRACKET
     7C |  0000007C | VERTICAL LINE
     7D |  0000007D | RIGHT CURLY BRACKET
     7E |  0000007E | TILDE
     7F |  0000007F | DELETE (DEL)
     80 |  00000660 | ARABIC-INDIC DIGIT ZERO
     81 |  00000661 | ARABIC-INDIC DIGIT ONE
     82 |  00000662 | ARABIC-INDIC DIGIT TWO
     83 |  00000663 | ARABIC-INDIC DIGIT THREE
     84 |  00000664 | ARABIC-INDIC DIGIT FOUR
     85 |  00000665 | ARABIC-INDIC DIGIT FIVE
     86 |  00000666 | ARABIC-INDIC DIGIT SIX
     87 |  00000667 | ARABIC-INDIC DIGIT SEVEN
     88 |  00000668 | ARABIC-INDIC DIGIT EIGHT
     89 |  00000669 | ARABIC-INDIC DIGIT NINE
     8A |  0000060C | ARABIC COMMA
     8B |  0000061B | ARABIC SEMICOLON
     8C |  0000061F | ARABIC QUESTION MARK
     8D |  00000622 | ARABIC LETTER ALEF WITH MADDA ABOVE
     8E |  00000627 | ARABIC LETTER ALEF
     8F |  0000FE8E | ARABIC LETTER ALEF FINAL FORM
     90 |  0000E016 | ARABIC LETTER ALEF FINAL FORM COMPATIBILITY E<lt>IBM868_90E<gt>
     91 |  00000628 | ARABIC LETTER BEH
     92 |  0000FE91 | ARABIC LETTER BEH INITIAL FORM
     93 |  0000067E | ARABIC LETTER PEH
     95 |  00000629 | ARABIC LETTER TEH MARBUTA
     96 |  0000062A | ARABIC LETTER TEH
     97 |  0000FE97 | ARABIC LETTER TEH INITIAL FORM
     9A |  0000062B | ARABIC LETTER THEH
     9B |  0000FE9B | ARABIC LETTER THEH INITIAL FORM
     9C |  0000062C | ARABIC LETTER JEEM
     9D |  0000FE9F | ARABIC LETTER JEEM INITIAL FORM
     A0 |  0000062D | ARABIC LETTER HAH
     A1 |  0000FEA3 | ARABIC LETTER HAH INITIAL FORM
     A2 |  0000062E | ARABIC LETTER KHAH
     A3 |  0000FEA7 | ARABIC LETTER KHAH INITIAL FORM
     A4 |  0000062F | ARABIC LETTER DAL
     A6 |  00000630 | ARABIC LETTER THAL
     A7 |  00000631 | ARABIC LETTER REH
     A9 |  00000632 | ARABIC LETTER ZAIN
     AB |  00000633 | ARABIC LETTER SEEN
     AC |  0000FEB3 | ARABIC LETTER SEEN INITIAL FORM
     AD |  00000634 | ARABIC LETTER SHEEN
     AE |  000000AB | LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
     AF |  000000BB | RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
     B0 |  0000FEB7 | ARABIC LETTER SHEEN INITIAL FORM
     B1 |  00000635 | ARABIC LETTER SAD
     B2 |  00002591 | LIGHT SHADE
     B3 |  00002592 | MEDIUM SHADE
     B4 |  00002593 | DARK SHADE
     B5 |  00002502 | BOX DRAWINGS LIGHT VERTICAL
     B6 |  00002524 | BOX DRAWINGS LIGHT VERTICAL AND LEFT
     B7 |  0000FEBB | ARABIC LETTER SAD INITIAL FORM
     B8 |  00000636 | ARABIC LETTER DAD
     B9 |  0000FEBF | ARABIC LETTER DAD INITIAL FORM
     BA |  00000637 | ARABIC LETTER TAH
     BB |  00002563 | BOX DRAWINGS DOUBLE VERTICAL AND LEFT
     BC |  00002551 | BOX DRAWINGS DOUBLE VERTICAL
     BD |  00002557 | BOX DRAWINGS DOUBLE DOWN AND LEFT
     BE |  0000255D | BOX DRAWINGS DOUBLE UP AND LEFT
     BF |  00000638 | ARABIC LETTER ZAH
     C0 |  00000639 | ARABIC LETTER AIN
     C1 |  00002510 | BOX DRAWINGS LIGHT DOWN AND LEFT
     C2 |  00002514 | BOX DRAWINGS LIGHT UP AND RIGHT
     C3 |  00002534 | BOX DRAWINGS LIGHT UP AND HORIZONTAL
     C4 |  0000252C | BOX DRAWINGS LIGHT DOWN AND HORIZONTAL
     C5 |  0000251C | BOX DRAWINGS LIGHT VERTICAL AND RIGHT
     C6 |  00002500 | BOX DRAWINGS LIGHT HORIZONTAL
     C7 |  0000253C | BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL
     C8 |  0000FECA | ARABIC LETTER AIN FINAL FORM
     C9 |  0000FECB | ARABIC LETTER AIN INITIAL FORM
     CA |  0000255A | BOX DRAWINGS DOUBLE UP AND RIGHT
     CB |  00002554 | BOX DRAWINGS DOUBLE DOWN AND RIGHT
     CC |  00002569 | BOX DRAWINGS DOUBLE UP AND HORIZONTAL
     CD |  00002566 | BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL
     CE |  00002560 | BOX DRAWINGS DOUBLE VERTICAL AND RIGHT
     CF |  00002550 | BOX DRAWINGS DOUBLE HORIZONTAL
     D0 |  0000256C | BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL
     D1 |  0000FECC | ARABIC LETTER AIN MEDIAL FORM
     D2 |  0000063A | ARABIC LETTER GHAIN
     D3 |  0000FECE | ARABIC LETTER GHAIN FINAL FORM
     D4 |  0000FECF | ARABIC LETTER GHAIN INITIAL FORM
     D5 |  0000FED0 | ARABIC LETTER GHAIN MEDIAL FORM
     D6 |  00000641 | ARABIC LETTER FEH
     D7 |  0000FED3 | ARABIC LETTER FEH INITIAL FORM
     D8 |  00000642 | ARABIC LETTER QAF
     D9 |  0000FED7 | ARABIC LETTER QAF INITIAL FORM
     DA |  0000FEDA | ARABIC LETTER KAF FINAL FORM
     DB |  00002518 | BOX DRAWINGS LIGHT UP AND LEFT
     DC |  0000250C | BOX DRAWINGS LIGHT DOWN AND RIGHT
     DD |  00002588 | FULL BLOCK
     DE |  00002580 | UPPER HALF BLOCK
     DF |  0000FEDB | ARABIC LETTER KAF INITIAL FORM
     E1 |  00002584 | LOWER HALF BLOCK
     E3 |  00000644 | ARABIC LETTER LAM
     E4 |  0000FEDE | ARABIC LETTER LAM FINAL FORM
     E5 |  0000FEE0 | ARABIC LETTER LAM MEDIAL FORM
     E6 |  00000645 | ARABIC LETTER MEEM
     E7 |  0000FEE3 | ARABIC LETTER MEEM INITIAL FORM
     E9 |  00000646 | ARABIC LETTER NOON
     EA |  0000FEE7 | ARABIC LETTER NOON INITIAL FORM
     EC |  00000648 | ARABIC LETTER WAW
     F1 |  00000621 | ARABIC LETTER HAMZA
     F2 |  000000AD | SOFT HYPHEN
     FB |  00000651 | ARABIC SHADDA
     FC |  0000FE7D | ARABIC SHADDA MEDIAL FORM
     FE |  000025A0 | BLACK SQUARE
     FF |  000000A0 | NO-BREAK SPACE
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/IBM869.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for IBM869.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::IBM869;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x0004,
     0x0005,
     0x0006,
     0x0007,
     0x0008,
     0x0009,
     0x000a,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x0014,
     0x0015,
     0x0016,
     0x0017,
     0x0018,
     0x0019,
     0x001a,
     0x001b,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0020,
     0x0021,
     0x0022,
     0x0023,
     0x0024,
     0x0025,
     0x0026,
     0x0027,
     0x0028,
     0x0029,
     0x002a,
     0x002b,
     0x002c,
     0x002d,
     0x002e,
     0x002f,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x003a,
     0x003b,
     0x003c,
     0x003d,
     0x003e,
     0x003f,
     0x0040,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x005b,
     0x005c,
     0x005d,
     0x005e,
     0x005f,
     0x0060,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x007b,
     0x007c,
     0x007d,
     0x007e,
     0x007f,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x0386,
     0xfffd,
     0x00b7,
     0x00ac,
     0x00a6,
     0x2018,
     0x2019,
     0x0388,
     0x2015,
     0x0389,
     0x038a,
     0x03aa,
     0x038c,
     0xfffd,
     0xfffd,
     0x038e,
     0x03ab,
     0x00a9,
     0x038f,
     0x00b2,
     0x00b3,
     0x03ac,
     0x00a3,
     0x03ad,
     0x03ae,
     0x03af,
     0x03ca,
     0x0390,
     0x03cc,
     0x03cd,
     0x0391,
     0x0392,
     0x0393,
     0x0394,
     0x0395,
     0x0396,
     0x0397,
     0x00bd,
     0x0398,
     0x0399,
     0x00ab,
     0x00bb,
     0x2591,
     0x2592,
     0x2593,
     0x2502,
     0x2524,
     0x039a,
     0x039b,
     0x039c,
     0x039d,
     0x2563,
     0x2551,
     0x2557,
     0x255d,
     0x039e,
     0x039f,
     0x2510,
     0x2514,
     0x2534,
     0x252c,
     0x251c,
     0x2500,
     0x253c,
     0x03a0,
     0x03a1,
     0x255a,
     0x2554,
     0x2569,
     0x2566,
     0x2560,
     0x2550,
     0x256c,
     0x03a3,
     0x03a4,
     0x03a5,
     0x03a6,
     0x03a7,
     0x03a8,
     0x03a9,
     0x03b1,
     0x03b2,
     0x03b3,
     0x2518,
     0x250c,
     0x2588,
     0x2584,
     0x03b4,
     0x03b5,
     0x2580,
     0x03b6,
     0x03b7,
     0x03b8,
     0x03b9,
     0x03ba,
     0x03bb,
     0x03bc,
     0x03bd,
     0x03be,
     0x03bf,
     0x03c0,
     0x03c1,
     0x03c3,
     0x03c2,
     0x03c4,
     0x0384,
     0x00ad,
     0x00b1,
     0x03c5,
     0x03c6,
     0x03c7,
     0x00a7,
     0x03c8,
     0x0385,
     0x00b0,
     0x00a8,
     0x03c9,
     0x03cb,
     0x03b0,
     0x03ce,
     0x25a0,
     0x00a0,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\x04",
     "\x05",
     "\x06",
     "\x07",
     "\x08",
     "\x09",
     "\x0a",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\x14",
     "\x15",
     "\x16",
     "\x17",
     "\x18",
     "\x19",
     "\x1a",
     "\x1b",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\x20",
     "\x21",
     "\x22",
     "\x23",
     "\x24",
     "\x25",
     "\x26",
     "\x27",
     "\x28",
     "\x29",
     "\x2a",
     "\x2b",
     "\x2c",
     "\x2d",
     "\x2e",
     "\x2f",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\x3a",
     "\x3b",
     "\x3c",
     "\x3d",
     "\x3e",
     "\x3f",
     "\x40",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\x5b",
     "\x5c",
     "\x5d",
     "\x5e",
     "\x5f",
     "\x60",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\x7b",
     "\x7c",
     "\x7d",
     "\x7e",
     "\x7f",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xce\x86",
     "\xef\xbf\xbd",
     "\xc2\xb7",
     "\xc2\xac",
     "\xc2\xa6",
     "\xe2\x80\x98",
     "\xe2\x80\x99",
     "\xce\x88",
     "\xe2\x80\x95",
     "\xce\x89",
     "\xce\x8a",
     "\xce\xaa",
     "\xce\x8c",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xce\x8e",
     "\xce\xab",
     "\xc2\xa9",
     "\xce\x8f",
     "\xc2\xb2",
     "\xc2\xb3",
     "\xce\xac",
     "\xc2\xa3",
     "\xce\xad",
     "\xce\xae",
     "\xce\xaf",
     "\xcf\x8a",
     "\xce\x90",
     "\xcf\x8c",
     "\xcf\x8d",
     "\xce\x91",
     "\xce\x92",
     "\xce\x93",
     "\xce\x94",
     "\xce\x95",
     "\xce\x96",
     "\xce\x97",
     "\xc2\xbd",
     "\xce\x98",
     "\xce\x99",
     "\xc2\xab",
     "\xc2\xbb",
     "\xe2\x96\x91",
     "\xe2\x96\x92",
     "\xe2\x96\x93",
     "\xe2\x94\x82",
     "\xe2\x94\xa4",
     "\xce\x9a",
     "\xce\x9b",
     "\xce\x9c",
     "\xce\x9d",
     "\xe2\x95\xa3",
     "\xe2\x95\x91",
     "\xe2\x95\x97",
     "\xe2\x95\x9d",
     "\xce\x9e",
     "\xce\x9f",
     "\xe2\x94\x90",
     "\xe2\x94\x94",
     "\xe2\x94\xb4",
     "\xe2\x94\xac",
     "\xe2\x94\x9c",
     "\xe2\x94\x80",
     "\xe2\x94\xbc",
     "\xce\xa0",
     "\xce\xa1",
     "\xe2\x95\x9a",
     "\xe2\x95\x94",
     "\xe2\x95\xa9",
     "\xe2\x95\xa6",
     "\xe2\x95\xa0",
     "\xe2\x95\x90",
     "\xe2\x95\xac",
     "\xce\xa3",
     "\xce\xa4",
     "\xce\xa5",
     "\xce\xa6",
     "\xce\xa7",
     "\xce\xa8",
     "\xce\xa9",
     "\xce\xb1",
     "\xce\xb2",
     "\xce\xb3",
     "\xe2\x94\x98",
     "\xe2\x94\x8c",
     "\xe2\x96\x88",
     "\xe2\x96\x84",
     "\xce\xb4",
     "\xce\xb5",
     "\xe2\x96\x80",
     "\xce\xb6",
     "\xce\xb7",
     "\xce\xb8",
     "\xce\xb9",
     "\xce\xba",
     "\xce\xbb",
     "\xce\xbc",
     "\xce\xbd",
     "\xce\xbe",
     "\xce\xbf",
     "\xcf\x80",
     "\xcf\x81",
     "\xcf\x83",
     "\xcf\x82",
     "\xcf\x84",
     "\xce\x84",
     "\xc2\xad",
     "\xc2\xb1",
     "\xcf\x85",
     "\xcf\x86",
     "\xcf\x87",
     "\xc2\xa7",
     "\xcf\x88",
     "\xce\x85",
     "\xc2\xb0",
     "\xc2\xa8",
     "\xcf\x89",
     "\xcf\x8b",
     "\xce\xb0",
     "\xcf\x8e",
     "\xe2\x96\xa0",
     "\xc2\xa0",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x04",
     0x00000005 => "\x05",
     0x00000006 => "\x06",
     0x00000007 => "\x07",
     0x00000008 => "\x08",
     0x00000009 => "\x09",
     0x0000000a => "\x0a",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x14",
     0x00000015 => "\x15",
     0x00000016 => "\x16",
     0x00000017 => "\x17",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x1a",
     0x0000001b => "\x1b",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x20",
     0x00000021 => "\x21",
     0x00000022 => "\x22",
     0x00000023 => "\x23",
     0x00000024 => "\x24",
     0x00000025 => "\x25",
     0x00000026 => "\x26",
     0x00000027 => "\x27",
     0x00000028 => "\x28",
     0x00000029 => "\x29",
     0x0000002a => "\x2a",
     0x0000002b => "\x2b",
     0x0000002c => "\x2c",
     0x0000002d => "\x2d",
     0x0000002e => "\x2e",
     0x0000002f => "\x2f",
     0x00000030 => "\x30",
     0x00000031 => "\x31",
     0x00000032 => "\x32",
     0x00000033 => "\x33",
     0x00000034 => "\x34",
     0x00000035 => "\x35",
     0x00000036 => "\x36",
     0x00000037 => "\x37",
     0x00000038 => "\x38",
     0x00000039 => "\x39",
     0x0000003a => "\x3a",
     0x0000003b => "\x3b",
     0x0000003c => "\x3c",
     0x0000003d => "\x3d",
     0x0000003e => "\x3e",
     0x0000003f => "\x3f",
     0x00000040 => "\x40",
     0x00000041 => "\x41",
     0x00000042 => "\x42",
     0x00000043 => "\x43",
     0x00000044 => "\x44",
     0x00000045 => "\x45",
     0x00000046 => "\x46",
     0x00000047 => "\x47",
     0x00000048 => "\x48",
     0x00000049 => "\x49",
     0x0000004a => "\x4a",
     0x0000004b => "\x4b",
     0x0000004c => "\x4c",
     0x0000004d => "\x4d",
     0x0000004e => "\x4e",
     0x0000004f => "\x4f",
     0x00000050 => "\x50",
     0x00000051 => "\x51",
     0x00000052 => "\x52",
     0x00000053 => "\x53",
     0x00000054 => "\x54",
     0x00000055 => "\x55",
     0x00000056 => "\x56",
     0x00000057 => "\x57",
     0x00000058 => "\x58",
     0x00000059 => "\x59",
     0x0000005a => "\x5a",
     0x0000005b => "\x5b",
     0x0000005c => "\x5c",
     0x0000005d => "\x5d",
     0x0000005e => "\x5e",
     0x0000005f => "\x5f",
     0x00000060 => "\x60",
     0x00000061 => "\x61",
     0x00000062 => "\x62",
     0x00000063 => "\x63",
     0x00000064 => "\x64",
     0x00000065 => "\x65",
     0x00000066 => "\x66",
     0x00000067 => "\x67",
     0x00000068 => "\x68",
     0x00000069 => "\x69",
     0x0000006a => "\x6a",
     0x0000006b => "\x6b",
     0x0000006c => "\x6c",
     0x0000006d => "\x6d",
     0x0000006e => "\x6e",
     0x0000006f => "\x6f",
     0x00000070 => "\x70",
     0x00000071 => "\x71",
     0x00000072 => "\x72",
     0x00000073 => "\x73",
     0x00000074 => "\x74",
     0x00000075 => "\x75",
     0x00000076 => "\x76",
     0x00000077 => "\x77",
     0x00000078 => "\x78",
     0x00000079 => "\x79",
     0x0000007a => "\x7a",
     0x0000007b => "\x7b",
     0x0000007c => "\x7c",
     0x0000007d => "\x7d",
     0x0000007e => "\x7e",
     0x0000007f => "\x7f",
     0x000000a0 => "\xff",
     0x000000a3 => "\x9c",
     0x000000a6 => "\x8a",
     0x000000a7 => "\xf5",
     0x000000a8 => "\xf9",
     0x000000a9 => "\x97",
     0x000000ab => "\xae",
     0x000000ac => "\x89",
     0x000000ad => "\xf0",
     0x000000b0 => "\xf8",
     0x000000b1 => "\xf1",
     0x000000b2 => "\x99",
     0x000000b3 => "\x9a",
     0x000000b7 => "\x88",
     0x000000bb => "\xaf",
     0x000000bd => "\xab",
     0x00000384 => "\xef",
     0x00000385 => "\xf7",
     0x00000386 => "\x86",
     0x00000388 => "\x8d",
     0x00000389 => "\x8f",
     0x0000038a => "\x90",
     0x0000038c => "\x92",
     0x0000038e => "\x95",
     0x0000038f => "\x98",
     0x00000390 => "\xa1",
     0x00000391 => "\xa4",
     0x00000392 => "\xa5",
     0x00000393 => "\xa6",
     0x00000394 => "\xa7",
     0x00000395 => "\xa8",
     0x00000396 => "\xa9",
     0x00000397 => "\xaa",
     0x00000398 => "\xac",
     0x00000399 => "\xad",
     0x0000039a => "\xb5",
     0x0000039b => "\xb6",
     0x0000039c => "\xb7",
     0x0000039d => "\xb8",
     0x0000039e => "\xbd",
     0x0000039f => "\xbe",
     0x000003a0 => "\xc6",
     0x000003a1 => "\xc7",
     0x000003a3 => "\xcf",
     0x000003a4 => "\xd0",
     0x000003a5 => "\xd1",
     0x000003a6 => "\xd2",
     0x000003a7 => "\xd3",
     0x000003a8 => "\xd4",
     0x000003a9 => "\xd5",
     0x000003aa => "\x91",
     0x000003ab => "\x96",
     0x000003ac => "\x9b",
     0x000003ad => "\x9d",
     0x000003ae => "\x9e",
     0x000003af => "\x9f",
     0x000003b0 => "\xfc",
     0x000003b1 => "\xd6",
     0x000003b2 => "\xd7",
     0x000003b3 => "\xd8",
     0x000003b4 => "\xdd",
     0x000003b5 => "\xde",
     0x000003b6 => "\xe0",
     0x000003b7 => "\xe1",
     0x000003b8 => "\xe2",
     0x000003b9 => "\xe3",
     0x000003ba => "\xe4",
     0x000003bb => "\xe5",
     0x000003bc => "\xe6",
     0x000003bd => "\xe7",
     0x000003be => "\xe8",
     0x000003bf => "\xe9",
     0x000003c0 => "\xea",
     0x000003c1 => "\xeb",
     0x000003c2 => "\xed",
     0x000003c3 => "\xec",
     0x000003c4 => "\xee",
     0x000003c5 => "\xf2",
     0x000003c6 => "\xf3",
     0x000003c7 => "\xf4",
     0x000003c8 => "\xf6",
     0x000003c9 => "\xfa",
     0x000003ca => "\xa0",
     0x000003cb => "\xfb",
     0x000003cc => "\xa2",
     0x000003cd => "\xa3",
     0x000003ce => "\xfd",
     0x00002015 => "\x8e",
     0x00002018 => "\x8b",
     0x00002019 => "\x8c",
     0x00002500 => "\xc4",
     0x00002502 => "\xb3",
     0x0000250c => "\xda",
     0x00002510 => "\xbf",
     0x00002514 => "\xc0",
     0x00002518 => "\xd9",
     0x0000251c => "\xc3",
     0x00002524 => "\xb4",
     0x0000252c => "\xc2",
     0x00002534 => "\xc1",
     0x0000253c => "\xc5",
     0x00002550 => "\xcd",
     0x00002551 => "\xba",
     0x00002554 => "\xc9",
     0x00002557 => "\xbb",
     0x0000255a => "\xc8",
     0x0000255d => "\xbc",
     0x00002560 => "\xcc",
     0x00002563 => "\xb9",
     0x00002566 => "\xcb",
     0x00002569 => "\xca",
     0x0000256c => "\xce",
     0x00002580 => "\xdf",
     0x00002584 => "\xdc",
     0x00002588 => "\xdb",
     0x00002591 => "\xb0",
     0x00002592 => "\xb1",
     0x00002593 => "\xb2",
     0x000025a0 => "\xfe",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::IBM869 - Conversion routines for IBM869
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for IBM869.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
   source: IBM Keyboard layouts and code pages, PN 07G4586 June 1991
  alias CP869
  alias 869
  alias CP-GR
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  00000004 | END OF TRANSMISSION (EOT)
     05 |  00000005 | ENQUIRY (ENQ)
     06 |  00000006 | ACKNOWLEDGE (ACK)
     07 |  00000007 | BELL (BEL)
     08 |  00000008 | BACKSPACE (BS)
     09 |  00000009 | CHARACTER TABULATION (HT)
     0A |  0000000A | LINE FEED (LF)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  00000014 | DEVICE CONTROL FOUR (DC4)
     15 |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     16 |  00000016 | SYNCHRONOUS IDLE (SYN)
     17 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  0000001A | SUBSTITUTE (SUB)
     1B |  0000001B | ESCAPE (ESC)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000020 | SPACE
     21 |  00000021 | EXCLAMATION MARK
     22 |  00000022 | QUOTATION MARK
     23 |  00000023 | NUMBER SIGN
     24 |  00000024 | DOLLAR SIGN
     25 |  00000025 | PERCENT SIGN
     26 |  00000026 | AMPERSAND
     27 |  00000027 | APOSTROPHE
     28 |  00000028 | LEFT PARENTHESIS
     29 |  00000029 | RIGHT PARENTHESIS
     2A |  0000002A | ASTERISK
     2B |  0000002B | PLUS SIGN
     2C |  0000002C | COMMA
     2D |  0000002D | HYPHEN-MINUS
     2E |  0000002E | FULL STOP
     2F |  0000002F | SOLIDUS
     30 |  00000030 | DIGIT ZERO
     31 |  00000031 | DIGIT ONE
     32 |  00000032 | DIGIT TWO
     33 |  00000033 | DIGIT THREE
     34 |  00000034 | DIGIT FOUR
     35 |  00000035 | DIGIT FIVE
     36 |  00000036 | DIGIT SIX
     37 |  00000037 | DIGIT SEVEN
     38 |  00000038 | DIGIT EIGHT
     39 |  00000039 | DIGIT NINE
     3A |  0000003A | COLON
     3B |  0000003B | SEMICOLON
     3C |  0000003C | LESS-THAN SIGN
     3D |  0000003D | EQUALS SIGN
     3E |  0000003E | GREATER-THAN SIGN
     3F |  0000003F | QUESTION MARK
     40 |  00000040 | COMMERCIAL AT
     41 |  00000041 | LATIN CAPITAL LETTER A
     42 |  00000042 | LATIN CAPITAL LETTER B
     43 |  00000043 | LATIN CAPITAL LETTER C
     44 |  00000044 | LATIN CAPITAL LETTER D
     45 |  00000045 | LATIN CAPITAL LETTER E
     46 |  00000046 | LATIN CAPITAL LETTER F
     47 |  00000047 | LATIN CAPITAL LETTER G
     48 |  00000048 | LATIN CAPITAL LETTER H
     49 |  00000049 | LATIN CAPITAL LETTER I
     4A |  0000004A | LATIN CAPITAL LETTER J
     4B |  0000004B | LATIN CAPITAL LETTER K
     4C |  0000004C | LATIN CAPITAL LETTER L
     4D |  0000004D | LATIN CAPITAL LETTER M
     4E |  0000004E | LATIN CAPITAL LETTER N
     4F |  0000004F | LATIN CAPITAL LETTER O
     50 |  00000050 | LATIN CAPITAL LETTER P
     51 |  00000051 | LATIN CAPITAL LETTER Q
     52 |  00000052 | LATIN CAPITAL LETTER R
     53 |  00000053 | LATIN CAPITAL LETTER S
     54 |  00000054 | LATIN CAPITAL LETTER T
     55 |  00000055 | LATIN CAPITAL LETTER U
     56 |  00000056 | LATIN CAPITAL LETTER V
     57 |  00000057 | LATIN CAPITAL LETTER W
     58 |  00000058 | LATIN CAPITAL LETTER X
     59 |  00000059 | LATIN CAPITAL LETTER Y
     5A |  0000005A | LATIN CAPITAL LETTER Z
     5B |  0000005B | LEFT SQUARE BRACKET
     5C |  0000005C | REVERSE SOLIDUS
     5D |  0000005D | RIGHT SQUARE BRACKET
     5E |  0000005E | CIRCUMFLEX ACCENT
     5F |  0000005F | LOW LINE
     60 |  00000060 | GRAVE ACCENT
     61 |  00000061 | LATIN SMALL LETTER A
     62 |  00000062 | LATIN SMALL LETTER B
     63 |  00000063 | LATIN SMALL LETTER C
     64 |  00000064 | LATIN SMALL LETTER D
     65 |  00000065 | LATIN SMALL LETTER E
     66 |  00000066 | LATIN SMALL LETTER F
     67 |  00000067 | LATIN SMALL LETTER G
     68 |  00000068 | LATIN SMALL LETTER H
     69 |  00000069 | LATIN SMALL LETTER I
     6A |  0000006A | LATIN SMALL LETTER J
     6B |  0000006B | LATIN SMALL LETTER K
     6C |  0000006C | LATIN SMALL LETTER L
     6D |  0000006D | LATIN SMALL LETTER M
     6E |  0000006E | LATIN SMALL LETTER N
     6F |  0000006F | LATIN SMALL LETTER O
     70 |  00000070 | LATIN SMALL LETTER P
     71 |  00000071 | LATIN SMALL LETTER Q
     72 |  00000072 | LATIN SMALL LETTER R
     73 |  00000073 | LATIN SMALL LETTER S
     74 |  00000074 | LATIN SMALL LETTER T
     75 |  00000075 | LATIN SMALL LETTER U
     76 |  00000076 | LATIN SMALL LETTER V
     77 |  00000077 | LATIN SMALL LETTER W
     78 |  00000078 | LATIN SMALL LETTER X
     79 |  00000079 | LATIN SMALL LETTER Y
     7A |  0000007A | LATIN SMALL LETTER Z
     7B |  0000007B | LEFT CURLY BRACKET
     7C |  0000007C | VERTICAL LINE
     7D |  0000007D | RIGHT CURLY BRACKET
     7E |  0000007E | TILDE
     7F |  0000007F | DELETE (DEL)
     86 |  00000386 | GREEK CAPITAL LETTER ALPHA WITH TONOS
     88 |  000000B7 | MIDDLE DOT
     89 |  000000AC | NOT SIGN
     8A |  000000A6 | BROKEN BAR
     8B |  00002018 | LEFT SINGLE QUOTATION MARK
     8C |  00002019 | RIGHT SINGLE QUOTATION MARK
     8D |  00000388 | GREEK CAPITAL LETTER EPSILON WITH TONOS
     8E |  00002015 | HORIZONTAL BAR
     8F |  00000389 | GREEK CAPITAL LETTER ETA WITH TONOS
     90 |  0000038A | GREEK CAPITAL LETTER IOTA WITH TONOS
     91 |  000003AA | GREEK CAPITAL LETTER IOTA WITH DIALYTIKA
     92 |  0000038C | GREEK CAPITAL LETTER OMICRON WITH TONOS
     95 |  0000038E | GREEK CAPITAL LETTER UPSILON WITH TONOS
     96 |  000003AB | GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA
     97 |  000000A9 | COPYRIGHT SIGN
     98 |  0000038F | GREEK CAPITAL LETTER OMEGA WITH TONOS
     99 |  000000B2 | SUPERSCRIPT TWO
     9A |  000000B3 | SUPERSCRIPT THREE
     9B |  000003AC | GREEK SMALL LETTER ALPHA WITH TONOS
     9C |  000000A3 | POUND SIGN
     9D |  000003AD | GREEK SMALL LETTER EPSILON WITH TONOS
     9E |  000003AE | GREEK SMALL LETTER ETA WITH TONOS
     9F |  000003AF | GREEK SMALL LETTER IOTA WITH TONOS
     A0 |  000003CA | GREEK SMALL LETTER IOTA WITH DIALYTIKA
     A1 |  00000390 | GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS
     A2 |  000003CC | GREEK SMALL LETTER OMICRON WITH TONOS
     A3 |  000003CD | GREEK SMALL LETTER UPSILON WITH TONOS
     A4 |  00000391 | GREEK CAPITAL LETTER ALPHA
     A5 |  00000392 | GREEK CAPITAL LETTER BETA
     A6 |  00000393 | GREEK CAPITAL LETTER GAMMA
     A7 |  00000394 | GREEK CAPITAL LETTER DELTA
     A8 |  00000395 | GREEK CAPITAL LETTER EPSILON
     A9 |  00000396 | GREEK CAPITAL LETTER ZETA
     AA |  00000397 | GREEK CAPITAL LETTER ETA
     AB |  000000BD | VULGAR FRACTION ONE HALF
     AC |  00000398 | GREEK CAPITAL LETTER THETA
     AD |  00000399 | GREEK CAPITAL LETTER IOTA
     AE |  000000AB | LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
     AF |  000000BB | RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
     B0 |  00002591 | LIGHT SHADE
     B1 |  00002592 | MEDIUM SHADE
     B2 |  00002593 | DARK SHADE
     B3 |  00002502 | BOX DRAWINGS LIGHT VERTICAL
     B4 |  00002524 | BOX DRAWINGS LIGHT VERTICAL AND LEFT
     B5 |  0000039A | GREEK CAPITAL LETTER KAPPA
     B6 |  0000039B | GREEK CAPITAL LETTER LAMDA
     B7 |  0000039C | GREEK CAPITAL LETTER MU
     B8 |  0000039D | GREEK CAPITAL LETTER NU
     B9 |  00002563 | BOX DRAWINGS DOUBLE VERTICAL AND LEFT
     BA |  00002551 | BOX DRAWINGS DOUBLE VERTICAL
     BB |  00002557 | BOX DRAWINGS DOUBLE DOWN AND LEFT
     BC |  0000255D | BOX DRAWINGS DOUBLE UP AND LEFT
     BD |  0000039E | GREEK CAPITAL LETTER XI
     BE |  0000039F | GREEK CAPITAL LETTER OMICRON
     BF |  00002510 | BOX DRAWINGS LIGHT DOWN AND LEFT
     C0 |  00002514 | BOX DRAWINGS LIGHT UP AND RIGHT
     C1 |  00002534 | BOX DRAWINGS LIGHT UP AND HORIZONTAL
     C2 |  0000252C | BOX DRAWINGS LIGHT DOWN AND HORIZONTAL
     C3 |  0000251C | BOX DRAWINGS LIGHT VERTICAL AND RIGHT
     C4 |  00002500 | BOX DRAWINGS LIGHT HORIZONTAL
     C5 |  0000253C | BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL
     C6 |  000003A0 | GREEK CAPITAL LETTER PI
     C7 |  000003A1 | GREEK CAPITAL LETTER RHO
     C8 |  0000255A | BOX DRAWINGS DOUBLE UP AND RIGHT
     C9 |  00002554 | BOX DRAWINGS DOUBLE DOWN AND RIGHT
     CA |  00002569 | BOX DRAWINGS DOUBLE UP AND HORIZONTAL
     CB |  00002566 | BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL
     CC |  00002560 | BOX DRAWINGS DOUBLE VERTICAL AND RIGHT
     CD |  00002550 | BOX DRAWINGS DOUBLE HORIZONTAL
     CE |  0000256C | BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL
     CF |  000003A3 | GREEK CAPITAL LETTER SIGMA
     D0 |  000003A4 | GREEK CAPITAL LETTER TAU
     D1 |  000003A5 | GREEK CAPITAL LETTER UPSILON
     D2 |  000003A6 | GREEK CAPITAL LETTER PHI
     D3 |  000003A7 | GREEK CAPITAL LETTER CHI
     D4 |  000003A8 | GREEK CAPITAL LETTER PSI
     D5 |  000003A9 | GREEK CAPITAL LETTER OMEGA
     D6 |  000003B1 | GREEK SMALL LETTER ALPHA
     D7 |  000003B2 | GREEK SMALL LETTER BETA
     D8 |  000003B3 | GREEK SMALL LETTER GAMMA
     D9 |  00002518 | BOX DRAWINGS LIGHT UP AND LEFT
     DA |  0000250C | BOX DRAWINGS LIGHT DOWN AND RIGHT
     DB |  00002588 | FULL BLOCK
     DC |  00002584 | LOWER HALF BLOCK
     DD |  000003B4 | GREEK SMALL LETTER DELTA
     DE |  000003B5 | GREEK SMALL LETTER EPSILON
     DF |  00002580 | UPPER HALF BLOCK
     E0 |  000003B6 | GREEK SMALL LETTER ZETA
     E1 |  000003B7 | GREEK SMALL LETTER ETA
     E2 |  000003B8 | GREEK SMALL LETTER THETA
     E3 |  000003B9 | GREEK SMALL LETTER IOTA
     E4 |  000003BA | GREEK SMALL LETTER KAPPA
     E5 |  000003BB | GREEK SMALL LETTER LAMDA
     E6 |  000003BC | GREEK SMALL LETTER MU
     E7 |  000003BD | GREEK SMALL LETTER NU
     E8 |  000003BE | GREEK SMALL LETTER XI
     E9 |  000003BF | GREEK SMALL LETTER OMICRON
     EA |  000003C0 | GREEK SMALL LETTER PI
     EB |  000003C1 | GREEK SMALL LETTER RHO
     EC |  000003C3 | GREEK SMALL LETTER SIGMA
     ED |  000003C2 | GREEK SMALL LETTER FINAL SIGMA
     EE |  000003C4 | GREEK SMALL LETTER TAU
     EF |  00000384 | GREEK TONOS
     F0 |  000000AD | SOFT HYPHEN
     F1 |  000000B1 | PLUS-MINUS SIGN
     F2 |  000003C5 | GREEK SMALL LETTER UPSILON
     F3 |  000003C6 | GREEK SMALL LETTER PHI
     F4 |  000003C7 | GREEK SMALL LETTER CHI
     F5 |  000000A7 | SECTION SIGN
     F6 |  000003C8 | GREEK SMALL LETTER PSI
     F7 |  00000385 | GREEK DIALYTIKA TONOS
     F8 |  000000B0 | DEGREE SIGN
     F9 |  000000A8 | DIAERESIS
     FA |  000003C9 | GREEK SMALL LETTER OMEGA
     FB |  000003CB | GREEK SMALL LETTER UPSILON WITH DIALYTIKA
     FC |  000003B0 | GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS
     FD |  000003CE | GREEK SMALL LETTER OMEGA WITH TONOS
     FE |  000025A0 | BLACK SQUARE
     FF |  000000A0 | NO-BREAK SPACE
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/IBM870.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for IBM870.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::IBM870;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x009c,
     0x0009,
     0x0086,
     0x007f,
     0x0097,
     0x008d,
     0x008e,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x009d,
     0x0085,
     0x0008,
     0x0087,
     0x0018,
     0x0019,
     0x0092,
     0x008f,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0080,
     0x0081,
     0x0082,
     0x0083,
     0x0084,
     0x000a,
     0x0017,
     0x001b,
     0x0088,
     0x0089,
     0x008a,
     0x008b,
     0x008c,
     0x0005,
     0x0006,
     0x0007,
     0x0090,
     0x0091,
     0x0016,
     0x0093,
     0x0094,
     0x0095,
     0x0096,
     0x0004,
     0x0098,
     0x0099,
     0x009a,
     0x009b,
     0x0014,
     0x0015,
     0x009e,
     0x001a,
     0x0020,
     0x00a0,
     0xfffd,
     0x00e4,
     0xfffd,
     0x00e1,
     0x0103,
     0x010d,
     0x00e7,
     0x0107,
     0x005b,
     0x002e,
     0x003c,
     0x0028,
     0x002b,
     0x0021,
     0x0026,
     0x00e9,
     0xfffd,
     0x00eb,
     0x016f,
     0x00ed,
     0xfffd,
     0x013e,
     0x013a,
     0x00df,
     0x005d,
     0x0024,
     0x002a,
     0x0029,
     0x003b,
     0x005e,
     0x002d,
     0x002f,
     0xfffd,
     0x00c4,
     0x02dd,
     0x00c1,
     0xfffd,
     0x010c,
     0x00c7,
     0x0106,
     0x007c,
     0x002c,
     0x0025,
     0x005f,
     0x003e,
     0x003f,
     0x02c7,
     0x00c9,
     0xfffd,
     0x00cb,
     0x016e,
     0x00cd,
     0xfffd,
     0x013d,
     0x0139,
     0x0060,
     0x003a,
     0x0023,
     0x0040,
     0x0027,
     0x003d,
     0x0022,
     0x02d8,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x015b,
     0x0148,
     0x0111,
     0x00fd,
     0x0159,
     0xfffd,
     0x00b0,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x0142,
     0x0144,
     0x0161,
     0x00b8,
     0x02db,
     0x00a4,
     0x0105,
     0x007e,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x015a,
     0x0147,
     0x0110,
     0x00dd,
     0x0158,
     0xfffd,
     0x00b7,
     0x0104,
     0x017c,
     0xfffd,
     0x017b,
     0x00a7,
     0x00b6,
     0x017e,
     0x017a,
     0x017d,
     0x0179,
     0x0143,
     0x0160,
     0x00a8,
     0x00b4,
     0x00d7,
     0x007b,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x00ad,
     0x00f4,
     0x00f6,
     0x0155,
     0x00f3,
     0x0151,
     0x007d,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x011a,
     0x0171,
     0x00fc,
     0x0165,
     0x00fa,
     0x011b,
     0x005c,
     0x00f7,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x010f,
     0x00d4,
     0x00d6,
     0x0154,
     0x00d3,
     0x0150,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x010e,
     0x0170,
     0x00dc,
     0x0164,
     0x00da,
     0x009f,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\xc2\x9c",
     "\x09",
     "\xc2\x86",
     "\x7f",
     "\xc2\x97",
     "\xc2\x8d",
     "\xc2\x8e",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\xc2\x9d",
     "\xc2\x85",
     "\x08",
     "\xc2\x87",
     "\x18",
     "\x19",
     "\xc2\x92",
     "\xc2\x8f",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\xc2\x80",
     "\xc2\x81",
     "\xc2\x82",
     "\xc2\x83",
     "\xc2\x84",
     "\x0a",
     "\x17",
     "\x1b",
     "\xc2\x88",
     "\xc2\x89",
     "\xc2\x8a",
     "\xc2\x8b",
     "\xc2\x8c",
     "\x05",
     "\x06",
     "\x07",
     "\xc2\x90",
     "\xc2\x91",
     "\x16",
     "\xc2\x93",
     "\xc2\x94",
     "\xc2\x95",
     "\xc2\x96",
     "\x04",
     "\xc2\x98",
     "\xc2\x99",
     "\xc2\x9a",
     "\xc2\x9b",
     "\x14",
     "\x15",
     "\xc2\x9e",
     "\x1a",
     "\x20",
     "\xc2\xa0",
     "\xef\xbf\xbd",
     "\xc3\xa4",
     "\xef\xbf\xbd",
     "\xc3\xa1",
     "\xc4\x83",
     "\xc4\x8d",
     "\xc3\xa7",
     "\xc4\x87",
     "\x5b",
     "\x2e",
     "\x3c",
     "\x28",
     "\x2b",
     "\x21",
     "\x26",
     "\xc3\xa9",
     "\xef\xbf\xbd",
     "\xc3\xab",
     "\xc5\xaf",
     "\xc3\xad",
     "\xef\xbf\xbd",
     "\xc4\xbe",
     "\xc4\xba",
     "\xc3\x9f",
     "\x5d",
     "\x24",
     "\x2a",
     "\x29",
     "\x3b",
     "\x5e",
     "\x2d",
     "\x2f",
     "\xef\xbf\xbd",
     "\xc3\x84",
     "\xcb\x9d",
     "\xc3\x81",
     "\xef\xbf\xbd",
     "\xc4\x8c",
     "\xc3\x87",
     "\xc4\x86",
     "\x7c",
     "\x2c",
     "\x25",
     "\x5f",
     "\x3e",
     "\x3f",
     "\xcb\x87",
     "\xc3\x89",
     "\xef\xbf\xbd",
     "\xc3\x8b",
     "\xc5\xae",
     "\xc3\x8d",
     "\xef\xbf\xbd",
     "\xc4\xbd",
     "\xc4\xb9",
     "\x60",
     "\x3a",
     "\x23",
     "\x40",
     "\x27",
     "\x3d",
     "\x22",
     "\xcb\x98",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\xc5\x9b",
     "\xc5\x88",
     "\xc4\x91",
     "\xc3\xbd",
     "\xc5\x99",
     "\xef\xbf\xbd",
     "\xc2\xb0",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\xc5\x82",
     "\xc5\x84",
     "\xc5\xa1",
     "\xc2\xb8",
     "\xcb\x9b",
     "\xc2\xa4",
     "\xc4\x85",
     "\x7e",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\xc5\x9a",
     "\xc5\x87",
     "\xc4\x90",
     "\xc3\x9d",
     "\xc5\x98",
     "\xef\xbf\xbd",
     "\xc2\xb7",
     "\xc4\x84",
     "\xc5\xbc",
     "\xef\xbf\xbd",
     "\xc5\xbb",
     "\xc2\xa7",
     "\xc2\xb6",
     "\xc5\xbe",
     "\xc5\xba",
     "\xc5\xbd",
     "\xc5\xb9",
     "\xc5\x83",
     "\xc5\xa0",
     "\xc2\xa8",
     "\xc2\xb4",
     "\xc3\x97",
     "\x7b",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\xc2\xad",
     "\xc3\xb4",
     "\xc3\xb6",
     "\xc5\x95",
     "\xc3\xb3",
     "\xc5\x91",
     "\x7d",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\xc4\x9a",
     "\xc5\xb1",
     "\xc3\xbc",
     "\xc5\xa5",
     "\xc3\xba",
     "\xc4\x9b",
     "\x5c",
     "\xc3\xb7",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\xc4\x8f",
     "\xc3\x94",
     "\xc3\x96",
     "\xc5\x94",
     "\xc3\x93",
     "\xc5\x90",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\xc4\x8e",
     "\xc5\xb0",
     "\xc3\x9c",
     "\xc5\xa4",
     "\xc3\x9a",
     "\xc2\x9f",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x37",
     0x00000005 => "\x2d",
     0x00000006 => "\x2e",
     0x00000007 => "\x2f",
     0x00000008 => "\x16",
     0x00000009 => "\x05",
     0x0000000a => "\x25",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x3c",
     0x00000015 => "\x3d",
     0x00000016 => "\x32",
     0x00000017 => "\x26",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x3f",
     0x0000001b => "\x27",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x40",
     0x00000021 => "\x4f",
     0x00000022 => "\x7f",
     0x00000023 => "\x7b",
     0x00000024 => "\x5b",
     0x00000025 => "\x6c",
     0x00000026 => "\x50",
     0x00000027 => "\x7d",
     0x00000028 => "\x4d",
     0x00000029 => "\x5d",
     0x0000002a => "\x5c",
     0x0000002b => "\x4e",
     0x0000002c => "\x6b",
     0x0000002d => "\x60",
     0x0000002e => "\x4b",
     0x0000002f => "\x61",
     0x00000030 => "\xf0",
     0x00000031 => "\xf1",
     0x00000032 => "\xf2",
     0x00000033 => "\xf3",
     0x00000034 => "\xf4",
     0x00000035 => "\xf5",
     0x00000036 => "\xf6",
     0x00000037 => "\xf7",
     0x00000038 => "\xf8",
     0x00000039 => "\xf9",
     0x0000003a => "\x7a",
     0x0000003b => "\x5e",
     0x0000003c => "\x4c",
     0x0000003d => "\x7e",
     0x0000003e => "\x6e",
     0x0000003f => "\x6f",
     0x00000040 => "\x7c",
     0x00000041 => "\xc1",
     0x00000042 => "\xc2",
     0x00000043 => "\xc3",
     0x00000044 => "\xc4",
     0x00000045 => "\xc5",
     0x00000046 => "\xc6",
     0x00000047 => "\xc7",
     0x00000048 => "\xc8",
     0x00000049 => "\xc9",
     0x0000004a => "\xd1",
     0x0000004b => "\xd2",
     0x0000004c => "\xd3",
     0x0000004d => "\xd4",
     0x0000004e => "\xd5",
     0x0000004f => "\xd6",
     0x00000050 => "\xd7",
     0x00000051 => "\xd8",
     0x00000052 => "\xd9",
     0x00000053 => "\xe2",
     0x00000054 => "\xe3",
     0x00000055 => "\xe4",
     0x00000056 => "\xe5",
     0x00000057 => "\xe6",
     0x00000058 => "\xe7",
     0x00000059 => "\xe8",
     0x0000005a => "\xe9",
     0x0000005b => "\x4a",
     0x0000005c => "\xe0",
     0x0000005d => "\x5a",
     0x0000005e => "\x5f",
     0x0000005f => "\x6d",
     0x00000060 => "\x79",
     0x00000061 => "\x81",
     0x00000062 => "\x82",
     0x00000063 => "\x83",
     0x00000064 => "\x84",
     0x00000065 => "\x85",
     0x00000066 => "\x86",
     0x00000067 => "\x87",
     0x00000068 => "\x88",
     0x00000069 => "\x89",
     0x0000006a => "\x91",
     0x0000006b => "\x92",
     0x0000006c => "\x93",
     0x0000006d => "\x94",
     0x0000006e => "\x95",
     0x0000006f => "\x96",
     0x00000070 => "\x97",
     0x00000071 => "\x98",
     0x00000072 => "\x99",
     0x00000073 => "\xa2",
     0x00000074 => "\xa3",
     0x00000075 => "\xa4",
     0x00000076 => "\xa5",
     0x00000077 => "\xa6",
     0x00000078 => "\xa7",
     0x00000079 => "\xa8",
     0x0000007a => "\xa9",
     0x0000007b => "\xc0",
     0x0000007c => "\x6a",
     0x0000007d => "\xd0",
     0x0000007e => "\xa1",
     0x0000007f => "\x07",
     0x00000080 => "\x20",
     0x00000081 => "\x21",
     0x00000082 => "\x22",
     0x00000083 => "\x23",
     0x00000084 => "\x24",
     0x00000085 => "\x15",
     0x00000086 => "\x06",
     0x00000087 => "\x17",
     0x00000088 => "\x28",
     0x00000089 => "\x29",
     0x0000008a => "\x2a",
     0x0000008b => "\x2b",
     0x0000008c => "\x2c",
     0x0000008d => "\x09",
     0x0000008e => "\x0a",
     0x0000008f => "\x1b",
     0x00000090 => "\x30",
     0x00000091 => "\x31",
     0x00000092 => "\x1a",
     0x00000093 => "\x33",
     0x00000094 => "\x34",
     0x00000095 => "\x35",
     0x00000096 => "\x36",
     0x00000097 => "\x08",
     0x00000098 => "\x38",
     0x00000099 => "\x39",
     0x0000009a => "\x3a",
     0x0000009b => "\x3b",
     0x0000009c => "\x04",
     0x0000009d => "\x14",
     0x0000009e => "\x3e",
     0x0000009f => "\xff",
     0x000000a0 => "\x41",
     0x000000a4 => "\x9f",
     0x000000a7 => "\xb5",
     0x000000a8 => "\xbd",
     0x000000ad => "\xca",
     0x000000b0 => "\x90",
     0x000000b4 => "\xbe",
     0x000000b6 => "\xb6",
     0x000000b7 => "\xb0",
     0x000000b8 => "\x9d",
     0x000000c1 => "\x65",
     0x000000c4 => "\x63",
     0x000000c7 => "\x68",
     0x000000c9 => "\x71",
     0x000000cb => "\x73",
     0x000000cd => "\x75",
     0x000000d3 => "\xee",
     0x000000d4 => "\xeb",
     0x000000d6 => "\xec",
     0x000000d7 => "\xbf",
     0x000000da => "\xfe",
     0x000000dc => "\xfc",
     0x000000dd => "\xad",
     0x000000df => "\x59",
     0x000000e1 => "\x45",
     0x000000e4 => "\x43",
     0x000000e7 => "\x48",
     0x000000e9 => "\x51",
     0x000000eb => "\x53",
     0x000000ed => "\x55",
     0x000000f3 => "\xce",
     0x000000f4 => "\xcb",
     0x000000f6 => "\xcc",
     0x000000f7 => "\xe1",
     0x000000fa => "\xde",
     0x000000fc => "\xdc",
     0x000000fd => "\x8d",
     0x00000103 => "\x46",
     0x00000104 => "\xb1",
     0x00000105 => "\xa0",
     0x00000106 => "\x69",
     0x00000107 => "\x49",
     0x0000010c => "\x67",
     0x0000010d => "\x47",
     0x0000010e => "\xfa",
     0x0000010f => "\xea",
     0x00000110 => "\xac",
     0x00000111 => "\x8c",
     0x0000011a => "\xda",
     0x0000011b => "\xdf",
     0x00000139 => "\x78",
     0x0000013a => "\x58",
     0x0000013d => "\x77",
     0x0000013e => "\x57",
     0x00000142 => "\x9a",
     0x00000143 => "\xbb",
     0x00000144 => "\x9b",
     0x00000147 => "\xab",
     0x00000148 => "\x8b",
     0x00000150 => "\xef",
     0x00000151 => "\xcf",
     0x00000154 => "\xed",
     0x00000155 => "\xcd",
     0x00000158 => "\xae",
     0x00000159 => "\x8e",
     0x0000015a => "\xaa",
     0x0000015b => "\x8a",
     0x00000160 => "\xbc",
     0x00000161 => "\x9c",
     0x00000164 => "\xfd",
     0x00000165 => "\xdd",
     0x0000016e => "\x74",
     0x0000016f => "\x54",
     0x00000170 => "\xfb",
     0x00000171 => "\xdb",
     0x00000179 => "\xba",
     0x0000017a => "\xb8",
     0x0000017b => "\xb4",
     0x0000017c => "\xb2",
     0x0000017d => "\xb9",
     0x0000017e => "\xb7",
     0x000002c7 => "\x70",
     0x000002d8 => "\x80",
     0x000002db => "\x9e",
     0x000002dd => "\x64",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x6f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::IBM870 - Conversion routines for IBM870
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for IBM870.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
   source: IBM NLS RM Vol2 SE09-8002-01, March 1990
  alias CP870
  alias EBCDIC-CP-ROECE
  alias EBCDIC-CP-YU
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  0000009C | STRING TERMINATOR (ST)
     05 |  00000009 | CHARACTER TABULATION (HT)
     06 |  00000086 | START OF SELECTED AREA (SSA)
     07 |  0000007F | DELETE (DEL)
     08 |  00000097 | END OF GUARDED AREA (EPA)
     09 |  0000008D | REVERSE LINE FEED (RI)
     0A |  0000008E | SINGLE-SHIFT TWO (SS2)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  0000009D | OPERATING SYSTEM COMMAND (OSC)
     15 |  00000085 | NEXT LINE (NEL)
     16 |  00000008 | BACKSPACE (BS)
     17 |  00000087 | END OF SELECTED AREA (ESA)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  00000092 | PRIVATE USE TWO (PU2)
     1B |  0000008F | SINGLE-SHIFT THREE (SS3)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000080 | PADDING CHARACTER (PAD)
     21 |  00000081 | HIGH OCTET PRESET (HOP)
     22 |  00000082 | BREAK PERMITTED HERE (BPH)
     23 |  00000083 | NO BREAK HERE (NBH)
     24 |  00000084 | INDEX (IND)
     25 |  0000000A | LINE FEED (LF)
     26 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     27 |  0000001B | ESCAPE (ESC)
     28 |  00000088 | CHARACTER TABULATION SET (HTS)
     29 |  00000089 | CHARACTER TABULATION WITH JUSTIFICATION (HTJ)
     2A |  0000008A | LINE TABULATION SET (VTS)
     2B |  0000008B | PARTIAL LINE FORWARD (PLD)
     2C |  0000008C | PARTIAL LINE BACKWARD (PLU)
     2D |  00000005 | ENQUIRY (ENQ)
     2E |  00000006 | ACKNOWLEDGE (ACK)
     2F |  00000007 | BELL (BEL)
     30 |  00000090 | DEVICE CONTROL STRING (DCS)
     31 |  00000091 | PRIVATE USE ONE (PU1)
     32 |  00000016 | SYNCHRONOUS IDLE (SYN)
     33 |  00000093 | SET TRANSMIT STATE (STS)
     34 |  00000094 | CANCEL CHARACTER (CCH)
     35 |  00000095 | MESSAGE WAITING (MW)
     36 |  00000096 | START OF GUARDED AREA (SPA)
     37 |  00000004 | END OF TRANSMISSION (EOT)
     38 |  00000098 | START OF STRING (SOS)
     39 |  00000099 | SINGLE GRAPHIC CHARACTER INTRODUCER (SGCI)
     3A |  0000009A | SINGLE CHARACTER INTRODUCER (SCI)
     3B |  0000009B | CONTROL SEQUENCE INTRODUCER (CSI)
     3C |  00000014 | DEVICE CONTROL FOUR (DC4)
     3D |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     3E |  0000009E | PRIVACY MESSAGE (PM)
     3F |  0000001A | SUBSTITUTE (SUB)
     40 |  00000020 | SPACE
     41 |  000000A0 | NO-BREAK SPACE
     43 |  000000E4 | LATIN SMALL LETTER A WITH DIAERESIS
     45 |  000000E1 | LATIN SMALL LETTER A WITH ACUTE
     46 |  00000103 | LATIN SMALL LETTER A WITH BREVE
     47 |  0000010D | LATIN SMALL LETTER C WITH CARON
     48 |  000000E7 | LATIN SMALL LETTER C WITH CEDILLA
     49 |  00000107 | LATIN SMALL LETTER C WITH ACUTE
     4A |  0000005B | LEFT SQUARE BRACKET
     4B |  0000002E | FULL STOP
     4C |  0000003C | LESS-THAN SIGN
     4D |  00000028 | LEFT PARENTHESIS
     4E |  0000002B | PLUS SIGN
     4F |  00000021 | EXCLAMATION MARK
     50 |  00000026 | AMPERSAND
     51 |  000000E9 | LATIN SMALL LETTER E WITH ACUTE
     53 |  000000EB | LATIN SMALL LETTER E WITH DIAERESIS
     54 |  0000016F | LATIN SMALL LETTER U WITH RING ABOVE
     55 |  000000ED | LATIN SMALL LETTER I WITH ACUTE
     57 |  0000013E | LATIN SMALL LETTER L WITH CARON
     58 |  0000013A | LATIN SMALL LETTER L WITH ACUTE
     59 |  000000DF | LATIN SMALL LETTER SHARP S (German)
     5A |  0000005D | RIGHT SQUARE BRACKET
     5B |  00000024 | DOLLAR SIGN
     5C |  0000002A | ASTERISK
     5D |  00000029 | RIGHT PARENTHESIS
     5E |  0000003B | SEMICOLON
     5F |  0000005E | CIRCUMFLEX ACCENT
     60 |  0000002D | HYPHEN-MINUS
     61 |  0000002F | SOLIDUS
     63 |  000000C4 | LATIN CAPITAL LETTER A WITH DIAERESIS
     64 |  000002DD | DOUBLE ACUTE ACCENT
     65 |  000000C1 | LATIN CAPITAL LETTER A WITH ACUTE
     67 |  0000010C | LATIN CAPITAL LETTER C WITH CARON
     68 |  000000C7 | LATIN CAPITAL LETTER C WITH CEDILLA
     69 |  00000106 | LATIN CAPITAL LETTER C WITH ACUTE
     6A |  0000007C | VERTICAL LINE
     6B |  0000002C | COMMA
     6C |  00000025 | PERCENT SIGN
     6D |  0000005F | LOW LINE
     6E |  0000003E | GREATER-THAN SIGN
     6F |  0000003F | QUESTION MARK
     70 |  000002C7 | CARON (Mandarin Chinese third tone)
     71 |  000000C9 | LATIN CAPITAL LETTER E WITH ACUTE
     73 |  000000CB | LATIN CAPITAL LETTER E WITH DIAERESIS
     74 |  0000016E | LATIN CAPITAL LETTER U WITH RING ABOVE
     75 |  000000CD | LATIN CAPITAL LETTER I WITH ACUTE
     77 |  0000013D | LATIN CAPITAL LETTER L WITH CARON
     78 |  00000139 | LATIN CAPITAL LETTER L WITH ACUTE
     79 |  00000060 | GRAVE ACCENT
     7A |  0000003A | COLON
     7B |  00000023 | NUMBER SIGN
     7C |  00000040 | COMMERCIAL AT
     7D |  00000027 | APOSTROPHE
     7E |  0000003D | EQUALS SIGN
     7F |  00000022 | QUOTATION MARK
     80 |  000002D8 | BREVE
     81 |  00000061 | LATIN SMALL LETTER A
     82 |  00000062 | LATIN SMALL LETTER B
     83 |  00000063 | LATIN SMALL LETTER C
     84 |  00000064 | LATIN SMALL LETTER D
     85 |  00000065 | LATIN SMALL LETTER E
     86 |  00000066 | LATIN SMALL LETTER F
     87 |  00000067 | LATIN SMALL LETTER G
     88 |  00000068 | LATIN SMALL LETTER H
     89 |  00000069 | LATIN SMALL LETTER I
     8A |  0000015B | LATIN SMALL LETTER S WITH ACUTE
     8B |  00000148 | LATIN SMALL LETTER N WITH CARON
     8C |  00000111 | LATIN SMALL LETTER D WITH STROKE
     8D |  000000FD | LATIN SMALL LETTER Y WITH ACUTE
     8E |  00000159 | LATIN SMALL LETTER R WITH CARON
     90 |  000000B0 | DEGREE SIGN
     91 |  0000006A | LATIN SMALL LETTER J
     92 |  0000006B | LATIN SMALL LETTER K
     93 |  0000006C | LATIN SMALL LETTER L
     94 |  0000006D | LATIN SMALL LETTER M
     95 |  0000006E | LATIN SMALL LETTER N
     96 |  0000006F | LATIN SMALL LETTER O
     97 |  00000070 | LATIN SMALL LETTER P
     98 |  00000071 | LATIN SMALL LETTER Q
     99 |  00000072 | LATIN SMALL LETTER R
     9A |  00000142 | LATIN SMALL LETTER L WITH STROKE
     9B |  00000144 | LATIN SMALL LETTER N WITH ACUTE
     9C |  00000161 | LATIN SMALL LETTER S WITH CARON
     9D |  000000B8 | CEDILLA
     9E |  000002DB | OGONEK
     9F |  000000A4 | CURRENCY SIGN
     A0 |  00000105 | LATIN SMALL LETTER A WITH OGONEK
     A1 |  0000007E | TILDE
     A2 |  00000073 | LATIN SMALL LETTER S
     A3 |  00000074 | LATIN SMALL LETTER T
     A4 |  00000075 | LATIN SMALL LETTER U
     A5 |  00000076 | LATIN SMALL LETTER V
     A6 |  00000077 | LATIN SMALL LETTER W
     A7 |  00000078 | LATIN SMALL LETTER X
     A8 |  00000079 | LATIN SMALL LETTER Y
     A9 |  0000007A | LATIN SMALL LETTER Z
     AA |  0000015A | LATIN CAPITAL LETTER S WITH ACUTE
     AB |  00000147 | LATIN CAPITAL LETTER N WITH CARON
     AC |  00000110 | LATIN CAPITAL LETTER D WITH STROKE
     AD |  000000DD | LATIN CAPITAL LETTER Y WITH ACUTE
     AE |  00000158 | LATIN CAPITAL LETTER R WITH CARON
     B0 |  000000B7 | MIDDLE DOT
     B1 |  00000104 | LATIN CAPITAL LETTER A WITH OGONEK
     B2 |  0000017C | LATIN SMALL LETTER Z WITH DOT ABOVE
     B4 |  0000017B | LATIN CAPITAL LETTER Z WITH DOT ABOVE
     B5 |  000000A7 | SECTION SIGN
     B6 |  000000B6 | PILCROW SIGN
     B7 |  0000017E | LATIN SMALL LETTER Z WITH CARON
     B8 |  0000017A | LATIN SMALL LETTER Z WITH ACUTE
     B9 |  0000017D | LATIN CAPITAL LETTER Z WITH CARON
     BA |  00000179 | LATIN CAPITAL LETTER Z WITH ACUTE
     BB |  00000143 | LATIN CAPITAL LETTER N WITH ACUTE
     BC |  00000160 | LATIN CAPITAL LETTER S WITH CARON
     BD |  000000A8 | DIAERESIS
     BE |  000000B4 | ACUTE ACCENT
     BF |  000000D7 | MULTIPLICATION SIGN
     C0 |  0000007B | LEFT CURLY BRACKET
     C1 |  00000041 | LATIN CAPITAL LETTER A
     C2 |  00000042 | LATIN CAPITAL LETTER B
     C3 |  00000043 | LATIN CAPITAL LETTER C
     C4 |  00000044 | LATIN CAPITAL LETTER D
     C5 |  00000045 | LATIN CAPITAL LETTER E
     C6 |  00000046 | LATIN CAPITAL LETTER F
     C7 |  00000047 | LATIN CAPITAL LETTER G
     C8 |  00000048 | LATIN CAPITAL LETTER H
     C9 |  00000049 | LATIN CAPITAL LETTER I
     CA |  000000AD | SOFT HYPHEN
     CB |  000000F4 | LATIN SMALL LETTER O WITH CIRCUMFLEX
     CC |  000000F6 | LATIN SMALL LETTER O WITH DIAERESIS
     CD |  00000155 | LATIN SMALL LETTER R WITH ACUTE
     CE |  000000F3 | LATIN SMALL LETTER O WITH ACUTE
     CF |  00000151 | LATIN SMALL LETTER O WITH DOUBLE ACUTE
     D0 |  0000007D | RIGHT CURLY BRACKET
     D1 |  0000004A | LATIN CAPITAL LETTER J
     D2 |  0000004B | LATIN CAPITAL LETTER K
     D3 |  0000004C | LATIN CAPITAL LETTER L
     D4 |  0000004D | LATIN CAPITAL LETTER M
     D5 |  0000004E | LATIN CAPITAL LETTER N
     D6 |  0000004F | LATIN CAPITAL LETTER O
     D7 |  00000050 | LATIN CAPITAL LETTER P
     D8 |  00000051 | LATIN CAPITAL LETTER Q
     D9 |  00000052 | LATIN CAPITAL LETTER R
     DA |  0000011A | LATIN CAPITAL LETTER E WITH CARON
     DB |  00000171 | LATIN SMALL LETTER U WITH DOUBLE ACUTE
     DC |  000000FC | LATIN SMALL LETTER U WITH DIAERESIS
     DD |  00000165 | LATIN SMALL LETTER T WITH CARON
     DE |  000000FA | LATIN SMALL LETTER U WITH ACUTE
     DF |  0000011B | LATIN SMALL LETTER E WITH CARON
     E0 |  0000005C | REVERSE SOLIDUS
     E1 |  000000F7 | DIVISION SIGN
     E2 |  00000053 | LATIN CAPITAL LETTER S
     E3 |  00000054 | LATIN CAPITAL LETTER T
     E4 |  00000055 | LATIN CAPITAL LETTER U
     E5 |  00000056 | LATIN CAPITAL LETTER V
     E6 |  00000057 | LATIN CAPITAL LETTER W
     E7 |  00000058 | LATIN CAPITAL LETTER X
     E8 |  00000059 | LATIN CAPITAL LETTER Y
     E9 |  0000005A | LATIN CAPITAL LETTER Z
     EA |  0000010F | LATIN SMALL LETTER D WITH CARON
     EB |  000000D4 | LATIN CAPITAL LETTER O WITH CIRCUMFLEX
     EC |  000000D6 | LATIN CAPITAL LETTER O WITH DIAERESIS
     ED |  00000154 | LATIN CAPITAL LETTER R WITH ACUTE
     EE |  000000D3 | LATIN CAPITAL LETTER O WITH ACUTE
     EF |  00000150 | LATIN CAPITAL LETTER O WITH DOUBLE ACUTE
     F0 |  00000030 | DIGIT ZERO
     F1 |  00000031 | DIGIT ONE
     F2 |  00000032 | DIGIT TWO
     F3 |  00000033 | DIGIT THREE
     F4 |  00000034 | DIGIT FOUR
     F5 |  00000035 | DIGIT FIVE
     F6 |  00000036 | DIGIT SIX
     F7 |  00000037 | DIGIT SEVEN
     F8 |  00000038 | DIGIT EIGHT
     F9 |  00000039 | DIGIT NINE
     FA |  0000010E | LATIN CAPITAL LETTER D WITH CARON
     FB |  00000170 | LATIN CAPITAL LETTER U WITH DOUBLE ACUTE
     FC |  000000DC | LATIN CAPITAL LETTER U WITH DIAERESIS
     FD |  00000164 | LATIN CAPITAL LETTER T WITH CARON
     FE |  000000DA | LATIN CAPITAL LETTER U WITH ACUTE
     FF |  0000009F | APPLICATION PROGRAM COMMAND (APC)
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/IBM871.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for IBM871.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::IBM871;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x009c,
     0x0009,
     0x0086,
     0x007f,
     0x0097,
     0x008d,
     0x008e,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x009d,
     0x0085,
     0x0008,
     0x0087,
     0x0018,
     0x0019,
     0x0092,
     0x008f,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0080,
     0x0081,
     0x0082,
     0x0083,
     0x0084,
     0x000a,
     0x0017,
     0x001b,
     0x0088,
     0x0089,
     0x008a,
     0x008b,
     0x008c,
     0x0005,
     0x0006,
     0x0007,
     0x0090,
     0x0091,
     0x0016,
     0x0093,
     0x0094,
     0x0095,
     0x0096,
     0x0004,
     0x0098,
     0x0099,
     0x009a,
     0x009b,
     0x0014,
     0x0015,
     0x009e,
     0x001a,
     0x0020,
     0x00a0,
     0x00e2,
     0x00e4,
     0x00e0,
     0x00e1,
     0x00e3,
     0x00e5,
     0x00e7,
     0x00f1,
     0x00fe,
     0x002e,
     0x003c,
     0x0028,
     0x002b,
     0x0021,
     0x0026,
     0x00e9,
     0x00ea,
     0x00eb,
     0x00e8,
     0x00ed,
     0x00ee,
     0x00ef,
     0x00ec,
     0x00df,
     0x00c6,
     0x0024,
     0x002a,
     0x0029,
     0x003b,
     0x00d6,
     0x002d,
     0x002f,
     0x00c2,
     0x00c4,
     0x00c0,
     0x00c1,
     0x00c3,
     0x00c5,
     0x00c7,
     0x00d1,
     0x00a6,
     0x002c,
     0x0025,
     0x005f,
     0x003e,
     0x003f,
     0x00f8,
     0x00c9,
     0x00ca,
     0x00cb,
     0x00c8,
     0x00cd,
     0x00ce,
     0x00cf,
     0x00cc,
     0x00f0,
     0x003a,
     0x0023,
     0x00d0,
     0x0027,
     0x003d,
     0x0022,
     0x00d8,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x00ab,
     0x00bb,
     0x0060,
     0x00fd,
     0x007b,
     0x00b1,
     0x00b0,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x00aa,
     0x00ba,
     0x007d,
     0x00b8,
     0x005d,
     0x00a4,
     0x00b5,
     0x00f6,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x00a1,
     0x00bf,
     0x0040,
     0x00dd,
     0x005b,
     0x00ae,
     0x00a2,
     0x00a3,
     0x00a5,
     0x00b7,
     0x00a9,
     0x00a7,
     0x00b6,
     0x00bc,
     0x00bd,
     0x00be,
     0x00ac,
     0x007c,
     0x00af,
     0x00a8,
     0x005c,
     0x00d7,
     0x00de,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x00ad,
     0x00f4,
     0x007e,
     0x00f2,
     0x00f3,
     0x00f5,
     0x00e6,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x00b9,
     0x00fb,
     0x00fc,
     0x00f9,
     0x00fa,
     0x00ff,
     0x00b4,
     0x00f7,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x00b2,
     0x00d4,
     0x005e,
     0x00d2,
     0x00d3,
     0x00d5,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x00b3,
     0x00db,
     0x00dc,
     0x00d9,
     0x00da,
     0x009f,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\xc2\x9c",
     "\x09",
     "\xc2\x86",
     "\x7f",
     "\xc2\x97",
     "\xc2\x8d",
     "\xc2\x8e",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\xc2\x9d",
     "\xc2\x85",
     "\x08",
     "\xc2\x87",
     "\x18",
     "\x19",
     "\xc2\x92",
     "\xc2\x8f",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\xc2\x80",
     "\xc2\x81",
     "\xc2\x82",
     "\xc2\x83",
     "\xc2\x84",
     "\x0a",
     "\x17",
     "\x1b",
     "\xc2\x88",
     "\xc2\x89",
     "\xc2\x8a",
     "\xc2\x8b",
     "\xc2\x8c",
     "\x05",
     "\x06",
     "\x07",
     "\xc2\x90",
     "\xc2\x91",
     "\x16",
     "\xc2\x93",
     "\xc2\x94",
     "\xc2\x95",
     "\xc2\x96",
     "\x04",
     "\xc2\x98",
     "\xc2\x99",
     "\xc2\x9a",
     "\xc2\x9b",
     "\x14",
     "\x15",
     "\xc2\x9e",
     "\x1a",
     "\x20",
     "\xc2\xa0",
     "\xc3\xa2",
     "\xc3\xa4",
     "\xc3\xa0",
     "\xc3\xa1",
     "\xc3\xa3",
     "\xc3\xa5",
     "\xc3\xa7",
     "\xc3\xb1",
     "\xc3\xbe",
     "\x2e",
     "\x3c",
     "\x28",
     "\x2b",
     "\x21",
     "\x26",
     "\xc3\xa9",
     "\xc3\xaa",
     "\xc3\xab",
     "\xc3\xa8",
     "\xc3\xad",
     "\xc3\xae",
     "\xc3\xaf",
     "\xc3\xac",
     "\xc3\x9f",
     "\xc3\x86",
     "\x24",
     "\x2a",
     "\x29",
     "\x3b",
     "\xc3\x96",
     "\x2d",
     "\x2f",
     "\xc3\x82",
     "\xc3\x84",
     "\xc3\x80",
     "\xc3\x81",
     "\xc3\x83",
     "\xc3\x85",
     "\xc3\x87",
     "\xc3\x91",
     "\xc2\xa6",
     "\x2c",
     "\x25",
     "\x5f",
     "\x3e",
     "\x3f",
     "\xc3\xb8",
     "\xc3\x89",
     "\xc3\x8a",
     "\xc3\x8b",
     "\xc3\x88",
     "\xc3\x8d",
     "\xc3\x8e",
     "\xc3\x8f",
     "\xc3\x8c",
     "\xc3\xb0",
     "\x3a",
     "\x23",
     "\xc3\x90",
     "\x27",
     "\x3d",
     "\x22",
     "\xc3\x98",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\xc2\xab",
     "\xc2\xbb",
     "\x60",
     "\xc3\xbd",
     "\x7b",
     "\xc2\xb1",
     "\xc2\xb0",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\xc2\xaa",
     "\xc2\xba",
     "\x7d",
     "\xc2\xb8",
     "\x5d",
     "\xc2\xa4",
     "\xc2\xb5",
     "\xc3\xb6",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\xc2\xa1",
     "\xc2\xbf",
     "\x40",
     "\xc3\x9d",
     "\x5b",
     "\xc2\xae",
     "\xc2\xa2",
     "\xc2\xa3",
     "\xc2\xa5",
     "\xc2\xb7",
     "\xc2\xa9",
     "\xc2\xa7",
     "\xc2\xb6",
     "\xc2\xbc",
     "\xc2\xbd",
     "\xc2\xbe",
     "\xc2\xac",
     "\x7c",
     "\xc2\xaf",
     "\xc2\xa8",
     "\x5c",
     "\xc3\x97",
     "\xc3\x9e",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\xc2\xad",
     "\xc3\xb4",
     "\x7e",
     "\xc3\xb2",
     "\xc3\xb3",
     "\xc3\xb5",
     "\xc3\xa6",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\xc2\xb9",
     "\xc3\xbb",
     "\xc3\xbc",
     "\xc3\xb9",
     "\xc3\xba",
     "\xc3\xbf",
     "\xc2\xb4",
     "\xc3\xb7",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\xc2\xb2",
     "\xc3\x94",
     "\x5e",
     "\xc3\x92",
     "\xc3\x93",
     "\xc3\x95",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\xc2\xb3",
     "\xc3\x9b",
     "\xc3\x9c",
     "\xc3\x99",
     "\xc3\x9a",
     "\xc2\x9f",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x37",
     0x00000005 => "\x2d",
     0x00000006 => "\x2e",
     0x00000007 => "\x2f",
     0x00000008 => "\x16",
     0x00000009 => "\x05",
     0x0000000a => "\x25",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x3c",
     0x00000015 => "\x3d",
     0x00000016 => "\x32",
     0x00000017 => "\x26",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x3f",
     0x0000001b => "\x27",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x40",
     0x00000021 => "\x4f",
     0x00000022 => "\x7f",
     0x00000023 => "\x7b",
     0x00000024 => "\x5b",
     0x00000025 => "\x6c",
     0x00000026 => "\x50",
     0x00000027 => "\x7d",
     0x00000028 => "\x4d",
     0x00000029 => "\x5d",
     0x0000002a => "\x5c",
     0x0000002b => "\x4e",
     0x0000002c => "\x6b",
     0x0000002d => "\x60",
     0x0000002e => "\x4b",
     0x0000002f => "\x61",
     0x00000030 => "\xf0",
     0x00000031 => "\xf1",
     0x00000032 => "\xf2",
     0x00000033 => "\xf3",
     0x00000034 => "\xf4",
     0x00000035 => "\xf5",
     0x00000036 => "\xf6",
     0x00000037 => "\xf7",
     0x00000038 => "\xf8",
     0x00000039 => "\xf9",
     0x0000003a => "\x7a",
     0x0000003b => "\x5e",
     0x0000003c => "\x4c",
     0x0000003d => "\x7e",
     0x0000003e => "\x6e",
     0x0000003f => "\x6f",
     0x00000040 => "\xac",
     0x00000041 => "\xc1",
     0x00000042 => "\xc2",
     0x00000043 => "\xc3",
     0x00000044 => "\xc4",
     0x00000045 => "\xc5",
     0x00000046 => "\xc6",
     0x00000047 => "\xc7",
     0x00000048 => "\xc8",
     0x00000049 => "\xc9",
     0x0000004a => "\xd1",
     0x0000004b => "\xd2",
     0x0000004c => "\xd3",
     0x0000004d => "\xd4",
     0x0000004e => "\xd5",
     0x0000004f => "\xd6",
     0x00000050 => "\xd7",
     0x00000051 => "\xd8",
     0x00000052 => "\xd9",
     0x00000053 => "\xe2",
     0x00000054 => "\xe3",
     0x00000055 => "\xe4",
     0x00000056 => "\xe5",
     0x00000057 => "\xe6",
     0x00000058 => "\xe7",
     0x00000059 => "\xe8",
     0x0000005a => "\xe9",
     0x0000005b => "\xae",
     0x0000005c => "\xbe",
     0x0000005d => "\x9e",
     0x0000005e => "\xec",
     0x0000005f => "\x6d",
     0x00000060 => "\x8c",
     0x00000061 => "\x81",
     0x00000062 => "\x82",
     0x00000063 => "\x83",
     0x00000064 => "\x84",
     0x00000065 => "\x85",
     0x00000066 => "\x86",
     0x00000067 => "\x87",
     0x00000068 => "\x88",
     0x00000069 => "\x89",
     0x0000006a => "\x91",
     0x0000006b => "\x92",
     0x0000006c => "\x93",
     0x0000006d => "\x94",
     0x0000006e => "\x95",
     0x0000006f => "\x96",
     0x00000070 => "\x97",
     0x00000071 => "\x98",
     0x00000072 => "\x99",
     0x00000073 => "\xa2",
     0x00000074 => "\xa3",
     0x00000075 => "\xa4",
     0x00000076 => "\xa5",
     0x00000077 => "\xa6",
     0x00000078 => "\xa7",
     0x00000079 => "\xa8",
     0x0000007a => "\xa9",
     0x0000007b => "\x8e",
     0x0000007c => "\xbb",
     0x0000007d => "\x9c",
     0x0000007e => "\xcc",
     0x0000007f => "\x07",
     0x00000080 => "\x20",
     0x00000081 => "\x21",
     0x00000082 => "\x22",
     0x00000083 => "\x23",
     0x00000084 => "\x24",
     0x00000085 => "\x15",
     0x00000086 => "\x06",
     0x00000087 => "\x17",
     0x00000088 => "\x28",
     0x00000089 => "\x29",
     0x0000008a => "\x2a",
     0x0000008b => "\x2b",
     0x0000008c => "\x2c",
     0x0000008d => "\x09",
     0x0000008e => "\x0a",
     0x0000008f => "\x1b",
     0x00000090 => "\x30",
     0x00000091 => "\x31",
     0x00000092 => "\x1a",
     0x00000093 => "\x33",
     0x00000094 => "\x34",
     0x00000095 => "\x35",
     0x00000096 => "\x36",
     0x00000097 => "\x08",
     0x00000098 => "\x38",
     0x00000099 => "\x39",
     0x0000009a => "\x3a",
     0x0000009b => "\x3b",
     0x0000009c => "\x04",
     0x0000009d => "\x14",
     0x0000009e => "\x3e",
     0x0000009f => "\xff",
     0x000000a0 => "\x41",
     0x000000a1 => "\xaa",
     0x000000a2 => "\xb0",
     0x000000a3 => "\xb1",
     0x000000a4 => "\x9f",
     0x000000a5 => "\xb2",
     0x000000a6 => "\x6a",
     0x000000a7 => "\xb5",
     0x000000a8 => "\xbd",
     0x000000a9 => "\xb4",
     0x000000aa => "\x9a",
     0x000000ab => "\x8a",
     0x000000ac => "\xba",
     0x000000ad => "\xca",
     0x000000ae => "\xaf",
     0x000000af => "\xbc",
     0x000000b0 => "\x90",
     0x000000b1 => "\x8f",
     0x000000b2 => "\xea",
     0x000000b3 => "\xfa",
     0x000000b4 => "\xe0",
     0x000000b5 => "\xa0",
     0x000000b6 => "\xb6",
     0x000000b7 => "\xb3",
     0x000000b8 => "\x9d",
     0x000000b9 => "\xda",
     0x000000ba => "\x9b",
     0x000000bb => "\x8b",
     0x000000bc => "\xb7",
     0x000000bd => "\xb8",
     0x000000be => "\xb9",
     0x000000bf => "\xab",
     0x000000c0 => "\x64",
     0x000000c1 => "\x65",
     0x000000c2 => "\x62",
     0x000000c3 => "\x66",
     0x000000c4 => "\x63",
     0x000000c5 => "\x67",
     0x000000c6 => "\x5a",
     0x000000c7 => "\x68",
     0x000000c8 => "\x74",
     0x000000c9 => "\x71",
     0x000000ca => "\x72",
     0x000000cb => "\x73",
     0x000000cc => "\x78",
     0x000000cd => "\x75",
     0x000000ce => "\x76",
     0x000000cf => "\x77",
     0x000000d0 => "\x7c",
     0x000000d1 => "\x69",
     0x000000d2 => "\xed",
     0x000000d3 => "\xee",
     0x000000d4 => "\xeb",
     0x000000d5 => "\xef",
     0x000000d6 => "\x5f",
     0x000000d7 => "\xbf",
     0x000000d8 => "\x80",
     0x000000d9 => "\xfd",
     0x000000da => "\xfe",
     0x000000db => "\xfb",
     0x000000dc => "\xfc",
     0x000000dd => "\xad",
     0x000000de => "\xc0",
     0x000000df => "\x59",
     0x000000e0 => "\x44",
     0x000000e1 => "\x45",
     0x000000e2 => "\x42",
     0x000000e3 => "\x46",
     0x000000e4 => "\x43",
     0x000000e5 => "\x47",
     0x000000e6 => "\xd0",
     0x000000e7 => "\x48",
     0x000000e8 => "\x54",
     0x000000e9 => "\x51",
     0x000000ea => "\x52",
     0x000000eb => "\x53",
     0x000000ec => "\x58",
     0x000000ed => "\x55",
     0x000000ee => "\x56",
     0x000000ef => "\x57",
     0x000000f0 => "\x79",
     0x000000f1 => "\x49",
     0x000000f2 => "\xcd",
     0x000000f3 => "\xce",
     0x000000f4 => "\xcb",
     0x000000f5 => "\xcf",
     0x000000f6 => "\xa1",
     0x000000f7 => "\xe1",
     0x000000f8 => "\x70",
     0x000000f9 => "\xdd",
     0x000000fa => "\xde",
     0x000000fb => "\xdb",
     0x000000fc => "\xdc",
     0x000000fd => "\x8d",
     0x000000fe => "\x4a",
     0x000000ff => "\xdf",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x6f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::IBM871 - Conversion routines for IBM871
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for IBM871.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
   source: IBM NLS RM Vol2 SE09-8002-01, March 1990
  alias CP871
  alias EBCDIC-CP-IS
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  0000009C | STRING TERMINATOR (ST)
     05 |  00000009 | CHARACTER TABULATION (HT)
     06 |  00000086 | START OF SELECTED AREA (SSA)
     07 |  0000007F | DELETE (DEL)
     08 |  00000097 | END OF GUARDED AREA (EPA)
     09 |  0000008D | REVERSE LINE FEED (RI)
     0A |  0000008E | SINGLE-SHIFT TWO (SS2)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  0000009D | OPERATING SYSTEM COMMAND (OSC)
     15 |  00000085 | NEXT LINE (NEL)
     16 |  00000008 | BACKSPACE (BS)
     17 |  00000087 | END OF SELECTED AREA (ESA)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  00000092 | PRIVATE USE TWO (PU2)
     1B |  0000008F | SINGLE-SHIFT THREE (SS3)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000080 | PADDING CHARACTER (PAD)
     21 |  00000081 | HIGH OCTET PRESET (HOP)
     22 |  00000082 | BREAK PERMITTED HERE (BPH)
     23 |  00000083 | NO BREAK HERE (NBH)
     24 |  00000084 | INDEX (IND)
     25 |  0000000A | LINE FEED (LF)
     26 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     27 |  0000001B | ESCAPE (ESC)
     28 |  00000088 | CHARACTER TABULATION SET (HTS)
     29 |  00000089 | CHARACTER TABULATION WITH JUSTIFICATION (HTJ)
     2A |  0000008A | LINE TABULATION SET (VTS)
     2B |  0000008B | PARTIAL LINE FORWARD (PLD)
     2C |  0000008C | PARTIAL LINE BACKWARD (PLU)
     2D |  00000005 | ENQUIRY (ENQ)
     2E |  00000006 | ACKNOWLEDGE (ACK)
     2F |  00000007 | BELL (BEL)
     30 |  00000090 | DEVICE CONTROL STRING (DCS)
     31 |  00000091 | PRIVATE USE ONE (PU1)
     32 |  00000016 | SYNCHRONOUS IDLE (SYN)
     33 |  00000093 | SET TRANSMIT STATE (STS)
     34 |  00000094 | CANCEL CHARACTER (CCH)
     35 |  00000095 | MESSAGE WAITING (MW)
     36 |  00000096 | START OF GUARDED AREA (SPA)
     37 |  00000004 | END OF TRANSMISSION (EOT)
     38 |  00000098 | START OF STRING (SOS)
     39 |  00000099 | SINGLE GRAPHIC CHARACTER INTRODUCER (SGCI)
     3A |  0000009A | SINGLE CHARACTER INTRODUCER (SCI)
     3B |  0000009B | CONTROL SEQUENCE INTRODUCER (CSI)
     3C |  00000014 | DEVICE CONTROL FOUR (DC4)
     3D |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     3E |  0000009E | PRIVACY MESSAGE (PM)
     3F |  0000001A | SUBSTITUTE (SUB)
     40 |  00000020 | SPACE
     41 |  000000A0 | NO-BREAK SPACE
     42 |  000000E2 | LATIN SMALL LETTER A WITH CIRCUMFLEX
     43 |  000000E4 | LATIN SMALL LETTER A WITH DIAERESIS
     44 |  000000E0 | LATIN SMALL LETTER A WITH GRAVE
     45 |  000000E1 | LATIN SMALL LETTER A WITH ACUTE
     46 |  000000E3 | LATIN SMALL LETTER A WITH TILDE
     47 |  000000E5 | LATIN SMALL LETTER A WITH RING ABOVE
     48 |  000000E7 | LATIN SMALL LETTER C WITH CEDILLA
     49 |  000000F1 | LATIN SMALL LETTER N WITH TILDE
     4A |  000000FE | LATIN SMALL LETTER THORN (Icelandic)
     4B |  0000002E | FULL STOP
     4C |  0000003C | LESS-THAN SIGN
     4D |  00000028 | LEFT PARENTHESIS
     4E |  0000002B | PLUS SIGN
     4F |  00000021 | EXCLAMATION MARK
     50 |  00000026 | AMPERSAND
     51 |  000000E9 | LATIN SMALL LETTER E WITH ACUTE
     52 |  000000EA | LATIN SMALL LETTER E WITH CIRCUMFLEX
     53 |  000000EB | LATIN SMALL LETTER E WITH DIAERESIS
     54 |  000000E8 | LATIN SMALL LETTER E WITH GRAVE
     55 |  000000ED | LATIN SMALL LETTER I WITH ACUTE
     56 |  000000EE | LATIN SMALL LETTER I WITH CIRCUMFLEX
     57 |  000000EF | LATIN SMALL LETTER I WITH DIAERESIS
     58 |  000000EC | LATIN SMALL LETTER I WITH GRAVE
     59 |  000000DF | LATIN SMALL LETTER SHARP S (German)
     5A |  000000C6 | LATIN CAPITAL LETTER AE
     5B |  00000024 | DOLLAR SIGN
     5C |  0000002A | ASTERISK
     5D |  00000029 | RIGHT PARENTHESIS
     5E |  0000003B | SEMICOLON
     5F |  000000D6 | LATIN CAPITAL LETTER O WITH DIAERESIS
     60 |  0000002D | HYPHEN-MINUS
     61 |  0000002F | SOLIDUS
     62 |  000000C2 | LATIN CAPITAL LETTER A WITH CIRCUMFLEX
     63 |  000000C4 | LATIN CAPITAL LETTER A WITH DIAERESIS
     64 |  000000C0 | LATIN CAPITAL LETTER A WITH GRAVE
     65 |  000000C1 | LATIN CAPITAL LETTER A WITH ACUTE
     66 |  000000C3 | LATIN CAPITAL LETTER A WITH TILDE
     67 |  000000C5 | LATIN CAPITAL LETTER A WITH RING ABOVE
     68 |  000000C7 | LATIN CAPITAL LETTER C WITH CEDILLA
     69 |  000000D1 | LATIN CAPITAL LETTER N WITH TILDE
     6A |  000000A6 | BROKEN BAR
     6B |  0000002C | COMMA
     6C |  00000025 | PERCENT SIGN
     6D |  0000005F | LOW LINE
     6E |  0000003E | GREATER-THAN SIGN
     6F |  0000003F | QUESTION MARK
     70 |  000000F8 | LATIN SMALL LETTER O WITH STROKE
     71 |  000000C9 | LATIN CAPITAL LETTER E WITH ACUTE
     72 |  000000CA | LATIN CAPITAL LETTER E WITH CIRCUMFLEX
     73 |  000000CB | LATIN CAPITAL LETTER E WITH DIAERESIS
     74 |  000000C8 | LATIN CAPITAL LETTER E WITH GRAVE
     75 |  000000CD | LATIN CAPITAL LETTER I WITH ACUTE
     76 |  000000CE | LATIN CAPITAL LETTER I WITH CIRCUMFLEX
     77 |  000000CF | LATIN CAPITAL LETTER I WITH DIAERESIS
     78 |  000000CC | LATIN CAPITAL LETTER I WITH GRAVE
     79 |  000000F0 | LATIN SMALL LETTER ETH (Icelandic)
     7A |  0000003A | COLON
     7B |  00000023 | NUMBER SIGN
     7C |  000000D0 | LATIN CAPITAL LETTER ETH (Icelandic)
     7D |  00000027 | APOSTROPHE
     7E |  0000003D | EQUALS SIGN
     7F |  00000022 | QUOTATION MARK
     80 |  000000D8 | LATIN CAPITAL LETTER O WITH STROKE
     81 |  00000061 | LATIN SMALL LETTER A
     82 |  00000062 | LATIN SMALL LETTER B
     83 |  00000063 | LATIN SMALL LETTER C
     84 |  00000064 | LATIN SMALL LETTER D
     85 |  00000065 | LATIN SMALL LETTER E
     86 |  00000066 | LATIN SMALL LETTER F
     87 |  00000067 | LATIN SMALL LETTER G
     88 |  00000068 | LATIN SMALL LETTER H
     89 |  00000069 | LATIN SMALL LETTER I
     8A |  000000AB | LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
     8B |  000000BB | RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
     8C |  00000060 | GRAVE ACCENT
     8D |  000000FD | LATIN SMALL LETTER Y WITH ACUTE
     8E |  0000007B | LEFT CURLY BRACKET
     8F |  000000B1 | PLUS-MINUS SIGN
     90 |  000000B0 | DEGREE SIGN
     91 |  0000006A | LATIN SMALL LETTER J
     92 |  0000006B | LATIN SMALL LETTER K
     93 |  0000006C | LATIN SMALL LETTER L
     94 |  0000006D | LATIN SMALL LETTER M
     95 |  0000006E | LATIN SMALL LETTER N
     96 |  0000006F | LATIN SMALL LETTER O
     97 |  00000070 | LATIN SMALL LETTER P
     98 |  00000071 | LATIN SMALL LETTER Q
     99 |  00000072 | LATIN SMALL LETTER R
     9A |  000000AA | FEMININE ORDINAL INDICATOR
     9B |  000000BA | MASCULINE ORDINAL INDICATOR
     9C |  0000007D | RIGHT CURLY BRACKET
     9D |  000000B8 | CEDILLA
     9E |  0000005D | RIGHT SQUARE BRACKET
     9F |  000000A4 | CURRENCY SIGN
     A0 |  000000B5 | MICRO SIGN
     A1 |  000000F6 | LATIN SMALL LETTER O WITH DIAERESIS
     A2 |  00000073 | LATIN SMALL LETTER S
     A3 |  00000074 | LATIN SMALL LETTER T
     A4 |  00000075 | LATIN SMALL LETTER U
     A5 |  00000076 | LATIN SMALL LETTER V
     A6 |  00000077 | LATIN SMALL LETTER W
     A7 |  00000078 | LATIN SMALL LETTER X
     A8 |  00000079 | LATIN SMALL LETTER Y
     A9 |  0000007A | LATIN SMALL LETTER Z
     AA |  000000A1 | INVERTED EXCLAMATION MARK
     AB |  000000BF | INVERTED QUESTION MARK
     AC |  00000040 | COMMERCIAL AT
     AD |  000000DD | LATIN CAPITAL LETTER Y WITH ACUTE
     AE |  0000005B | LEFT SQUARE BRACKET
     AF |  000000AE | REGISTERED SIGN
     B0 |  000000A2 | CENT SIGN
     B1 |  000000A3 | POUND SIGN
     B2 |  000000A5 | YEN SIGN
     B3 |  000000B7 | MIDDLE DOT
     B4 |  000000A9 | COPYRIGHT SIGN
     B5 |  000000A7 | SECTION SIGN
     B6 |  000000B6 | PILCROW SIGN
     B7 |  000000BC | VULGAR FRACTION ONE QUARTER
     B8 |  000000BD | VULGAR FRACTION ONE HALF
     B9 |  000000BE | VULGAR FRACTION THREE QUARTERS
     BA |  000000AC | NOT SIGN
     BB |  0000007C | VERTICAL LINE
     BC |  000000AF | MACRON
     BD |  000000A8 | DIAERESIS
     BE |  0000005C | REVERSE SOLIDUS
     BF |  000000D7 | MULTIPLICATION SIGN
     C0 |  000000DE | LATIN CAPITAL LETTER THORN (Icelandic)
     C1 |  00000041 | LATIN CAPITAL LETTER A
     C2 |  00000042 | LATIN CAPITAL LETTER B
     C3 |  00000043 | LATIN CAPITAL LETTER C
     C4 |  00000044 | LATIN CAPITAL LETTER D
     C5 |  00000045 | LATIN CAPITAL LETTER E
     C6 |  00000046 | LATIN CAPITAL LETTER F
     C7 |  00000047 | LATIN CAPITAL LETTER G
     C8 |  00000048 | LATIN CAPITAL LETTER H
     C9 |  00000049 | LATIN CAPITAL LETTER I
     CA |  000000AD | SOFT HYPHEN
     CB |  000000F4 | LATIN SMALL LETTER O WITH CIRCUMFLEX
     CC |  0000007E | TILDE
     CD |  000000F2 | LATIN SMALL LETTER O WITH GRAVE
     CE |  000000F3 | LATIN SMALL LETTER O WITH ACUTE
     CF |  000000F5 | LATIN SMALL LETTER O WITH TILDE
     D0 |  000000E6 | LATIN SMALL LETTER AE
     D1 |  0000004A | LATIN CAPITAL LETTER J
     D2 |  0000004B | LATIN CAPITAL LETTER K
     D3 |  0000004C | LATIN CAPITAL LETTER L
     D4 |  0000004D | LATIN CAPITAL LETTER M
     D5 |  0000004E | LATIN CAPITAL LETTER N
     D6 |  0000004F | LATIN CAPITAL LETTER O
     D7 |  00000050 | LATIN CAPITAL LETTER P
     D8 |  00000051 | LATIN CAPITAL LETTER Q
     D9 |  00000052 | LATIN CAPITAL LETTER R
     DA |  000000B9 | SUPERSCRIPT ONE
     DB |  000000FB | LATIN SMALL LETTER U WITH CIRCUMFLEX
     DC |  000000FC | LATIN SMALL LETTER U WITH DIAERESIS
     DD |  000000F9 | LATIN SMALL LETTER U WITH GRAVE
     DE |  000000FA | LATIN SMALL LETTER U WITH ACUTE
     DF |  000000FF | LATIN SMALL LETTER Y WITH DIAERESIS
     E0 |  000000B4 | ACUTE ACCENT
     E1 |  000000F7 | DIVISION SIGN
     E2 |  00000053 | LATIN CAPITAL LETTER S
     E3 |  00000054 | LATIN CAPITAL LETTER T
     E4 |  00000055 | LATIN CAPITAL LETTER U
     E5 |  00000056 | LATIN CAPITAL LETTER V
     E6 |  00000057 | LATIN CAPITAL LETTER W
     E7 |  00000058 | LATIN CAPITAL LETTER X
     E8 |  00000059 | LATIN CAPITAL LETTER Y
     E9 |  0000005A | LATIN CAPITAL LETTER Z
     EA |  000000B2 | SUPERSCRIPT TWO
     EB |  000000D4 | LATIN CAPITAL LETTER O WITH CIRCUMFLEX
     EC |  0000005E | CIRCUMFLEX ACCENT
     ED |  000000D2 | LATIN CAPITAL LETTER O WITH GRAVE
     EE |  000000D3 | LATIN CAPITAL LETTER O WITH ACUTE
     EF |  000000D5 | LATIN CAPITAL LETTER O WITH TILDE
     F0 |  00000030 | DIGIT ZERO
     F1 |  00000031 | DIGIT ONE
     F2 |  00000032 | DIGIT TWO
     F3 |  00000033 | DIGIT THREE
     F4 |  00000034 | DIGIT FOUR
     F5 |  00000035 | DIGIT FIVE
     F6 |  00000036 | DIGIT SIX
     F7 |  00000037 | DIGIT SEVEN
     F8 |  00000038 | DIGIT EIGHT
     F9 |  00000039 | DIGIT NINE
     FA |  000000B3 | SUPERSCRIPT THREE
     FB |  000000DB | LATIN CAPITAL LETTER U WITH CIRCUMFLEX
     FC |  000000DC | LATIN CAPITAL LETTER U WITH DIAERESIS
     FD |  000000D9 | LATIN CAPITAL LETTER U WITH GRAVE
     FE |  000000DA | LATIN CAPITAL LETTER U WITH ACUTE
     FF |  0000009F | APPLICATION PROGRAM COMMAND (APC)
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/IBM874.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for IBM874.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::IBM874;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x0004,
     0x0005,
     0x0006,
     0x0007,
     0x0008,
     0x0009,
     0x000a,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x0014,
     0x0015,
     0x0016,
     0x0017,
     0x0018,
     0x0019,
     0x001a,
     0x001b,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0020,
     0x0021,
     0x0022,
     0x0023,
     0x0024,
     0x0025,
     0x0026,
     0x0027,
     0x0028,
     0x0029,
     0x002a,
     0x002b,
     0x002c,
     0x002d,
     0x002e,
     0x002f,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x003a,
     0x003b,
     0x003c,
     0x003d,
     0x003e,
     0x003f,
     0x0040,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x005b,
     0x005c,
     0x005d,
     0x005e,
     0x005f,
     0x0060,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x007b,
     0x007c,
     0x007d,
     0x007e,
     0x007f,
     0x20ac,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x2026,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x2018,
     0x2019,
     0x201c,
     0x201d,
     0x2022,
     0x2013,
     0x2014,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00a0,
     0x0e01,
     0x0e02,
     0x0e03,
     0x0e04,
     0x0e05,
     0x0e06,
     0x0e07,
     0x0e08,
     0x0e09,
     0x0e0a,
     0x0e0b,
     0x0e0c,
     0x0e0d,
     0x0e0e,
     0x0e0f,
     0x0e10,
     0x0e11,
     0x0e12,
     0x0e13,
     0x0e14,
     0x0e15,
     0x0e16,
     0x0e17,
     0x0e18,
     0x0e19,
     0x0e1a,
     0x0e1b,
     0x0e1c,
     0x0e1d,
     0x0e1e,
     0x0e1f,
     0x0e20,
     0x0e21,
     0x0e22,
     0x0e23,
     0x0e24,
     0x0e25,
     0x0e26,
     0x0e27,
     0x0e28,
     0x0e29,
     0x0e2a,
     0x0e2b,
     0x0e2c,
     0x0e2d,
     0x0e2e,
     0x0e2f,
     0x0e30,
     0x0e31,
     0x0e32,
     0x0e33,
     0x0e34,
     0x0e35,
     0x0e36,
     0x0e37,
     0x0e38,
     0x0e39,
     0x0e3a,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x0e3f,
     0x0e40,
     0x0e41,
     0x0e42,
     0x0e43,
     0x0e44,
     0x0e45,
     0x0e46,
     0x0e47,
     0x0e48,
     0x0e49,
     0x0e4a,
     0x0e4b,
     0x0e4c,
     0x0e4d,
     0x0e4e,
     0x0e4f,
     0x0e50,
     0x0e51,
     0x0e52,
     0x0e53,
     0x0e54,
     0x0e55,
     0x0e56,
     0x0e57,
     0x0e58,
     0x0e59,
     0x0e5a,
     0x0e5b,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\x04",
     "\x05",
     "\x06",
     "\x07",
     "\x08",
     "\x09",
     "\x0a",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\x14",
     "\x15",
     "\x16",
     "\x17",
     "\x18",
     "\x19",
     "\x1a",
     "\x1b",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\x20",
     "\x21",
     "\x22",
     "\x23",
     "\x24",
     "\x25",
     "\x26",
     "\x27",
     "\x28",
     "\x29",
     "\x2a",
     "\x2b",
     "\x2c",
     "\x2d",
     "\x2e",
     "\x2f",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\x3a",
     "\x3b",
     "\x3c",
     "\x3d",
     "\x3e",
     "\x3f",
     "\x40",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\x5b",
     "\x5c",
     "\x5d",
     "\x5e",
     "\x5f",
     "\x60",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\x7b",
     "\x7c",
     "\x7d",
     "\x7e",
     "\x7f",
     "\xe2\x82\xac",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xe2\x80\xa6",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xe2\x80\x98",
     "\xe2\x80\x99",
     "\xe2\x80\x9c",
     "\xe2\x80\x9d",
     "\xe2\x80\xa2",
     "\xe2\x80\x93",
     "\xe2\x80\x94",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc2\xa0",
     "\xe0\xb8\x81",
     "\xe0\xb8\x82",
     "\xe0\xb8\x83",
     "\xe0\xb8\x84",
     "\xe0\xb8\x85",
     "\xe0\xb8\x86",
     "\xe0\xb8\x87",
     "\xe0\xb8\x88",
     "\xe0\xb8\x89",
     "\xe0\xb8\x8a",
     "\xe0\xb8\x8b",
     "\xe0\xb8\x8c",
     "\xe0\xb8\x8d",
     "\xe0\xb8\x8e",
     "\xe0\xb8\x8f",
     "\xe0\xb8\x90",
     "\xe0\xb8\x91",
     "\xe0\xb8\x92",
     "\xe0\xb8\x93",
     "\xe0\xb8\x94",
     "\xe0\xb8\x95",
     "\xe0\xb8\x96",
     "\xe0\xb8\x97",
     "\xe0\xb8\x98",
     "\xe0\xb8\x99",
     "\xe0\xb8\x9a",
     "\xe0\xb8\x9b",
     "\xe0\xb8\x9c",
     "\xe0\xb8\x9d",
     "\xe0\xb8\x9e",
     "\xe0\xb8\x9f",
     "\xe0\xb8\xa0",
     "\xe0\xb8\xa1",
     "\xe0\xb8\xa2",
     "\xe0\xb8\xa3",
     "\xe0\xb8\xa4",
     "\xe0\xb8\xa5",
     "\xe0\xb8\xa6",
     "\xe0\xb8\xa7",
     "\xe0\xb8\xa8",
     "\xe0\xb8\xa9",
     "\xe0\xb8\xaa",
     "\xe0\xb8\xab",
     "\xe0\xb8\xac",
     "\xe0\xb8\xad",
     "\xe0\xb8\xae",
     "\xe0\xb8\xaf",
     "\xe0\xb8\xb0",
     "\xe0\xb8\xb1",
     "\xe0\xb8\xb2",
     "\xe0\xb8\xb3",
     "\xe0\xb8\xb4",
     "\xe0\xb8\xb5",
     "\xe0\xb8\xb6",
     "\xe0\xb8\xb7",
     "\xe0\xb8\xb8",
     "\xe0\xb8\xb9",
     "\xe0\xb8\xba",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xe0\xb8\xbf",
     "\xe0\xb9\x80",
     "\xe0\xb9\x81",
     "\xe0\xb9\x82",
     "\xe0\xb9\x83",
     "\xe0\xb9\x84",
     "\xe0\xb9\x85",
     "\xe0\xb9\x86",
     "\xe0\xb9\x87",
     "\xe0\xb9\x88",
     "\xe0\xb9\x89",
     "\xe0\xb9\x8a",
     "\xe0\xb9\x8b",
     "\xe0\xb9\x8c",
     "\xe0\xb9\x8d",
     "\xe0\xb9\x8e",
     "\xe0\xb9\x8f",
     "\xe0\xb9\x90",
     "\xe0\xb9\x91",
     "\xe0\xb9\x92",
     "\xe0\xb9\x93",
     "\xe0\xb9\x94",
     "\xe0\xb9\x95",
     "\xe0\xb9\x96",
     "\xe0\xb9\x97",
     "\xe0\xb9\x98",
     "\xe0\xb9\x99",
     "\xe0\xb9\x9a",
     "\xe0\xb9\x9b",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x04",
     0x00000005 => "\x05",
     0x00000006 => "\x06",
     0x00000007 => "\x07",
     0x00000008 => "\x08",
     0x00000009 => "\x09",
     0x0000000a => "\x0a",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x14",
     0x00000015 => "\x15",
     0x00000016 => "\x16",
     0x00000017 => "\x17",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x1a",
     0x0000001b => "\x1b",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x20",
     0x00000021 => "\x21",
     0x00000022 => "\x22",
     0x00000023 => "\x23",
     0x00000024 => "\x24",
     0x00000025 => "\x25",
     0x00000026 => "\x26",
     0x00000027 => "\x27",
     0x00000028 => "\x28",
     0x00000029 => "\x29",
     0x0000002a => "\x2a",
     0x0000002b => "\x2b",
     0x0000002c => "\x2c",
     0x0000002d => "\x2d",
     0x0000002e => "\x2e",
     0x0000002f => "\x2f",
     0x00000030 => "\x30",
     0x00000031 => "\x31",
     0x00000032 => "\x32",
     0x00000033 => "\x33",
     0x00000034 => "\x34",
     0x00000035 => "\x35",
     0x00000036 => "\x36",
     0x00000037 => "\x37",
     0x00000038 => "\x38",
     0x00000039 => "\x39",
     0x0000003a => "\x3a",
     0x0000003b => "\x3b",
     0x0000003c => "\x3c",
     0x0000003d => "\x3d",
     0x0000003e => "\x3e",
     0x0000003f => "\x3f",
     0x00000040 => "\x40",
     0x00000041 => "\x41",
     0x00000042 => "\x42",
     0x00000043 => "\x43",
     0x00000044 => "\x44",
     0x00000045 => "\x45",
     0x00000046 => "\x46",
     0x00000047 => "\x47",
     0x00000048 => "\x48",
     0x00000049 => "\x49",
     0x0000004a => "\x4a",
     0x0000004b => "\x4b",
     0x0000004c => "\x4c",
     0x0000004d => "\x4d",
     0x0000004e => "\x4e",
     0x0000004f => "\x4f",
     0x00000050 => "\x50",
     0x00000051 => "\x51",
     0x00000052 => "\x52",
     0x00000053 => "\x53",
     0x00000054 => "\x54",
     0x00000055 => "\x55",
     0x00000056 => "\x56",
     0x00000057 => "\x57",
     0x00000058 => "\x58",
     0x00000059 => "\x59",
     0x0000005a => "\x5a",
     0x0000005b => "\x5b",
     0x0000005c => "\x5c",
     0x0000005d => "\x5d",
     0x0000005e => "\x5e",
     0x0000005f => "\x5f",
     0x00000060 => "\x60",
     0x00000061 => "\x61",
     0x00000062 => "\x62",
     0x00000063 => "\x63",
     0x00000064 => "\x64",
     0x00000065 => "\x65",
     0x00000066 => "\x66",
     0x00000067 => "\x67",
     0x00000068 => "\x68",
     0x00000069 => "\x69",
     0x0000006a => "\x6a",
     0x0000006b => "\x6b",
     0x0000006c => "\x6c",
     0x0000006d => "\x6d",
     0x0000006e => "\x6e",
     0x0000006f => "\x6f",
     0x00000070 => "\x70",
     0x00000071 => "\x71",
     0x00000072 => "\x72",
     0x00000073 => "\x73",
     0x00000074 => "\x74",
     0x00000075 => "\x75",
     0x00000076 => "\x76",
     0x00000077 => "\x77",
     0x00000078 => "\x78",
     0x00000079 => "\x79",
     0x0000007a => "\x7a",
     0x0000007b => "\x7b",
     0x0000007c => "\x7c",
     0x0000007d => "\x7d",
     0x0000007e => "\x7e",
     0x0000007f => "\x7f",
     0x000000a0 => "\xa0",
     0x00000e01 => "\xa1",
     0x00000e02 => "\xa2",
     0x00000e03 => "\xa3",
     0x00000e04 => "\xa4",
     0x00000e05 => "\xa5",
     0x00000e06 => "\xa6",
     0x00000e07 => "\xa7",
     0x00000e08 => "\xa8",
     0x00000e09 => "\xa9",
     0x00000e0a => "\xaa",
     0x00000e0b => "\xab",
     0x00000e0c => "\xac",
     0x00000e0d => "\xad",
     0x00000e0e => "\xae",
     0x00000e0f => "\xaf",
     0x00000e10 => "\xb0",
     0x00000e11 => "\xb1",
     0x00000e12 => "\xb2",
     0x00000e13 => "\xb3",
     0x00000e14 => "\xb4",
     0x00000e15 => "\xb5",
     0x00000e16 => "\xb6",
     0x00000e17 => "\xb7",
     0x00000e18 => "\xb8",
     0x00000e19 => "\xb9",
     0x00000e1a => "\xba",
     0x00000e1b => "\xbb",
     0x00000e1c => "\xbc",
     0x00000e1d => "\xbd",
     0x00000e1e => "\xbe",
     0x00000e1f => "\xbf",
     0x00000e20 => "\xc0",
     0x00000e21 => "\xc1",
     0x00000e22 => "\xc2",
     0x00000e23 => "\xc3",
     0x00000e24 => "\xc4",
     0x00000e25 => "\xc5",
     0x00000e26 => "\xc6",
     0x00000e27 => "\xc7",
     0x00000e28 => "\xc8",
     0x00000e29 => "\xc9",
     0x00000e2a => "\xca",
     0x00000e2b => "\xcb",
     0x00000e2c => "\xcc",
     0x00000e2d => "\xcd",
     0x00000e2e => "\xce",
     0x00000e2f => "\xcf",
     0x00000e30 => "\xd0",
     0x00000e31 => "\xd1",
     0x00000e32 => "\xd2",
     0x00000e33 => "\xd3",
     0x00000e34 => "\xd4",
     0x00000e35 => "\xd5",
     0x00000e36 => "\xd6",
     0x00000e37 => "\xd7",
     0x00000e38 => "\xd8",
     0x00000e39 => "\xd9",
     0x00000e3a => "\xda",
     0x00000e3f => "\xdf",
     0x00000e40 => "\xe0",
     0x00000e41 => "\xe1",
     0x00000e42 => "\xe2",
     0x00000e43 => "\xe3",
     0x00000e44 => "\xe4",
     0x00000e45 => "\xe5",
     0x00000e46 => "\xe6",
     0x00000e47 => "\xe7",
     0x00000e48 => "\xe8",
     0x00000e49 => "\xe9",
     0x00000e4a => "\xea",
     0x00000e4b => "\xeb",
     0x00000e4c => "\xec",
     0x00000e4d => "\xed",
     0x00000e4e => "\xee",
     0x00000e4f => "\xef",
     0x00000e50 => "\xf0",
     0x00000e51 => "\xf1",
     0x00000e52 => "\xf2",
     0x00000e53 => "\xf3",
     0x00000e54 => "\xf4",
     0x00000e55 => "\xf5",
     0x00000e56 => "\xf6",
     0x00000e57 => "\xf7",
     0x00000e58 => "\xf8",
     0x00000e59 => "\xf9",
     0x00000e5a => "\xfa",
     0x00000e5b => "\xfb",
     0x00002013 => "\x96",
     0x00002014 => "\x97",
     0x00002018 => "\x91",
     0x00002019 => "\x92",
     0x0000201c => "\x93",
     0x0000201d => "\x94",
     0x00002022 => "\x95",
     0x00002026 => "\x85",
     0x000020ac => "\x80",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::IBM874 - Conversion routines for IBM874
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for IBM874.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  automatically generated from the charDB
  alias CP874
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL
     01 |  00000001 | START OF HEADING
     02 |  00000002 | START OF TEXT
     03 |  00000003 | END OF TEXT
     04 |  00000004 | END OF TRANSMISSION
     05 |  00000005 | ENQUIRY
     06 |  00000006 | ACKNOWLEDGE
     07 |  00000007 | BELL
     08 |  00000008 | BACKSPACE
     09 |  00000009 | HORIZONTAL TABULATION
     0A |  0000000A | LINE FEED
     0B |  0000000B | VERTICAL TABULATION
     0C |  0000000C | FORM FEED
     0D |  0000000D | CARRIAGE RETURN
     0E |  0000000E | SHIFT OUT
     0F |  0000000F | SHIFT IN
     10 |  00000010 | DATA LINK ESCAPE
     11 |  00000011 | DEVICE CONTROL ONE
     12 |  00000012 | DEVICE CONTROL TWO
     13 |  00000013 | DEVICE CONTROL THREE
     14 |  00000014 | DEVICE CONTROL FOUR
     15 |  00000015 | NEGATIVE ACKNOWLEDGE
     16 |  00000016 | SYNCHRONOUS IDLE
     17 |  00000017 | END OF TRANSMISSION BLOCK
     18 |  00000018 | CANCEL
     19 |  00000019 | END OF MEDIUM
     1A |  0000001A | SUBSTITUTE
     1B |  0000001B | ESCAPE
     1C |  0000001C | FILE SEPARATOR
     1D |  0000001D | GROUP SEPARATOR
     1E |  0000001E | RECORD SEPARATOR
     1F |  0000001F | UNIT SEPARATOR
     20 |  00000020 | SPACE
     21 |  00000021 | EXCLAMATION MARK
     22 |  00000022 | QUOTATION MARK
     23 |  00000023 | NUMBER SIGN
     24 |  00000024 | DOLLAR SIGN
     25 |  00000025 | PERCENT SIGN
     26 |  00000026 | AMPERSAND
     27 |  00000027 | APOSTROPHE
     28 |  00000028 | LEFT PARENTHESIS
     29 |  00000029 | RIGHT PARENTHESIS
     2A |  0000002A | ASTERISK
     2B |  0000002B | PLUS SIGN
     2C |  0000002C | COMMA
     2D |  0000002D | HYPHEN-MINUS
     2E |  0000002E | FULL STOP
     2F |  0000002F | SOLIDUS
     30 |  00000030 | DIGIT ZERO
     31 |  00000031 | DIGIT ONE
     32 |  00000032 | DIGIT TWO
     33 |  00000033 | DIGIT THREE
     34 |  00000034 | DIGIT FOUR
     35 |  00000035 | DIGIT FIVE
     36 |  00000036 | DIGIT SIX
     37 |  00000037 | DIGIT SEVEN
     38 |  00000038 | DIGIT EIGHT
     39 |  00000039 | DIGIT NINE
     3A |  0000003A | COLON
     3B |  0000003B | SEMICOLON
     3C |  0000003C | LESS-THAN SIGN
     3D |  0000003D | EQUALS SIGN
     3E |  0000003E | GREATER-THAN SIGN
     3F |  0000003F | QUESTION MARK
     40 |  00000040 | COMMERCIAL AT
     41 |  00000041 | LATIN CAPITAL LETTER A
     42 |  00000042 | LATIN CAPITAL LETTER B
     43 |  00000043 | LATIN CAPITAL LETTER C
     44 |  00000044 | LATIN CAPITAL LETTER D
     45 |  00000045 | LATIN CAPITAL LETTER E
     46 |  00000046 | LATIN CAPITAL LETTER F
     47 |  00000047 | LATIN CAPITAL LETTER G
     48 |  00000048 | LATIN CAPITAL LETTER H
     49 |  00000049 | LATIN CAPITAL LETTER I
     4A |  0000004A | LATIN CAPITAL LETTER J
     4B |  0000004B | LATIN CAPITAL LETTER K
     4C |  0000004C | LATIN CAPITAL LETTER L
     4D |  0000004D | LATIN CAPITAL LETTER M
     4E |  0000004E | LATIN CAPITAL LETTER N
     4F |  0000004F | LATIN CAPITAL LETTER O
     50 |  00000050 | LATIN CAPITAL LETTER P
     51 |  00000051 | LATIN CAPITAL LETTER Q
     52 |  00000052 | LATIN CAPITAL LETTER R
     53 |  00000053 | LATIN CAPITAL LETTER S
     54 |  00000054 | LATIN CAPITAL LETTER T
     55 |  00000055 | LATIN CAPITAL LETTER U
     56 |  00000056 | LATIN CAPITAL LETTER V
     57 |  00000057 | LATIN CAPITAL LETTER W
     58 |  00000058 | LATIN CAPITAL LETTER X
     59 |  00000059 | LATIN CAPITAL LETTER Y
     5A |  0000005A | LATIN CAPITAL LETTER Z
     5B |  0000005B | LEFT SQUARE BRACKET
     5C |  0000005C | REVERSE SOLIDUS
     5D |  0000005D | RIGHT SQUARE BRACKET
     5E |  0000005E | CIRCUMFLEX ACCENT
     5F |  0000005F | LOW LINE
     60 |  00000060 | GRAVE ACCENT
     61 |  00000061 | LATIN SMALL LETTER A
     62 |  00000062 | LATIN SMALL LETTER B
     63 |  00000063 | LATIN SMALL LETTER C
     64 |  00000064 | LATIN SMALL LETTER D
     65 |  00000065 | LATIN SMALL LETTER E
     66 |  00000066 | LATIN SMALL LETTER F
     67 |  00000067 | LATIN SMALL LETTER G
     68 |  00000068 | LATIN SMALL LETTER H
     69 |  00000069 | LATIN SMALL LETTER I
     6A |  0000006A | LATIN SMALL LETTER J
     6B |  0000006B | LATIN SMALL LETTER K
     6C |  0000006C | LATIN SMALL LETTER L
     6D |  0000006D | LATIN SMALL LETTER M
     6E |  0000006E | LATIN SMALL LETTER N
     6F |  0000006F | LATIN SMALL LETTER O
     70 |  00000070 | LATIN SMALL LETTER P
     71 |  00000071 | LATIN SMALL LETTER Q
     72 |  00000072 | LATIN SMALL LETTER R
     73 |  00000073 | LATIN SMALL LETTER S
     74 |  00000074 | LATIN SMALL LETTER T
     75 |  00000075 | LATIN SMALL LETTER U
     76 |  00000076 | LATIN SMALL LETTER V
     77 |  00000077 | LATIN SMALL LETTER W
     78 |  00000078 | LATIN SMALL LETTER X
     79 |  00000079 | LATIN SMALL LETTER Y
     7A |  0000007A | LATIN SMALL LETTER Z
     7B |  0000007B | LEFT CURLY BRACKET
     7C |  0000007C | VERTICAL LINE
     7D |  0000007D | RIGHT CURLY BRACKET
     7E |  0000007E | TILDE
     7F |  0000007F | DELETE
     80 |  000020AC | EURO SIGN
     85 |  00002026 | HORIZONTAL ELLIPSIS
     91 |  00002018 | LEFT SINGLE QUOTATION MARK
     92 |  00002019 | RIGHT SINGLE QUOTATION MARK
     93 |  0000201C | LEFT DOUBLE QUOTATION MARK
     94 |  0000201D | RIGHT DOUBLE QUOTATION MARK
     95 |  00002022 | BULLET
     96 |  00002013 | EN DASH
     97 |  00002014 | EM DASH
     A0 |  000000A0 | NO-BREAK SPACE
     A1 |  00000E01 | THAI CHARACTER KO KAI
     A2 |  00000E02 | THAI CHARACTER KHO KHAI
     A3 |  00000E03 | THAI CHARACTER KHO KHUAT
     A4 |  00000E04 | THAI CHARACTER KHO KHWAI
     A5 |  00000E05 | THAI CHARACTER KHO KHON
     A6 |  00000E06 | THAI CHARACTER KHO RAKHANG
     A7 |  00000E07 | THAI CHARACTER NGO NGU
     A8 |  00000E08 | THAI CHARACTER CHO CHAN
     A9 |  00000E09 | THAI CHARACTER CHO CHING
     AA |  00000E0A | THAI CHARACTER CHO CHANG
     AB |  00000E0B | THAI CHARACTER SO SO
     AC |  00000E0C | THAI CHARACTER CHO CHOE
     AD |  00000E0D | THAI CHARACTER YO YING
     AE |  00000E0E | THAI CHARACTER DO CHADA
     AF |  00000E0F | THAI CHARACTER TO PATAK
     B0 |  00000E10 | THAI CHARACTER THO THAN
     B1 |  00000E11 | THAI CHARACTER THO NANGMONTHO
     B2 |  00000E12 | THAI CHARACTER THO PHUTHAO
     B3 |  00000E13 | THAI CHARACTER NO NEN
     B4 |  00000E14 | THAI CHARACTER DO DEK
     B5 |  00000E15 | THAI CHARACTER TO TAO
     B6 |  00000E16 | THAI CHARACTER THO THUNG
     B7 |  00000E17 | THAI CHARACTER THO THAHAN
     B8 |  00000E18 | THAI CHARACTER THO THONG
     B9 |  00000E19 | THAI CHARACTER NO NU
     BA |  00000E1A | THAI CHARACTER BO BAIMAI
     BB |  00000E1B | THAI CHARACTER PO PLA
     BC |  00000E1C | THAI CHARACTER PHO PHUNG
     BD |  00000E1D | THAI CHARACTER FO FA
     BE |  00000E1E | THAI CHARACTER PHO PHAN
     BF |  00000E1F | THAI CHARACTER FO FAN
     C0 |  00000E20 | THAI CHARACTER PHO SAMPHAO
     C1 |  00000E21 | THAI CHARACTER MO MA
     C2 |  00000E22 | THAI CHARACTER YO YAK
     C3 |  00000E23 | THAI CHARACTER RO RUA
     C4 |  00000E24 | THAI CHARACTER RU
     C5 |  00000E25 | THAI CHARACTER LO LING
     C6 |  00000E26 | THAI CHARACTER LU
     C7 |  00000E27 | THAI CHARACTER WO WAEN
     C8 |  00000E28 | THAI CHARACTER SO SALA
     C9 |  00000E29 | THAI CHARACTER SO RUSI
     CA |  00000E2A | THAI CHARACTER SO SUA
     CB |  00000E2B | THAI CHARACTER HO HIP
     CC |  00000E2C | THAI CHARACTER LO CHULA
     CD |  00000E2D | THAI CHARACTER O ANG
     CE |  00000E2E | THAI CHARACTER HO NOKHUK
     CF |  00000E2F | THAI CHARACTER PAIYANNOI
     D0 |  00000E30 | THAI CHARACTER SARA A
     D1 |  00000E31 | THAI CHARACTER MAI HAN-AKAT
     D2 |  00000E32 | THAI CHARACTER SARA AA
     D3 |  00000E33 | THAI CHARACTER SARA AM
     D4 |  00000E34 | THAI CHARACTER SARA I
     D5 |  00000E35 | THAI CHARACTER SARA II
     D6 |  00000E36 | THAI CHARACTER SARA UE
     D7 |  00000E37 | THAI CHARACTER SARA UEE
     D8 |  00000E38 | THAI CHARACTER SARA U
     D9 |  00000E39 | THAI CHARACTER SARA UU
     DA |  00000E3A | THAI CHARACTER PHINTHU
     DF |  00000E3F | THAI CURRENCY SYMBOL BAHT
     E0 |  00000E40 | THAI CHARACTER SARA E
     E1 |  00000E41 | THAI CHARACTER SARA AE
     E2 |  00000E42 | THAI CHARACTER SARA O
     E3 |  00000E43 | THAI CHARACTER SARA AI MAIMUAN
     E4 |  00000E44 | THAI CHARACTER SARA AI MAIMALAI
     E5 |  00000E45 | THAI CHARACTER LAKKHANGYAO
     E6 |  00000E46 | THAI CHARACTER MAIYAMOK
     E7 |  00000E47 | THAI CHARACTER MAITAIKHU
     E8 |  00000E48 | THAI CHARACTER MAI EK
     E9 |  00000E49 | THAI CHARACTER MAI THO
     EA |  00000E4A | THAI CHARACTER MAI TRI
     EB |  00000E4B | THAI CHARACTER MAI CHATTAWA
     EC |  00000E4C | THAI CHARACTER THANTHAKHAT
     ED |  00000E4D | THAI CHARACTER NIKHAHIT
     EE |  00000E4E | THAI CHARACTER YAMAKKAN
     EF |  00000E4F | THAI CHARACTER FONGMAN
     F0 |  00000E50 | THAI DIGIT ZERO
     F1 |  00000E51 | THAI DIGIT ONE
     F2 |  00000E52 | THAI DIGIT TWO
     F3 |  00000E53 | THAI DIGIT THREE
     F4 |  00000E54 | THAI DIGIT FOUR
     F5 |  00000E55 | THAI DIGIT FIVE
     F6 |  00000E56 | THAI DIGIT SIX
     F7 |  00000E57 | THAI DIGIT SEVEN
     F8 |  00000E58 | THAI DIGIT EIGHT
     F9 |  00000E59 | THAI DIGIT NINE
     FA |  00000E5A | THAI CHARACTER ANGKHANKHU
     FB |  00000E5B | THAI CHARACTER KHOMUT
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/IBM875.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for IBM875.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::IBM875;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x009c,
     0x0009,
     0x0086,
     0x007f,
     0x0097,
     0x008d,
     0x008e,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x009d,
     0x0085,
     0x0008,
     0x0087,
     0x0018,
     0x0019,
     0x0092,
     0x008f,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0080,
     0x0081,
     0x0082,
     0x0083,
     0x0084,
     0x000a,
     0x0017,
     0x001b,
     0x0088,
     0x0089,
     0x008a,
     0x008b,
     0x008c,
     0x0005,
     0x0006,
     0x0007,
     0x0090,
     0x0091,
     0x0016,
     0x0093,
     0x0094,
     0x0095,
     0x0096,
     0x0004,
     0x0098,
     0x0099,
     0x009a,
     0x009b,
     0x0014,
     0x0015,
     0x009e,
     0x001a,
     0x0020,
     0x0391,
     0x0392,
     0x0393,
     0x0394,
     0x0395,
     0x0396,
     0x0397,
     0x0398,
     0x0399,
     0x005b,
     0x002e,
     0x003c,
     0x0028,
     0x002b,
     0x0021,
     0x0026,
     0x039a,
     0x039b,
     0x039c,
     0x039d,
     0x039e,
     0x039f,
     0x03a0,
     0x03a1,
     0x03a3,
     0x005d,
     0x0024,
     0x002a,
     0x0029,
     0x003b,
     0x005e,
     0x002d,
     0x002f,
     0x03a4,
     0x03a5,
     0x03a6,
     0x03a7,
     0x03a8,
     0x03a9,
     0x03aa,
     0x03ab,
     0xfffd,
     0x002c,
     0x0025,
     0x005f,
     0x003e,
     0x003f,
     0x00a8,
     0x0386,
     0x0388,
     0x0389,
     0x2207,
     0x038a,
     0x038c,
     0x038e,
     0x038f,
     0x0060,
     0x003a,
     0x0023,
     0x0040,
     0x0027,
     0x003d,
     0x0022,
     0x0385,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x03b1,
     0x03b2,
     0x03b3,
     0x03b4,
     0x03b5,
     0x03b6,
     0x00b0,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x03b7,
     0x03b8,
     0x03b9,
     0x03ba,
     0x03bb,
     0x03bc,
     0x00b4,
     0x007e,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x03bd,
     0x03be,
     0x03bf,
     0x03c0,
     0x03c1,
     0x03c3,
     0x00a3,
     0x03ac,
     0x03ad,
     0x03ae,
     0x0390,
     0x03af,
     0x03cc,
     0x03cd,
     0x03b0,
     0x03ce,
     0x03c2,
     0x03c4,
     0x03c5,
     0x03c6,
     0x03c7,
     0x03c8,
     0x007b,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x00ad,
     0x03c9,
     0x03ca,
     0x03cb,
     0x2018,
     0x2015,
     0x007d,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x00b1,
     0x00bd,
     0xfffd,
     0x00b7,
     0x2019,
     0x00a6,
     0x005c,
     0xfffd,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x00b2,
     0x00a7,
     0xfffd,
     0xfffd,
     0x00ab,
     0x00ac,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x00b3,
     0x00a9,
     0xfffd,
     0xfffd,
     0x00bb,
     0x009f,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\xc2\x9c",
     "\x09",
     "\xc2\x86",
     "\x7f",
     "\xc2\x97",
     "\xc2\x8d",
     "\xc2\x8e",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\xc2\x9d",
     "\xc2\x85",
     "\x08",
     "\xc2\x87",
     "\x18",
     "\x19",
     "\xc2\x92",
     "\xc2\x8f",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\xc2\x80",
     "\xc2\x81",
     "\xc2\x82",
     "\xc2\x83",
     "\xc2\x84",
     "\x0a",
     "\x17",
     "\x1b",
     "\xc2\x88",
     "\xc2\x89",
     "\xc2\x8a",
     "\xc2\x8b",
     "\xc2\x8c",
     "\x05",
     "\x06",
     "\x07",
     "\xc2\x90",
     "\xc2\x91",
     "\x16",
     "\xc2\x93",
     "\xc2\x94",
     "\xc2\x95",
     "\xc2\x96",
     "\x04",
     "\xc2\x98",
     "\xc2\x99",
     "\xc2\x9a",
     "\xc2\x9b",
     "\x14",
     "\x15",
     "\xc2\x9e",
     "\x1a",
     "\x20",
     "\xce\x91",
     "\xce\x92",
     "\xce\x93",
     "\xce\x94",
     "\xce\x95",
     "\xce\x96",
     "\xce\x97",
     "\xce\x98",
     "\xce\x99",
     "\x5b",
     "\x2e",
     "\x3c",
     "\x28",
     "\x2b",
     "\x21",
     "\x26",
     "\xce\x9a",
     "\xce\x9b",
     "\xce\x9c",
     "\xce\x9d",
     "\xce\x9e",
     "\xce\x9f",
     "\xce\xa0",
     "\xce\xa1",
     "\xce\xa3",
     "\x5d",
     "\x24",
     "\x2a",
     "\x29",
     "\x3b",
     "\x5e",
     "\x2d",
     "\x2f",
     "\xce\xa4",
     "\xce\xa5",
     "\xce\xa6",
     "\xce\xa7",
     "\xce\xa8",
     "\xce\xa9",
     "\xce\xaa",
     "\xce\xab",
     "\xef\xbf\xbd",
     "\x2c",
     "\x25",
     "\x5f",
     "\x3e",
     "\x3f",
     "\xc2\xa8",
     "\xce\x86",
     "\xce\x88",
     "\xce\x89",
     "\xe2\x88\x87",
     "\xce\x8a",
     "\xce\x8c",
     "\xce\x8e",
     "\xce\x8f",
     "\x60",
     "\x3a",
     "\x23",
     "\x40",
     "\x27",
     "\x3d",
     "\x22",
     "\xce\x85",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\xce\xb1",
     "\xce\xb2",
     "\xce\xb3",
     "\xce\xb4",
     "\xce\xb5",
     "\xce\xb6",
     "\xc2\xb0",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\xce\xb7",
     "\xce\xb8",
     "\xce\xb9",
     "\xce\xba",
     "\xce\xbb",
     "\xce\xbc",
     "\xc2\xb4",
     "\x7e",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\xce\xbd",
     "\xce\xbe",
     "\xce\xbf",
     "\xcf\x80",
     "\xcf\x81",
     "\xcf\x83",
     "\xc2\xa3",
     "\xce\xac",
     "\xce\xad",
     "\xce\xae",
     "\xce\x90",
     "\xce\xaf",
     "\xcf\x8c",
     "\xcf\x8d",
     "\xce\xb0",
     "\xcf\x8e",
     "\xcf\x82",
     "\xcf\x84",
     "\xcf\x85",
     "\xcf\x86",
     "\xcf\x87",
     "\xcf\x88",
     "\x7b",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\xc2\xad",
     "\xcf\x89",
     "\xcf\x8a",
     "\xcf\x8b",
     "\xe2\x80\x98",
     "\xe2\x80\x95",
     "\x7d",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\xc2\xb1",
     "\xc2\xbd",
     "\xef\xbf\xbd",
     "\xc2\xb7",
     "\xe2\x80\x99",
     "\xc2\xa6",
     "\x5c",
     "\xef\xbf\xbd",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\xc2\xb2",
     "\xc2\xa7",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc2\xab",
     "\xc2\xac",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\xc2\xb3",
     "\xc2\xa9",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc2\xbb",
     "\xc2\x9f",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x37",
     0x00000005 => "\x2d",
     0x00000006 => "\x2e",
     0x00000007 => "\x2f",
     0x00000008 => "\x16",
     0x00000009 => "\x05",
     0x0000000a => "\x25",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x3c",
     0x00000015 => "\x3d",
     0x00000016 => "\x32",
     0x00000017 => "\x26",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x3f",
     0x0000001b => "\x27",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x40",
     0x00000021 => "\x4f",
     0x00000022 => "\x7f",
     0x00000023 => "\x7b",
     0x00000024 => "\x5b",
     0x00000025 => "\x6c",
     0x00000026 => "\x50",
     0x00000027 => "\x7d",
     0x00000028 => "\x4d",
     0x00000029 => "\x5d",
     0x0000002a => "\x5c",
     0x0000002b => "\x4e",
     0x0000002c => "\x6b",
     0x0000002d => "\x60",
     0x0000002e => "\x4b",
     0x0000002f => "\x61",
     0x00000030 => "\xf0",
     0x00000031 => "\xf1",
     0x00000032 => "\xf2",
     0x00000033 => "\xf3",
     0x00000034 => "\xf4",
     0x00000035 => "\xf5",
     0x00000036 => "\xf6",
     0x00000037 => "\xf7",
     0x00000038 => "\xf8",
     0x00000039 => "\xf9",
     0x0000003a => "\x7a",
     0x0000003b => "\x5e",
     0x0000003c => "\x4c",
     0x0000003d => "\x7e",
     0x0000003e => "\x6e",
     0x0000003f => "\x6f",
     0x00000040 => "\x7c",
     0x00000041 => "\xc1",
     0x00000042 => "\xc2",
     0x00000043 => "\xc3",
     0x00000044 => "\xc4",
     0x00000045 => "\xc5",
     0x00000046 => "\xc6",
     0x00000047 => "\xc7",
     0x00000048 => "\xc8",
     0x00000049 => "\xc9",
     0x0000004a => "\xd1",
     0x0000004b => "\xd2",
     0x0000004c => "\xd3",
     0x0000004d => "\xd4",
     0x0000004e => "\xd5",
     0x0000004f => "\xd6",
     0x00000050 => "\xd7",
     0x00000051 => "\xd8",
     0x00000052 => "\xd9",
     0x00000053 => "\xe2",
     0x00000054 => "\xe3",
     0x00000055 => "\xe4",
     0x00000056 => "\xe5",
     0x00000057 => "\xe6",
     0x00000058 => "\xe7",
     0x00000059 => "\xe8",
     0x0000005a => "\xe9",
     0x0000005b => "\x4a",
     0x0000005c => "\xe0",
     0x0000005d => "\x5a",
     0x0000005e => "\x5f",
     0x0000005f => "\x6d",
     0x00000060 => "\x79",
     0x00000061 => "\x81",
     0x00000062 => "\x82",
     0x00000063 => "\x83",
     0x00000064 => "\x84",
     0x00000065 => "\x85",
     0x00000066 => "\x86",
     0x00000067 => "\x87",
     0x00000068 => "\x88",
     0x00000069 => "\x89",
     0x0000006a => "\x91",
     0x0000006b => "\x92",
     0x0000006c => "\x93",
     0x0000006d => "\x94",
     0x0000006e => "\x95",
     0x0000006f => "\x96",
     0x00000070 => "\x97",
     0x00000071 => "\x98",
     0x00000072 => "\x99",
     0x00000073 => "\xa2",
     0x00000074 => "\xa3",
     0x00000075 => "\xa4",
     0x00000076 => "\xa5",
     0x00000077 => "\xa6",
     0x00000078 => "\xa7",
     0x00000079 => "\xa8",
     0x0000007a => "\xa9",
     0x0000007b => "\xc0",
     0x0000007d => "\xd0",
     0x0000007e => "\xa1",
     0x0000007f => "\x07",
     0x00000080 => "\x20",
     0x00000081 => "\x21",
     0x00000082 => "\x22",
     0x00000083 => "\x23",
     0x00000084 => "\x24",
     0x00000085 => "\x15",
     0x00000086 => "\x06",
     0x00000087 => "\x17",
     0x00000088 => "\x28",
     0x00000089 => "\x29",
     0x0000008a => "\x2a",
     0x0000008b => "\x2b",
     0x0000008c => "\x2c",
     0x0000008d => "\x09",
     0x0000008e => "\x0a",
     0x0000008f => "\x1b",
     0x00000090 => "\x30",
     0x00000091 => "\x31",
     0x00000092 => "\x1a",
     0x00000093 => "\x33",
     0x00000094 => "\x34",
     0x00000095 => "\x35",
     0x00000096 => "\x36",
     0x00000097 => "\x08",
     0x00000098 => "\x38",
     0x00000099 => "\x39",
     0x0000009a => "\x3a",
     0x0000009b => "\x3b",
     0x0000009c => "\x04",
     0x0000009d => "\x14",
     0x0000009e => "\x3e",
     0x0000009f => "\xff",
     0x000000a3 => "\xb0",
     0x000000a6 => "\xdf",
     0x000000a7 => "\xeb",
     0x000000a8 => "\x70",
     0x000000a9 => "\xfb",
     0x000000ab => "\xee",
     0x000000ac => "\xef",
     0x000000ad => "\xca",
     0x000000b0 => "\x90",
     0x000000b1 => "\xda",
     0x000000b2 => "\xea",
     0x000000b3 => "\xfa",
     0x000000b4 => "\xa0",
     0x000000b7 => "\xdd",
     0x000000bb => "\xfe",
     0x000000bd => "\xdb",
     0x00000385 => "\x80",
     0x00000386 => "\x71",
     0x00000388 => "\x72",
     0x00000389 => "\x73",
     0x0000038a => "\x75",
     0x0000038c => "\x76",
     0x0000038e => "\x77",
     0x0000038f => "\x78",
     0x00000390 => "\xb4",
     0x00000391 => "\x41",
     0x00000392 => "\x42",
     0x00000393 => "\x43",
     0x00000394 => "\x44",
     0x00000395 => "\x45",
     0x00000396 => "\x46",
     0x00000397 => "\x47",
     0x00000398 => "\x48",
     0x00000399 => "\x49",
     0x0000039a => "\x51",
     0x0000039b => "\x52",
     0x0000039c => "\x53",
     0x0000039d => "\x54",
     0x0000039e => "\x55",
     0x0000039f => "\x56",
     0x000003a0 => "\x57",
     0x000003a1 => "\x58",
     0x000003a3 => "\x59",
     0x000003a4 => "\x62",
     0x000003a5 => "\x63",
     0x000003a6 => "\x64",
     0x000003a7 => "\x65",
     0x000003a8 => "\x66",
     0x000003a9 => "\x67",
     0x000003aa => "\x68",
     0x000003ab => "\x69",
     0x000003ac => "\xb1",
     0x000003ad => "\xb2",
     0x000003ae => "\xb3",
     0x000003af => "\xb5",
     0x000003b0 => "\xb8",
     0x000003b1 => "\x8a",
     0x000003b2 => "\x8b",
     0x000003b3 => "\x8c",
     0x000003b4 => "\x8d",
     0x000003b5 => "\x8e",
     0x000003b6 => "\x8f",
     0x000003b7 => "\x9a",
     0x000003b8 => "\x9b",
     0x000003b9 => "\x9c",
     0x000003ba => "\x9d",
     0x000003bb => "\x9e",
     0x000003bc => "\x9f",
     0x000003bd => "\xaa",
     0x000003be => "\xab",
     0x000003bf => "\xac",
     0x000003c0 => "\xad",
     0x000003c1 => "\xae",
     0x000003c2 => "\xba",
     0x000003c3 => "\xaf",
     0x000003c4 => "\xbb",
     0x000003c5 => "\xbc",
     0x000003c6 => "\xbd",
     0x000003c7 => "\xbe",
     0x000003c8 => "\xbf",
     0x000003c9 => "\xcb",
     0x000003ca => "\xcc",
     0x000003cb => "\xcd",
     0x000003cc => "\xb6",
     0x000003cd => "\xb7",
     0x000003ce => "\xb9",
     0x00002015 => "\xcf",
     0x00002018 => "\xce",
     0x00002019 => "\xde",
     0x00002207 => "\x74",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x6f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::IBM875 - Conversion routines for IBM875
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for IBM875.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
   source: UNICODE 1.0
  alias CP875
  alias EBCDIC-GREEK
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  0000009C | STRING TERMINATOR (ST)
     05 |  00000009 | CHARACTER TABULATION (HT)
     06 |  00000086 | START OF SELECTED AREA (SSA)
     07 |  0000007F | DELETE (DEL)
     08 |  00000097 | END OF GUARDED AREA (EPA)
     09 |  0000008D | REVERSE LINE FEED (RI)
     0A |  0000008E | SINGLE-SHIFT TWO (SS2)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  0000009D | OPERATING SYSTEM COMMAND (OSC)
     15 |  00000085 | NEXT LINE (NEL)
     16 |  00000008 | BACKSPACE (BS)
     17 |  00000087 | END OF SELECTED AREA (ESA)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  00000092 | PRIVATE USE TWO (PU2)
     1B |  0000008F | SINGLE-SHIFT THREE (SS3)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000080 | PADDING CHARACTER (PAD)
     21 |  00000081 | HIGH OCTET PRESET (HOP)
     22 |  00000082 | BREAK PERMITTED HERE (BPH)
     23 |  00000083 | NO BREAK HERE (NBH)
     24 |  00000084 | INDEX (IND)
     25 |  0000000A | LINE FEED (LF)
     26 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     27 |  0000001B | ESCAPE (ESC)
     28 |  00000088 | CHARACTER TABULATION SET (HTS)
     29 |  00000089 | CHARACTER TABULATION WITH JUSTIFICATION (HTJ)
     2A |  0000008A | LINE TABULATION SET (VTS)
     2B |  0000008B | PARTIAL LINE FORWARD (PLD)
     2C |  0000008C | PARTIAL LINE BACKWARD (PLU)
     2D |  00000005 | ENQUIRY (ENQ)
     2E |  00000006 | ACKNOWLEDGE (ACK)
     2F |  00000007 | BELL (BEL)
     30 |  00000090 | DEVICE CONTROL STRING (DCS)
     31 |  00000091 | PRIVATE USE ONE (PU1)
     32 |  00000016 | SYNCHRONOUS IDLE (SYN)
     33 |  00000093 | SET TRANSMIT STATE (STS)
     34 |  00000094 | CANCEL CHARACTER (CCH)
     35 |  00000095 | MESSAGE WAITING (MW)
     36 |  00000096 | START OF GUARDED AREA (SPA)
     37 |  00000004 | END OF TRANSMISSION (EOT)
     38 |  00000098 | START OF STRING (SOS)
     39 |  00000099 | SINGLE GRAPHIC CHARACTER INTRODUCER (SGCI)
     3A |  0000009A | SINGLE CHARACTER INTRODUCER (SCI)
     3B |  0000009B | CONTROL SEQUENCE INTRODUCER (CSI)
     3C |  00000014 | DEVICE CONTROL FOUR (DC4)
     3D |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     3E |  0000009E | PRIVACY MESSAGE (PM)
     3F |  0000001A | SUBSTITUTE (SUB)
     40 |  00000020 | SPACE
     41 |  00000391 | GREEK CAPITAL LETTER ALPHA
     42 |  00000392 | GREEK CAPITAL LETTER BETA
     43 |  00000393 | GREEK CAPITAL LETTER GAMMA
     44 |  00000394 | GREEK CAPITAL LETTER DELTA
     45 |  00000395 | GREEK CAPITAL LETTER EPSILON
     46 |  00000396 | GREEK CAPITAL LETTER ZETA
     47 |  00000397 | GREEK CAPITAL LETTER ETA
     48 |  00000398 | GREEK CAPITAL LETTER THETA
     49 |  00000399 | GREEK CAPITAL LETTER IOTA
     4A |  0000005B | LEFT SQUARE BRACKET
     4B |  0000002E | FULL STOP
     4C |  0000003C | LESS-THAN SIGN
     4D |  00000028 | LEFT PARENTHESIS
     4E |  0000002B | PLUS SIGN
     4F |  00000021 | EXCLAMATION MARK
     50 |  00000026 | AMPERSAND
     51 |  0000039A | GREEK CAPITAL LETTER KAPPA
     52 |  0000039B | GREEK CAPITAL LETTER LAMDA
     53 |  0000039C | GREEK CAPITAL LETTER MU
     54 |  0000039D | GREEK CAPITAL LETTER NU
     55 |  0000039E | GREEK CAPITAL LETTER XI
     56 |  0000039F | GREEK CAPITAL LETTER OMICRON
     57 |  000003A0 | GREEK CAPITAL LETTER PI
     58 |  000003A1 | GREEK CAPITAL LETTER RHO
     59 |  000003A3 | GREEK CAPITAL LETTER SIGMA
     5A |  0000005D | RIGHT SQUARE BRACKET
     5B |  00000024 | DOLLAR SIGN
     5C |  0000002A | ASTERISK
     5D |  00000029 | RIGHT PARENTHESIS
     5E |  0000003B | SEMICOLON
     5F |  0000005E | CIRCUMFLEX ACCENT
     60 |  0000002D | HYPHEN-MINUS
     61 |  0000002F | SOLIDUS
     62 |  000003A4 | GREEK CAPITAL LETTER TAU
     63 |  000003A5 | GREEK CAPITAL LETTER UPSILON
     64 |  000003A6 | GREEK CAPITAL LETTER PHI
     65 |  000003A7 | GREEK CAPITAL LETTER CHI
     66 |  000003A8 | GREEK CAPITAL LETTER PSI
     67 |  000003A9 | GREEK CAPITAL LETTER OMEGA
     68 |  000003AA | GREEK CAPITAL LETTER IOTA WITH DIALYTIKA
     69 |  000003AB | GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA
     6B |  0000002C | COMMA
     6C |  00000025 | PERCENT SIGN
     6D |  0000005F | LOW LINE
     6E |  0000003E | GREATER-THAN SIGN
     6F |  0000003F | QUESTION MARK
     70 |  000000A8 | DIAERESIS
     71 |  00000386 | GREEK CAPITAL LETTER ALPHA WITH TONOS
     72 |  00000388 | GREEK CAPITAL LETTER EPSILON WITH TONOS
     73 |  00000389 | GREEK CAPITAL LETTER ETA WITH TONOS
     74 |  00002207 | NABLA
     75 |  0000038A | GREEK CAPITAL LETTER IOTA WITH TONOS
     76 |  0000038C | GREEK CAPITAL LETTER OMICRON WITH TONOS
     77 |  0000038E | GREEK CAPITAL LETTER UPSILON WITH TONOS
     78 |  0000038F | GREEK CAPITAL LETTER OMEGA WITH TONOS
     79 |  00000060 | GRAVE ACCENT
     7A |  0000003A | COLON
     7B |  00000023 | NUMBER SIGN
     7C |  00000040 | COMMERCIAL AT
     7D |  00000027 | APOSTROPHE
     7E |  0000003D | EQUALS SIGN
     7F |  00000022 | QUOTATION MARK
     80 |  00000385 | GREEK DIALYTIKA TONOS
     81 |  00000061 | LATIN SMALL LETTER A
     82 |  00000062 | LATIN SMALL LETTER B
     83 |  00000063 | LATIN SMALL LETTER C
     84 |  00000064 | LATIN SMALL LETTER D
     85 |  00000065 | LATIN SMALL LETTER E
     86 |  00000066 | LATIN SMALL LETTER F
     87 |  00000067 | LATIN SMALL LETTER G
     88 |  00000068 | LATIN SMALL LETTER H
     89 |  00000069 | LATIN SMALL LETTER I
     8A |  000003B1 | GREEK SMALL LETTER ALPHA
     8B |  000003B2 | GREEK SMALL LETTER BETA
     8C |  000003B3 | GREEK SMALL LETTER GAMMA
     8D |  000003B4 | GREEK SMALL LETTER DELTA
     8E |  000003B5 | GREEK SMALL LETTER EPSILON
     8F |  000003B6 | GREEK SMALL LETTER ZETA
     90 |  000000B0 | DEGREE SIGN
     91 |  0000006A | LATIN SMALL LETTER J
     92 |  0000006B | LATIN SMALL LETTER K
     93 |  0000006C | LATIN SMALL LETTER L
     94 |  0000006D | LATIN SMALL LETTER M
     95 |  0000006E | LATIN SMALL LETTER N
     96 |  0000006F | LATIN SMALL LETTER O
     97 |  00000070 | LATIN SMALL LETTER P
     98 |  00000071 | LATIN SMALL LETTER Q
     99 |  00000072 | LATIN SMALL LETTER R
     9A |  000003B7 | GREEK SMALL LETTER ETA
     9B |  000003B8 | GREEK SMALL LETTER THETA
     9C |  000003B9 | GREEK SMALL LETTER IOTA
     9D |  000003BA | GREEK SMALL LETTER KAPPA
     9E |  000003BB | GREEK SMALL LETTER LAMDA
     9F |  000003BC | GREEK SMALL LETTER MU
     A0 |  000000B4 | ACUTE ACCENT
     A1 |  0000007E | TILDE
     A2 |  00000073 | LATIN SMALL LETTER S
     A3 |  00000074 | LATIN SMALL LETTER T
     A4 |  00000075 | LATIN SMALL LETTER U
     A5 |  00000076 | LATIN SMALL LETTER V
     A6 |  00000077 | LATIN SMALL LETTER W
     A7 |  00000078 | LATIN SMALL LETTER X
     A8 |  00000079 | LATIN SMALL LETTER Y
     A9 |  0000007A | LATIN SMALL LETTER Z
     AA |  000003BD | GREEK SMALL LETTER NU
     AB |  000003BE | GREEK SMALL LETTER XI
     AC |  000003BF | GREEK SMALL LETTER OMICRON
     AD |  000003C0 | GREEK SMALL LETTER PI
     AE |  000003C1 | GREEK SMALL LETTER RHO
     AF |  000003C3 | GREEK SMALL LETTER SIGMA
     B0 |  000000A3 | POUND SIGN
     B1 |  000003AC | GREEK SMALL LETTER ALPHA WITH TONOS
     B2 |  000003AD | GREEK SMALL LETTER EPSILON WITH TONOS
     B3 |  000003AE | GREEK SMALL LETTER ETA WITH TONOS
     B4 |  00000390 | GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS
     B5 |  000003AF | GREEK SMALL LETTER IOTA WITH TONOS
     B6 |  000003CC | GREEK SMALL LETTER OMICRON WITH TONOS
     B7 |  000003CD | GREEK SMALL LETTER UPSILON WITH TONOS
     B8 |  000003B0 | GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS
     B9 |  000003CE | GREEK SMALL LETTER OMEGA WITH TONOS
     BA |  000003C2 | GREEK SMALL LETTER FINAL SIGMA
     BB |  000003C4 | GREEK SMALL LETTER TAU
     BC |  000003C5 | GREEK SMALL LETTER UPSILON
     BD |  000003C6 | GREEK SMALL LETTER PHI
     BE |  000003C7 | GREEK SMALL LETTER CHI
     BF |  000003C8 | GREEK SMALL LETTER PSI
     C0 |  0000007B | LEFT CURLY BRACKET
     C1 |  00000041 | LATIN CAPITAL LETTER A
     C2 |  00000042 | LATIN CAPITAL LETTER B
     C3 |  00000043 | LATIN CAPITAL LETTER C
     C4 |  00000044 | LATIN CAPITAL LETTER D
     C5 |  00000045 | LATIN CAPITAL LETTER E
     C6 |  00000046 | LATIN CAPITAL LETTER F
     C7 |  00000047 | LATIN CAPITAL LETTER G
     C8 |  00000048 | LATIN CAPITAL LETTER H
     C9 |  00000049 | LATIN CAPITAL LETTER I
     CA |  000000AD | SOFT HYPHEN
     CB |  000003C9 | GREEK SMALL LETTER OMEGA
     CC |  000003CA | GREEK SMALL LETTER IOTA WITH DIALYTIKA
     CD |  000003CB | GREEK SMALL LETTER UPSILON WITH DIALYTIKA
     CE |  00002018 | LEFT SINGLE QUOTATION MARK
     CF |  00002015 | HORIZONTAL BAR
     D0 |  0000007D | RIGHT CURLY BRACKET
     D1 |  0000004A | LATIN CAPITAL LETTER J
     D2 |  0000004B | LATIN CAPITAL LETTER K
     D3 |  0000004C | LATIN CAPITAL LETTER L
     D4 |  0000004D | LATIN CAPITAL LETTER M
     D5 |  0000004E | LATIN CAPITAL LETTER N
     D6 |  0000004F | LATIN CAPITAL LETTER O
     D7 |  00000050 | LATIN CAPITAL LETTER P
     D8 |  00000051 | LATIN CAPITAL LETTER Q
     D9 |  00000052 | LATIN CAPITAL LETTER R
     DA |  000000B1 | PLUS-MINUS SIGN
     DB |  000000BD | VULGAR FRACTION ONE HALF
     DD |  000000B7 | MIDDLE DOT
     DE |  00002019 | RIGHT SINGLE QUOTATION MARK
     DF |  000000A6 | BROKEN BAR
     E0 |  0000005C | REVERSE SOLIDUS
     E2 |  00000053 | LATIN CAPITAL LETTER S
     E3 |  00000054 | LATIN CAPITAL LETTER T
     E4 |  00000055 | LATIN CAPITAL LETTER U
     E5 |  00000056 | LATIN CAPITAL LETTER V
     E6 |  00000057 | LATIN CAPITAL LETTER W
     E7 |  00000058 | LATIN CAPITAL LETTER X
     E8 |  00000059 | LATIN CAPITAL LETTER Y
     E9 |  0000005A | LATIN CAPITAL LETTER Z
     EA |  000000B2 | SUPERSCRIPT TWO
     EB |  000000A7 | SECTION SIGN
     EE |  000000AB | LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
     EF |  000000AC | NOT SIGN
     F0 |  00000030 | DIGIT ZERO
     F1 |  00000031 | DIGIT ONE
     F2 |  00000032 | DIGIT TWO
     F3 |  00000033 | DIGIT THREE
     F4 |  00000034 | DIGIT FOUR
     F5 |  00000035 | DIGIT FIVE
     F6 |  00000036 | DIGIT SIX
     F7 |  00000037 | DIGIT SEVEN
     F8 |  00000038 | DIGIT EIGHT
     F9 |  00000039 | DIGIT NINE
     FA |  000000B3 | SUPERSCRIPT THREE
     FB |  000000A9 | COPYRIGHT SIGN
     FE |  000000BB | RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
     FF |  0000009F | APPLICATION PROGRAM COMMAND (APC)
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/IBM880.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for IBM880.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::IBM880;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x009c,
     0x0009,
     0x0086,
     0x007f,
     0x0097,
     0x008d,
     0x008e,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x009d,
     0x0085,
     0x0008,
     0x0087,
     0x0018,
     0x0019,
     0x0092,
     0x008f,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0080,
     0x0081,
     0x0082,
     0x0083,
     0x0084,
     0x000a,
     0x0017,
     0x001b,
     0x0088,
     0x0089,
     0x008a,
     0x008b,
     0x008c,
     0x0005,
     0x0006,
     0x0007,
     0x0090,
     0x0091,
     0x0016,
     0x0093,
     0x0094,
     0x0095,
     0x0096,
     0x0004,
     0x0098,
     0x0099,
     0x009a,
     0x009b,
     0x0014,
     0x0015,
     0x009e,
     0x001a,
     0x0020,
     0xfffd,
     0x0452,
     0x0453,
     0x0451,
     0xfffd,
     0x0455,
     0x0456,
     0x0457,
     0x0458,
     0x005b,
     0x002e,
     0x003c,
     0x0028,
     0x002b,
     0x0021,
     0x0026,
     0x0459,
     0x045a,
     0x045b,
     0x045c,
     0xfffd,
     0x045f,
     0x042a,
     0x2116,
     0x0402,
     0x005d,
     0x0024,
     0x002a,
     0x0029,
     0x003b,
     0x005e,
     0x002d,
     0x002f,
     0x0403,
     0x0401,
     0xfffd,
     0x0405,
     0x0406,
     0x0407,
     0x0408,
     0x0409,
     0x00a6,
     0x002c,
     0x0025,
     0x005f,
     0x003e,
     0x003f,
     0x040a,
     0x040b,
     0x040c,
     0xfffd,
     0xfffd,
     0x040f,
     0x044e,
     0x0430,
     0x0431,
     0xfffd,
     0x003a,
     0x0023,
     0x0040,
     0x0027,
     0x003d,
     0x0022,
     0x0446,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x0434,
     0x0435,
     0x0444,
     0x0433,
     0x0445,
     0x0438,
     0x0439,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x043a,
     0x043b,
     0x043c,
     0x043d,
     0x043e,
     0x043f,
     0x044f,
     0xfffd,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x0440,
     0x0441,
     0x0442,
     0x0443,
     0x0436,
     0x0432,
     0x044c,
     0x044b,
     0x0437,
     0x0448,
     0x044d,
     0x0449,
     0x0447,
     0x044a,
     0x042e,
     0x0410,
     0x0411,
     0x0426,
     0x0414,
     0x0415,
     0x0424,
     0x0413,
     0xfffd,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x0425,
     0x0418,
     0x0419,
     0x041a,
     0x041b,
     0x041c,
     0xfffd,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x041d,
     0x041e,
     0x041f,
     0x042f,
     0x0420,
     0x0421,
     0x005c,
     0x00a4,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x0422,
     0x0423,
     0x0416,
     0x0412,
     0x042c,
     0x042b,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x0417,
     0x0428,
     0x042d,
     0x0429,
     0x0427,
     0x009f,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\xc2\x9c",
     "\x09",
     "\xc2\x86",
     "\x7f",
     "\xc2\x97",
     "\xc2\x8d",
     "\xc2\x8e",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\xc2\x9d",
     "\xc2\x85",
     "\x08",
     "\xc2\x87",
     "\x18",
     "\x19",
     "\xc2\x92",
     "\xc2\x8f",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\xc2\x80",
     "\xc2\x81",
     "\xc2\x82",
     "\xc2\x83",
     "\xc2\x84",
     "\x0a",
     "\x17",
     "\x1b",
     "\xc2\x88",
     "\xc2\x89",
     "\xc2\x8a",
     "\xc2\x8b",
     "\xc2\x8c",
     "\x05",
     "\x06",
     "\x07",
     "\xc2\x90",
     "\xc2\x91",
     "\x16",
     "\xc2\x93",
     "\xc2\x94",
     "\xc2\x95",
     "\xc2\x96",
     "\x04",
     "\xc2\x98",
     "\xc2\x99",
     "\xc2\x9a",
     "\xc2\x9b",
     "\x14",
     "\x15",
     "\xc2\x9e",
     "\x1a",
     "\x20",
     "\xef\xbf\xbd",
     "\xd1\x92",
     "\xd1\x93",
     "\xd1\x91",
     "\xef\xbf\xbd",
     "\xd1\x95",
     "\xd1\x96",
     "\xd1\x97",
     "\xd1\x98",
     "\x5b",
     "\x2e",
     "\x3c",
     "\x28",
     "\x2b",
     "\x21",
     "\x26",
     "\xd1\x99",
     "\xd1\x9a",
     "\xd1\x9b",
     "\xd1\x9c",
     "\xef\xbf\xbd",
     "\xd1\x9f",
     "\xd0\xaa",
     "\xe2\x84\x96",
     "\xd0\x82",
     "\x5d",
     "\x24",
     "\x2a",
     "\x29",
     "\x3b",
     "\x5e",
     "\x2d",
     "\x2f",
     "\xd0\x83",
     "\xd0\x81",
     "\xef\xbf\xbd",
     "\xd0\x85",
     "\xd0\x86",
     "\xd0\x87",
     "\xd0\x88",
     "\xd0\x89",
     "\xc2\xa6",
     "\x2c",
     "\x25",
     "\x5f",
     "\x3e",
     "\x3f",
     "\xd0\x8a",
     "\xd0\x8b",
     "\xd0\x8c",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xd0\x8f",
     "\xd1\x8e",
     "\xd0\xb0",
     "\xd0\xb1",
     "\xef\xbf\xbd",
     "\x3a",
     "\x23",
     "\x40",
     "\x27",
     "\x3d",
     "\x22",
     "\xd1\x86",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\xd0\xb4",
     "\xd0\xb5",
     "\xd1\x84",
     "\xd0\xb3",
     "\xd1\x85",
     "\xd0\xb8",
     "\xd0\xb9",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\xd0\xba",
     "\xd0\xbb",
     "\xd0\xbc",
     "\xd0\xbd",
     "\xd0\xbe",
     "\xd0\xbf",
     "\xd1\x8f",
     "\xef\xbf\xbd",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\xd1\x80",
     "\xd1\x81",
     "\xd1\x82",
     "\xd1\x83",
     "\xd0\xb6",
     "\xd0\xb2",
     "\xd1\x8c",
     "\xd1\x8b",
     "\xd0\xb7",
     "\xd1\x88",
     "\xd1\x8d",
     "\xd1\x89",
     "\xd1\x87",
     "\xd1\x8a",
     "\xd0\xae",
     "\xd0\x90",
     "\xd0\x91",
     "\xd0\xa6",
     "\xd0\x94",
     "\xd0\x95",
     "\xd0\xa4",
     "\xd0\x93",
     "\xef\xbf\xbd",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\xd0\xa5",
     "\xd0\x98",
     "\xd0\x99",
     "\xd0\x9a",
     "\xd0\x9b",
     "\xd0\x9c",
     "\xef\xbf\xbd",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\xd0\x9d",
     "\xd0\x9e",
     "\xd0\x9f",
     "\xd0\xaf",
     "\xd0\xa0",
     "\xd0\xa1",
     "\x5c",
     "\xc2\xa4",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\xd0\xa2",
     "\xd0\xa3",
     "\xd0\x96",
     "\xd0\x92",
     "\xd0\xac",
     "\xd0\xab",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\xd0\x97",
     "\xd0\xa8",
     "\xd0\xad",
     "\xd0\xa9",
     "\xd0\xa7",
     "\xc2\x9f",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x37",
     0x00000005 => "\x2d",
     0x00000006 => "\x2e",
     0x00000007 => "\x2f",
     0x00000008 => "\x16",
     0x00000009 => "\x05",
     0x0000000a => "\x25",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x3c",
     0x00000015 => "\x3d",
     0x00000016 => "\x32",
     0x00000017 => "\x26",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x3f",
     0x0000001b => "\x27",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x40",
     0x00000021 => "\x4f",
     0x00000022 => "\x7f",
     0x00000023 => "\x7b",
     0x00000024 => "\x5b",
     0x00000025 => "\x6c",
     0x00000026 => "\x50",
     0x00000027 => "\x7d",
     0x00000028 => "\x4d",
     0x00000029 => "\x5d",
     0x0000002a => "\x5c",
     0x0000002b => "\x4e",
     0x0000002c => "\x6b",
     0x0000002d => "\x60",
     0x0000002e => "\x4b",
     0x0000002f => "\x61",
     0x00000030 => "\xf0",
     0x00000031 => "\xf1",
     0x00000032 => "\xf2",
     0x00000033 => "\xf3",
     0x00000034 => "\xf4",
     0x00000035 => "\xf5",
     0x00000036 => "\xf6",
     0x00000037 => "\xf7",
     0x00000038 => "\xf8",
     0x00000039 => "\xf9",
     0x0000003a => "\x7a",
     0x0000003b => "\x5e",
     0x0000003c => "\x4c",
     0x0000003d => "\x7e",
     0x0000003e => "\x6e",
     0x0000003f => "\x6f",
     0x00000040 => "\x7c",
     0x00000041 => "\xc1",
     0x00000042 => "\xc2",
     0x00000043 => "\xc3",
     0x00000044 => "\xc4",
     0x00000045 => "\xc5",
     0x00000046 => "\xc6",
     0x00000047 => "\xc7",
     0x00000048 => "\xc8",
     0x00000049 => "\xc9",
     0x0000004a => "\xd1",
     0x0000004b => "\xd2",
     0x0000004c => "\xd3",
     0x0000004d => "\xd4",
     0x0000004e => "\xd5",
     0x0000004f => "\xd6",
     0x00000050 => "\xd7",
     0x00000051 => "\xd8",
     0x00000052 => "\xd9",
     0x00000053 => "\xe2",
     0x00000054 => "\xe3",
     0x00000055 => "\xe4",
     0x00000056 => "\xe5",
     0x00000057 => "\xe6",
     0x00000058 => "\xe7",
     0x00000059 => "\xe8",
     0x0000005a => "\xe9",
     0x0000005b => "\x4a",
     0x0000005c => "\xe0",
     0x0000005d => "\x5a",
     0x0000005e => "\x5f",
     0x0000005f => "\x6d",
     0x00000061 => "\x81",
     0x00000062 => "\x82",
     0x00000063 => "\x83",
     0x00000064 => "\x84",
     0x00000065 => "\x85",
     0x00000066 => "\x86",
     0x00000067 => "\x87",
     0x00000068 => "\x88",
     0x00000069 => "\x89",
     0x0000006a => "\x91",
     0x0000006b => "\x92",
     0x0000006c => "\x93",
     0x0000006d => "\x94",
     0x0000006e => "\x95",
     0x0000006f => "\x96",
     0x00000070 => "\x97",
     0x00000071 => "\x98",
     0x00000072 => "\x99",
     0x00000073 => "\xa2",
     0x00000074 => "\xa3",
     0x00000075 => "\xa4",
     0x00000076 => "\xa5",
     0x00000077 => "\xa6",
     0x00000078 => "\xa7",
     0x00000079 => "\xa8",
     0x0000007a => "\xa9",
     0x0000007f => "\x07",
     0x00000080 => "\x20",
     0x00000081 => "\x21",
     0x00000082 => "\x22",
     0x00000083 => "\x23",
     0x00000084 => "\x24",
     0x00000085 => "\x15",
     0x00000086 => "\x06",
     0x00000087 => "\x17",
     0x00000088 => "\x28",
     0x00000089 => "\x29",
     0x0000008a => "\x2a",
     0x0000008b => "\x2b",
     0x0000008c => "\x2c",
     0x0000008d => "\x09",
     0x0000008e => "\x0a",
     0x0000008f => "\x1b",
     0x00000090 => "\x30",
     0x00000091 => "\x31",
     0x00000092 => "\x1a",
     0x00000093 => "\x33",
     0x00000094 => "\x34",
     0x00000095 => "\x35",
     0x00000096 => "\x36",
     0x00000097 => "\x08",
     0x00000098 => "\x38",
     0x00000099 => "\x39",
     0x0000009a => "\x3a",
     0x0000009b => "\x3b",
     0x0000009c => "\x04",
     0x0000009d => "\x14",
     0x0000009e => "\x3e",
     0x0000009f => "\xff",
     0x000000a4 => "\xe1",
     0x000000a6 => "\x6a",
     0x00000401 => "\x63",
     0x00000402 => "\x59",
     0x00000403 => "\x62",
     0x00000405 => "\x65",
     0x00000406 => "\x66",
     0x00000407 => "\x67",
     0x00000408 => "\x68",
     0x00000409 => "\x69",
     0x0000040a => "\x70",
     0x0000040b => "\x71",
     0x0000040c => "\x72",
     0x0000040f => "\x75",
     0x00000410 => "\xb9",
     0x00000411 => "\xba",
     0x00000412 => "\xed",
     0x00000413 => "\xbf",
     0x00000414 => "\xbc",
     0x00000415 => "\xbd",
     0x00000416 => "\xec",
     0x00000417 => "\xfa",
     0x00000418 => "\xcb",
     0x00000419 => "\xcc",
     0x0000041a => "\xcd",
     0x0000041b => "\xce",
     0x0000041c => "\xcf",
     0x0000041d => "\xda",
     0x0000041e => "\xdb",
     0x0000041f => "\xdc",
     0x00000420 => "\xde",
     0x00000421 => "\xdf",
     0x00000422 => "\xea",
     0x00000423 => "\xeb",
     0x00000424 => "\xbe",
     0x00000425 => "\xca",
     0x00000426 => "\xbb",
     0x00000427 => "\xfe",
     0x00000428 => "\xfb",
     0x00000429 => "\xfd",
     0x0000042a => "\x57",
     0x0000042b => "\xef",
     0x0000042c => "\xee",
     0x0000042d => "\xfc",
     0x0000042e => "\xb8",
     0x0000042f => "\xdd",
     0x00000430 => "\x77",
     0x00000431 => "\x78",
     0x00000432 => "\xaf",
     0x00000433 => "\x8d",
     0x00000434 => "\x8a",
     0x00000435 => "\x8b",
     0x00000436 => "\xae",
     0x00000437 => "\xb2",
     0x00000438 => "\x8f",
     0x00000439 => "\x90",
     0x0000043a => "\x9a",
     0x0000043b => "\x9b",
     0x0000043c => "\x9c",
     0x0000043d => "\x9d",
     0x0000043e => "\x9e",
     0x0000043f => "\x9f",
     0x00000440 => "\xaa",
     0x00000441 => "\xab",
     0x00000442 => "\xac",
     0x00000443 => "\xad",
     0x00000444 => "\x8c",
     0x00000445 => "\x8e",
     0x00000446 => "\x80",
     0x00000447 => "\xb6",
     0x00000448 => "\xb3",
     0x00000449 => "\xb5",
     0x0000044a => "\xb7",
     0x0000044b => "\xb1",
     0x0000044c => "\xb0",
     0x0000044d => "\xb4",
     0x0000044e => "\x76",
     0x0000044f => "\xa0",
     0x00000451 => "\x44",
     0x00000452 => "\x42",
     0x00000453 => "\x43",
     0x00000455 => "\x46",
     0x00000456 => "\x47",
     0x00000457 => "\x48",
     0x00000458 => "\x49",
     0x00000459 => "\x51",
     0x0000045a => "\x52",
     0x0000045b => "\x53",
     0x0000045c => "\x54",
     0x0000045f => "\x56",
     0x00002116 => "\x58",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x6f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::IBM880 - Conversion routines for IBM880
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for IBM880.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
   source: IBM NLS RM Vol2 SE09-8002-01, March 1990
  alias CP880
  alias EBCDIC-CYRILLIC
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  0000009C | STRING TERMINATOR (ST)
     05 |  00000009 | CHARACTER TABULATION (HT)
     06 |  00000086 | START OF SELECTED AREA (SSA)
     07 |  0000007F | DELETE (DEL)
     08 |  00000097 | END OF GUARDED AREA (EPA)
     09 |  0000008D | REVERSE LINE FEED (RI)
     0A |  0000008E | SINGLE-SHIFT TWO (SS2)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  0000009D | OPERATING SYSTEM COMMAND (OSC)
     15 |  00000085 | NEXT LINE (NEL)
     16 |  00000008 | BACKSPACE (BS)
     17 |  00000087 | END OF SELECTED AREA (ESA)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  00000092 | PRIVATE USE TWO (PU2)
     1B |  0000008F | SINGLE-SHIFT THREE (SS3)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000080 | PADDING CHARACTER (PAD)
     21 |  00000081 | HIGH OCTET PRESET (HOP)
     22 |  00000082 | BREAK PERMITTED HERE (BPH)
     23 |  00000083 | NO BREAK HERE (NBH)
     24 |  00000084 | INDEX (IND)
     25 |  0000000A | LINE FEED (LF)
     26 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     27 |  0000001B | ESCAPE (ESC)
     28 |  00000088 | CHARACTER TABULATION SET (HTS)
     29 |  00000089 | CHARACTER TABULATION WITH JUSTIFICATION (HTJ)
     2A |  0000008A | LINE TABULATION SET (VTS)
     2B |  0000008B | PARTIAL LINE FORWARD (PLD)
     2C |  0000008C | PARTIAL LINE BACKWARD (PLU)
     2D |  00000005 | ENQUIRY (ENQ)
     2E |  00000006 | ACKNOWLEDGE (ACK)
     2F |  00000007 | BELL (BEL)
     30 |  00000090 | DEVICE CONTROL STRING (DCS)
     31 |  00000091 | PRIVATE USE ONE (PU1)
     32 |  00000016 | SYNCHRONOUS IDLE (SYN)
     33 |  00000093 | SET TRANSMIT STATE (STS)
     34 |  00000094 | CANCEL CHARACTER (CCH)
     35 |  00000095 | MESSAGE WAITING (MW)
     36 |  00000096 | START OF GUARDED AREA (SPA)
     37 |  00000004 | END OF TRANSMISSION (EOT)
     38 |  00000098 | START OF STRING (SOS)
     39 |  00000099 | SINGLE GRAPHIC CHARACTER INTRODUCER (SGCI)
     3A |  0000009A | SINGLE CHARACTER INTRODUCER (SCI)
     3B |  0000009B | CONTROL SEQUENCE INTRODUCER (CSI)
     3C |  00000014 | DEVICE CONTROL FOUR (DC4)
     3D |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     3E |  0000009E | PRIVACY MESSAGE (PM)
     3F |  0000001A | SUBSTITUTE (SUB)
     40 |  00000020 | SPACE
     42 |  00000452 | CYRILLIC SMALL LETTER DJE (Serbocroatian)
     43 |  00000453 | CYRILLIC SMALL LETTER GJE
     44 |  00000451 | CYRILLIC SMALL LETTER IO
     46 |  00000455 | CYRILLIC SMALL LETTER DZE
     47 |  00000456 | CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I
     48 |  00000457 | CYRILLIC SMALL LETTER YI (Ukrainian)
     49 |  00000458 | CYRILLIC SMALL LETTER JE
     4A |  0000005B | LEFT SQUARE BRACKET
     4B |  0000002E | FULL STOP
     4C |  0000003C | LESS-THAN SIGN
     4D |  00000028 | LEFT PARENTHESIS
     4E |  0000002B | PLUS SIGN
     4F |  00000021 | EXCLAMATION MARK
     50 |  00000026 | AMPERSAND
     51 |  00000459 | CYRILLIC SMALL LETTER LJE
     52 |  0000045A | CYRILLIC SMALL LETTER NJE
     53 |  0000045B | CYRILLIC SMALL LETTER TSHE (Serbocroatian)
     54 |  0000045C | CYRILLIC SMALL LETTER KJE
     56 |  0000045F | CYRILLIC SMALL LETTER DZHE
     57 |  0000042A | CYRILLIC CAPITAL LETTER HARD SIGN
     58 |  00002116 | NUMERO SIGN
     59 |  00000402 | CYRILLIC CAPITAL LETTER DJE (Serbocroatian)
     5A |  0000005D | RIGHT SQUARE BRACKET
     5B |  00000024 | DOLLAR SIGN
     5C |  0000002A | ASTERISK
     5D |  00000029 | RIGHT PARENTHESIS
     5E |  0000003B | SEMICOLON
     5F |  0000005E | CIRCUMFLEX ACCENT
     60 |  0000002D | HYPHEN-MINUS
     61 |  0000002F | SOLIDUS
     62 |  00000403 | CYRILLIC CAPITAL LETTER GJE
     63 |  00000401 | CYRILLIC CAPITAL LETTER IO
     65 |  00000405 | CYRILLIC CAPITAL LETTER DZE
     66 |  00000406 | CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I
     67 |  00000407 | CYRILLIC CAPITAL LETTER YI (Ukrainian)
     68 |  00000408 | CYRILLIC CAPITAL LETTER JE
     69 |  00000409 | CYRILLIC CAPITAL LETTER LJE
     6A |  000000A6 | BROKEN BAR
     6B |  0000002C | COMMA
     6C |  00000025 | PERCENT SIGN
     6D |  0000005F | LOW LINE
     6E |  0000003E | GREATER-THAN SIGN
     6F |  0000003F | QUESTION MARK
     70 |  0000040A | CYRILLIC CAPITAL LETTER NJE
     71 |  0000040B | CYRILLIC CAPITAL LETTER TSHE (Serbocroatian)
     72 |  0000040C | CYRILLIC CAPITAL LETTER KJE
     75 |  0000040F | CYRILLIC CAPITAL LETTER DZHE
     76 |  0000044E | CYRILLIC SMALL LETTER YU
     77 |  00000430 | CYRILLIC SMALL LETTER A
     78 |  00000431 | CYRILLIC SMALL LETTER BE
     7A |  0000003A | COLON
     7B |  00000023 | NUMBER SIGN
     7C |  00000040 | COMMERCIAL AT
     7D |  00000027 | APOSTROPHE
     7E |  0000003D | EQUALS SIGN
     7F |  00000022 | QUOTATION MARK
     80 |  00000446 | CYRILLIC SMALL LETTER TSE
     81 |  00000061 | LATIN SMALL LETTER A
     82 |  00000062 | LATIN SMALL LETTER B
     83 |  00000063 | LATIN SMALL LETTER C
     84 |  00000064 | LATIN SMALL LETTER D
     85 |  00000065 | LATIN SMALL LETTER E
     86 |  00000066 | LATIN SMALL LETTER F
     87 |  00000067 | LATIN SMALL LETTER G
     88 |  00000068 | LATIN SMALL LETTER H
     89 |  00000069 | LATIN SMALL LETTER I
     8A |  00000434 | CYRILLIC SMALL LETTER DE
     8B |  00000435 | CYRILLIC SMALL LETTER IE
     8C |  00000444 | CYRILLIC SMALL LETTER EF
     8D |  00000433 | CYRILLIC SMALL LETTER GHE
     8E |  00000445 | CYRILLIC SMALL LETTER HA
     8F |  00000438 | CYRILLIC SMALL LETTER I
     90 |  00000439 | CYRILLIC SMALL LETTER SHORT I
     91 |  0000006A | LATIN SMALL LETTER J
     92 |  0000006B | LATIN SMALL LETTER K
     93 |  0000006C | LATIN SMALL LETTER L
     94 |  0000006D | LATIN SMALL LETTER M
     95 |  0000006E | LATIN SMALL LETTER N
     96 |  0000006F | LATIN SMALL LETTER O
     97 |  00000070 | LATIN SMALL LETTER P
     98 |  00000071 | LATIN SMALL LETTER Q
     99 |  00000072 | LATIN SMALL LETTER R
     9A |  0000043A | CYRILLIC SMALL LETTER KA
     9B |  0000043B | CYRILLIC SMALL LETTER EL
     9C |  0000043C | CYRILLIC SMALL LETTER EM
     9D |  0000043D | CYRILLIC SMALL LETTER EN
     9E |  0000043E | CYRILLIC SMALL LETTER O
     9F |  0000043F | CYRILLIC SMALL LETTER PE
     A0 |  0000044F | CYRILLIC SMALL LETTER YA
     A2 |  00000073 | LATIN SMALL LETTER S
     A3 |  00000074 | LATIN SMALL LETTER T
     A4 |  00000075 | LATIN SMALL LETTER U
     A5 |  00000076 | LATIN SMALL LETTER V
     A6 |  00000077 | LATIN SMALL LETTER W
     A7 |  00000078 | LATIN SMALL LETTER X
     A8 |  00000079 | LATIN SMALL LETTER Y
     A9 |  0000007A | LATIN SMALL LETTER Z
     AA |  00000440 | CYRILLIC SMALL LETTER ER
     AB |  00000441 | CYRILLIC SMALL LETTER ES
     AC |  00000442 | CYRILLIC SMALL LETTER TE
     AD |  00000443 | CYRILLIC SMALL LETTER U
     AE |  00000436 | CYRILLIC SMALL LETTER ZHE
     AF |  00000432 | CYRILLIC SMALL LETTER VE
     B0 |  0000044C | CYRILLIC SMALL LETTER SOFT SIGN
     B1 |  0000044B | CYRILLIC SMALL LETTER YERU
     B2 |  00000437 | CYRILLIC SMALL LETTER ZE
     B3 |  00000448 | CYRILLIC SMALL LETTER SHA
     B4 |  0000044D | CYRILLIC SMALL LETTER E
     B5 |  00000449 | CYRILLIC SMALL LETTER SHCHA
     B6 |  00000447 | CYRILLIC SMALL LETTER CHE
     B7 |  0000044A | CYRILLIC SMALL LETTER HARD SIGN
     B8 |  0000042E | CYRILLIC CAPITAL LETTER YU
     B9 |  00000410 | CYRILLIC CAPITAL LETTER A
     BA |  00000411 | CYRILLIC CAPITAL LETTER BE
     BB |  00000426 | CYRILLIC CAPITAL LETTER TSE
     BC |  00000414 | CYRILLIC CAPITAL LETTER DE
     BD |  00000415 | CYRILLIC CAPITAL LETTER IE
     BE |  00000424 | CYRILLIC CAPITAL LETTER EF
     BF |  00000413 | CYRILLIC CAPITAL LETTER GHE
     C1 |  00000041 | LATIN CAPITAL LETTER A
     C2 |  00000042 | LATIN CAPITAL LETTER B
     C3 |  00000043 | LATIN CAPITAL LETTER C
     C4 |  00000044 | LATIN CAPITAL LETTER D
     C5 |  00000045 | LATIN CAPITAL LETTER E
     C6 |  00000046 | LATIN CAPITAL LETTER F
     C7 |  00000047 | LATIN CAPITAL LETTER G
     C8 |  00000048 | LATIN CAPITAL LETTER H
     C9 |  00000049 | LATIN CAPITAL LETTER I
     CA |  00000425 | CYRILLIC CAPITAL LETTER HA
     CB |  00000418 | CYRILLIC CAPITAL LETTER I
     CC |  00000419 | CYRILLIC CAPITAL LETTER SHORT I
     CD |  0000041A | CYRILLIC CAPITAL LETTER KA
     CE |  0000041B | CYRILLIC CAPITAL LETTER EL
     CF |  0000041C | CYRILLIC CAPITAL LETTER EM
     D1 |  0000004A | LATIN CAPITAL LETTER J
     D2 |  0000004B | LATIN CAPITAL LETTER K
     D3 |  0000004C | LATIN CAPITAL LETTER L
     D4 |  0000004D | LATIN CAPITAL LETTER M
     D5 |  0000004E | LATIN CAPITAL LETTER N
     D6 |  0000004F | LATIN CAPITAL LETTER O
     D7 |  00000050 | LATIN CAPITAL LETTER P
     D8 |  00000051 | LATIN CAPITAL LETTER Q
     D9 |  00000052 | LATIN CAPITAL LETTER R
     DA |  0000041D | CYRILLIC CAPITAL LETTER EN
     DB |  0000041E | CYRILLIC CAPITAL LETTER O
     DC |  0000041F | CYRILLIC CAPITAL LETTER PE
     DD |  0000042F | CYRILLIC CAPITAL LETTER YA
     DE |  00000420 | CYRILLIC CAPITAL LETTER ER
     DF |  00000421 | CYRILLIC CAPITAL LETTER ES
     E0 |  0000005C | REVERSE SOLIDUS
     E1 |  000000A4 | CURRENCY SIGN
     E2 |  00000053 | LATIN CAPITAL LETTER S
     E3 |  00000054 | LATIN CAPITAL LETTER T
     E4 |  00000055 | LATIN CAPITAL LETTER U
     E5 |  00000056 | LATIN CAPITAL LETTER V
     E6 |  00000057 | LATIN CAPITAL LETTER W
     E7 |  00000058 | LATIN CAPITAL LETTER X
     E8 |  00000059 | LATIN CAPITAL LETTER Y
     E9 |  0000005A | LATIN CAPITAL LETTER Z
     EA |  00000422 | CYRILLIC CAPITAL LETTER TE
     EB |  00000423 | CYRILLIC CAPITAL LETTER U
     EC |  00000416 | CYRILLIC CAPITAL LETTER ZHE
     ED |  00000412 | CYRILLIC CAPITAL LETTER VE
     EE |  0000042C | CYRILLIC CAPITAL LETTER SOFT SIGN
     EF |  0000042B | CYRILLIC CAPITAL LETTER YERU
     F0 |  00000030 | DIGIT ZERO
     F1 |  00000031 | DIGIT ONE
     F2 |  00000032 | DIGIT TWO
     F3 |  00000033 | DIGIT THREE
     F4 |  00000034 | DIGIT FOUR
     F5 |  00000035 | DIGIT FIVE
     F6 |  00000036 | DIGIT SIX
     F7 |  00000037 | DIGIT SEVEN
     F8 |  00000038 | DIGIT EIGHT
     F9 |  00000039 | DIGIT NINE
     FA |  00000417 | CYRILLIC CAPITAL LETTER ZE
     FB |  00000428 | CYRILLIC CAPITAL LETTER SHA
     FC |  0000042D | CYRILLIC CAPITAL LETTER E
     FD |  00000429 | CYRILLIC CAPITAL LETTER SHCHA
     FE |  00000427 | CYRILLIC CAPITAL LETTER CHE
     FF |  0000009F | APPLICATION PROGRAM COMMAND (APC)
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/IBM891.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for IBM891.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::IBM891;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x0004,
     0x0005,
     0x0006,
     0x0007,
     0x0008,
     0x0009,
     0x000a,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x0014,
     0x0015,
     0x0016,
     0x0017,
     0x0018,
     0x0019,
     0x001a,
     0x001b,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0020,
     0x0021,
     0x0022,
     0x0023,
     0x0024,
     0x0025,
     0x0026,
     0x0027,
     0x0028,
     0x0029,
     0x002a,
     0x002b,
     0x002c,
     0x002d,
     0x002e,
     0x002f,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x003a,
     0x003b,
     0x003c,
     0x003d,
     0x003e,
     0x003f,
     0x0040,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x005b,
     0x005c,
     0x005d,
     0x005e,
     0x005f,
     0x0060,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x007b,
     0x007c,
     0x007d,
     0x007e,
     0x007f,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\x04",
     "\x05",
     "\x06",
     "\x07",
     "\x08",
     "\x09",
     "\x0a",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\x14",
     "\x15",
     "\x16",
     "\x17",
     "\x18",
     "\x19",
     "\x1a",
     "\x1b",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\x20",
     "\x21",
     "\x22",
     "\x23",
     "\x24",
     "\x25",
     "\x26",
     "\x27",
     "\x28",
     "\x29",
     "\x2a",
     "\x2b",
     "\x2c",
     "\x2d",
     "\x2e",
     "\x2f",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\x3a",
     "\x3b",
     "\x3c",
     "\x3d",
     "\x3e",
     "\x3f",
     "\x40",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\x5b",
     "\x5c",
     "\x5d",
     "\x5e",
     "\x5f",
     "\x60",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\x7b",
     "\x7c",
     "\x7d",
     "\x7e",
     "\x7f",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x04",
     0x00000005 => "\x05",
     0x00000006 => "\x06",
     0x00000007 => "\x07",
     0x00000008 => "\x08",
     0x00000009 => "\x09",
     0x0000000a => "\x0a",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x14",
     0x00000015 => "\x15",
     0x00000016 => "\x16",
     0x00000017 => "\x17",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x1a",
     0x0000001b => "\x1b",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x20",
     0x00000021 => "\x21",
     0x00000022 => "\x22",
     0x00000023 => "\x23",
     0x00000024 => "\x24",
     0x00000025 => "\x25",
     0x00000026 => "\x26",
     0x00000027 => "\x27",
     0x00000028 => "\x28",
     0x00000029 => "\x29",
     0x0000002a => "\x2a",
     0x0000002b => "\x2b",
     0x0000002c => "\x2c",
     0x0000002d => "\x2d",
     0x0000002e => "\x2e",
     0x0000002f => "\x2f",
     0x00000030 => "\x30",
     0x00000031 => "\x31",
     0x00000032 => "\x32",
     0x00000033 => "\x33",
     0x00000034 => "\x34",
     0x00000035 => "\x35",
     0x00000036 => "\x36",
     0x00000037 => "\x37",
     0x00000038 => "\x38",
     0x00000039 => "\x39",
     0x0000003a => "\x3a",
     0x0000003b => "\x3b",
     0x0000003c => "\x3c",
     0x0000003d => "\x3d",
     0x0000003e => "\x3e",
     0x0000003f => "\x3f",
     0x00000040 => "\x40",
     0x00000041 => "\x41",
     0x00000042 => "\x42",
     0x00000043 => "\x43",
     0x00000044 => "\x44",
     0x00000045 => "\x45",
     0x00000046 => "\x46",
     0x00000047 => "\x47",
     0x00000048 => "\x48",
     0x00000049 => "\x49",
     0x0000004a => "\x4a",
     0x0000004b => "\x4b",
     0x0000004c => "\x4c",
     0x0000004d => "\x4d",
     0x0000004e => "\x4e",
     0x0000004f => "\x4f",
     0x00000050 => "\x50",
     0x00000051 => "\x51",
     0x00000052 => "\x52",
     0x00000053 => "\x53",
     0x00000054 => "\x54",
     0x00000055 => "\x55",
     0x00000056 => "\x56",
     0x00000057 => "\x57",
     0x00000058 => "\x58",
     0x00000059 => "\x59",
     0x0000005a => "\x5a",
     0x0000005b => "\x5b",
     0x0000005c => "\x5c",
     0x0000005d => "\x5d",
     0x0000005e => "\x5e",
     0x0000005f => "\x5f",
     0x00000060 => "\x60",
     0x00000061 => "\x61",
     0x00000062 => "\x62",
     0x00000063 => "\x63",
     0x00000064 => "\x64",
     0x00000065 => "\x65",
     0x00000066 => "\x66",
     0x00000067 => "\x67",
     0x00000068 => "\x68",
     0x00000069 => "\x69",
     0x0000006a => "\x6a",
     0x0000006b => "\x6b",
     0x0000006c => "\x6c",
     0x0000006d => "\x6d",
     0x0000006e => "\x6e",
     0x0000006f => "\x6f",
     0x00000070 => "\x70",
     0x00000071 => "\x71",
     0x00000072 => "\x72",
     0x00000073 => "\x73",
     0x00000074 => "\x74",
     0x00000075 => "\x75",
     0x00000076 => "\x76",
     0x00000077 => "\x77",
     0x00000078 => "\x78",
     0x00000079 => "\x79",
     0x0000007a => "\x7a",
     0x0000007b => "\x7b",
     0x0000007c => "\x7c",
     0x0000007d => "\x7d",
     0x0000007e => "\x7e",
     0x0000007f => "\x7f",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::IBM891 - Conversion routines for IBM891
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for IBM891.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
   source: IBM NLS RM Vol2 SE09-8002-01, March 1990
  alias CP891
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  00000004 | END OF TRANSMISSION (EOT)
     05 |  00000005 | ENQUIRY (ENQ)
     06 |  00000006 | ACKNOWLEDGE (ACK)
     07 |  00000007 | BELL (BEL)
     08 |  00000008 | BACKSPACE (BS)
     09 |  00000009 | CHARACTER TABULATION (HT)
     0A |  0000000A | LINE FEED (LF)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  00000014 | DEVICE CONTROL FOUR (DC4)
     15 |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     16 |  00000016 | SYNCHRONOUS IDLE (SYN)
     17 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  0000001A | SUBSTITUTE (SUB)
     1B |  0000001B | ESCAPE (ESC)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000020 | SPACE
     21 |  00000021 | EXCLAMATION MARK
     22 |  00000022 | QUOTATION MARK
     23 |  00000023 | NUMBER SIGN
     24 |  00000024 | DOLLAR SIGN
     25 |  00000025 | PERCENT SIGN
     26 |  00000026 | AMPERSAND
     27 |  00000027 | APOSTROPHE
     28 |  00000028 | LEFT PARENTHESIS
     29 |  00000029 | RIGHT PARENTHESIS
     2A |  0000002A | ASTERISK
     2B |  0000002B | PLUS SIGN
     2C |  0000002C | COMMA
     2D |  0000002D | HYPHEN-MINUS
     2E |  0000002E | FULL STOP
     2F |  0000002F | SOLIDUS
     30 |  00000030 | DIGIT ZERO
     31 |  00000031 | DIGIT ONE
     32 |  00000032 | DIGIT TWO
     33 |  00000033 | DIGIT THREE
     34 |  00000034 | DIGIT FOUR
     35 |  00000035 | DIGIT FIVE
     36 |  00000036 | DIGIT SIX
     37 |  00000037 | DIGIT SEVEN
     38 |  00000038 | DIGIT EIGHT
     39 |  00000039 | DIGIT NINE
     3A |  0000003A | COLON
     3B |  0000003B | SEMICOLON
     3C |  0000003C | LESS-THAN SIGN
     3D |  0000003D | EQUALS SIGN
     3E |  0000003E | GREATER-THAN SIGN
     3F |  0000003F | QUESTION MARK
     40 |  00000040 | COMMERCIAL AT
     41 |  00000041 | LATIN CAPITAL LETTER A
     42 |  00000042 | LATIN CAPITAL LETTER B
     43 |  00000043 | LATIN CAPITAL LETTER C
     44 |  00000044 | LATIN CAPITAL LETTER D
     45 |  00000045 | LATIN CAPITAL LETTER E
     46 |  00000046 | LATIN CAPITAL LETTER F
     47 |  00000047 | LATIN CAPITAL LETTER G
     48 |  00000048 | LATIN CAPITAL LETTER H
     49 |  00000049 | LATIN CAPITAL LETTER I
     4A |  0000004A | LATIN CAPITAL LETTER J
     4B |  0000004B | LATIN CAPITAL LETTER K
     4C |  0000004C | LATIN CAPITAL LETTER L
     4D |  0000004D | LATIN CAPITAL LETTER M
     4E |  0000004E | LATIN CAPITAL LETTER N
     4F |  0000004F | LATIN CAPITAL LETTER O
     50 |  00000050 | LATIN CAPITAL LETTER P
     51 |  00000051 | LATIN CAPITAL LETTER Q
     52 |  00000052 | LATIN CAPITAL LETTER R
     53 |  00000053 | LATIN CAPITAL LETTER S
     54 |  00000054 | LATIN CAPITAL LETTER T
     55 |  00000055 | LATIN CAPITAL LETTER U
     56 |  00000056 | LATIN CAPITAL LETTER V
     57 |  00000057 | LATIN CAPITAL LETTER W
     58 |  00000058 | LATIN CAPITAL LETTER X
     59 |  00000059 | LATIN CAPITAL LETTER Y
     5A |  0000005A | LATIN CAPITAL LETTER Z
     5B |  0000005B | LEFT SQUARE BRACKET
     5C |  0000005C | REVERSE SOLIDUS
     5D |  0000005D | RIGHT SQUARE BRACKET
     5E |  0000005E | CIRCUMFLEX ACCENT
     5F |  0000005F | LOW LINE
     60 |  00000060 | GRAVE ACCENT
     61 |  00000061 | LATIN SMALL LETTER A
     62 |  00000062 | LATIN SMALL LETTER B
     63 |  00000063 | LATIN SMALL LETTER C
     64 |  00000064 | LATIN SMALL LETTER D
     65 |  00000065 | LATIN SMALL LETTER E
     66 |  00000066 | LATIN SMALL LETTER F
     67 |  00000067 | LATIN SMALL LETTER G
     68 |  00000068 | LATIN SMALL LETTER H
     69 |  00000069 | LATIN SMALL LETTER I
     6A |  0000006A | LATIN SMALL LETTER J
     6B |  0000006B | LATIN SMALL LETTER K
     6C |  0000006C | LATIN SMALL LETTER L
     6D |  0000006D | LATIN SMALL LETTER M
     6E |  0000006E | LATIN SMALL LETTER N
     6F |  0000006F | LATIN SMALL LETTER O
     70 |  00000070 | LATIN SMALL LETTER P
     71 |  00000071 | LATIN SMALL LETTER Q
     72 |  00000072 | LATIN SMALL LETTER R
     73 |  00000073 | LATIN SMALL LETTER S
     74 |  00000074 | LATIN SMALL LETTER T
     75 |  00000075 | LATIN SMALL LETTER U
     76 |  00000076 | LATIN SMALL LETTER V
     77 |  00000077 | LATIN SMALL LETTER W
     78 |  00000078 | LATIN SMALL LETTER X
     79 |  00000079 | LATIN SMALL LETTER Y
     7A |  0000007A | LATIN SMALL LETTER Z
     7B |  0000007B | LEFT CURLY BRACKET
     7C |  0000007C | VERTICAL LINE
     7D |  0000007D | RIGHT CURLY BRACKET
     7E |  0000007E | TILDE
     7F |  0000007F | DELETE (DEL)
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/IBM903.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for IBM903.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::IBM903;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x0004,
     0x0005,
     0x0006,
     0x0007,
     0x0008,
     0x0009,
     0x000a,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x0014,
     0x0015,
     0x0016,
     0x0017,
     0x0018,
     0x0019,
     0x001a,
     0x001b,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0020,
     0x0021,
     0x0022,
     0x0023,
     0x0024,
     0x0025,
     0x0026,
     0x0027,
     0x0028,
     0x0029,
     0x002a,
     0x002b,
     0x002c,
     0x002d,
     0x002e,
     0x002f,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x003a,
     0x003b,
     0x003c,
     0x003d,
     0x003e,
     0x003f,
     0x0040,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x005b,
     0x005c,
     0x005d,
     0x005e,
     0x005f,
     0x0060,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x007b,
     0x007c,
     0x007d,
     0x007e,
     0x007f,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\x04",
     "\x05",
     "\x06",
     "\x07",
     "\x08",
     "\x09",
     "\x0a",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\x14",
     "\x15",
     "\x16",
     "\x17",
     "\x18",
     "\x19",
     "\x1a",
     "\x1b",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\x20",
     "\x21",
     "\x22",
     "\x23",
     "\x24",
     "\x25",
     "\x26",
     "\x27",
     "\x28",
     "\x29",
     "\x2a",
     "\x2b",
     "\x2c",
     "\x2d",
     "\x2e",
     "\x2f",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\x3a",
     "\x3b",
     "\x3c",
     "\x3d",
     "\x3e",
     "\x3f",
     "\x40",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\x5b",
     "\x5c",
     "\x5d",
     "\x5e",
     "\x5f",
     "\x60",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\x7b",
     "\x7c",
     "\x7d",
     "\x7e",
     "\x7f",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x04",
     0x00000005 => "\x05",
     0x00000006 => "\x06",
     0x00000007 => "\x07",
     0x00000008 => "\x08",
     0x00000009 => "\x09",
     0x0000000a => "\x0a",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x14",
     0x00000015 => "\x15",
     0x00000016 => "\x16",
     0x00000017 => "\x17",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x1a",
     0x0000001b => "\x1b",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x20",
     0x00000021 => "\x21",
     0x00000022 => "\x22",
     0x00000023 => "\x23",
     0x00000024 => "\x24",
     0x00000025 => "\x25",
     0x00000026 => "\x26",
     0x00000027 => "\x27",
     0x00000028 => "\x28",
     0x00000029 => "\x29",
     0x0000002a => "\x2a",
     0x0000002b => "\x2b",
     0x0000002c => "\x2c",
     0x0000002d => "\x2d",
     0x0000002e => "\x2e",
     0x0000002f => "\x2f",
     0x00000030 => "\x30",
     0x00000031 => "\x31",
     0x00000032 => "\x32",
     0x00000033 => "\x33",
     0x00000034 => "\x34",
     0x00000035 => "\x35",
     0x00000036 => "\x36",
     0x00000037 => "\x37",
     0x00000038 => "\x38",
     0x00000039 => "\x39",
     0x0000003a => "\x3a",
     0x0000003b => "\x3b",
     0x0000003c => "\x3c",
     0x0000003d => "\x3d",
     0x0000003e => "\x3e",
     0x0000003f => "\x3f",
     0x00000040 => "\x40",
     0x00000041 => "\x41",
     0x00000042 => "\x42",
     0x00000043 => "\x43",
     0x00000044 => "\x44",
     0x00000045 => "\x45",
     0x00000046 => "\x46",
     0x00000047 => "\x47",
     0x00000048 => "\x48",
     0x00000049 => "\x49",
     0x0000004a => "\x4a",
     0x0000004b => "\x4b",
     0x0000004c => "\x4c",
     0x0000004d => "\x4d",
     0x0000004e => "\x4e",
     0x0000004f => "\x4f",
     0x00000050 => "\x50",
     0x00000051 => "\x51",
     0x00000052 => "\x52",
     0x00000053 => "\x53",
     0x00000054 => "\x54",
     0x00000055 => "\x55",
     0x00000056 => "\x56",
     0x00000057 => "\x57",
     0x00000058 => "\x58",
     0x00000059 => "\x59",
     0x0000005a => "\x5a",
     0x0000005b => "\x5b",
     0x0000005c => "\x5c",
     0x0000005d => "\x5d",
     0x0000005e => "\x5e",
     0x0000005f => "\x5f",
     0x00000060 => "\x60",
     0x00000061 => "\x61",
     0x00000062 => "\x62",
     0x00000063 => "\x63",
     0x00000064 => "\x64",
     0x00000065 => "\x65",
     0x00000066 => "\x66",
     0x00000067 => "\x67",
     0x00000068 => "\x68",
     0x00000069 => "\x69",
     0x0000006a => "\x6a",
     0x0000006b => "\x6b",
     0x0000006c => "\x6c",
     0x0000006d => "\x6d",
     0x0000006e => "\x6e",
     0x0000006f => "\x6f",
     0x00000070 => "\x70",
     0x00000071 => "\x71",
     0x00000072 => "\x72",
     0x00000073 => "\x73",
     0x00000074 => "\x74",
     0x00000075 => "\x75",
     0x00000076 => "\x76",
     0x00000077 => "\x77",
     0x00000078 => "\x78",
     0x00000079 => "\x79",
     0x0000007a => "\x7a",
     0x0000007b => "\x7b",
     0x0000007c => "\x7c",
     0x0000007d => "\x7d",
     0x0000007e => "\x7e",
     0x0000007f => "\x7f",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::IBM903 - Conversion routines for IBM903
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for IBM903.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
   source: IBM NLS RM Vol2 SE09-8002-01, March 1990
  alias CP903
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  00000004 | END OF TRANSMISSION (EOT)
     05 |  00000005 | ENQUIRY (ENQ)
     06 |  00000006 | ACKNOWLEDGE (ACK)
     07 |  00000007 | BELL (BEL)
     08 |  00000008 | BACKSPACE (BS)
     09 |  00000009 | CHARACTER TABULATION (HT)
     0A |  0000000A | LINE FEED (LF)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  00000014 | DEVICE CONTROL FOUR (DC4)
     15 |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     16 |  00000016 | SYNCHRONOUS IDLE (SYN)
     17 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  0000001A | SUBSTITUTE (SUB)
     1B |  0000001B | ESCAPE (ESC)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000020 | SPACE
     21 |  00000021 | EXCLAMATION MARK
     22 |  00000022 | QUOTATION MARK
     23 |  00000023 | NUMBER SIGN
     24 |  00000024 | DOLLAR SIGN
     25 |  00000025 | PERCENT SIGN
     26 |  00000026 | AMPERSAND
     27 |  00000027 | APOSTROPHE
     28 |  00000028 | LEFT PARENTHESIS
     29 |  00000029 | RIGHT PARENTHESIS
     2A |  0000002A | ASTERISK
     2B |  0000002B | PLUS SIGN
     2C |  0000002C | COMMA
     2D |  0000002D | HYPHEN-MINUS
     2E |  0000002E | FULL STOP
     2F |  0000002F | SOLIDUS
     30 |  00000030 | DIGIT ZERO
     31 |  00000031 | DIGIT ONE
     32 |  00000032 | DIGIT TWO
     33 |  00000033 | DIGIT THREE
     34 |  00000034 | DIGIT FOUR
     35 |  00000035 | DIGIT FIVE
     36 |  00000036 | DIGIT SIX
     37 |  00000037 | DIGIT SEVEN
     38 |  00000038 | DIGIT EIGHT
     39 |  00000039 | DIGIT NINE
     3A |  0000003A | COLON
     3B |  0000003B | SEMICOLON
     3C |  0000003C | LESS-THAN SIGN
     3D |  0000003D | EQUALS SIGN
     3E |  0000003E | GREATER-THAN SIGN
     3F |  0000003F | QUESTION MARK
     40 |  00000040 | COMMERCIAL AT
     41 |  00000041 | LATIN CAPITAL LETTER A
     42 |  00000042 | LATIN CAPITAL LETTER B
     43 |  00000043 | LATIN CAPITAL LETTER C
     44 |  00000044 | LATIN CAPITAL LETTER D
     45 |  00000045 | LATIN CAPITAL LETTER E
     46 |  00000046 | LATIN CAPITAL LETTER F
     47 |  00000047 | LATIN CAPITAL LETTER G
     48 |  00000048 | LATIN CAPITAL LETTER H
     49 |  00000049 | LATIN CAPITAL LETTER I
     4A |  0000004A | LATIN CAPITAL LETTER J
     4B |  0000004B | LATIN CAPITAL LETTER K
     4C |  0000004C | LATIN CAPITAL LETTER L
     4D |  0000004D | LATIN CAPITAL LETTER M
     4E |  0000004E | LATIN CAPITAL LETTER N
     4F |  0000004F | LATIN CAPITAL LETTER O
     50 |  00000050 | LATIN CAPITAL LETTER P
     51 |  00000051 | LATIN CAPITAL LETTER Q
     52 |  00000052 | LATIN CAPITAL LETTER R
     53 |  00000053 | LATIN CAPITAL LETTER S
     54 |  00000054 | LATIN CAPITAL LETTER T
     55 |  00000055 | LATIN CAPITAL LETTER U
     56 |  00000056 | LATIN CAPITAL LETTER V
     57 |  00000057 | LATIN CAPITAL LETTER W
     58 |  00000058 | LATIN CAPITAL LETTER X
     59 |  00000059 | LATIN CAPITAL LETTER Y
     5A |  0000005A | LATIN CAPITAL LETTER Z
     5B |  0000005B | LEFT SQUARE BRACKET
     5C |  0000005C | REVERSE SOLIDUS
     5D |  0000005D | RIGHT SQUARE BRACKET
     5E |  0000005E | CIRCUMFLEX ACCENT
     5F |  0000005F | LOW LINE
     60 |  00000060 | GRAVE ACCENT
     61 |  00000061 | LATIN SMALL LETTER A
     62 |  00000062 | LATIN SMALL LETTER B
     63 |  00000063 | LATIN SMALL LETTER C
     64 |  00000064 | LATIN SMALL LETTER D
     65 |  00000065 | LATIN SMALL LETTER E
     66 |  00000066 | LATIN SMALL LETTER F
     67 |  00000067 | LATIN SMALL LETTER G
     68 |  00000068 | LATIN SMALL LETTER H
     69 |  00000069 | LATIN SMALL LETTER I
     6A |  0000006A | LATIN SMALL LETTER J
     6B |  0000006B | LATIN SMALL LETTER K
     6C |  0000006C | LATIN SMALL LETTER L
     6D |  0000006D | LATIN SMALL LETTER M
     6E |  0000006E | LATIN SMALL LETTER N
     6F |  0000006F | LATIN SMALL LETTER O
     70 |  00000070 | LATIN SMALL LETTER P
     71 |  00000071 | LATIN SMALL LETTER Q
     72 |  00000072 | LATIN SMALL LETTER R
     73 |  00000073 | LATIN SMALL LETTER S
     74 |  00000074 | LATIN SMALL LETTER T
     75 |  00000075 | LATIN SMALL LETTER U
     76 |  00000076 | LATIN SMALL LETTER V
     77 |  00000077 | LATIN SMALL LETTER W
     78 |  00000078 | LATIN SMALL LETTER X
     79 |  00000079 | LATIN SMALL LETTER Y
     7A |  0000007A | LATIN SMALL LETTER Z
     7B |  0000007B | LEFT CURLY BRACKET
     7C |  0000007C | VERTICAL LINE
     7D |  0000007D | RIGHT CURLY BRACKET
     7E |  0000007E | TILDE
     7F |  0000007F | DELETE (DEL)
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/IBM904.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for IBM904.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::IBM904;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x0004,
     0x0005,
     0x0006,
     0x0007,
     0x0008,
     0x0009,
     0x000a,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x0014,
     0x0015,
     0x0016,
     0x0017,
     0x0018,
     0x0019,
     0x001a,
     0x001b,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0020,
     0x0021,
     0x0022,
     0x0023,
     0x0024,
     0x0025,
     0x0026,
     0x0027,
     0x0028,
     0x0029,
     0x002a,
     0x002b,
     0x002c,
     0x002d,
     0x002e,
     0x002f,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x003a,
     0x003b,
     0x003c,
     0x003d,
     0x003e,
     0x003f,
     0x0040,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x005b,
     0x005c,
     0x005d,
     0x005e,
     0x005f,
     0x0060,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x007b,
     0x007c,
     0x007d,
     0x007e,
     0x007f,
     0x00a2,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00ac,
     0x00a6,
     0xfffd,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\x04",
     "\x05",
     "\x06",
     "\x07",
     "\x08",
     "\x09",
     "\x0a",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\x14",
     "\x15",
     "\x16",
     "\x17",
     "\x18",
     "\x19",
     "\x1a",
     "\x1b",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\x20",
     "\x21",
     "\x22",
     "\x23",
     "\x24",
     "\x25",
     "\x26",
     "\x27",
     "\x28",
     "\x29",
     "\x2a",
     "\x2b",
     "\x2c",
     "\x2d",
     "\x2e",
     "\x2f",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\x3a",
     "\x3b",
     "\x3c",
     "\x3d",
     "\x3e",
     "\x3f",
     "\x40",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\x5b",
     "\x5c",
     "\x5d",
     "\x5e",
     "\x5f",
     "\x60",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\x7b",
     "\x7c",
     "\x7d",
     "\x7e",
     "\x7f",
     "\xc2\xa2",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc2\xac",
     "\xc2\xa6",
     "\xef\xbf\xbd",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x04",
     0x00000005 => "\x05",
     0x00000006 => "\x06",
     0x00000007 => "\x07",
     0x00000008 => "\x08",
     0x00000009 => "\x09",
     0x0000000a => "\x0a",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x14",
     0x00000015 => "\x15",
     0x00000016 => "\x16",
     0x00000017 => "\x17",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x1a",
     0x0000001b => "\x1b",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x20",
     0x00000021 => "\x21",
     0x00000022 => "\x22",
     0x00000023 => "\x23",
     0x00000024 => "\x24",
     0x00000025 => "\x25",
     0x00000026 => "\x26",
     0x00000027 => "\x27",
     0x00000028 => "\x28",
     0x00000029 => "\x29",
     0x0000002a => "\x2a",
     0x0000002b => "\x2b",
     0x0000002c => "\x2c",
     0x0000002d => "\x2d",
     0x0000002e => "\x2e",
     0x0000002f => "\x2f",
     0x00000030 => "\x30",
     0x00000031 => "\x31",
     0x00000032 => "\x32",
     0x00000033 => "\x33",
     0x00000034 => "\x34",
     0x00000035 => "\x35",
     0x00000036 => "\x36",
     0x00000037 => "\x37",
     0x00000038 => "\x38",
     0x00000039 => "\x39",
     0x0000003a => "\x3a",
     0x0000003b => "\x3b",
     0x0000003c => "\x3c",
     0x0000003d => "\x3d",
     0x0000003e => "\x3e",
     0x0000003f => "\x3f",
     0x00000040 => "\x40",
     0x00000041 => "\x41",
     0x00000042 => "\x42",
     0x00000043 => "\x43",
     0x00000044 => "\x44",
     0x00000045 => "\x45",
     0x00000046 => "\x46",
     0x00000047 => "\x47",
     0x00000048 => "\x48",
     0x00000049 => "\x49",
     0x0000004a => "\x4a",
     0x0000004b => "\x4b",
     0x0000004c => "\x4c",
     0x0000004d => "\x4d",
     0x0000004e => "\x4e",
     0x0000004f => "\x4f",
     0x00000050 => "\x50",
     0x00000051 => "\x51",
     0x00000052 => "\x52",
     0x00000053 => "\x53",
     0x00000054 => "\x54",
     0x00000055 => "\x55",
     0x00000056 => "\x56",
     0x00000057 => "\x57",
     0x00000058 => "\x58",
     0x00000059 => "\x59",
     0x0000005a => "\x5a",
     0x0000005b => "\x5b",
     0x0000005c => "\x5c",
     0x0000005d => "\x5d",
     0x0000005e => "\x5e",
     0x0000005f => "\x5f",
     0x00000060 => "\x60",
     0x00000061 => "\x61",
     0x00000062 => "\x62",
     0x00000063 => "\x63",
     0x00000064 => "\x64",
     0x00000065 => "\x65",
     0x00000066 => "\x66",
     0x00000067 => "\x67",
     0x00000068 => "\x68",
     0x00000069 => "\x69",
     0x0000006a => "\x6a",
     0x0000006b => "\x6b",
     0x0000006c => "\x6c",
     0x0000006d => "\x6d",
     0x0000006e => "\x6e",
     0x0000006f => "\x6f",
     0x00000070 => "\x70",
     0x00000071 => "\x71",
     0x00000072 => "\x72",
     0x00000073 => "\x73",
     0x00000074 => "\x74",
     0x00000075 => "\x75",
     0x00000076 => "\x76",
     0x00000077 => "\x77",
     0x00000078 => "\x78",
     0x00000079 => "\x79",
     0x0000007a => "\x7a",
     0x0000007b => "\x7b",
     0x0000007c => "\x7c",
     0x0000007d => "\x7d",
     0x0000007e => "\x7e",
     0x0000007f => "\x7f",
     0x000000a2 => "\x80",
     0x000000a6 => "\xfe",
     0x000000ac => "\xfd",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::IBM904 - Conversion routines for IBM904
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for IBM904.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
   source: IBM NLS RM Vol2 SE09-8002-01, March 1990
  alias CP904
  alias 904
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  00000004 | END OF TRANSMISSION (EOT)
     05 |  00000005 | ENQUIRY (ENQ)
     06 |  00000006 | ACKNOWLEDGE (ACK)
     07 |  00000007 | BELL (BEL)
     08 |  00000008 | BACKSPACE (BS)
     09 |  00000009 | CHARACTER TABULATION (HT)
     0A |  0000000A | LINE FEED (LF)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  00000014 | DEVICE CONTROL FOUR (DC4)
     15 |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     16 |  00000016 | SYNCHRONOUS IDLE (SYN)
     17 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  0000001A | SUBSTITUTE (SUB)
     1B |  0000001B | ESCAPE (ESC)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000020 | SPACE
     21 |  00000021 | EXCLAMATION MARK
     22 |  00000022 | QUOTATION MARK
     23 |  00000023 | NUMBER SIGN
     24 |  00000024 | DOLLAR SIGN
     25 |  00000025 | PERCENT SIGN
     26 |  00000026 | AMPERSAND
     27 |  00000027 | APOSTROPHE
     28 |  00000028 | LEFT PARENTHESIS
     29 |  00000029 | RIGHT PARENTHESIS
     2A |  0000002A | ASTERISK
     2B |  0000002B | PLUS SIGN
     2C |  0000002C | COMMA
     2D |  0000002D | HYPHEN-MINUS
     2E |  0000002E | FULL STOP
     2F |  0000002F | SOLIDUS
     30 |  00000030 | DIGIT ZERO
     31 |  00000031 | DIGIT ONE
     32 |  00000032 | DIGIT TWO
     33 |  00000033 | DIGIT THREE
     34 |  00000034 | DIGIT FOUR
     35 |  00000035 | DIGIT FIVE
     36 |  00000036 | DIGIT SIX
     37 |  00000037 | DIGIT SEVEN
     38 |  00000038 | DIGIT EIGHT
     39 |  00000039 | DIGIT NINE
     3A |  0000003A | COLON
     3B |  0000003B | SEMICOLON
     3C |  0000003C | LESS-THAN SIGN
     3D |  0000003D | EQUALS SIGN
     3E |  0000003E | GREATER-THAN SIGN
     3F |  0000003F | QUESTION MARK
     40 |  00000040 | COMMERCIAL AT
     41 |  00000041 | LATIN CAPITAL LETTER A
     42 |  00000042 | LATIN CAPITAL LETTER B
     43 |  00000043 | LATIN CAPITAL LETTER C
     44 |  00000044 | LATIN CAPITAL LETTER D
     45 |  00000045 | LATIN CAPITAL LETTER E
     46 |  00000046 | LATIN CAPITAL LETTER F
     47 |  00000047 | LATIN CAPITAL LETTER G
     48 |  00000048 | LATIN CAPITAL LETTER H
     49 |  00000049 | LATIN CAPITAL LETTER I
     4A |  0000004A | LATIN CAPITAL LETTER J
     4B |  0000004B | LATIN CAPITAL LETTER K
     4C |  0000004C | LATIN CAPITAL LETTER L
     4D |  0000004D | LATIN CAPITAL LETTER M
     4E |  0000004E | LATIN CAPITAL LETTER N
     4F |  0000004F | LATIN CAPITAL LETTER O
     50 |  00000050 | LATIN CAPITAL LETTER P
     51 |  00000051 | LATIN CAPITAL LETTER Q
     52 |  00000052 | LATIN CAPITAL LETTER R
     53 |  00000053 | LATIN CAPITAL LETTER S
     54 |  00000054 | LATIN CAPITAL LETTER T
     55 |  00000055 | LATIN CAPITAL LETTER U
     56 |  00000056 | LATIN CAPITAL LETTER V
     57 |  00000057 | LATIN CAPITAL LETTER W
     58 |  00000058 | LATIN CAPITAL LETTER X
     59 |  00000059 | LATIN CAPITAL LETTER Y
     5A |  0000005A | LATIN CAPITAL LETTER Z
     5B |  0000005B | LEFT SQUARE BRACKET
     5C |  0000005C | REVERSE SOLIDUS
     5D |  0000005D | RIGHT SQUARE BRACKET
     5E |  0000005E | CIRCUMFLEX ACCENT
     5F |  0000005F | LOW LINE
     60 |  00000060 | GRAVE ACCENT
     61 |  00000061 | LATIN SMALL LETTER A
     62 |  00000062 | LATIN SMALL LETTER B
     63 |  00000063 | LATIN SMALL LETTER C
     64 |  00000064 | LATIN SMALL LETTER D
     65 |  00000065 | LATIN SMALL LETTER E
     66 |  00000066 | LATIN SMALL LETTER F
     67 |  00000067 | LATIN SMALL LETTER G
     68 |  00000068 | LATIN SMALL LETTER H
     69 |  00000069 | LATIN SMALL LETTER I
     6A |  0000006A | LATIN SMALL LETTER J
     6B |  0000006B | LATIN SMALL LETTER K
     6C |  0000006C | LATIN SMALL LETTER L
     6D |  0000006D | LATIN SMALL LETTER M
     6E |  0000006E | LATIN SMALL LETTER N
     6F |  0000006F | LATIN SMALL LETTER O
     70 |  00000070 | LATIN SMALL LETTER P
     71 |  00000071 | LATIN SMALL LETTER Q
     72 |  00000072 | LATIN SMALL LETTER R
     73 |  00000073 | LATIN SMALL LETTER S
     74 |  00000074 | LATIN SMALL LETTER T
     75 |  00000075 | LATIN SMALL LETTER U
     76 |  00000076 | LATIN SMALL LETTER V
     77 |  00000077 | LATIN SMALL LETTER W
     78 |  00000078 | LATIN SMALL LETTER X
     79 |  00000079 | LATIN SMALL LETTER Y
     7A |  0000007A | LATIN SMALL LETTER Z
     7B |  0000007B | LEFT CURLY BRACKET
     7C |  0000007C | VERTICAL LINE
     7D |  0000007D | RIGHT CURLY BRACKET
     7E |  0000007E | TILDE
     7F |  0000007F | DELETE (DEL)
     80 |  000000A2 | CENT SIGN
     FD |  000000AC | NOT SIGN
     FE |  000000A6 | BROKEN BAR
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/IBM905.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for IBM905.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::IBM905;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x009c,
     0x0009,
     0x0086,
     0x007f,
     0x0097,
     0x008d,
     0x008e,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x009d,
     0x0085,
     0x0008,
     0x0087,
     0x0018,
     0x0019,
     0x0092,
     0x008f,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0080,
     0x0081,
     0x0082,
     0x0083,
     0x0084,
     0x000a,
     0x0017,
     0x001b,
     0x0088,
     0x0089,
     0x008a,
     0x008b,
     0x008c,
     0x0005,
     0x0006,
     0x0007,
     0x0090,
     0x0091,
     0x0016,
     0x0093,
     0x0094,
     0x0095,
     0x0096,
     0x0004,
     0x0098,
     0x0099,
     0x009a,
     0x009b,
     0x0014,
     0x0015,
     0x009e,
     0x001a,
     0x0020,
     0xfffd,
     0x00e2,
     0x00e4,
     0x00e0,
     0x00e1,
     0xfffd,
     0x010b,
     0x007b,
     0x00f1,
     0x00c7,
     0x002e,
     0x003c,
     0x0028,
     0x002b,
     0x0021,
     0x0026,
     0x00e9,
     0x00ea,
     0x00eb,
     0x00e8,
     0x00ed,
     0x00ee,
     0x00ef,
     0x00ec,
     0x00df,
     0x011e,
     0x0130,
     0x002a,
     0x0029,
     0x003b,
     0x005e,
     0x002d,
     0x002f,
     0x00c2,
     0x00c4,
     0x00c0,
     0x00c1,
     0xfffd,
     0x010a,
     0x005b,
     0x00d1,
     0x015f,
     0x002c,
     0x0025,
     0x005f,
     0x003e,
     0x003f,
     0xfffd,
     0x00c9,
     0x00ca,
     0x00cb,
     0x00c8,
     0x00cd,
     0x00ce,
     0x00cf,
     0x00cc,
     0x0131,
     0x003a,
     0x00d6,
     0x015e,
     0x0027,
     0x003d,
     0x00dc,
     0x02d8,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x0127,
     0x0109,
     0x015d,
     0x016d,
     0xfffd,
     0x007c,
     0x00b0,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x0125,
     0x011d,
     0x0135,
     0x02db,
     0xfffd,
     0x00a4,
     0x00b5,
     0x00f6,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x0126,
     0x0108,
     0x015c,
     0x016c,
     0xfffd,
     0x0040,
     0x00b7,
     0x00a3,
     0x017c,
     0x007d,
     0x017b,
     0x00a7,
     0x005d,
     0xfffd,
     0x00bd,
     0x0024,
     0x0124,
     0x011c,
     0x0134,
     0x00a8,
     0x00b4,
     0x00d7,
     0x00e7,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x00ad,
     0x00f4,
     0x007e,
     0x00f2,
     0x00f3,
     0x0121,
     0x011f,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x0060,
     0x00fb,
     0x005c,
     0x00f9,
     0x00fa,
     0xfffd,
     0x00fc,
     0x00f7,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x00b2,
     0x00d4,
     0x0023,
     0x00d2,
     0x00d3,
     0x0120,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x00b3,
     0x00db,
     0x0022,
     0x00d9,
     0x00da,
     0x009f,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\xc2\x9c",
     "\x09",
     "\xc2\x86",
     "\x7f",
     "\xc2\x97",
     "\xc2\x8d",
     "\xc2\x8e",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\xc2\x9d",
     "\xc2\x85",
     "\x08",
     "\xc2\x87",
     "\x18",
     "\x19",
     "\xc2\x92",
     "\xc2\x8f",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\xc2\x80",
     "\xc2\x81",
     "\xc2\x82",
     "\xc2\x83",
     "\xc2\x84",
     "\x0a",
     "\x17",
     "\x1b",
     "\xc2\x88",
     "\xc2\x89",
     "\xc2\x8a",
     "\xc2\x8b",
     "\xc2\x8c",
     "\x05",
     "\x06",
     "\x07",
     "\xc2\x90",
     "\xc2\x91",
     "\x16",
     "\xc2\x93",
     "\xc2\x94",
     "\xc2\x95",
     "\xc2\x96",
     "\x04",
     "\xc2\x98",
     "\xc2\x99",
     "\xc2\x9a",
     "\xc2\x9b",
     "\x14",
     "\x15",
     "\xc2\x9e",
     "\x1a",
     "\x20",
     "\xef\xbf\xbd",
     "\xc3\xa2",
     "\xc3\xa4",
     "\xc3\xa0",
     "\xc3\xa1",
     "\xef\xbf\xbd",
     "\xc4\x8b",
     "\x7b",
     "\xc3\xb1",
     "\xc3\x87",
     "\x2e",
     "\x3c",
     "\x28",
     "\x2b",
     "\x21",
     "\x26",
     "\xc3\xa9",
     "\xc3\xaa",
     "\xc3\xab",
     "\xc3\xa8",
     "\xc3\xad",
     "\xc3\xae",
     "\xc3\xaf",
     "\xc3\xac",
     "\xc3\x9f",
     "\xc4\x9e",
     "\xc4\xb0",
     "\x2a",
     "\x29",
     "\x3b",
     "\x5e",
     "\x2d",
     "\x2f",
     "\xc3\x82",
     "\xc3\x84",
     "\xc3\x80",
     "\xc3\x81",
     "\xef\xbf\xbd",
     "\xc4\x8a",
     "\x5b",
     "\xc3\x91",
     "\xc5\x9f",
     "\x2c",
     "\x25",
     "\x5f",
     "\x3e",
     "\x3f",
     "\xef\xbf\xbd",
     "\xc3\x89",
     "\xc3\x8a",
     "\xc3\x8b",
     "\xc3\x88",
     "\xc3\x8d",
     "\xc3\x8e",
     "\xc3\x8f",
     "\xc3\x8c",
     "\xc4\xb1",
     "\x3a",
     "\xc3\x96",
     "\xc5\x9e",
     "\x27",
     "\x3d",
     "\xc3\x9c",
     "\xcb\x98",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\xc4\xa7",
     "\xc4\x89",
     "\xc5\x9d",
     "\xc5\xad",
     "\xef\xbf\xbd",
     "\x7c",
     "\xc2\xb0",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\xc4\xa5",
     "\xc4\x9d",
     "\xc4\xb5",
     "\xcb\x9b",
     "\xef\xbf\xbd",
     "\xc2\xa4",
     "\xc2\xb5",
     "\xc3\xb6",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\xc4\xa6",
     "\xc4\x88",
     "\xc5\x9c",
     "\xc5\xac",
     "\xef\xbf\xbd",
     "\x40",
     "\xc2\xb7",
     "\xc2\xa3",
     "\xc5\xbc",
     "\x7d",
     "\xc5\xbb",
     "\xc2\xa7",
     "\x5d",
     "\xef\xbf\xbd",
     "\xc2\xbd",
     "\x24",
     "\xc4\xa4",
     "\xc4\x9c",
     "\xc4\xb4",
     "\xc2\xa8",
     "\xc2\xb4",
     "\xc3\x97",
     "\xc3\xa7",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\xc2\xad",
     "\xc3\xb4",
     "\x7e",
     "\xc3\xb2",
     "\xc3\xb3",
     "\xc4\xa1",
     "\xc4\x9f",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\x60",
     "\xc3\xbb",
     "\x5c",
     "\xc3\xb9",
     "\xc3\xba",
     "\xef\xbf\xbd",
     "\xc3\xbc",
     "\xc3\xb7",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\xc2\xb2",
     "\xc3\x94",
     "\x23",
     "\xc3\x92",
     "\xc3\x93",
     "\xc4\xa0",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\xc2\xb3",
     "\xc3\x9b",
     "\x22",
     "\xc3\x99",
     "\xc3\x9a",
     "\xc2\x9f",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x37",
     0x00000005 => "\x2d",
     0x00000006 => "\x2e",
     0x00000007 => "\x2f",
     0x00000008 => "\x16",
     0x00000009 => "\x05",
     0x0000000a => "\x25",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x3c",
     0x00000015 => "\x3d",
     0x00000016 => "\x32",
     0x00000017 => "\x26",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x3f",
     0x0000001b => "\x27",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x40",
     0x00000021 => "\x4f",
     0x00000022 => "\xfc",
     0x00000023 => "\xec",
     0x00000024 => "\xb9",
     0x00000025 => "\x6c",
     0x00000026 => "\x50",
     0x00000027 => "\x7d",
     0x00000028 => "\x4d",
     0x00000029 => "\x5d",
     0x0000002a => "\x5c",
     0x0000002b => "\x4e",
     0x0000002c => "\x6b",
     0x0000002d => "\x60",
     0x0000002e => "\x4b",
     0x0000002f => "\x61",
     0x00000030 => "\xf0",
     0x00000031 => "\xf1",
     0x00000032 => "\xf2",
     0x00000033 => "\xf3",
     0x00000034 => "\xf4",
     0x00000035 => "\xf5",
     0x00000036 => "\xf6",
     0x00000037 => "\xf7",
     0x00000038 => "\xf8",
     0x00000039 => "\xf9",
     0x0000003a => "\x7a",
     0x0000003b => "\x5e",
     0x0000003c => "\x4c",
     0x0000003d => "\x7e",
     0x0000003e => "\x6e",
     0x0000003f => "\x6f",
     0x00000040 => "\xaf",
     0x00000041 => "\xc1",
     0x00000042 => "\xc2",
     0x00000043 => "\xc3",
     0x00000044 => "\xc4",
     0x00000045 => "\xc5",
     0x00000046 => "\xc6",
     0x00000047 => "\xc7",
     0x00000048 => "\xc8",
     0x00000049 => "\xc9",
     0x0000004a => "\xd1",
     0x0000004b => "\xd2",
     0x0000004c => "\xd3",
     0x0000004d => "\xd4",
     0x0000004e => "\xd5",
     0x0000004f => "\xd6",
     0x00000050 => "\xd7",
     0x00000051 => "\xd8",
     0x00000052 => "\xd9",
     0x00000053 => "\xe2",
     0x00000054 => "\xe3",
     0x00000055 => "\xe4",
     0x00000056 => "\xe5",
     0x00000057 => "\xe6",
     0x00000058 => "\xe7",
     0x00000059 => "\xe8",
     0x0000005a => "\xe9",
     0x0000005b => "\x68",
     0x0000005c => "\xdc",
     0x0000005d => "\xb6",
     0x0000005e => "\x5f",
     0x0000005f => "\x6d",
     0x00000060 => "\xda",
     0x00000061 => "\x81",
     0x00000062 => "\x82",
     0x00000063 => "\x83",
     0x00000064 => "\x84",
     0x00000065 => "\x85",
     0x00000066 => "\x86",
     0x00000067 => "\x87",
     0x00000068 => "\x88",
     0x00000069 => "\x89",
     0x0000006a => "\x91",
     0x0000006b => "\x92",
     0x0000006c => "\x93",
     0x0000006d => "\x94",
     0x0000006e => "\x95",
     0x0000006f => "\x96",
     0x00000070 => "\x97",
     0x00000071 => "\x98",
     0x00000072 => "\x99",
     0x00000073 => "\xa2",
     0x00000074 => "\xa3",
     0x00000075 => "\xa4",
     0x00000076 => "\xa5",
     0x00000077 => "\xa6",
     0x00000078 => "\xa7",
     0x00000079 => "\xa8",
     0x0000007a => "\xa9",
     0x0000007b => "\x48",
     0x0000007c => "\x8f",
     0x0000007d => "\xb3",
     0x0000007e => "\xcc",
     0x0000007f => "\x07",
     0x00000080 => "\x20",
     0x00000081 => "\x21",
     0x00000082 => "\x22",
     0x00000083 => "\x23",
     0x00000084 => "\x24",
     0x00000085 => "\x15",
     0x00000086 => "\x06",
     0x00000087 => "\x17",
     0x00000088 => "\x28",
     0x00000089 => "\x29",
     0x0000008a => "\x2a",
     0x0000008b => "\x2b",
     0x0000008c => "\x2c",
     0x0000008d => "\x09",
     0x0000008e => "\x0a",
     0x0000008f => "\x1b",
     0x00000090 => "\x30",
     0x00000091 => "\x31",
     0x00000092 => "\x1a",
     0x00000093 => "\x33",
     0x00000094 => "\x34",
     0x00000095 => "\x35",
     0x00000096 => "\x36",
     0x00000097 => "\x08",
     0x00000098 => "\x38",
     0x00000099 => "\x39",
     0x0000009a => "\x3a",
     0x0000009b => "\x3b",
     0x0000009c => "\x04",
     0x0000009d => "\x14",
     0x0000009e => "\x3e",
     0x0000009f => "\xff",
     0x000000a3 => "\xb1",
     0x000000a4 => "\x9f",
     0x000000a7 => "\xb5",
     0x000000a8 => "\xbd",
     0x000000ad => "\xca",
     0x000000b0 => "\x90",
     0x000000b2 => "\xea",
     0x000000b3 => "\xfa",
     0x000000b4 => "\xbe",
     0x000000b5 => "\xa0",
     0x000000b7 => "\xb0",
     0x000000bd => "\xb8",
     0x000000c0 => "\x64",
     0x000000c1 => "\x65",
     0x000000c2 => "\x62",
     0x000000c4 => "\x63",
     0x000000c7 => "\x4a",
     0x000000c8 => "\x74",
     0x000000c9 => "\x71",
     0x000000ca => "\x72",
     0x000000cb => "\x73",
     0x000000cc => "\x78",
     0x000000cd => "\x75",
     0x000000ce => "\x76",
     0x000000cf => "\x77",
     0x000000d1 => "\x69",
     0x000000d2 => "\xed",
     0x000000d3 => "\xee",
     0x000000d4 => "\xeb",
     0x000000d6 => "\x7b",
     0x000000d7 => "\xbf",
     0x000000d9 => "\xfd",
     0x000000da => "\xfe",
     0x000000db => "\xfb",
     0x000000dc => "\x7f",
     0x000000df => "\x59",
     0x000000e0 => "\x44",
     0x000000e1 => "\x45",
     0x000000e2 => "\x42",
     0x000000e4 => "\x43",
     0x000000e7 => "\xc0",
     0x000000e8 => "\x54",
     0x000000e9 => "\x51",
     0x000000ea => "\x52",
     0x000000eb => "\x53",
     0x000000ec => "\x58",
     0x000000ed => "\x55",
     0x000000ee => "\x56",
     0x000000ef => "\x57",
     0x000000f1 => "\x49",
     0x000000f2 => "\xcd",
     0x000000f3 => "\xce",
     0x000000f4 => "\xcb",
     0x000000f6 => "\xa1",
     0x000000f7 => "\xe1",
     0x000000f9 => "\xdd",
     0x000000fa => "\xde",
     0x000000fb => "\xdb",
     0x000000fc => "\xe0",
     0x00000108 => "\xab",
     0x00000109 => "\x8b",
     0x0000010a => "\x67",
     0x0000010b => "\x47",
     0x0000011c => "\xbb",
     0x0000011d => "\x9b",
     0x0000011e => "\x5a",
     0x0000011f => "\xd0",
     0x00000120 => "\xef",
     0x00000121 => "\xcf",
     0x00000124 => "\xba",
     0x00000125 => "\x9a",
     0x00000126 => "\xaa",
     0x00000127 => "\x8a",
     0x00000130 => "\x5b",
     0x00000131 => "\x79",
     0x00000134 => "\xbc",
     0x00000135 => "\x9c",
     0x0000015c => "\xac",
     0x0000015d => "\x8c",
     0x0000015e => "\x7c",
     0x0000015f => "\x6a",
     0x0000016c => "\xad",
     0x0000016d => "\x8d",
     0x0000017b => "\xb4",
     0x0000017c => "\xb2",
     0x000002d8 => "\x80",
     0x000002db => "\x9d",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x6f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::IBM905 - Conversion routines for IBM905
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for IBM905.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
   source: IBM 3174 Character Set Ref, GA27-3831-02, March 1990
  alias CP905
  alias EBCDIC-CP-TR
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  0000009C | STRING TERMINATOR (ST)
     05 |  00000009 | CHARACTER TABULATION (HT)
     06 |  00000086 | START OF SELECTED AREA (SSA)
     07 |  0000007F | DELETE (DEL)
     08 |  00000097 | END OF GUARDED AREA (EPA)
     09 |  0000008D | REVERSE LINE FEED (RI)
     0A |  0000008E | SINGLE-SHIFT TWO (SS2)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  0000009D | OPERATING SYSTEM COMMAND (OSC)
     15 |  00000085 | NEXT LINE (NEL)
     16 |  00000008 | BACKSPACE (BS)
     17 |  00000087 | END OF SELECTED AREA (ESA)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  00000092 | PRIVATE USE TWO (PU2)
     1B |  0000008F | SINGLE-SHIFT THREE (SS3)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000080 | PADDING CHARACTER (PAD)
     21 |  00000081 | HIGH OCTET PRESET (HOP)
     22 |  00000082 | BREAK PERMITTED HERE (BPH)
     23 |  00000083 | NO BREAK HERE (NBH)
     24 |  00000084 | INDEX (IND)
     25 |  0000000A | LINE FEED (LF)
     26 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     27 |  0000001B | ESCAPE (ESC)
     28 |  00000088 | CHARACTER TABULATION SET (HTS)
     29 |  00000089 | CHARACTER TABULATION WITH JUSTIFICATION (HTJ)
     2A |  0000008A | LINE TABULATION SET (VTS)
     2B |  0000008B | PARTIAL LINE FORWARD (PLD)
     2C |  0000008C | PARTIAL LINE BACKWARD (PLU)
     2D |  00000005 | ENQUIRY (ENQ)
     2E |  00000006 | ACKNOWLEDGE (ACK)
     2F |  00000007 | BELL (BEL)
     30 |  00000090 | DEVICE CONTROL STRING (DCS)
     31 |  00000091 | PRIVATE USE ONE (PU1)
     32 |  00000016 | SYNCHRONOUS IDLE (SYN)
     33 |  00000093 | SET TRANSMIT STATE (STS)
     34 |  00000094 | CANCEL CHARACTER (CCH)
     35 |  00000095 | MESSAGE WAITING (MW)
     36 |  00000096 | START OF GUARDED AREA (SPA)
     37 |  00000004 | END OF TRANSMISSION (EOT)
     38 |  00000098 | START OF STRING (SOS)
     39 |  00000099 | SINGLE GRAPHIC CHARACTER INTRODUCER (SGCI)
     3A |  0000009A | SINGLE CHARACTER INTRODUCER (SCI)
     3B |  0000009B | CONTROL SEQUENCE INTRODUCER (CSI)
     3C |  00000014 | DEVICE CONTROL FOUR (DC4)
     3D |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     3E |  0000009E | PRIVACY MESSAGE (PM)
     3F |  0000001A | SUBSTITUTE (SUB)
     40 |  00000020 | SPACE
     42 |  000000E2 | LATIN SMALL LETTER A WITH CIRCUMFLEX
     43 |  000000E4 | LATIN SMALL LETTER A WITH DIAERESIS
     44 |  000000E0 | LATIN SMALL LETTER A WITH GRAVE
     45 |  000000E1 | LATIN SMALL LETTER A WITH ACUTE
     47 |  0000010B | LATIN SMALL LETTER C WITH DOT ABOVE
     48 |  0000007B | LEFT CURLY BRACKET
     49 |  000000F1 | LATIN SMALL LETTER N WITH TILDE
     4A |  000000C7 | LATIN CAPITAL LETTER C WITH CEDILLA
     4B |  0000002E | FULL STOP
     4C |  0000003C | LESS-THAN SIGN
     4D |  00000028 | LEFT PARENTHESIS
     4E |  0000002B | PLUS SIGN
     4F |  00000021 | EXCLAMATION MARK
     50 |  00000026 | AMPERSAND
     51 |  000000E9 | LATIN SMALL LETTER E WITH ACUTE
     52 |  000000EA | LATIN SMALL LETTER E WITH CIRCUMFLEX
     53 |  000000EB | LATIN SMALL LETTER E WITH DIAERESIS
     54 |  000000E8 | LATIN SMALL LETTER E WITH GRAVE
     55 |  000000ED | LATIN SMALL LETTER I WITH ACUTE
     56 |  000000EE | LATIN SMALL LETTER I WITH CIRCUMFLEX
     57 |  000000EF | LATIN SMALL LETTER I WITH DIAERESIS
     58 |  000000EC | LATIN SMALL LETTER I WITH GRAVE
     59 |  000000DF | LATIN SMALL LETTER SHARP S (German)
     5A |  0000011E | LATIN CAPITAL LETTER G WITH BREVE
     5B |  00000130 | LATIN CAPITAL LETTER I WITH DOT ABOVE
     5C |  0000002A | ASTERISK
     5D |  00000029 | RIGHT PARENTHESIS
     5E |  0000003B | SEMICOLON
     5F |  0000005E | CIRCUMFLEX ACCENT
     60 |  0000002D | HYPHEN-MINUS
     61 |  0000002F | SOLIDUS
     62 |  000000C2 | LATIN CAPITAL LETTER A WITH CIRCUMFLEX
     63 |  000000C4 | LATIN CAPITAL LETTER A WITH DIAERESIS
     64 |  000000C0 | LATIN CAPITAL LETTER A WITH GRAVE
     65 |  000000C1 | LATIN CAPITAL LETTER A WITH ACUTE
     67 |  0000010A | LATIN CAPITAL LETTER C WITH DOT ABOVE
     68 |  0000005B | LEFT SQUARE BRACKET
     69 |  000000D1 | LATIN CAPITAL LETTER N WITH TILDE
     6A |  0000015F | LATIN SMALL LETTER S WITH CEDILLA
     6B |  0000002C | COMMA
     6C |  00000025 | PERCENT SIGN
     6D |  0000005F | LOW LINE
     6E |  0000003E | GREATER-THAN SIGN
     6F |  0000003F | QUESTION MARK
     71 |  000000C9 | LATIN CAPITAL LETTER E WITH ACUTE
     72 |  000000CA | LATIN CAPITAL LETTER E WITH CIRCUMFLEX
     73 |  000000CB | LATIN CAPITAL LETTER E WITH DIAERESIS
     74 |  000000C8 | LATIN CAPITAL LETTER E WITH GRAVE
     75 |  000000CD | LATIN CAPITAL LETTER I WITH ACUTE
     76 |  000000CE | LATIN CAPITAL LETTER I WITH CIRCUMFLEX
     77 |  000000CF | LATIN CAPITAL LETTER I WITH DIAERESIS
     78 |  000000CC | LATIN CAPITAL LETTER I WITH GRAVE
     79 |  00000131 | LATIN SMALL LETTER DOTLESS I
     7A |  0000003A | COLON
     7B |  000000D6 | LATIN CAPITAL LETTER O WITH DIAERESIS
     7C |  0000015E | LATIN CAPITAL LETTER S WITH CEDILLA
     7D |  00000027 | APOSTROPHE
     7E |  0000003D | EQUALS SIGN
     7F |  000000DC | LATIN CAPITAL LETTER U WITH DIAERESIS
     80 |  000002D8 | BREVE
     81 |  00000061 | LATIN SMALL LETTER A
     82 |  00000062 | LATIN SMALL LETTER B
     83 |  00000063 | LATIN SMALL LETTER C
     84 |  00000064 | LATIN SMALL LETTER D
     85 |  00000065 | LATIN SMALL LETTER E
     86 |  00000066 | LATIN SMALL LETTER F
     87 |  00000067 | LATIN SMALL LETTER G
     88 |  00000068 | LATIN SMALL LETTER H
     89 |  00000069 | LATIN SMALL LETTER I
     8A |  00000127 | LATIN SMALL LETTER H WITH STROKE
     8B |  00000109 | LATIN SMALL LETTER C WITH CIRCUMFLEX
     8C |  0000015D | LATIN SMALL LETTER S WITH CIRCUMFLEX
     8D |  0000016D | LATIN SMALL LETTER U WITH BREVE
     8F |  0000007C | VERTICAL LINE
     90 |  000000B0 | DEGREE SIGN
     91 |  0000006A | LATIN SMALL LETTER J
     92 |  0000006B | LATIN SMALL LETTER K
     93 |  0000006C | LATIN SMALL LETTER L
     94 |  0000006D | LATIN SMALL LETTER M
     95 |  0000006E | LATIN SMALL LETTER N
     96 |  0000006F | LATIN SMALL LETTER O
     97 |  00000070 | LATIN SMALL LETTER P
     98 |  00000071 | LATIN SMALL LETTER Q
     99 |  00000072 | LATIN SMALL LETTER R
     9A |  00000125 | LATIN SMALL LETTER H WITH CIRCUMFLEX
     9B |  0000011D | LATIN SMALL LETTER G WITH CIRCUMFLEX
     9C |  00000135 | LATIN SMALL LETTER J WITH CIRCUMFLEX
     9D |  000002DB | OGONEK
     9F |  000000A4 | CURRENCY SIGN
     A0 |  000000B5 | MICRO SIGN
     A1 |  000000F6 | LATIN SMALL LETTER O WITH DIAERESIS
     A2 |  00000073 | LATIN SMALL LETTER S
     A3 |  00000074 | LATIN SMALL LETTER T
     A4 |  00000075 | LATIN SMALL LETTER U
     A5 |  00000076 | LATIN SMALL LETTER V
     A6 |  00000077 | LATIN SMALL LETTER W
     A7 |  00000078 | LATIN SMALL LETTER X
     A8 |  00000079 | LATIN SMALL LETTER Y
     A9 |  0000007A | LATIN SMALL LETTER Z
     AA |  00000126 | LATIN CAPITAL LETTER H WITH STROKE
     AB |  00000108 | LATIN CAPITAL LETTER C WITH CIRCUMFLEX
     AC |  0000015C | LATIN CAPITAL LETTER S WITH CIRCUMFLEX
     AD |  0000016C | LATIN CAPITAL LETTER U WITH BREVE
     AF |  00000040 | COMMERCIAL AT
     B0 |  000000B7 | MIDDLE DOT
     B1 |  000000A3 | POUND SIGN
     B2 |  0000017C | LATIN SMALL LETTER Z WITH DOT ABOVE
     B3 |  0000007D | RIGHT CURLY BRACKET
     B4 |  0000017B | LATIN CAPITAL LETTER Z WITH DOT ABOVE
     B5 |  000000A7 | SECTION SIGN
     B6 |  0000005D | RIGHT SQUARE BRACKET
     B8 |  000000BD | VULGAR FRACTION ONE HALF
     B9 |  00000024 | DOLLAR SIGN
     BA |  00000124 | LATIN CAPITAL LETTER H WITH CIRCUMFLEX
     BB |  0000011C | LATIN CAPITAL LETTER G WITH CIRCUMFLEX
     BC |  00000134 | LATIN CAPITAL LETTER J WITH CIRCUMFLEX
     BD |  000000A8 | DIAERESIS
     BE |  000000B4 | ACUTE ACCENT
     BF |  000000D7 | MULTIPLICATION SIGN
     C0 |  000000E7 | LATIN SMALL LETTER C WITH CEDILLA
     C1 |  00000041 | LATIN CAPITAL LETTER A
     C2 |  00000042 | LATIN CAPITAL LETTER B
     C3 |  00000043 | LATIN CAPITAL LETTER C
     C4 |  00000044 | LATIN CAPITAL LETTER D
     C5 |  00000045 | LATIN CAPITAL LETTER E
     C6 |  00000046 | LATIN CAPITAL LETTER F
     C7 |  00000047 | LATIN CAPITAL LETTER G
     C8 |  00000048 | LATIN CAPITAL LETTER H
     C9 |  00000049 | LATIN CAPITAL LETTER I
     CA |  000000AD | SOFT HYPHEN
     CB |  000000F4 | LATIN SMALL LETTER O WITH CIRCUMFLEX
     CC |  0000007E | TILDE
     CD |  000000F2 | LATIN SMALL LETTER O WITH GRAVE
     CE |  000000F3 | LATIN SMALL LETTER O WITH ACUTE
     CF |  00000121 | LATIN SMALL LETTER G WITH DOT ABOVE
     D0 |  0000011F | LATIN SMALL LETTER G WITH BREVE
     D1 |  0000004A | LATIN CAPITAL LETTER J
     D2 |  0000004B | LATIN CAPITAL LETTER K
     D3 |  0000004C | LATIN CAPITAL LETTER L
     D4 |  0000004D | LATIN CAPITAL LETTER M
     D5 |  0000004E | LATIN CAPITAL LETTER N
     D6 |  0000004F | LATIN CAPITAL LETTER O
     D7 |  00000050 | LATIN CAPITAL LETTER P
     D8 |  00000051 | LATIN CAPITAL LETTER Q
     D9 |  00000052 | LATIN CAPITAL LETTER R
     DA |  00000060 | GRAVE ACCENT
     DB |  000000FB | LATIN SMALL LETTER U WITH CIRCUMFLEX
     DC |  0000005C | REVERSE SOLIDUS
     DD |  000000F9 | LATIN SMALL LETTER U WITH GRAVE
     DE |  000000FA | LATIN SMALL LETTER U WITH ACUTE
     E0 |  000000FC | LATIN SMALL LETTER U WITH DIAERESIS
     E1 |  000000F7 | DIVISION SIGN
     E2 |  00000053 | LATIN CAPITAL LETTER S
     E3 |  00000054 | LATIN CAPITAL LETTER T
     E4 |  00000055 | LATIN CAPITAL LETTER U
     E5 |  00000056 | LATIN CAPITAL LETTER V
     E6 |  00000057 | LATIN CAPITAL LETTER W
     E7 |  00000058 | LATIN CAPITAL LETTER X
     E8 |  00000059 | LATIN CAPITAL LETTER Y
     E9 |  0000005A | LATIN CAPITAL LETTER Z
     EA |  000000B2 | SUPERSCRIPT TWO
     EB |  000000D4 | LATIN CAPITAL LETTER O WITH CIRCUMFLEX
     EC |  00000023 | NUMBER SIGN
     ED |  000000D2 | LATIN CAPITAL LETTER O WITH GRAVE
     EE |  000000D3 | LATIN CAPITAL LETTER O WITH ACUTE
     EF |  00000120 | LATIN CAPITAL LETTER G WITH DOT ABOVE
     F0 |  00000030 | DIGIT ZERO
     F1 |  00000031 | DIGIT ONE
     F2 |  00000032 | DIGIT TWO
     F3 |  00000033 | DIGIT THREE
     F4 |  00000034 | DIGIT FOUR
     F5 |  00000035 | DIGIT FIVE
     F6 |  00000036 | DIGIT SIX
     F7 |  00000037 | DIGIT SEVEN
     F8 |  00000038 | DIGIT EIGHT
     F9 |  00000039 | DIGIT NINE
     FA |  000000B3 | SUPERSCRIPT THREE
     FB |  000000DB | LATIN CAPITAL LETTER U WITH CIRCUMFLEX
     FC |  00000022 | QUOTATION MARK
     FD |  000000D9 | LATIN CAPITAL LETTER U WITH GRAVE
     FE |  000000DA | LATIN CAPITAL LETTER U WITH ACUTE
     FF |  0000009F | APPLICATION PROGRAM COMMAND (APC)
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/IBM918.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for IBM918.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::IBM918;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x009c,
     0x0009,
     0x0086,
     0x007f,
     0x0097,
     0x008d,
     0x008e,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x009d,
     0x0085,
     0x0008,
     0x0087,
     0x0018,
     0x0019,
     0x0092,
     0x008f,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0080,
     0x0081,
     0x0082,
     0x0083,
     0x0084,
     0x000a,
     0x0017,
     0x001b,
     0x0088,
     0x0089,
     0x008a,
     0x008b,
     0x008c,
     0x0005,
     0x0006,
     0x0007,
     0x0090,
     0x0091,
     0x0016,
     0x0093,
     0x0094,
     0x0095,
     0x0096,
     0x0004,
     0x0098,
     0x0099,
     0x009a,
     0x009b,
     0x0014,
     0x0015,
     0x009e,
     0x001a,
     0x0020,
     0x00a0,
     0x060c,
     0x061b,
     0x061f,
     0x0623,
     0x0627,
     0xfe8e,
     0xfffd,
     0x0628,
     0x005b,
     0x002e,
     0x003c,
     0x0028,
     0x002b,
     0x0021,
     0x0026,
     0xfe91,
     0x067e,
     0xfffd,
     0x0629,
     0x062a,
     0xfe97,
     0xfffd,
     0xfffd,
     0x062b,
     0x005d,
     0x0024,
     0x002a,
     0x0029,
     0x003b,
     0x005e,
     0x002d,
     0x002f,
     0xfe9b,
     0x062c,
     0xfe9f,
     0xfffd,
     0xfffd,
     0x062d,
     0xfea3,
     0x062e,
     0x0060,
     0x002c,
     0x0025,
     0x005f,
     0x003e,
     0x003f,
     0x0660,
     0x0661,
     0x0662,
     0x0663,
     0x0664,
     0x0665,
     0x0666,
     0x0667,
     0x0668,
     0x0669,
     0x003a,
     0x0023,
     0x0040,
     0x0027,
     0x003d,
     0x0022,
     0xfea7,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x062f,
     0xfffd,
     0x0630,
     0x0631,
     0xfffd,
     0x0632,
     0xfffd,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x0633,
     0xfeb3,
     0x0634,
     0xfeb7,
     0x0635,
     0xfebb,
     0x0636,
     0x007e,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0xfebf,
     0x0637,
     0x0638,
     0x0639,
     0xfeca,
     0xfecb,
     0xfecc,
     0x063a,
     0xfece,
     0xfecf,
     0xfed0,
     0x0641,
     0xfed3,
     0x0642,
     0xfed7,
     0x0643,
     0xfedb,
     0x007c,
     0xfffd,
     0xfffd,
     0x0644,
     0xfede,
     0x007b,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x00ad,
     0xfffd,
     0x0645,
     0xfee3,
     0xfffd,
     0x0646,
     0x007d,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0xfee7,
     0xfffd,
     0x0648,
     0xfffd,
     0xfffd,
     0xfffd,
     0x005c,
     0xfffd,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x0621,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0xfffd,
     0xfffd,
     0xfffd,
     0x0651,
     0xfe7d,
     0x009f,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\xc2\x9c",
     "\x09",
     "\xc2\x86",
     "\x7f",
     "\xc2\x97",
     "\xc2\x8d",
     "\xc2\x8e",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\xc2\x9d",
     "\xc2\x85",
     "\x08",
     "\xc2\x87",
     "\x18",
     "\x19",
     "\xc2\x92",
     "\xc2\x8f",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\xc2\x80",
     "\xc2\x81",
     "\xc2\x82",
     "\xc2\x83",
     "\xc2\x84",
     "\x0a",
     "\x17",
     "\x1b",
     "\xc2\x88",
     "\xc2\x89",
     "\xc2\x8a",
     "\xc2\x8b",
     "\xc2\x8c",
     "\x05",
     "\x06",
     "\x07",
     "\xc2\x90",
     "\xc2\x91",
     "\x16",
     "\xc2\x93",
     "\xc2\x94",
     "\xc2\x95",
     "\xc2\x96",
     "\x04",
     "\xc2\x98",
     "\xc2\x99",
     "\xc2\x9a",
     "\xc2\x9b",
     "\x14",
     "\x15",
     "\xc2\x9e",
     "\x1a",
     "\x20",
     "\xc2\xa0",
     "\xd8\x8c",
     "\xd8\x9b",
     "\xd8\x9f",
     "\xd8\xa3",
     "\xd8\xa7",
     "\xef\xba\x8e",
     "\xef\xbf\xbd",
     "\xd8\xa8",
     "\x5b",
     "\x2e",
     "\x3c",
     "\x28",
     "\x2b",
     "\x21",
     "\x26",
     "\xef\xba\x91",
     "\xd9\xbe",
     "\xef\xbf\xbd",
     "\xd8\xa9",
     "\xd8\xaa",
     "\xef\xba\x97",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xd8\xab",
     "\x5d",
     "\x24",
     "\x2a",
     "\x29",
     "\x3b",
     "\x5e",
     "\x2d",
     "\x2f",
     "\xef\xba\x9b",
     "\xd8\xac",
     "\xef\xba\x9f",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xd8\xad",
     "\xef\xba\xa3",
     "\xd8\xae",
     "\x60",
     "\x2c",
     "\x25",
     "\x5f",
     "\x3e",
     "\x3f",
     "\xd9\xa0",
     "\xd9\xa1",
     "\xd9\xa2",
     "\xd9\xa3",
     "\xd9\xa4",
     "\xd9\xa5",
     "\xd9\xa6",
     "\xd9\xa7",
     "\xd9\xa8",
     "\xd9\xa9",
     "\x3a",
     "\x23",
     "\x40",
     "\x27",
     "\x3d",
     "\x22",
     "\xef\xba\xa7",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\xd8\xaf",
     "\xef\xbf\xbd",
     "\xd8\xb0",
     "\xd8\xb1",
     "\xef\xbf\xbd",
     "\xd8\xb2",
     "\xef\xbf\xbd",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\xd8\xb3",
     "\xef\xba\xb3",
     "\xd8\xb4",
     "\xef\xba\xb7",
     "\xd8\xb5",
     "\xef\xba\xbb",
     "\xd8\xb6",
     "\x7e",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\xef\xba\xbf",
     "\xd8\xb7",
     "\xd8\xb8",
     "\xd8\xb9",
     "\xef\xbb\x8a",
     "\xef\xbb\x8b",
     "\xef\xbb\x8c",
     "\xd8\xba",
     "\xef\xbb\x8e",
     "\xef\xbb\x8f",
     "\xef\xbb\x90",
     "\xd9\x81",
     "\xef\xbb\x93",
     "\xd9\x82",
     "\xef\xbb\x97",
     "\xd9\x83",
     "\xef\xbb\x9b",
     "\x7c",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xd9\x84",
     "\xef\xbb\x9e",
     "\x7b",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\xc2\xad",
     "\xef\xbf\xbd",
     "\xd9\x85",
     "\xef\xbb\xa3",
     "\xef\xbf\xbd",
     "\xd9\x86",
     "\x7d",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\xef\xbb\xa7",
     "\xef\xbf\xbd",
     "\xd9\x88",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x5c",
     "\xef\xbf\xbd",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\xd8\xa1",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xd9\x91",
     "\xef\xb9\xbd",
     "\xc2\x9f",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x37",
     0x00000005 => "\x2d",
     0x00000006 => "\x2e",
     0x00000007 => "\x2f",
     0x00000008 => "\x16",
     0x00000009 => "\x05",
     0x0000000a => "\x25",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x3c",
     0x00000015 => "\x3d",
     0x00000016 => "\x32",
     0x00000017 => "\x26",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x3f",
     0x0000001b => "\x27",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x40",
     0x00000021 => "\x4f",
     0x00000022 => "\x7f",
     0x00000023 => "\x7b",
     0x00000024 => "\x5b",
     0x00000025 => "\x6c",
     0x00000026 => "\x50",
     0x00000027 => "\x7d",
     0x00000028 => "\x4d",
     0x00000029 => "\x5d",
     0x0000002a => "\x5c",
     0x0000002b => "\x4e",
     0x0000002c => "\x6b",
     0x0000002d => "\x60",
     0x0000002e => "\x4b",
     0x0000002f => "\x61",
     0x00000030 => "\xf0",
     0x00000031 => "\xf1",
     0x00000032 => "\xf2",
     0x00000033 => "\xf3",
     0x00000034 => "\xf4",
     0x00000035 => "\xf5",
     0x00000036 => "\xf6",
     0x00000037 => "\xf7",
     0x00000038 => "\xf8",
     0x00000039 => "\xf9",
     0x0000003a => "\x7a",
     0x0000003b => "\x5e",
     0x0000003c => "\x4c",
     0x0000003d => "\x7e",
     0x0000003e => "\x6e",
     0x0000003f => "\x6f",
     0x00000040 => "\x7c",
     0x00000041 => "\xc1",
     0x00000042 => "\xc2",
     0x00000043 => "\xc3",
     0x00000044 => "\xc4",
     0x00000045 => "\xc5",
     0x00000046 => "\xc6",
     0x00000047 => "\xc7",
     0x00000048 => "\xc8",
     0x00000049 => "\xc9",
     0x0000004a => "\xd1",
     0x0000004b => "\xd2",
     0x0000004c => "\xd3",
     0x0000004d => "\xd4",
     0x0000004e => "\xd5",
     0x0000004f => "\xd6",
     0x00000050 => "\xd7",
     0x00000051 => "\xd8",
     0x00000052 => "\xd9",
     0x00000053 => "\xe2",
     0x00000054 => "\xe3",
     0x00000055 => "\xe4",
     0x00000056 => "\xe5",
     0x00000057 => "\xe6",
     0x00000058 => "\xe7",
     0x00000059 => "\xe8",
     0x0000005a => "\xe9",
     0x0000005b => "\x4a",
     0x0000005c => "\xe0",
     0x0000005d => "\x5a",
     0x0000005e => "\x5f",
     0x0000005f => "\x6d",
     0x00000060 => "\x6a",
     0x00000061 => "\x81",
     0x00000062 => "\x82",
     0x00000063 => "\x83",
     0x00000064 => "\x84",
     0x00000065 => "\x85",
     0x00000066 => "\x86",
     0x00000067 => "\x87",
     0x00000068 => "\x88",
     0x00000069 => "\x89",
     0x0000006a => "\x91",
     0x0000006b => "\x92",
     0x0000006c => "\x93",
     0x0000006d => "\x94",
     0x0000006e => "\x95",
     0x0000006f => "\x96",
     0x00000070 => "\x97",
     0x00000071 => "\x98",
     0x00000072 => "\x99",
     0x00000073 => "\xa2",
     0x00000074 => "\xa3",
     0x00000075 => "\xa4",
     0x00000076 => "\xa5",
     0x00000077 => "\xa6",
     0x00000078 => "\xa7",
     0x00000079 => "\xa8",
     0x0000007a => "\xa9",
     0x0000007b => "\xc0",
     0x0000007c => "\xbb",
     0x0000007d => "\xd0",
     0x0000007e => "\xa1",
     0x0000007f => "\x07",
     0x00000080 => "\x20",
     0x00000081 => "\x21",
     0x00000082 => "\x22",
     0x00000083 => "\x23",
     0x00000084 => "\x24",
     0x00000085 => "\x15",
     0x00000086 => "\x06",
     0x00000087 => "\x17",
     0x00000088 => "\x28",
     0x00000089 => "\x29",
     0x0000008a => "\x2a",
     0x0000008b => "\x2b",
     0x0000008c => "\x2c",
     0x0000008d => "\x09",
     0x0000008e => "\x0a",
     0x0000008f => "\x1b",
     0x00000090 => "\x30",
     0x00000091 => "\x31",
     0x00000092 => "\x1a",
     0x00000093 => "\x33",
     0x00000094 => "\x34",
     0x00000095 => "\x35",
     0x00000096 => "\x36",
     0x00000097 => "\x08",
     0x00000098 => "\x38",
     0x00000099 => "\x39",
     0x0000009a => "\x3a",
     0x0000009b => "\x3b",
     0x0000009c => "\x04",
     0x0000009d => "\x14",
     0x0000009e => "\x3e",
     0x0000009f => "\xff",
     0x000000a0 => "\x41",
     0x000000ad => "\xca",
     0x0000060c => "\x42",
     0x0000061b => "\x43",
     0x0000061f => "\x44",
     0x00000621 => "\xea",
     0x00000623 => "\x45",
     0x00000627 => "\x46",
     0x00000628 => "\x49",
     0x00000629 => "\x54",
     0x0000062a => "\x55",
     0x0000062b => "\x59",
     0x0000062c => "\x63",
     0x0000062d => "\x67",
     0x0000062e => "\x69",
     0x0000062f => "\x8a",
     0x00000630 => "\x8c",
     0x00000631 => "\x8d",
     0x00000632 => "\x8f",
     0x00000633 => "\x9a",
     0x00000634 => "\x9c",
     0x00000635 => "\x9e",
     0x00000636 => "\xa0",
     0x00000637 => "\xab",
     0x00000638 => "\xac",
     0x00000639 => "\xad",
     0x0000063a => "\xb1",
     0x00000641 => "\xb5",
     0x00000642 => "\xb7",
     0x00000643 => "\xb9",
     0x00000644 => "\xbe",
     0x00000645 => "\xcc",
     0x00000646 => "\xcf",
     0x00000648 => "\xdc",
     0x00000651 => "\xfd",
     0x00000660 => "\x70",
     0x00000661 => "\x71",
     0x00000662 => "\x72",
     0x00000663 => "\x73",
     0x00000664 => "\x74",
     0x00000665 => "\x75",
     0x00000666 => "\x76",
     0x00000667 => "\x77",
     0x00000668 => "\x78",
     0x00000669 => "\x79",
     0x0000067e => "\x52",
     0x0000fe7d => "\xfe",
     0x0000fe8e => "\x47",
     0x0000fe91 => "\x51",
     0x0000fe97 => "\x56",
     0x0000fe9b => "\x62",
     0x0000fe9f => "\x64",
     0x0000fea3 => "\x68",
     0x0000fea7 => "\x80",
     0x0000feb3 => "\x9b",
     0x0000feb7 => "\x9d",
     0x0000febb => "\x9f",
     0x0000febf => "\xaa",
     0x0000feca => "\xae",
     0x0000fecb => "\xaf",
     0x0000fecc => "\xb0",
     0x0000fece => "\xb2",
     0x0000fecf => "\xb3",
     0x0000fed0 => "\xb4",
     0x0000fed3 => "\xb6",
     0x0000fed7 => "\xb8",
     0x0000fedb => "\xba",
     0x0000fede => "\xbf",
     0x0000fee3 => "\xcd",
     0x0000fee7 => "\xda",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x6f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::IBM918 - Conversion routines for IBM918
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for IBM918.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
   source: IBM NLS RM Vol2 SE09-8002-01, March 1990
  alias CP918
  alias EBCDIC-CP-AR2
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  0000009C | STRING TERMINATOR (ST)
     05 |  00000009 | CHARACTER TABULATION (HT)
     06 |  00000086 | START OF SELECTED AREA (SSA)
     07 |  0000007F | DELETE (DEL)
     08 |  00000097 | END OF GUARDED AREA (EPA)
     09 |  0000008D | REVERSE LINE FEED (RI)
     0A |  0000008E | SINGLE-SHIFT TWO (SS2)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  0000009D | OPERATING SYSTEM COMMAND (OSC)
     15 |  00000085 | NEXT LINE (NEL)
     16 |  00000008 | BACKSPACE (BS)
     17 |  00000087 | END OF SELECTED AREA (ESA)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  00000092 | PRIVATE USE TWO (PU2)
     1B |  0000008F | SINGLE-SHIFT THREE (SS3)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000080 | PADDING CHARACTER (PAD)
     21 |  00000081 | HIGH OCTET PRESET (HOP)
     22 |  00000082 | BREAK PERMITTED HERE (BPH)
     23 |  00000083 | NO BREAK HERE (NBH)
     24 |  00000084 | INDEX (IND)
     25 |  0000000A | LINE FEED (LF)
     26 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     27 |  0000001B | ESCAPE (ESC)
     28 |  00000088 | CHARACTER TABULATION SET (HTS)
     29 |  00000089 | CHARACTER TABULATION WITH JUSTIFICATION (HTJ)
     2A |  0000008A | LINE TABULATION SET (VTS)
     2B |  0000008B | PARTIAL LINE FORWARD (PLD)
     2C |  0000008C | PARTIAL LINE BACKWARD (PLU)
     2D |  00000005 | ENQUIRY (ENQ)
     2E |  00000006 | ACKNOWLEDGE (ACK)
     2F |  00000007 | BELL (BEL)
     30 |  00000090 | DEVICE CONTROL STRING (DCS)
     31 |  00000091 | PRIVATE USE ONE (PU1)
     32 |  00000016 | SYNCHRONOUS IDLE (SYN)
     33 |  00000093 | SET TRANSMIT STATE (STS)
     34 |  00000094 | CANCEL CHARACTER (CCH)
     35 |  00000095 | MESSAGE WAITING (MW)
     36 |  00000096 | START OF GUARDED AREA (SPA)
     37 |  00000004 | END OF TRANSMISSION (EOT)
     38 |  00000098 | START OF STRING (SOS)
     39 |  00000099 | SINGLE GRAPHIC CHARACTER INTRODUCER (SGCI)
     3A |  0000009A | SINGLE CHARACTER INTRODUCER (SCI)
     3B |  0000009B | CONTROL SEQUENCE INTRODUCER (CSI)
     3C |  00000014 | DEVICE CONTROL FOUR (DC4)
     3D |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     3E |  0000009E | PRIVACY MESSAGE (PM)
     3F |  0000001A | SUBSTITUTE (SUB)
     40 |  00000020 | SPACE
     41 |  000000A0 | NO-BREAK SPACE
     42 |  0000060C | ARABIC COMMA
     43 |  0000061B | ARABIC SEMICOLON
     44 |  0000061F | ARABIC QUESTION MARK
     45 |  00000623 | ARABIC LETTER ALEF WITH HAMZA ABOVE
     46 |  00000627 | ARABIC LETTER ALEF
     47 |  0000FE8E | ARABIC LETTER ALEF FINAL FORM
     49 |  00000628 | ARABIC LETTER BEH
     4A |  0000005B | LEFT SQUARE BRACKET
     4B |  0000002E | FULL STOP
     4C |  0000003C | LESS-THAN SIGN
     4D |  00000028 | LEFT PARENTHESIS
     4E |  0000002B | PLUS SIGN
     4F |  00000021 | EXCLAMATION MARK
     50 |  00000026 | AMPERSAND
     51 |  0000FE91 | ARABIC LETTER BEH INITIAL FORM
     52 |  0000067E | ARABIC LETTER PEH
     54 |  00000629 | ARABIC LETTER TEH MARBUTA
     55 |  0000062A | ARABIC LETTER TEH
     56 |  0000FE97 | ARABIC LETTER TEH INITIAL FORM
     59 |  0000062B | ARABIC LETTER THEH
     5A |  0000005D | RIGHT SQUARE BRACKET
     5B |  00000024 | DOLLAR SIGN
     5C |  0000002A | ASTERISK
     5D |  00000029 | RIGHT PARENTHESIS
     5E |  0000003B | SEMICOLON
     5F |  0000005E | CIRCUMFLEX ACCENT
     60 |  0000002D | HYPHEN-MINUS
     61 |  0000002F | SOLIDUS
     62 |  0000FE9B | ARABIC LETTER THEH INITIAL FORM
     63 |  0000062C | ARABIC LETTER JEEM
     64 |  0000FE9F | ARABIC LETTER JEEM INITIAL FORM
     67 |  0000062D | ARABIC LETTER HAH
     68 |  0000FEA3 | ARABIC LETTER HAH INITIAL FORM
     69 |  0000062E | ARABIC LETTER KHAH
     6A |  00000060 | GRAVE ACCENT
     6B |  0000002C | COMMA
     6C |  00000025 | PERCENT SIGN
     6D |  0000005F | LOW LINE
     6E |  0000003E | GREATER-THAN SIGN
     6F |  0000003F | QUESTION MARK
     70 |  00000660 | ARABIC-INDIC DIGIT ZERO
     71 |  00000661 | ARABIC-INDIC DIGIT ONE
     72 |  00000662 | ARABIC-INDIC DIGIT TWO
     73 |  00000663 | ARABIC-INDIC DIGIT THREE
     74 |  00000664 | ARABIC-INDIC DIGIT FOUR
     75 |  00000665 | ARABIC-INDIC DIGIT FIVE
     76 |  00000666 | ARABIC-INDIC DIGIT SIX
     77 |  00000667 | ARABIC-INDIC DIGIT SEVEN
     78 |  00000668 | ARABIC-INDIC DIGIT EIGHT
     79 |  00000669 | ARABIC-INDIC DIGIT NINE
     7A |  0000003A | COLON
     7B |  00000023 | NUMBER SIGN
     7C |  00000040 | COMMERCIAL AT
     7D |  00000027 | APOSTROPHE
     7E |  0000003D | EQUALS SIGN
     7F |  00000022 | QUOTATION MARK
     80 |  0000FEA7 | ARABIC LETTER KHAH INITIAL FORM
     81 |  00000061 | LATIN SMALL LETTER A
     82 |  00000062 | LATIN SMALL LETTER B
     83 |  00000063 | LATIN SMALL LETTER C
     84 |  00000064 | LATIN SMALL LETTER D
     85 |  00000065 | LATIN SMALL LETTER E
     86 |  00000066 | LATIN SMALL LETTER F
     87 |  00000067 | LATIN SMALL LETTER G
     88 |  00000068 | LATIN SMALL LETTER H
     89 |  00000069 | LATIN SMALL LETTER I
     8A |  0000062F | ARABIC LETTER DAL
     8C |  00000630 | ARABIC LETTER THAL
     8D |  00000631 | ARABIC LETTER REH
     8F |  00000632 | ARABIC LETTER ZAIN
     91 |  0000006A | LATIN SMALL LETTER J
     92 |  0000006B | LATIN SMALL LETTER K
     93 |  0000006C | LATIN SMALL LETTER L
     94 |  0000006D | LATIN SMALL LETTER M
     95 |  0000006E | LATIN SMALL LETTER N
     96 |  0000006F | LATIN SMALL LETTER O
     97 |  00000070 | LATIN SMALL LETTER P
     98 |  00000071 | LATIN SMALL LETTER Q
     99 |  00000072 | LATIN SMALL LETTER R
     9A |  00000633 | ARABIC LETTER SEEN
     9B |  0000FEB3 | ARABIC LETTER SEEN INITIAL FORM
     9C |  00000634 | ARABIC LETTER SHEEN
     9D |  0000FEB7 | ARABIC LETTER SHEEN INITIAL FORM
     9E |  00000635 | ARABIC LETTER SAD
     9F |  0000FEBB | ARABIC LETTER SAD INITIAL FORM
     A0 |  00000636 | ARABIC LETTER DAD
     A1 |  0000007E | TILDE
     A2 |  00000073 | LATIN SMALL LETTER S
     A3 |  00000074 | LATIN SMALL LETTER T
     A4 |  00000075 | LATIN SMALL LETTER U
     A5 |  00000076 | LATIN SMALL LETTER V
     A6 |  00000077 | LATIN SMALL LETTER W
     A7 |  00000078 | LATIN SMALL LETTER X
     A8 |  00000079 | LATIN SMALL LETTER Y
     A9 |  0000007A | LATIN SMALL LETTER Z
     AA |  0000FEBF | ARABIC LETTER DAD INITIAL FORM
     AB |  00000637 | ARABIC LETTER TAH
     AC |  00000638 | ARABIC LETTER ZAH
     AD |  00000639 | ARABIC LETTER AIN
     AE |  0000FECA | ARABIC LETTER AIN FINAL FORM
     AF |  0000FECB | ARABIC LETTER AIN INITIAL FORM
     B0 |  0000FECC | ARABIC LETTER AIN MEDIAL FORM
     B1 |  0000063A | ARABIC LETTER GHAIN
     B2 |  0000FECE | ARABIC LETTER GHAIN FINAL FORM
     B3 |  0000FECF | ARABIC LETTER GHAIN INITIAL FORM
     B4 |  0000FED0 | ARABIC LETTER GHAIN MEDIAL FORM
     B5 |  00000641 | ARABIC LETTER FEH
     B6 |  0000FED3 | ARABIC LETTER FEH INITIAL FORM
     B7 |  00000642 | ARABIC LETTER QAF
     B8 |  0000FED7 | ARABIC LETTER QAF INITIAL FORM
     B9 |  00000643 | ARABIC LETTER KAF
     BA |  0000FEDB | ARABIC LETTER KAF INITIAL FORM
     BB |  0000007C | VERTICAL LINE
     BE |  00000644 | ARABIC LETTER LAM
     BF |  0000FEDE | ARABIC LETTER LAM FINAL FORM
     C0 |  0000007B | LEFT CURLY BRACKET
     C1 |  00000041 | LATIN CAPITAL LETTER A
     C2 |  00000042 | LATIN CAPITAL LETTER B
     C3 |  00000043 | LATIN CAPITAL LETTER C
     C4 |  00000044 | LATIN CAPITAL LETTER D
     C5 |  00000045 | LATIN CAPITAL LETTER E
     C6 |  00000046 | LATIN CAPITAL LETTER F
     C7 |  00000047 | LATIN CAPITAL LETTER G
     C8 |  00000048 | LATIN CAPITAL LETTER H
     C9 |  00000049 | LATIN CAPITAL LETTER I
     CA |  000000AD | SOFT HYPHEN
     CC |  00000645 | ARABIC LETTER MEEM
     CD |  0000FEE3 | ARABIC LETTER MEEM INITIAL FORM
     CF |  00000646 | ARABIC LETTER NOON
     D0 |  0000007D | RIGHT CURLY BRACKET
     D1 |  0000004A | LATIN CAPITAL LETTER J
     D2 |  0000004B | LATIN CAPITAL LETTER K
     D3 |  0000004C | LATIN CAPITAL LETTER L
     D4 |  0000004D | LATIN CAPITAL LETTER M
     D5 |  0000004E | LATIN CAPITAL LETTER N
     D6 |  0000004F | LATIN CAPITAL LETTER O
     D7 |  00000050 | LATIN CAPITAL LETTER P
     D8 |  00000051 | LATIN CAPITAL LETTER Q
     D9 |  00000052 | LATIN CAPITAL LETTER R
     DA |  0000FEE7 | ARABIC LETTER NOON INITIAL FORM
     DC |  00000648 | ARABIC LETTER WAW
     E0 |  0000005C | REVERSE SOLIDUS
     E2 |  00000053 | LATIN CAPITAL LETTER S
     E3 |  00000054 | LATIN CAPITAL LETTER T
     E4 |  00000055 | LATIN CAPITAL LETTER U
     E5 |  00000056 | LATIN CAPITAL LETTER V
     E6 |  00000057 | LATIN CAPITAL LETTER W
     E7 |  00000058 | LATIN CAPITAL LETTER X
     E8 |  00000059 | LATIN CAPITAL LETTER Y
     E9 |  0000005A | LATIN CAPITAL LETTER Z
     EA |  00000621 | ARABIC LETTER HAMZA
     F0 |  00000030 | DIGIT ZERO
     F1 |  00000031 | DIGIT ONE
     F2 |  00000032 | DIGIT TWO
     F3 |  00000033 | DIGIT THREE
     F4 |  00000034 | DIGIT FOUR
     F5 |  00000035 | DIGIT FIVE
     F6 |  00000036 | DIGIT SIX
     F7 |  00000037 | DIGIT SEVEN
     F8 |  00000038 | DIGIT EIGHT
     F9 |  00000039 | DIGIT NINE
     FD |  00000651 | ARABIC SHADDA
     FE |  0000FE7D | ARABIC SHADDA MEDIAL FORM
     FF |  0000009F | APPLICATION PROGRAM COMMAND (APC)
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/IEC_P27_1.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for IEC_P27-1.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::IEC_P27_1;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x0004,
     0x0005,
     0x0006,
     0x0007,
     0x0008,
     0x0009,
     0x000a,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x0014,
     0x0015,
     0x0016,
     0x0017,
     0x0018,
     0x0019,
     0x001a,
     0x001b,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0020,
     0x0021,
     0x0022,
     0x0023,
     0x0024,
     0x0025,
     0x0026,
     0x0027,
     0x0028,
     0x0029,
     0x002a,
     0x002b,
     0x002c,
     0x002d,
     0x002e,
     0x002f,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x003a,
     0x003b,
     0x003c,
     0x003d,
     0x003e,
     0x003f,
     0x0040,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x005b,
     0x005c,
     0x005d,
     0x005e,
     0x005f,
     0x0060,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x007b,
     0x007c,
     0x007d,
     0x007e,
     0x007f,
     0x0080,
     0x0081,
     0x0082,
     0x0083,
     0x0084,
     0x0085,
     0x0086,
     0x0087,
     0x0088,
     0x0089,
     0x008a,
     0x008b,
     0x008c,
     0x008d,
     0x008e,
     0x008f,
     0x0090,
     0x0091,
     0x0092,
     0x0093,
     0x0094,
     0x0095,
     0x0096,
     0x0097,
     0x0098,
     0x0099,
     0x009a,
     0x009b,
     0x009c,
     0x009d,
     0x009e,
     0x009f,
     0x02c7,
     0x2261,
     0x2227,
     0x2228,
     0x2229,
     0x222a,
     0x2282,
     0x2283,
     0x21d0,
     0x21d2,
     0x2234,
     0x2235,
     0x2208,
     0x220b,
     0x2286,
     0x2287,
     0x222b,
     0x222e,
     0x221e,
     0x2207,
     0x2202,
     0x223c,
     0x2248,
     0x2243,
     0x2245,
     0x2264,
     0x2260,
     0x2265,
     0x2194,
     0x00ac,
     0x2200,
     0x2203,
     0x05d0,
     0x25a1,
     0x2225,
     0x0393,
     0x0394,
     0x22a5,
     0x2220,
     0x221f,
     0x0398,
     0x2329,
     0x232a,
     0x039b,
     0x2032,
     0x2033,
     0x039e,
     0x2213,
     0x03a0,
     0x00b2,
     0x03a3,
     0x00d7,
     0x00b3,
     0x03a5,
     0x03a6,
     0x00b7,
     0x03a8,
     0x03a9,
     0x2205,
     0x21c0,
     0x221a,
     0x0192,
     0x221d,
     0x00b1,
     0x00b0,
     0x03b1,
     0x03b2,
     0x03b3,
     0x03b4,
     0x03b5,
     0x03b6,
     0x03b7,
     0x03b8,
     0x03b9,
     0x03ba,
     0x03bb,
     0x03bc,
     0x03bd,
     0x03be,
     0x2030,
     0x03c0,
     0x03c1,
     0x03c3,
     0x00f7,
     0x03c4,
     0x03c5,
     0x03c6,
     0x03c7,
     0x03c8,
     0x03c9,
     0x2020,
     0x2190,
     0x2191,
     0x2192,
     0x2193,
     0x203e,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\x04",
     "\x05",
     "\x06",
     "\x07",
     "\x08",
     "\x09",
     "\x0a",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\x14",
     "\x15",
     "\x16",
     "\x17",
     "\x18",
     "\x19",
     "\x1a",
     "\x1b",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\x20",
     "\x21",
     "\x22",
     "\x23",
     "\x24",
     "\x25",
     "\x26",
     "\x27",
     "\x28",
     "\x29",
     "\x2a",
     "\x2b",
     "\x2c",
     "\x2d",
     "\x2e",
     "\x2f",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\x3a",
     "\x3b",
     "\x3c",
     "\x3d",
     "\x3e",
     "\x3f",
     "\x40",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\x5b",
     "\x5c",
     "\x5d",
     "\x5e",
     "\x5f",
     "\x60",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\x7b",
     "\x7c",
     "\x7d",
     "\x7e",
     "\x7f",
     "\xc2\x80",
     "\xc2\x81",
     "\xc2\x82",
     "\xc2\x83",
     "\xc2\x84",
     "\xc2\x85",
     "\xc2\x86",
     "\xc2\x87",
     "\xc2\x88",
     "\xc2\x89",
     "\xc2\x8a",
     "\xc2\x8b",
     "\xc2\x8c",
     "\xc2\x8d",
     "\xc2\x8e",
     "\xc2\x8f",
     "\xc2\x90",
     "\xc2\x91",
     "\xc2\x92",
     "\xc2\x93",
     "\xc2\x94",
     "\xc2\x95",
     "\xc2\x96",
     "\xc2\x97",
     "\xc2\x98",
     "\xc2\x99",
     "\xc2\x9a",
     "\xc2\x9b",
     "\xc2\x9c",
     "\xc2\x9d",
     "\xc2\x9e",
     "\xc2\x9f",
     "\xcb\x87",
     "\xe2\x89\xa1",
     "\xe2\x88\xa7",
     "\xe2\x88\xa8",
     "\xe2\x88\xa9",
     "\xe2\x88\xaa",
     "\xe2\x8a\x82",
     "\xe2\x8a\x83",
     "\xe2\x87\x90",
     "\xe2\x87\x92",
     "\xe2\x88\xb4",
     "\xe2\x88\xb5",
     "\xe2\x88\x88",
     "\xe2\x88\x8b",
     "\xe2\x8a\x86",
     "\xe2\x8a\x87",
     "\xe2\x88\xab",
     "\xe2\x88\xae",
     "\xe2\x88\x9e",
     "\xe2\x88\x87",
     "\xe2\x88\x82",
     "\xe2\x88\xbc",
     "\xe2\x89\x88",
     "\xe2\x89\x83",
     "\xe2\x89\x85",
     "\xe2\x89\xa4",
     "\xe2\x89\xa0",
     "\xe2\x89\xa5",
     "\xe2\x86\x94",
     "\xc2\xac",
     "\xe2\x88\x80",
     "\xe2\x88\x83",
     "\xd7\x90",
     "\xe2\x96\xa1",
     "\xe2\x88\xa5",
     "\xce\x93",
     "\xce\x94",
     "\xe2\x8a\xa5",
     "\xe2\x88\xa0",
     "\xe2\x88\x9f",
     "\xce\x98",
     "\xe2\x8c\xa9",
     "\xe2\x8c\xaa",
     "\xce\x9b",
     "\xe2\x80\xb2",
     "\xe2\x80\xb3",
     "\xce\x9e",
     "\xe2\x88\x93",
     "\xce\xa0",
     "\xc2\xb2",
     "\xce\xa3",
     "\xc3\x97",
     "\xc2\xb3",
     "\xce\xa5",
     "\xce\xa6",
     "\xc2\xb7",
     "\xce\xa8",
     "\xce\xa9",
     "\xe2\x88\x85",
     "\xe2\x87\x80",
     "\xe2\x88\x9a",
     "\xc6\x92",
     "\xe2\x88\x9d",
     "\xc2\xb1",
     "\xc2\xb0",
     "\xce\xb1",
     "\xce\xb2",
     "\xce\xb3",
     "\xce\xb4",
     "\xce\xb5",
     "\xce\xb6",
     "\xce\xb7",
     "\xce\xb8",
     "\xce\xb9",
     "\xce\xba",
     "\xce\xbb",
     "\xce\xbc",
     "\xce\xbd",
     "\xce\xbe",
     "\xe2\x80\xb0",
     "\xcf\x80",
     "\xcf\x81",
     "\xcf\x83",
     "\xc3\xb7",
     "\xcf\x84",
     "\xcf\x85",
     "\xcf\x86",
     "\xcf\x87",
     "\xcf\x88",
     "\xcf\x89",
     "\xe2\x80\xa0",
     "\xe2\x86\x90",
     "\xe2\x86\x91",
     "\xe2\x86\x92",
     "\xe2\x86\x93",
     "\xe2\x80\xbe",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x04",
     0x00000005 => "\x05",
     0x00000006 => "\x06",
     0x00000007 => "\x07",
     0x00000008 => "\x08",
     0x00000009 => "\x09",
     0x0000000a => "\x0a",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x14",
     0x00000015 => "\x15",
     0x00000016 => "\x16",
     0x00000017 => "\x17",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x1a",
     0x0000001b => "\x1b",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x20",
     0x00000021 => "\x21",
     0x00000022 => "\x22",
     0x00000023 => "\x23",
     0x00000024 => "\x24",
     0x00000025 => "\x25",
     0x00000026 => "\x26",
     0x00000027 => "\x27",
     0x00000028 => "\x28",
     0x00000029 => "\x29",
     0x0000002a => "\x2a",
     0x0000002b => "\x2b",
     0x0000002c => "\x2c",
     0x0000002d => "\x2d",
     0x0000002e => "\x2e",
     0x0000002f => "\x2f",
     0x00000030 => "\x30",
     0x00000031 => "\x31",
     0x00000032 => "\x32",
     0x00000033 => "\x33",
     0x00000034 => "\x34",
     0x00000035 => "\x35",
     0x00000036 => "\x36",
     0x00000037 => "\x37",
     0x00000038 => "\x38",
     0x00000039 => "\x39",
     0x0000003a => "\x3a",
     0x0000003b => "\x3b",
     0x0000003c => "\x3c",
     0x0000003d => "\x3d",
     0x0000003e => "\x3e",
     0x0000003f => "\x3f",
     0x00000040 => "\x40",
     0x00000041 => "\x41",
     0x00000042 => "\x42",
     0x00000043 => "\x43",
     0x00000044 => "\x44",
     0x00000045 => "\x45",
     0x00000046 => "\x46",
     0x00000047 => "\x47",
     0x00000048 => "\x48",
     0x00000049 => "\x49",
     0x0000004a => "\x4a",
     0x0000004b => "\x4b",
     0x0000004c => "\x4c",
     0x0000004d => "\x4d",
     0x0000004e => "\x4e",
     0x0000004f => "\x4f",
     0x00000050 => "\x50",
     0x00000051 => "\x51",
     0x00000052 => "\x52",
     0x00000053 => "\x53",
     0x00000054 => "\x54",
     0x00000055 => "\x55",
     0x00000056 => "\x56",
     0x00000057 => "\x57",
     0x00000058 => "\x58",
     0x00000059 => "\x59",
     0x0000005a => "\x5a",
     0x0000005b => "\x5b",
     0x0000005c => "\x5c",
     0x0000005d => "\x5d",
     0x0000005e => "\x5e",
     0x0000005f => "\x5f",
     0x00000060 => "\x60",
     0x00000061 => "\x61",
     0x00000062 => "\x62",
     0x00000063 => "\x63",
     0x00000064 => "\x64",
     0x00000065 => "\x65",
     0x00000066 => "\x66",
     0x00000067 => "\x67",
     0x00000068 => "\x68",
     0x00000069 => "\x69",
     0x0000006a => "\x6a",
     0x0000006b => "\x6b",
     0x0000006c => "\x6c",
     0x0000006d => "\x6d",
     0x0000006e => "\x6e",
     0x0000006f => "\x6f",
     0x00000070 => "\x70",
     0x00000071 => "\x71",
     0x00000072 => "\x72",
     0x00000073 => "\x73",
     0x00000074 => "\x74",
     0x00000075 => "\x75",
     0x00000076 => "\x76",
     0x00000077 => "\x77",
     0x00000078 => "\x78",
     0x00000079 => "\x79",
     0x0000007a => "\x7a",
     0x0000007b => "\x7b",
     0x0000007c => "\x7c",
     0x0000007d => "\x7d",
     0x0000007e => "\x7e",
     0x0000007f => "\x7f",
     0x00000080 => "\x80",
     0x00000081 => "\x81",
     0x00000082 => "\x82",
     0x00000083 => "\x83",
     0x00000084 => "\x84",
     0x00000085 => "\x85",
     0x00000086 => "\x86",
     0x00000087 => "\x87",
     0x00000088 => "\x88",
     0x00000089 => "\x89",
     0x0000008a => "\x8a",
     0x0000008b => "\x8b",
     0x0000008c => "\x8c",
     0x0000008d => "\x8d",
     0x0000008e => "\x8e",
     0x0000008f => "\x8f",
     0x00000090 => "\x90",
     0x00000091 => "\x91",
     0x00000092 => "\x92",
     0x00000093 => "\x93",
     0x00000094 => "\x94",
     0x00000095 => "\x95",
     0x00000096 => "\x96",
     0x00000097 => "\x97",
     0x00000098 => "\x98",
     0x00000099 => "\x99",
     0x0000009a => "\x9a",
     0x0000009b => "\x9b",
     0x0000009c => "\x9c",
     0x0000009d => "\x9d",
     0x0000009e => "\x9e",
     0x0000009f => "\x9f",
     0x000000ac => "\xbd",
     0x000000b0 => "\xe0",
     0x000000b1 => "\xdf",
     0x000000b2 => "\xd1",
     0x000000b3 => "\xd4",
     0x000000b7 => "\xd7",
     0x000000d7 => "\xd3",
     0x000000f7 => "\xf3",
     0x00000192 => "\xdd",
     0x000002c7 => "\xa0",
     0x00000393 => "\xc3",
     0x00000394 => "\xc4",
     0x00000398 => "\xc8",
     0x0000039b => "\xcb",
     0x0000039e => "\xce",
     0x000003a0 => "\xd0",
     0x000003a3 => "\xd2",
     0x000003a5 => "\xd5",
     0x000003a6 => "\xd6",
     0x000003a8 => "\xd8",
     0x000003a9 => "\xd9",
     0x000003b1 => "\xe1",
     0x000003b2 => "\xe2",
     0x000003b3 => "\xe3",
     0x000003b4 => "\xe4",
     0x000003b5 => "\xe5",
     0x000003b6 => "\xe6",
     0x000003b7 => "\xe7",
     0x000003b8 => "\xe8",
     0x000003b9 => "\xe9",
     0x000003ba => "\xea",
     0x000003bb => "\xeb",
     0x000003bc => "\xec",
     0x000003bd => "\xed",
     0x000003be => "\xee",
     0x000003c0 => "\xf0",
     0x000003c1 => "\xf1",
     0x000003c3 => "\xf2",
     0x000003c4 => "\xf4",
     0x000003c5 => "\xf5",
     0x000003c6 => "\xf6",
     0x000003c7 => "\xf7",
     0x000003c8 => "\xf8",
     0x000003c9 => "\xf9",
     0x000005d0 => "\xc0",
     0x00002020 => "\xfa",
     0x00002030 => "\xef",
     0x00002032 => "\xcc",
     0x00002033 => "\xcd",
     0x0000203e => "\xff",
     0x00002190 => "\xfb",
     0x00002191 => "\xfc",
     0x00002192 => "\xfd",
     0x00002193 => "\xfe",
     0x00002194 => "\xbc",
     0x000021c0 => "\xdb",
     0x000021d0 => "\xa8",
     0x000021d2 => "\xa9",
     0x00002200 => "\xbe",
     0x00002202 => "\xb4",
     0x00002203 => "\xbf",
     0x00002205 => "\xda",
     0x00002207 => "\xb3",
     0x00002208 => "\xac",
     0x0000220b => "\xad",
     0x00002213 => "\xcf",
     0x0000221a => "\xdc",
     0x0000221d => "\xde",
     0x0000221e => "\xb2",
     0x0000221f => "\xc7",
     0x00002220 => "\xc6",
     0x00002225 => "\xc2",
     0x00002227 => "\xa2",
     0x00002228 => "\xa3",
     0x00002229 => "\xa4",
     0x0000222a => "\xa5",
     0x0000222b => "\xb0",
     0x0000222e => "\xb1",
     0x00002234 => "\xaa",
     0x00002235 => "\xab",
     0x0000223c => "\xb5",
     0x00002243 => "\xb7",
     0x00002245 => "\xb8",
     0x00002248 => "\xb6",
     0x00002260 => "\xba",
     0x00002261 => "\xa1",
     0x00002264 => "\xb9",
     0x00002265 => "\xbb",
     0x00002282 => "\xa6",
     0x00002283 => "\xa7",
     0x00002286 => "\xae",
     0x00002287 => "\xaf",
     0x000022a5 => "\xc5",
     0x00002329 => "\xc9",
     0x0000232a => "\xca",
     0x000025a1 => "\xc1",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::IEC_P27_1 - Conversion routines for IEC_P27_1
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for IEC_P27-1.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
   source: ECMA registry
  alias ISO-IR-143
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  00000004 | END OF TRANSMISSION (EOT)
     05 |  00000005 | ENQUIRY (ENQ)
     06 |  00000006 | ACKNOWLEDGE (ACK)
     07 |  00000007 | BELL (BEL)
     08 |  00000008 | BACKSPACE (BS)
     09 |  00000009 | CHARACTER TABULATION (HT)
     0A |  0000000A | LINE FEED (LF)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  00000014 | DEVICE CONTROL FOUR (DC4)
     15 |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     16 |  00000016 | SYNCHRONOUS IDLE (SYN)
     17 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  0000001A | SUBSTITUTE (SUB)
     1B |  0000001B | ESCAPE (ESC)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000020 | SPACE
     21 |  00000021 | EXCLAMATION MARK
     22 |  00000022 | QUOTATION MARK
     23 |  00000023 | NUMBER SIGN
     24 |  00000024 | DOLLAR SIGN
     25 |  00000025 | PERCENT SIGN
     26 |  00000026 | AMPERSAND
     27 |  00000027 | APOSTROPHE
     28 |  00000028 | LEFT PARENTHESIS
     29 |  00000029 | RIGHT PARENTHESIS
     2A |  0000002A | ASTERISK
     2B |  0000002B | PLUS SIGN
     2C |  0000002C | COMMA
     2D |  0000002D | HYPHEN-MINUS
     2E |  0000002E | FULL STOP
     2F |  0000002F | SOLIDUS
     30 |  00000030 | DIGIT ZERO
     31 |  00000031 | DIGIT ONE
     32 |  00000032 | DIGIT TWO
     33 |  00000033 | DIGIT THREE
     34 |  00000034 | DIGIT FOUR
     35 |  00000035 | DIGIT FIVE
     36 |  00000036 | DIGIT SIX
     37 |  00000037 | DIGIT SEVEN
     38 |  00000038 | DIGIT EIGHT
     39 |  00000039 | DIGIT NINE
     3A |  0000003A | COLON
     3B |  0000003B | SEMICOLON
     3C |  0000003C | LESS-THAN SIGN
     3D |  0000003D | EQUALS SIGN
     3E |  0000003E | GREATER-THAN SIGN
     3F |  0000003F | QUESTION MARK
     40 |  00000040 | COMMERCIAL AT
     41 |  00000041 | LATIN CAPITAL LETTER A
     42 |  00000042 | LATIN CAPITAL LETTER B
     43 |  00000043 | LATIN CAPITAL LETTER C
     44 |  00000044 | LATIN CAPITAL LETTER D
     45 |  00000045 | LATIN CAPITAL LETTER E
     46 |  00000046 | LATIN CAPITAL LETTER F
     47 |  00000047 | LATIN CAPITAL LETTER G
     48 |  00000048 | LATIN CAPITAL LETTER H
     49 |  00000049 | LATIN CAPITAL LETTER I
     4A |  0000004A | LATIN CAPITAL LETTER J
     4B |  0000004B | LATIN CAPITAL LETTER K
     4C |  0000004C | LATIN CAPITAL LETTER L
     4D |  0000004D | LATIN CAPITAL LETTER M
     4E |  0000004E | LATIN CAPITAL LETTER N
     4F |  0000004F | LATIN CAPITAL LETTER O
     50 |  00000050 | LATIN CAPITAL LETTER P
     51 |  00000051 | LATIN CAPITAL LETTER Q
     52 |  00000052 | LATIN CAPITAL LETTER R
     53 |  00000053 | LATIN CAPITAL LETTER S
     54 |  00000054 | LATIN CAPITAL LETTER T
     55 |  00000055 | LATIN CAPITAL LETTER U
     56 |  00000056 | LATIN CAPITAL LETTER V
     57 |  00000057 | LATIN CAPITAL LETTER W
     58 |  00000058 | LATIN CAPITAL LETTER X
     59 |  00000059 | LATIN CAPITAL LETTER Y
     5A |  0000005A | LATIN CAPITAL LETTER Z
     5B |  0000005B | LEFT SQUARE BRACKET
     5C |  0000005C | REVERSE SOLIDUS
     5D |  0000005D | RIGHT SQUARE BRACKET
     5E |  0000005E | CIRCUMFLEX ACCENT
     5F |  0000005F | LOW LINE
     60 |  00000060 | GRAVE ACCENT
     61 |  00000061 | LATIN SMALL LETTER A
     62 |  00000062 | LATIN SMALL LETTER B
     63 |  00000063 | LATIN SMALL LETTER C
     64 |  00000064 | LATIN SMALL LETTER D
     65 |  00000065 | LATIN SMALL LETTER E
     66 |  00000066 | LATIN SMALL LETTER F
     67 |  00000067 | LATIN SMALL LETTER G
     68 |  00000068 | LATIN SMALL LETTER H
     69 |  00000069 | LATIN SMALL LETTER I
     6A |  0000006A | LATIN SMALL LETTER J
     6B |  0000006B | LATIN SMALL LETTER K
     6C |  0000006C | LATIN SMALL LETTER L
     6D |  0000006D | LATIN SMALL LETTER M
     6E |  0000006E | LATIN SMALL LETTER N
     6F |  0000006F | LATIN SMALL LETTER O
     70 |  00000070 | LATIN SMALL LETTER P
     71 |  00000071 | LATIN SMALL LETTER Q
     72 |  00000072 | LATIN SMALL LETTER R
     73 |  00000073 | LATIN SMALL LETTER S
     74 |  00000074 | LATIN SMALL LETTER T
     75 |  00000075 | LATIN SMALL LETTER U
     76 |  00000076 | LATIN SMALL LETTER V
     77 |  00000077 | LATIN SMALL LETTER W
     78 |  00000078 | LATIN SMALL LETTER X
     79 |  00000079 | LATIN SMALL LETTER Y
     7A |  0000007A | LATIN SMALL LETTER Z
     7B |  0000007B | LEFT CURLY BRACKET
     7C |  0000007C | VERTICAL LINE
     7D |  0000007D | RIGHT CURLY BRACKET
     7E |  0000007E | TILDE
     7F |  0000007F | DELETE (DEL)
     80 |  00000080 | PADDING CHARACTER (PAD)
     81 |  00000081 | HIGH OCTET PRESET (HOP)
     82 |  00000082 | BREAK PERMITTED HERE (BPH)
     83 |  00000083 | NO BREAK HERE (NBH)
     84 |  00000084 | INDEX (IND)
     85 |  00000085 | NEXT LINE (NEL)
     86 |  00000086 | START OF SELECTED AREA (SSA)
     87 |  00000087 | END OF SELECTED AREA (ESA)
     88 |  00000088 | CHARACTER TABULATION SET (HTS)
     89 |  00000089 | CHARACTER TABULATION WITH JUSTIFICATION (HTJ)
     8A |  0000008A | LINE TABULATION SET (VTS)
     8B |  0000008B | PARTIAL LINE FORWARD (PLD)
     8C |  0000008C | PARTIAL LINE BACKWARD (PLU)
     8D |  0000008D | REVERSE LINE FEED (RI)
     8E |  0000008E | SINGLE-SHIFT TWO (SS2)
     8F |  0000008F | SINGLE-SHIFT THREE (SS3)
     90 |  00000090 | DEVICE CONTROL STRING (DCS)
     91 |  00000091 | PRIVATE USE ONE (PU1)
     92 |  00000092 | PRIVATE USE TWO (PU2)
     93 |  00000093 | SET TRANSMIT STATE (STS)
     94 |  00000094 | CANCEL CHARACTER (CCH)
     95 |  00000095 | MESSAGE WAITING (MW)
     96 |  00000096 | START OF GUARDED AREA (SPA)
     97 |  00000097 | END OF GUARDED AREA (EPA)
     98 |  00000098 | START OF STRING (SOS)
     99 |  00000099 | SINGLE GRAPHIC CHARACTER INTRODUCER (SGCI)
     9A |  0000009A | SINGLE CHARACTER INTRODUCER (SCI)
     9B |  0000009B | CONTROL SEQUENCE INTRODUCER (CSI)
     9C |  0000009C | STRING TERMINATOR (ST)
     9D |  0000009D | OPERATING SYSTEM COMMAND (OSC)
     9E |  0000009E | PRIVACY MESSAGE (PM)
     9F |  0000009F | APPLICATION PROGRAM COMMAND (APC)
     A0 |  000002C7 | CARON (Mandarin Chinese third tone)
     A1 |  00002261 | IDENTICAL TO
     A2 |  00002227 | LOGICAL AND
     A3 |  00002228 | LOGICAL OR
     A4 |  00002229 | INTERSECTION
     A5 |  0000222A | UNION
     A6 |  00002282 | SUBSET OF
     A7 |  00002283 | SUPERSET OF
     A8 |  000021D0 | LEFTWARDS DOUBLE ARROW
     A9 |  000021D2 | RIGHTWARDS DOUBLE ARROW
     AA |  00002234 | THEREFORE
     AB |  00002235 | BECAUSE
     AC |  00002208 | ELEMENT OF
     AD |  0000220B | CONTAINS AS MEMBER
     AE |  00002286 | SUBSET OF OR EQUAL TO
     AF |  00002287 | SUPERSET OF OR EQUAL TO
     B0 |  0000222B | INTEGRAL
     B1 |  0000222E | CONTOUR INTEGRAL
     B2 |  0000221E | INFINITY
     B3 |  00002207 | NABLA
     B4 |  00002202 | PARTIAL DIFFERENTIAL
     B5 |  0000223C | TILDE OPERATOR
     B6 |  00002248 | ALMOST EQUAL TO
     B7 |  00002243 | ASYMPTOTICALLY EQUAL TO
     B8 |  00002245 | APPROXIMATELY EQUAL TO
     B9 |  00002264 | LESS-THAN OR EQUAL TO
     BA |  00002260 | NOT EQUAL TO
     BB |  00002265 | GREATER-THAN OR EQUAL TO
     BC |  00002194 | LEFT RIGHT ARROW
     BD |  000000AC | NOT SIGN
     BE |  00002200 | FOR ALL
     BF |  00002203 | THERE EXISTS
     C0 |  000005D0 | HEBREW LETTER ALEF
     C1 |  000025A1 | WHITE SQUARE
     C2 |  00002225 | PARALLEL TO
     C3 |  00000393 | GREEK CAPITAL LETTER GAMMA
     C4 |  00000394 | GREEK CAPITAL LETTER DELTA
     C5 |  000022A5 | UP TACK
     C6 |  00002220 | ANGLE
     C7 |  0000221F | RIGHT ANGLE
     C8 |  00000398 | GREEK CAPITAL LETTER THETA
     C9 |  00002329 | LEFT-POINTING ANGLE BRACKET
     CA |  0000232A | RIGHT-POINTING ANGLE BRACKET
     CB |  0000039B | GREEK CAPITAL LETTER LAMDA
     CC |  00002032 | PRIME
     CD |  00002033 | DOUBLE PRIME
     CE |  0000039E | GREEK CAPITAL LETTER XI
     CF |  00002213 | MINUS-OR-PLUS SIGN
     D0 |  000003A0 | GREEK CAPITAL LETTER PI
     D1 |  000000B2 | SUPERSCRIPT TWO
     D2 |  000003A3 | GREEK CAPITAL LETTER SIGMA
     D3 |  000000D7 | MULTIPLICATION SIGN
     D4 |  000000B3 | SUPERSCRIPT THREE
     D5 |  000003A5 | GREEK CAPITAL LETTER UPSILON
     D6 |  000003A6 | GREEK CAPITAL LETTER PHI
     D7 |  000000B7 | MIDDLE DOT
     D8 |  000003A8 | GREEK CAPITAL LETTER PSI
     D9 |  000003A9 | GREEK CAPITAL LETTER OMEGA
     DA |  00002205 | EMPTY SET
     DB |  000021C0 | RIGHTWARDS HARPOON WITH BARB UPWARDS
     DC |  0000221A | SQUARE ROOT
     DD |  00000192 | LATIN SMALL LETTER F WITH HOOK
     DE |  0000221D | PROPORTIONAL TO
     DF |  000000B1 | PLUS-MINUS SIGN
     E0 |  000000B0 | DEGREE SIGN
     E1 |  000003B1 | GREEK SMALL LETTER ALPHA
     E2 |  000003B2 | GREEK SMALL LETTER BETA
     E3 |  000003B3 | GREEK SMALL LETTER GAMMA
     E4 |  000003B4 | GREEK SMALL LETTER DELTA
     E5 |  000003B5 | GREEK SMALL LETTER EPSILON
     E6 |  000003B6 | GREEK SMALL LETTER ZETA
     E7 |  000003B7 | GREEK SMALL LETTER ETA
     E8 |  000003B8 | GREEK SMALL LETTER THETA
     E9 |  000003B9 | GREEK SMALL LETTER IOTA
     EA |  000003BA | GREEK SMALL LETTER KAPPA
     EB |  000003BB | GREEK SMALL LETTER LAMDA
     EC |  000003BC | GREEK SMALL LETTER MU
     ED |  000003BD | GREEK SMALL LETTER NU
     EE |  000003BE | GREEK SMALL LETTER XI
     EF |  00002030 | PER MILLE SIGN
     F0 |  000003C0 | GREEK SMALL LETTER PI
     F1 |  000003C1 | GREEK SMALL LETTER RHO
     F2 |  000003C3 | GREEK SMALL LETTER SIGMA
     F3 |  000000F7 | DIVISION SIGN
     F4 |  000003C4 | GREEK SMALL LETTER TAU
     F5 |  000003C5 | GREEK SMALL LETTER UPSILON
     F6 |  000003C6 | GREEK SMALL LETTER PHI
     F7 |  000003C7 | GREEK SMALL LETTER CHI
     F8 |  000003C8 | GREEK SMALL LETTER PSI
     F9 |  000003C9 | GREEK SMALL LETTER OMEGA
     FA |  00002020 | DAGGER
     FB |  00002190 | LEFTWARDS ARROW
     FC |  00002191 | UPWARDS ARROW
     FD |  00002192 | RIGHTWARDS ARROW
     FE |  00002193 | DOWNWARDS ARROW
     FF |  0000203E | OVERLINE
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/INIS.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for INIS.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::INIS;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x0004,
     0x0005,
     0x0006,
     0x0007,
     0x0008,
     0x0009,
     0x000a,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x0014,
     0x0015,
     0x0016,
     0x0017,
     0x0018,
     0x0019,
     0x001a,
     0x001b,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0020,
     0xfffd,
     0xfffd,
     0xfffd,
     0x0024,
     0x0025,
     0xfffd,
     0x0027,
     0x0028,
     0x0029,
     0x002a,
     0x002b,
     0x002c,
     0x002d,
     0x002e,
     0x002f,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x003a,
     0x003b,
     0x003c,
     0x003d,
     0x003e,
     0xfffd,
     0xfffd,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x005b,
     0xfffd,
     0x005d,
     0xfffd,
     0xfffd,
     0xfffd,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0xfffd,
     0x007c,
     0xfffd,
     0xfffd,
     0x007f,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\x04",
     "\x05",
     "\x06",
     "\x07",
     "\x08",
     "\x09",
     "\x0a",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\x14",
     "\x15",
     "\x16",
     "\x17",
     "\x18",
     "\x19",
     "\x1a",
     "\x1b",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\x20",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x24",
     "\x25",
     "\xef\xbf\xbd",
     "\x27",
     "\x28",
     "\x29",
     "\x2a",
     "\x2b",
     "\x2c",
     "\x2d",
     "\x2e",
     "\x2f",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\x3a",
     "\x3b",
     "\x3c",
     "\x3d",
     "\x3e",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\x5b",
     "\xef\xbf\xbd",
     "\x5d",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\xef\xbf\xbd",
     "\x7c",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x7f",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x04",
     0x00000005 => "\x05",
     0x00000006 => "\x06",
     0x00000007 => "\x07",
     0x00000008 => "\x08",
     0x00000009 => "\x09",
     0x0000000a => "\x0a",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x14",
     0x00000015 => "\x15",
     0x00000016 => "\x16",
     0x00000017 => "\x17",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x1a",
     0x0000001b => "\x1b",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x20",
     0x00000024 => "\x24",
     0x00000025 => "\x25",
     0x00000027 => "\x27",
     0x00000028 => "\x28",
     0x00000029 => "\x29",
     0x0000002a => "\x2a",
     0x0000002b => "\x2b",
     0x0000002c => "\x2c",
     0x0000002d => "\x2d",
     0x0000002e => "\x2e",
     0x0000002f => "\x2f",
     0x00000030 => "\x30",
     0x00000031 => "\x31",
     0x00000032 => "\x32",
     0x00000033 => "\x33",
     0x00000034 => "\x34",
     0x00000035 => "\x35",
     0x00000036 => "\x36",
     0x00000037 => "\x37",
     0x00000038 => "\x38",
     0x00000039 => "\x39",
     0x0000003a => "\x3a",
     0x0000003b => "\x3b",
     0x0000003c => "\x3c",
     0x0000003d => "\x3d",
     0x0000003e => "\x3e",
     0x00000041 => "\x41",
     0x00000042 => "\x42",
     0x00000043 => "\x43",
     0x00000044 => "\x44",
     0x00000045 => "\x45",
     0x00000046 => "\x46",
     0x00000047 => "\x47",
     0x00000048 => "\x48",
     0x00000049 => "\x49",
     0x0000004a => "\x4a",
     0x0000004b => "\x4b",
     0x0000004c => "\x4c",
     0x0000004d => "\x4d",
     0x0000004e => "\x4e",
     0x0000004f => "\x4f",
     0x00000050 => "\x50",
     0x00000051 => "\x51",
     0x00000052 => "\x52",
     0x00000053 => "\x53",
     0x00000054 => "\x54",
     0x00000055 => "\x55",
     0x00000056 => "\x56",
     0x00000057 => "\x57",
     0x00000058 => "\x58",
     0x00000059 => "\x59",
     0x0000005a => "\x5a",
     0x0000005b => "\x5b",
     0x0000005d => "\x5d",
     0x00000061 => "\x61",
     0x00000062 => "\x62",
     0x00000063 => "\x63",
     0x00000064 => "\x64",
     0x00000065 => "\x65",
     0x00000066 => "\x66",
     0x00000067 => "\x67",
     0x00000068 => "\x68",
     0x00000069 => "\x69",
     0x0000006a => "\x6a",
     0x0000006b => "\x6b",
     0x0000006c => "\x6c",
     0x0000006d => "\x6d",
     0x0000006e => "\x6e",
     0x0000006f => "\x6f",
     0x00000070 => "\x70",
     0x00000071 => "\x71",
     0x00000072 => "\x72",
     0x00000073 => "\x73",
     0x00000074 => "\x74",
     0x00000075 => "\x75",
     0x00000076 => "\x76",
     0x00000077 => "\x77",
     0x00000078 => "\x78",
     0x00000079 => "\x79",
     0x0000007a => "\x7a",
     0x0000007c => "\x7c",
     0x0000007f => "\x7f",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::INIS - Conversion routines for INIS
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for INIS.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
   source: ECMA registry
  alias ISO-IR-49
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  00000004 | END OF TRANSMISSION (EOT)
     05 |  00000005 | ENQUIRY (ENQ)
     06 |  00000006 | ACKNOWLEDGE (ACK)
     07 |  00000007 | BELL (BEL)
     08 |  00000008 | BACKSPACE (BS)
     09 |  00000009 | CHARACTER TABULATION (HT)
     0A |  0000000A | LINE FEED (LF)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  00000014 | DEVICE CONTROL FOUR (DC4)
     15 |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     16 |  00000016 | SYNCHRONOUS IDLE (SYN)
     17 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  0000001A | SUBSTITUTE (SUB)
     1B |  0000001B | ESCAPE (ESC)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000020 | SPACE
     24 |  00000024 | DOLLAR SIGN
     25 |  00000025 | PERCENT SIGN
     27 |  00000027 | APOSTROPHE
     28 |  00000028 | LEFT PARENTHESIS
     29 |  00000029 | RIGHT PARENTHESIS
     2A |  0000002A | ASTERISK
     2B |  0000002B | PLUS SIGN
     2C |  0000002C | COMMA
     2D |  0000002D | HYPHEN-MINUS
     2E |  0000002E | FULL STOP
     2F |  0000002F | SOLIDUS
     30 |  00000030 | DIGIT ZERO
     31 |  00000031 | DIGIT ONE
     32 |  00000032 | DIGIT TWO
     33 |  00000033 | DIGIT THREE
     34 |  00000034 | DIGIT FOUR
     35 |  00000035 | DIGIT FIVE
     36 |  00000036 | DIGIT SIX
     37 |  00000037 | DIGIT SEVEN
     38 |  00000038 | DIGIT EIGHT
     39 |  00000039 | DIGIT NINE
     3A |  0000003A | COLON
     3B |  0000003B | SEMICOLON
     3C |  0000003C | LESS-THAN SIGN
     3D |  0000003D | EQUALS SIGN
     3E |  0000003E | GREATER-THAN SIGN
     41 |  00000041 | LATIN CAPITAL LETTER A
     42 |  00000042 | LATIN CAPITAL LETTER B
     43 |  00000043 | LATIN CAPITAL LETTER C
     44 |  00000044 | LATIN CAPITAL LETTER D
     45 |  00000045 | LATIN CAPITAL LETTER E
     46 |  00000046 | LATIN CAPITAL LETTER F
     47 |  00000047 | LATIN CAPITAL LETTER G
     48 |  00000048 | LATIN CAPITAL LETTER H
     49 |  00000049 | LATIN CAPITAL LETTER I
     4A |  0000004A | LATIN CAPITAL LETTER J
     4B |  0000004B | LATIN CAPITAL LETTER K
     4C |  0000004C | LATIN CAPITAL LETTER L
     4D |  0000004D | LATIN CAPITAL LETTER M
     4E |  0000004E | LATIN CAPITAL LETTER N
     4F |  0000004F | LATIN CAPITAL LETTER O
     50 |  00000050 | LATIN CAPITAL LETTER P
     51 |  00000051 | LATIN CAPITAL LETTER Q
     52 |  00000052 | LATIN CAPITAL LETTER R
     53 |  00000053 | LATIN CAPITAL LETTER S
     54 |  00000054 | LATIN CAPITAL LETTER T
     55 |  00000055 | LATIN CAPITAL LETTER U
     56 |  00000056 | LATIN CAPITAL LETTER V
     57 |  00000057 | LATIN CAPITAL LETTER W
     58 |  00000058 | LATIN CAPITAL LETTER X
     59 |  00000059 | LATIN CAPITAL LETTER Y
     5A |  0000005A | LATIN CAPITAL LETTER Z
     5B |  0000005B | LEFT SQUARE BRACKET
     5D |  0000005D | RIGHT SQUARE BRACKET
     61 |  00000061 | LATIN SMALL LETTER A
     62 |  00000062 | LATIN SMALL LETTER B
     63 |  00000063 | LATIN SMALL LETTER C
     64 |  00000064 | LATIN SMALL LETTER D
     65 |  00000065 | LATIN SMALL LETTER E
     66 |  00000066 | LATIN SMALL LETTER F
     67 |  00000067 | LATIN SMALL LETTER G
     68 |  00000068 | LATIN SMALL LETTER H
     69 |  00000069 | LATIN SMALL LETTER I
     6A |  0000006A | LATIN SMALL LETTER J
     6B |  0000006B | LATIN SMALL LETTER K
     6C |  0000006C | LATIN SMALL LETTER L
     6D |  0000006D | LATIN SMALL LETTER M
     6E |  0000006E | LATIN SMALL LETTER N
     6F |  0000006F | LATIN SMALL LETTER O
     70 |  00000070 | LATIN SMALL LETTER P
     71 |  00000071 | LATIN SMALL LETTER Q
     72 |  00000072 | LATIN SMALL LETTER R
     73 |  00000073 | LATIN SMALL LETTER S
     74 |  00000074 | LATIN SMALL LETTER T
     75 |  00000075 | LATIN SMALL LETTER U
     76 |  00000076 | LATIN SMALL LETTER V
     77 |  00000077 | LATIN SMALL LETTER W
     78 |  00000078 | LATIN SMALL LETTER X
     79 |  00000079 | LATIN SMALL LETTER Y
     7A |  0000007A | LATIN SMALL LETTER Z
     7C |  0000007C | VERTICAL LINE
     7F |  0000007F | DELETE (DEL)
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/INIS_8.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for INIS-8.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::INIS_8;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x0004,
     0x0005,
     0x0006,
     0x0007,
     0x0008,
     0x0009,
     0x000a,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x0014,
     0x0015,
     0x0016,
     0x0017,
     0x0018,
     0x0019,
     0x001a,
     0x001b,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0020,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x03b1,
     0x03b2,
     0x03b3,
     0x03b4,
     0x039e,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x2192,
     0x222b,
     0x2070,
     0x00b9,
     0x00b2,
     0x00b3,
     0x2074,
     0x2075,
     0x2076,
     0x2077,
     0x2078,
     0x2079,
     0x207a,
     0x207b,
     0x30eb,
     0x0394,
     0x039b,
     0x03a9,
     0x2080,
     0x2081,
     0x2082,
     0x2083,
     0x2084,
     0x2085,
     0x2086,
     0x2087,
     0x2088,
     0x2089,
     0x03a3,
     0x03bc,
     0x03bd,
     0x03c9,
     0x03c0,
     0x007f,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\x04",
     "\x05",
     "\x06",
     "\x07",
     "\x08",
     "\x09",
     "\x0a",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\x14",
     "\x15",
     "\x16",
     "\x17",
     "\x18",
     "\x19",
     "\x1a",
     "\x1b",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\x20",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xce\xb1",
     "\xce\xb2",
     "\xce\xb3",
     "\xce\xb4",
     "\xce\x9e",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xe2\x86\x92",
     "\xe2\x88\xab",
     "\xe2\x81\xb0",
     "\xc2\xb9",
     "\xc2\xb2",
     "\xc2\xb3",
     "\xe2\x81\xb4",
     "\xe2\x81\xb5",
     "\xe2\x81\xb6",
     "\xe2\x81\xb7",
     "\xe2\x81\xb8",
     "\xe2\x81\xb9",
     "\xe2\x81\xba",
     "\xe2\x81\xbb",
     "\xe3\x83\xab",
     "\xce\x94",
     "\xce\x9b",
     "\xce\xa9",
     "\xe2\x82\x80",
     "\xe2\x82\x81",
     "\xe2\x82\x82",
     "\xe2\x82\x83",
     "\xe2\x82\x84",
     "\xe2\x82\x85",
     "\xe2\x82\x86",
     "\xe2\x82\x87",
     "\xe2\x82\x88",
     "\xe2\x82\x89",
     "\xce\xa3",
     "\xce\xbc",
     "\xce\xbd",
     "\xcf\x89",
     "\xcf\x80",
     "\x7f",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x04",
     0x00000005 => "\x05",
     0x00000006 => "\x06",
     0x00000007 => "\x07",
     0x00000008 => "\x08",
     0x00000009 => "\x09",
     0x0000000a => "\x0a",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x14",
     0x00000015 => "\x15",
     0x00000016 => "\x16",
     0x00000017 => "\x17",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x1a",
     0x0000001b => "\x1b",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x20",
     0x0000007f => "\x7f",
     0x000000b2 => "\x62",
     0x000000b3 => "\x63",
     0x000000b9 => "\x61",
     0x00000394 => "\x6d",
     0x0000039b => "\x6e",
     0x0000039e => "\x3e",
     0x000003a3 => "\x7a",
     0x000003a9 => "\x6f",
     0x000003b1 => "\x3a",
     0x000003b2 => "\x3b",
     0x000003b3 => "\x3c",
     0x000003b4 => "\x3d",
     0x000003bc => "\x7b",
     0x000003bd => "\x7c",
     0x000003c0 => "\x7e",
     0x000003c9 => "\x7d",
     0x00002070 => "\x60",
     0x00002074 => "\x64",
     0x00002075 => "\x65",
     0x00002076 => "\x66",
     0x00002077 => "\x67",
     0x00002078 => "\x68",
     0x00002079 => "\x69",
     0x0000207a => "\x6a",
     0x0000207b => "\x6b",
     0x00002080 => "\x70",
     0x00002081 => "\x71",
     0x00002082 => "\x72",
     0x00002083 => "\x73",
     0x00002084 => "\x74",
     0x00002085 => "\x75",
     0x00002086 => "\x76",
     0x00002087 => "\x77",
     0x00002088 => "\x78",
     0x00002089 => "\x79",
     0x00002192 => "\x5e",
     0x0000222b => "\x5f",
     0x000030eb => "\x6c",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::INIS_8 - Conversion routines for INIS_8
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for INIS-8.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
  repertoiremap: mnemonic,ds
   source: ECMA registry
  alias ISO-IR-50
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  00000004 | END OF TRANSMISSION (EOT)
     05 |  00000005 | ENQUIRY (ENQ)
     06 |  00000006 | ACKNOWLEDGE (ACK)
     07 |  00000007 | BELL (BEL)
     08 |  00000008 | BACKSPACE (BS)
     09 |  00000009 | CHARACTER TABULATION (HT)
     0A |  0000000A | LINE FEED (LF)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  00000014 | DEVICE CONTROL FOUR (DC4)
     15 |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     16 |  00000016 | SYNCHRONOUS IDLE (SYN)
     17 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  0000001A | SUBSTITUTE (SUB)
     1B |  0000001B | ESCAPE (ESC)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000020 | SPACE
     3A |  000003B1 | GREEK SMALL LETTER ALPHA
     3B |  000003B2 | GREEK SMALL LETTER BETA
     3C |  000003B3 | GREEK SMALL LETTER GAMMA
     3D |  000003B4 | GREEK SMALL LETTER DELTA
     3E |  0000039E | GREEK CAPITAL LETTER XI
     5E |  00002192 | RIGHTWARDS ARROW
     5F |  0000222B | INTEGRAL
     60 |  00002070 | SUPERSCRIPT ZERO
     61 |  000000B9 | SUPERSCRIPT ONE
     62 |  000000B2 | SUPERSCRIPT TWO
     63 |  000000B3 | SUPERSCRIPT THREE
     64 |  00002074 | SUPERSCRIPT FOUR
     65 |  00002075 | SUPERSCRIPT FIVE
     66 |  00002076 | SUPERSCRIPT SIX
     67 |  00002077 | SUPERSCRIPT SEVEN
     68 |  00002078 | SUPERSCRIPT EIGHT
     69 |  00002079 | SUPERSCRIPT NINE
     6A |  0000207A | SUPERSCRIPT PLUS SIGN
     6B |  0000207B | SUPERSCRIPT MINUS
     6C |  000030EB | KATAKANA LETTER RU
     6D |  00000394 | GREEK CAPITAL LETTER DELTA
     6E |  0000039B | GREEK CAPITAL LETTER LAMDA
     6F |  000003A9 | GREEK CAPITAL LETTER OMEGA
     70 |  00002080 | SUBSCRIPT ZERO
     71 |  00002081 | SUBSCRIPT ONE
     72 |  00002082 | SUBSCRIPT TWO
     73 |  00002083 | SUBSCRIPT THREE
     74 |  00002084 | SUBSCRIPT FOUR
     75 |  00002085 | SUBSCRIPT FIVE
     76 |  00002086 | SUBSCRIPT SIX
     77 |  00002087 | SUBSCRIPT SEVEN
     78 |  00002088 | SUBSCRIPT EIGHT
     79 |  00002089 | SUBSCRIPT NINE
     7A |  000003A3 | GREEK CAPITAL LETTER SIGMA
     7B |  000003BC | GREEK SMALL LETTER MU
     7C |  000003BD | GREEK SMALL LETTER NU
     7D |  000003C9 | GREEK SMALL LETTER OMEGA
     7E |  000003C0 | GREEK SMALL LETTER PI
     7F |  0000007F | DELETE (DEL)
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/INIS_CYRILLIC.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for INIS-CYRILLIC.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::INIS_CYRILLIC;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x0004,
     0x0005,
     0x0006,
     0x0007,
     0x0008,
     0x0009,
     0x000a,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x0014,
     0x0015,
     0x0016,
     0x0017,
     0x0018,
     0x0019,
     0x001a,
     0x001b,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0020,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x221a,
     0xfffd,
     0x2192,
     0x222b,
     0x03b1,
     0x03b2,
     0x03b3,
     0x03b4,
     0x03a3,
     0x03bc,
     0x03bd,
     0x03c9,
     0x03c0,
     0x039e,
     0x0394,
     0x039b,
     0x03a9,
     0x042a,
     0x207b,
     0x207a,
     0x044e,
     0x0430,
     0x0431,
     0x0446,
     0x0434,
     0x0435,
     0x0444,
     0x0433,
     0x0445,
     0x0438,
     0x0439,
     0x043a,
     0x043b,
     0x043c,
     0x043d,
     0x043e,
     0x043f,
     0x044f,
     0x0440,
     0x0441,
     0x0442,
     0x0443,
     0x0436,
     0x0432,
     0x044c,
     0x044b,
     0x0437,
     0x0448,
     0x044d,
     0x0449,
     0x0447,
     0x044a,
     0x042e,
     0x0410,
     0x0411,
     0x0426,
     0x0414,
     0x0415,
     0x0424,
     0x0413,
     0x0425,
     0x0418,
     0x0419,
     0x041a,
     0x041b,
     0x041c,
     0x041d,
     0x041e,
     0x041f,
     0x042f,
     0x0420,
     0x0421,
     0x0422,
     0x0423,
     0x0416,
     0x0412,
     0x042c,
     0x042b,
     0x0417,
     0x0428,
     0x042d,
     0x0429,
     0x0427,
     0x007f,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\x04",
     "\x05",
     "\x06",
     "\x07",
     "\x08",
     "\x09",
     "\x0a",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\x14",
     "\x15",
     "\x16",
     "\x17",
     "\x18",
     "\x19",
     "\x1a",
     "\x1b",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\x20",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xe2\x88\x9a",
     "\xef\xbf\xbd",
     "\xe2\x86\x92",
     "\xe2\x88\xab",
     "\xce\xb1",
     "\xce\xb2",
     "\xce\xb3",
     "\xce\xb4",
     "\xce\xa3",
     "\xce\xbc",
     "\xce\xbd",
     "\xcf\x89",
     "\xcf\x80",
     "\xce\x9e",
     "\xce\x94",
     "\xce\x9b",
     "\xce\xa9",
     "\xd0\xaa",
     "\xe2\x81\xbb",
     "\xe2\x81\xba",
     "\xd1\x8e",
     "\xd0\xb0",
     "\xd0\xb1",
     "\xd1\x86",
     "\xd0\xb4",
     "\xd0\xb5",
     "\xd1\x84",
     "\xd0\xb3",
     "\xd1\x85",
     "\xd0\xb8",
     "\xd0\xb9",
     "\xd0\xba",
     "\xd0\xbb",
     "\xd0\xbc",
     "\xd0\xbd",
     "\xd0\xbe",
     "\xd0\xbf",
     "\xd1\x8f",
     "\xd1\x80",
     "\xd1\x81",
     "\xd1\x82",
     "\xd1\x83",
     "\xd0\xb6",
     "\xd0\xb2",
     "\xd1\x8c",
     "\xd1\x8b",
     "\xd0\xb7",
     "\xd1\x88",
     "\xd1\x8d",
     "\xd1\x89",
     "\xd1\x87",
     "\xd1\x8a",
     "\xd0\xae",
     "\xd0\x90",
     "\xd0\x91",
     "\xd0\xa6",
     "\xd0\x94",
     "\xd0\x95",
     "\xd0\xa4",
     "\xd0\x93",
     "\xd0\xa5",
     "\xd0\x98",
     "\xd0\x99",
     "\xd0\x9a",
     "\xd0\x9b",
     "\xd0\x9c",
     "\xd0\x9d",
     "\xd0\x9e",
     "\xd0\x9f",
     "\xd0\xaf",
     "\xd0\xa0",
     "\xd0\xa1",
     "\xd0\xa2",
     "\xd0\xa3",
     "\xd0\x96",
     "\xd0\x92",
     "\xd0\xac",
     "\xd0\xab",
     "\xd0\x97",
     "\xd0\xa8",
     "\xd0\xad",
     "\xd0\xa9",
     "\xd0\xa7",
     "\x7f",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x04",
     0x00000005 => "\x05",
     0x00000006 => "\x06",
     0x00000007 => "\x07",
     0x00000008 => "\x08",
     0x00000009 => "\x09",
     0x0000000a => "\x0a",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x14",
     0x00000015 => "\x15",
     0x00000016 => "\x16",
     0x00000017 => "\x17",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x1a",
     0x0000001b => "\x1b",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x20",
     0x0000007f => "\x7f",
     0x00000394 => "\x3a",
     0x0000039b => "\x3b",
     0x0000039e => "\x39",
     0x000003a3 => "\x34",
     0x000003a9 => "\x3c",
     0x000003b1 => "\x30",
     0x000003b2 => "\x31",
     0x000003b3 => "\x32",
     0x000003b4 => "\x33",
     0x000003bc => "\x35",
     0x000003bd => "\x36",
     0x000003c0 => "\x38",
     0x000003c9 => "\x37",
     0x00000410 => "\x61",
     0x00000411 => "\x62",
     0x00000412 => "\x77",
     0x00000413 => "\x67",
     0x00000414 => "\x64",
     0x00000415 => "\x65",
     0x00000416 => "\x76",
     0x00000417 => "\x7a",
     0x00000418 => "\x69",
     0x00000419 => "\x6a",
     0x0000041a => "\x6b",
     0x0000041b => "\x6c",
     0x0000041c => "\x6d",
     0x0000041d => "\x6e",
     0x0000041e => "\x6f",
     0x0000041f => "\x70",
     0x00000420 => "\x72",
     0x00000421 => "\x73",
     0x00000422 => "\x74",
     0x00000423 => "\x75",
     0x00000424 => "\x66",
     0x00000425 => "\x68",
     0x00000426 => "\x63",
     0x00000427 => "\x7e",
     0x00000428 => "\x7b",
     0x00000429 => "\x7d",
     0x0000042a => "\x3d",
     0x0000042b => "\x79",
     0x0000042c => "\x78",
     0x0000042d => "\x7c",
     0x0000042e => "\x60",
     0x0000042f => "\x71",
     0x00000430 => "\x41",
     0x00000431 => "\x42",
     0x00000432 => "\x57",
     0x00000433 => "\x47",
     0x00000434 => "\x44",
     0x00000435 => "\x45",
     0x00000436 => "\x56",
     0x00000437 => "\x5a",
     0x00000438 => "\x49",
     0x00000439 => "\x4a",
     0x0000043a => "\x4b",
     0x0000043b => "\x4c",
     0x0000043c => "\x4d",
     0x0000043d => "\x4e",
     0x0000043e => "\x4f",
     0x0000043f => "\x50",
     0x00000440 => "\x52",
     0x00000441 => "\x53",
     0x00000442 => "\x54",
     0x00000443 => "\x55",
     0x00000444 => "\x46",
     0x00000445 => "\x48",
     0x00000446 => "\x43",
     0x00000447 => "\x5e",
     0x00000448 => "\x5b",
     0x00000449 => "\x5d",
     0x0000044a => "\x5f",
     0x0000044b => "\x59",
     0x0000044c => "\x58",
     0x0000044d => "\x5c",
     0x0000044e => "\x40",
     0x0000044f => "\x51",
     0x0000207a => "\x3f",
     0x0000207b => "\x3e",
     0x00002192 => "\x2e",
     0x0000221a => "\x2c",
     0x0000222b => "\x2f",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::INIS_CYRILLIC - Conversion routines for INIS_CYRILLIC
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for INIS-CYRILLIC.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
   source: ECMA registry
  alias ISO-IR-51
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  00000004 | END OF TRANSMISSION (EOT)
     05 |  00000005 | ENQUIRY (ENQ)
     06 |  00000006 | ACKNOWLEDGE (ACK)
     07 |  00000007 | BELL (BEL)
     08 |  00000008 | BACKSPACE (BS)
     09 |  00000009 | CHARACTER TABULATION (HT)
     0A |  0000000A | LINE FEED (LF)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  00000014 | DEVICE CONTROL FOUR (DC4)
     15 |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     16 |  00000016 | SYNCHRONOUS IDLE (SYN)
     17 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  0000001A | SUBSTITUTE (SUB)
     1B |  0000001B | ESCAPE (ESC)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000020 | SPACE
     2C |  0000221A | SQUARE ROOT
     2E |  00002192 | RIGHTWARDS ARROW
     2F |  0000222B | INTEGRAL
     30 |  000003B1 | GREEK SMALL LETTER ALPHA
     31 |  000003B2 | GREEK SMALL LETTER BETA
     32 |  000003B3 | GREEK SMALL LETTER GAMMA
     33 |  000003B4 | GREEK SMALL LETTER DELTA
     34 |  000003A3 | GREEK CAPITAL LETTER SIGMA
     35 |  000003BC | GREEK SMALL LETTER MU
     36 |  000003BD | GREEK SMALL LETTER NU
     37 |  000003C9 | GREEK SMALL LETTER OMEGA
     38 |  000003C0 | GREEK SMALL LETTER PI
     39 |  0000039E | GREEK CAPITAL LETTER XI
     3A |  00000394 | GREEK CAPITAL LETTER DELTA
     3B |  0000039B | GREEK CAPITAL LETTER LAMDA
     3C |  000003A9 | GREEK CAPITAL LETTER OMEGA
     3D |  0000042A | CYRILLIC CAPITAL LETTER HARD SIGN
     3E |  0000207B | SUPERSCRIPT MINUS
     3F |  0000207A | SUPERSCRIPT PLUS SIGN
     40 |  0000044E | CYRILLIC SMALL LETTER YU
     41 |  00000430 | CYRILLIC SMALL LETTER A
     42 |  00000431 | CYRILLIC SMALL LETTER BE
     43 |  00000446 | CYRILLIC SMALL LETTER TSE
     44 |  00000434 | CYRILLIC SMALL LETTER DE
     45 |  00000435 | CYRILLIC SMALL LETTER IE
     46 |  00000444 | CYRILLIC SMALL LETTER EF
     47 |  00000433 | CYRILLIC SMALL LETTER GHE
     48 |  00000445 | CYRILLIC SMALL LETTER HA
     49 |  00000438 | CYRILLIC SMALL LETTER I
     4A |  00000439 | CYRILLIC SMALL LETTER SHORT I
     4B |  0000043A | CYRILLIC SMALL LETTER KA
     4C |  0000043B | CYRILLIC SMALL LETTER EL
     4D |  0000043C | CYRILLIC SMALL LETTER EM
     4E |  0000043D | CYRILLIC SMALL LETTER EN
     4F |  0000043E | CYRILLIC SMALL LETTER O
     50 |  0000043F | CYRILLIC SMALL LETTER PE
     51 |  0000044F | CYRILLIC SMALL LETTER YA
     52 |  00000440 | CYRILLIC SMALL LETTER ER
     53 |  00000441 | CYRILLIC SMALL LETTER ES
     54 |  00000442 | CYRILLIC SMALL LETTER TE
     55 |  00000443 | CYRILLIC SMALL LETTER U
     56 |  00000436 | CYRILLIC SMALL LETTER ZHE
     57 |  00000432 | CYRILLIC SMALL LETTER VE
     58 |  0000044C | CYRILLIC SMALL LETTER SOFT SIGN
     59 |  0000044B | CYRILLIC SMALL LETTER YERU
     5A |  00000437 | CYRILLIC SMALL LETTER ZE
     5B |  00000448 | CYRILLIC SMALL LETTER SHA
     5C |  0000044D | CYRILLIC SMALL LETTER E
     5D |  00000449 | CYRILLIC SMALL LETTER SHCHA
     5E |  00000447 | CYRILLIC SMALL LETTER CHE
     5F |  0000044A | CYRILLIC SMALL LETTER HARD SIGN
     60 |  0000042E | CYRILLIC CAPITAL LETTER YU
     61 |  00000410 | CYRILLIC CAPITAL LETTER A
     62 |  00000411 | CYRILLIC CAPITAL LETTER BE
     63 |  00000426 | CYRILLIC CAPITAL LETTER TSE
     64 |  00000414 | CYRILLIC CAPITAL LETTER DE
     65 |  00000415 | CYRILLIC CAPITAL LETTER IE
     66 |  00000424 | CYRILLIC CAPITAL LETTER EF
     67 |  00000413 | CYRILLIC CAPITAL LETTER GHE
     68 |  00000425 | CYRILLIC CAPITAL LETTER HA
     69 |  00000418 | CYRILLIC CAPITAL LETTER I
     6A |  00000419 | CYRILLIC CAPITAL LETTER SHORT I
     6B |  0000041A | CYRILLIC CAPITAL LETTER KA
     6C |  0000041B | CYRILLIC CAPITAL LETTER EL
     6D |  0000041C | CYRILLIC CAPITAL LETTER EM
     6E |  0000041D | CYRILLIC CAPITAL LETTER EN
     6F |  0000041E | CYRILLIC CAPITAL LETTER O
     70 |  0000041F | CYRILLIC CAPITAL LETTER PE
     71 |  0000042F | CYRILLIC CAPITAL LETTER YA
     72 |  00000420 | CYRILLIC CAPITAL LETTER ER
     73 |  00000421 | CYRILLIC CAPITAL LETTER ES
     74 |  00000422 | CYRILLIC CAPITAL LETTER TE
     75 |  00000423 | CYRILLIC CAPITAL LETTER U
     76 |  00000416 | CYRILLIC CAPITAL LETTER ZHE
     77 |  00000412 | CYRILLIC CAPITAL LETTER VE
     78 |  0000042C | CYRILLIC CAPITAL LETTER SOFT SIGN
     79 |  0000042B | CYRILLIC CAPITAL LETTER YERU
     7A |  00000417 | CYRILLIC CAPITAL LETTER ZE
     7B |  00000428 | CYRILLIC CAPITAL LETTER SHA
     7C |  0000042D | CYRILLIC CAPITAL LETTER E
     7D |  00000429 | CYRILLIC CAPITAL LETTER SHCHA
     7E |  00000427 | CYRILLIC CAPITAL LETTER CHE
     7F |  0000007F | DELETE (DEL)
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/ISO_10367_BOX.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for ISO_10367-BOX.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::ISO_10367_BOX;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x0004,
     0x0005,
     0x0006,
     0x0007,
     0x0008,
     0x0009,
     0x000a,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x0014,
     0x0015,
     0x0016,
     0x0017,
     0x0018,
     0x0019,
     0x001a,
     0x001b,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0020,
     0x0021,
     0x0022,
     0x0023,
     0x0024,
     0x0025,
     0x0026,
     0x0027,
     0x0028,
     0x0029,
     0x002a,
     0x002b,
     0x002c,
     0x002d,
     0x002e,
     0x002f,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x003a,
     0x003b,
     0x003c,
     0x003d,
     0x003e,
     0x003f,
     0x0040,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x005b,
     0x005c,
     0x005d,
     0x005e,
     0x005f,
     0x0060,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x007b,
     0x007c,
     0x007d,
     0x007e,
     0x007f,
     0x0080,
     0x0081,
     0x0082,
     0x0083,
     0x0084,
     0x0085,
     0x0086,
     0x0087,
     0x0088,
     0x0089,
     0x008a,
     0x008b,
     0x008c,
     0x008d,
     0x008e,
     0x008f,
     0x0090,
     0x0091,
     0x0092,
     0x0093,
     0x0094,
     0x0095,
     0x0096,
     0x0097,
     0x0098,
     0x0099,
     0x009a,
     0x009b,
     0x009c,
     0x009d,
     0x009e,
     0x009f,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x2551,
     0x2550,
     0x2554,
     0x2557,
     0x255a,
     0x255d,
     0x2560,
     0x2563,
     0x2566,
     0x2569,
     0x256c,
     0xe019,
     0x2584,
     0x2588,
     0x25aa,
     0xfffd,
     0x2502,
     0x2500,
     0x250c,
     0x2510,
     0x2514,
     0x2518,
     0x251c,
     0x2524,
     0x252c,
     0x2534,
     0x253c,
     0x2591,
     0x2592,
     0x2593,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\x04",
     "\x05",
     "\x06",
     "\x07",
     "\x08",
     "\x09",
     "\x0a",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\x14",
     "\x15",
     "\x16",
     "\x17",
     "\x18",
     "\x19",
     "\x1a",
     "\x1b",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\x20",
     "\x21",
     "\x22",
     "\x23",
     "\x24",
     "\x25",
     "\x26",
     "\x27",
     "\x28",
     "\x29",
     "\x2a",
     "\x2b",
     "\x2c",
     "\x2d",
     "\x2e",
     "\x2f",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\x3a",
     "\x3b",
     "\x3c",
     "\x3d",
     "\x3e",
     "\x3f",
     "\x40",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\x5b",
     "\x5c",
     "\x5d",
     "\x5e",
     "\x5f",
     "\x60",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\x7b",
     "\x7c",
     "\x7d",
     "\x7e",
     "\x7f",
     "\xc2\x80",
     "\xc2\x81",
     "\xc2\x82",
     "\xc2\x83",
     "\xc2\x84",
     "\xc2\x85",
     "\xc2\x86",
     "\xc2\x87",
     "\xc2\x88",
     "\xc2\x89",
     "\xc2\x8a",
     "\xc2\x8b",
     "\xc2\x8c",
     "\xc2\x8d",
     "\xc2\x8e",
     "\xc2\x8f",
     "\xc2\x90",
     "\xc2\x91",
     "\xc2\x92",
     "\xc2\x93",
     "\xc2\x94",
     "\xc2\x95",
     "\xc2\x96",
     "\xc2\x97",
     "\xc2\x98",
     "\xc2\x99",
     "\xc2\x9a",
     "\xc2\x9b",
     "\xc2\x9c",
     "\xc2\x9d",
     "\xc2\x9e",
     "\xc2\x9f",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xe2\x95\x91",
     "\xe2\x95\x90",
     "\xe2\x95\x94",
     "\xe2\x95\x97",
     "\xe2\x95\x9a",
     "\xe2\x95\x9d",
     "\xe2\x95\xa0",
     "\xe2\x95\xa3",
     "\xe2\x95\xa6",
     "\xe2\x95\xa9",
     "\xe2\x95\xac",
     "\xee\x80\x99",
     "\xe2\x96\x84",
     "\xe2\x96\x88",
     "\xe2\x96\xaa",
     "\xef\xbf\xbd",
     "\xe2\x94\x82",
     "\xe2\x94\x80",
     "\xe2\x94\x8c",
     "\xe2\x94\x90",
     "\xe2\x94\x94",
     "\xe2\x94\x98",
     "\xe2\x94\x9c",
     "\xe2\x94\xa4",
     "\xe2\x94\xac",
     "\xe2\x94\xb4",
     "\xe2\x94\xbc",
     "\xe2\x96\x91",
     "\xe2\x96\x92",
     "\xe2\x96\x93",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x04",
     0x00000005 => "\x05",
     0x00000006 => "\x06",
     0x00000007 => "\x07",
     0x00000008 => "\x08",
     0x00000009 => "\x09",
     0x0000000a => "\x0a",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x14",
     0x00000015 => "\x15",
     0x00000016 => "\x16",
     0x00000017 => "\x17",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x1a",
     0x0000001b => "\x1b",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x20",
     0x00000021 => "\x21",
     0x00000022 => "\x22",
     0x00000023 => "\x23",
     0x00000024 => "\x24",
     0x00000025 => "\x25",
     0x00000026 => "\x26",
     0x00000027 => "\x27",
     0x00000028 => "\x28",
     0x00000029 => "\x29",
     0x0000002a => "\x2a",
     0x0000002b => "\x2b",
     0x0000002c => "\x2c",
     0x0000002d => "\x2d",
     0x0000002e => "\x2e",
     0x0000002f => "\x2f",
     0x00000030 => "\x30",
     0x00000031 => "\x31",
     0x00000032 => "\x32",
     0x00000033 => "\x33",
     0x00000034 => "\x34",
     0x00000035 => "\x35",
     0x00000036 => "\x36",
     0x00000037 => "\x37",
     0x00000038 => "\x38",
     0x00000039 => "\x39",
     0x0000003a => "\x3a",
     0x0000003b => "\x3b",
     0x0000003c => "\x3c",
     0x0000003d => "\x3d",
     0x0000003e => "\x3e",
     0x0000003f => "\x3f",
     0x00000040 => "\x40",
     0x00000041 => "\x41",
     0x00000042 => "\x42",
     0x00000043 => "\x43",
     0x00000044 => "\x44",
     0x00000045 => "\x45",
     0x00000046 => "\x46",
     0x00000047 => "\x47",
     0x00000048 => "\x48",
     0x00000049 => "\x49",
     0x0000004a => "\x4a",
     0x0000004b => "\x4b",
     0x0000004c => "\x4c",
     0x0000004d => "\x4d",
     0x0000004e => "\x4e",
     0x0000004f => "\x4f",
     0x00000050 => "\x50",
     0x00000051 => "\x51",
     0x00000052 => "\x52",
     0x00000053 => "\x53",
     0x00000054 => "\x54",
     0x00000055 => "\x55",
     0x00000056 => "\x56",
     0x00000057 => "\x57",
     0x00000058 => "\x58",
     0x00000059 => "\x59",
     0x0000005a => "\x5a",
     0x0000005b => "\x5b",
     0x0000005c => "\x5c",
     0x0000005d => "\x5d",
     0x0000005e => "\x5e",
     0x0000005f => "\x5f",
     0x00000060 => "\x60",
     0x00000061 => "\x61",
     0x00000062 => "\x62",
     0x00000063 => "\x63",
     0x00000064 => "\x64",
     0x00000065 => "\x65",
     0x00000066 => "\x66",
     0x00000067 => "\x67",
     0x00000068 => "\x68",
     0x00000069 => "\x69",
     0x0000006a => "\x6a",
     0x0000006b => "\x6b",
     0x0000006c => "\x6c",
     0x0000006d => "\x6d",
     0x0000006e => "\x6e",
     0x0000006f => "\x6f",
     0x00000070 => "\x70",
     0x00000071 => "\x71",
     0x00000072 => "\x72",
     0x00000073 => "\x73",
     0x00000074 => "\x74",
     0x00000075 => "\x75",
     0x00000076 => "\x76",
     0x00000077 => "\x77",
     0x00000078 => "\x78",
     0x00000079 => "\x79",
     0x0000007a => "\x7a",
     0x0000007b => "\x7b",
     0x0000007c => "\x7c",
     0x0000007d => "\x7d",
     0x0000007e => "\x7e",
     0x0000007f => "\x7f",
     0x00000080 => "\x80",
     0x00000081 => "\x81",
     0x00000082 => "\x82",
     0x00000083 => "\x83",
     0x00000084 => "\x84",
     0x00000085 => "\x85",
     0x00000086 => "\x86",
     0x00000087 => "\x87",
     0x00000088 => "\x88",
     0x00000089 => "\x89",
     0x0000008a => "\x8a",
     0x0000008b => "\x8b",
     0x0000008c => "\x8c",
     0x0000008d => "\x8d",
     0x0000008e => "\x8e",
     0x0000008f => "\x8f",
     0x00000090 => "\x90",
     0x00000091 => "\x91",
     0x00000092 => "\x92",
     0x00000093 => "\x93",
     0x00000094 => "\x94",
     0x00000095 => "\x95",
     0x00000096 => "\x96",
     0x00000097 => "\x97",
     0x00000098 => "\x98",
     0x00000099 => "\x99",
     0x0000009a => "\x9a",
     0x0000009b => "\x9b",
     0x0000009c => "\x9c",
     0x0000009d => "\x9d",
     0x0000009e => "\x9e",
     0x0000009f => "\x9f",
     0x00002500 => "\xd1",
     0x00002502 => "\xd0",
     0x0000250c => "\xd2",
     0x00002510 => "\xd3",
     0x00002514 => "\xd4",
     0x00002518 => "\xd5",
     0x0000251c => "\xd6",
     0x00002524 => "\xd7",
     0x0000252c => "\xd8",
     0x00002534 => "\xd9",
     0x0000253c => "\xda",
     0x00002550 => "\xc1",
     0x00002551 => "\xc0",
     0x00002554 => "\xc2",
     0x00002557 => "\xc3",
     0x0000255a => "\xc4",
     0x0000255d => "\xc5",
     0x00002560 => "\xc6",
     0x00002563 => "\xc7",
     0x00002566 => "\xc8",
     0x00002569 => "\xc9",
     0x0000256c => "\xca",
     0x00002584 => "\xcc",
     0x00002588 => "\xcd",
     0x00002591 => "\xdb",
     0x00002592 => "\xdc",
     0x00002593 => "\xdd",
     0x000025aa => "\xce",
     0x0000e019 => "\xcb",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::ISO_10367_BOX - Conversion routines for ISO_10367_BOX
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for ISO_10367-BOX.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
   source: ECMA registry
  alias ISO-IR-155
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  00000004 | END OF TRANSMISSION (EOT)
     05 |  00000005 | ENQUIRY (ENQ)
     06 |  00000006 | ACKNOWLEDGE (ACK)
     07 |  00000007 | BELL (BEL)
     08 |  00000008 | BACKSPACE (BS)
     09 |  00000009 | CHARACTER TABULATION (HT)
     0A |  0000000A | LINE FEED (LF)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  00000014 | DEVICE CONTROL FOUR (DC4)
     15 |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     16 |  00000016 | SYNCHRONOUS IDLE (SYN)
     17 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  0000001A | SUBSTITUTE (SUB)
     1B |  0000001B | ESCAPE (ESC)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000020 | SPACE
     21 |  00000021 | EXCLAMATION MARK
     22 |  00000022 | QUOTATION MARK
     23 |  00000023 | NUMBER SIGN
     24 |  00000024 | DOLLAR SIGN
     25 |  00000025 | PERCENT SIGN
     26 |  00000026 | AMPERSAND
     27 |  00000027 | APOSTROPHE
     28 |  00000028 | LEFT PARENTHESIS
     29 |  00000029 | RIGHT PARENTHESIS
     2A |  0000002A | ASTERISK
     2B |  0000002B | PLUS SIGN
     2C |  0000002C | COMMA
     2D |  0000002D | HYPHEN-MINUS
     2E |  0000002E | FULL STOP
     2F |  0000002F | SOLIDUS
     30 |  00000030 | DIGIT ZERO
     31 |  00000031 | DIGIT ONE
     32 |  00000032 | DIGIT TWO
     33 |  00000033 | DIGIT THREE
     34 |  00000034 | DIGIT FOUR
     35 |  00000035 | DIGIT FIVE
     36 |  00000036 | DIGIT SIX
     37 |  00000037 | DIGIT SEVEN
     38 |  00000038 | DIGIT EIGHT
     39 |  00000039 | DIGIT NINE
     3A |  0000003A | COLON
     3B |  0000003B | SEMICOLON
     3C |  0000003C | LESS-THAN SIGN
     3D |  0000003D | EQUALS SIGN
     3E |  0000003E | GREATER-THAN SIGN
     3F |  0000003F | QUESTION MARK
     40 |  00000040 | COMMERCIAL AT
     41 |  00000041 | LATIN CAPITAL LETTER A
     42 |  00000042 | LATIN CAPITAL LETTER B
     43 |  00000043 | LATIN CAPITAL LETTER C
     44 |  00000044 | LATIN CAPITAL LETTER D
     45 |  00000045 | LATIN CAPITAL LETTER E
     46 |  00000046 | LATIN CAPITAL LETTER F
     47 |  00000047 | LATIN CAPITAL LETTER G
     48 |  00000048 | LATIN CAPITAL LETTER H
     49 |  00000049 | LATIN CAPITAL LETTER I
     4A |  0000004A | LATIN CAPITAL LETTER J
     4B |  0000004B | LATIN CAPITAL LETTER K
     4C |  0000004C | LATIN CAPITAL LETTER L
     4D |  0000004D | LATIN CAPITAL LETTER M
     4E |  0000004E | LATIN CAPITAL LETTER N
     4F |  0000004F | LATIN CAPITAL LETTER O
     50 |  00000050 | LATIN CAPITAL LETTER P
     51 |  00000051 | LATIN CAPITAL LETTER Q
     52 |  00000052 | LATIN CAPITAL LETTER R
     53 |  00000053 | LATIN CAPITAL LETTER S
     54 |  00000054 | LATIN CAPITAL LETTER T
     55 |  00000055 | LATIN CAPITAL LETTER U
     56 |  00000056 | LATIN CAPITAL LETTER V
     57 |  00000057 | LATIN CAPITAL LETTER W
     58 |  00000058 | LATIN CAPITAL LETTER X
     59 |  00000059 | LATIN CAPITAL LETTER Y
     5A |  0000005A | LATIN CAPITAL LETTER Z
     5B |  0000005B | LEFT SQUARE BRACKET
     5C |  0000005C | REVERSE SOLIDUS
     5D |  0000005D | RIGHT SQUARE BRACKET
     5E |  0000005E | CIRCUMFLEX ACCENT
     5F |  0000005F | LOW LINE
     60 |  00000060 | GRAVE ACCENT
     61 |  00000061 | LATIN SMALL LETTER A
     62 |  00000062 | LATIN SMALL LETTER B
     63 |  00000063 | LATIN SMALL LETTER C
     64 |  00000064 | LATIN SMALL LETTER D
     65 |  00000065 | LATIN SMALL LETTER E
     66 |  00000066 | LATIN SMALL LETTER F
     67 |  00000067 | LATIN SMALL LETTER G
     68 |  00000068 | LATIN SMALL LETTER H
     69 |  00000069 | LATIN SMALL LETTER I
     6A |  0000006A | LATIN SMALL LETTER J
     6B |  0000006B | LATIN SMALL LETTER K
     6C |  0000006C | LATIN SMALL LETTER L
     6D |  0000006D | LATIN SMALL LETTER M
     6E |  0000006E | LATIN SMALL LETTER N
     6F |  0000006F | LATIN SMALL LETTER O
     70 |  00000070 | LATIN SMALL LETTER P
     71 |  00000071 | LATIN SMALL LETTER Q
     72 |  00000072 | LATIN SMALL LETTER R
     73 |  00000073 | LATIN SMALL LETTER S
     74 |  00000074 | LATIN SMALL LETTER T
     75 |  00000075 | LATIN SMALL LETTER U
     76 |  00000076 | LATIN SMALL LETTER V
     77 |  00000077 | LATIN SMALL LETTER W
     78 |  00000078 | LATIN SMALL LETTER X
     79 |  00000079 | LATIN SMALL LETTER Y
     7A |  0000007A | LATIN SMALL LETTER Z
     7B |  0000007B | LEFT CURLY BRACKET
     7C |  0000007C | VERTICAL LINE
     7D |  0000007D | RIGHT CURLY BRACKET
     7E |  0000007E | TILDE
     7F |  0000007F | DELETE (DEL)
     80 |  00000080 | PADDING CHARACTER (PAD)
     81 |  00000081 | HIGH OCTET PRESET (HOP)
     82 |  00000082 | BREAK PERMITTED HERE (BPH)
     83 |  00000083 | NO BREAK HERE (NBH)
     84 |  00000084 | INDEX (IND)
     85 |  00000085 | NEXT LINE (NEL)
     86 |  00000086 | START OF SELECTED AREA (SSA)
     87 |  00000087 | END OF SELECTED AREA (ESA)
     88 |  00000088 | CHARACTER TABULATION SET (HTS)
     89 |  00000089 | CHARACTER TABULATION WITH JUSTIFICATION (HTJ)
     8A |  0000008A | LINE TABULATION SET (VTS)
     8B |  0000008B | PARTIAL LINE FORWARD (PLD)
     8C |  0000008C | PARTIAL LINE BACKWARD (PLU)
     8D |  0000008D | REVERSE LINE FEED (RI)
     8E |  0000008E | SINGLE-SHIFT TWO (SS2)
     8F |  0000008F | SINGLE-SHIFT THREE (SS3)
     90 |  00000090 | DEVICE CONTROL STRING (DCS)
     91 |  00000091 | PRIVATE USE ONE (PU1)
     92 |  00000092 | PRIVATE USE TWO (PU2)
     93 |  00000093 | SET TRANSMIT STATE (STS)
     94 |  00000094 | CANCEL CHARACTER (CCH)
     95 |  00000095 | MESSAGE WAITING (MW)
     96 |  00000096 | START OF GUARDED AREA (SPA)
     97 |  00000097 | END OF GUARDED AREA (EPA)
     98 |  00000098 | START OF STRING (SOS)
     99 |  00000099 | SINGLE GRAPHIC CHARACTER INTRODUCER (SGCI)
     9A |  0000009A | SINGLE CHARACTER INTRODUCER (SCI)
     9B |  0000009B | CONTROL SEQUENCE INTRODUCER (CSI)
     9C |  0000009C | STRING TERMINATOR (ST)
     9D |  0000009D | OPERATING SYSTEM COMMAND (OSC)
     9E |  0000009E | PRIVACY MESSAGE (PM)
     9F |  0000009F | APPLICATION PROGRAM COMMAND (APC)
     C0 |  00002551 | BOX DRAWINGS DOUBLE VERTICAL
     C1 |  00002550 | BOX DRAWINGS DOUBLE HORIZONTAL
     C2 |  00002554 | BOX DRAWINGS DOUBLE DOWN AND RIGHT
     C3 |  00002557 | BOX DRAWINGS DOUBLE DOWN AND LEFT
     C4 |  0000255A | BOX DRAWINGS DOUBLE UP AND RIGHT
     C5 |  0000255D | BOX DRAWINGS DOUBLE UP AND LEFT
     C6 |  00002560 | BOX DRAWINGS DOUBLE VERTICAL AND RIGHT
     C7 |  00002563 | BOX DRAWINGS DOUBLE VERTICAL AND LEFT
     C8 |  00002566 | BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL
     C9 |  00002569 | BOX DRAWINGS DOUBLE UP AND HORIZONTAL
     CA |  0000256C | BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL
     CB |  0000E019 | Unit space B E<lt>ISO-IR-8-1_60E<gt>
     CC |  00002584 | LOWER HALF BLOCK
     CD |  00002588 | FULL BLOCK
     CE |  000025AA | BLACK SMALL SQUARE
     D0 |  00002502 | BOX DRAWINGS LIGHT VERTICAL
     D1 |  00002500 | BOX DRAWINGS LIGHT HORIZONTAL
     D2 |  0000250C | BOX DRAWINGS LIGHT DOWN AND RIGHT
     D3 |  00002510 | BOX DRAWINGS LIGHT DOWN AND LEFT
     D4 |  00002514 | BOX DRAWINGS LIGHT UP AND RIGHT
     D5 |  00002518 | BOX DRAWINGS LIGHT UP AND LEFT
     D6 |  0000251C | BOX DRAWINGS LIGHT VERTICAL AND RIGHT
     D7 |  00002524 | BOX DRAWINGS LIGHT VERTICAL AND LEFT
     D8 |  0000252C | BOX DRAWINGS LIGHT DOWN AND HORIZONTAL
     D9 |  00002534 | BOX DRAWINGS LIGHT UP AND HORIZONTAL
     DA |  0000253C | BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL
     DB |  00002591 | LIGHT SHADE
     DC |  00002592 | MEDIUM SHADE
     DD |  00002593 | DARK SHADE
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/ISO_2033_1983.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for ISO_2033-1983.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::ISO_2033_1983;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x0004,
     0x0005,
     0x0006,
     0x0007,
     0x0008,
     0x0009,
     0x000a,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x0014,
     0x0015,
     0x0016,
     0x0017,
     0x0018,
     0x0019,
     0x001a,
     0x001b,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0020,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x2446,
     0x2447,
     0x2448,
     0x2449,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x007f,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\x04",
     "\x05",
     "\x06",
     "\x07",
     "\x08",
     "\x09",
     "\x0a",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\x14",
     "\x15",
     "\x16",
     "\x17",
     "\x18",
     "\x19",
     "\x1a",
     "\x1b",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\x20",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\xe2\x91\x86",
     "\xe2\x91\x87",
     "\xe2\x91\x88",
     "\xe2\x91\x89",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x7f",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x04",
     0x00000005 => "\x05",
     0x00000006 => "\x06",
     0x00000007 => "\x07",
     0x00000008 => "\x08",
     0x00000009 => "\x09",
     0x0000000a => "\x0a",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x14",
     0x00000015 => "\x15",
     0x00000016 => "\x16",
     0x00000017 => "\x17",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x1a",
     0x0000001b => "\x1b",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x20",
     0x00000030 => "\x30",
     0x00000031 => "\x31",
     0x00000032 => "\x32",
     0x00000033 => "\x33",
     0x00000034 => "\x34",
     0x00000035 => "\x35",
     0x00000036 => "\x36",
     0x00000037 => "\x37",
     0x00000038 => "\x38",
     0x00000039 => "\x39",
     0x0000007f => "\x7f",
     0x00002446 => "\x3a",
     0x00002447 => "\x3b",
     0x00002448 => "\x3c",
     0x00002449 => "\x3d",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::ISO_2033_1983 - Conversion routines for ISO_2033_1983
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for ISO_2033-1983.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
  repertoiremap: mnemonic,ds
   source: ECMA registry
  alias ISO-IR-98
  alias E13B
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  00000004 | END OF TRANSMISSION (EOT)
     05 |  00000005 | ENQUIRY (ENQ)
     06 |  00000006 | ACKNOWLEDGE (ACK)
     07 |  00000007 | BELL (BEL)
     08 |  00000008 | BACKSPACE (BS)
     09 |  00000009 | CHARACTER TABULATION (HT)
     0A |  0000000A | LINE FEED (LF)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  00000014 | DEVICE CONTROL FOUR (DC4)
     15 |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     16 |  00000016 | SYNCHRONOUS IDLE (SYN)
     17 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  0000001A | SUBSTITUTE (SUB)
     1B |  0000001B | ESCAPE (ESC)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000020 | SPACE
     30 |  00000030 | DIGIT ZERO
     31 |  00000031 | DIGIT ONE
     32 |  00000032 | DIGIT TWO
     33 |  00000033 | DIGIT THREE
     34 |  00000034 | DIGIT FOUR
     35 |  00000035 | DIGIT FIVE
     36 |  00000036 | DIGIT SIX
     37 |  00000037 | DIGIT SEVEN
     38 |  00000038 | DIGIT EIGHT
     39 |  00000039 | DIGIT NINE
     3A |  00002446 | OCR BRANCH BANK IDENTIFICATION
     3B |  00002447 | OCR AMOUNT OF CHECK
     3C |  00002448 | OCR DASH
     3D |  00002449 | OCR CUSTOMER ACCOUNT NUMBER
     7F |  0000007F | DELETE (DEL)
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/ISO_5427.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for ISO_5427.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::ISO_5427;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x0004,
     0x0005,
     0x0006,
     0x0007,
     0x0008,
     0x0009,
     0x000a,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x0014,
     0x0015,
     0x0016,
     0x0017,
     0x0018,
     0x0019,
     0x001a,
     0x001b,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0020,
     0x0021,
     0x0022,
     0x0023,
     0x00a4,
     0x0025,
     0x0026,
     0x0027,
     0x0028,
     0x0029,
     0x002a,
     0x002b,
     0x002c,
     0x002d,
     0x002e,
     0x002f,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x003a,
     0x003b,
     0x003c,
     0x003d,
     0x003e,
     0x003f,
     0x044e,
     0x0430,
     0x0431,
     0x0446,
     0x0434,
     0x0435,
     0x0444,
     0x0433,
     0x0445,
     0x0438,
     0x0439,
     0x043a,
     0x043b,
     0x043c,
     0x043d,
     0x043e,
     0x043f,
     0x044f,
     0x0440,
     0x0441,
     0x0442,
     0x0443,
     0x0436,
     0x0432,
     0x044c,
     0x044b,
     0x0437,
     0x0448,
     0x044d,
     0x0449,
     0x0447,
     0x044a,
     0x042e,
     0x0410,
     0x0411,
     0x0426,
     0x0414,
     0x0415,
     0x0424,
     0x0413,
     0x0425,
     0x0418,
     0x0419,
     0x041a,
     0x041b,
     0x041c,
     0x041d,
     0x041e,
     0x041f,
     0x042f,
     0x0420,
     0x0421,
     0x0422,
     0x0423,
     0x0416,
     0x0412,
     0x042c,
     0x042b,
     0x0417,
     0x0428,
     0x042d,
     0x0429,
     0x0427,
     0x007f,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\x04",
     "\x05",
     "\x06",
     "\x07",
     "\x08",
     "\x09",
     "\x0a",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\x14",
     "\x15",
     "\x16",
     "\x17",
     "\x18",
     "\x19",
     "\x1a",
     "\x1b",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\x20",
     "\x21",
     "\x22",
     "\x23",
     "\xc2\xa4",
     "\x25",
     "\x26",
     "\x27",
     "\x28",
     "\x29",
     "\x2a",
     "\x2b",
     "\x2c",
     "\x2d",
     "\x2e",
     "\x2f",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\x3a",
     "\x3b",
     "\x3c",
     "\x3d",
     "\x3e",
     "\x3f",
     "\xd1\x8e",
     "\xd0\xb0",
     "\xd0\xb1",
     "\xd1\x86",
     "\xd0\xb4",
     "\xd0\xb5",
     "\xd1\x84",
     "\xd0\xb3",
     "\xd1\x85",
     "\xd0\xb8",
     "\xd0\xb9",
     "\xd0\xba",
     "\xd0\xbb",
     "\xd0\xbc",
     "\xd0\xbd",
     "\xd0\xbe",
     "\xd0\xbf",
     "\xd1\x8f",
     "\xd1\x80",
     "\xd1\x81",
     "\xd1\x82",
     "\xd1\x83",
     "\xd0\xb6",
     "\xd0\xb2",
     "\xd1\x8c",
     "\xd1\x8b",
     "\xd0\xb7",
     "\xd1\x88",
     "\xd1\x8d",
     "\xd1\x89",
     "\xd1\x87",
     "\xd1\x8a",
     "\xd0\xae",
     "\xd0\x90",
     "\xd0\x91",
     "\xd0\xa6",
     "\xd0\x94",
     "\xd0\x95",
     "\xd0\xa4",
     "\xd0\x93",
     "\xd0\xa5",
     "\xd0\x98",
     "\xd0\x99",
     "\xd0\x9a",
     "\xd0\x9b",
     "\xd0\x9c",
     "\xd0\x9d",
     "\xd0\x9e",
     "\xd0\x9f",
     "\xd0\xaf",
     "\xd0\xa0",
     "\xd0\xa1",
     "\xd0\xa2",
     "\xd0\xa3",
     "\xd0\x96",
     "\xd0\x92",
     "\xd0\xac",
     "\xd0\xab",
     "\xd0\x97",
     "\xd0\xa8",
     "\xd0\xad",
     "\xd0\xa9",
     "\xd0\xa7",
     "\x7f",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x04",
     0x00000005 => "\x05",
     0x00000006 => "\x06",
     0x00000007 => "\x07",
     0x00000008 => "\x08",
     0x00000009 => "\x09",
     0x0000000a => "\x0a",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x14",
     0x00000015 => "\x15",
     0x00000016 => "\x16",
     0x00000017 => "\x17",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x1a",
     0x0000001b => "\x1b",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x20",
     0x00000021 => "\x21",
     0x00000022 => "\x22",
     0x00000023 => "\x23",
     0x00000025 => "\x25",
     0x00000026 => "\x26",
     0x00000027 => "\x27",
     0x00000028 => "\x28",
     0x00000029 => "\x29",
     0x0000002a => "\x2a",
     0x0000002b => "\x2b",
     0x0000002c => "\x2c",
     0x0000002d => "\x2d",
     0x0000002e => "\x2e",
     0x0000002f => "\x2f",
     0x00000030 => "\x30",
     0x00000031 => "\x31",
     0x00000032 => "\x32",
     0x00000033 => "\x33",
     0x00000034 => "\x34",
     0x00000035 => "\x35",
     0x00000036 => "\x36",
     0x00000037 => "\x37",
     0x00000038 => "\x38",
     0x00000039 => "\x39",
     0x0000003a => "\x3a",
     0x0000003b => "\x3b",
     0x0000003c => "\x3c",
     0x0000003d => "\x3d",
     0x0000003e => "\x3e",
     0x0000003f => "\x3f",
     0x0000007f => "\x7f",
     0x000000a4 => "\x24",
     0x00000410 => "\x61",
     0x00000411 => "\x62",
     0x00000412 => "\x77",
     0x00000413 => "\x67",
     0x00000414 => "\x64",
     0x00000415 => "\x65",
     0x00000416 => "\x76",
     0x00000417 => "\x7a",
     0x00000418 => "\x69",
     0x00000419 => "\x6a",
     0x0000041a => "\x6b",
     0x0000041b => "\x6c",
     0x0000041c => "\x6d",
     0x0000041d => "\x6e",
     0x0000041e => "\x6f",
     0x0000041f => "\x70",
     0x00000420 => "\x72",
     0x00000421 => "\x73",
     0x00000422 => "\x74",
     0x00000423 => "\x75",
     0x00000424 => "\x66",
     0x00000425 => "\x68",
     0x00000426 => "\x63",
     0x00000427 => "\x7e",
     0x00000428 => "\x7b",
     0x00000429 => "\x7d",
     0x0000042b => "\x79",
     0x0000042c => "\x78",
     0x0000042d => "\x7c",
     0x0000042e => "\x60",
     0x0000042f => "\x71",
     0x00000430 => "\x41",
     0x00000431 => "\x42",
     0x00000432 => "\x57",
     0x00000433 => "\x47",
     0x00000434 => "\x44",
     0x00000435 => "\x45",
     0x00000436 => "\x56",
     0x00000437 => "\x5a",
     0x00000438 => "\x49",
     0x00000439 => "\x4a",
     0x0000043a => "\x4b",
     0x0000043b => "\x4c",
     0x0000043c => "\x4d",
     0x0000043d => "\x4e",
     0x0000043e => "\x4f",
     0x0000043f => "\x50",
     0x00000440 => "\x52",
     0x00000441 => "\x53",
     0x00000442 => "\x54",
     0x00000443 => "\x55",
     0x00000444 => "\x46",
     0x00000445 => "\x48",
     0x00000446 => "\x43",
     0x00000447 => "\x5e",
     0x00000448 => "\x5b",
     0x00000449 => "\x5d",
     0x0000044a => "\x5f",
     0x0000044b => "\x59",
     0x0000044c => "\x58",
     0x0000044d => "\x5c",
     0x0000044e => "\x40",
     0x0000044f => "\x51",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::ISO_5427 - Conversion routines for ISO_5427
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for ISO_5427.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
   source: ECMA registry
  alias ISO-IR-37
  alias KOI-7
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  00000004 | END OF TRANSMISSION (EOT)
     05 |  00000005 | ENQUIRY (ENQ)
     06 |  00000006 | ACKNOWLEDGE (ACK)
     07 |  00000007 | BELL (BEL)
     08 |  00000008 | BACKSPACE (BS)
     09 |  00000009 | CHARACTER TABULATION (HT)
     0A |  0000000A | LINE FEED (LF)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  00000014 | DEVICE CONTROL FOUR (DC4)
     15 |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     16 |  00000016 | SYNCHRONOUS IDLE (SYN)
     17 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  0000001A | SUBSTITUTE (SUB)
     1B |  0000001B | ESCAPE (ESC)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000020 | SPACE
     21 |  00000021 | EXCLAMATION MARK
     22 |  00000022 | QUOTATION MARK
     23 |  00000023 | NUMBER SIGN
     24 |  000000A4 | CURRENCY SIGN
     25 |  00000025 | PERCENT SIGN
     26 |  00000026 | AMPERSAND
     27 |  00000027 | APOSTROPHE
     28 |  00000028 | LEFT PARENTHESIS
     29 |  00000029 | RIGHT PARENTHESIS
     2A |  0000002A | ASTERISK
     2B |  0000002B | PLUS SIGN
     2C |  0000002C | COMMA
     2D |  0000002D | HYPHEN-MINUS
     2E |  0000002E | FULL STOP
     2F |  0000002F | SOLIDUS
     30 |  00000030 | DIGIT ZERO
     31 |  00000031 | DIGIT ONE
     32 |  00000032 | DIGIT TWO
     33 |  00000033 | DIGIT THREE
     34 |  00000034 | DIGIT FOUR
     35 |  00000035 | DIGIT FIVE
     36 |  00000036 | DIGIT SIX
     37 |  00000037 | DIGIT SEVEN
     38 |  00000038 | DIGIT EIGHT
     39 |  00000039 | DIGIT NINE
     3A |  0000003A | COLON
     3B |  0000003B | SEMICOLON
     3C |  0000003C | LESS-THAN SIGN
     3D |  0000003D | EQUALS SIGN
     3E |  0000003E | GREATER-THAN SIGN
     3F |  0000003F | QUESTION MARK
     40 |  0000044E | CYRILLIC SMALL LETTER YU
     41 |  00000430 | CYRILLIC SMALL LETTER A
     42 |  00000431 | CYRILLIC SMALL LETTER BE
     43 |  00000446 | CYRILLIC SMALL LETTER TSE
     44 |  00000434 | CYRILLIC SMALL LETTER DE
     45 |  00000435 | CYRILLIC SMALL LETTER IE
     46 |  00000444 | CYRILLIC SMALL LETTER EF
     47 |  00000433 | CYRILLIC SMALL LETTER GHE
     48 |  00000445 | CYRILLIC SMALL LETTER HA
     49 |  00000438 | CYRILLIC SMALL LETTER I
     4A |  00000439 | CYRILLIC SMALL LETTER SHORT I
     4B |  0000043A | CYRILLIC SMALL LETTER KA
     4C |  0000043B | CYRILLIC SMALL LETTER EL
     4D |  0000043C | CYRILLIC SMALL LETTER EM
     4E |  0000043D | CYRILLIC SMALL LETTER EN
     4F |  0000043E | CYRILLIC SMALL LETTER O
     50 |  0000043F | CYRILLIC SMALL LETTER PE
     51 |  0000044F | CYRILLIC SMALL LETTER YA
     52 |  00000440 | CYRILLIC SMALL LETTER ER
     53 |  00000441 | CYRILLIC SMALL LETTER ES
     54 |  00000442 | CYRILLIC SMALL LETTER TE
     55 |  00000443 | CYRILLIC SMALL LETTER U
     56 |  00000436 | CYRILLIC SMALL LETTER ZHE
     57 |  00000432 | CYRILLIC SMALL LETTER VE
     58 |  0000044C | CYRILLIC SMALL LETTER SOFT SIGN
     59 |  0000044B | CYRILLIC SMALL LETTER YERU
     5A |  00000437 | CYRILLIC SMALL LETTER ZE
     5B |  00000448 | CYRILLIC SMALL LETTER SHA
     5C |  0000044D | CYRILLIC SMALL LETTER E
     5D |  00000449 | CYRILLIC SMALL LETTER SHCHA
     5E |  00000447 | CYRILLIC SMALL LETTER CHE
     5F |  0000044A | CYRILLIC SMALL LETTER HARD SIGN
     60 |  0000042E | CYRILLIC CAPITAL LETTER YU
     61 |  00000410 | CYRILLIC CAPITAL LETTER A
     62 |  00000411 | CYRILLIC CAPITAL LETTER BE
     63 |  00000426 | CYRILLIC CAPITAL LETTER TSE
     64 |  00000414 | CYRILLIC CAPITAL LETTER DE
     65 |  00000415 | CYRILLIC CAPITAL LETTER IE
     66 |  00000424 | CYRILLIC CAPITAL LETTER EF
     67 |  00000413 | CYRILLIC CAPITAL LETTER GHE
     68 |  00000425 | CYRILLIC CAPITAL LETTER HA
     69 |  00000418 | CYRILLIC CAPITAL LETTER I
     6A |  00000419 | CYRILLIC CAPITAL LETTER SHORT I
     6B |  0000041A | CYRILLIC CAPITAL LETTER KA
     6C |  0000041B | CYRILLIC CAPITAL LETTER EL
     6D |  0000041C | CYRILLIC CAPITAL LETTER EM
     6E |  0000041D | CYRILLIC CAPITAL LETTER EN
     6F |  0000041E | CYRILLIC CAPITAL LETTER O
     70 |  0000041F | CYRILLIC CAPITAL LETTER PE
     71 |  0000042F | CYRILLIC CAPITAL LETTER YA
     72 |  00000420 | CYRILLIC CAPITAL LETTER ER
     73 |  00000421 | CYRILLIC CAPITAL LETTER ES
     74 |  00000422 | CYRILLIC CAPITAL LETTER TE
     75 |  00000423 | CYRILLIC CAPITAL LETTER U
     76 |  00000416 | CYRILLIC CAPITAL LETTER ZHE
     77 |  00000412 | CYRILLIC CAPITAL LETTER VE
     78 |  0000042C | CYRILLIC CAPITAL LETTER SOFT SIGN
     79 |  0000042B | CYRILLIC CAPITAL LETTER YERU
     7A |  00000417 | CYRILLIC CAPITAL LETTER ZE
     7B |  00000428 | CYRILLIC CAPITAL LETTER SHA
     7C |  0000042D | CYRILLIC CAPITAL LETTER E
     7D |  00000429 | CYRILLIC CAPITAL LETTER SHCHA
     7E |  00000427 | CYRILLIC CAPITAL LETTER CHE
     7F |  0000007F | DELETE (DEL)
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/ISO_5427_EXT.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for ISO_5427-EXT.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::ISO_5427_EXT;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x0004,
     0x0005,
     0x0006,
     0x0007,
     0x0008,
     0x0009,
     0x000a,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x0014,
     0x0015,
     0x0016,
     0x0017,
     0x0018,
     0x0019,
     0x001a,
     0x001b,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0020,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x0491,
     0x0452,
     0x0453,
     0x0454,
     0x0451,
     0x0455,
     0x0456,
     0x0457,
     0x0458,
     0x0459,
     0x045a,
     0x045b,
     0x045c,
     0x045e,
     0x045f,
     0xfffd,
     0x0463,
     0x0473,
     0x0475,
     0x046b,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x005b,
     0xfffd,
     0x005d,
     0xfffd,
     0x005f,
     0x0490,
     0x0402,
     0x0403,
     0x0404,
     0x0401,
     0x0405,
     0x0406,
     0x0407,
     0x0408,
     0x0409,
     0x040a,
     0x040b,
     0x040c,
     0x040e,
     0x040f,
     0x042a,
     0x0462,
     0x0472,
     0x0474,
     0x046a,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x007f,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\x04",
     "\x05",
     "\x06",
     "\x07",
     "\x08",
     "\x09",
     "\x0a",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\x14",
     "\x15",
     "\x16",
     "\x17",
     "\x18",
     "\x19",
     "\x1a",
     "\x1b",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\x20",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xd2\x91",
     "\xd1\x92",
     "\xd1\x93",
     "\xd1\x94",
     "\xd1\x91",
     "\xd1\x95",
     "\xd1\x96",
     "\xd1\x97",
     "\xd1\x98",
     "\xd1\x99",
     "\xd1\x9a",
     "\xd1\x9b",
     "\xd1\x9c",
     "\xd1\x9e",
     "\xd1\x9f",
     "\xef\xbf\xbd",
     "\xd1\xa3",
     "\xd1\xb3",
     "\xd1\xb5",
     "\xd1\xab",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x5b",
     "\xef\xbf\xbd",
     "\x5d",
     "\xef\xbf\xbd",
     "\x5f",
     "\xd2\x90",
     "\xd0\x82",
     "\xd0\x83",
     "\xd0\x84",
     "\xd0\x81",
     "\xd0\x85",
     "\xd0\x86",
     "\xd0\x87",
     "\xd0\x88",
     "\xd0\x89",
     "\xd0\x8a",
     "\xd0\x8b",
     "\xd0\x8c",
     "\xd0\x8e",
     "\xd0\x8f",
     "\xd0\xaa",
     "\xd1\xa2",
     "\xd1\xb2",
     "\xd1\xb4",
     "\xd1\xaa",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x7f",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x04",
     0x00000005 => "\x05",
     0x00000006 => "\x06",
     0x00000007 => "\x07",
     0x00000008 => "\x08",
     0x00000009 => "\x09",
     0x0000000a => "\x0a",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x14",
     0x00000015 => "\x15",
     0x00000016 => "\x16",
     0x00000017 => "\x17",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x1a",
     0x0000001b => "\x1b",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x20",
     0x0000005b => "\x5b",
     0x0000005d => "\x5d",
     0x0000005f => "\x5f",
     0x0000007f => "\x7f",
     0x00000401 => "\x64",
     0x00000402 => "\x61",
     0x00000403 => "\x62",
     0x00000404 => "\x63",
     0x00000405 => "\x65",
     0x00000406 => "\x66",
     0x00000407 => "\x67",
     0x00000408 => "\x68",
     0x00000409 => "\x69",
     0x0000040a => "\x6a",
     0x0000040b => "\x6b",
     0x0000040c => "\x6c",
     0x0000040e => "\x6d",
     0x0000040f => "\x6e",
     0x0000042a => "\x6f",
     0x00000451 => "\x44",
     0x00000452 => "\x41",
     0x00000453 => "\x42",
     0x00000454 => "\x43",
     0x00000455 => "\x45",
     0x00000456 => "\x46",
     0x00000457 => "\x47",
     0x00000458 => "\x48",
     0x00000459 => "\x49",
     0x0000045a => "\x4a",
     0x0000045b => "\x4b",
     0x0000045c => "\x4c",
     0x0000045e => "\x4d",
     0x0000045f => "\x4e",
     0x00000462 => "\x70",
     0x00000463 => "\x50",
     0x0000046a => "\x73",
     0x0000046b => "\x53",
     0x00000472 => "\x71",
     0x00000473 => "\x51",
     0x00000474 => "\x72",
     0x00000475 => "\x52",
     0x00000490 => "\x60",
     0x00000491 => "\x40",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::ISO_5427_EXT - Conversion routines for ISO_5427_EXT
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for ISO_5427-EXT.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
  repertoiremap: mnemonic,ds
   source: ECMA registry
  alias ISO-IR-54
  alias ISO_5427:1981
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  00000004 | END OF TRANSMISSION (EOT)
     05 |  00000005 | ENQUIRY (ENQ)
     06 |  00000006 | ACKNOWLEDGE (ACK)
     07 |  00000007 | BELL (BEL)
     08 |  00000008 | BACKSPACE (BS)
     09 |  00000009 | CHARACTER TABULATION (HT)
     0A |  0000000A | LINE FEED (LF)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  00000014 | DEVICE CONTROL FOUR (DC4)
     15 |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     16 |  00000016 | SYNCHRONOUS IDLE (SYN)
     17 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  0000001A | SUBSTITUTE (SUB)
     1B |  0000001B | ESCAPE (ESC)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000020 | SPACE
     40 |  00000491 | CYRILLIC SMALL LETTER GHE WITH UPTURN
     41 |  00000452 | CYRILLIC SMALL LETTER DJE
     42 |  00000453 | CYRILLIC SMALL LETTER GJE
     43 |  00000454 | CYRILLIC SMALL LETTER UKRAINIAN IE
     44 |  00000451 | CYRILLIC SMALL LETTER IO
     45 |  00000455 | CYRILLIC SMALL LETTER DZE
     46 |  00000456 | CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I
     47 |  00000457 | CYRILLIC SMALL LETTER YI
     48 |  00000458 | CYRILLIC SMALL LETTER JE
     49 |  00000459 | CYRILLIC SMALL LETTER LJE
     4A |  0000045A | CYRILLIC SMALL LETTER NJE
     4B |  0000045B | CYRILLIC SMALL LETTER TSHE
     4C |  0000045C | CYRILLIC SMALL LETTER KJE
     4D |  0000045E | CYRILLIC SMALL LETTER SHORT U
     4E |  0000045F | CYRILLIC SMALL LETTER DZHE
     50 |  00000463 | CYRILLIC SMALL LETTER YAT
     51 |  00000473 | CYRILLIC SMALL LETTER FITA
     52 |  00000475 | CYRILLIC SMALL LETTER IZHITSA
     53 |  0000046B | CYRILLIC SMALL LETTER BIG YUS
     5B |  0000005B | LEFT SQUARE BRACKET
     5D |  0000005D | RIGHT SQUARE BRACKET
     5F |  0000005F | LOW LINE
     60 |  00000490 | CYRILLIC CAPITAL LETTER GHE WITH UPTURN
     61 |  00000402 | CYRILLIC CAPITAL LETTER DJE
     62 |  00000403 | CYRILLIC CAPITAL LETTER GJE
     63 |  00000404 | CYRILLIC CAPITAL LETTER UKRAINIAN IE
     64 |  00000401 | CYRILLIC CAPITAL LETTER IO
     65 |  00000405 | CYRILLIC CAPITAL LETTER DZE
     66 |  00000406 | CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I
     67 |  00000407 | CYRILLIC CAPITAL LETTER YI
     68 |  00000408 | CYRILLIC CAPITAL LETTER JE
     69 |  00000409 | CYRILLIC CAPITAL LETTER LJE
     6A |  0000040A | CYRILLIC CAPITAL LETTER NJE
     6B |  0000040B | CYRILLIC CAPITAL LETTER TSHE
     6C |  0000040C | CYRILLIC CAPITAL LETTER KJE
     6D |  0000040E | CYRILLIC CAPITAL LETTER SHORT U
     6E |  0000040F | CYRILLIC CAPITAL LETTER DZHE
     6F |  0000042A | CYRILLIC CAPITAL LETTER HARD SIGN
     70 |  00000462 | CYRILLIC CAPITAL LETTER YAT
     71 |  00000472 | CYRILLIC CAPITAL LETTER FITA
     72 |  00000474 | CYRILLIC CAPITAL LETTER IZHITSA
     73 |  0000046A | CYRILLIC CAPITAL LETTER BIG YUS
     7F |  0000007F | DELETE (DEL)
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/ISO_5428.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for ISO_5428.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::ISO_5428;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x0004,
     0x0005,
     0x0006,
     0x0007,
     0x0008,
     0x0009,
     0x000a,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x0014,
     0x0015,
     0x0016,
     0x0017,
     0x0018,
     0x0019,
     0x001a,
     0x001b,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0020,
     0xe002,
     0xe003,
     0xe009,
     0xe005,
     0xe012,
     0xe013,
     0xe014,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00ab,
     0x00bb,
     0x201d,
     0x201c,
     0x0374,
     0x0375,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00b7,
     0xfffd,
     0xfffd,
     0xfffd,
     0x003b,
     0xfffd,
     0x0391,
     0x0392,
     0xfffd,
     0x0393,
     0x0394,
     0x0395,
     0x03da,
     0x03dc,
     0x0396,
     0x0397,
     0x0398,
     0x0399,
     0x039a,
     0x039b,
     0x039c,
     0x039d,
     0x039e,
     0x039f,
     0x03a0,
     0x03de,
     0x03a1,
     0x03a3,
     0xfffd,
     0x03a4,
     0x03a5,
     0x03a6,
     0x03a7,
     0x03a8,
     0x03a9,
     0x03e0,
     0xfffd,
     0xfffd,
     0x03b1,
     0x03b2,
     0x03d0,
     0x03b3,
     0x03b4,
     0x03b5,
     0xe01a,
     0xe01b,
     0x03b6,
     0x03b7,
     0x03b8,
     0x03b9,
     0x03ba,
     0x03bb,
     0x03bc,
     0x03bd,
     0x03be,
     0x03bf,
     0x03c0,
     0xe01c,
     0x03c1,
     0x03c3,
     0x03c2,
     0x03c4,
     0x03c5,
     0x03c6,
     0x03c7,
     0x03c8,
     0x03c9,
     0xe01d,
     0x007f,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\x04",
     "\x05",
     "\x06",
     "\x07",
     "\x08",
     "\x09",
     "\x0a",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\x14",
     "\x15",
     "\x16",
     "\x17",
     "\x18",
     "\x19",
     "\x1a",
     "\x1b",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\x20",
     "\xee\x80\x82",
     "\xee\x80\x83",
     "\xee\x80\x89",
     "\xee\x80\x85",
     "\xee\x80\x92",
     "\xee\x80\x93",
     "\xee\x80\x94",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc2\xab",
     "\xc2\xbb",
     "\xe2\x80\x9d",
     "\xe2\x80\x9c",
     "\xcd\xb4",
     "\xcd\xb5",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc2\xb7",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\x3b",
     "\xef\xbf\xbd",
     "\xce\x91",
     "\xce\x92",
     "\xef\xbf\xbd",
     "\xce\x93",
     "\xce\x94",
     "\xce\x95",
     "\xcf\x9a",
     "\xcf\x9c",
     "\xce\x96",
     "\xce\x97",
     "\xce\x98",
     "\xce\x99",
     "\xce\x9a",
     "\xce\x9b",
     "\xce\x9c",
     "\xce\x9d",
     "\xce\x9e",
     "\xce\x9f",
     "\xce\xa0",
     "\xcf\x9e",
     "\xce\xa1",
     "\xce\xa3",
     "\xef\xbf\xbd",
     "\xce\xa4",
     "\xce\xa5",
     "\xce\xa6",
     "\xce\xa7",
     "\xce\xa8",
     "\xce\xa9",
     "\xcf\xa0",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xce\xb1",
     "\xce\xb2",
     "\xcf\x90",
     "\xce\xb3",
     "\xce\xb4",
     "\xce\xb5",
     "\xee\x80\x9a",
     "\xee\x80\x9b",
     "\xce\xb6",
     "\xce\xb7",
     "\xce\xb8",
     "\xce\xb9",
     "\xce\xba",
     "\xce\xbb",
     "\xce\xbc",
     "\xce\xbd",
     "\xce\xbe",
     "\xce\xbf",
     "\xcf\x80",
     "\xee\x80\x9c",
     "\xcf\x81",
     "\xcf\x83",
     "\xcf\x82",
     "\xcf\x84",
     "\xcf\x85",
     "\xcf\x86",
     "\xcf\x87",
     "\xcf\x88",
     "\xcf\x89",
     "\xee\x80\x9d",
     "\x7f",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x04",
     0x00000005 => "\x05",
     0x00000006 => "\x06",
     0x00000007 => "\x07",
     0x00000008 => "\x08",
     0x00000009 => "\x09",
     0x0000000a => "\x0a",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x14",
     0x00000015 => "\x15",
     0x00000016 => "\x16",
     0x00000017 => "\x17",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x1a",
     0x0000001b => "\x1b",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x20",
     0x0000003b => "\x3f",
     0x0000007f => "\x7f",
     0x000000ab => "\x30",
     0x000000b7 => "\x3b",
     0x000000bb => "\x31",
     0x00000374 => "\x34",
     0x00000375 => "\x35",
     0x00000391 => "\x41",
     0x00000392 => "\x42",
     0x00000393 => "\x44",
     0x00000394 => "\x45",
     0x00000395 => "\x46",
     0x00000396 => "\x49",
     0x00000397 => "\x4a",
     0x00000398 => "\x4b",
     0x00000399 => "\x4c",
     0x0000039a => "\x4d",
     0x0000039b => "\x4e",
     0x0000039c => "\x4f",
     0x0000039d => "\x50",
     0x0000039e => "\x51",
     0x0000039f => "\x52",
     0x000003a0 => "\x53",
     0x000003a1 => "\x55",
     0x000003a3 => "\x56",
     0x000003a4 => "\x58",
     0x000003a5 => "\x59",
     0x000003a6 => "\x5a",
     0x000003a7 => "\x5b",
     0x000003a8 => "\x5c",
     0x000003a9 => "\x5d",
     0x000003b1 => "\x61",
     0x000003b2 => "\x62",
     0x000003b3 => "\x64",
     0x000003b4 => "\x65",
     0x000003b5 => "\x66",
     0x000003b6 => "\x69",
     0x000003b7 => "\x6a",
     0x000003b8 => "\x6b",
     0x000003b9 => "\x6c",
     0x000003ba => "\x6d",
     0x000003bb => "\x6e",
     0x000003bc => "\x6f",
     0x000003bd => "\x70",
     0x000003be => "\x71",
     0x000003bf => "\x72",
     0x000003c0 => "\x73",
     0x000003c1 => "\x75",
     0x000003c2 => "\x77",
     0x000003c3 => "\x76",
     0x000003c4 => "\x78",
     0x000003c5 => "\x79",
     0x000003c6 => "\x7a",
     0x000003c7 => "\x7b",
     0x000003c8 => "\x7c",
     0x000003c9 => "\x7d",
     0x000003d0 => "\x63",
     0x000003da => "\x47",
     0x000003dc => "\x48",
     0x000003de => "\x54",
     0x000003e0 => "\x5e",
     0x0000201c => "\x33",
     0x0000201d => "\x32",
     0x0000e002 => "\x21",
     0x0000e003 => "\x22",
     0x0000e005 => "\x24",
     0x0000e009 => "\x23",
     0x0000e012 => "\x25",
     0x0000e013 => "\x26",
     0x0000e014 => "\x27",
     0x0000e01a => "\x67",
     0x0000e01b => "\x68",
     0x0000e01c => "\x74",
     0x0000e01d => "\x7e",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::ISO_5428 - Conversion routines for ISO_5428
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for ISO_5428.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
   source: ECMA registry
  alias ISO-IR-55
  alias ISO_5428:1980
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  00000004 | END OF TRANSMISSION (EOT)
     05 |  00000005 | ENQUIRY (ENQ)
     06 |  00000006 | ACKNOWLEDGE (ACK)
     07 |  00000007 | BELL (BEL)
     08 |  00000008 | BACKSPACE (BS)
     09 |  00000009 | CHARACTER TABULATION (HT)
     0A |  0000000A | LINE FEED (LF)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  00000014 | DEVICE CONTROL FOUR (DC4)
     15 |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     16 |  00000016 | SYNCHRONOUS IDLE (SYN)
     17 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  0000001A | SUBSTITUTE (SUB)
     1B |  0000001B | ESCAPE (ESC)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000020 | SPACE
     21 |  0000E002 | NON-SPACING GRAVE ACCENT E<lt>ISO-IR-103_C1E<gt> (not a real character)
     22 |  0000E003 | NON-SPACING ACUTE ACCENT E<lt>ISO-IR-103_C2E<gt> (not a real character)
     23 |  0000E009 | NON-SPACING DIAERESIS E<lt>ISO-IR-103_C8E<gt> (not a real character)
     24 |  0000E005 | NON-SPACING TILDE E<lt>ISO-IR-103_C4E<gt> (not a real character)
     25 |  0000E012 | GREEK NON-SPACING PSILI PNEUMATA E<lt>ISO-IR-55_25E<gt> (not a real character)
     26 |  0000E013 | GREEK NON-SPACING DASIA PNEUMATA E<lt>ISO-IR-55_26E<gt> (not a real character)
     27 |  0000E014 | GREEK NON-SPACING IOTA BELOW E<lt>ISO-IR-55_27E<gt> (not a real character)
     30 |  000000AB | LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
     31 |  000000BB | RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
     32 |  0000201D | RIGHT DOUBLE QUOTATION MARK
     33 |  0000201C | LEFT DOUBLE QUOTATION MARK
     34 |  00000374 | GREEK NUMERAL SIGN (Dexia keraia)
     35 |  00000375 | GREEK LOWER NUMERAL SIGN (Aristeri keraia)
     3B |  000000B7 | MIDDLE DOT
     3F |  0000003B | SEMICOLON
     41 |  00000391 | GREEK CAPITAL LETTER ALPHA
     42 |  00000392 | GREEK CAPITAL LETTER BETA
     44 |  00000393 | GREEK CAPITAL LETTER GAMMA
     45 |  00000394 | GREEK CAPITAL LETTER DELTA
     46 |  00000395 | GREEK CAPITAL LETTER EPSILON
     47 |  000003DA | GREEK LETTER STIGMA
     48 |  000003DC | GREEK LETTER DIGAMMA
     49 |  00000396 | GREEK CAPITAL LETTER ZETA
     4A |  00000397 | GREEK CAPITAL LETTER ETA
     4B |  00000398 | GREEK CAPITAL LETTER THETA
     4C |  00000399 | GREEK CAPITAL LETTER IOTA
     4D |  0000039A | GREEK CAPITAL LETTER KAPPA
     4E |  0000039B | GREEK CAPITAL LETTER LAMDA
     4F |  0000039C | GREEK CAPITAL LETTER MU
     50 |  0000039D | GREEK CAPITAL LETTER NU
     51 |  0000039E | GREEK CAPITAL LETTER XI
     52 |  0000039F | GREEK CAPITAL LETTER OMICRON
     53 |  000003A0 | GREEK CAPITAL LETTER PI
     54 |  000003DE | GREEK LETTER KOPPA
     55 |  000003A1 | GREEK CAPITAL LETTER RHO
     56 |  000003A3 | GREEK CAPITAL LETTER SIGMA
     58 |  000003A4 | GREEK CAPITAL LETTER TAU
     59 |  000003A5 | GREEK CAPITAL LETTER UPSILON
     5A |  000003A6 | GREEK CAPITAL LETTER PHI
     5B |  000003A7 | GREEK CAPITAL LETTER CHI
     5C |  000003A8 | GREEK CAPITAL LETTER PSI
     5D |  000003A9 | GREEK CAPITAL LETTER OMEGA
     5E |  000003E0 | GREEK LETTER SAMPI
     61 |  000003B1 | GREEK SMALL LETTER ALPHA
     62 |  000003B2 | GREEK SMALL LETTER BETA
     63 |  000003D0 | GREEK BETA SYMBOL
     64 |  000003B3 | GREEK SMALL LETTER GAMMA
     65 |  000003B4 | GREEK SMALL LETTER DELTA
     66 |  000003B5 | GREEK SMALL LETTER EPSILON
     67 |  0000E01A | GREEK SMALL LETTER STIGMA E<lt>ISO-IR-55_47E<gt>
     68 |  0000E01B | GREEK SMALL LETTER DIGAMMA E<lt>ISO-IR-55_48E<gt>
     69 |  000003B6 | GREEK SMALL LETTER ZETA
     6A |  000003B7 | GREEK SMALL LETTER ETA
     6B |  000003B8 | GREEK SMALL LETTER THETA
     6C |  000003B9 | GREEK SMALL LETTER IOTA
     6D |  000003BA | GREEK SMALL LETTER KAPPA
     6E |  000003BB | GREEK SMALL LETTER LAMDA
     6F |  000003BC | GREEK SMALL LETTER MU
     70 |  000003BD | GREEK SMALL LETTER NU
     71 |  000003BE | GREEK SMALL LETTER XI
     72 |  000003BF | GREEK SMALL LETTER OMICRON
     73 |  000003C0 | GREEK SMALL LETTER PI
     74 |  0000E01C | GREEK SMALL LETTER KOPPA E<lt>ISO-IR-55_54E<gt>
     75 |  000003C1 | GREEK SMALL LETTER RHO
     76 |  000003C3 | GREEK SMALL LETTER SIGMA
     77 |  000003C2 | GREEK SMALL LETTER FINAL SIGMA
     78 |  000003C4 | GREEK SMALL LETTER TAU
     79 |  000003C5 | GREEK SMALL LETTER UPSILON
     7A |  000003C6 | GREEK SMALL LETTER PHI
     7B |  000003C7 | GREEK SMALL LETTER CHI
     7C |  000003C8 | GREEK SMALL LETTER PSI
     7D |  000003C9 | GREEK SMALL LETTER OMEGA
     7E |  0000E01D | GREEK SMALL LETTER SAMPI E<lt>ISO-IR-55_5EE<gt>
     7F |  0000007F | DELETE (DEL)
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/ISO_8859_1.pm ###
 #! /bin/false
 
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for ISO-8859-1.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::ISO_8859_1;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 use constant TO_UTF8 => [
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\x04",
     "\x05",
     "\x06",
     "\x07",
     "\x08",
     "\x09",
     "\x0a",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\x14",
     "\x15",
     "\x16",
     "\x17",
     "\x18",
     "\x19",
     "\x1a",
     "\x1b",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\x20",
     "\x21",
     "\x22",
     "\x23",
     "\x24",
     "\x25",
     "\x26",
     "\x27",
     "\x28",
     "\x29",
     "\x2a",
     "\x2b",
     "\x2c",
     "\x2d",
     "\x2e",
     "\x2f",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\x3a",
     "\x3b",
     "\x3c",
     "\x3d",
     "\x3e",
     "\x3f",
     "\x40",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\x5b",
     "\x5c",
     "\x5d",
     "\x5e",
     "\x5f",
     "\x60",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\x7b",
     "\x7c",
     "\x7d",
     "\x7e",
     "\x7f",
     "\xc2\x80",
     "\xc2\x81",
     "\xc2\x82",
     "\xc2\x83",
     "\xc2\x84",
     "\xc2\x85",
     "\xc2\x86",
     "\xc2\x87",
     "\xc2\x88",
     "\xc2\x89",
     "\xc2\x8a",
     "\xc2\x8b",
     "\xc2\x8c",
     "\xc2\x8d",
     "\xc2\x8e",
     "\xc2\x8f",
     "\xc2\x90",
     "\xc2\x91",
     "\xc2\x92",
     "\xc2\x93",
     "\xc2\x94",
     "\xc2\x95",
     "\xc2\x96",
     "\xc2\x97",
     "\xc2\x98",
     "\xc2\x99",
     "\xc2\x9a",
     "\xc2\x9b",
     "\xc2\x9c",
     "\xc2\x9d",
     "\xc2\x9e",
     "\xc2\x9f",
     "\xc2\xa0",
     "\xc2\xa1",
     "\xc2\xa2",
     "\xc2\xa3",
     "\xc2\xa4",
     "\xc2\xa5",
     "\xc2\xa6",
     "\xc2\xa7",
     "\xc2\xa8",
     "\xc2\xa9",
     "\xc2\xaa",
     "\xc2\xab",
     "\xc2\xac",
     "\xc2\xad",
     "\xc2\xae",
     "\xc2\xaf",
     "\xc2\xb0",
     "\xc2\xb1",
     "\xc2\xb2",
     "\xc2\xb3",
     "\xc2\xb4",
     "\xc2\xb5",
     "\xc2\xb6",
     "\xc2\xb7",
     "\xc2\xb8",
     "\xc2\xb9",
     "\xc2\xba",
     "\xc2\xbb",
     "\xc2\xbc",
     "\xc2\xbd",
     "\xc2\xbe",
     "\xc2\xbf",
     "\xc3\x80",
     "\xc3\x81",
     "\xc3\x82",
     "\xc3\x83",
     "\xc3\x84",
     "\xc3\x85",
     "\xc3\x86",
     "\xc3\x87",
     "\xc3\x88",
     "\xc3\x89",
     "\xc3\x8a",
     "\xc3\x8b",
     "\xc3\x8c",
     "\xc3\x8d",
     "\xc3\x8e",
     "\xc3\x8f",
     "\xc3\x90",
     "\xc3\x91",
     "\xc3\x92",
     "\xc3\x93",
     "\xc3\x94",
     "\xc3\x95",
     "\xc3\x96",
     "\xc3\x97",
     "\xc3\x98",
     "\xc3\x99",
     "\xc3\x9a",
     "\xc3\x9b",
     "\xc3\x9c",
     "\xc3\x9d",
     "\xc3\x9e",
     "\xc3\x9f",
     "\xc3\xa0",
     "\xc3\xa1",
     "\xc3\xa2",
     "\xc3\xa3",
     "\xc3\xa4",
     "\xc3\xa5",
     "\xc3\xa6",
     "\xc3\xa7",
     "\xc3\xa8",
     "\xc3\xa9",
     "\xc3\xaa",
     "\xc3\xab",
     "\xc3\xac",
     "\xc3\xad",
     "\xc3\xae",
     "\xc3\xaf",
     "\xc3\xb0",
     "\xc3\xb1",
     "\xc3\xb2",
     "\xc3\xb3",
     "\xc3\xb4",
     "\xc3\xb5",
     "\xc3\xb6",
     "\xc3\xb7",
     "\xc3\xb8",
     "\xc3\xb9",
     "\xc3\xba",
     "\xc3\xbb",
     "\xc3\xbc",
     "\xc3\xbd",
     "\xc3\xbe",
     "\xc3\xbf",
 ];
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		# FIXME: Maybe the lookup is cheaper than the call to chr().
 		$_[1] = join '', 
 		    map $_ > 255 ? "\x3f" : chr $_,
 			    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8') {
 		$_[1] = join '', map TO_UTF8->[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ unpack 'C*', $_[1] ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::ISO_8859_1 - Conversion routines for ISO-8859-1
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module contains the conversion tables and routines for ISO-8859-1.
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  00000004 | END OF TRANSMISSION (EOT)
     05 |  00000005 | ENQUIRY (ENQ)
     06 |  00000006 | ACKNOWLEDGE (ACK)
     07 |  00000007 | BELL (BEL)
     08 |  00000008 | BACKSPACE (BS)
     09 |  00000009 | CHARACTER TABULATION (HT)
     0A |  0000000A | LINE FEED (LF)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  00000014 | DEVICE CONTROL FOUR (DC4)
     15 |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     16 |  00000016 | SYNCHRONOUS IDLE (SYN)
     17 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  0000001A | SUBSTITUTE (SUB)
     1B |  0000001B | ESCAPE (ESC)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000020 | SPACE
     21 |  00000021 | EXCLAMATION MARK
     22 |  00000022 | QUOTATION MARK
     23 |  00000023 | NUMBER SIGN
     24 |  00000024 | DOLLAR SIGN
     25 |  00000025 | PERCENT SIGN
     26 |  00000026 | AMPERSAND
     27 |  00000027 | APOSTROPHE
     28 |  00000028 | LEFT PARENTHESIS
     29 |  00000029 | RIGHT PARENTHESIS
     2A |  0000002A | ASTERISK
     2B |  0000002B | PLUS SIGN
     2C |  0000002C | COMMA
     2D |  0000002D | HYPHEN-MINUS
     2E |  0000002E | FULL STOP
     2F |  0000002F | SOLIDUS
     30 |  00000030 | DIGIT ZERO
     31 |  00000031 | DIGIT ONE
     32 |  00000032 | DIGIT TWO
     33 |  00000033 | DIGIT THREE
     34 |  00000034 | DIGIT FOUR
     35 |  00000035 | DIGIT FIVE
     36 |  00000036 | DIGIT SIX
     37 |  00000037 | DIGIT SEVEN
     38 |  00000038 | DIGIT EIGHT
     39 |  00000039 | DIGIT NINE
     3A |  0000003A | COLON
     3B |  0000003B | SEMICOLON
     3C |  0000003C | LESS-THAN SIGN
     3D |  0000003D | EQUALS SIGN
     3E |  0000003E | GREATER-THAN SIGN
     3F |  0000003F | QUESTION MARK
     40 |  00000040 | COMMERCIAL AT
     41 |  00000041 | LATIN CAPITAL LETTER A
     42 |  00000042 | LATIN CAPITAL LETTER B
     43 |  00000043 | LATIN CAPITAL LETTER C
     44 |  00000044 | LATIN CAPITAL LETTER D
     45 |  00000045 | LATIN CAPITAL LETTER E
     46 |  00000046 | LATIN CAPITAL LETTER F
     47 |  00000047 | LATIN CAPITAL LETTER G
     48 |  00000048 | LATIN CAPITAL LETTER H
     49 |  00000049 | LATIN CAPITAL LETTER I
     4A |  0000004A | LATIN CAPITAL LETTER J
     4B |  0000004B | LATIN CAPITAL LETTER K
     4C |  0000004C | LATIN CAPITAL LETTER L
     4D |  0000004D | LATIN CAPITAL LETTER M
     4E |  0000004E | LATIN CAPITAL LETTER N
     4F |  0000004F | LATIN CAPITAL LETTER O
     50 |  00000050 | LATIN CAPITAL LETTER P
     51 |  00000051 | LATIN CAPITAL LETTER Q
     52 |  00000052 | LATIN CAPITAL LETTER R
     53 |  00000053 | LATIN CAPITAL LETTER S
     54 |  00000054 | LATIN CAPITAL LETTER T
     55 |  00000055 | LATIN CAPITAL LETTER U
     56 |  00000056 | LATIN CAPITAL LETTER V
     57 |  00000057 | LATIN CAPITAL LETTER W
     58 |  00000058 | LATIN CAPITAL LETTER X
     59 |  00000059 | LATIN CAPITAL LETTER Y
     5A |  0000005A | LATIN CAPITAL LETTER Z
     5B |  0000005B | LEFT SQUARE BRACKET
     5C |  0000005C | REVERSE SOLIDUS
     5D |  0000005D | RIGHT SQUARE BRACKET
     5E |  0000005E | CIRCUMFLEX ACCENT
     5F |  0000005F | LOW LINE
     60 |  00000060 | GRAVE ACCENT
     61 |  00000061 | LATIN SMALL LETTER A
     62 |  00000062 | LATIN SMALL LETTER B
     63 |  00000063 | LATIN SMALL LETTER C
     64 |  00000064 | LATIN SMALL LETTER D
     65 |  00000065 | LATIN SMALL LETTER E
     66 |  00000066 | LATIN SMALL LETTER F
     67 |  00000067 | LATIN SMALL LETTER G
     68 |  00000068 | LATIN SMALL LETTER H
     69 |  00000069 | LATIN SMALL LETTER I
     6A |  0000006A | LATIN SMALL LETTER J
     6B |  0000006B | LATIN SMALL LETTER K
     6C |  0000006C | LATIN SMALL LETTER L
     6D |  0000006D | LATIN SMALL LETTER M
     6E |  0000006E | LATIN SMALL LETTER N
     6F |  0000006F | LATIN SMALL LETTER O
     70 |  00000070 | LATIN SMALL LETTER P
     71 |  00000071 | LATIN SMALL LETTER Q
     72 |  00000072 | LATIN SMALL LETTER R
     73 |  00000073 | LATIN SMALL LETTER S
     74 |  00000074 | LATIN SMALL LETTER T
     75 |  00000075 | LATIN SMALL LETTER U
     76 |  00000076 | LATIN SMALL LETTER V
     77 |  00000077 | LATIN SMALL LETTER W
     78 |  00000078 | LATIN SMALL LETTER X
     79 |  00000079 | LATIN SMALL LETTER Y
     7A |  0000007A | LATIN SMALL LETTER Z
     7B |  0000007B | LEFT CURLY BRACKET
     7C |  0000007C | VERTICAL LINE
     7D |  0000007D | RIGHT CURLY BRACKET
     7E |  0000007E | TILDE
     7F |  0000007F | DELETE (DEL)
     80 |  00000080 | PADDING CHARACTER (PAD)
     81 |  00000081 | HIGH OCTET PRESET (HOP)
     82 |  00000082 | BREAK PERMITTED HERE (BPH)
     83 |  00000083 | NO BREAK HERE (NBH)
     84 |  00000084 | INDEX (IND)
     85 |  00000085 | NEXT LINE (NEL)
     86 |  00000086 | START OF SELECTED AREA (SSA)
     87 |  00000087 | END OF SELECTED AREA (ESA)
     88 |  00000088 | CHARACTER TABULATION SET (HTS)
     89 |  00000089 | CHARACTER TABULATION WITH JUSTIFICATION (HTJ)
     8A |  0000008A | LINE TABULATION SET (VTS)
     8B |  0000008B | PARTIAL LINE FORWARD (PLD)
     8C |  0000008C | PARTIAL LINE BACKWARD (PLU)
     8D |  0000008D | REVERSE LINE FEED (RI)
     8E |  0000008E | SINGLE-SHIFT TWO (SS2)
     8F |  0000008F | SINGLE-SHIFT THREE (SS3)
     90 |  00000090 | DEVICE CONTROL STRING (DCS)
     91 |  00000091 | PRIVATE USE ONE (PU1)
     92 |  00000092 | PRIVATE USE TWO (PU2)
     93 |  00000093 | SET TRANSMIT STATE (STS)
     94 |  00000094 | CANCEL CHARACTER (CCH)
     95 |  00000095 | MESSAGE WAITING (MW)
     96 |  00000096 | START OF GUARDED AREA (SPA)
     97 |  00000097 | END OF GUARDED AREA (EPA)
     98 |  00000098 | START OF STRING (SOS)
     99 |  00000099 | SINGLE GRAPHIC CHARACTER INTRODUCER (SGCI)
     9A |  0000009A | SINGLE CHARACTER INTRODUCER (SCI)
     9B |  0000009B | CONTROL SEQUENCE INTRODUCER (CSI)
     9C |  0000009C | STRING TERMINATOR (ST)
     9D |  0000009D | OPERATING SYSTEM COMMAND (OSC)
     9E |  0000009E | PRIVACY MESSAGE (PM)
     9F |  0000009F | APPLICATION PROGRAM COMMAND (APC)
     A0 |  000000A0 | NO-BREAK SPACE
     A1 |  000000A1 | INVERTED EXCLAMATION MARK
     A2 |  000000A2 | CENT SIGN
     A3 |  000000A3 | POUND SIGN
     A4 |  000000A4 | CURRENCY SIGN
     A5 |  000000A5 | YEN SIGN
     A6 |  000000A6 | BROKEN BAR
     A7 |  000000A7 | SECTION SIGN
     A8 |  000000A8 | DIAERESIS
     A9 |  000000A9 | COPYRIGHT SIGN
     AA |  000000AA | FEMININE ORDINAL INDICATOR
     AB |  000000AB | LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
     AC |  000000AC | NOT SIGN
     AD |  000000AD | SOFT HYPHEN
     AE |  000000AE | REGISTERED SIGN
     AF |  000000AF | MACRON
     B0 |  000000B0 | DEGREE SIGN
     B1 |  000000B1 | PLUS-MINUS SIGN
     B2 |  000000B2 | SUPERSCRIPT TWO
     B3 |  000000B3 | SUPERSCRIPT THREE
     B4 |  000000B4 | ACUTE ACCENT
     B5 |  000000B5 | MICRO SIGN
     B6 |  000000B6 | PILCROW SIGN
     B7 |  000000B7 | MIDDLE DOT
     B8 |  000000B8 | CEDILLA
     B9 |  000000B9 | SUPERSCRIPT ONE
     BA |  000000BA | MASCULINE ORDINAL INDICATOR
     BB |  000000BB | RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
     BC |  000000BC | VULGAR FRACTION ONE QUARTER
     BD |  000000BD | VULGAR FRACTION ONE HALF
     BE |  000000BE | VULGAR FRACTION THREE QUARTERS
     BF |  000000BF | INVERTED QUESTION MARK
     C0 |  000000C0 | LATIN CAPITAL LETTER A WITH GRAVE
     C1 |  000000C1 | LATIN CAPITAL LETTER A WITH ACUTE
     C2 |  000000C2 | LATIN CAPITAL LETTER A WITH CIRCUMFLEX
     C3 |  000000C3 | LATIN CAPITAL LETTER A WITH TILDE
     C4 |  000000C4 | LATIN CAPITAL LETTER A WITH DIAERESIS
     C5 |  000000C5 | LATIN CAPITAL LETTER A WITH RING ABOVE
     C6 |  000000C6 | LATIN CAPITAL LETTER AE
     C7 |  000000C7 | LATIN CAPITAL LETTER C WITH CEDILLA
     C8 |  000000C8 | LATIN CAPITAL LETTER E WITH GRAVE
     C9 |  000000C9 | LATIN CAPITAL LETTER E WITH ACUTE
     CA |  000000CA | LATIN CAPITAL LETTER E WITH CIRCUMFLEX
     CB |  000000CB | LATIN CAPITAL LETTER E WITH DIAERESIS
     CC |  000000CC | LATIN CAPITAL LETTER I WITH GRAVE
     CD |  000000CD | LATIN CAPITAL LETTER I WITH ACUTE
     CE |  000000CE | LATIN CAPITAL LETTER I WITH CIRCUMFLEX
     CF |  000000CF | LATIN CAPITAL LETTER I WITH DIAERESIS
     D0 |  000000D0 | LATIN CAPITAL LETTER ETH
     D1 |  000000D1 | LATIN CAPITAL LETTER N WITH TILDE
     D2 |  000000D2 | LATIN CAPITAL LETTER O WITH GRAVE
     D3 |  000000D3 | LATIN CAPITAL LETTER O WITH ACUTE
     D4 |  000000D4 | LATIN CAPITAL LETTER O WITH CIRCUMFLEX
     D5 |  000000D5 | LATIN CAPITAL LETTER O WITH TILDE
     D6 |  000000D6 | LATIN CAPITAL LETTER O WITH DIAERESIS
     D7 |  000000D7 | MULTIPLICATION SIGN
     D8 |  000000D8 | LATIN CAPITAL LETTER O WITH STROKE
     D9 |  000000D9 | LATIN CAPITAL LETTER U WITH GRAVE
     DA |  000000DA | LATIN CAPITAL LETTER U WITH ACUTE
     DB |  000000DB | LATIN CAPITAL LETTER U WITH CIRCUMFLEX
     DC |  000000DC | LATIN CAPITAL LETTER U WITH DIAERESIS
     DD |  000000DD | LATIN CAPITAL LETTER Y WITH ACUTE
     DE |  000000DE | LATIN CAPITAL LETTER THORN
     DF |  000000DF | LATIN SMALL LETTER SHARP S
     E0 |  000000E0 | LATIN SMALL LETTER A WITH GRAVE
     E1 |  000000E1 | LATIN SMALL LETTER A WITH ACUTE
     E2 |  000000E2 | LATIN SMALL LETTER A WITH CIRCUMFLEX
     E3 |  000000E3 | LATIN SMALL LETTER A WITH TILDE
     E4 |  000000E4 | LATIN SMALL LETTER A WITH DIAERESIS
     E5 |  000000E5 | LATIN SMALL LETTER A WITH RING ABOVE
     E6 |  000000E6 | LATIN SMALL LETTER AE
     E7 |  000000E7 | LATIN SMALL LETTER C WITH CEDILLA
     E8 |  000000E8 | LATIN SMALL LETTER E WITH GRAVE
     E9 |  000000E9 | LATIN SMALL LETTER E WITH ACUTE
     EA |  000000EA | LATIN SMALL LETTER E WITH CIRCUMFLEX
     EB |  000000EB | LATIN SMALL LETTER E WITH DIAERESIS
     EC |  000000EC | LATIN SMALL LETTER I WITH GRAVE
     ED |  000000ED | LATIN SMALL LETTER I WITH ACUTE
     EE |  000000EE | LATIN SMALL LETTER I WITH CIRCUMFLEX
     EF |  000000EF | LATIN SMALL LETTER I WITH DIAERESIS
     F0 |  000000F0 | LATIN SMALL LETTER ETH
     F1 |  000000F1 | LATIN SMALL LETTER N WITH TILDE
     F2 |  000000F2 | LATIN SMALL LETTER O WITH GRAVE
     F3 |  000000F3 | LATIN SMALL LETTER O WITH ACUTE
     F4 |  000000F4 | LATIN SMALL LETTER O WITH CIRCUMFLEX
     F5 |  000000F5 | LATIN SMALL LETTER O WITH TILDE
     F6 |  000000F6 | LATIN SMALL LETTER O WITH DIAERESIS
     F7 |  000000F7 | DIVISION SIGN
     F8 |  000000F8 | LATIN SMALL LETTER O WITH STROKE
     F9 |  000000F9 | LATIN SMALL LETTER U WITH GRAVE
     FA |  000000FA | LATIN SMALL LETTER U WITH ACUTE
     FB |  000000FB | LATIN SMALL LETTER U WITH CIRCUMFLEX
     FC |  000000FC | LATIN SMALL LETTER U WITH DIAERESIS
     FD |  000000FD | LATIN SMALL LETTER Y WITH ACUTE
     FE |  000000FE | LATIN SMALL LETTER THORN
     FF |  000000FF | LATIN SMALL LETTER Y WITH DIAERESIS
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/ISO_8859_10.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for ISO-8859-10.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::ISO_8859_10;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x0004,
     0x0005,
     0x0006,
     0x0007,
     0x0008,
     0x0009,
     0x000a,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x0014,
     0x0015,
     0x0016,
     0x0017,
     0x0018,
     0x0019,
     0x001a,
     0x001b,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0020,
     0x0021,
     0x0022,
     0x0023,
     0x0024,
     0x0025,
     0x0026,
     0x0027,
     0x0028,
     0x0029,
     0x002a,
     0x002b,
     0x002c,
     0x002d,
     0x002e,
     0x002f,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x003a,
     0x003b,
     0x003c,
     0x003d,
     0x003e,
     0x003f,
     0x0040,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x005b,
     0x005c,
     0x005d,
     0x005e,
     0x005f,
     0x0060,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x007b,
     0x007c,
     0x007d,
     0x007e,
     0x007f,
     0x0080,
     0x0081,
     0x0082,
     0x0083,
     0x0084,
     0x0085,
     0x0086,
     0x0087,
     0x0088,
     0x0089,
     0x008a,
     0x008b,
     0x008c,
     0x008d,
     0x008e,
     0x008f,
     0x0090,
     0x0091,
     0x0092,
     0x0093,
     0x0094,
     0x0095,
     0x0096,
     0x0097,
     0x0098,
     0x0099,
     0x009a,
     0x009b,
     0x009c,
     0x009d,
     0x009e,
     0x009f,
     0x00a0,
     0x0104,
     0x0112,
     0x0122,
     0x012a,
     0x0128,
     0x0136,
     0x00a7,
     0x013b,
     0x0110,
     0x0160,
     0x0166,
     0x017d,
     0x00ad,
     0x016a,
     0x014a,
     0x00b0,
     0x0105,
     0x0113,
     0x0123,
     0x012b,
     0x0129,
     0x0137,
     0x00b7,
     0x013c,
     0x0111,
     0x0161,
     0x0167,
     0x017e,
     0x2015,
     0x016b,
     0x014b,
     0x0100,
     0x00c1,
     0x00c2,
     0x00c3,
     0x00c4,
     0x00c5,
     0x00c6,
     0x012e,
     0x010c,
     0x00c9,
     0x0118,
     0x00cb,
     0x0116,
     0x00cd,
     0x00ce,
     0x00cf,
     0x00d0,
     0x0145,
     0x014c,
     0x00d3,
     0x00d4,
     0x00d5,
     0x00d6,
     0x0168,
     0x00d8,
     0x0172,
     0x00da,
     0x00db,
     0x00dc,
     0x00dd,
     0x00de,
     0x00df,
     0x0101,
     0x00e1,
     0x00e2,
     0x00e3,
     0x00e4,
     0x00e5,
     0x00e6,
     0x012f,
     0x010d,
     0x00e9,
     0x0119,
     0x00eb,
     0x0117,
     0x00ed,
     0x00ee,
     0x00ef,
     0x00f0,
     0x0146,
     0x014d,
     0x00f3,
     0x00f4,
     0x00f5,
     0x00f6,
     0x0169,
     0x00f8,
     0x0173,
     0x00fa,
     0x00fb,
     0x00fc,
     0x00fd,
     0x00fe,
     0x0138,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\x04",
     "\x05",
     "\x06",
     "\x07",
     "\x08",
     "\x09",
     "\x0a",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\x14",
     "\x15",
     "\x16",
     "\x17",
     "\x18",
     "\x19",
     "\x1a",
     "\x1b",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\x20",
     "\x21",
     "\x22",
     "\x23",
     "\x24",
     "\x25",
     "\x26",
     "\x27",
     "\x28",
     "\x29",
     "\x2a",
     "\x2b",
     "\x2c",
     "\x2d",
     "\x2e",
     "\x2f",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\x3a",
     "\x3b",
     "\x3c",
     "\x3d",
     "\x3e",
     "\x3f",
     "\x40",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\x5b",
     "\x5c",
     "\x5d",
     "\x5e",
     "\x5f",
     "\x60",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\x7b",
     "\x7c",
     "\x7d",
     "\x7e",
     "\x7f",
     "\xc2\x80",
     "\xc2\x81",
     "\xc2\x82",
     "\xc2\x83",
     "\xc2\x84",
     "\xc2\x85",
     "\xc2\x86",
     "\xc2\x87",
     "\xc2\x88",
     "\xc2\x89",
     "\xc2\x8a",
     "\xc2\x8b",
     "\xc2\x8c",
     "\xc2\x8d",
     "\xc2\x8e",
     "\xc2\x8f",
     "\xc2\x90",
     "\xc2\x91",
     "\xc2\x92",
     "\xc2\x93",
     "\xc2\x94",
     "\xc2\x95",
     "\xc2\x96",
     "\xc2\x97",
     "\xc2\x98",
     "\xc2\x99",
     "\xc2\x9a",
     "\xc2\x9b",
     "\xc2\x9c",
     "\xc2\x9d",
     "\xc2\x9e",
     "\xc2\x9f",
     "\xc2\xa0",
     "\xc4\x84",
     "\xc4\x92",
     "\xc4\xa2",
     "\xc4\xaa",
     "\xc4\xa8",
     "\xc4\xb6",
     "\xc2\xa7",
     "\xc4\xbb",
     "\xc4\x90",
     "\xc5\xa0",
     "\xc5\xa6",
     "\xc5\xbd",
     "\xc2\xad",
     "\xc5\xaa",
     "\xc5\x8a",
     "\xc2\xb0",
     "\xc4\x85",
     "\xc4\x93",
     "\xc4\xa3",
     "\xc4\xab",
     "\xc4\xa9",
     "\xc4\xb7",
     "\xc2\xb7",
     "\xc4\xbc",
     "\xc4\x91",
     "\xc5\xa1",
     "\xc5\xa7",
     "\xc5\xbe",
     "\xe2\x80\x95",
     "\xc5\xab",
     "\xc5\x8b",
     "\xc4\x80",
     "\xc3\x81",
     "\xc3\x82",
     "\xc3\x83",
     "\xc3\x84",
     "\xc3\x85",
     "\xc3\x86",
     "\xc4\xae",
     "\xc4\x8c",
     "\xc3\x89",
     "\xc4\x98",
     "\xc3\x8b",
     "\xc4\x96",
     "\xc3\x8d",
     "\xc3\x8e",
     "\xc3\x8f",
     "\xc3\x90",
     "\xc5\x85",
     "\xc5\x8c",
     "\xc3\x93",
     "\xc3\x94",
     "\xc3\x95",
     "\xc3\x96",
     "\xc5\xa8",
     "\xc3\x98",
     "\xc5\xb2",
     "\xc3\x9a",
     "\xc3\x9b",
     "\xc3\x9c",
     "\xc3\x9d",
     "\xc3\x9e",
     "\xc3\x9f",
     "\xc4\x81",
     "\xc3\xa1",
     "\xc3\xa2",
     "\xc3\xa3",
     "\xc3\xa4",
     "\xc3\xa5",
     "\xc3\xa6",
     "\xc4\xaf",
     "\xc4\x8d",
     "\xc3\xa9",
     "\xc4\x99",
     "\xc3\xab",
     "\xc4\x97",
     "\xc3\xad",
     "\xc3\xae",
     "\xc3\xaf",
     "\xc3\xb0",
     "\xc5\x86",
     "\xc5\x8d",
     "\xc3\xb3",
     "\xc3\xb4",
     "\xc3\xb5",
     "\xc3\xb6",
     "\xc5\xa9",
     "\xc3\xb8",
     "\xc5\xb3",
     "\xc3\xba",
     "\xc3\xbb",
     "\xc3\xbc",
     "\xc3\xbd",
     "\xc3\xbe",
     "\xc4\xb8",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x04",
     0x00000005 => "\x05",
     0x00000006 => "\x06",
     0x00000007 => "\x07",
     0x00000008 => "\x08",
     0x00000009 => "\x09",
     0x0000000a => "\x0a",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x14",
     0x00000015 => "\x15",
     0x00000016 => "\x16",
     0x00000017 => "\x17",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x1a",
     0x0000001b => "\x1b",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x20",
     0x00000021 => "\x21",
     0x00000022 => "\x22",
     0x00000023 => "\x23",
     0x00000024 => "\x24",
     0x00000025 => "\x25",
     0x00000026 => "\x26",
     0x00000027 => "\x27",
     0x00000028 => "\x28",
     0x00000029 => "\x29",
     0x0000002a => "\x2a",
     0x0000002b => "\x2b",
     0x0000002c => "\x2c",
     0x0000002d => "\x2d",
     0x0000002e => "\x2e",
     0x0000002f => "\x2f",
     0x00000030 => "\x30",
     0x00000031 => "\x31",
     0x00000032 => "\x32",
     0x00000033 => "\x33",
     0x00000034 => "\x34",
     0x00000035 => "\x35",
     0x00000036 => "\x36",
     0x00000037 => "\x37",
     0x00000038 => "\x38",
     0x00000039 => "\x39",
     0x0000003a => "\x3a",
     0x0000003b => "\x3b",
     0x0000003c => "\x3c",
     0x0000003d => "\x3d",
     0x0000003e => "\x3e",
     0x0000003f => "\x3f",
     0x00000040 => "\x40",
     0x00000041 => "\x41",
     0x00000042 => "\x42",
     0x00000043 => "\x43",
     0x00000044 => "\x44",
     0x00000045 => "\x45",
     0x00000046 => "\x46",
     0x00000047 => "\x47",
     0x00000048 => "\x48",
     0x00000049 => "\x49",
     0x0000004a => "\x4a",
     0x0000004b => "\x4b",
     0x0000004c => "\x4c",
     0x0000004d => "\x4d",
     0x0000004e => "\x4e",
     0x0000004f => "\x4f",
     0x00000050 => "\x50",
     0x00000051 => "\x51",
     0x00000052 => "\x52",
     0x00000053 => "\x53",
     0x00000054 => "\x54",
     0x00000055 => "\x55",
     0x00000056 => "\x56",
     0x00000057 => "\x57",
     0x00000058 => "\x58",
     0x00000059 => "\x59",
     0x0000005a => "\x5a",
     0x0000005b => "\x5b",
     0x0000005c => "\x5c",
     0x0000005d => "\x5d",
     0x0000005e => "\x5e",
     0x0000005f => "\x5f",
     0x00000060 => "\x60",
     0x00000061 => "\x61",
     0x00000062 => "\x62",
     0x00000063 => "\x63",
     0x00000064 => "\x64",
     0x00000065 => "\x65",
     0x00000066 => "\x66",
     0x00000067 => "\x67",
     0x00000068 => "\x68",
     0x00000069 => "\x69",
     0x0000006a => "\x6a",
     0x0000006b => "\x6b",
     0x0000006c => "\x6c",
     0x0000006d => "\x6d",
     0x0000006e => "\x6e",
     0x0000006f => "\x6f",
     0x00000070 => "\x70",
     0x00000071 => "\x71",
     0x00000072 => "\x72",
     0x00000073 => "\x73",
     0x00000074 => "\x74",
     0x00000075 => "\x75",
     0x00000076 => "\x76",
     0x00000077 => "\x77",
     0x00000078 => "\x78",
     0x00000079 => "\x79",
     0x0000007a => "\x7a",
     0x0000007b => "\x7b",
     0x0000007c => "\x7c",
     0x0000007d => "\x7d",
     0x0000007e => "\x7e",
     0x0000007f => "\x7f",
     0x00000080 => "\x80",
     0x00000081 => "\x81",
     0x00000082 => "\x82",
     0x00000083 => "\x83",
     0x00000084 => "\x84",
     0x00000085 => "\x85",
     0x00000086 => "\x86",
     0x00000087 => "\x87",
     0x00000088 => "\x88",
     0x00000089 => "\x89",
     0x0000008a => "\x8a",
     0x0000008b => "\x8b",
     0x0000008c => "\x8c",
     0x0000008d => "\x8d",
     0x0000008e => "\x8e",
     0x0000008f => "\x8f",
     0x00000090 => "\x90",
     0x00000091 => "\x91",
     0x00000092 => "\x92",
     0x00000093 => "\x93",
     0x00000094 => "\x94",
     0x00000095 => "\x95",
     0x00000096 => "\x96",
     0x00000097 => "\x97",
     0x00000098 => "\x98",
     0x00000099 => "\x99",
     0x0000009a => "\x9a",
     0x0000009b => "\x9b",
     0x0000009c => "\x9c",
     0x0000009d => "\x9d",
     0x0000009e => "\x9e",
     0x0000009f => "\x9f",
     0x000000a0 => "\xa0",
     0x000000a7 => "\xa7",
     0x000000ad => "\xad",
     0x000000b0 => "\xb0",
     0x000000b7 => "\xb7",
     0x000000c1 => "\xc1",
     0x000000c2 => "\xc2",
     0x000000c3 => "\xc3",
     0x000000c4 => "\xc4",
     0x000000c5 => "\xc5",
     0x000000c6 => "\xc6",
     0x000000c9 => "\xc9",
     0x000000cb => "\xcb",
     0x000000cd => "\xcd",
     0x000000ce => "\xce",
     0x000000cf => "\xcf",
     0x000000d0 => "\xd0",
     0x000000d3 => "\xd3",
     0x000000d4 => "\xd4",
     0x000000d5 => "\xd5",
     0x000000d6 => "\xd6",
     0x000000d8 => "\xd8",
     0x000000da => "\xda",
     0x000000db => "\xdb",
     0x000000dc => "\xdc",
     0x000000dd => "\xdd",
     0x000000de => "\xde",
     0x000000df => "\xdf",
     0x000000e1 => "\xe1",
     0x000000e2 => "\xe2",
     0x000000e3 => "\xe3",
     0x000000e4 => "\xe4",
     0x000000e5 => "\xe5",
     0x000000e6 => "\xe6",
     0x000000e9 => "\xe9",
     0x000000eb => "\xeb",
     0x000000ed => "\xed",
     0x000000ee => "\xee",
     0x000000ef => "\xef",
     0x000000f0 => "\xf0",
     0x000000f3 => "\xf3",
     0x000000f4 => "\xf4",
     0x000000f5 => "\xf5",
     0x000000f6 => "\xf6",
     0x000000f8 => "\xf8",
     0x000000fa => "\xfa",
     0x000000fb => "\xfb",
     0x000000fc => "\xfc",
     0x000000fd => "\xfd",
     0x000000fe => "\xfe",
     0x00000100 => "\xc0",
     0x00000101 => "\xe0",
     0x00000104 => "\xa1",
     0x00000105 => "\xb1",
     0x0000010c => "\xc8",
     0x0000010d => "\xe8",
     0x00000110 => "\xa9",
     0x00000111 => "\xb9",
     0x00000112 => "\xa2",
     0x00000113 => "\xb2",
     0x00000116 => "\xcc",
     0x00000117 => "\xec",
     0x00000118 => "\xca",
     0x00000119 => "\xea",
     0x00000122 => "\xa3",
     0x00000123 => "\xb3",
     0x00000128 => "\xa5",
     0x00000129 => "\xb5",
     0x0000012a => "\xa4",
     0x0000012b => "\xb4",
     0x0000012e => "\xc7",
     0x0000012f => "\xe7",
     0x00000136 => "\xa6",
     0x00000137 => "\xb6",
     0x00000138 => "\xff",
     0x0000013b => "\xa8",
     0x0000013c => "\xb8",
     0x00000145 => "\xd1",
     0x00000146 => "\xf1",
     0x0000014a => "\xaf",
     0x0000014b => "\xbf",
     0x0000014c => "\xd2",
     0x0000014d => "\xf2",
     0x00000160 => "\xaa",
     0x00000161 => "\xba",
     0x00000166 => "\xab",
     0x00000167 => "\xbb",
     0x00000168 => "\xd7",
     0x00000169 => "\xf7",
     0x0000016a => "\xae",
     0x0000016b => "\xbe",
     0x00000172 => "\xd9",
     0x00000173 => "\xf9",
     0x0000017d => "\xac",
     0x0000017e => "\xbc",
     0x00002015 => "\xbd",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::ISO_8859_10 - Conversion routines for ISO-8859-10
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for ISO-8859-10.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
   source: ECMA registry
  alias ISO-IR-157
  alias ISO_8859-10:1992
  alias ISO_8859-10
  alias L6
  alias LATIN6
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  00000004 | END OF TRANSMISSION (EOT)
     05 |  00000005 | ENQUIRY (ENQ)
     06 |  00000006 | ACKNOWLEDGE (ACK)
     07 |  00000007 | BELL (BEL)
     08 |  00000008 | BACKSPACE (BS)
     09 |  00000009 | CHARACTER TABULATION (HT)
     0A |  0000000A | LINE FEED (LF)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  00000014 | DEVICE CONTROL FOUR (DC4)
     15 |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     16 |  00000016 | SYNCHRONOUS IDLE (SYN)
     17 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  0000001A | SUBSTITUTE (SUB)
     1B |  0000001B | ESCAPE (ESC)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000020 | SPACE
     21 |  00000021 | EXCLAMATION MARK
     22 |  00000022 | QUOTATION MARK
     23 |  00000023 | NUMBER SIGN
     24 |  00000024 | DOLLAR SIGN
     25 |  00000025 | PERCENT SIGN
     26 |  00000026 | AMPERSAND
     27 |  00000027 | APOSTROPHE
     28 |  00000028 | LEFT PARENTHESIS
     29 |  00000029 | RIGHT PARENTHESIS
     2A |  0000002A | ASTERISK
     2B |  0000002B | PLUS SIGN
     2C |  0000002C | COMMA
     2D |  0000002D | HYPHEN-MINUS
     2E |  0000002E | FULL STOP
     2F |  0000002F | SOLIDUS
     30 |  00000030 | DIGIT ZERO
     31 |  00000031 | DIGIT ONE
     32 |  00000032 | DIGIT TWO
     33 |  00000033 | DIGIT THREE
     34 |  00000034 | DIGIT FOUR
     35 |  00000035 | DIGIT FIVE
     36 |  00000036 | DIGIT SIX
     37 |  00000037 | DIGIT SEVEN
     38 |  00000038 | DIGIT EIGHT
     39 |  00000039 | DIGIT NINE
     3A |  0000003A | COLON
     3B |  0000003B | SEMICOLON
     3C |  0000003C | LESS-THAN SIGN
     3D |  0000003D | EQUALS SIGN
     3E |  0000003E | GREATER-THAN SIGN
     3F |  0000003F | QUESTION MARK
     40 |  00000040 | COMMERCIAL AT
     41 |  00000041 | LATIN CAPITAL LETTER A
     42 |  00000042 | LATIN CAPITAL LETTER B
     43 |  00000043 | LATIN CAPITAL LETTER C
     44 |  00000044 | LATIN CAPITAL LETTER D
     45 |  00000045 | LATIN CAPITAL LETTER E
     46 |  00000046 | LATIN CAPITAL LETTER F
     47 |  00000047 | LATIN CAPITAL LETTER G
     48 |  00000048 | LATIN CAPITAL LETTER H
     49 |  00000049 | LATIN CAPITAL LETTER I
     4A |  0000004A | LATIN CAPITAL LETTER J
     4B |  0000004B | LATIN CAPITAL LETTER K
     4C |  0000004C | LATIN CAPITAL LETTER L
     4D |  0000004D | LATIN CAPITAL LETTER M
     4E |  0000004E | LATIN CAPITAL LETTER N
     4F |  0000004F | LATIN CAPITAL LETTER O
     50 |  00000050 | LATIN CAPITAL LETTER P
     51 |  00000051 | LATIN CAPITAL LETTER Q
     52 |  00000052 | LATIN CAPITAL LETTER R
     53 |  00000053 | LATIN CAPITAL LETTER S
     54 |  00000054 | LATIN CAPITAL LETTER T
     55 |  00000055 | LATIN CAPITAL LETTER U
     56 |  00000056 | LATIN CAPITAL LETTER V
     57 |  00000057 | LATIN CAPITAL LETTER W
     58 |  00000058 | LATIN CAPITAL LETTER X
     59 |  00000059 | LATIN CAPITAL LETTER Y
     5A |  0000005A | LATIN CAPITAL LETTER Z
     5B |  0000005B | LEFT SQUARE BRACKET
     5C |  0000005C | REVERSE SOLIDUS
     5D |  0000005D | RIGHT SQUARE BRACKET
     5E |  0000005E | CIRCUMFLEX ACCENT
     5F |  0000005F | LOW LINE
     60 |  00000060 | GRAVE ACCENT
     61 |  00000061 | LATIN SMALL LETTER A
     62 |  00000062 | LATIN SMALL LETTER B
     63 |  00000063 | LATIN SMALL LETTER C
     64 |  00000064 | LATIN SMALL LETTER D
     65 |  00000065 | LATIN SMALL LETTER E
     66 |  00000066 | LATIN SMALL LETTER F
     67 |  00000067 | LATIN SMALL LETTER G
     68 |  00000068 | LATIN SMALL LETTER H
     69 |  00000069 | LATIN SMALL LETTER I
     6A |  0000006A | LATIN SMALL LETTER J
     6B |  0000006B | LATIN SMALL LETTER K
     6C |  0000006C | LATIN SMALL LETTER L
     6D |  0000006D | LATIN SMALL LETTER M
     6E |  0000006E | LATIN SMALL LETTER N
     6F |  0000006F | LATIN SMALL LETTER O
     70 |  00000070 | LATIN SMALL LETTER P
     71 |  00000071 | LATIN SMALL LETTER Q
     72 |  00000072 | LATIN SMALL LETTER R
     73 |  00000073 | LATIN SMALL LETTER S
     74 |  00000074 | LATIN SMALL LETTER T
     75 |  00000075 | LATIN SMALL LETTER U
     76 |  00000076 | LATIN SMALL LETTER V
     77 |  00000077 | LATIN SMALL LETTER W
     78 |  00000078 | LATIN SMALL LETTER X
     79 |  00000079 | LATIN SMALL LETTER Y
     7A |  0000007A | LATIN SMALL LETTER Z
     7B |  0000007B | LEFT CURLY BRACKET
     7C |  0000007C | VERTICAL LINE
     7D |  0000007D | RIGHT CURLY BRACKET
     7E |  0000007E | TILDE
     7F |  0000007F | DELETE (DEL)
     80 |  00000080 | PADDING CHARACTER (PAD)
     81 |  00000081 | HIGH OCTET PRESET (HOP)
     82 |  00000082 | BREAK PERMITTED HERE (BPH)
     83 |  00000083 | NO BREAK HERE (NBH)
     84 |  00000084 | INDEX (IND)
     85 |  00000085 | NEXT LINE (NEL)
     86 |  00000086 | START OF SELECTED AREA (SSA)
     87 |  00000087 | END OF SELECTED AREA (ESA)
     88 |  00000088 | CHARACTER TABULATION SET (HTS)
     89 |  00000089 | CHARACTER TABULATION WITH JUSTIFICATION (HTJ)
     8A |  0000008A | LINE TABULATION SET (VTS)
     8B |  0000008B | PARTIAL LINE FORWARD (PLD)
     8C |  0000008C | PARTIAL LINE BACKWARD (PLU)
     8D |  0000008D | REVERSE LINE FEED (RI)
     8E |  0000008E | SINGLE-SHIFT TWO (SS2)
     8F |  0000008F | SINGLE-SHIFT THREE (SS3)
     90 |  00000090 | DEVICE CONTROL STRING (DCS)
     91 |  00000091 | PRIVATE USE ONE (PU1)
     92 |  00000092 | PRIVATE USE TWO (PU2)
     93 |  00000093 | SET TRANSMIT STATE (STS)
     94 |  00000094 | CANCEL CHARACTER (CCH)
     95 |  00000095 | MESSAGE WAITING (MW)
     96 |  00000096 | START OF GUARDED AREA (SPA)
     97 |  00000097 | END OF GUARDED AREA (EPA)
     98 |  00000098 | START OF STRING (SOS)
     99 |  00000099 | SINGLE GRAPHIC CHARACTER INTRODUCER (SGCI)
     9A |  0000009A | SINGLE CHARACTER INTRODUCER (SCI)
     9B |  0000009B | CONTROL SEQUENCE INTRODUCER (CSI)
     9C |  0000009C | STRING TERMINATOR (ST)
     9D |  0000009D | OPERATING SYSTEM COMMAND (OSC)
     9E |  0000009E | PRIVACY MESSAGE (PM)
     9F |  0000009F | APPLICATION PROGRAM COMMAND (APC)
     A0 |  000000A0 | NO-BREAK SPACE
     A1 |  00000104 | LATIN CAPITAL LETTER A WITH OGONEK
     A2 |  00000112 | LATIN CAPITAL LETTER E WITH MACRON
     A3 |  00000122 | LATIN CAPITAL LETTER G WITH CEDILLA
     A4 |  0000012A | LATIN CAPITAL LETTER I WITH MACRON
     A5 |  00000128 | LATIN CAPITAL LETTER I WITH TILDE
     A6 |  00000136 | LATIN CAPITAL LETTER K WITH CEDILLA
     A7 |  000000A7 | SECTION SIGN
     A8 |  0000013B | LATIN CAPITAL LETTER L WITH CEDILLA
     A9 |  00000110 | LATIN CAPITAL LETTER D WITH STROKE
     AA |  00000160 | LATIN CAPITAL LETTER S WITH CARON
     AB |  00000166 | LATIN CAPITAL LETTER T WITH STROKE
     AC |  0000017D | LATIN CAPITAL LETTER Z WITH CARON
     AD |  000000AD | SOFT HYPHEN
     AE |  0000016A | LATIN CAPITAL LETTER U WITH MACRON
     AF |  0000014A | LATIN CAPITAL LETTER ENG (Sami)
     B0 |  000000B0 | DEGREE SIGN
     B1 |  00000105 | LATIN SMALL LETTER A WITH OGONEK
     B2 |  00000113 | LATIN SMALL LETTER E WITH MACRON
     B3 |  00000123 | LATIN SMALL LETTER G WITH CEDILLA
     B4 |  0000012B | LATIN SMALL LETTER I WITH MACRON
     B5 |  00000129 | LATIN SMALL LETTER I WITH TILDE
     B6 |  00000137 | LATIN SMALL LETTER K WITH CEDILLA
     B7 |  000000B7 | MIDDLE DOT
     B8 |  0000013C | LATIN SMALL LETTER L WITH CEDILLA
     B9 |  00000111 | LATIN SMALL LETTER D WITH STROKE
     BA |  00000161 | LATIN SMALL LETTER S WITH CARON
     BB |  00000167 | LATIN SMALL LETTER T WITH STROKE
     BC |  0000017E | LATIN SMALL LETTER Z WITH CARON
     BD |  00002015 | HORIZONTAL BAR
     BE |  0000016B | LATIN SMALL LETTER U WITH MACRON
     BF |  0000014B | LATIN SMALL LETTER ENG (Sami)
     C0 |  00000100 | LATIN CAPITAL LETTER A WITH MACRON
     C1 |  000000C1 | LATIN CAPITAL LETTER A WITH ACUTE
     C2 |  000000C2 | LATIN CAPITAL LETTER A WITH CIRCUMFLEX
     C3 |  000000C3 | LATIN CAPITAL LETTER A WITH TILDE
     C4 |  000000C4 | LATIN CAPITAL LETTER A WITH DIAERESIS
     C5 |  000000C5 | LATIN CAPITAL LETTER A WITH RING ABOVE
     C6 |  000000C6 | LATIN CAPITAL LETTER AE
     C7 |  0000012E | LATIN CAPITAL LETTER I WITH OGONEK
     C8 |  0000010C | LATIN CAPITAL LETTER C WITH CARON
     C9 |  000000C9 | LATIN CAPITAL LETTER E WITH ACUTE
     CA |  00000118 | LATIN CAPITAL LETTER E WITH OGONEK
     CB |  000000CB | LATIN CAPITAL LETTER E WITH DIAERESIS
     CC |  00000116 | LATIN CAPITAL LETTER E WITH DOT ABOVE
     CD |  000000CD | LATIN CAPITAL LETTER I WITH ACUTE
     CE |  000000CE | LATIN CAPITAL LETTER I WITH CIRCUMFLEX
     CF |  000000CF | LATIN CAPITAL LETTER I WITH DIAERESIS
     D0 |  000000D0 | LATIN CAPITAL LETTER ETH (Icelandic)
     D1 |  00000145 | LATIN CAPITAL LETTER N WITH CEDILLA
     D2 |  0000014C | LATIN CAPITAL LETTER O WITH MACRON
     D3 |  000000D3 | LATIN CAPITAL LETTER O WITH ACUTE
     D4 |  000000D4 | LATIN CAPITAL LETTER O WITH CIRCUMFLEX
     D5 |  000000D5 | LATIN CAPITAL LETTER O WITH TILDE
     D6 |  000000D6 | LATIN CAPITAL LETTER O WITH DIAERESIS
     D7 |  00000168 | LATIN CAPITAL LETTER U WITH TILDE
     D8 |  000000D8 | LATIN CAPITAL LETTER O WITH STROKE
     D9 |  00000172 | LATIN CAPITAL LETTER U WITH OGONEK
     DA |  000000DA | LATIN CAPITAL LETTER U WITH ACUTE
     DB |  000000DB | LATIN CAPITAL LETTER U WITH CIRCUMFLEX
     DC |  000000DC | LATIN CAPITAL LETTER U WITH DIAERESIS
     DD |  000000DD | LATIN CAPITAL LETTER Y WITH ACUTE
     DE |  000000DE | LATIN CAPITAL LETTER THORN (Icelandic)
     DF |  000000DF | LATIN SMALL LETTER SHARP S (German)
     E0 |  00000101 | LATIN SMALL LETTER A WITH MACRON
     E1 |  000000E1 | LATIN SMALL LETTER A WITH ACUTE
     E2 |  000000E2 | LATIN SMALL LETTER A WITH CIRCUMFLEX
     E3 |  000000E3 | LATIN SMALL LETTER A WITH TILDE
     E4 |  000000E4 | LATIN SMALL LETTER A WITH DIAERESIS
     E5 |  000000E5 | LATIN SMALL LETTER A WITH RING ABOVE
     E6 |  000000E6 | LATIN SMALL LETTER AE
     E7 |  0000012F | LATIN SMALL LETTER I WITH OGONEK
     E8 |  0000010D | LATIN SMALL LETTER C WITH CARON
     E9 |  000000E9 | LATIN SMALL LETTER E WITH ACUTE
     EA |  00000119 | LATIN SMALL LETTER E WITH OGONEK
     EB |  000000EB | LATIN SMALL LETTER E WITH DIAERESIS
     EC |  00000117 | LATIN SMALL LETTER E WITH DOT ABOVE
     ED |  000000ED | LATIN SMALL LETTER I WITH ACUTE
     EE |  000000EE | LATIN SMALL LETTER I WITH CIRCUMFLEX
     EF |  000000EF | LATIN SMALL LETTER I WITH DIAERESIS
     F0 |  000000F0 | LATIN SMALL LETTER ETH (Icelandic)
     F1 |  00000146 | LATIN SMALL LETTER N WITH CEDILLA
     F2 |  0000014D | LATIN SMALL LETTER O WITH MACRON
     F3 |  000000F3 | LATIN SMALL LETTER O WITH ACUTE
     F4 |  000000F4 | LATIN SMALL LETTER O WITH CIRCUMFLEX
     F5 |  000000F5 | LATIN SMALL LETTER O WITH TILDE
     F6 |  000000F6 | LATIN SMALL LETTER O WITH DIAERESIS
     F7 |  00000169 | LATIN SMALL LETTER U WITH TILDE
     F8 |  000000F8 | LATIN SMALL LETTER O WITH STROKE
     F9 |  00000173 | LATIN SMALL LETTER U WITH OGONEK
     FA |  000000FA | LATIN SMALL LETTER U WITH ACUTE
     FB |  000000FB | LATIN SMALL LETTER U WITH CIRCUMFLEX
     FC |  000000FC | LATIN SMALL LETTER U WITH DIAERESIS
     FD |  000000FD | LATIN SMALL LETTER Y WITH ACUTE
     FE |  000000FE | LATIN SMALL LETTER THORN (Icelandic)
     FF |  00000138 | LATIN SMALL LETTER KRA (Greenlandic)
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/ISO_8859_11.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for ISO-8859-11.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::ISO_8859_11;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x0004,
     0x0005,
     0x0006,
     0x0007,
     0x0008,
     0x0009,
     0x000a,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x0014,
     0x0015,
     0x0016,
     0x0017,
     0x0018,
     0x0019,
     0x001a,
     0x001b,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0020,
     0x0021,
     0x0022,
     0x0023,
     0x0024,
     0x0025,
     0x0026,
     0x0027,
     0x0028,
     0x0029,
     0x002a,
     0x002b,
     0x002c,
     0x002d,
     0x002e,
     0x002f,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x003a,
     0x003b,
     0x003c,
     0x003d,
     0x003e,
     0x003f,
     0x0040,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x005b,
     0x005c,
     0x005d,
     0x005e,
     0x005f,
     0x0060,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x007b,
     0x007c,
     0x007d,
     0x007e,
     0x007f,
 	0xfffd,
 	0xfffd,
 	0xfffd,
 	0xfffd,
 	0xfffd,
 	0xfffd,
 	0xfffd,
 	0xfffd,
 	0xfffd,
 	0xfffd,
 	0xfffd,
 	0xfffd,
 	0xfffd,
 	0xfffd,
 	0xfffd,
 	0xfffd,
 	0xfffd,
 	0xfffd,
 	0xfffd,
 	0xfffd,
 	0xfffd,
 	0xfffd,
 	0xfffd,
 	0xfffd,
 	0xfffd,
 	0xfffd,
 	0xfffd,
 	0xfffd,
 	0xfffd,
 	0xfffd,
 	0xfffd,
 	0xfffd,
     0x00a0,
     0x0e01,
     0x0e02,
     0x0e03,
     0x0e04,
     0x0e05,
     0x0e06,
     0x0e07,
     0x0e08,
     0x0e09,
     0x0e0a,
     0x0e0b,
     0x0e0c,
     0x0e0d,
     0x0e0e,
     0x0e0f,
     0x0e10,
     0x0e11,
     0x0e12,
     0x0e13,
     0x0e14,
     0x0e15,
     0x0e16,
     0x0e17,
     0x0e18,
     0x0e19,
     0x0e1a,
     0x0e1b,
     0x0e1c,
     0x0e1d,
     0x0e1e,
     0x0e1f,
     0x0e20,
     0x0e21,
     0x0e22,
     0x0e23,
     0x0e24,
     0x0e25,
     0x0e26,
     0x0e27,
     0x0e28,
     0x0e29,
     0x0e2a,
     0x0e2b,
     0x0e2c,
     0x0e2d,
     0x0e2e,
     0x0e2f,
     0x0e30,
     0x0e31,
     0x0e32,
     0x0e33,
     0x0e34,
     0x0e35,
     0x0e36,
     0x0e37,
     0x0e38,
     0x0e39,
     0x0e3a,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x0e3f,
     0x0e40,
     0x0e41,
     0x0e42,
     0x0e43,
     0x0e44,
     0x0e45,
     0x0e46,
     0x0e47,
     0x0e48,
     0x0e49,
     0x0e4a,
     0x0e4b,
     0x0e4c,
     0x0e4d,
     0x0e4e,
     0x0e4f,
     0x0e50,
     0x0e51,
     0x0e52,
     0x0e53,
     0x0e54,
     0x0e55,
     0x0e56,
     0x0e57,
     0x0e58,
     0x0e59,
     0x0e5a,
     0x0e5b,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\x04",
     "\x05",
     "\x06",
     "\x07",
     "\x08",
     "\x09",
     "\x0a",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\x14",
     "\x15",
     "\x16",
     "\x17",
     "\x18",
     "\x19",
     "\x1a",
     "\x1b",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\x20",
     "\x21",
     "\x22",
     "\x23",
     "\x24",
     "\x25",
     "\x26",
     "\x27",
     "\x28",
     "\x29",
     "\x2a",
     "\x2b",
     "\x2c",
     "\x2d",
     "\x2e",
     "\x2f",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\x3a",
     "\x3b",
     "\x3c",
     "\x3d",
     "\x3e",
     "\x3f",
     "\x40",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\x5b",
     "\x5c",
     "\x5d",
     "\x5e",
     "\x5f",
     "\x60",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\x7b",
     "\x7c",
     "\x7d",
     "\x7e",
     "\x7f",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc2\xa0",
     "\xe0\xb8\x81",
     "\xe0\xb8\x82",
     "\xe0\xb8\x83",
     "\xe0\xb8\x84",
     "\xe0\xb8\x85",
     "\xe0\xb8\x86",
     "\xe0\xb8\x87",
     "\xe0\xb8\x88",
     "\xe0\xb8\x89",
     "\xe0\xb8\x8a",
     "\xe0\xb8\x8b",
     "\xe0\xb8\x8c",
     "\xe0\xb8\x8d",
     "\xe0\xb8\x8e",
     "\xe0\xb8\x8f",
     "\xe0\xb8\x90",
     "\xe0\xb8\x91",
     "\xe0\xb8\x92",
     "\xe0\xb8\x93",
     "\xe0\xb8\x94",
     "\xe0\xb8\x95",
     "\xe0\xb8\x96",
     "\xe0\xb8\x97",
     "\xe0\xb8\x98",
     "\xe0\xb8\x99",
     "\xe0\xb8\x9a",
     "\xe0\xb8\x9b",
     "\xe0\xb8\x9c",
     "\xe0\xb8\x9d",
     "\xe0\xb8\x9e",
     "\xe0\xb8\x9f",
     "\xe0\xb8\xa0",
     "\xe0\xb8\xa1",
     "\xe0\xb8\xa2",
     "\xe0\xb8\xa3",
     "\xe0\xb8\xa4",
     "\xe0\xb8\xa5",
     "\xe0\xb8\xa6",
     "\xe0\xb8\xa7",
     "\xe0\xb8\xa8",
     "\xe0\xb8\xa9",
     "\xe0\xb8\xaa",
     "\xe0\xb8\xab",
     "\xe0\xb8\xac",
     "\xe0\xb8\xad",
     "\xe0\xb8\xae",
     "\xe0\xb8\xaf",
     "\xe0\xb8\xb0",
     "\xe0\xb8\xb1",
     "\xe0\xb8\xb2",
     "\xe0\xb8\xb3",
     "\xe0\xb8\xb4",
     "\xe0\xb8\xb5",
     "\xe0\xb8\xb6",
     "\xe0\xb8\xb7",
     "\xe0\xb8\xb8",
     "\xe0\xb8\xb9",
     "\xe0\xb8\xba",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xe0\xb8\xbf",
     "\xe0\xb9\x80",
     "\xe0\xb9\x81",
     "\xe0\xb9\x82",
     "\xe0\xb9\x83",
     "\xe0\xb9\x84",
     "\xe0\xb9\x85",
     "\xe0\xb9\x86",
     "\xe0\xb9\x87",
     "\xe0\xb9\x88",
     "\xe0\xb9\x89",
     "\xe0\xb9\x8a",
     "\xe0\xb9\x8b",
     "\xe0\xb9\x8c",
     "\xe0\xb9\x8d",
     "\xe0\xb9\x8e",
     "\xe0\xb9\x8f",
     "\xe0\xb9\x90",
     "\xe0\xb9\x91",
     "\xe0\xb9\x92",
     "\xe0\xb9\x93",
     "\xe0\xb9\x94",
     "\xe0\xb9\x95",
     "\xe0\xb9\x96",
     "\xe0\xb9\x97",
     "\xe0\xb9\x98",
     "\xe0\xb9\x99",
     "\xe0\xb9\x9a",
     "\xe0\xb9\x9b",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x04",
     0x00000005 => "\x05",
     0x00000006 => "\x06",
     0x00000007 => "\x07",
     0x00000008 => "\x08",
     0x00000009 => "\x09",
     0x0000000a => "\x0a",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x14",
     0x00000015 => "\x15",
     0x00000016 => "\x16",
     0x00000017 => "\x17",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x1a",
     0x0000001b => "\x1b",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x20",
     0x00000021 => "\x21",
     0x00000022 => "\x22",
     0x00000023 => "\x23",
     0x00000024 => "\x24",
     0x00000025 => "\x25",
     0x00000026 => "\x26",
     0x00000027 => "\x27",
     0x00000028 => "\x28",
     0x00000029 => "\x29",
     0x0000002a => "\x2a",
     0x0000002b => "\x2b",
     0x0000002c => "\x2c",
     0x0000002d => "\x2d",
     0x0000002e => "\x2e",
     0x0000002f => "\x2f",
     0x00000030 => "\x30",
     0x00000031 => "\x31",
     0x00000032 => "\x32",
     0x00000033 => "\x33",
     0x00000034 => "\x34",
     0x00000035 => "\x35",
     0x00000036 => "\x36",
     0x00000037 => "\x37",
     0x00000038 => "\x38",
     0x00000039 => "\x39",
     0x0000003a => "\x3a",
     0x0000003b => "\x3b",
     0x0000003c => "\x3c",
     0x0000003d => "\x3d",
     0x0000003e => "\x3e",
     0x0000003f => "\x3f",
     0x00000040 => "\x40",
     0x00000041 => "\x41",
     0x00000042 => "\x42",
     0x00000043 => "\x43",
     0x00000044 => "\x44",
     0x00000045 => "\x45",
     0x00000046 => "\x46",
     0x00000047 => "\x47",
     0x00000048 => "\x48",
     0x00000049 => "\x49",
     0x0000004a => "\x4a",
     0x0000004b => "\x4b",
     0x0000004c => "\x4c",
     0x0000004d => "\x4d",
     0x0000004e => "\x4e",
     0x0000004f => "\x4f",
     0x00000050 => "\x50",
     0x00000051 => "\x51",
     0x00000052 => "\x52",
     0x00000053 => "\x53",
     0x00000054 => "\x54",
     0x00000055 => "\x55",
     0x00000056 => "\x56",
     0x00000057 => "\x57",
     0x00000058 => "\x58",
     0x00000059 => "\x59",
     0x0000005a => "\x5a",
     0x0000005b => "\x5b",
     0x0000005c => "\x5c",
     0x0000005d => "\x5d",
     0x0000005e => "\x5e",
     0x0000005f => "\x5f",
     0x00000060 => "\x60",
     0x00000061 => "\x61",
     0x00000062 => "\x62",
     0x00000063 => "\x63",
     0x00000064 => "\x64",
     0x00000065 => "\x65",
     0x00000066 => "\x66",
     0x00000067 => "\x67",
     0x00000068 => "\x68",
     0x00000069 => "\x69",
     0x0000006a => "\x6a",
     0x0000006b => "\x6b",
     0x0000006c => "\x6c",
     0x0000006d => "\x6d",
     0x0000006e => "\x6e",
     0x0000006f => "\x6f",
     0x00000070 => "\x70",
     0x00000071 => "\x71",
     0x00000072 => "\x72",
     0x00000073 => "\x73",
     0x00000074 => "\x74",
     0x00000075 => "\x75",
     0x00000076 => "\x76",
     0x00000077 => "\x77",
     0x00000078 => "\x78",
     0x00000079 => "\x79",
     0x0000007a => "\x7a",
     0x0000007b => "\x7b",
     0x0000007c => "\x7c",
     0x0000007d => "\x7d",
     0x0000007e => "\x7e",
     0x0000007f => "\x7f",
     0x000000a0 => "\xa0",
     0x00000e01 => "\xa1",
     0x00000e02 => "\xa2",
     0x00000e03 => "\xa3",
     0x00000e04 => "\xa4",
     0x00000e05 => "\xa5",
     0x00000e06 => "\xa6",
     0x00000e07 => "\xa7",
     0x00000e08 => "\xa8",
     0x00000e09 => "\xa9",
     0x00000e0a => "\xaa",
     0x00000e0b => "\xab",
     0x00000e0c => "\xac",
     0x00000e0d => "\xad",
     0x00000e0e => "\xae",
     0x00000e0f => "\xaf",
     0x00000e10 => "\xb0",
     0x00000e11 => "\xb1",
     0x00000e12 => "\xb2",
     0x00000e13 => "\xb3",
     0x00000e14 => "\xb4",
     0x00000e15 => "\xb5",
     0x00000e16 => "\xb6",
     0x00000e17 => "\xb7",
     0x00000e18 => "\xb8",
     0x00000e19 => "\xb9",
     0x00000e1a => "\xba",
     0x00000e1b => "\xbb",
     0x00000e1c => "\xbc",
     0x00000e1d => "\xbd",
     0x00000e1e => "\xbe",
     0x00000e1f => "\xbf",
     0x00000e20 => "\xc0",
     0x00000e21 => "\xc1",
     0x00000e22 => "\xc2",
     0x00000e23 => "\xc3",
     0x00000e24 => "\xc4",
     0x00000e25 => "\xc5",
     0x00000e26 => "\xc6",
     0x00000e27 => "\xc7",
     0x00000e28 => "\xc8",
     0x00000e29 => "\xc9",
     0x00000e2a => "\xca",
     0x00000e2b => "\xcb",
     0x00000e2c => "\xcc",
     0x00000e2d => "\xcd",
     0x00000e2e => "\xce",
     0x00000e2f => "\xcf",
     0x00000e30 => "\xd0",
     0x00000e31 => "\xd1",
     0x00000e32 => "\xd2",
     0x00000e33 => "\xd3",
     0x00000e34 => "\xd4",
     0x00000e35 => "\xd5",
     0x00000e36 => "\xd6",
     0x00000e37 => "\xd7",
     0x00000e38 => "\xd8",
     0x00000e39 => "\xd9",
     0x00000e3a => "\xda",
     0x00000e3f => "\xdf",
     0x00000e40 => "\xe0",
     0x00000e41 => "\xe1",
     0x00000e42 => "\xe2",
     0x00000e43 => "\xe3",
     0x00000e44 => "\xe4",
     0x00000e45 => "\xe5",
     0x00000e46 => "\xe6",
     0x00000e47 => "\xe7",
     0x00000e48 => "\xe8",
     0x00000e49 => "\xe9",
     0x00000e4a => "\xea",
     0x00000e4b => "\xeb",
     0x00000e4c => "\xec",
     0x00000e4d => "\xed",
     0x00000e4e => "\xee",
     0x00000e4f => "\xef",
     0x00000e50 => "\xf0",
     0x00000e51 => "\xf1",
     0x00000e52 => "\xf2",
     0x00000e53 => "\xf3",
     0x00000e54 => "\xf4",
     0x00000e55 => "\xf5",
     0x00000e56 => "\xf6",
     0x00000e57 => "\xf7",
     0x00000e58 => "\xf8",
     0x00000e59 => "\xf9",
     0x00000e5a => "\xfa",
     0x00000e5b => "\xfb",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::ISO_8859_11 - Conversion routines for ISO-8859-11
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for ISO-8859-11.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  source: Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>
 
  The encoding ISO-8859-11 is not yet official at the time of this writing.
  It is based on TIS-620, but with the addition of the non-breaking space.
 
  The mapping of 0xfc-0xff is identical to Latin-1 but this should be
  checked.
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  00000004 | END OF TRANSMISSION (EOT)
     05 |  00000005 | ENQUIRY (ENQ)
     06 |  00000006 | ACKNOWLEDGE (ACK)
     07 |  00000007 | BELL (BEL)
     08 |  00000008 | BACKSPACE (BS)
     09 |  00000009 | CHARACTER TABULATION (HT)
     0A |  0000000A | LINE FEED (LF)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  00000014 | DEVICE CONTROL FOUR (DC4)
     15 |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     16 |  00000016 | SYNCHRONOUS IDLE (SYN)
     17 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  0000001A | SUBSTITUTE (SUB)
     1B |  0000001B | ESCAPE (ESC)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000020 | SPACE
     21 |  00000021 | EXCLAMATION MARK
     22 |  00000022 | QUOTATION MARK
     23 |  00000023 | NUMBER SIGN
     24 |  00000024 | DOLLAR SIGN
     25 |  00000025 | PERCENT SIGN
     26 |  00000026 | AMPERSAND
     27 |  00000027 | APOSTROPHE
     28 |  00000028 | LEFT PARENTHESIS
     29 |  00000029 | RIGHT PARENTHESIS
     2A |  0000002A | ASTERISK
     2B |  0000002B | PLUS SIGN
     2C |  0000002C | COMMA
     2D |  0000002D | HYPHEN-MINUS
     2E |  0000002E | FULL STOP
     2F |  0000002F | SOLIDUS
     30 |  00000030 | DIGIT ZERO
     31 |  00000031 | DIGIT ONE
     32 |  00000032 | DIGIT TWO
     33 |  00000033 | DIGIT THREE
     34 |  00000034 | DIGIT FOUR
     35 |  00000035 | DIGIT FIVE
     36 |  00000036 | DIGIT SIX
     37 |  00000037 | DIGIT SEVEN
     38 |  00000038 | DIGIT EIGHT
     39 |  00000039 | DIGIT NINE
     3A |  0000003A | COLON
     3B |  0000003B | SEMICOLON
     3C |  0000003C | LESS-THAN SIGN
     3D |  0000003D | EQUALS SIGN
     3E |  0000003E | GREATER-THAN SIGN
     3F |  0000003F | QUESTION MARK
     40 |  00000040 | COMMERCIAL AT
     41 |  00000041 | LATIN CAPITAL LETTER A
     42 |  00000042 | LATIN CAPITAL LETTER B
     43 |  00000043 | LATIN CAPITAL LETTER C
     44 |  00000044 | LATIN CAPITAL LETTER D
     45 |  00000045 | LATIN CAPITAL LETTER E
     46 |  00000046 | LATIN CAPITAL LETTER F
     47 |  00000047 | LATIN CAPITAL LETTER G
     48 |  00000048 | LATIN CAPITAL LETTER H
     49 |  00000049 | LATIN CAPITAL LETTER I
     4A |  0000004A | LATIN CAPITAL LETTER J
     4B |  0000004B | LATIN CAPITAL LETTER K
     4C |  0000004C | LATIN CAPITAL LETTER L
     4D |  0000004D | LATIN CAPITAL LETTER M
     4E |  0000004E | LATIN CAPITAL LETTER N
     4F |  0000004F | LATIN CAPITAL LETTER O
     50 |  00000050 | LATIN CAPITAL LETTER P
     51 |  00000051 | LATIN CAPITAL LETTER Q
     52 |  00000052 | LATIN CAPITAL LETTER R
     53 |  00000053 | LATIN CAPITAL LETTER S
     54 |  00000054 | LATIN CAPITAL LETTER T
     55 |  00000055 | LATIN CAPITAL LETTER U
     56 |  00000056 | LATIN CAPITAL LETTER V
     57 |  00000057 | LATIN CAPITAL LETTER W
     58 |  00000058 | LATIN CAPITAL LETTER X
     59 |  00000059 | LATIN CAPITAL LETTER Y
     5A |  0000005A | LATIN CAPITAL LETTER Z
     5B |  0000005B | LEFT SQUARE BRACKET
     5C |  0000005C | REVERSE SOLIDUS
     5D |  0000005D | RIGHT SQUARE BRACKET
     5E |  0000005E | CIRCUMFLEX ACCENT
     5F |  0000005F | LOW LINE
     60 |  00000060 | GRAVE ACCENT
     61 |  00000061 | LATIN SMALL LETTER A
     62 |  00000062 | LATIN SMALL LETTER B
     63 |  00000063 | LATIN SMALL LETTER C
     64 |  00000064 | LATIN SMALL LETTER D
     65 |  00000065 | LATIN SMALL LETTER E
     66 |  00000066 | LATIN SMALL LETTER F
     67 |  00000067 | LATIN SMALL LETTER G
     68 |  00000068 | LATIN SMALL LETTER H
     69 |  00000069 | LATIN SMALL LETTER I
     6A |  0000006A | LATIN SMALL LETTER J
     6B |  0000006B | LATIN SMALL LETTER K
     6C |  0000006C | LATIN SMALL LETTER L
     6D |  0000006D | LATIN SMALL LETTER M
     6E |  0000006E | LATIN SMALL LETTER N
     6F |  0000006F | LATIN SMALL LETTER O
     70 |  00000070 | LATIN SMALL LETTER P
     71 |  00000071 | LATIN SMALL LETTER Q
     72 |  00000072 | LATIN SMALL LETTER R
     73 |  00000073 | LATIN SMALL LETTER S
     74 |  00000074 | LATIN SMALL LETTER T
     75 |  00000075 | LATIN SMALL LETTER U
     76 |  00000076 | LATIN SMALL LETTER V
     77 |  00000077 | LATIN SMALL LETTER W
     78 |  00000078 | LATIN SMALL LETTER X
     79 |  00000079 | LATIN SMALL LETTER Y
     7A |  0000007A | LATIN SMALL LETTER Z
     7B |  0000007B | LEFT CURLY BRACKET
     7C |  0000007C | VERTICAL LINE
     7D |  0000007D | RIGHT CURLY BRACKET
     7E |  0000007E | TILDE
     7F |  0000007F | DELETE (DEL)
     A0 |  000000A0 | NO-BREAK SPACE
     A1 |  00000E01 | THAI CHARACTER KO KAI
     A2 |  00000E02 | THAI CHARACTER KHO KHAI
     A3 |  00000E03 | THAI CHARACTER KHO KHUAT
     A4 |  00000E04 | THAI CHARACTER KHO KHWAI
     A5 |  00000E05 | THAI CHARACTER KHO KHON
     A6 |  00000E06 | THAI CHARACTER KHO RAKHANG
     A7 |  00000E07 | THAI CHARACTER NGO NGU
     A8 |  00000E08 | THAI CHARACTER CHO CHAN
     A9 |  00000E09 | THAI CHARACTER CHO CHING
     AA |  00000E0A | THAI CHARACTER CHO CHANG
     AB |  00000E0B | THAI CHARACTER SO SO
     AC |  00000E0C | THAI CHARACTER CHO CHOE
     AD |  00000E0D | THAI CHARACTER YO YING
     AE |  00000E0E | THAI CHARACTER DO CHADA
     AF |  00000E0F | THAI CHARACTER TO PATAK
     B0 |  00000E10 | THAI CHARACTER THO THAN
     B1 |  00000E11 | THAI CHARACTER THO NANGMONTHO
     B2 |  00000E12 | THAI CHARACTER THO PHUTHAO
     B3 |  00000E13 | THAI CHARACTER NO NEN
     B4 |  00000E14 | THAI CHARACTER DO DEK
     B5 |  00000E15 | THAI CHARACTER TO TAO
     B6 |  00000E16 | THAI CHARACTER THO THUNG
     B7 |  00000E17 | THAI CHARACTER THO THAHAN
     B8 |  00000E18 | THAI CHARACTER THO THONG
     B9 |  00000E19 | THAI CHARACTER NO NU
     BA |  00000E1A | THAI CHARACTER BO BAIMAI
     BB |  00000E1B | THAI CHARACTER PO PLA
     BC |  00000E1C | THAI CHARACTER PHO PHUNG
     BD |  00000E1D | THAI CHARACTER FO FA
     BE |  00000E1E | THAI CHARACTER PHO PHAN
     BF |  00000E1F | THAI CHARACTER FO FAN
     C0 |  00000E20 | THAI CHARACTER PHO SAMPHAO
     C1 |  00000E21 | THAI CHARACTER MO MA
     C2 |  00000E22 | THAI CHARACTER YO YAK
     C3 |  00000E23 | THAI CHARACTER RO RUA
     C4 |  00000E24 | THAI CHARACTER RU
     C5 |  00000E25 | THAI CHARACTER LO LING
     C6 |  00000E26 | THAI CHARACTER LU
     C7 |  00000E27 | THAI CHARACTER WO WAEN
     C8 |  00000E28 | THAI CHARACTER SO SALA
     C9 |  00000E29 | THAI CHARACTER SO RUSI
     CA |  00000E2A | THAI CHARACTER SO SUA
     CB |  00000E2B | THAI CHARACTER HO HIP
     CC |  00000E2C | THAI CHARACTER LO CHULA
     CD |  00000E2D | THAI CHARACTER O ANG
     CE |  00000E2E | THAI CHARACTER HO NOKHUK
     CF |  00000E2F | THAI CHARACTER PAIYANNOI
     D0 |  00000E30 | THAI CHARACTER SARA A
     D1 |  00000E31 | THAI CHARACTER MAI HAN-AKAT
     D2 |  00000E32 | THAI CHARACTER SARA AA
     D3 |  00000E33 | THAI CHARACTER SARA AM
     D4 |  00000E34 | THAI CHARACTER SARA I
     D5 |  00000E35 | THAI CHARACTER SARA II
     D6 |  00000E36 | THAI CHARACTER SARA UE
     D7 |  00000E37 | THAI CHARACTER SARA UEE
     D8 |  00000E38 | THAI CHARACTER SARA U
     D9 |  00000E39 | THAI CHARACTER SARA UU
     DA |  00000E3A | THAI CHARACTER PHINTHU
     DF |  00000E3F | THAI CHARACTER SYMBOL BAHT
     E0 |  00000E40 | THAI CHARACTER SARA E
     E1 |  00000E41 | THAI CHARACTER SARA AE
     E2 |  00000E42 | THAI CHARACTER SARA O
     E3 |  00000E43 | THAI CHARACTER SARA AI MAIMUAN
     E4 |  00000E44 | THAI CHARACTER SARA AI MAIMALAI
     E5 |  00000E45 | THAI CHARACTER LAKKHANGYAO
     E6 |  00000E46 | THAI CHARACTER MAIYAMOK
     E7 |  00000E47 | THAI CHARACTER MAITAIKHU
     E8 |  00000E48 | THAI CHARACTER MAI EK
     E9 |  00000E49 | THAI CHARACTER MAI THO
     EA |  00000E4A | THAI CHARACTER MAI TRI
     EB |  00000E4B | THAI CHARACTER MAI CHATTAWA
     EC |  00000E4C | THAI CHARACTER THANTHAKHAT
     ED |  00000E4D | THAI CHARACTER NIKHAHIT
     EE |  00000E4E | THAI CHARACTER YAMAKKAN
     EF |  00000E4F | THAI CHARACTER FONGMAN
     F0 |  00000E50 | THAI DIGIT ZERO
     F1 |  00000E51 | THAI DIGIT ONE
     F2 |  00000E52 | THAI DIGIT TWO
     F3 |  00000E53 | THAI DIGIT THREE
     F4 |  00000E54 | THAI DIGIT FOUR
     F5 |  00000E55 | THAI DIGIT FIVE
     F6 |  00000E56 | THAI DIGIT SIX
     F7 |  00000E57 | THAI DIGIT SEVEN
     F8 |  00000E58 | THAI DIGIT EIGHT
     F9 |  00000E59 | THAI DIGIT NINE
     FA |  00000E5A | THAI CHARACTER ANGKHANKHU
     FB |  00000E5B | THAI CHARACTER KHOMUT
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/ISO_8859_13.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for ISO-8859-13.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::ISO_8859_13;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x0004,
     0x0005,
     0x0006,
     0x0007,
     0x0008,
     0x0009,
     0x000a,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x0014,
     0x0015,
     0x0016,
     0x0017,
     0x0018,
     0x0019,
     0x001a,
     0x001b,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0020,
     0x0021,
     0x0022,
     0x0023,
     0x0024,
     0x0025,
     0x0026,
     0x0027,
     0x0028,
     0x0029,
     0x002a,
     0x002b,
     0x002c,
     0x002d,
     0x002e,
     0x002f,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x003a,
     0x003b,
     0x003c,
     0x003d,
     0x003e,
     0x003f,
     0x0040,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x005b,
     0x005c,
     0x005d,
     0x005e,
     0x005f,
     0x0060,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x007b,
     0x007c,
     0x007d,
     0x007e,
     0x007f,
     0x0080,
     0x0081,
     0x0082,
     0x0083,
     0x0084,
     0x0085,
     0x0086,
     0x0087,
     0x0088,
     0x0089,
     0x008a,
     0x008b,
     0x008c,
     0x008d,
     0x008e,
     0x008f,
     0x0090,
     0x0091,
     0x0092,
     0x0093,
     0x0094,
     0x0095,
     0x0096,
     0x0097,
     0x0098,
     0x0099,
     0x009a,
     0x009b,
     0x009c,
     0x009d,
     0x009e,
     0x009f,
     0x00a0,
     0x201d,
     0x00a2,
     0x00a3,
     0x00a4,
     0x201e,
     0x00a6,
     0x00a7,
     0x00d8,
     0x00a9,
     0x0156,
     0x00ab,
     0x00ac,
     0x00ad,
     0x00ae,
     0x00c6,
     0x00b0,
     0x00b1,
     0x00b2,
     0x00b3,
     0x201c,
     0x00b5,
     0x00b6,
     0x00b7,
     0x00f8,
     0x00b9,
     0x0157,
     0x00bb,
     0x00bc,
     0x00bd,
     0x00be,
     0x00e6,
     0x0104,
     0x012e,
     0x0100,
     0x0106,
     0x00c4,
     0x00c5,
     0x0118,
     0x0112,
     0x010c,
     0x00c9,
     0x0179,
     0x0116,
     0x0122,
     0x0136,
     0x012a,
     0x013b,
     0x0160,
     0x0143,
     0x0145,
     0x00d3,
     0x014c,
     0x00d5,
     0x00d6,
     0x00d7,
     0x0172,
     0x0141,
     0x015a,
     0x016a,
     0x00dc,
     0x017b,
     0x017d,
     0x00df,
     0x0105,
     0x012f,
     0x0101,
     0x0107,
     0x00e4,
     0x00e5,
     0x0119,
     0x0113,
     0x010d,
     0x00e9,
     0x017a,
     0x0117,
     0x0123,
     0x0137,
     0x012b,
     0x013c,
     0x0161,
     0x0144,
     0x0146,
     0x00f3,
     0x014d,
     0x00f5,
     0x00f6,
     0x00f7,
     0x0173,
     0x0142,
     0x015b,
     0x016b,
     0x00fc,
     0x017c,
     0x017e,
     0x2019,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\x04",
     "\x05",
     "\x06",
     "\x07",
     "\x08",
     "\x09",
     "\x0a",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\x14",
     "\x15",
     "\x16",
     "\x17",
     "\x18",
     "\x19",
     "\x1a",
     "\x1b",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\x20",
     "\x21",
     "\x22",
     "\x23",
     "\x24",
     "\x25",
     "\x26",
     "\x27",
     "\x28",
     "\x29",
     "\x2a",
     "\x2b",
     "\x2c",
     "\x2d",
     "\x2e",
     "\x2f",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\x3a",
     "\x3b",
     "\x3c",
     "\x3d",
     "\x3e",
     "\x3f",
     "\x40",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\x5b",
     "\x5c",
     "\x5d",
     "\x5e",
     "\x5f",
     "\x60",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\x7b",
     "\x7c",
     "\x7d",
     "\x7e",
     "\x7f",
     "\xc2\x80",
     "\xc2\x81",
     "\xc2\x82",
     "\xc2\x83",
     "\xc2\x84",
     "\xc2\x85",
     "\xc2\x86",
     "\xc2\x87",
     "\xc2\x88",
     "\xc2\x89",
     "\xc2\x8a",
     "\xc2\x8b",
     "\xc2\x8c",
     "\xc2\x8d",
     "\xc2\x8e",
     "\xc2\x8f",
     "\xc2\x90",
     "\xc2\x91",
     "\xc2\x92",
     "\xc2\x93",
     "\xc2\x94",
     "\xc2\x95",
     "\xc2\x96",
     "\xc2\x97",
     "\xc2\x98",
     "\xc2\x99",
     "\xc2\x9a",
     "\xc2\x9b",
     "\xc2\x9c",
     "\xc2\x9d",
     "\xc2\x9e",
     "\xc2\x9f",
     "\xc2\xa0",
     "\xe2\x80\x9d",
     "\xc2\xa2",
     "\xc2\xa3",
     "\xc2\xa4",
     "\xe2\x80\x9e",
     "\xc2\xa6",
     "\xc2\xa7",
     "\xc3\x98",
     "\xc2\xa9",
     "\xc5\x96",
     "\xc2\xab",
     "\xc2\xac",
     "\xc2\xad",
     "\xc2\xae",
     "\xc3\x86",
     "\xc2\xb0",
     "\xc2\xb1",
     "\xc2\xb2",
     "\xc2\xb3",
     "\xe2\x80\x9c",
     "\xc2\xb5",
     "\xc2\xb6",
     "\xc2\xb7",
     "\xc3\xb8",
     "\xc2\xb9",
     "\xc5\x97",
     "\xc2\xbb",
     "\xc2\xbc",
     "\xc2\xbd",
     "\xc2\xbe",
     "\xc3\xa6",
     "\xc4\x84",
     "\xc4\xae",
     "\xc4\x80",
     "\xc4\x86",
     "\xc3\x84",
     "\xc3\x85",
     "\xc4\x98",
     "\xc4\x92",
     "\xc4\x8c",
     "\xc3\x89",
     "\xc5\xb9",
     "\xc4\x96",
     "\xc4\xa2",
     "\xc4\xb6",
     "\xc4\xaa",
     "\xc4\xbb",
     "\xc5\xa0",
     "\xc5\x83",
     "\xc5\x85",
     "\xc3\x93",
     "\xc5\x8c",
     "\xc3\x95",
     "\xc3\x96",
     "\xc3\x97",
     "\xc5\xb2",
     "\xc5\x81",
     "\xc5\x9a",
     "\xc5\xaa",
     "\xc3\x9c",
     "\xc5\xbb",
     "\xc5\xbd",
     "\xc3\x9f",
     "\xc4\x85",
     "\xc4\xaf",
     "\xc4\x81",
     "\xc4\x87",
     "\xc3\xa4",
     "\xc3\xa5",
     "\xc4\x99",
     "\xc4\x93",
     "\xc4\x8d",
     "\xc3\xa9",
     "\xc5\xba",
     "\xc4\x97",
     "\xc4\xa3",
     "\xc4\xb7",
     "\xc4\xab",
     "\xc4\xbc",
     "\xc5\xa1",
     "\xc5\x84",
     "\xc5\x86",
     "\xc3\xb3",
     "\xc5\x8d",
     "\xc3\xb5",
     "\xc3\xb6",
     "\xc3\xb7",
     "\xc5\xb3",
     "\xc5\x82",
     "\xc5\x9b",
     "\xc5\xab",
     "\xc3\xbc",
     "\xc5\xbc",
     "\xc5\xbe",
     "\xe2\x80\x99",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x04",
     0x00000005 => "\x05",
     0x00000006 => "\x06",
     0x00000007 => "\x07",
     0x00000008 => "\x08",
     0x00000009 => "\x09",
     0x0000000a => "\x0a",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x14",
     0x00000015 => "\x15",
     0x00000016 => "\x16",
     0x00000017 => "\x17",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x1a",
     0x0000001b => "\x1b",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x20",
     0x00000021 => "\x21",
     0x00000022 => "\x22",
     0x00000023 => "\x23",
     0x00000024 => "\x24",
     0x00000025 => "\x25",
     0x00000026 => "\x26",
     0x00000027 => "\x27",
     0x00000028 => "\x28",
     0x00000029 => "\x29",
     0x0000002a => "\x2a",
     0x0000002b => "\x2b",
     0x0000002c => "\x2c",
     0x0000002d => "\x2d",
     0x0000002e => "\x2e",
     0x0000002f => "\x2f",
     0x00000030 => "\x30",
     0x00000031 => "\x31",
     0x00000032 => "\x32",
     0x00000033 => "\x33",
     0x00000034 => "\x34",
     0x00000035 => "\x35",
     0x00000036 => "\x36",
     0x00000037 => "\x37",
     0x00000038 => "\x38",
     0x00000039 => "\x39",
     0x0000003a => "\x3a",
     0x0000003b => "\x3b",
     0x0000003c => "\x3c",
     0x0000003d => "\x3d",
     0x0000003e => "\x3e",
     0x0000003f => "\x3f",
     0x00000040 => "\x40",
     0x00000041 => "\x41",
     0x00000042 => "\x42",
     0x00000043 => "\x43",
     0x00000044 => "\x44",
     0x00000045 => "\x45",
     0x00000046 => "\x46",
     0x00000047 => "\x47",
     0x00000048 => "\x48",
     0x00000049 => "\x49",
     0x0000004a => "\x4a",
     0x0000004b => "\x4b",
     0x0000004c => "\x4c",
     0x0000004d => "\x4d",
     0x0000004e => "\x4e",
     0x0000004f => "\x4f",
     0x00000050 => "\x50",
     0x00000051 => "\x51",
     0x00000052 => "\x52",
     0x00000053 => "\x53",
     0x00000054 => "\x54",
     0x00000055 => "\x55",
     0x00000056 => "\x56",
     0x00000057 => "\x57",
     0x00000058 => "\x58",
     0x00000059 => "\x59",
     0x0000005a => "\x5a",
     0x0000005b => "\x5b",
     0x0000005c => "\x5c",
     0x0000005d => "\x5d",
     0x0000005e => "\x5e",
     0x0000005f => "\x5f",
     0x00000060 => "\x60",
     0x00000061 => "\x61",
     0x00000062 => "\x62",
     0x00000063 => "\x63",
     0x00000064 => "\x64",
     0x00000065 => "\x65",
     0x00000066 => "\x66",
     0x00000067 => "\x67",
     0x00000068 => "\x68",
     0x00000069 => "\x69",
     0x0000006a => "\x6a",
     0x0000006b => "\x6b",
     0x0000006c => "\x6c",
     0x0000006d => "\x6d",
     0x0000006e => "\x6e",
     0x0000006f => "\x6f",
     0x00000070 => "\x70",
     0x00000071 => "\x71",
     0x00000072 => "\x72",
     0x00000073 => "\x73",
     0x00000074 => "\x74",
     0x00000075 => "\x75",
     0x00000076 => "\x76",
     0x00000077 => "\x77",
     0x00000078 => "\x78",
     0x00000079 => "\x79",
     0x0000007a => "\x7a",
     0x0000007b => "\x7b",
     0x0000007c => "\x7c",
     0x0000007d => "\x7d",
     0x0000007e => "\x7e",
     0x0000007f => "\x7f",
     0x00000080 => "\x80",
     0x00000081 => "\x81",
     0x00000082 => "\x82",
     0x00000083 => "\x83",
     0x00000084 => "\x84",
     0x00000085 => "\x85",
     0x00000086 => "\x86",
     0x00000087 => "\x87",
     0x00000088 => "\x88",
     0x00000089 => "\x89",
     0x0000008a => "\x8a",
     0x0000008b => "\x8b",
     0x0000008c => "\x8c",
     0x0000008d => "\x8d",
     0x0000008e => "\x8e",
     0x0000008f => "\x8f",
     0x00000090 => "\x90",
     0x00000091 => "\x91",
     0x00000092 => "\x92",
     0x00000093 => "\x93",
     0x00000094 => "\x94",
     0x00000095 => "\x95",
     0x00000096 => "\x96",
     0x00000097 => "\x97",
     0x00000098 => "\x98",
     0x00000099 => "\x99",
     0x0000009a => "\x9a",
     0x0000009b => "\x9b",
     0x0000009c => "\x9c",
     0x0000009d => "\x9d",
     0x0000009e => "\x9e",
     0x0000009f => "\x9f",
     0x000000a0 => "\xa0",
     0x000000a2 => "\xa2",
     0x000000a3 => "\xa3",
     0x000000a4 => "\xa4",
     0x000000a6 => "\xa6",
     0x000000a7 => "\xa7",
     0x000000a9 => "\xa9",
     0x000000ab => "\xab",
     0x000000ac => "\xac",
     0x000000ad => "\xad",
     0x000000ae => "\xae",
     0x000000b0 => "\xb0",
     0x000000b1 => "\xb1",
     0x000000b2 => "\xb2",
     0x000000b3 => "\xb3",
     0x000000b5 => "\xb5",
     0x000000b6 => "\xb6",
     0x000000b7 => "\xb7",
     0x000000b9 => "\xb9",
     0x000000bb => "\xbb",
     0x000000bc => "\xbc",
     0x000000bd => "\xbd",
     0x000000be => "\xbe",
     0x000000c4 => "\xc4",
     0x000000c5 => "\xc5",
     0x000000c6 => "\xaf",
     0x000000c9 => "\xc9",
     0x000000d3 => "\xd3",
     0x000000d5 => "\xd5",
     0x000000d6 => "\xd6",
     0x000000d7 => "\xd7",
     0x000000d8 => "\xa8",
     0x000000dc => "\xdc",
     0x000000df => "\xdf",
     0x000000e4 => "\xe4",
     0x000000e5 => "\xe5",
     0x000000e6 => "\xbf",
     0x000000e9 => "\xe9",
     0x000000f3 => "\xf3",
     0x000000f5 => "\xf5",
     0x000000f6 => "\xf6",
     0x000000f7 => "\xf7",
     0x000000f8 => "\xb8",
     0x000000fc => "\xfc",
     0x00000100 => "\xc2",
     0x00000101 => "\xe2",
     0x00000104 => "\xc0",
     0x00000105 => "\xe0",
     0x00000106 => "\xc3",
     0x00000107 => "\xe3",
     0x0000010c => "\xc8",
     0x0000010d => "\xe8",
     0x00000112 => "\xc7",
     0x00000113 => "\xe7",
     0x00000116 => "\xcb",
     0x00000117 => "\xeb",
     0x00000118 => "\xc6",
     0x00000119 => "\xe6",
     0x00000122 => "\xcc",
     0x00000123 => "\xec",
     0x0000012a => "\xce",
     0x0000012b => "\xee",
     0x0000012e => "\xc1",
     0x0000012f => "\xe1",
     0x00000136 => "\xcd",
     0x00000137 => "\xed",
     0x0000013b => "\xcf",
     0x0000013c => "\xef",
     0x00000141 => "\xd9",
     0x00000142 => "\xf9",
     0x00000143 => "\xd1",
     0x00000144 => "\xf1",
     0x00000145 => "\xd2",
     0x00000146 => "\xf2",
     0x0000014c => "\xd4",
     0x0000014d => "\xf4",
     0x00000156 => "\xaa",
     0x00000157 => "\xba",
     0x0000015a => "\xda",
     0x0000015b => "\xfa",
     0x00000160 => "\xd0",
     0x00000161 => "\xf0",
     0x0000016a => "\xdb",
     0x0000016b => "\xfb",
     0x00000172 => "\xd8",
     0x00000173 => "\xf8",
     0x00000179 => "\xca",
     0x0000017a => "\xea",
     0x0000017b => "\xdd",
     0x0000017c => "\xfd",
     0x0000017d => "\xde",
     0x0000017e => "\xfe",
     0x00002019 => "\xff",
     0x0000201c => "\xb4",
     0x0000201d => "\xa1",
     0x0000201e => "\xa5",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::ISO_8859_13 - Conversion routines for ISO-8859-13
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for ISO-8859-13.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  automatically generated from the charDB
  alias ISO-IR-179
  alias LATIN7
  alias L7
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL
     01 |  00000001 | START OF HEADING
     02 |  00000002 | START OF TEXT
     03 |  00000003 | END OF TEXT
     04 |  00000004 | END OF TRANSMISSION
     05 |  00000005 | ENQUIRY
     06 |  00000006 | ACKNOWLEDGE
     07 |  00000007 | BELL
     08 |  00000008 | BACKSPACE
     09 |  00000009 | HORIZONTAL TABULATION
     0A |  0000000A | LINE FEED
     0B |  0000000B | VERTICAL TABULATION
     0C |  0000000C | FORM FEED
     0D |  0000000D | CARRIAGE RETURN
     0E |  0000000E | SHIFT OUT
     0F |  0000000F | SHIFT IN
     10 |  00000010 | DATA LINK ESCAPE
     11 |  00000011 | DEVICE CONTROL ONE
     12 |  00000012 | DEVICE CONTROL TWO
     13 |  00000013 | DEVICE CONTROL THREE
     14 |  00000014 | DEVICE CONTROL FOUR
     15 |  00000015 | NEGATIVE ACKNOWLEDGE
     16 |  00000016 | SYNCHRONOUS IDLE
     17 |  00000017 | END OF TRANSMISSION BLOCK
     18 |  00000018 | CANCEL
     19 |  00000019 | END OF MEDIUM
     1A |  0000001A | SUBSTITUTE
     1B |  0000001B | ESCAPE
     1C |  0000001C | FILE SEPARATOR
     1D |  0000001D | GROUP SEPARATOR
     1E |  0000001E | RECORD SEPARATOR
     1F |  0000001F | UNIT SEPARATOR
     20 |  00000020 | SPACE
     21 |  00000021 | EXCLAMATION MARK
     22 |  00000022 | QUOTATION MARK
     23 |  00000023 | NUMBER SIGN
     24 |  00000024 | DOLLAR SIGN
     25 |  00000025 | PERCENT SIGN
     26 |  00000026 | AMPERSAND
     27 |  00000027 | APOSTROPHE
     28 |  00000028 | LEFT PARENTHESIS
     29 |  00000029 | RIGHT PARENTHESIS
     2A |  0000002A | ASTERISK
     2B |  0000002B | PLUS SIGN
     2C |  0000002C | COMMA
     2D |  0000002D | HYPHEN-MINUS
     2E |  0000002E | FULL STOP
     2F |  0000002F | SOLIDUS
     30 |  00000030 | DIGIT ZERO
     31 |  00000031 | DIGIT ONE
     32 |  00000032 | DIGIT TWO
     33 |  00000033 | DIGIT THREE
     34 |  00000034 | DIGIT FOUR
     35 |  00000035 | DIGIT FIVE
     36 |  00000036 | DIGIT SIX
     37 |  00000037 | DIGIT SEVEN
     38 |  00000038 | DIGIT EIGHT
     39 |  00000039 | DIGIT NINE
     3A |  0000003A | COLON
     3B |  0000003B | SEMICOLON
     3C |  0000003C | LESS-THAN SIGN
     3D |  0000003D | EQUALS SIGN
     3E |  0000003E | GREATER-THAN SIGN
     3F |  0000003F | QUESTION MARK
     40 |  00000040 | COMMERCIAL AT
     41 |  00000041 | LATIN CAPITAL LETTER A
     42 |  00000042 | LATIN CAPITAL LETTER B
     43 |  00000043 | LATIN CAPITAL LETTER C
     44 |  00000044 | LATIN CAPITAL LETTER D
     45 |  00000045 | LATIN CAPITAL LETTER E
     46 |  00000046 | LATIN CAPITAL LETTER F
     47 |  00000047 | LATIN CAPITAL LETTER G
     48 |  00000048 | LATIN CAPITAL LETTER H
     49 |  00000049 | LATIN CAPITAL LETTER I
     4A |  0000004A | LATIN CAPITAL LETTER J
     4B |  0000004B | LATIN CAPITAL LETTER K
     4C |  0000004C | LATIN CAPITAL LETTER L
     4D |  0000004D | LATIN CAPITAL LETTER M
     4E |  0000004E | LATIN CAPITAL LETTER N
     4F |  0000004F | LATIN CAPITAL LETTER O
     50 |  00000050 | LATIN CAPITAL LETTER P
     51 |  00000051 | LATIN CAPITAL LETTER Q
     52 |  00000052 | LATIN CAPITAL LETTER R
     53 |  00000053 | LATIN CAPITAL LETTER S
     54 |  00000054 | LATIN CAPITAL LETTER T
     55 |  00000055 | LATIN CAPITAL LETTER U
     56 |  00000056 | LATIN CAPITAL LETTER V
     57 |  00000057 | LATIN CAPITAL LETTER W
     58 |  00000058 | LATIN CAPITAL LETTER X
     59 |  00000059 | LATIN CAPITAL LETTER Y
     5A |  0000005A | LATIN CAPITAL LETTER Z
     5B |  0000005B | LEFT SQUARE BRACKET
     5C |  0000005C | REVERSE SOLIDUS
     5D |  0000005D | RIGHT SQUARE BRACKET
     5E |  0000005E | CIRCUMFLEX ACCENT
     5F |  0000005F | LOW LINE
     60 |  00000060 | GRAVE ACCENT
     61 |  00000061 | LATIN SMALL LETTER A
     62 |  00000062 | LATIN SMALL LETTER B
     63 |  00000063 | LATIN SMALL LETTER C
     64 |  00000064 | LATIN SMALL LETTER D
     65 |  00000065 | LATIN SMALL LETTER E
     66 |  00000066 | LATIN SMALL LETTER F
     67 |  00000067 | LATIN SMALL LETTER G
     68 |  00000068 | LATIN SMALL LETTER H
     69 |  00000069 | LATIN SMALL LETTER I
     6A |  0000006A | LATIN SMALL LETTER J
     6B |  0000006B | LATIN SMALL LETTER K
     6C |  0000006C | LATIN SMALL LETTER L
     6D |  0000006D | LATIN SMALL LETTER M
     6E |  0000006E | LATIN SMALL LETTER N
     6F |  0000006F | LATIN SMALL LETTER O
     70 |  00000070 | LATIN SMALL LETTER P
     71 |  00000071 | LATIN SMALL LETTER Q
     72 |  00000072 | LATIN SMALL LETTER R
     73 |  00000073 | LATIN SMALL LETTER S
     74 |  00000074 | LATIN SMALL LETTER T
     75 |  00000075 | LATIN SMALL LETTER U
     76 |  00000076 | LATIN SMALL LETTER V
     77 |  00000077 | LATIN SMALL LETTER W
     78 |  00000078 | LATIN SMALL LETTER X
     79 |  00000079 | LATIN SMALL LETTER Y
     7A |  0000007A | LATIN SMALL LETTER Z
     7B |  0000007B | LEFT CURLY BRACKET
     7C |  0000007C | VERTICAL LINE
     7D |  0000007D | RIGHT CURLY BRACKET
     7E |  0000007E | TILDE
     7F |  0000007F | DELETE
     80 |  00000080 | PADDING CHARACTER (PAD)
     81 |  00000081 | HIGH OCTET PRESET (HOP)
     82 |  00000082 | BREAK PERMITTED HERE (BPH)
     83 |  00000083 | NO BREAK HERE (NBH)
     84 |  00000084 | INDEX (IND)
     85 |  00000085 | NEXT LINE (NEL)
     86 |  00000086 | START OF SELECTED AREA (SSA)
     87 |  00000087 | END OF SELECTED AREA (ESA)
     88 |  00000088 | CHARACTER TABULATION SET (HTS)
     89 |  00000089 | CHARACTER TABULATION WITH JUSTIFICATION (HTJ)
     8A |  0000008A | LINE TABULATION SET (VTS)
     8B |  0000008B | PARTIAL LINE FORWARD (PLD)
     8C |  0000008C | PARTIAL LINE BACKWARD (PLU)
     8D |  0000008D | REVERSE LINE FEED (RI)
     8E |  0000008E | SINGLE-SHIFT TWO (SS2)
     8F |  0000008F | SINGLE-SHIFT THREE (SS3)
     90 |  00000090 | DEVICE CONTROL STRING (DCS)
     91 |  00000091 | PRIVATE USE ONE (PU1)
     92 |  00000092 | PRIVATE USE TWO (PU2)
     93 |  00000093 | SET TRANSMIT STATE (STS)
     94 |  00000094 | CANCEL CHARACTER (CCH)
     95 |  00000095 | MESSAGE WAITING (MW)
     96 |  00000096 | START OF GUARDED AREA (SPA)
     97 |  00000097 | END OF GUARDED AREA (EPA)
     98 |  00000098 | START OF STRING (SOS)
     99 |  00000099 | SINGLE GRAPHIC CHARACTER INTRODUCER (SGCI)
     9A |  0000009A | SINGLE CHARACTER INTRODUCER (SCI)
     9B |  0000009B | CONTROL SEQUENCE INTRODUCER (CSI)
     9C |  0000009C | STRING TERMINATOR (ST)
     9D |  0000009D | OPERATING SYSTEM COMMAND (OSC)
     9E |  0000009E | PRIVACY MESSAGE (PM)
     9F |  0000009F | APPLICATION PROGRAM COMMAND (APC)
     A0 |  000000A0 | NO-BREAK SPACE
     A1 |  0000201D | RIGHT DOUBLE QUOTATION MARK
     A2 |  000000A2 | CENT SIGN
     A3 |  000000A3 | POUND SIGN
     A4 |  000000A4 | CURRENCY SIGN
     A5 |  0000201E | DOUBLE LOW-9 QUOTATION MARK
     A6 |  000000A6 | BROKEN BAR
     A7 |  000000A7 | SECTION SIGN
     A8 |  000000D8 | LATIN CAPITAL LETTER O WITH STROKE
     A9 |  000000A9 | COPYRIGHT SIGN
     AA |  00000156 | LATIN CAPITAL LETTER R WITH CEDILLA
     AB |  000000AB | LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
     AC |  000000AC | NOT SIGN
     AD |  000000AD | SOFT HYPHEN
     AE |  000000AE | REGISTERED SIGN
     AF |  000000C6 | LATIN CAPITAL LETTER AE
     B0 |  000000B0 | DEGREE SIGN
     B1 |  000000B1 | PLUS-MINUS SIGN
     B2 |  000000B2 | SUPERSCRIPT TWO
     B3 |  000000B3 | SUPERSCRIPT THREE
     B4 |  0000201C | LEFT DOUBLE QUOTATION MARK
     B5 |  000000B5 | MICRO SIGN
     B6 |  000000B6 | PILCROW SIGN
     B7 |  000000B7 | MIDDLE DOT
     B8 |  000000F8 | LATIN SMALL LETTER O WITH STROKE
     B9 |  000000B9 | SUPERSCRIPT ONE
     BA |  00000157 | LATIN SMALL LETTER R WITH CEDILLA
     BB |  000000BB | RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
     BC |  000000BC | VULGAR FRACTION ONE QUARTER
     BD |  000000BD | VULGAR FRACTION ONE HALF
     BE |  000000BE | VULGAR FRACTION THREE QUARTERS
     BF |  000000E6 | LATIN SMALL LETTER AE
     C0 |  00000104 | LATIN CAPITAL LETTER A WITH OGONEK
     C1 |  0000012E | LATIN CAPITAL LETTER I WITH OGONEK
     C2 |  00000100 | LATIN CAPITAL LETTER A WITH MACRON
     C3 |  00000106 | LATIN CAPITAL LETTER C WITH ACUTE
     C4 |  000000C4 | LATIN CAPITAL LETTER A WITH DIAERESIS
     C5 |  000000C5 | LATIN CAPITAL LETTER A WITH RING ABOVE
     C6 |  00000118 | LATIN CAPITAL LETTER E WITH OGONEK
     C7 |  00000112 | LATIN CAPITAL LETTER E WITH MACRON
     C8 |  0000010C | LATIN CAPITAL LETTER C WITH CARON
     C9 |  000000C9 | LATIN CAPITAL LETTER E WITH ACUTE
     CA |  00000179 | LATIN CAPITAL LETTER Z WITH ACUTE
     CB |  00000116 | LATIN CAPITAL LETTER E WITH DOT ABOVE
     CC |  00000122 | LATIN CAPITAL LETTER G WITH CEDILLA
     CD |  00000136 | LATIN CAPITAL LETTER K WITH CEDILLA
     CE |  0000012A | LATIN CAPITAL LETTER I WITH MACRON
     CF |  0000013B | LATIN CAPITAL LETTER L WITH CEDILLA
     D0 |  00000160 | LATIN CAPITAL LETTER S WITH CARON
     D1 |  00000143 | LATIN CAPITAL LETTER N WITH ACUTE
     D2 |  00000145 | LATIN CAPITAL LETTER N WITH CEDILLA
     D3 |  000000D3 | LATIN CAPITAL LETTER O WITH ACUTE
     D4 |  0000014C | LATIN CAPITAL LETTER O WITH MACRON
     D5 |  000000D5 | LATIN CAPITAL LETTER O WITH TILDE
     D6 |  000000D6 | LATIN CAPITAL LETTER O WITH DIAERESIS
     D7 |  000000D7 | MULTIPLICATION SIGN
     D8 |  00000172 | LATIN CAPITAL LETTER U WITH OGONEK
     D9 |  00000141 | LATIN CAPITAL LETTER L WITH STROKE
     DA |  0000015A | LATIN CAPITAL LETTER S WITH ACUTE
     DB |  0000016A | LATIN CAPITAL LETTER U WITH MACRON
     DC |  000000DC | LATIN CAPITAL LETTER U WITH DIAERESIS
     DD |  0000017B | LATIN CAPITAL LETTER Z WITH DOT ABOVE
     DE |  0000017D | LATIN CAPITAL LETTER Z WITH CARON
     DF |  000000DF | LATIN SMALL LETTER SHARP S
     E0 |  00000105 | LATIN SMALL LETTER A WITH OGONEK
     E1 |  0000012F | LATIN SMALL LETTER I WITH OGONEK
     E2 |  00000101 | LATIN SMALL LETTER A WITH MACRON
     E3 |  00000107 | LATIN SMALL LETTER C WITH ACUTE
     E4 |  000000E4 | LATIN SMALL LETTER A WITH DIAERESIS
     E5 |  000000E5 | LATIN SMALL LETTER A WITH RING ABOVE
     E6 |  00000119 | LATIN SMALL LETTER E WITH OGONEK
     E7 |  00000113 | LATIN SMALL LETTER E WITH MACRON
     E8 |  0000010D | LATIN SMALL LETTER C WITH CARON
     E9 |  000000E9 | LATIN SMALL LETTER E WITH ACUTE
     EA |  0000017A | LATIN SMALL LETTER Z WITH ACUTE
     EB |  00000117 | LATIN SMALL LETTER E WITH DOT ABOVE
     EC |  00000123 | LATIN SMALL LETTER G WITH CEDILLA
     ED |  00000137 | LATIN SMALL LETTER K WITH CEDILLA
     EE |  0000012B | LATIN SMALL LETTER I WITH MACRON
     EF |  0000013C | LATIN SMALL LETTER L WITH CEDILLA
     F0 |  00000161 | LATIN SMALL LETTER S WITH CARON
     F1 |  00000144 | LATIN SMALL LETTER N WITH ACUTE
     F2 |  00000146 | LATIN SMALL LETTER N WITH CEDILLA
     F3 |  000000F3 | LATIN SMALL LETTER O WITH ACUTE
     F4 |  0000014D | LATIN SMALL LETTER O WITH MACRON
     F5 |  000000F5 | LATIN SMALL LETTER O WITH TILDE
     F6 |  000000F6 | LATIN SMALL LETTER O WITH DIAERESIS
     F7 |  000000F7 | DIVISION SIGN
     F8 |  00000173 | LATIN SMALL LETTER U WITH OGONEK
     F9 |  00000142 | LATIN SMALL LETTER L WITH STROKE
     FA |  0000015B | LATIN SMALL LETTER S WITH ACUTE
     FB |  0000016B | LATIN SMALL LETTER U WITH MACRON
     FC |  000000FC | LATIN SMALL LETTER U WITH DIAERESIS
     FD |  0000017C | LATIN SMALL LETTER Z WITH DOT ABOVE
     FE |  0000017E | LATIN SMALL LETTER Z WITH CARON
     FF |  00002019 | RIGHT SINGLE QUOTATION MARK
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/ISO_8859_14.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for ISO-8859-14.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::ISO_8859_14;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x0004,
     0x0005,
     0x0006,
     0x0007,
     0x0008,
     0x0009,
     0x000a,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x0014,
     0x0015,
     0x0016,
     0x0017,
     0x0018,
     0x0019,
     0x001a,
     0x001b,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0020,
     0x0021,
     0x0022,
     0x0023,
     0x0024,
     0x0025,
     0x0026,
     0x0027,
     0x0028,
     0x0029,
     0x002a,
     0x002b,
     0x002c,
     0x002d,
     0x002e,
     0x002f,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x003a,
     0x003b,
     0x003c,
     0x003d,
     0x003e,
     0x003f,
     0x0040,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x005b,
     0x005c,
     0x005d,
     0x005e,
     0x005f,
     0x0060,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x007b,
     0x007c,
     0x007d,
     0x007e,
     0x007f,
     0x0080,
     0x0081,
     0x0082,
     0x0083,
     0x0084,
     0x0085,
     0x0086,
     0x0087,
     0x0088,
     0x0089,
     0x008a,
     0x008b,
     0x008c,
     0x008d,
     0x008e,
     0x008f,
     0x0090,
     0x0091,
     0x0092,
     0x0093,
     0x0094,
     0x0095,
     0x0096,
     0x0097,
     0x0098,
     0x0099,
     0x009a,
     0x009b,
     0x009c,
     0x009d,
     0x009e,
     0x009f,
     0x00a0,
     0x1e02,
     0x1e03,
     0x00a3,
     0x010a,
     0x010b,
     0x1e0a,
     0x00a7,
     0x1e80,
     0x00a9,
     0x1e82,
     0x1e0b,
     0x1ef2,
     0x00ad,
     0x00ae,
     0x0178,
     0x1e1e,
     0x1e1f,
     0x0120,
     0x0121,
     0x1e40,
     0x1e41,
     0x00b6,
     0x1e56,
     0x1e81,
     0x1e57,
     0x1e83,
     0x1e60,
     0x1ef3,
     0x1e84,
     0x1e85,
     0x1e61,
     0x00c0,
     0x00c1,
     0x00c2,
     0x00c3,
     0x00c4,
     0x00c5,
     0x00c6,
     0x00c7,
     0x00c8,
     0x00c9,
     0x00ca,
     0x00cb,
     0x00cc,
     0x00cd,
     0x00ce,
     0x00cf,
     0x0174,
     0x00d1,
     0x00d2,
     0x00d3,
     0x00d4,
     0x00d5,
     0x00d6,
     0x1e6a,
     0x00d8,
     0x00d9,
     0x00da,
     0x00db,
     0x00dc,
     0x00dd,
     0x0176,
     0x00df,
     0x00e0,
     0x00e1,
     0x00e2,
     0x00e3,
     0x00e4,
     0x00e5,
     0x00e6,
     0x00e7,
     0x00e8,
     0x00e9,
     0x00ea,
     0x00eb,
     0x00ec,
     0x00ed,
     0x00ee,
     0x00ef,
     0x0175,
     0x00f1,
     0x00f2,
     0x00f3,
     0x00f4,
     0x00f5,
     0x00f6,
     0x1e6b,
     0x00f8,
     0x00f9,
     0x00fa,
     0x00fb,
     0x00fc,
     0x00fd,
     0x0177,
     0x00ff,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\x04",
     "\x05",
     "\x06",
     "\x07",
     "\x08",
     "\x09",
     "\x0a",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\x14",
     "\x15",
     "\x16",
     "\x17",
     "\x18",
     "\x19",
     "\x1a",
     "\x1b",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\x20",
     "\x21",
     "\x22",
     "\x23",
     "\x24",
     "\x25",
     "\x26",
     "\x27",
     "\x28",
     "\x29",
     "\x2a",
     "\x2b",
     "\x2c",
     "\x2d",
     "\x2e",
     "\x2f",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\x3a",
     "\x3b",
     "\x3c",
     "\x3d",
     "\x3e",
     "\x3f",
     "\x40",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\x5b",
     "\x5c",
     "\x5d",
     "\x5e",
     "\x5f",
     "\x60",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\x7b",
     "\x7c",
     "\x7d",
     "\x7e",
     "\x7f",
     "\xc2\x80",
     "\xc2\x81",
     "\xc2\x82",
     "\xc2\x83",
     "\xc2\x84",
     "\xc2\x85",
     "\xc2\x86",
     "\xc2\x87",
     "\xc2\x88",
     "\xc2\x89",
     "\xc2\x8a",
     "\xc2\x8b",
     "\xc2\x8c",
     "\xc2\x8d",
     "\xc2\x8e",
     "\xc2\x8f",
     "\xc2\x90",
     "\xc2\x91",
     "\xc2\x92",
     "\xc2\x93",
     "\xc2\x94",
     "\xc2\x95",
     "\xc2\x96",
     "\xc2\x97",
     "\xc2\x98",
     "\xc2\x99",
     "\xc2\x9a",
     "\xc2\x9b",
     "\xc2\x9c",
     "\xc2\x9d",
     "\xc2\x9e",
     "\xc2\x9f",
     "\xc2\xa0",
     "\xe1\xb8\x82",
     "\xe1\xb8\x83",
     "\xc2\xa3",
     "\xc4\x8a",
     "\xc4\x8b",
     "\xe1\xb8\x8a",
     "\xc2\xa7",
     "\xe1\xba\x80",
     "\xc2\xa9",
     "\xe1\xba\x82",
     "\xe1\xb8\x8b",
     "\xe1\xbb\xb2",
     "\xc2\xad",
     "\xc2\xae",
     "\xc5\xb8",
     "\xe1\xb8\x9e",
     "\xe1\xb8\x9f",
     "\xc4\xa0",
     "\xc4\xa1",
     "\xe1\xb9\x80",
     "\xe1\xb9\x81",
     "\xc2\xb6",
     "\xe1\xb9\x96",
     "\xe1\xba\x81",
     "\xe1\xb9\x97",
     "\xe1\xba\x83",
     "\xe1\xb9\xa0",
     "\xe1\xbb\xb3",
     "\xe1\xba\x84",
     "\xe1\xba\x85",
     "\xe1\xb9\xa1",
     "\xc3\x80",
     "\xc3\x81",
     "\xc3\x82",
     "\xc3\x83",
     "\xc3\x84",
     "\xc3\x85",
     "\xc3\x86",
     "\xc3\x87",
     "\xc3\x88",
     "\xc3\x89",
     "\xc3\x8a",
     "\xc3\x8b",
     "\xc3\x8c",
     "\xc3\x8d",
     "\xc3\x8e",
     "\xc3\x8f",
     "\xc5\xb4",
     "\xc3\x91",
     "\xc3\x92",
     "\xc3\x93",
     "\xc3\x94",
     "\xc3\x95",
     "\xc3\x96",
     "\xe1\xb9\xaa",
     "\xc3\x98",
     "\xc3\x99",
     "\xc3\x9a",
     "\xc3\x9b",
     "\xc3\x9c",
     "\xc3\x9d",
     "\xc5\xb6",
     "\xc3\x9f",
     "\xc3\xa0",
     "\xc3\xa1",
     "\xc3\xa2",
     "\xc3\xa3",
     "\xc3\xa4",
     "\xc3\xa5",
     "\xc3\xa6",
     "\xc3\xa7",
     "\xc3\xa8",
     "\xc3\xa9",
     "\xc3\xaa",
     "\xc3\xab",
     "\xc3\xac",
     "\xc3\xad",
     "\xc3\xae",
     "\xc3\xaf",
     "\xc5\xb5",
     "\xc3\xb1",
     "\xc3\xb2",
     "\xc3\xb3",
     "\xc3\xb4",
     "\xc3\xb5",
     "\xc3\xb6",
     "\xe1\xb9\xab",
     "\xc3\xb8",
     "\xc3\xb9",
     "\xc3\xba",
     "\xc3\xbb",
     "\xc3\xbc",
     "\xc3\xbd",
     "\xc5\xb7",
     "\xc3\xbf",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x04",
     0x00000005 => "\x05",
     0x00000006 => "\x06",
     0x00000007 => "\x07",
     0x00000008 => "\x08",
     0x00000009 => "\x09",
     0x0000000a => "\x0a",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x14",
     0x00000015 => "\x15",
     0x00000016 => "\x16",
     0x00000017 => "\x17",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x1a",
     0x0000001b => "\x1b",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x20",
     0x00000021 => "\x21",
     0x00000022 => "\x22",
     0x00000023 => "\x23",
     0x00000024 => "\x24",
     0x00000025 => "\x25",
     0x00000026 => "\x26",
     0x00000027 => "\x27",
     0x00000028 => "\x28",
     0x00000029 => "\x29",
     0x0000002a => "\x2a",
     0x0000002b => "\x2b",
     0x0000002c => "\x2c",
     0x0000002d => "\x2d",
     0x0000002e => "\x2e",
     0x0000002f => "\x2f",
     0x00000030 => "\x30",
     0x00000031 => "\x31",
     0x00000032 => "\x32",
     0x00000033 => "\x33",
     0x00000034 => "\x34",
     0x00000035 => "\x35",
     0x00000036 => "\x36",
     0x00000037 => "\x37",
     0x00000038 => "\x38",
     0x00000039 => "\x39",
     0x0000003a => "\x3a",
     0x0000003b => "\x3b",
     0x0000003c => "\x3c",
     0x0000003d => "\x3d",
     0x0000003e => "\x3e",
     0x0000003f => "\x3f",
     0x00000040 => "\x40",
     0x00000041 => "\x41",
     0x00000042 => "\x42",
     0x00000043 => "\x43",
     0x00000044 => "\x44",
     0x00000045 => "\x45",
     0x00000046 => "\x46",
     0x00000047 => "\x47",
     0x00000048 => "\x48",
     0x00000049 => "\x49",
     0x0000004a => "\x4a",
     0x0000004b => "\x4b",
     0x0000004c => "\x4c",
     0x0000004d => "\x4d",
     0x0000004e => "\x4e",
     0x0000004f => "\x4f",
     0x00000050 => "\x50",
     0x00000051 => "\x51",
     0x00000052 => "\x52",
     0x00000053 => "\x53",
     0x00000054 => "\x54",
     0x00000055 => "\x55",
     0x00000056 => "\x56",
     0x00000057 => "\x57",
     0x00000058 => "\x58",
     0x00000059 => "\x59",
     0x0000005a => "\x5a",
     0x0000005b => "\x5b",
     0x0000005c => "\x5c",
     0x0000005d => "\x5d",
     0x0000005e => "\x5e",
     0x0000005f => "\x5f",
     0x00000060 => "\x60",
     0x00000061 => "\x61",
     0x00000062 => "\x62",
     0x00000063 => "\x63",
     0x00000064 => "\x64",
     0x00000065 => "\x65",
     0x00000066 => "\x66",
     0x00000067 => "\x67",
     0x00000068 => "\x68",
     0x00000069 => "\x69",
     0x0000006a => "\x6a",
     0x0000006b => "\x6b",
     0x0000006c => "\x6c",
     0x0000006d => "\x6d",
     0x0000006e => "\x6e",
     0x0000006f => "\x6f",
     0x00000070 => "\x70",
     0x00000071 => "\x71",
     0x00000072 => "\x72",
     0x00000073 => "\x73",
     0x00000074 => "\x74",
     0x00000075 => "\x75",
     0x00000076 => "\x76",
     0x00000077 => "\x77",
     0x00000078 => "\x78",
     0x00000079 => "\x79",
     0x0000007a => "\x7a",
     0x0000007b => "\x7b",
     0x0000007c => "\x7c",
     0x0000007d => "\x7d",
     0x0000007e => "\x7e",
     0x0000007f => "\x7f",
     0x00000080 => "\x80",
     0x00000081 => "\x81",
     0x00000082 => "\x82",
     0x00000083 => "\x83",
     0x00000084 => "\x84",
     0x00000085 => "\x85",
     0x00000086 => "\x86",
     0x00000087 => "\x87",
     0x00000088 => "\x88",
     0x00000089 => "\x89",
     0x0000008a => "\x8a",
     0x0000008b => "\x8b",
     0x0000008c => "\x8c",
     0x0000008d => "\x8d",
     0x0000008e => "\x8e",
     0x0000008f => "\x8f",
     0x00000090 => "\x90",
     0x00000091 => "\x91",
     0x00000092 => "\x92",
     0x00000093 => "\x93",
     0x00000094 => "\x94",
     0x00000095 => "\x95",
     0x00000096 => "\x96",
     0x00000097 => "\x97",
     0x00000098 => "\x98",
     0x00000099 => "\x99",
     0x0000009a => "\x9a",
     0x0000009b => "\x9b",
     0x0000009c => "\x9c",
     0x0000009d => "\x9d",
     0x0000009e => "\x9e",
     0x0000009f => "\x9f",
     0x000000a0 => "\xa0",
     0x000000a3 => "\xa3",
     0x000000a7 => "\xa7",
     0x000000a9 => "\xa9",
     0x000000ad => "\xad",
     0x000000ae => "\xae",
     0x000000b6 => "\xb6",
     0x000000c0 => "\xc0",
     0x000000c1 => "\xc1",
     0x000000c2 => "\xc2",
     0x000000c3 => "\xc3",
     0x000000c4 => "\xc4",
     0x000000c5 => "\xc5",
     0x000000c6 => "\xc6",
     0x000000c7 => "\xc7",
     0x000000c8 => "\xc8",
     0x000000c9 => "\xc9",
     0x000000ca => "\xca",
     0x000000cb => "\xcb",
     0x000000cc => "\xcc",
     0x000000cd => "\xcd",
     0x000000ce => "\xce",
     0x000000cf => "\xcf",
     0x000000d1 => "\xd1",
     0x000000d2 => "\xd2",
     0x000000d3 => "\xd3",
     0x000000d4 => "\xd4",
     0x000000d5 => "\xd5",
     0x000000d6 => "\xd6",
     0x000000d8 => "\xd8",
     0x000000d9 => "\xd9",
     0x000000da => "\xda",
     0x000000db => "\xdb",
     0x000000dc => "\xdc",
     0x000000dd => "\xdd",
     0x000000df => "\xdf",
     0x000000e0 => "\xe0",
     0x000000e1 => "\xe1",
     0x000000e2 => "\xe2",
     0x000000e3 => "\xe3",
     0x000000e4 => "\xe4",
     0x000000e5 => "\xe5",
     0x000000e6 => "\xe6",
     0x000000e7 => "\xe7",
     0x000000e8 => "\xe8",
     0x000000e9 => "\xe9",
     0x000000ea => "\xea",
     0x000000eb => "\xeb",
     0x000000ec => "\xec",
     0x000000ed => "\xed",
     0x000000ee => "\xee",
     0x000000ef => "\xef",
     0x000000f1 => "\xf1",
     0x000000f2 => "\xf2",
     0x000000f3 => "\xf3",
     0x000000f4 => "\xf4",
     0x000000f5 => "\xf5",
     0x000000f6 => "\xf6",
     0x000000f8 => "\xf8",
     0x000000f9 => "\xf9",
     0x000000fa => "\xfa",
     0x000000fb => "\xfb",
     0x000000fc => "\xfc",
     0x000000fd => "\xfd",
     0x000000ff => "\xff",
     0x0000010a => "\xa4",
     0x0000010b => "\xa5",
     0x00000120 => "\xb2",
     0x00000121 => "\xb3",
     0x00000174 => "\xd0",
     0x00000175 => "\xf0",
     0x00000176 => "\xde",
     0x00000177 => "\xfe",
     0x00000178 => "\xaf",
     0x00001e02 => "\xa1",
     0x00001e03 => "\xa2",
     0x00001e0a => "\xa6",
     0x00001e0b => "\xab",
     0x00001e1e => "\xb0",
     0x00001e1f => "\xb1",
     0x00001e40 => "\xb4",
     0x00001e41 => "\xb5",
     0x00001e56 => "\xb7",
     0x00001e57 => "\xb9",
     0x00001e60 => "\xbb",
     0x00001e61 => "\xbf",
     0x00001e6a => "\xd7",
     0x00001e6b => "\xf7",
     0x00001e80 => "\xa8",
     0x00001e81 => "\xb8",
     0x00001e82 => "\xaa",
     0x00001e83 => "\xba",
     0x00001e84 => "\xbd",
     0x00001e85 => "\xbe",
     0x00001ef2 => "\xac",
     0x00001ef3 => "\xbc",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::ISO_8859_14 - Conversion routines for ISO-8859-14
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for ISO-8859-14.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  automatically generated from the charDB
  alias LATIN8
  alias L8
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL
     01 |  00000001 | START OF HEADING
     02 |  00000002 | START OF TEXT
     03 |  00000003 | END OF TEXT
     04 |  00000004 | END OF TRANSMISSION
     05 |  00000005 | ENQUIRY
     06 |  00000006 | ACKNOWLEDGE
     07 |  00000007 | BELL
     08 |  00000008 | BACKSPACE
     09 |  00000009 | HORIZONTAL TABULATION
     0A |  0000000A | LINE FEED
     0B |  0000000B | VERTICAL TABULATION
     0C |  0000000C | FORM FEED
     0D |  0000000D | CARRIAGE RETURN
     0E |  0000000E | SHIFT OUT
     0F |  0000000F | SHIFT IN
     10 |  00000010 | DATA LINK ESCAPE
     11 |  00000011 | DEVICE CONTROL ONE
     12 |  00000012 | DEVICE CONTROL TWO
     13 |  00000013 | DEVICE CONTROL THREE
     14 |  00000014 | DEVICE CONTROL FOUR
     15 |  00000015 | NEGATIVE ACKNOWLEDGE
     16 |  00000016 | SYNCHRONOUS IDLE
     17 |  00000017 | END OF TRANSMISSION BLOCK
     18 |  00000018 | CANCEL
     19 |  00000019 | END OF MEDIUM
     1A |  0000001A | SUBSTITUTE
     1B |  0000001B | ESCAPE
     1C |  0000001C | FILE SEPARATOR
     1D |  0000001D | GROUP SEPARATOR
     1E |  0000001E | RECORD SEPARATOR
     1F |  0000001F | UNIT SEPARATOR
     20 |  00000020 | SPACE
     21 |  00000021 | EXCLAMATION MARK
     22 |  00000022 | QUOTATION MARK
     23 |  00000023 | NUMBER SIGN
     24 |  00000024 | DOLLAR SIGN
     25 |  00000025 | PERCENT SIGN
     26 |  00000026 | AMPERSAND
     27 |  00000027 | APOSTROPHE
     28 |  00000028 | LEFT PARENTHESIS
     29 |  00000029 | RIGHT PARENTHESIS
     2A |  0000002A | ASTERISK
     2B |  0000002B | PLUS SIGN
     2C |  0000002C | COMMA
     2D |  0000002D | HYPHEN-MINUS
     2E |  0000002E | FULL STOP
     2F |  0000002F | SOLIDUS
     30 |  00000030 | DIGIT ZERO
     31 |  00000031 | DIGIT ONE
     32 |  00000032 | DIGIT TWO
     33 |  00000033 | DIGIT THREE
     34 |  00000034 | DIGIT FOUR
     35 |  00000035 | DIGIT FIVE
     36 |  00000036 | DIGIT SIX
     37 |  00000037 | DIGIT SEVEN
     38 |  00000038 | DIGIT EIGHT
     39 |  00000039 | DIGIT NINE
     3A |  0000003A | COLON
     3B |  0000003B | SEMICOLON
     3C |  0000003C | LESS-THAN SIGN
     3D |  0000003D | EQUALS SIGN
     3E |  0000003E | GREATER-THAN SIGN
     3F |  0000003F | QUESTION MARK
     40 |  00000040 | COMMERCIAL AT
     41 |  00000041 | LATIN CAPITAL LETTER A
     42 |  00000042 | LATIN CAPITAL LETTER B
     43 |  00000043 | LATIN CAPITAL LETTER C
     44 |  00000044 | LATIN CAPITAL LETTER D
     45 |  00000045 | LATIN CAPITAL LETTER E
     46 |  00000046 | LATIN CAPITAL LETTER F
     47 |  00000047 | LATIN CAPITAL LETTER G
     48 |  00000048 | LATIN CAPITAL LETTER H
     49 |  00000049 | LATIN CAPITAL LETTER I
     4A |  0000004A | LATIN CAPITAL LETTER J
     4B |  0000004B | LATIN CAPITAL LETTER K
     4C |  0000004C | LATIN CAPITAL LETTER L
     4D |  0000004D | LATIN CAPITAL LETTER M
     4E |  0000004E | LATIN CAPITAL LETTER N
     4F |  0000004F | LATIN CAPITAL LETTER O
     50 |  00000050 | LATIN CAPITAL LETTER P
     51 |  00000051 | LATIN CAPITAL LETTER Q
     52 |  00000052 | LATIN CAPITAL LETTER R
     53 |  00000053 | LATIN CAPITAL LETTER S
     54 |  00000054 | LATIN CAPITAL LETTER T
     55 |  00000055 | LATIN CAPITAL LETTER U
     56 |  00000056 | LATIN CAPITAL LETTER V
     57 |  00000057 | LATIN CAPITAL LETTER W
     58 |  00000058 | LATIN CAPITAL LETTER X
     59 |  00000059 | LATIN CAPITAL LETTER Y
     5A |  0000005A | LATIN CAPITAL LETTER Z
     5B |  0000005B | LEFT SQUARE BRACKET
     5C |  0000005C | REVERSE SOLIDUS
     5D |  0000005D | RIGHT SQUARE BRACKET
     5E |  0000005E | CIRCUMFLEX ACCENT
     5F |  0000005F | LOW LINE
     60 |  00000060 | GRAVE ACCENT
     61 |  00000061 | LATIN SMALL LETTER A
     62 |  00000062 | LATIN SMALL LETTER B
     63 |  00000063 | LATIN SMALL LETTER C
     64 |  00000064 | LATIN SMALL LETTER D
     65 |  00000065 | LATIN SMALL LETTER E
     66 |  00000066 | LATIN SMALL LETTER F
     67 |  00000067 | LATIN SMALL LETTER G
     68 |  00000068 | LATIN SMALL LETTER H
     69 |  00000069 | LATIN SMALL LETTER I
     6A |  0000006A | LATIN SMALL LETTER J
     6B |  0000006B | LATIN SMALL LETTER K
     6C |  0000006C | LATIN SMALL LETTER L
     6D |  0000006D | LATIN SMALL LETTER M
     6E |  0000006E | LATIN SMALL LETTER N
     6F |  0000006F | LATIN SMALL LETTER O
     70 |  00000070 | LATIN SMALL LETTER P
     71 |  00000071 | LATIN SMALL LETTER Q
     72 |  00000072 | LATIN SMALL LETTER R
     73 |  00000073 | LATIN SMALL LETTER S
     74 |  00000074 | LATIN SMALL LETTER T
     75 |  00000075 | LATIN SMALL LETTER U
     76 |  00000076 | LATIN SMALL LETTER V
     77 |  00000077 | LATIN SMALL LETTER W
     78 |  00000078 | LATIN SMALL LETTER X
     79 |  00000079 | LATIN SMALL LETTER Y
     7A |  0000007A | LATIN SMALL LETTER Z
     7B |  0000007B | LEFT CURLY BRACKET
     7C |  0000007C | VERTICAL LINE
     7D |  0000007D | RIGHT CURLY BRACKET
     7E |  0000007E | TILDE
     7F |  0000007F | DELETE
     80 |  00000080 | PADDING CHARACTER (PAD)
     81 |  00000081 | HIGH OCTET PRESET (HOP)
     82 |  00000082 | BREAK PERMITTED HERE (BPH)
     83 |  00000083 | NO BREAK HERE (NBH)
     84 |  00000084 | INDEX (IND)
     85 |  00000085 | NEXT LINE (NEL)
     86 |  00000086 | START OF SELECTED AREA (SSA)
     87 |  00000087 | END OF SELECTED AREA (ESA)
     88 |  00000088 | CHARACTER TABULATION SET (HTS)
     89 |  00000089 | CHARACTER TABULATION WITH JUSTIFICATION (HTJ)
     8A |  0000008A | LINE TABULATION SET (VTS)
     8B |  0000008B | PARTIAL LINE FORWARD (PLD)
     8C |  0000008C | PARTIAL LINE BACKWARD (PLU)
     8D |  0000008D | REVERSE LINE FEED (RI)
     8E |  0000008E | SINGLE-SHIFT TWO (SS2)
     8F |  0000008F | SINGLE-SHIFT THREE (SS3)
     90 |  00000090 | DEVICE CONTROL STRING (DCS)
     91 |  00000091 | PRIVATE USE ONE (PU1)
     92 |  00000092 | PRIVATE USE TWO (PU2)
     93 |  00000093 | SET TRANSMIT STATE (STS)
     94 |  00000094 | CANCEL CHARACTER (CCH)
     95 |  00000095 | MESSAGE WAITING (MW)
     96 |  00000096 | START OF GUARDED AREA (SPA)
     97 |  00000097 | END OF GUARDED AREA (EPA)
     98 |  00000098 | START OF STRING (SOS)
     99 |  00000099 | SINGLE GRAPHIC CHARACTER INTRODUCER (SGCI)
     9A |  0000009A | SINGLE CHARACTER INTRODUCER (SCI)
     9B |  0000009B | CONTROL SEQUENCE INTRODUCER (CSI)
     9C |  0000009C | STRING TERMINATOR (ST)
     9D |  0000009D | OPERATING SYSTEM COMMAND (OSC)
     9E |  0000009E | PRIVACY MESSAGE (PM)
     9F |  0000009F | APPLICATION PROGRAM COMMAND (APC)
     A0 |  000000A0 | NO-BREAK SPACE
     A1 |  00001E02 | LATIN CAPITAL LETTER B WITH DOT ABOVE
     A2 |  00001E03 | LATIN SMALL LETTER B WITH DOT ABOVE
     A3 |  000000A3 | POUND SIGN
     A4 |  0000010A | LATIN CAPITAL LETTER C WITH DOT ABOVE
     A5 |  0000010B | LATIN SMALL LETTER C WITH DOT ABOVE
     A6 |  00001E0A | LATIN CAPITAL LETTER D WITH DOT ABOVE
     A7 |  000000A7 | SECTION SIGN
     A8 |  00001E80 | LATIN CAPITAL LETTER W WITH GRAVE
     A9 |  000000A9 | COPYRIGHT SIGN
     AA |  00001E82 | LATIN CAPITAL LETTER W WITH ACUTE
     AB |  00001E0B | LATIN SMALL LETTER D WITH DOT ABOVE
     AC |  00001EF2 | LATIN CAPITAL LETTER Y WITH GRAVE
     AD |  000000AD | SOFT HYPHEN
     AE |  000000AE | REGISTERED SIGN
     AF |  00000178 | LATIN CAPITAL LETTER Y WITH DIAERESIS
     B0 |  00001E1E | LATIN CAPITAL LETTER F WITH DOT ABOVE
     B1 |  00001E1F | LATIN SMALL LETTER F WITH DOT ABOVE
     B2 |  00000120 | LATIN CAPITAL LETTER G WITH DOT ABOVE
     B3 |  00000121 | LATIN SMALL LETTER G WITH DOT ABOVE
     B4 |  00001E40 | LATIN CAPITAL LETTER M WITH DOT ABOVE
     B5 |  00001E41 | LATIN SMALL LETTER M WITH DOT ABOVE
     B6 |  000000B6 | PILCROW SIGN
     B7 |  00001E56 | LATIN CAPITAL LETTER P WITH DOT ABOVE
     B8 |  00001E81 | LATIN SMALL LETTER W WITH GRAVE
     B9 |  00001E57 | LATIN SMALL LETTER P WITH DOT ABOVE
     BA |  00001E83 | LATIN SMALL LETTER W WITH ACUTE
     BB |  00001E60 | LATIN CAPITAL LETTER S WITH DOT ABOVE
     BC |  00001EF3 | LATIN SMALL LETTER Y WITH GRAVE
     BD |  00001E84 | LATIN CAPITAL LETTER W WITH DIAERESIS
     BE |  00001E85 | LATIN SMALL LETTER W WITH DIAERESIS
     BF |  00001E61 | LATIN SMALL LETTER S WITH DOT ABOVE
     C0 |  000000C0 | LATIN CAPITAL LETTER A WITH GRAVE
     C1 |  000000C1 | LATIN CAPITAL LETTER A WITH ACUTE
     C2 |  000000C2 | LATIN CAPITAL LETTER A WITH CIRCUMFLEX
     C3 |  000000C3 | LATIN CAPITAL LETTER A WITH TILDE
     C4 |  000000C4 | LATIN CAPITAL LETTER A WITH DIAERESIS
     C5 |  000000C5 | LATIN CAPITAL LETTER A WITH RING ABOVE
     C6 |  000000C6 | LATIN CAPITAL LETTER AE
     C7 |  000000C7 | LATIN CAPITAL LETTER C WITH CEDILLA
     C8 |  000000C8 | LATIN CAPITAL LETTER E WITH GRAVE
     C9 |  000000C9 | LATIN CAPITAL LETTER E WITH ACUTE
     CA |  000000CA | LATIN CAPITAL LETTER E WITH CIRCUMFLEX
     CB |  000000CB | LATIN CAPITAL LETTER E WITH DIAERESIS
     CC |  000000CC | LATIN CAPITAL LETTER I WITH GRAVE
     CD |  000000CD | LATIN CAPITAL LETTER I WITH ACUTE
     CE |  000000CE | LATIN CAPITAL LETTER I WITH CIRCUMFLEX
     CF |  000000CF | LATIN CAPITAL LETTER I WITH DIAERESIS
     D0 |  00000174 | LATIN CAPITAL LETTER W WITH CIRCUMFLEX
     D1 |  000000D1 | LATIN CAPITAL LETTER N WITH TILDE
     D2 |  000000D2 | LATIN CAPITAL LETTER O WITH GRAVE
     D3 |  000000D3 | LATIN CAPITAL LETTER O WITH ACUTE
     D4 |  000000D4 | LATIN CAPITAL LETTER O WITH CIRCUMFLEX
     D5 |  000000D5 | LATIN CAPITAL LETTER O WITH TILDE
     D6 |  000000D6 | LATIN CAPITAL LETTER O WITH DIAERESIS
     D7 |  00001E6A | LATIN CAPITAL LETTER T WITH DOT ABOVE
     D8 |  000000D8 | LATIN CAPITAL LETTER O WITH STROKE
     D9 |  000000D9 | LATIN CAPITAL LETTER U WITH GRAVE
     DA |  000000DA | LATIN CAPITAL LETTER U WITH ACUTE
     DB |  000000DB | LATIN CAPITAL LETTER U WITH CIRCUMFLEX
     DC |  000000DC | LATIN CAPITAL LETTER U WITH DIAERESIS
     DD |  000000DD | LATIN CAPITAL LETTER Y WITH ACUTE
     DE |  00000176 | LATIN CAPITAL LETTER Y WITH CIRCUMFLEX
     DF |  000000DF | LATIN SMALL LETTER SHARP S
     E0 |  000000E0 | LATIN SMALL LETTER A WITH GRAVE
     E1 |  000000E1 | LATIN SMALL LETTER A WITH ACUTE
     E2 |  000000E2 | LATIN SMALL LETTER A WITH CIRCUMFLEX
     E3 |  000000E3 | LATIN SMALL LETTER A WITH TILDE
     E4 |  000000E4 | LATIN SMALL LETTER A WITH DIAERESIS
     E5 |  000000E5 | LATIN SMALL LETTER A WITH RING ABOVE
     E6 |  000000E6 | LATIN SMALL LETTER AE
     E7 |  000000E7 | LATIN SMALL LETTER C WITH CEDILLA
     E8 |  000000E8 | LATIN SMALL LETTER E WITH GRAVE
     E9 |  000000E9 | LATIN SMALL LETTER E WITH ACUTE
     EA |  000000EA | LATIN SMALL LETTER E WITH CIRCUMFLEX
     EB |  000000EB | LATIN SMALL LETTER E WITH DIAERESIS
     EC |  000000EC | LATIN SMALL LETTER I WITH GRAVE
     ED |  000000ED | LATIN SMALL LETTER I WITH ACUTE
     EE |  000000EE | LATIN SMALL LETTER I WITH CIRCUMFLEX
     EF |  000000EF | LATIN SMALL LETTER I WITH DIAERESIS
     F0 |  00000175 | LATIN SMALL LETTER W WITH CIRCUMFLEX
     F1 |  000000F1 | LATIN SMALL LETTER N WITH TILDE
     F2 |  000000F2 | LATIN SMALL LETTER O WITH GRAVE
     F3 |  000000F3 | LATIN SMALL LETTER O WITH ACUTE
     F4 |  000000F4 | LATIN SMALL LETTER O WITH CIRCUMFLEX
     F5 |  000000F5 | LATIN SMALL LETTER O WITH TILDE
     F6 |  000000F6 | LATIN SMALL LETTER O WITH DIAERESIS
     F7 |  00001E6B | LATIN SMALL LETTER T WITH DOT ABOVE
     F8 |  000000F8 | LATIN SMALL LETTER O WITH STROKE
     F9 |  000000F9 | LATIN SMALL LETTER U WITH GRAVE
     FA |  000000FA | LATIN SMALL LETTER U WITH ACUTE
     FB |  000000FB | LATIN SMALL LETTER U WITH CIRCUMFLEX
     FC |  000000FC | LATIN SMALL LETTER U WITH DIAERESIS
     FD |  000000FD | LATIN SMALL LETTER Y WITH ACUTE
     FE |  00000177 | LATIN SMALL LETTER Y WITH CIRCUMFLEX
     FF |  000000FF | LATIN SMALL LETTER Y WITH DIAERESIS
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/ISO_8859_15.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for ISO-8859-15.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::ISO_8859_15;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x0004,
     0x0005,
     0x0006,
     0x0007,
     0x0008,
     0x0009,
     0x000a,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x0014,
     0x0015,
     0x0016,
     0x0017,
     0x0018,
     0x0019,
     0x001a,
     0x001b,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0020,
     0x0021,
     0x0022,
     0x0023,
     0x0024,
     0x0025,
     0x0026,
     0x0027,
     0x0028,
     0x0029,
     0x002a,
     0x002b,
     0x002c,
     0x002d,
     0x002e,
     0x002f,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x003a,
     0x003b,
     0x003c,
     0x003d,
     0x003e,
     0x003f,
     0x0040,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x005b,
     0x005c,
     0x005d,
     0x005e,
     0x005f,
     0x0060,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x007b,
     0x007c,
     0x007d,
     0x007e,
     0x007f,
     0x0080,
     0x0081,
     0x0082,
     0x0083,
     0x0084,
     0x0085,
     0x0086,
     0x0087,
     0x0088,
     0x0089,
     0x008a,
     0x008b,
     0x008c,
     0x008d,
     0x008e,
     0x008f,
     0x0090,
     0x0091,
     0x0092,
     0x0093,
     0x0094,
     0x0095,
     0x0096,
     0x0097,
     0x0098,
     0x0099,
     0x009a,
     0x009b,
     0x009c,
     0x009d,
     0x009e,
     0x009f,
     0x00a0,
     0x00a1,
     0x00a2,
     0x00a3,
     0x20ac,
     0x00a5,
     0x0160,
     0x00a7,
     0x0161,
     0x00a9,
     0x00aa,
     0x00ab,
     0x00ac,
     0x00ad,
     0x00ae,
     0x00af,
     0x00b0,
     0x00b1,
     0x00b2,
     0x00b3,
     0x017d,
     0x00b5,
     0x00b6,
     0x00b7,
     0x017e,
     0x00b9,
     0x00ba,
     0x00bb,
     0x0152,
     0x0153,
     0x0178,
     0x00bf,
     0x00c0,
     0x00c1,
     0x00c2,
     0x00c3,
     0x00c4,
     0x00c5,
     0x00c6,
     0x00c7,
     0x00c8,
     0x00c9,
     0x00ca,
     0x00cb,
     0x00cc,
     0x00cd,
     0x00ce,
     0x00cf,
     0x00d0,
     0x00d1,
     0x00d2,
     0x00d3,
     0x00d4,
     0x00d5,
     0x00d6,
     0x00d7,
     0x00d8,
     0x00d9,
     0x00da,
     0x00db,
     0x00dc,
     0x00dd,
     0x00de,
     0x00df,
     0x00e0,
     0x00e1,
     0x00e2,
     0x00e3,
     0x00e4,
     0x00e5,
     0x00e6,
     0x00e7,
     0x00e8,
     0x00e9,
     0x00ea,
     0x00eb,
     0x00ec,
     0x00ed,
     0x00ee,
     0x00ef,
     0x00f0,
     0x00f1,
     0x00f2,
     0x00f3,
     0x00f4,
     0x00f5,
     0x00f6,
     0x00f7,
     0x00f8,
     0x00f9,
     0x00fa,
     0x00fb,
     0x00fc,
     0x00fd,
     0x00fe,
     0x00ff,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\x04",
     "\x05",
     "\x06",
     "\x07",
     "\x08",
     "\x09",
     "\x0a",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\x14",
     "\x15",
     "\x16",
     "\x17",
     "\x18",
     "\x19",
     "\x1a",
     "\x1b",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\x20",
     "\x21",
     "\x22",
     "\x23",
     "\x24",
     "\x25",
     "\x26",
     "\x27",
     "\x28",
     "\x29",
     "\x2a",
     "\x2b",
     "\x2c",
     "\x2d",
     "\x2e",
     "\x2f",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\x3a",
     "\x3b",
     "\x3c",
     "\x3d",
     "\x3e",
     "\x3f",
     "\x40",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\x5b",
     "\x5c",
     "\x5d",
     "\x5e",
     "\x5f",
     "\x60",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\x7b",
     "\x7c",
     "\x7d",
     "\x7e",
     "\x7f",
     "\xc2\x80",
     "\xc2\x81",
     "\xc2\x82",
     "\xc2\x83",
     "\xc2\x84",
     "\xc2\x85",
     "\xc2\x86",
     "\xc2\x87",
     "\xc2\x88",
     "\xc2\x89",
     "\xc2\x8a",
     "\xc2\x8b",
     "\xc2\x8c",
     "\xc2\x8d",
     "\xc2\x8e",
     "\xc2\x8f",
     "\xc2\x90",
     "\xc2\x91",
     "\xc2\x92",
     "\xc2\x93",
     "\xc2\x94",
     "\xc2\x95",
     "\xc2\x96",
     "\xc2\x97",
     "\xc2\x98",
     "\xc2\x99",
     "\xc2\x9a",
     "\xc2\x9b",
     "\xc2\x9c",
     "\xc2\x9d",
     "\xc2\x9e",
     "\xc2\x9f",
     "\xc2\xa0",
     "\xc2\xa1",
     "\xc2\xa2",
     "\xc2\xa3",
     "\xe2\x82\xac",
     "\xc2\xa5",
     "\xc5\xa0",
     "\xc2\xa7",
     "\xc5\xa1",
     "\xc2\xa9",
     "\xc2\xaa",
     "\xc2\xab",
     "\xc2\xac",
     "\xc2\xad",
     "\xc2\xae",
     "\xc2\xaf",
     "\xc2\xb0",
     "\xc2\xb1",
     "\xc2\xb2",
     "\xc2\xb3",
     "\xc5\xbd",
     "\xc2\xb5",
     "\xc2\xb6",
     "\xc2\xb7",
     "\xc5\xbe",
     "\xc2\xb9",
     "\xc2\xba",
     "\xc2\xbb",
     "\xc5\x92",
     "\xc5\x93",
     "\xc5\xb8",
     "\xc2\xbf",
     "\xc3\x80",
     "\xc3\x81",
     "\xc3\x82",
     "\xc3\x83",
     "\xc3\x84",
     "\xc3\x85",
     "\xc3\x86",
     "\xc3\x87",
     "\xc3\x88",
     "\xc3\x89",
     "\xc3\x8a",
     "\xc3\x8b",
     "\xc3\x8c",
     "\xc3\x8d",
     "\xc3\x8e",
     "\xc3\x8f",
     "\xc3\x90",
     "\xc3\x91",
     "\xc3\x92",
     "\xc3\x93",
     "\xc3\x94",
     "\xc3\x95",
     "\xc3\x96",
     "\xc3\x97",
     "\xc3\x98",
     "\xc3\x99",
     "\xc3\x9a",
     "\xc3\x9b",
     "\xc3\x9c",
     "\xc3\x9d",
     "\xc3\x9e",
     "\xc3\x9f",
     "\xc3\xa0",
     "\xc3\xa1",
     "\xc3\xa2",
     "\xc3\xa3",
     "\xc3\xa4",
     "\xc3\xa5",
     "\xc3\xa6",
     "\xc3\xa7",
     "\xc3\xa8",
     "\xc3\xa9",
     "\xc3\xaa",
     "\xc3\xab",
     "\xc3\xac",
     "\xc3\xad",
     "\xc3\xae",
     "\xc3\xaf",
     "\xc3\xb0",
     "\xc3\xb1",
     "\xc3\xb2",
     "\xc3\xb3",
     "\xc3\xb4",
     "\xc3\xb5",
     "\xc3\xb6",
     "\xc3\xb7",
     "\xc3\xb8",
     "\xc3\xb9",
     "\xc3\xba",
     "\xc3\xbb",
     "\xc3\xbc",
     "\xc3\xbd",
     "\xc3\xbe",
     "\xc3\xbf",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x04",
     0x00000005 => "\x05",
     0x00000006 => "\x06",
     0x00000007 => "\x07",
     0x00000008 => "\x08",
     0x00000009 => "\x09",
     0x0000000a => "\x0a",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x14",
     0x00000015 => "\x15",
     0x00000016 => "\x16",
     0x00000017 => "\x17",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x1a",
     0x0000001b => "\x1b",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x20",
     0x00000021 => "\x21",
     0x00000022 => "\x22",
     0x00000023 => "\x23",
     0x00000024 => "\x24",
     0x00000025 => "\x25",
     0x00000026 => "\x26",
     0x00000027 => "\x27",
     0x00000028 => "\x28",
     0x00000029 => "\x29",
     0x0000002a => "\x2a",
     0x0000002b => "\x2b",
     0x0000002c => "\x2c",
     0x0000002d => "\x2d",
     0x0000002e => "\x2e",
     0x0000002f => "\x2f",
     0x00000030 => "\x30",
     0x00000031 => "\x31",
     0x00000032 => "\x32",
     0x00000033 => "\x33",
     0x00000034 => "\x34",
     0x00000035 => "\x35",
     0x00000036 => "\x36",
     0x00000037 => "\x37",
     0x00000038 => "\x38",
     0x00000039 => "\x39",
     0x0000003a => "\x3a",
     0x0000003b => "\x3b",
     0x0000003c => "\x3c",
     0x0000003d => "\x3d",
     0x0000003e => "\x3e",
     0x0000003f => "\x3f",
     0x00000040 => "\x40",
     0x00000041 => "\x41",
     0x00000042 => "\x42",
     0x00000043 => "\x43",
     0x00000044 => "\x44",
     0x00000045 => "\x45",
     0x00000046 => "\x46",
     0x00000047 => "\x47",
     0x00000048 => "\x48",
     0x00000049 => "\x49",
     0x0000004a => "\x4a",
     0x0000004b => "\x4b",
     0x0000004c => "\x4c",
     0x0000004d => "\x4d",
     0x0000004e => "\x4e",
     0x0000004f => "\x4f",
     0x00000050 => "\x50",
     0x00000051 => "\x51",
     0x00000052 => "\x52",
     0x00000053 => "\x53",
     0x00000054 => "\x54",
     0x00000055 => "\x55",
     0x00000056 => "\x56",
     0x00000057 => "\x57",
     0x00000058 => "\x58",
     0x00000059 => "\x59",
     0x0000005a => "\x5a",
     0x0000005b => "\x5b",
     0x0000005c => "\x5c",
     0x0000005d => "\x5d",
     0x0000005e => "\x5e",
     0x0000005f => "\x5f",
     0x00000060 => "\x60",
     0x00000061 => "\x61",
     0x00000062 => "\x62",
     0x00000063 => "\x63",
     0x00000064 => "\x64",
     0x00000065 => "\x65",
     0x00000066 => "\x66",
     0x00000067 => "\x67",
     0x00000068 => "\x68",
     0x00000069 => "\x69",
     0x0000006a => "\x6a",
     0x0000006b => "\x6b",
     0x0000006c => "\x6c",
     0x0000006d => "\x6d",
     0x0000006e => "\x6e",
     0x0000006f => "\x6f",
     0x00000070 => "\x70",
     0x00000071 => "\x71",
     0x00000072 => "\x72",
     0x00000073 => "\x73",
     0x00000074 => "\x74",
     0x00000075 => "\x75",
     0x00000076 => "\x76",
     0x00000077 => "\x77",
     0x00000078 => "\x78",
     0x00000079 => "\x79",
     0x0000007a => "\x7a",
     0x0000007b => "\x7b",
     0x0000007c => "\x7c",
     0x0000007d => "\x7d",
     0x0000007e => "\x7e",
     0x0000007f => "\x7f",
     0x00000080 => "\x80",
     0x00000081 => "\x81",
     0x00000082 => "\x82",
     0x00000083 => "\x83",
     0x00000084 => "\x84",
     0x00000085 => "\x85",
     0x00000086 => "\x86",
     0x00000087 => "\x87",
     0x00000088 => "\x88",
     0x00000089 => "\x89",
     0x0000008a => "\x8a",
     0x0000008b => "\x8b",
     0x0000008c => "\x8c",
     0x0000008d => "\x8d",
     0x0000008e => "\x8e",
     0x0000008f => "\x8f",
     0x00000090 => "\x90",
     0x00000091 => "\x91",
     0x00000092 => "\x92",
     0x00000093 => "\x93",
     0x00000094 => "\x94",
     0x00000095 => "\x95",
     0x00000096 => "\x96",
     0x00000097 => "\x97",
     0x00000098 => "\x98",
     0x00000099 => "\x99",
     0x0000009a => "\x9a",
     0x0000009b => "\x9b",
     0x0000009c => "\x9c",
     0x0000009d => "\x9d",
     0x0000009e => "\x9e",
     0x0000009f => "\x9f",
     0x000000a0 => "\xa0",
     0x000000a1 => "\xa1",
     0x000000a2 => "\xa2",
     0x000000a3 => "\xa3",
     0x000000a5 => "\xa5",
     0x000000a7 => "\xa7",
     0x000000a9 => "\xa9",
     0x000000aa => "\xaa",
     0x000000ab => "\xab",
     0x000000ac => "\xac",
     0x000000ad => "\xad",
     0x000000ae => "\xae",
     0x000000af => "\xaf",
     0x000000b0 => "\xb0",
     0x000000b1 => "\xb1",
     0x000000b2 => "\xb2",
     0x000000b3 => "\xb3",
     0x000000b5 => "\xb5",
     0x000000b6 => "\xb6",
     0x000000b7 => "\xb7",
     0x000000b9 => "\xb9",
     0x000000ba => "\xba",
     0x000000bb => "\xbb",
     0x000000bf => "\xbf",
     0x000000c0 => "\xc0",
     0x000000c1 => "\xc1",
     0x000000c2 => "\xc2",
     0x000000c3 => "\xc3",
     0x000000c4 => "\xc4",
     0x000000c5 => "\xc5",
     0x000000c6 => "\xc6",
     0x000000c7 => "\xc7",
     0x000000c8 => "\xc8",
     0x000000c9 => "\xc9",
     0x000000ca => "\xca",
     0x000000cb => "\xcb",
     0x000000cc => "\xcc",
     0x000000cd => "\xcd",
     0x000000ce => "\xce",
     0x000000cf => "\xcf",
     0x000000d0 => "\xd0",
     0x000000d1 => "\xd1",
     0x000000d2 => "\xd2",
     0x000000d3 => "\xd3",
     0x000000d4 => "\xd4",
     0x000000d5 => "\xd5",
     0x000000d6 => "\xd6",
     0x000000d7 => "\xd7",
     0x000000d8 => "\xd8",
     0x000000d9 => "\xd9",
     0x000000da => "\xda",
     0x000000db => "\xdb",
     0x000000dc => "\xdc",
     0x000000dd => "\xdd",
     0x000000de => "\xde",
     0x000000df => "\xdf",
     0x000000e0 => "\xe0",
     0x000000e1 => "\xe1",
     0x000000e2 => "\xe2",
     0x000000e3 => "\xe3",
     0x000000e4 => "\xe4",
     0x000000e5 => "\xe5",
     0x000000e6 => "\xe6",
     0x000000e7 => "\xe7",
     0x000000e8 => "\xe8",
     0x000000e9 => "\xe9",
     0x000000ea => "\xea",
     0x000000eb => "\xeb",
     0x000000ec => "\xec",
     0x000000ed => "\xed",
     0x000000ee => "\xee",
     0x000000ef => "\xef",
     0x000000f0 => "\xf0",
     0x000000f1 => "\xf1",
     0x000000f2 => "\xf2",
     0x000000f3 => "\xf3",
     0x000000f4 => "\xf4",
     0x000000f5 => "\xf5",
     0x000000f6 => "\xf6",
     0x000000f7 => "\xf7",
     0x000000f8 => "\xf8",
     0x000000f9 => "\xf9",
     0x000000fa => "\xfa",
     0x000000fb => "\xfb",
     0x000000fc => "\xfc",
     0x000000fd => "\xfd",
     0x000000fe => "\xfe",
     0x000000ff => "\xff",
     0x00000152 => "\xbc",
     0x00000153 => "\xbd",
     0x00000160 => "\xa6",
     0x00000161 => "\xa8",
     0x00000178 => "\xbe",
     0x0000017d => "\xb4",
     0x0000017e => "\xb8",
     0x000020ac => "\xa4",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::ISO_8859_15 - Conversion routines for ISO-8859-15
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for ISO-8859-15.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  automatically generated from the charDB
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL
     01 |  00000001 | START OF HEADING
     02 |  00000002 | START OF TEXT
     03 |  00000003 | END OF TEXT
     04 |  00000004 | END OF TRANSMISSION
     05 |  00000005 | ENQUIRY
     06 |  00000006 | ACKNOWLEDGE
     07 |  00000007 | BELL
     08 |  00000008 | BACKSPACE
     09 |  00000009 | HORIZONTAL TABULATION
     0A |  0000000A | LINE FEED
     0B |  0000000B | VERTICAL TABULATION
     0C |  0000000C | FORM FEED
     0D |  0000000D | CARRIAGE RETURN
     0E |  0000000E | SHIFT OUT
     0F |  0000000F | SHIFT IN
     10 |  00000010 | DATA LINK ESCAPE
     11 |  00000011 | DEVICE CONTROL ONE
     12 |  00000012 | DEVICE CONTROL TWO
     13 |  00000013 | DEVICE CONTROL THREE
     14 |  00000014 | DEVICE CONTROL FOUR
     15 |  00000015 | NEGATIVE ACKNOWLEDGE
     16 |  00000016 | SYNCHRONOUS IDLE
     17 |  00000017 | END OF TRANSMISSION BLOCK
     18 |  00000018 | CANCEL
     19 |  00000019 | END OF MEDIUM
     1A |  0000001A | SUBSTITUTE
     1B |  0000001B | ESCAPE
     1C |  0000001C | FILE SEPARATOR
     1D |  0000001D | GROUP SEPARATOR
     1E |  0000001E | RECORD SEPARATOR
     1F |  0000001F | UNIT SEPARATOR
     20 |  00000020 | SPACE
     21 |  00000021 | EXCLAMATION MARK
     22 |  00000022 | QUOTATION MARK
     23 |  00000023 | NUMBER SIGN
     24 |  00000024 | DOLLAR SIGN
     25 |  00000025 | PERCENT SIGN
     26 |  00000026 | AMPERSAND
     27 |  00000027 | APOSTROPHE
     28 |  00000028 | LEFT PARENTHESIS
     29 |  00000029 | RIGHT PARENTHESIS
     2A |  0000002A | ASTERISK
     2B |  0000002B | PLUS SIGN
     2C |  0000002C | COMMA
     2D |  0000002D | HYPHEN-MINUS
     2E |  0000002E | FULL STOP
     2F |  0000002F | SOLIDUS
     30 |  00000030 | DIGIT ZERO
     31 |  00000031 | DIGIT ONE
     32 |  00000032 | DIGIT TWO
     33 |  00000033 | DIGIT THREE
     34 |  00000034 | DIGIT FOUR
     35 |  00000035 | DIGIT FIVE
     36 |  00000036 | DIGIT SIX
     37 |  00000037 | DIGIT SEVEN
     38 |  00000038 | DIGIT EIGHT
     39 |  00000039 | DIGIT NINE
     3A |  0000003A | COLON
     3B |  0000003B | SEMICOLON
     3C |  0000003C | LESS-THAN SIGN
     3D |  0000003D | EQUALS SIGN
     3E |  0000003E | GREATER-THAN SIGN
     3F |  0000003F | QUESTION MARK
     40 |  00000040 | COMMERCIAL AT
     41 |  00000041 | LATIN CAPITAL LETTER A
     42 |  00000042 | LATIN CAPITAL LETTER B
     43 |  00000043 | LATIN CAPITAL LETTER C
     44 |  00000044 | LATIN CAPITAL LETTER D
     45 |  00000045 | LATIN CAPITAL LETTER E
     46 |  00000046 | LATIN CAPITAL LETTER F
     47 |  00000047 | LATIN CAPITAL LETTER G
     48 |  00000048 | LATIN CAPITAL LETTER H
     49 |  00000049 | LATIN CAPITAL LETTER I
     4A |  0000004A | LATIN CAPITAL LETTER J
     4B |  0000004B | LATIN CAPITAL LETTER K
     4C |  0000004C | LATIN CAPITAL LETTER L
     4D |  0000004D | LATIN CAPITAL LETTER M
     4E |  0000004E | LATIN CAPITAL LETTER N
     4F |  0000004F | LATIN CAPITAL LETTER O
     50 |  00000050 | LATIN CAPITAL LETTER P
     51 |  00000051 | LATIN CAPITAL LETTER Q
     52 |  00000052 | LATIN CAPITAL LETTER R
     53 |  00000053 | LATIN CAPITAL LETTER S
     54 |  00000054 | LATIN CAPITAL LETTER T
     55 |  00000055 | LATIN CAPITAL LETTER U
     56 |  00000056 | LATIN CAPITAL LETTER V
     57 |  00000057 | LATIN CAPITAL LETTER W
     58 |  00000058 | LATIN CAPITAL LETTER X
     59 |  00000059 | LATIN CAPITAL LETTER Y
     5A |  0000005A | LATIN CAPITAL LETTER Z
     5B |  0000005B | LEFT SQUARE BRACKET
     5C |  0000005C | REVERSE SOLIDUS
     5D |  0000005D | RIGHT SQUARE BRACKET
     5E |  0000005E | CIRCUMFLEX ACCENT
     5F |  0000005F | LOW LINE
     60 |  00000060 | GRAVE ACCENT
     61 |  00000061 | LATIN SMALL LETTER A
     62 |  00000062 | LATIN SMALL LETTER B
     63 |  00000063 | LATIN SMALL LETTER C
     64 |  00000064 | LATIN SMALL LETTER D
     65 |  00000065 | LATIN SMALL LETTER E
     66 |  00000066 | LATIN SMALL LETTER F
     67 |  00000067 | LATIN SMALL LETTER G
     68 |  00000068 | LATIN SMALL LETTER H
     69 |  00000069 | LATIN SMALL LETTER I
     6A |  0000006A | LATIN SMALL LETTER J
     6B |  0000006B | LATIN SMALL LETTER K
     6C |  0000006C | LATIN SMALL LETTER L
     6D |  0000006D | LATIN SMALL LETTER M
     6E |  0000006E | LATIN SMALL LETTER N
     6F |  0000006F | LATIN SMALL LETTER O
     70 |  00000070 | LATIN SMALL LETTER P
     71 |  00000071 | LATIN SMALL LETTER Q
     72 |  00000072 | LATIN SMALL LETTER R
     73 |  00000073 | LATIN SMALL LETTER S
     74 |  00000074 | LATIN SMALL LETTER T
     75 |  00000075 | LATIN SMALL LETTER U
     76 |  00000076 | LATIN SMALL LETTER V
     77 |  00000077 | LATIN SMALL LETTER W
     78 |  00000078 | LATIN SMALL LETTER X
     79 |  00000079 | LATIN SMALL LETTER Y
     7A |  0000007A | LATIN SMALL LETTER Z
     7B |  0000007B | LEFT CURLY BRACKET
     7C |  0000007C | VERTICAL LINE
     7D |  0000007D | RIGHT CURLY BRACKET
     7E |  0000007E | TILDE
     7F |  0000007F | DELETE
     80 |  00000080 | PADDING CHARACTER (PAD)
     81 |  00000081 | HIGH OCTET PRESET (HOP)
     82 |  00000082 | BREAK PERMITTED HERE (BPH)
     83 |  00000083 | NO BREAK HERE (NBH)
     84 |  00000084 | INDEX (IND)
     85 |  00000085 | NEXT LINE (NEL)
     86 |  00000086 | START OF SELECTED AREA (SSA)
     87 |  00000087 | END OF SELECTED AREA (ESA)
     88 |  00000088 | CHARACTER TABULATION SET (HTS)
     89 |  00000089 | CHARACTER TABULATION WITH JUSTIFICATION (HTJ)
     8A |  0000008A | LINE TABULATION SET (VTS)
     8B |  0000008B | PARTIAL LINE FORWARD (PLD)
     8C |  0000008C | PARTIAL LINE BACKWARD (PLU)
     8D |  0000008D | REVERSE LINE FEED (RI)
     8E |  0000008E | SINGLE-SHIFT TWO (SS2)
     8F |  0000008F | SINGLE-SHIFT THREE (SS3)
     90 |  00000090 | DEVICE CONTROL STRING (DCS)
     91 |  00000091 | PRIVATE USE ONE (PU1)
     92 |  00000092 | PRIVATE USE TWO (PU2)
     93 |  00000093 | SET TRANSMIT STATE (STS)
     94 |  00000094 | CANCEL CHARACTER (CCH)
     95 |  00000095 | MESSAGE WAITING (MW)
     96 |  00000096 | START OF GUARDED AREA (SPA)
     97 |  00000097 | END OF GUARDED AREA (EPA)
     98 |  00000098 | START OF STRING (SOS)
     99 |  00000099 | SINGLE GRAPHIC CHARACTER INTRODUCER (SGCI)
     9A |  0000009A | SINGLE CHARACTER INTRODUCER (SCI)
     9B |  0000009B | CONTROL SEQUENCE INTRODUCER (CSI)
     9C |  0000009C | STRING TERMINATOR (ST)
     9D |  0000009D | OPERATING SYSTEM COMMAND (OSC)
     9E |  0000009E | PRIVACY MESSAGE (PM)
     9F |  0000009F | APPLICATION PROGRAM COMMAND (APC)
     A0 |  000000A0 | NO-BREAK SPACE
     A1 |  000000A1 | INVERTED EXCLAMATION MARK
     A2 |  000000A2 | CENT SIGN
     A3 |  000000A3 | POUND SIGN
     A4 |  000020AC | EURO SIGN
     A5 |  000000A5 | YEN SIGN
     A6 |  00000160 | LATIN CAPITAL LETTER S WITH CARON
     A7 |  000000A7 | SECTION SIGN
     A8 |  00000161 | LATIN SMALL LETTER S WITH CARON
     A9 |  000000A9 | COPYRIGHT SIGN
     AA |  000000AA | FEMININE ORDINAL INDICATOR
     AB |  000000AB | LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
     AC |  000000AC | NOT SIGN
     AD |  000000AD | SOFT HYPHEN
     AE |  000000AE | REGISTERED SIGN
     AF |  000000AF | MACRON
     B0 |  000000B0 | DEGREE SIGN
     B1 |  000000B1 | PLUS-MINUS SIGN
     B2 |  000000B2 | SUPERSCRIPT TWO
     B3 |  000000B3 | SUPERSCRIPT THREE
     B4 |  0000017D | LATIN CAPITAL LETTER Z WITH CARON
     B5 |  000000B5 | MICRO SIGN
     B6 |  000000B6 | PILCROW SIGN
     B7 |  000000B7 | MIDDLE DOT
     B8 |  0000017E | LATIN SMALL LETTER Z WITH CARON
     B9 |  000000B9 | SUPERSCRIPT ONE
     BA |  000000BA | MASCULINE ORDINAL INDICATOR
     BB |  000000BB | RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
     BC |  00000152 | LATIN CAPITAL LIGATURE OE
     BD |  00000153 | LATIN SMALL LIGATURE OE
     BE |  00000178 | LATIN CAPITAL LETTER Y WITH DIAERESIS
     BF |  000000BF | INVERTED QUESTION MARK
     C0 |  000000C0 | LATIN CAPITAL LETTER A WITH GRAVE
     C1 |  000000C1 | LATIN CAPITAL LETTER A WITH ACUTE
     C2 |  000000C2 | LATIN CAPITAL LETTER A WITH CIRCUMFLEX
     C3 |  000000C3 | LATIN CAPITAL LETTER A WITH TILDE
     C4 |  000000C4 | LATIN CAPITAL LETTER A WITH DIAERESIS
     C5 |  000000C5 | LATIN CAPITAL LETTER A WITH RING ABOVE
     C6 |  000000C6 | LATIN CAPITAL LETTER AE
     C7 |  000000C7 | LATIN CAPITAL LETTER C WITH CEDILLA
     C8 |  000000C8 | LATIN CAPITAL LETTER E WITH GRAVE
     C9 |  000000C9 | LATIN CAPITAL LETTER E WITH ACUTE
     CA |  000000CA | LATIN CAPITAL LETTER E WITH CIRCUMFLEX
     CB |  000000CB | LATIN CAPITAL LETTER E WITH DIAERESIS
     CC |  000000CC | LATIN CAPITAL LETTER I WITH GRAVE
     CD |  000000CD | LATIN CAPITAL LETTER I WITH ACUTE
     CE |  000000CE | LATIN CAPITAL LETTER I WITH CIRCUMFLEX
     CF |  000000CF | LATIN CAPITAL LETTER I WITH DIAERESIS
     D0 |  000000D0 | LATIN CAPITAL LETTER ETH
     D1 |  000000D1 | LATIN CAPITAL LETTER N WITH TILDE
     D2 |  000000D2 | LATIN CAPITAL LETTER O WITH GRAVE
     D3 |  000000D3 | LATIN CAPITAL LETTER O WITH ACUTE
     D4 |  000000D4 | LATIN CAPITAL LETTER O WITH CIRCUMFLEX
     D5 |  000000D5 | LATIN CAPITAL LETTER O WITH TILDE
     D6 |  000000D6 | LATIN CAPITAL LETTER O WITH DIAERESIS
     D7 |  000000D7 | MULTIPLICATION SIGN
     D8 |  000000D8 | LATIN CAPITAL LETTER O WITH STROKE
     D9 |  000000D9 | LATIN CAPITAL LETTER U WITH GRAVE
     DA |  000000DA | LATIN CAPITAL LETTER U WITH ACUTE
     DB |  000000DB | LATIN CAPITAL LETTER U WITH CIRCUMFLEX
     DC |  000000DC | LATIN CAPITAL LETTER U WITH DIAERESIS
     DD |  000000DD | LATIN CAPITAL LETTER Y WITH ACUTE
     DE |  000000DE | LATIN CAPITAL LETTER THORN
     DF |  000000DF | LATIN SMALL LETTER SHARP S
     E0 |  000000E0 | LATIN SMALL LETTER A WITH GRAVE
     E1 |  000000E1 | LATIN SMALL LETTER A WITH ACUTE
     E2 |  000000E2 | LATIN SMALL LETTER A WITH CIRCUMFLEX
     E3 |  000000E3 | LATIN SMALL LETTER A WITH TILDE
     E4 |  000000E4 | LATIN SMALL LETTER A WITH DIAERESIS
     E5 |  000000E5 | LATIN SMALL LETTER A WITH RING ABOVE
     E6 |  000000E6 | LATIN SMALL LETTER AE
     E7 |  000000E7 | LATIN SMALL LETTER C WITH CEDILLA
     E8 |  000000E8 | LATIN SMALL LETTER E WITH GRAVE
     E9 |  000000E9 | LATIN SMALL LETTER E WITH ACUTE
     EA |  000000EA | LATIN SMALL LETTER E WITH CIRCUMFLEX
     EB |  000000EB | LATIN SMALL LETTER E WITH DIAERESIS
     EC |  000000EC | LATIN SMALL LETTER I WITH GRAVE
     ED |  000000ED | LATIN SMALL LETTER I WITH ACUTE
     EE |  000000EE | LATIN SMALL LETTER I WITH CIRCUMFLEX
     EF |  000000EF | LATIN SMALL LETTER I WITH DIAERESIS
     F0 |  000000F0 | LATIN SMALL LETTER ETH
     F1 |  000000F1 | LATIN SMALL LETTER N WITH TILDE
     F2 |  000000F2 | LATIN SMALL LETTER O WITH GRAVE
     F3 |  000000F3 | LATIN SMALL LETTER O WITH ACUTE
     F4 |  000000F4 | LATIN SMALL LETTER O WITH CIRCUMFLEX
     F5 |  000000F5 | LATIN SMALL LETTER O WITH TILDE
     F6 |  000000F6 | LATIN SMALL LETTER O WITH DIAERESIS
     F7 |  000000F7 | DIVISION SIGN
     F8 |  000000F8 | LATIN SMALL LETTER O WITH STROKE
     F9 |  000000F9 | LATIN SMALL LETTER U WITH GRAVE
     FA |  000000FA | LATIN SMALL LETTER U WITH ACUTE
     FB |  000000FB | LATIN SMALL LETTER U WITH CIRCUMFLEX
     FC |  000000FC | LATIN SMALL LETTER U WITH DIAERESIS
     FD |  000000FD | LATIN SMALL LETTER Y WITH ACUTE
     FE |  000000FE | LATIN SMALL LETTER THORN
     FF |  000000FF | LATIN SMALL LETTER Y WITH DIAERESIS
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/ISO_8859_16.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for ISO-8859-16.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::ISO_8859_16;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x0004,
     0x0005,
     0x0006,
     0x0007,
     0x0008,
     0x0009,
     0x000a,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x0014,
     0x0015,
     0x0016,
     0x0017,
     0x0018,
     0x0019,
     0x001a,
     0x001b,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0020,
     0x0021,
     0x0022,
     0x0023,
     0x0024,
     0x0025,
     0x0026,
     0x0027,
     0x0028,
     0x0029,
     0x002a,
     0x002b,
     0x002c,
     0x002d,
     0x002e,
     0x002f,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x003a,
     0x003b,
     0x003c,
     0x003d,
     0x003e,
     0x003f,
     0x0040,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x005b,
     0x005c,
     0x005d,
     0x005e,
     0x005f,
     0x0060,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x007b,
     0x007c,
     0x007d,
     0x007e,
     0x007f,
     0x0080,
     0x0081,
     0x0082,
     0x0083,
     0x0084,
     0x0085,
     0x0086,
     0x0087,
     0x0088,
     0x0089,
     0x008a,
     0x008b,
     0x008c,
     0x008d,
     0x008e,
     0x008f,
     0x0090,
     0x0091,
     0x0092,
     0x0093,
     0x0094,
     0x0095,
     0x0096,
     0x0097,
     0x0098,
     0x0099,
     0x009a,
     0x009b,
     0x009c,
     0x009d,
     0x009e,
     0x009f,
     0x00a0,
     0x0104,
     0x0105,
     0x0141,
     0x20ac,
     0x201e,
     0x0160,
     0x00a7,
     0x0161,
     0x00a9,
     0x0218,
     0x00ab,
     0x0179,
     0x00ad,
     0x017a,
     0x017b,
     0x00b0,
     0x00b1,
     0x010c,
     0x0142,
     0x017d,
     0x201d,
     0x00b6,
     0x00b7,
     0x017e,
     0x010d,
     0x0219,
     0x00bb,
     0x0152,
     0x0153,
     0x0178,
     0x017c,
     0x00c0,
     0x00c1,
     0x00c2,
     0x0102,
     0x00c4,
     0x0106,
     0x00c6,
     0x00c7,
     0x00c8,
     0x00c9,
     0x00ca,
     0x00cb,
     0x00cc,
     0x00cd,
     0x00ce,
     0x00cf,
     0x0110,
     0x0143,
     0x00d2,
     0x00d3,
     0x00d4,
     0x0150,
     0x00d6,
     0x015a,
     0x0170,
     0x00d9,
     0x00da,
     0x00db,
     0x00dc,
     0x0118,
     0x021a,
     0x00df,
     0x00e0,
     0x00e1,
     0x00e2,
     0x0103,
     0x00e4,
     0x0107,
     0x00e6,
     0x00e7,
     0x00e8,
     0x00e9,
     0x00ea,
     0x00eb,
     0x00ec,
     0x00ed,
     0x00ee,
     0x00ef,
     0x0111,
     0x0144,
     0x00f2,
     0x00f3,
     0x00f4,
     0x0151,
     0x00f6,
     0x015b,
     0x0171,
     0x00f9,
     0x00fa,
     0x00fb,
     0x00fc,
     0x0119,
     0x021b,
     0x00ff,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\x04",
     "\x05",
     "\x06",
     "\x07",
     "\x08",
     "\x09",
     "\x0a",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\x14",
     "\x15",
     "\x16",
     "\x17",
     "\x18",
     "\x19",
     "\x1a",
     "\x1b",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\x20",
     "\x21",
     "\x22",
     "\x23",
     "\x24",
     "\x25",
     "\x26",
     "\x27",
     "\x28",
     "\x29",
     "\x2a",
     "\x2b",
     "\x2c",
     "\x2d",
     "\x2e",
     "\x2f",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\x3a",
     "\x3b",
     "\x3c",
     "\x3d",
     "\x3e",
     "\x3f",
     "\x40",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\x5b",
     "\x5c",
     "\x5d",
     "\x5e",
     "\x5f",
     "\x60",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\x7b",
     "\x7c",
     "\x7d",
     "\x7e",
     "\x7f",
     "\xc2\x80",
     "\xc2\x81",
     "\xc2\x82",
     "\xc2\x83",
     "\xc2\x84",
     "\xc2\x85",
     "\xc2\x86",
     "\xc2\x87",
     "\xc2\x88",
     "\xc2\x89",
     "\xc2\x8a",
     "\xc2\x8b",
     "\xc2\x8c",
     "\xc2\x8d",
     "\xc2\x8e",
     "\xc2\x8f",
     "\xc2\x90",
     "\xc2\x91",
     "\xc2\x92",
     "\xc2\x93",
     "\xc2\x94",
     "\xc2\x95",
     "\xc2\x96",
     "\xc2\x97",
     "\xc2\x98",
     "\xc2\x99",
     "\xc2\x9a",
     "\xc2\x9b",
     "\xc2\x9c",
     "\xc2\x9d",
     "\xc2\x9e",
     "\xc2\x9f",
     "\xc2\xa0",
     "\xc4\x84",
     "\xc4\x85",
     "\xc5\x81",
     "\xe2\x82\xac",
     "\xe2\x80\x9e",
     "\xc5\xa0",
     "\xc2\xa7",
     "\xc5\xa1",
     "\xc2\xa9",
     "\xc8\x98",
     "\xc2\xab",
     "\xc5\xb9",
     "\xc2\xad",
     "\xc5\xba",
     "\xc5\xbb",
     "\xc2\xb0",
     "\xc2\xb1",
     "\xc4\x8c",
     "\xc5\x82",
     "\xc5\xbd",
     "\xe2\x80\x9d",
     "\xc2\xb6",
     "\xc2\xb7",
     "\xc5\xbe",
     "\xc4\x8d",
     "\xc8\x99",
     "\xc2\xbb",
     "\xc5\x92",
     "\xc5\x93",
     "\xc5\xb8",
     "\xc5\xbc",
     "\xc3\x80",
     "\xc3\x81",
     "\xc3\x82",
     "\xc4\x82",
     "\xc3\x84",
     "\xc4\x86",
     "\xc3\x86",
     "\xc3\x87",
     "\xc3\x88",
     "\xc3\x89",
     "\xc3\x8a",
     "\xc3\x8b",
     "\xc3\x8c",
     "\xc3\x8d",
     "\xc3\x8e",
     "\xc3\x8f",
     "\xc4\x90",
     "\xc5\x83",
     "\xc3\x92",
     "\xc3\x93",
     "\xc3\x94",
     "\xc5\x90",
     "\xc3\x96",
     "\xc5\x9a",
     "\xc5\xb0",
     "\xc3\x99",
     "\xc3\x9a",
     "\xc3\x9b",
     "\xc3\x9c",
     "\xc4\x98",
     "\xc8\x9a",
     "\xc3\x9f",
     "\xc3\xa0",
     "\xc3\xa1",
     "\xc3\xa2",
     "\xc4\x83",
     "\xc3\xa4",
     "\xc4\x87",
     "\xc3\xa6",
     "\xc3\xa7",
     "\xc3\xa8",
     "\xc3\xa9",
     "\xc3\xaa",
     "\xc3\xab",
     "\xc3\xac",
     "\xc3\xad",
     "\xc3\xae",
     "\xc3\xaf",
     "\xc4\x91",
     "\xc5\x84",
     "\xc3\xb2",
     "\xc3\xb3",
     "\xc3\xb4",
     "\xc5\x91",
     "\xc3\xb6",
     "\xc5\x9b",
     "\xc5\xb1",
     "\xc3\xb9",
     "\xc3\xba",
     "\xc3\xbb",
     "\xc3\xbc",
     "\xc4\x99",
     "\xc8\x9b",
     "\xc3\xbf",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x04",
     0x00000005 => "\x05",
     0x00000006 => "\x06",
     0x00000007 => "\x07",
     0x00000008 => "\x08",
     0x00000009 => "\x09",
     0x0000000a => "\x0a",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x14",
     0x00000015 => "\x15",
     0x00000016 => "\x16",
     0x00000017 => "\x17",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x1a",
     0x0000001b => "\x1b",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x20",
     0x00000021 => "\x21",
     0x00000022 => "\x22",
     0x00000023 => "\x23",
     0x00000024 => "\x24",
     0x00000025 => "\x25",
     0x00000026 => "\x26",
     0x00000027 => "\x27",
     0x00000028 => "\x28",
     0x00000029 => "\x29",
     0x0000002a => "\x2a",
     0x0000002b => "\x2b",
     0x0000002c => "\x2c",
     0x0000002d => "\x2d",
     0x0000002e => "\x2e",
     0x0000002f => "\x2f",
     0x00000030 => "\x30",
     0x00000031 => "\x31",
     0x00000032 => "\x32",
     0x00000033 => "\x33",
     0x00000034 => "\x34",
     0x00000035 => "\x35",
     0x00000036 => "\x36",
     0x00000037 => "\x37",
     0x00000038 => "\x38",
     0x00000039 => "\x39",
     0x0000003a => "\x3a",
     0x0000003b => "\x3b",
     0x0000003c => "\x3c",
     0x0000003d => "\x3d",
     0x0000003e => "\x3e",
     0x0000003f => "\x3f",
     0x00000040 => "\x40",
     0x00000041 => "\x41",
     0x00000042 => "\x42",
     0x00000043 => "\x43",
     0x00000044 => "\x44",
     0x00000045 => "\x45",
     0x00000046 => "\x46",
     0x00000047 => "\x47",
     0x00000048 => "\x48",
     0x00000049 => "\x49",
     0x0000004a => "\x4a",
     0x0000004b => "\x4b",
     0x0000004c => "\x4c",
     0x0000004d => "\x4d",
     0x0000004e => "\x4e",
     0x0000004f => "\x4f",
     0x00000050 => "\x50",
     0x00000051 => "\x51",
     0x00000052 => "\x52",
     0x00000053 => "\x53",
     0x00000054 => "\x54",
     0x00000055 => "\x55",
     0x00000056 => "\x56",
     0x00000057 => "\x57",
     0x00000058 => "\x58",
     0x00000059 => "\x59",
     0x0000005a => "\x5a",
     0x0000005b => "\x5b",
     0x0000005c => "\x5c",
     0x0000005d => "\x5d",
     0x0000005e => "\x5e",
     0x0000005f => "\x5f",
     0x00000060 => "\x60",
     0x00000061 => "\x61",
     0x00000062 => "\x62",
     0x00000063 => "\x63",
     0x00000064 => "\x64",
     0x00000065 => "\x65",
     0x00000066 => "\x66",
     0x00000067 => "\x67",
     0x00000068 => "\x68",
     0x00000069 => "\x69",
     0x0000006a => "\x6a",
     0x0000006b => "\x6b",
     0x0000006c => "\x6c",
     0x0000006d => "\x6d",
     0x0000006e => "\x6e",
     0x0000006f => "\x6f",
     0x00000070 => "\x70",
     0x00000071 => "\x71",
     0x00000072 => "\x72",
     0x00000073 => "\x73",
     0x00000074 => "\x74",
     0x00000075 => "\x75",
     0x00000076 => "\x76",
     0x00000077 => "\x77",
     0x00000078 => "\x78",
     0x00000079 => "\x79",
     0x0000007a => "\x7a",
     0x0000007b => "\x7b",
     0x0000007c => "\x7c",
     0x0000007d => "\x7d",
     0x0000007e => "\x7e",
     0x0000007f => "\x7f",
     0x00000080 => "\x80",
     0x00000081 => "\x81",
     0x00000082 => "\x82",
     0x00000083 => "\x83",
     0x00000084 => "\x84",
     0x00000085 => "\x85",
     0x00000086 => "\x86",
     0x00000087 => "\x87",
     0x00000088 => "\x88",
     0x00000089 => "\x89",
     0x0000008a => "\x8a",
     0x0000008b => "\x8b",
     0x0000008c => "\x8c",
     0x0000008d => "\x8d",
     0x0000008e => "\x8e",
     0x0000008f => "\x8f",
     0x00000090 => "\x90",
     0x00000091 => "\x91",
     0x00000092 => "\x92",
     0x00000093 => "\x93",
     0x00000094 => "\x94",
     0x00000095 => "\x95",
     0x00000096 => "\x96",
     0x00000097 => "\x97",
     0x00000098 => "\x98",
     0x00000099 => "\x99",
     0x0000009a => "\x9a",
     0x0000009b => "\x9b",
     0x0000009c => "\x9c",
     0x0000009d => "\x9d",
     0x0000009e => "\x9e",
     0x0000009f => "\x9f",
     0x000000a0 => "\xa0",
     0x000000a7 => "\xa7",
     0x000000a9 => "\xa9",
     0x000000ab => "\xab",
     0x000000ad => "\xad",
     0x000000b0 => "\xb0",
     0x000000b1 => "\xb1",
     0x000000b6 => "\xb6",
     0x000000b7 => "\xb7",
     0x000000bb => "\xbb",
     0x000000c0 => "\xc0",
     0x000000c1 => "\xc1",
     0x000000c2 => "\xc2",
     0x000000c4 => "\xc4",
     0x000000c6 => "\xc6",
     0x000000c7 => "\xc7",
     0x000000c8 => "\xc8",
     0x000000c9 => "\xc9",
     0x000000ca => "\xca",
     0x000000cb => "\xcb",
     0x000000cc => "\xcc",
     0x000000cd => "\xcd",
     0x000000ce => "\xce",
     0x000000cf => "\xcf",
     0x000000d2 => "\xd2",
     0x000000d3 => "\xd3",
     0x000000d4 => "\xd4",
     0x000000d6 => "\xd6",
     0x000000d9 => "\xd9",
     0x000000da => "\xda",
     0x000000db => "\xdb",
     0x000000dc => "\xdc",
     0x000000df => "\xdf",
     0x000000e0 => "\xe0",
     0x000000e1 => "\xe1",
     0x000000e2 => "\xe2",
     0x000000e4 => "\xe4",
     0x000000e6 => "\xe6",
     0x000000e7 => "\xe7",
     0x000000e8 => "\xe8",
     0x000000e9 => "\xe9",
     0x000000ea => "\xea",
     0x000000eb => "\xeb",
     0x000000ec => "\xec",
     0x000000ed => "\xed",
     0x000000ee => "\xee",
     0x000000ef => "\xef",
     0x000000f2 => "\xf2",
     0x000000f3 => "\xf3",
     0x000000f4 => "\xf4",
     0x000000f6 => "\xf6",
     0x000000f9 => "\xf9",
     0x000000fa => "\xfa",
     0x000000fb => "\xfb",
     0x000000fc => "\xfc",
     0x000000ff => "\xff",
     0x00000102 => "\xc3",
     0x00000103 => "\xe3",
     0x00000104 => "\xa1",
     0x00000105 => "\xa2",
     0x00000106 => "\xc5",
     0x00000107 => "\xe5",
     0x0000010c => "\xb2",
     0x0000010d => "\xb9",
     0x00000110 => "\xd0",
     0x00000111 => "\xf0",
     0x00000118 => "\xdd",
     0x00000119 => "\xfd",
     0x00000141 => "\xa3",
     0x00000142 => "\xb3",
     0x00000143 => "\xd1",
     0x00000144 => "\xf1",
     0x00000150 => "\xd5",
     0x00000151 => "\xf5",
     0x00000152 => "\xbc",
     0x00000153 => "\xbd",
     0x0000015a => "\xd7",
     0x0000015b => "\xf7",
     0x00000160 => "\xa6",
     0x00000161 => "\xa8",
     0x00000170 => "\xd8",
     0x00000171 => "\xf8",
     0x00000178 => "\xbe",
     0x00000179 => "\xac",
     0x0000017a => "\xae",
     0x0000017b => "\xaf",
     0x0000017c => "\xbf",
     0x0000017d => "\xb4",
     0x0000017e => "\xb8",
     0x00000218 => "\xaa",
     0x00000219 => "\xba",
     0x0000021a => "\xde",
     0x0000021b => "\xfe",
     0x0000201d => "\xb5",
     0x0000201e => "\xa5",
     0x000020ac => "\xa4",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::ISO_8859_16 - Conversion routines for ISO-8859-16
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for ISO-8859-16.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  automatically generated from the charDB
  alias ISO-IR-226
  alias LATIN10
  alias L10
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL
     01 |  00000001 | START OF HEADING
     02 |  00000002 | START OF TEXT
     03 |  00000003 | END OF TEXT
     04 |  00000004 | END OF TRANSMISSION
     05 |  00000005 | ENQUIRY
     06 |  00000006 | ACKNOWLEDGE
     07 |  00000007 | BELL
     08 |  00000008 | BACKSPACE
     09 |  00000009 | HORIZONTAL TABULATION
     0A |  0000000A | LINE FEED
     0B |  0000000B | VERTICAL TABULATION
     0C |  0000000C | FORM FEED
     0D |  0000000D | CARRIAGE RETURN
     0E |  0000000E | SHIFT OUT
     0F |  0000000F | SHIFT IN
     10 |  00000010 | DATA LINK ESCAPE
     11 |  00000011 | DEVICE CONTROL ONE
     12 |  00000012 | DEVICE CONTROL TWO
     13 |  00000013 | DEVICE CONTROL THREE
     14 |  00000014 | DEVICE CONTROL FOUR
     15 |  00000015 | NEGATIVE ACKNOWLEDGE
     16 |  00000016 | SYNCHRONOUS IDLE
     17 |  00000017 | END OF TRANSMISSION BLOCK
     18 |  00000018 | CANCEL
     19 |  00000019 | END OF MEDIUM
     1A |  0000001A | SUBSTITUTE
     1B |  0000001B | ESCAPE
     1C |  0000001C | FILE SEPARATOR
     1D |  0000001D | GROUP SEPARATOR
     1E |  0000001E | RECORD SEPARATOR
     1F |  0000001F | UNIT SEPARATOR
     20 |  00000020 | SPACE
     21 |  00000021 | EXCLAMATION MARK
     22 |  00000022 | QUOTATION MARK
     23 |  00000023 | NUMBER SIGN
     24 |  00000024 | DOLLAR SIGN
     25 |  00000025 | PERCENT SIGN
     26 |  00000026 | AMPERSAND
     27 |  00000027 | APOSTROPHE
     28 |  00000028 | LEFT PARENTHESIS
     29 |  00000029 | RIGHT PARENTHESIS
     2A |  0000002A | ASTERISK
     2B |  0000002B | PLUS SIGN
     2C |  0000002C | COMMA
     2D |  0000002D | HYPHEN-MINUS
     2E |  0000002E | FULL STOP
     2F |  0000002F | SOLIDUS
     30 |  00000030 | DIGIT ZERO
     31 |  00000031 | DIGIT ONE
     32 |  00000032 | DIGIT TWO
     33 |  00000033 | DIGIT THREE
     34 |  00000034 | DIGIT FOUR
     35 |  00000035 | DIGIT FIVE
     36 |  00000036 | DIGIT SIX
     37 |  00000037 | DIGIT SEVEN
     38 |  00000038 | DIGIT EIGHT
     39 |  00000039 | DIGIT NINE
     3A |  0000003A | COLON
     3B |  0000003B | SEMICOLON
     3C |  0000003C | LESS-THAN SIGN
     3D |  0000003D | EQUALS SIGN
     3E |  0000003E | GREATER-THAN SIGN
     3F |  0000003F | QUESTION MARK
     40 |  00000040 | COMMERCIAL AT
     41 |  00000041 | LATIN CAPITAL LETTER A
     42 |  00000042 | LATIN CAPITAL LETTER B
     43 |  00000043 | LATIN CAPITAL LETTER C
     44 |  00000044 | LATIN CAPITAL LETTER D
     45 |  00000045 | LATIN CAPITAL LETTER E
     46 |  00000046 | LATIN CAPITAL LETTER F
     47 |  00000047 | LATIN CAPITAL LETTER G
     48 |  00000048 | LATIN CAPITAL LETTER H
     49 |  00000049 | LATIN CAPITAL LETTER I
     4A |  0000004A | LATIN CAPITAL LETTER J
     4B |  0000004B | LATIN CAPITAL LETTER K
     4C |  0000004C | LATIN CAPITAL LETTER L
     4D |  0000004D | LATIN CAPITAL LETTER M
     4E |  0000004E | LATIN CAPITAL LETTER N
     4F |  0000004F | LATIN CAPITAL LETTER O
     50 |  00000050 | LATIN CAPITAL LETTER P
     51 |  00000051 | LATIN CAPITAL LETTER Q
     52 |  00000052 | LATIN CAPITAL LETTER R
     53 |  00000053 | LATIN CAPITAL LETTER S
     54 |  00000054 | LATIN CAPITAL LETTER T
     55 |  00000055 | LATIN CAPITAL LETTER U
     56 |  00000056 | LATIN CAPITAL LETTER V
     57 |  00000057 | LATIN CAPITAL LETTER W
     58 |  00000058 | LATIN CAPITAL LETTER X
     59 |  00000059 | LATIN CAPITAL LETTER Y
     5A |  0000005A | LATIN CAPITAL LETTER Z
     5B |  0000005B | LEFT SQUARE BRACKET
     5C |  0000005C | REVERSE SOLIDUS
     5D |  0000005D | RIGHT SQUARE BRACKET
     5E |  0000005E | CIRCUMFLEX ACCENT
     5F |  0000005F | LOW LINE
     60 |  00000060 | GRAVE ACCENT
     61 |  00000061 | LATIN SMALL LETTER A
     62 |  00000062 | LATIN SMALL LETTER B
     63 |  00000063 | LATIN SMALL LETTER C
     64 |  00000064 | LATIN SMALL LETTER D
     65 |  00000065 | LATIN SMALL LETTER E
     66 |  00000066 | LATIN SMALL LETTER F
     67 |  00000067 | LATIN SMALL LETTER G
     68 |  00000068 | LATIN SMALL LETTER H
     69 |  00000069 | LATIN SMALL LETTER I
     6A |  0000006A | LATIN SMALL LETTER J
     6B |  0000006B | LATIN SMALL LETTER K
     6C |  0000006C | LATIN SMALL LETTER L
     6D |  0000006D | LATIN SMALL LETTER M
     6E |  0000006E | LATIN SMALL LETTER N
     6F |  0000006F | LATIN SMALL LETTER O
     70 |  00000070 | LATIN SMALL LETTER P
     71 |  00000071 | LATIN SMALL LETTER Q
     72 |  00000072 | LATIN SMALL LETTER R
     73 |  00000073 | LATIN SMALL LETTER S
     74 |  00000074 | LATIN SMALL LETTER T
     75 |  00000075 | LATIN SMALL LETTER U
     76 |  00000076 | LATIN SMALL LETTER V
     77 |  00000077 | LATIN SMALL LETTER W
     78 |  00000078 | LATIN SMALL LETTER X
     79 |  00000079 | LATIN SMALL LETTER Y
     7A |  0000007A | LATIN SMALL LETTER Z
     7B |  0000007B | LEFT CURLY BRACKET
     7C |  0000007C | VERTICAL LINE
     7D |  0000007D | RIGHT CURLY BRACKET
     7E |  0000007E | TILDE
     7F |  0000007F | DELETE
     80 |  00000080 | PADDING CHARACTER (PAD)
     81 |  00000081 | HIGH OCTET PRESET (HOP)
     82 |  00000082 | BREAK PERMITTED HERE (BPH)
     83 |  00000083 | NO BREAK HERE (NBH)
     84 |  00000084 | INDEX (IND)
     85 |  00000085 | NEXT LINE (NEL)
     86 |  00000086 | START OF SELECTED AREA (SSA)
     87 |  00000087 | END OF SELECTED AREA (ESA)
     88 |  00000088 | CHARACTER TABULATION SET (HTS)
     89 |  00000089 | CHARACTER TABULATION WITH JUSTIFICATION (HTJ)
     8A |  0000008A | LINE TABULATION SET (VTS)
     8B |  0000008B | PARTIAL LINE FORWARD (PLD)
     8C |  0000008C | PARTIAL LINE BACKWARD (PLU)
     8D |  0000008D | REVERSE LINE FEED (RI)
     8E |  0000008E | SINGLE-SHIFT TWO (SS2)
     8F |  0000008F | SINGLE-SHIFT THREE (SS3)
     90 |  00000090 | DEVICE CONTROL STRING (DCS)
     91 |  00000091 | PRIVATE USE ONE (PU1)
     92 |  00000092 | PRIVATE USE TWO (PU2)
     93 |  00000093 | SET TRANSMIT STATE (STS)
     94 |  00000094 | CANCEL CHARACTER (CCH)
     95 |  00000095 | MESSAGE WAITING (MW)
     96 |  00000096 | START OF GUARDED AREA (SPA)
     97 |  00000097 | END OF GUARDED AREA (EPA)
     98 |  00000098 | START OF STRING (SOS)
     99 |  00000099 | SINGLE GRAPHIC CHARACTER INTRODUCER (SGCI)
     9A |  0000009A | SINGLE CHARACTER INTRODUCER (SCI)
     9B |  0000009B | CONTROL SEQUENCE INTRODUCER (CSI)
     9C |  0000009C | STRING TERMINATOR (ST)
     9D |  0000009D | OPERATING SYSTEM COMMAND (OSC)
     9E |  0000009E | PRIVACY MESSAGE (PM)
     9F |  0000009F | APPLICATION PROGRAM COMMAND (APC)
     A0 |  000000A0 | NO-BREAK SPACE
     A1 |  00000104 | LATIN CAPITAL LETTER A WITH OGONEK
     A2 |  00000105 | LATIN SMALL LETTER A WITH OGONEK
     A3 |  00000141 | LATIN CAPITAL LETTER L WITH STROKE
     A4 |  000020AC | EURO SIGN
     A5 |  0000201E | DOUBLE LOW-9 QUOTATION MARK
     A6 |  00000160 | LATIN CAPITAL LETTER S WITH CARON
     A7 |  000000A7 | SECTION SIGN
     A8 |  00000161 | LATIN SMALL LETTER S WITH CARON
     A9 |  000000A9 | COPYRIGHT SIGN
     AA |  00000218 | LATIN CAPITAL LETTER S WITH COMMA BELOW
     AB |  000000AB | LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
     AC |  00000179 | LATIN CAPITAL LETTER Z WITH ACUTE
     AD |  000000AD | SOFT HYPHEN
     AE |  0000017A | LATIN SMALL LETTER Z WITH ACUTE
     AF |  0000017B | LATIN CAPITAL LETTER Z WITH DOT ABOVE
     B0 |  000000B0 | DEGREE SIGN
     B1 |  000000B1 | PLUS-MINUS SIGN
     B2 |  0000010C | LATIN CAPITAL LETTER C WITH CARON
     B3 |  00000142 | LATIN SMALL LETTER L WITH STROKE
     B4 |  0000017D | LATIN CAPITAL LETTER Z WITH CARON
     B5 |  0000201D | RIGHT DOUBLE QUOTATION MARK
     B6 |  000000B6 | PILCROW SIGN
     B7 |  000000B7 | MIDDLE DOT
     B8 |  0000017E | LATIN SMALL LETTER Z WITH CARON
     B9 |  0000010D | LATIN SMALL LETTER C WITH CARON
     BA |  00000219 | LATIN SMALL LETTER S WITH COMMA BELOW
     BB |  000000BB | RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
     BC |  00000152 | LATIN CAPITAL LIGATURE OE
     BD |  00000153 | LATIN SMALL LIGATURE OE
     BE |  00000178 | LATIN CAPITAL LETTER Y WITH DIAERESIS
     BF |  0000017C | LATIN SMALL LETTER Z WITH DOT ABOVE
     C0 |  000000C0 | LATIN CAPITAL LETTER A WITH GRAVE
     C1 |  000000C1 | LATIN CAPITAL LETTER A WITH ACUTE
     C2 |  000000C2 | LATIN CAPITAL LETTER A WITH CIRCUMFLEX
     C3 |  00000102 | LATIN CAPITAL LETTER A WITH BREVE
     C4 |  000000C4 | LATIN CAPITAL LETTER A WITH DIAERESIS
     C5 |  00000106 | LATIN CAPITAL LETTER C WITH ACUTE
     C6 |  000000C6 | LATIN CAPITAL LETTER AE
     C7 |  000000C7 | LATIN CAPITAL LETTER C WITH CEDILLA
     C8 |  000000C8 | LATIN CAPITAL LETTER E WITH GRAVE
     C9 |  000000C9 | LATIN CAPITAL LETTER E WITH ACUTE
     CA |  000000CA | LATIN CAPITAL LETTER E WITH CIRCUMFLEX
     CB |  000000CB | LATIN CAPITAL LETTER E WITH DIAERESIS
     CC |  000000CC | LATIN CAPITAL LETTER I WITH GRAVE
     CD |  000000CD | LATIN CAPITAL LETTER I WITH ACUTE
     CE |  000000CE | LATIN CAPITAL LETTER I WITH CIRCUMFLEX
     CF |  000000CF | LATIN CAPITAL LETTER I WITH DIAERESIS
     D0 |  00000110 | LATIN CAPITAL LETTER D WITH STROKE
     D1 |  00000143 | LATIN CAPITAL LETTER N WITH ACUTE
     D2 |  000000D2 | LATIN CAPITAL LETTER O WITH GRAVE
     D3 |  000000D3 | LATIN CAPITAL LETTER O WITH ACUTE
     D4 |  000000D4 | LATIN CAPITAL LETTER O WITH CIRCUMFLEX
     D5 |  00000150 | LATIN CAPITAL LETTER O WITH DOUBLE ACUTE
     D6 |  000000D6 | LATIN CAPITAL LETTER O WITH DIAERESIS
     D7 |  0000015A | LATIN CAPITAL LETTER S WITH ACUTE
     D8 |  00000170 | LATIN CAPITAL LETTER U WITH DOUBLE ACUTE
     D9 |  000000D9 | LATIN CAPITAL LETTER U WITH GRAVE
     DA |  000000DA | LATIN CAPITAL LETTER U WITH ACUTE
     DB |  000000DB | LATIN CAPITAL LETTER U WITH CIRCUMFLEX
     DC |  000000DC | LATIN CAPITAL LETTER U WITH DIAERESIS
     DD |  00000118 | LATIN CAPITAL LETTER E WITH OGONEK
     DE |  0000021A | LATIN CAPITAL LETTER T WITH COMMA BELOW
     DF |  000000DF | LATIN SMALL LETTER SHARP S
     E0 |  000000E0 | LATIN SMALL LETTER A WITH GRAVE
     E1 |  000000E1 | LATIN SMALL LETTER A WITH ACUTE
     E2 |  000000E2 | LATIN SMALL LETTER A WITH CIRCUMFLEX
     E3 |  00000103 | LATIN SMALL LETTER A WITH BREVE
     E4 |  000000E4 | LATIN SMALL LETTER A WITH DIAERESIS
     E5 |  00000107 | LATIN SMALL LETTER C WITH ACUTE
     E6 |  000000E6 | LATIN SMALL LETTER AE
     E7 |  000000E7 | LATIN SMALL LETTER C WITH CEDILLA
     E8 |  000000E8 | LATIN SMALL LETTER E WITH GRAVE
     E9 |  000000E9 | LATIN SMALL LETTER E WITH ACUTE
     EA |  000000EA | LATIN SMALL LETTER E WITH CIRCUMFLEX
     EB |  000000EB | LATIN SMALL LETTER E WITH DIAERESIS
     EC |  000000EC | LATIN SMALL LETTER I WITH GRAVE
     ED |  000000ED | LATIN SMALL LETTER I WITH ACUTE
     EE |  000000EE | LATIN SMALL LETTER I WITH CIRCUMFLEX
     EF |  000000EF | LATIN SMALL LETTER I WITH DIAERESIS
     F0 |  00000111 | LATIN SMALL LETTER D WITH STROKE
     F1 |  00000144 | LATIN SMALL LETTER N WITH ACUTE
     F2 |  000000F2 | LATIN SMALL LETTER O WITH GRAVE
     F3 |  000000F3 | LATIN SMALL LETTER O WITH ACUTE
     F4 |  000000F4 | LATIN SMALL LETTER O WITH CIRCUMFLEX
     F5 |  00000151 | LATIN SMALL LETTER O WITH DOUBLE ACUTE
     F6 |  000000F6 | LATIN SMALL LETTER O WITH DIAERESIS
     F7 |  0000015B | LATIN SMALL LETTER S WITH ACUTE
     F8 |  00000171 | LATIN SMALL LETTER U WITH DOUBLE ACUTE
     F9 |  000000F9 | LATIN SMALL LETTER U WITH GRAVE
     FA |  000000FA | LATIN SMALL LETTER U WITH ACUTE
     FB |  000000FB | LATIN SMALL LETTER U WITH CIRCUMFLEX
     FC |  000000FC | LATIN SMALL LETTER U WITH DIAERESIS
     FD |  00000119 | LATIN SMALL LETTER E WITH OGONEK
     FE |  0000021B | LATIN SMALL LETTER T WITH COMMA BELOW
     FF |  000000FF | LATIN SMALL LETTER Y WITH DIAERESIS
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/ISO_8859_2.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for ISO-8859-2.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::ISO_8859_2;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x0004,
     0x0005,
     0x0006,
     0x0007,
     0x0008,
     0x0009,
     0x000a,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x0014,
     0x0015,
     0x0016,
     0x0017,
     0x0018,
     0x0019,
     0x001a,
     0x001b,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0020,
     0x0021,
     0x0022,
     0x0023,
     0x0024,
     0x0025,
     0x0026,
     0x0027,
     0x0028,
     0x0029,
     0x002a,
     0x002b,
     0x002c,
     0x002d,
     0x002e,
     0x002f,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x003a,
     0x003b,
     0x003c,
     0x003d,
     0x003e,
     0x003f,
     0x0040,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x005b,
     0x005c,
     0x005d,
     0x005e,
     0x005f,
     0x0060,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x007b,
     0x007c,
     0x007d,
     0x007e,
     0x007f,
     0x0080,
     0x0081,
     0x0082,
     0x0083,
     0x0084,
     0x0085,
     0x0086,
     0x0087,
     0x0088,
     0x0089,
     0x008a,
     0x008b,
     0x008c,
     0x008d,
     0x008e,
     0x008f,
     0x0090,
     0x0091,
     0x0092,
     0x0093,
     0x0094,
     0x0095,
     0x0096,
     0x0097,
     0x0098,
     0x0099,
     0x009a,
     0x009b,
     0x009c,
     0x009d,
     0x009e,
     0x009f,
     0x00a0,
     0x0104,
     0x02d8,
     0x0141,
     0x00a4,
     0x013d,
     0x015a,
     0x00a7,
     0x00a8,
     0x0160,
     0x015e,
     0x0164,
     0x0179,
     0x00ad,
     0x017d,
     0x017b,
     0x00b0,
     0x0105,
     0x02db,
     0x0142,
     0x00b4,
     0x013e,
     0x015b,
     0x02c7,
     0x00b8,
     0x0161,
     0x015f,
     0x0165,
     0x017a,
     0x02dd,
     0x017e,
     0x017c,
     0x0154,
     0x00c1,
     0x00c2,
     0x0102,
     0x00c4,
     0x0139,
     0x0106,
     0x00c7,
     0x010c,
     0x00c9,
     0x0118,
     0x00cb,
     0x011a,
     0x00cd,
     0x00ce,
     0x010e,
     0x0110,
     0x0143,
     0x0147,
     0x00d3,
     0x00d4,
     0x0150,
     0x00d6,
     0x00d7,
     0x0158,
     0x016e,
     0x00da,
     0x0170,
     0x00dc,
     0x00dd,
     0x0162,
     0x00df,
     0x0155,
     0x00e1,
     0x00e2,
     0x0103,
     0x00e4,
     0x013a,
     0x0107,
     0x00e7,
     0x010d,
     0x00e9,
     0x0119,
     0x00eb,
     0x011b,
     0x00ed,
     0x00ee,
     0x010f,
     0x0111,
     0x0144,
     0x0148,
     0x00f3,
     0x00f4,
     0x0151,
     0x00f6,
     0x00f7,
     0x0159,
     0x016f,
     0x00fa,
     0x0171,
     0x00fc,
     0x00fd,
     0x0163,
     0x02d9,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\x04",
     "\x05",
     "\x06",
     "\x07",
     "\x08",
     "\x09",
     "\x0a",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\x14",
     "\x15",
     "\x16",
     "\x17",
     "\x18",
     "\x19",
     "\x1a",
     "\x1b",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\x20",
     "\x21",
     "\x22",
     "\x23",
     "\x24",
     "\x25",
     "\x26",
     "\x27",
     "\x28",
     "\x29",
     "\x2a",
     "\x2b",
     "\x2c",
     "\x2d",
     "\x2e",
     "\x2f",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\x3a",
     "\x3b",
     "\x3c",
     "\x3d",
     "\x3e",
     "\x3f",
     "\x40",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\x5b",
     "\x5c",
     "\x5d",
     "\x5e",
     "\x5f",
     "\x60",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\x7b",
     "\x7c",
     "\x7d",
     "\x7e",
     "\x7f",
     "\xc2\x80",
     "\xc2\x81",
     "\xc2\x82",
     "\xc2\x83",
     "\xc2\x84",
     "\xc2\x85",
     "\xc2\x86",
     "\xc2\x87",
     "\xc2\x88",
     "\xc2\x89",
     "\xc2\x8a",
     "\xc2\x8b",
     "\xc2\x8c",
     "\xc2\x8d",
     "\xc2\x8e",
     "\xc2\x8f",
     "\xc2\x90",
     "\xc2\x91",
     "\xc2\x92",
     "\xc2\x93",
     "\xc2\x94",
     "\xc2\x95",
     "\xc2\x96",
     "\xc2\x97",
     "\xc2\x98",
     "\xc2\x99",
     "\xc2\x9a",
     "\xc2\x9b",
     "\xc2\x9c",
     "\xc2\x9d",
     "\xc2\x9e",
     "\xc2\x9f",
     "\xc2\xa0",
     "\xc4\x84",
     "\xcb\x98",
     "\xc5\x81",
     "\xc2\xa4",
     "\xc4\xbd",
     "\xc5\x9a",
     "\xc2\xa7",
     "\xc2\xa8",
     "\xc5\xa0",
     "\xc5\x9e",
     "\xc5\xa4",
     "\xc5\xb9",
     "\xc2\xad",
     "\xc5\xbd",
     "\xc5\xbb",
     "\xc2\xb0",
     "\xc4\x85",
     "\xcb\x9b",
     "\xc5\x82",
     "\xc2\xb4",
     "\xc4\xbe",
     "\xc5\x9b",
     "\xcb\x87",
     "\xc2\xb8",
     "\xc5\xa1",
     "\xc5\x9f",
     "\xc5\xa5",
     "\xc5\xba",
     "\xcb\x9d",
     "\xc5\xbe",
     "\xc5\xbc",
     "\xc5\x94",
     "\xc3\x81",
     "\xc3\x82",
     "\xc4\x82",
     "\xc3\x84",
     "\xc4\xb9",
     "\xc4\x86",
     "\xc3\x87",
     "\xc4\x8c",
     "\xc3\x89",
     "\xc4\x98",
     "\xc3\x8b",
     "\xc4\x9a",
     "\xc3\x8d",
     "\xc3\x8e",
     "\xc4\x8e",
     "\xc4\x90",
     "\xc5\x83",
     "\xc5\x87",
     "\xc3\x93",
     "\xc3\x94",
     "\xc5\x90",
     "\xc3\x96",
     "\xc3\x97",
     "\xc5\x98",
     "\xc5\xae",
     "\xc3\x9a",
     "\xc5\xb0",
     "\xc3\x9c",
     "\xc3\x9d",
     "\xc5\xa2",
     "\xc3\x9f",
     "\xc5\x95",
     "\xc3\xa1",
     "\xc3\xa2",
     "\xc4\x83",
     "\xc3\xa4",
     "\xc4\xba",
     "\xc4\x87",
     "\xc3\xa7",
     "\xc4\x8d",
     "\xc3\xa9",
     "\xc4\x99",
     "\xc3\xab",
     "\xc4\x9b",
     "\xc3\xad",
     "\xc3\xae",
     "\xc4\x8f",
     "\xc4\x91",
     "\xc5\x84",
     "\xc5\x88",
     "\xc3\xb3",
     "\xc3\xb4",
     "\xc5\x91",
     "\xc3\xb6",
     "\xc3\xb7",
     "\xc5\x99",
     "\xc5\xaf",
     "\xc3\xba",
     "\xc5\xb1",
     "\xc3\xbc",
     "\xc3\xbd",
     "\xc5\xa3",
     "\xcb\x99",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x04",
     0x00000005 => "\x05",
     0x00000006 => "\x06",
     0x00000007 => "\x07",
     0x00000008 => "\x08",
     0x00000009 => "\x09",
     0x0000000a => "\x0a",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x14",
     0x00000015 => "\x15",
     0x00000016 => "\x16",
     0x00000017 => "\x17",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x1a",
     0x0000001b => "\x1b",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x20",
     0x00000021 => "\x21",
     0x00000022 => "\x22",
     0x00000023 => "\x23",
     0x00000024 => "\x24",
     0x00000025 => "\x25",
     0x00000026 => "\x26",
     0x00000027 => "\x27",
     0x00000028 => "\x28",
     0x00000029 => "\x29",
     0x0000002a => "\x2a",
     0x0000002b => "\x2b",
     0x0000002c => "\x2c",
     0x0000002d => "\x2d",
     0x0000002e => "\x2e",
     0x0000002f => "\x2f",
     0x00000030 => "\x30",
     0x00000031 => "\x31",
     0x00000032 => "\x32",
     0x00000033 => "\x33",
     0x00000034 => "\x34",
     0x00000035 => "\x35",
     0x00000036 => "\x36",
     0x00000037 => "\x37",
     0x00000038 => "\x38",
     0x00000039 => "\x39",
     0x0000003a => "\x3a",
     0x0000003b => "\x3b",
     0x0000003c => "\x3c",
     0x0000003d => "\x3d",
     0x0000003e => "\x3e",
     0x0000003f => "\x3f",
     0x00000040 => "\x40",
     0x00000041 => "\x41",
     0x00000042 => "\x42",
     0x00000043 => "\x43",
     0x00000044 => "\x44",
     0x00000045 => "\x45",
     0x00000046 => "\x46",
     0x00000047 => "\x47",
     0x00000048 => "\x48",
     0x00000049 => "\x49",
     0x0000004a => "\x4a",
     0x0000004b => "\x4b",
     0x0000004c => "\x4c",
     0x0000004d => "\x4d",
     0x0000004e => "\x4e",
     0x0000004f => "\x4f",
     0x00000050 => "\x50",
     0x00000051 => "\x51",
     0x00000052 => "\x52",
     0x00000053 => "\x53",
     0x00000054 => "\x54",
     0x00000055 => "\x55",
     0x00000056 => "\x56",
     0x00000057 => "\x57",
     0x00000058 => "\x58",
     0x00000059 => "\x59",
     0x0000005a => "\x5a",
     0x0000005b => "\x5b",
     0x0000005c => "\x5c",
     0x0000005d => "\x5d",
     0x0000005e => "\x5e",
     0x0000005f => "\x5f",
     0x00000060 => "\x60",
     0x00000061 => "\x61",
     0x00000062 => "\x62",
     0x00000063 => "\x63",
     0x00000064 => "\x64",
     0x00000065 => "\x65",
     0x00000066 => "\x66",
     0x00000067 => "\x67",
     0x00000068 => "\x68",
     0x00000069 => "\x69",
     0x0000006a => "\x6a",
     0x0000006b => "\x6b",
     0x0000006c => "\x6c",
     0x0000006d => "\x6d",
     0x0000006e => "\x6e",
     0x0000006f => "\x6f",
     0x00000070 => "\x70",
     0x00000071 => "\x71",
     0x00000072 => "\x72",
     0x00000073 => "\x73",
     0x00000074 => "\x74",
     0x00000075 => "\x75",
     0x00000076 => "\x76",
     0x00000077 => "\x77",
     0x00000078 => "\x78",
     0x00000079 => "\x79",
     0x0000007a => "\x7a",
     0x0000007b => "\x7b",
     0x0000007c => "\x7c",
     0x0000007d => "\x7d",
     0x0000007e => "\x7e",
     0x0000007f => "\x7f",
     0x00000080 => "\x80",
     0x00000081 => "\x81",
     0x00000082 => "\x82",
     0x00000083 => "\x83",
     0x00000084 => "\x84",
     0x00000085 => "\x85",
     0x00000086 => "\x86",
     0x00000087 => "\x87",
     0x00000088 => "\x88",
     0x00000089 => "\x89",
     0x0000008a => "\x8a",
     0x0000008b => "\x8b",
     0x0000008c => "\x8c",
     0x0000008d => "\x8d",
     0x0000008e => "\x8e",
     0x0000008f => "\x8f",
     0x00000090 => "\x90",
     0x00000091 => "\x91",
     0x00000092 => "\x92",
     0x00000093 => "\x93",
     0x00000094 => "\x94",
     0x00000095 => "\x95",
     0x00000096 => "\x96",
     0x00000097 => "\x97",
     0x00000098 => "\x98",
     0x00000099 => "\x99",
     0x0000009a => "\x9a",
     0x0000009b => "\x9b",
     0x0000009c => "\x9c",
     0x0000009d => "\x9d",
     0x0000009e => "\x9e",
     0x0000009f => "\x9f",
     0x000000a0 => "\xa0",
     0x000000a4 => "\xa4",
     0x000000a7 => "\xa7",
     0x000000a8 => "\xa8",
     0x000000ad => "\xad",
     0x000000b0 => "\xb0",
     0x000000b4 => "\xb4",
     0x000000b8 => "\xb8",
     0x000000c1 => "\xc1",
     0x000000c2 => "\xc2",
     0x000000c4 => "\xc4",
     0x000000c7 => "\xc7",
     0x000000c9 => "\xc9",
     0x000000cb => "\xcb",
     0x000000cd => "\xcd",
     0x000000ce => "\xce",
     0x000000d3 => "\xd3",
     0x000000d4 => "\xd4",
     0x000000d6 => "\xd6",
     0x000000d7 => "\xd7",
     0x000000da => "\xda",
     0x000000dc => "\xdc",
     0x000000dd => "\xdd",
     0x000000df => "\xdf",
     0x000000e1 => "\xe1",
     0x000000e2 => "\xe2",
     0x000000e4 => "\xe4",
     0x000000e7 => "\xe7",
     0x000000e9 => "\xe9",
     0x000000eb => "\xeb",
     0x000000ed => "\xed",
     0x000000ee => "\xee",
     0x000000f3 => "\xf3",
     0x000000f4 => "\xf4",
     0x000000f6 => "\xf6",
     0x000000f7 => "\xf7",
     0x000000fa => "\xfa",
     0x000000fc => "\xfc",
     0x000000fd => "\xfd",
     0x00000102 => "\xc3",
     0x00000103 => "\xe3",
     0x00000104 => "\xa1",
     0x00000105 => "\xb1",
     0x00000106 => "\xc6",
     0x00000107 => "\xe6",
     0x0000010c => "\xc8",
     0x0000010d => "\xe8",
     0x0000010e => "\xcf",
     0x0000010f => "\xef",
     0x00000110 => "\xd0",
     0x00000111 => "\xf0",
     0x00000118 => "\xca",
     0x00000119 => "\xea",
     0x0000011a => "\xcc",
     0x0000011b => "\xec",
     0x00000139 => "\xc5",
     0x0000013a => "\xe5",
     0x0000013d => "\xa5",
     0x0000013e => "\xb5",
     0x00000141 => "\xa3",
     0x00000142 => "\xb3",
     0x00000143 => "\xd1",
     0x00000144 => "\xf1",
     0x00000147 => "\xd2",
     0x00000148 => "\xf2",
     0x00000150 => "\xd5",
     0x00000151 => "\xf5",
     0x00000154 => "\xc0",
     0x00000155 => "\xe0",
     0x00000158 => "\xd8",
     0x00000159 => "\xf8",
     0x0000015a => "\xa6",
     0x0000015b => "\xb6",
     0x0000015e => "\xaa",
     0x0000015f => "\xba",
     0x00000160 => "\xa9",
     0x00000161 => "\xb9",
     0x00000162 => "\xde",
     0x00000163 => "\xfe",
     0x00000164 => "\xab",
     0x00000165 => "\xbb",
     0x0000016e => "\xd9",
     0x0000016f => "\xf9",
     0x00000170 => "\xdb",
     0x00000171 => "\xfb",
     0x00000179 => "\xac",
     0x0000017a => "\xbc",
     0x0000017b => "\xaf",
     0x0000017c => "\xbf",
     0x0000017d => "\xae",
     0x0000017e => "\xbe",
     0x000002c7 => "\xb7",
     0x000002d8 => "\xa2",
     0x000002d9 => "\xff",
     0x000002db => "\xb2",
     0x000002dd => "\xbd",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::ISO_8859_2 - Conversion routines for ISO-8859-2
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for ISO-8859-2.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
   source: ECMA registry
  alias ISO-IR-101
  alias ISO_8859-2:1987
  alias ISO_8859-2
  alias LATIN2
  alias L2
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  00000004 | END OF TRANSMISSION (EOT)
     05 |  00000005 | ENQUIRY (ENQ)
     06 |  00000006 | ACKNOWLEDGE (ACK)
     07 |  00000007 | BELL (BEL)
     08 |  00000008 | BACKSPACE (BS)
     09 |  00000009 | CHARACTER TABULATION (HT)
     0A |  0000000A | LINE FEED (LF)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  00000014 | DEVICE CONTROL FOUR (DC4)
     15 |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     16 |  00000016 | SYNCHRONOUS IDLE (SYN)
     17 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  0000001A | SUBSTITUTE (SUB)
     1B |  0000001B | ESCAPE (ESC)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000020 | SPACE
     21 |  00000021 | EXCLAMATION MARK
     22 |  00000022 | QUOTATION MARK
     23 |  00000023 | NUMBER SIGN
     24 |  00000024 | DOLLAR SIGN
     25 |  00000025 | PERCENT SIGN
     26 |  00000026 | AMPERSAND
     27 |  00000027 | APOSTROPHE
     28 |  00000028 | LEFT PARENTHESIS
     29 |  00000029 | RIGHT PARENTHESIS
     2A |  0000002A | ASTERISK
     2B |  0000002B | PLUS SIGN
     2C |  0000002C | COMMA
     2D |  0000002D | HYPHEN-MINUS
     2E |  0000002E | FULL STOP
     2F |  0000002F | SOLIDUS
     30 |  00000030 | DIGIT ZERO
     31 |  00000031 | DIGIT ONE
     32 |  00000032 | DIGIT TWO
     33 |  00000033 | DIGIT THREE
     34 |  00000034 | DIGIT FOUR
     35 |  00000035 | DIGIT FIVE
     36 |  00000036 | DIGIT SIX
     37 |  00000037 | DIGIT SEVEN
     38 |  00000038 | DIGIT EIGHT
     39 |  00000039 | DIGIT NINE
     3A |  0000003A | COLON
     3B |  0000003B | SEMICOLON
     3C |  0000003C | LESS-THAN SIGN
     3D |  0000003D | EQUALS SIGN
     3E |  0000003E | GREATER-THAN SIGN
     3F |  0000003F | QUESTION MARK
     40 |  00000040 | COMMERCIAL AT
     41 |  00000041 | LATIN CAPITAL LETTER A
     42 |  00000042 | LATIN CAPITAL LETTER B
     43 |  00000043 | LATIN CAPITAL LETTER C
     44 |  00000044 | LATIN CAPITAL LETTER D
     45 |  00000045 | LATIN CAPITAL LETTER E
     46 |  00000046 | LATIN CAPITAL LETTER F
     47 |  00000047 | LATIN CAPITAL LETTER G
     48 |  00000048 | LATIN CAPITAL LETTER H
     49 |  00000049 | LATIN CAPITAL LETTER I
     4A |  0000004A | LATIN CAPITAL LETTER J
     4B |  0000004B | LATIN CAPITAL LETTER K
     4C |  0000004C | LATIN CAPITAL LETTER L
     4D |  0000004D | LATIN CAPITAL LETTER M
     4E |  0000004E | LATIN CAPITAL LETTER N
     4F |  0000004F | LATIN CAPITAL LETTER O
     50 |  00000050 | LATIN CAPITAL LETTER P
     51 |  00000051 | LATIN CAPITAL LETTER Q
     52 |  00000052 | LATIN CAPITAL LETTER R
     53 |  00000053 | LATIN CAPITAL LETTER S
     54 |  00000054 | LATIN CAPITAL LETTER T
     55 |  00000055 | LATIN CAPITAL LETTER U
     56 |  00000056 | LATIN CAPITAL LETTER V
     57 |  00000057 | LATIN CAPITAL LETTER W
     58 |  00000058 | LATIN CAPITAL LETTER X
     59 |  00000059 | LATIN CAPITAL LETTER Y
     5A |  0000005A | LATIN CAPITAL LETTER Z
     5B |  0000005B | LEFT SQUARE BRACKET
     5C |  0000005C | REVERSE SOLIDUS
     5D |  0000005D | RIGHT SQUARE BRACKET
     5E |  0000005E | CIRCUMFLEX ACCENT
     5F |  0000005F | LOW LINE
     60 |  00000060 | GRAVE ACCENT
     61 |  00000061 | LATIN SMALL LETTER A
     62 |  00000062 | LATIN SMALL LETTER B
     63 |  00000063 | LATIN SMALL LETTER C
     64 |  00000064 | LATIN SMALL LETTER D
     65 |  00000065 | LATIN SMALL LETTER E
     66 |  00000066 | LATIN SMALL LETTER F
     67 |  00000067 | LATIN SMALL LETTER G
     68 |  00000068 | LATIN SMALL LETTER H
     69 |  00000069 | LATIN SMALL LETTER I
     6A |  0000006A | LATIN SMALL LETTER J
     6B |  0000006B | LATIN SMALL LETTER K
     6C |  0000006C | LATIN SMALL LETTER L
     6D |  0000006D | LATIN SMALL LETTER M
     6E |  0000006E | LATIN SMALL LETTER N
     6F |  0000006F | LATIN SMALL LETTER O
     70 |  00000070 | LATIN SMALL LETTER P
     71 |  00000071 | LATIN SMALL LETTER Q
     72 |  00000072 | LATIN SMALL LETTER R
     73 |  00000073 | LATIN SMALL LETTER S
     74 |  00000074 | LATIN SMALL LETTER T
     75 |  00000075 | LATIN SMALL LETTER U
     76 |  00000076 | LATIN SMALL LETTER V
     77 |  00000077 | LATIN SMALL LETTER W
     78 |  00000078 | LATIN SMALL LETTER X
     79 |  00000079 | LATIN SMALL LETTER Y
     7A |  0000007A | LATIN SMALL LETTER Z
     7B |  0000007B | LEFT CURLY BRACKET
     7C |  0000007C | VERTICAL LINE
     7D |  0000007D | RIGHT CURLY BRACKET
     7E |  0000007E | TILDE
     7F |  0000007F | DELETE (DEL)
     80 |  00000080 | PADDING CHARACTER (PAD)
     81 |  00000081 | HIGH OCTET PRESET (HOP)
     82 |  00000082 | BREAK PERMITTED HERE (BPH)
     83 |  00000083 | NO BREAK HERE (NBH)
     84 |  00000084 | INDEX (IND)
     85 |  00000085 | NEXT LINE (NEL)
     86 |  00000086 | START OF SELECTED AREA (SSA)
     87 |  00000087 | END OF SELECTED AREA (ESA)
     88 |  00000088 | CHARACTER TABULATION SET (HTS)
     89 |  00000089 | CHARACTER TABULATION WITH JUSTIFICATION (HTJ)
     8A |  0000008A | LINE TABULATION SET (VTS)
     8B |  0000008B | PARTIAL LINE FORWARD (PLD)
     8C |  0000008C | PARTIAL LINE BACKWARD (PLU)
     8D |  0000008D | REVERSE LINE FEED (RI)
     8E |  0000008E | SINGLE-SHIFT TWO (SS2)
     8F |  0000008F | SINGLE-SHIFT THREE (SS3)
     90 |  00000090 | DEVICE CONTROL STRING (DCS)
     91 |  00000091 | PRIVATE USE ONE (PU1)
     92 |  00000092 | PRIVATE USE TWO (PU2)
     93 |  00000093 | SET TRANSMIT STATE (STS)
     94 |  00000094 | CANCEL CHARACTER (CCH)
     95 |  00000095 | MESSAGE WAITING (MW)
     96 |  00000096 | START OF GUARDED AREA (SPA)
     97 |  00000097 | END OF GUARDED AREA (EPA)
     98 |  00000098 | START OF STRING (SOS)
     99 |  00000099 | SINGLE GRAPHIC CHARACTER INTRODUCER (SGCI)
     9A |  0000009A | SINGLE CHARACTER INTRODUCER (SCI)
     9B |  0000009B | CONTROL SEQUENCE INTRODUCER (CSI)
     9C |  0000009C | STRING TERMINATOR (ST)
     9D |  0000009D | OPERATING SYSTEM COMMAND (OSC)
     9E |  0000009E | PRIVACY MESSAGE (PM)
     9F |  0000009F | APPLICATION PROGRAM COMMAND (APC)
     A0 |  000000A0 | NO-BREAK SPACE
     A1 |  00000104 | LATIN CAPITAL LETTER A WITH OGONEK
     A2 |  000002D8 | BREVE
     A3 |  00000141 | LATIN CAPITAL LETTER L WITH STROKE
     A4 |  000000A4 | CURRENCY SIGN
     A5 |  0000013D | LATIN CAPITAL LETTER L WITH CARON
     A6 |  0000015A | LATIN CAPITAL LETTER S WITH ACUTE
     A7 |  000000A7 | SECTION SIGN
     A8 |  000000A8 | DIAERESIS
     A9 |  00000160 | LATIN CAPITAL LETTER S WITH CARON
     AA |  0000015E | LATIN CAPITAL LETTER S WITH CEDILLA
     AB |  00000164 | LATIN CAPITAL LETTER T WITH CARON
     AC |  00000179 | LATIN CAPITAL LETTER Z WITH ACUTE
     AD |  000000AD | SOFT HYPHEN
     AE |  0000017D | LATIN CAPITAL LETTER Z WITH CARON
     AF |  0000017B | LATIN CAPITAL LETTER Z WITH DOT ABOVE
     B0 |  000000B0 | DEGREE SIGN
     B1 |  00000105 | LATIN SMALL LETTER A WITH OGONEK
     B2 |  000002DB | OGONEK
     B3 |  00000142 | LATIN SMALL LETTER L WITH STROKE
     B4 |  000000B4 | ACUTE ACCENT
     B5 |  0000013E | LATIN SMALL LETTER L WITH CARON
     B6 |  0000015B | LATIN SMALL LETTER S WITH ACUTE
     B7 |  000002C7 | CARON (Mandarin Chinese third tone)
     B8 |  000000B8 | CEDILLA
     B9 |  00000161 | LATIN SMALL LETTER S WITH CARON
     BA |  0000015F | LATIN SMALL LETTER S WITH CEDILLA
     BB |  00000165 | LATIN SMALL LETTER T WITH CARON
     BC |  0000017A | LATIN SMALL LETTER Z WITH ACUTE
     BD |  000002DD | DOUBLE ACUTE ACCENT
     BE |  0000017E | LATIN SMALL LETTER Z WITH CARON
     BF |  0000017C | LATIN SMALL LETTER Z WITH DOT ABOVE
     C0 |  00000154 | LATIN CAPITAL LETTER R WITH ACUTE
     C1 |  000000C1 | LATIN CAPITAL LETTER A WITH ACUTE
     C2 |  000000C2 | LATIN CAPITAL LETTER A WITH CIRCUMFLEX
     C3 |  00000102 | LATIN CAPITAL LETTER A WITH BREVE
     C4 |  000000C4 | LATIN CAPITAL LETTER A WITH DIAERESIS
     C5 |  00000139 | LATIN CAPITAL LETTER L WITH ACUTE
     C6 |  00000106 | LATIN CAPITAL LETTER C WITH ACUTE
     C7 |  000000C7 | LATIN CAPITAL LETTER C WITH CEDILLA
     C8 |  0000010C | LATIN CAPITAL LETTER C WITH CARON
     C9 |  000000C9 | LATIN CAPITAL LETTER E WITH ACUTE
     CA |  00000118 | LATIN CAPITAL LETTER E WITH OGONEK
     CB |  000000CB | LATIN CAPITAL LETTER E WITH DIAERESIS
     CC |  0000011A | LATIN CAPITAL LETTER E WITH CARON
     CD |  000000CD | LATIN CAPITAL LETTER I WITH ACUTE
     CE |  000000CE | LATIN CAPITAL LETTER I WITH CIRCUMFLEX
     CF |  0000010E | LATIN CAPITAL LETTER D WITH CARON
     D0 |  00000110 | LATIN CAPITAL LETTER D WITH STROKE
     D1 |  00000143 | LATIN CAPITAL LETTER N WITH ACUTE
     D2 |  00000147 | LATIN CAPITAL LETTER N WITH CARON
     D3 |  000000D3 | LATIN CAPITAL LETTER O WITH ACUTE
     D4 |  000000D4 | LATIN CAPITAL LETTER O WITH CIRCUMFLEX
     D5 |  00000150 | LATIN CAPITAL LETTER O WITH DOUBLE ACUTE
     D6 |  000000D6 | LATIN CAPITAL LETTER O WITH DIAERESIS
     D7 |  000000D7 | MULTIPLICATION SIGN
     D8 |  00000158 | LATIN CAPITAL LETTER R WITH CARON
     D9 |  0000016E | LATIN CAPITAL LETTER U WITH RING ABOVE
     DA |  000000DA | LATIN CAPITAL LETTER U WITH ACUTE
     DB |  00000170 | LATIN CAPITAL LETTER U WITH DOUBLE ACUTE
     DC |  000000DC | LATIN CAPITAL LETTER U WITH DIAERESIS
     DD |  000000DD | LATIN CAPITAL LETTER Y WITH ACUTE
     DE |  00000162 | LATIN CAPITAL LETTER T WITH CEDILLA
     DF |  000000DF | LATIN SMALL LETTER SHARP S (German)
     E0 |  00000155 | LATIN SMALL LETTER R WITH ACUTE
     E1 |  000000E1 | LATIN SMALL LETTER A WITH ACUTE
     E2 |  000000E2 | LATIN SMALL LETTER A WITH CIRCUMFLEX
     E3 |  00000103 | LATIN SMALL LETTER A WITH BREVE
     E4 |  000000E4 | LATIN SMALL LETTER A WITH DIAERESIS
     E5 |  0000013A | LATIN SMALL LETTER L WITH ACUTE
     E6 |  00000107 | LATIN SMALL LETTER C WITH ACUTE
     E7 |  000000E7 | LATIN SMALL LETTER C WITH CEDILLA
     E8 |  0000010D | LATIN SMALL LETTER C WITH CARON
     E9 |  000000E9 | LATIN SMALL LETTER E WITH ACUTE
     EA |  00000119 | LATIN SMALL LETTER E WITH OGONEK
     EB |  000000EB | LATIN SMALL LETTER E WITH DIAERESIS
     EC |  0000011B | LATIN SMALL LETTER E WITH CARON
     ED |  000000ED | LATIN SMALL LETTER I WITH ACUTE
     EE |  000000EE | LATIN SMALL LETTER I WITH CIRCUMFLEX
     EF |  0000010F | LATIN SMALL LETTER D WITH CARON
     F0 |  00000111 | LATIN SMALL LETTER D WITH STROKE
     F1 |  00000144 | LATIN SMALL LETTER N WITH ACUTE
     F2 |  00000148 | LATIN SMALL LETTER N WITH CARON
     F3 |  000000F3 | LATIN SMALL LETTER O WITH ACUTE
     F4 |  000000F4 | LATIN SMALL LETTER O WITH CIRCUMFLEX
     F5 |  00000151 | LATIN SMALL LETTER O WITH DOUBLE ACUTE
     F6 |  000000F6 | LATIN SMALL LETTER O WITH DIAERESIS
     F7 |  000000F7 | DIVISION SIGN
     F8 |  00000159 | LATIN SMALL LETTER R WITH CARON
     F9 |  0000016F | LATIN SMALL LETTER U WITH RING ABOVE
     FA |  000000FA | LATIN SMALL LETTER U WITH ACUTE
     FB |  00000171 | LATIN SMALL LETTER U WITH DOUBLE ACUTE
     FC |  000000FC | LATIN SMALL LETTER U WITH DIAERESIS
     FD |  000000FD | LATIN SMALL LETTER Y WITH ACUTE
     FE |  00000163 | LATIN SMALL LETTER T WITH CEDILLA
     FF |  000002D9 | DOT ABOVE (Mandarin Chinese light tone)
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/ISO_8859_3.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for ISO-8859-3.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::ISO_8859_3;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x0004,
     0x0005,
     0x0006,
     0x0007,
     0x0008,
     0x0009,
     0x000a,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x0014,
     0x0015,
     0x0016,
     0x0017,
     0x0018,
     0x0019,
     0x001a,
     0x001b,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0020,
     0x0021,
     0x0022,
     0x0023,
     0x0024,
     0x0025,
     0x0026,
     0x0027,
     0x0028,
     0x0029,
     0x002a,
     0x002b,
     0x002c,
     0x002d,
     0x002e,
     0x002f,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x003a,
     0x003b,
     0x003c,
     0x003d,
     0x003e,
     0x003f,
     0x0040,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x005b,
     0x005c,
     0x005d,
     0x005e,
     0x005f,
     0x0060,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x007b,
     0x007c,
     0x007d,
     0x007e,
     0x007f,
     0x0080,
     0x0081,
     0x0082,
     0x0083,
     0x0084,
     0x0085,
     0x0086,
     0x0087,
     0x0088,
     0x0089,
     0x008a,
     0x008b,
     0x008c,
     0x008d,
     0x008e,
     0x008f,
     0x0090,
     0x0091,
     0x0092,
     0x0093,
     0x0094,
     0x0095,
     0x0096,
     0x0097,
     0x0098,
     0x0099,
     0x009a,
     0x009b,
     0x009c,
     0x009d,
     0x009e,
     0x009f,
     0x00a0,
     0x0126,
     0x02d8,
     0x00a3,
     0x00a4,
     0xfffd,
     0x0124,
     0x00a7,
     0x00a8,
     0x0130,
     0x015e,
     0x011e,
     0x0134,
     0x00ad,
     0xfffd,
     0x017b,
     0x00b0,
     0x0127,
     0x00b2,
     0x00b3,
     0x00b4,
     0x00b5,
     0x0125,
     0x00b7,
     0x00b8,
     0x0131,
     0x015f,
     0x011f,
     0x0135,
     0x00bd,
     0xfffd,
     0x017c,
     0x00c0,
     0x00c1,
     0x00c2,
     0xfffd,
     0x00c4,
     0x010a,
     0x0108,
     0x00c7,
     0x00c8,
     0x00c9,
     0x00ca,
     0x00cb,
     0x00cc,
     0x00cd,
     0x00ce,
     0x00cf,
     0xfffd,
     0x00d1,
     0x00d2,
     0x00d3,
     0x00d4,
     0x0120,
     0x00d6,
     0x00d7,
     0x011c,
     0x00d9,
     0x00da,
     0x00db,
     0x00dc,
     0x016c,
     0x015c,
     0x00df,
     0x00e0,
     0x00e1,
     0x00e2,
     0xfffd,
     0x00e4,
     0x010b,
     0x0109,
     0x00e7,
     0x00e8,
     0x00e9,
     0x00ea,
     0x00eb,
     0x00ec,
     0x00ed,
     0x00ee,
     0x00ef,
     0xfffd,
     0x00f1,
     0x00f2,
     0x00f3,
     0x00f4,
     0x0121,
     0x00f6,
     0x00f7,
     0x011d,
     0x00f9,
     0x00fa,
     0x00fb,
     0x00fc,
     0x016d,
     0x015d,
     0x02d9,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\x04",
     "\x05",
     "\x06",
     "\x07",
     "\x08",
     "\x09",
     "\x0a",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\x14",
     "\x15",
     "\x16",
     "\x17",
     "\x18",
     "\x19",
     "\x1a",
     "\x1b",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\x20",
     "\x21",
     "\x22",
     "\x23",
     "\x24",
     "\x25",
     "\x26",
     "\x27",
     "\x28",
     "\x29",
     "\x2a",
     "\x2b",
     "\x2c",
     "\x2d",
     "\x2e",
     "\x2f",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\x3a",
     "\x3b",
     "\x3c",
     "\x3d",
     "\x3e",
     "\x3f",
     "\x40",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\x5b",
     "\x5c",
     "\x5d",
     "\x5e",
     "\x5f",
     "\x60",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\x7b",
     "\x7c",
     "\x7d",
     "\x7e",
     "\x7f",
     "\xc2\x80",
     "\xc2\x81",
     "\xc2\x82",
     "\xc2\x83",
     "\xc2\x84",
     "\xc2\x85",
     "\xc2\x86",
     "\xc2\x87",
     "\xc2\x88",
     "\xc2\x89",
     "\xc2\x8a",
     "\xc2\x8b",
     "\xc2\x8c",
     "\xc2\x8d",
     "\xc2\x8e",
     "\xc2\x8f",
     "\xc2\x90",
     "\xc2\x91",
     "\xc2\x92",
     "\xc2\x93",
     "\xc2\x94",
     "\xc2\x95",
     "\xc2\x96",
     "\xc2\x97",
     "\xc2\x98",
     "\xc2\x99",
     "\xc2\x9a",
     "\xc2\x9b",
     "\xc2\x9c",
     "\xc2\x9d",
     "\xc2\x9e",
     "\xc2\x9f",
     "\xc2\xa0",
     "\xc4\xa6",
     "\xcb\x98",
     "\xc2\xa3",
     "\xc2\xa4",
     "\xef\xbf\xbd",
     "\xc4\xa4",
     "\xc2\xa7",
     "\xc2\xa8",
     "\xc4\xb0",
     "\xc5\x9e",
     "\xc4\x9e",
     "\xc4\xb4",
     "\xc2\xad",
     "\xef\xbf\xbd",
     "\xc5\xbb",
     "\xc2\xb0",
     "\xc4\xa7",
     "\xc2\xb2",
     "\xc2\xb3",
     "\xc2\xb4",
     "\xc2\xb5",
     "\xc4\xa5",
     "\xc2\xb7",
     "\xc2\xb8",
     "\xc4\xb1",
     "\xc5\x9f",
     "\xc4\x9f",
     "\xc4\xb5",
     "\xc2\xbd",
     "\xef\xbf\xbd",
     "\xc5\xbc",
     "\xc3\x80",
     "\xc3\x81",
     "\xc3\x82",
     "\xef\xbf\xbd",
     "\xc3\x84",
     "\xc4\x8a",
     "\xc4\x88",
     "\xc3\x87",
     "\xc3\x88",
     "\xc3\x89",
     "\xc3\x8a",
     "\xc3\x8b",
     "\xc3\x8c",
     "\xc3\x8d",
     "\xc3\x8e",
     "\xc3\x8f",
     "\xef\xbf\xbd",
     "\xc3\x91",
     "\xc3\x92",
     "\xc3\x93",
     "\xc3\x94",
     "\xc4\xa0",
     "\xc3\x96",
     "\xc3\x97",
     "\xc4\x9c",
     "\xc3\x99",
     "\xc3\x9a",
     "\xc3\x9b",
     "\xc3\x9c",
     "\xc5\xac",
     "\xc5\x9c",
     "\xc3\x9f",
     "\xc3\xa0",
     "\xc3\xa1",
     "\xc3\xa2",
     "\xef\xbf\xbd",
     "\xc3\xa4",
     "\xc4\x8b",
     "\xc4\x89",
     "\xc3\xa7",
     "\xc3\xa8",
     "\xc3\xa9",
     "\xc3\xaa",
     "\xc3\xab",
     "\xc3\xac",
     "\xc3\xad",
     "\xc3\xae",
     "\xc3\xaf",
     "\xef\xbf\xbd",
     "\xc3\xb1",
     "\xc3\xb2",
     "\xc3\xb3",
     "\xc3\xb4",
     "\xc4\xa1",
     "\xc3\xb6",
     "\xc3\xb7",
     "\xc4\x9d",
     "\xc3\xb9",
     "\xc3\xba",
     "\xc3\xbb",
     "\xc3\xbc",
     "\xc5\xad",
     "\xc5\x9d",
     "\xcb\x99",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x04",
     0x00000005 => "\x05",
     0x00000006 => "\x06",
     0x00000007 => "\x07",
     0x00000008 => "\x08",
     0x00000009 => "\x09",
     0x0000000a => "\x0a",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x14",
     0x00000015 => "\x15",
     0x00000016 => "\x16",
     0x00000017 => "\x17",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x1a",
     0x0000001b => "\x1b",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x20",
     0x00000021 => "\x21",
     0x00000022 => "\x22",
     0x00000023 => "\x23",
     0x00000024 => "\x24",
     0x00000025 => "\x25",
     0x00000026 => "\x26",
     0x00000027 => "\x27",
     0x00000028 => "\x28",
     0x00000029 => "\x29",
     0x0000002a => "\x2a",
     0x0000002b => "\x2b",
     0x0000002c => "\x2c",
     0x0000002d => "\x2d",
     0x0000002e => "\x2e",
     0x0000002f => "\x2f",
     0x00000030 => "\x30",
     0x00000031 => "\x31",
     0x00000032 => "\x32",
     0x00000033 => "\x33",
     0x00000034 => "\x34",
     0x00000035 => "\x35",
     0x00000036 => "\x36",
     0x00000037 => "\x37",
     0x00000038 => "\x38",
     0x00000039 => "\x39",
     0x0000003a => "\x3a",
     0x0000003b => "\x3b",
     0x0000003c => "\x3c",
     0x0000003d => "\x3d",
     0x0000003e => "\x3e",
     0x0000003f => "\x3f",
     0x00000040 => "\x40",
     0x00000041 => "\x41",
     0x00000042 => "\x42",
     0x00000043 => "\x43",
     0x00000044 => "\x44",
     0x00000045 => "\x45",
     0x00000046 => "\x46",
     0x00000047 => "\x47",
     0x00000048 => "\x48",
     0x00000049 => "\x49",
     0x0000004a => "\x4a",
     0x0000004b => "\x4b",
     0x0000004c => "\x4c",
     0x0000004d => "\x4d",
     0x0000004e => "\x4e",
     0x0000004f => "\x4f",
     0x00000050 => "\x50",
     0x00000051 => "\x51",
     0x00000052 => "\x52",
     0x00000053 => "\x53",
     0x00000054 => "\x54",
     0x00000055 => "\x55",
     0x00000056 => "\x56",
     0x00000057 => "\x57",
     0x00000058 => "\x58",
     0x00000059 => "\x59",
     0x0000005a => "\x5a",
     0x0000005b => "\x5b",
     0x0000005c => "\x5c",
     0x0000005d => "\x5d",
     0x0000005e => "\x5e",
     0x0000005f => "\x5f",
     0x00000060 => "\x60",
     0x00000061 => "\x61",
     0x00000062 => "\x62",
     0x00000063 => "\x63",
     0x00000064 => "\x64",
     0x00000065 => "\x65",
     0x00000066 => "\x66",
     0x00000067 => "\x67",
     0x00000068 => "\x68",
     0x00000069 => "\x69",
     0x0000006a => "\x6a",
     0x0000006b => "\x6b",
     0x0000006c => "\x6c",
     0x0000006d => "\x6d",
     0x0000006e => "\x6e",
     0x0000006f => "\x6f",
     0x00000070 => "\x70",
     0x00000071 => "\x71",
     0x00000072 => "\x72",
     0x00000073 => "\x73",
     0x00000074 => "\x74",
     0x00000075 => "\x75",
     0x00000076 => "\x76",
     0x00000077 => "\x77",
     0x00000078 => "\x78",
     0x00000079 => "\x79",
     0x0000007a => "\x7a",
     0x0000007b => "\x7b",
     0x0000007c => "\x7c",
     0x0000007d => "\x7d",
     0x0000007e => "\x7e",
     0x0000007f => "\x7f",
     0x00000080 => "\x80",
     0x00000081 => "\x81",
     0x00000082 => "\x82",
     0x00000083 => "\x83",
     0x00000084 => "\x84",
     0x00000085 => "\x85",
     0x00000086 => "\x86",
     0x00000087 => "\x87",
     0x00000088 => "\x88",
     0x00000089 => "\x89",
     0x0000008a => "\x8a",
     0x0000008b => "\x8b",
     0x0000008c => "\x8c",
     0x0000008d => "\x8d",
     0x0000008e => "\x8e",
     0x0000008f => "\x8f",
     0x00000090 => "\x90",
     0x00000091 => "\x91",
     0x00000092 => "\x92",
     0x00000093 => "\x93",
     0x00000094 => "\x94",
     0x00000095 => "\x95",
     0x00000096 => "\x96",
     0x00000097 => "\x97",
     0x00000098 => "\x98",
     0x00000099 => "\x99",
     0x0000009a => "\x9a",
     0x0000009b => "\x9b",
     0x0000009c => "\x9c",
     0x0000009d => "\x9d",
     0x0000009e => "\x9e",
     0x0000009f => "\x9f",
     0x000000a0 => "\xa0",
     0x000000a3 => "\xa3",
     0x000000a4 => "\xa4",
     0x000000a7 => "\xa7",
     0x000000a8 => "\xa8",
     0x000000ad => "\xad",
     0x000000b0 => "\xb0",
     0x000000b2 => "\xb2",
     0x000000b3 => "\xb3",
     0x000000b4 => "\xb4",
     0x000000b5 => "\xb5",
     0x000000b7 => "\xb7",
     0x000000b8 => "\xb8",
     0x000000bd => "\xbd",
     0x000000c0 => "\xc0",
     0x000000c1 => "\xc1",
     0x000000c2 => "\xc2",
     0x000000c4 => "\xc4",
     0x000000c7 => "\xc7",
     0x000000c8 => "\xc8",
     0x000000c9 => "\xc9",
     0x000000ca => "\xca",
     0x000000cb => "\xcb",
     0x000000cc => "\xcc",
     0x000000cd => "\xcd",
     0x000000ce => "\xce",
     0x000000cf => "\xcf",
     0x000000d1 => "\xd1",
     0x000000d2 => "\xd2",
     0x000000d3 => "\xd3",
     0x000000d4 => "\xd4",
     0x000000d6 => "\xd6",
     0x000000d7 => "\xd7",
     0x000000d9 => "\xd9",
     0x000000da => "\xda",
     0x000000db => "\xdb",
     0x000000dc => "\xdc",
     0x000000df => "\xdf",
     0x000000e0 => "\xe0",
     0x000000e1 => "\xe1",
     0x000000e2 => "\xe2",
     0x000000e4 => "\xe4",
     0x000000e7 => "\xe7",
     0x000000e8 => "\xe8",
     0x000000e9 => "\xe9",
     0x000000ea => "\xea",
     0x000000eb => "\xeb",
     0x000000ec => "\xec",
     0x000000ed => "\xed",
     0x000000ee => "\xee",
     0x000000ef => "\xef",
     0x000000f1 => "\xf1",
     0x000000f2 => "\xf2",
     0x000000f3 => "\xf3",
     0x000000f4 => "\xf4",
     0x000000f6 => "\xf6",
     0x000000f7 => "\xf7",
     0x000000f9 => "\xf9",
     0x000000fa => "\xfa",
     0x000000fb => "\xfb",
     0x000000fc => "\xfc",
     0x00000108 => "\xc6",
     0x00000109 => "\xe6",
     0x0000010a => "\xc5",
     0x0000010b => "\xe5",
     0x0000011c => "\xd8",
     0x0000011d => "\xf8",
     0x0000011e => "\xab",
     0x0000011f => "\xbb",
     0x00000120 => "\xd5",
     0x00000121 => "\xf5",
     0x00000124 => "\xa6",
     0x00000125 => "\xb6",
     0x00000126 => "\xa1",
     0x00000127 => "\xb1",
     0x00000130 => "\xa9",
     0x00000131 => "\xb9",
     0x00000134 => "\xac",
     0x00000135 => "\xbc",
     0x0000015c => "\xde",
     0x0000015d => "\xfe",
     0x0000015e => "\xaa",
     0x0000015f => "\xba",
     0x0000016c => "\xdd",
     0x0000016d => "\xfd",
     0x0000017b => "\xaf",
     0x0000017c => "\xbf",
     0x000002d8 => "\xa2",
     0x000002d9 => "\xff",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::ISO_8859_3 - Conversion routines for ISO-8859-3
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for ISO-8859-3.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
   source: ECMA registry
  alias ISO-IR-109
  alias ISO_8859-3:1988
  alias ISO_8859-3
  alias LATIN3
  alias L3
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  00000004 | END OF TRANSMISSION (EOT)
     05 |  00000005 | ENQUIRY (ENQ)
     06 |  00000006 | ACKNOWLEDGE (ACK)
     07 |  00000007 | BELL (BEL)
     08 |  00000008 | BACKSPACE (BS)
     09 |  00000009 | CHARACTER TABULATION (HT)
     0A |  0000000A | LINE FEED (LF)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  00000014 | DEVICE CONTROL FOUR (DC4)
     15 |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     16 |  00000016 | SYNCHRONOUS IDLE (SYN)
     17 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  0000001A | SUBSTITUTE (SUB)
     1B |  0000001B | ESCAPE (ESC)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000020 | SPACE
     21 |  00000021 | EXCLAMATION MARK
     22 |  00000022 | QUOTATION MARK
     23 |  00000023 | NUMBER SIGN
     24 |  00000024 | DOLLAR SIGN
     25 |  00000025 | PERCENT SIGN
     26 |  00000026 | AMPERSAND
     27 |  00000027 | APOSTROPHE
     28 |  00000028 | LEFT PARENTHESIS
     29 |  00000029 | RIGHT PARENTHESIS
     2A |  0000002A | ASTERISK
     2B |  0000002B | PLUS SIGN
     2C |  0000002C | COMMA
     2D |  0000002D | HYPHEN-MINUS
     2E |  0000002E | FULL STOP
     2F |  0000002F | SOLIDUS
     30 |  00000030 | DIGIT ZERO
     31 |  00000031 | DIGIT ONE
     32 |  00000032 | DIGIT TWO
     33 |  00000033 | DIGIT THREE
     34 |  00000034 | DIGIT FOUR
     35 |  00000035 | DIGIT FIVE
     36 |  00000036 | DIGIT SIX
     37 |  00000037 | DIGIT SEVEN
     38 |  00000038 | DIGIT EIGHT
     39 |  00000039 | DIGIT NINE
     3A |  0000003A | COLON
     3B |  0000003B | SEMICOLON
     3C |  0000003C | LESS-THAN SIGN
     3D |  0000003D | EQUALS SIGN
     3E |  0000003E | GREATER-THAN SIGN
     3F |  0000003F | QUESTION MARK
     40 |  00000040 | COMMERCIAL AT
     41 |  00000041 | LATIN CAPITAL LETTER A
     42 |  00000042 | LATIN CAPITAL LETTER B
     43 |  00000043 | LATIN CAPITAL LETTER C
     44 |  00000044 | LATIN CAPITAL LETTER D
     45 |  00000045 | LATIN CAPITAL LETTER E
     46 |  00000046 | LATIN CAPITAL LETTER F
     47 |  00000047 | LATIN CAPITAL LETTER G
     48 |  00000048 | LATIN CAPITAL LETTER H
     49 |  00000049 | LATIN CAPITAL LETTER I
     4A |  0000004A | LATIN CAPITAL LETTER J
     4B |  0000004B | LATIN CAPITAL LETTER K
     4C |  0000004C | LATIN CAPITAL LETTER L
     4D |  0000004D | LATIN CAPITAL LETTER M
     4E |  0000004E | LATIN CAPITAL LETTER N
     4F |  0000004F | LATIN CAPITAL LETTER O
     50 |  00000050 | LATIN CAPITAL LETTER P
     51 |  00000051 | LATIN CAPITAL LETTER Q
     52 |  00000052 | LATIN CAPITAL LETTER R
     53 |  00000053 | LATIN CAPITAL LETTER S
     54 |  00000054 | LATIN CAPITAL LETTER T
     55 |  00000055 | LATIN CAPITAL LETTER U
     56 |  00000056 | LATIN CAPITAL LETTER V
     57 |  00000057 | LATIN CAPITAL LETTER W
     58 |  00000058 | LATIN CAPITAL LETTER X
     59 |  00000059 | LATIN CAPITAL LETTER Y
     5A |  0000005A | LATIN CAPITAL LETTER Z
     5B |  0000005B | LEFT SQUARE BRACKET
     5C |  0000005C | REVERSE SOLIDUS
     5D |  0000005D | RIGHT SQUARE BRACKET
     5E |  0000005E | CIRCUMFLEX ACCENT
     5F |  0000005F | LOW LINE
     60 |  00000060 | GRAVE ACCENT
     61 |  00000061 | LATIN SMALL LETTER A
     62 |  00000062 | LATIN SMALL LETTER B
     63 |  00000063 | LATIN SMALL LETTER C
     64 |  00000064 | LATIN SMALL LETTER D
     65 |  00000065 | LATIN SMALL LETTER E
     66 |  00000066 | LATIN SMALL LETTER F
     67 |  00000067 | LATIN SMALL LETTER G
     68 |  00000068 | LATIN SMALL LETTER H
     69 |  00000069 | LATIN SMALL LETTER I
     6A |  0000006A | LATIN SMALL LETTER J
     6B |  0000006B | LATIN SMALL LETTER K
     6C |  0000006C | LATIN SMALL LETTER L
     6D |  0000006D | LATIN SMALL LETTER M
     6E |  0000006E | LATIN SMALL LETTER N
     6F |  0000006F | LATIN SMALL LETTER O
     70 |  00000070 | LATIN SMALL LETTER P
     71 |  00000071 | LATIN SMALL LETTER Q
     72 |  00000072 | LATIN SMALL LETTER R
     73 |  00000073 | LATIN SMALL LETTER S
     74 |  00000074 | LATIN SMALL LETTER T
     75 |  00000075 | LATIN SMALL LETTER U
     76 |  00000076 | LATIN SMALL LETTER V
     77 |  00000077 | LATIN SMALL LETTER W
     78 |  00000078 | LATIN SMALL LETTER X
     79 |  00000079 | LATIN SMALL LETTER Y
     7A |  0000007A | LATIN SMALL LETTER Z
     7B |  0000007B | LEFT CURLY BRACKET
     7C |  0000007C | VERTICAL LINE
     7D |  0000007D | RIGHT CURLY BRACKET
     7E |  0000007E | TILDE
     7F |  0000007F | DELETE (DEL)
     80 |  00000080 | PADDING CHARACTER (PAD)
     81 |  00000081 | HIGH OCTET PRESET (HOP)
     82 |  00000082 | BREAK PERMITTED HERE (BPH)
     83 |  00000083 | NO BREAK HERE (NBH)
     84 |  00000084 | INDEX (IND)
     85 |  00000085 | NEXT LINE (NEL)
     86 |  00000086 | START OF SELECTED AREA (SSA)
     87 |  00000087 | END OF SELECTED AREA (ESA)
     88 |  00000088 | CHARACTER TABULATION SET (HTS)
     89 |  00000089 | CHARACTER TABULATION WITH JUSTIFICATION (HTJ)
     8A |  0000008A | LINE TABULATION SET (VTS)
     8B |  0000008B | PARTIAL LINE FORWARD (PLD)
     8C |  0000008C | PARTIAL LINE BACKWARD (PLU)
     8D |  0000008D | REVERSE LINE FEED (RI)
     8E |  0000008E | SINGLE-SHIFT TWO (SS2)
     8F |  0000008F | SINGLE-SHIFT THREE (SS3)
     90 |  00000090 | DEVICE CONTROL STRING (DCS)
     91 |  00000091 | PRIVATE USE ONE (PU1)
     92 |  00000092 | PRIVATE USE TWO (PU2)
     93 |  00000093 | SET TRANSMIT STATE (STS)
     94 |  00000094 | CANCEL CHARACTER (CCH)
     95 |  00000095 | MESSAGE WAITING (MW)
     96 |  00000096 | START OF GUARDED AREA (SPA)
     97 |  00000097 | END OF GUARDED AREA (EPA)
     98 |  00000098 | START OF STRING (SOS)
     99 |  00000099 | SINGLE GRAPHIC CHARACTER INTRODUCER (SGCI)
     9A |  0000009A | SINGLE CHARACTER INTRODUCER (SCI)
     9B |  0000009B | CONTROL SEQUENCE INTRODUCER (CSI)
     9C |  0000009C | STRING TERMINATOR (ST)
     9D |  0000009D | OPERATING SYSTEM COMMAND (OSC)
     9E |  0000009E | PRIVACY MESSAGE (PM)
     9F |  0000009F | APPLICATION PROGRAM COMMAND (APC)
     A0 |  000000A0 | NO-BREAK SPACE
     A1 |  00000126 | LATIN CAPITAL LETTER H WITH STROKE
     A2 |  000002D8 | BREVE
     A3 |  000000A3 | POUND SIGN
     A4 |  000000A4 | CURRENCY SIGN
     A6 |  00000124 | LATIN CAPITAL LETTER H WITH CIRCUMFLEX
     A7 |  000000A7 | SECTION SIGN
     A8 |  000000A8 | DIAERESIS
     A9 |  00000130 | LATIN CAPITAL LETTER I WITH DOT ABOVE
     AA |  0000015E | LATIN CAPITAL LETTER S WITH CEDILLA
     AB |  0000011E | LATIN CAPITAL LETTER G WITH BREVE
     AC |  00000134 | LATIN CAPITAL LETTER J WITH CIRCUMFLEX
     AD |  000000AD | SOFT HYPHEN
     AF |  0000017B | LATIN CAPITAL LETTER Z WITH DOT ABOVE
     B0 |  000000B0 | DEGREE SIGN
     B1 |  00000127 | LATIN SMALL LETTER H WITH STROKE
     B2 |  000000B2 | SUPERSCRIPT TWO
     B3 |  000000B3 | SUPERSCRIPT THREE
     B4 |  000000B4 | ACUTE ACCENT
     B5 |  000000B5 | MICRO SIGN
     B6 |  00000125 | LATIN SMALL LETTER H WITH CIRCUMFLEX
     B7 |  000000B7 | MIDDLE DOT
     B8 |  000000B8 | CEDILLA
     B9 |  00000131 | LATIN SMALL LETTER DOTLESS I
     BA |  0000015F | LATIN SMALL LETTER S WITH CEDILLA
     BB |  0000011F | LATIN SMALL LETTER G WITH BREVE
     BC |  00000135 | LATIN SMALL LETTER J WITH CIRCUMFLEX
     BD |  000000BD | VULGAR FRACTION ONE HALF
     BF |  0000017C | LATIN SMALL LETTER Z WITH DOT ABOVE
     C0 |  000000C0 | LATIN CAPITAL LETTER A WITH GRAVE
     C1 |  000000C1 | LATIN CAPITAL LETTER A WITH ACUTE
     C2 |  000000C2 | LATIN CAPITAL LETTER A WITH CIRCUMFLEX
     C4 |  000000C4 | LATIN CAPITAL LETTER A WITH DIAERESIS
     C5 |  0000010A | LATIN CAPITAL LETTER C WITH DOT ABOVE
     C6 |  00000108 | LATIN CAPITAL LETTER C WITH CIRCUMFLEX
     C7 |  000000C7 | LATIN CAPITAL LETTER C WITH CEDILLA
     C8 |  000000C8 | LATIN CAPITAL LETTER E WITH GRAVE
     C9 |  000000C9 | LATIN CAPITAL LETTER E WITH ACUTE
     CA |  000000CA | LATIN CAPITAL LETTER E WITH CIRCUMFLEX
     CB |  000000CB | LATIN CAPITAL LETTER E WITH DIAERESIS
     CC |  000000CC | LATIN CAPITAL LETTER I WITH GRAVE
     CD |  000000CD | LATIN CAPITAL LETTER I WITH ACUTE
     CE |  000000CE | LATIN CAPITAL LETTER I WITH CIRCUMFLEX
     CF |  000000CF | LATIN CAPITAL LETTER I WITH DIAERESIS
     D1 |  000000D1 | LATIN CAPITAL LETTER N WITH TILDE
     D2 |  000000D2 | LATIN CAPITAL LETTER O WITH GRAVE
     D3 |  000000D3 | LATIN CAPITAL LETTER O WITH ACUTE
     D4 |  000000D4 | LATIN CAPITAL LETTER O WITH CIRCUMFLEX
     D5 |  00000120 | LATIN CAPITAL LETTER G WITH DOT ABOVE
     D6 |  000000D6 | LATIN CAPITAL LETTER O WITH DIAERESIS
     D7 |  000000D7 | MULTIPLICATION SIGN
     D8 |  0000011C | LATIN CAPITAL LETTER G WITH CIRCUMFLEX
     D9 |  000000D9 | LATIN CAPITAL LETTER U WITH GRAVE
     DA |  000000DA | LATIN CAPITAL LETTER U WITH ACUTE
     DB |  000000DB | LATIN CAPITAL LETTER U WITH CIRCUMFLEX
     DC |  000000DC | LATIN CAPITAL LETTER U WITH DIAERESIS
     DD |  0000016C | LATIN CAPITAL LETTER U WITH BREVE
     DE |  0000015C | LATIN CAPITAL LETTER S WITH CIRCUMFLEX
     DF |  000000DF | LATIN SMALL LETTER SHARP S (German)
     E0 |  000000E0 | LATIN SMALL LETTER A WITH GRAVE
     E1 |  000000E1 | LATIN SMALL LETTER A WITH ACUTE
     E2 |  000000E2 | LATIN SMALL LETTER A WITH CIRCUMFLEX
     E4 |  000000E4 | LATIN SMALL LETTER A WITH DIAERESIS
     E5 |  0000010B | LATIN SMALL LETTER C WITH DOT ABOVE
     E6 |  00000109 | LATIN SMALL LETTER C WITH CIRCUMFLEX
     E7 |  000000E7 | LATIN SMALL LETTER C WITH CEDILLA
     E8 |  000000E8 | LATIN SMALL LETTER E WITH GRAVE
     E9 |  000000E9 | LATIN SMALL LETTER E WITH ACUTE
     EA |  000000EA | LATIN SMALL LETTER E WITH CIRCUMFLEX
     EB |  000000EB | LATIN SMALL LETTER E WITH DIAERESIS
     EC |  000000EC | LATIN SMALL LETTER I WITH GRAVE
     ED |  000000ED | LATIN SMALL LETTER I WITH ACUTE
     EE |  000000EE | LATIN SMALL LETTER I WITH CIRCUMFLEX
     EF |  000000EF | LATIN SMALL LETTER I WITH DIAERESIS
     F1 |  000000F1 | LATIN SMALL LETTER N WITH TILDE
     F2 |  000000F2 | LATIN SMALL LETTER O WITH GRAVE
     F3 |  000000F3 | LATIN SMALL LETTER O WITH ACUTE
     F4 |  000000F4 | LATIN SMALL LETTER O WITH CIRCUMFLEX
     F5 |  00000121 | LATIN SMALL LETTER G WITH DOT ABOVE
     F6 |  000000F6 | LATIN SMALL LETTER O WITH DIAERESIS
     F7 |  000000F7 | DIVISION SIGN
     F8 |  0000011D | LATIN SMALL LETTER G WITH CIRCUMFLEX
     F9 |  000000F9 | LATIN SMALL LETTER U WITH GRAVE
     FA |  000000FA | LATIN SMALL LETTER U WITH ACUTE
     FB |  000000FB | LATIN SMALL LETTER U WITH CIRCUMFLEX
     FC |  000000FC | LATIN SMALL LETTER U WITH DIAERESIS
     FD |  0000016D | LATIN SMALL LETTER U WITH BREVE
     FE |  0000015D | LATIN SMALL LETTER S WITH CIRCUMFLEX
     FF |  000002D9 | DOT ABOVE (Mandarin Chinese light tone)
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/ISO_8859_4.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for ISO-8859-4.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::ISO_8859_4;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x0004,
     0x0005,
     0x0006,
     0x0007,
     0x0008,
     0x0009,
     0x000a,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x0014,
     0x0015,
     0x0016,
     0x0017,
     0x0018,
     0x0019,
     0x001a,
     0x001b,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0020,
     0x0021,
     0x0022,
     0x0023,
     0x0024,
     0x0025,
     0x0026,
     0x0027,
     0x0028,
     0x0029,
     0x002a,
     0x002b,
     0x002c,
     0x002d,
     0x002e,
     0x002f,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x003a,
     0x003b,
     0x003c,
     0x003d,
     0x003e,
     0x003f,
     0x0040,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x005b,
     0x005c,
     0x005d,
     0x005e,
     0x005f,
     0x0060,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x007b,
     0x007c,
     0x007d,
     0x007e,
     0x007f,
     0x0080,
     0x0081,
     0x0082,
     0x0083,
     0x0084,
     0x0085,
     0x0086,
     0x0087,
     0x0088,
     0x0089,
     0x008a,
     0x008b,
     0x008c,
     0x008d,
     0x008e,
     0x008f,
     0x0090,
     0x0091,
     0x0092,
     0x0093,
     0x0094,
     0x0095,
     0x0096,
     0x0097,
     0x0098,
     0x0099,
     0x009a,
     0x009b,
     0x009c,
     0x009d,
     0x009e,
     0x009f,
     0x00a0,
     0x0104,
     0x0138,
     0x0156,
     0x00a4,
     0x0128,
     0x013b,
     0x00a7,
     0x00a8,
     0x0160,
     0x0112,
     0x0122,
     0x0166,
     0x00ad,
     0x017d,
     0x00af,
     0x00b0,
     0x0105,
     0x02db,
     0x0157,
     0x00b4,
     0x0129,
     0x013c,
     0x02c7,
     0x00b8,
     0x0161,
     0x0113,
     0x0123,
     0x0167,
     0x014a,
     0x017e,
     0x014b,
     0x0100,
     0x00c1,
     0x00c2,
     0x00c3,
     0x00c4,
     0x00c5,
     0x00c6,
     0x012e,
     0x010c,
     0x00c9,
     0x0118,
     0x00cb,
     0x0116,
     0x00cd,
     0x00ce,
     0x012a,
     0x0110,
     0x0145,
     0x014c,
     0x0136,
     0x00d4,
     0x00d5,
     0x00d6,
     0x00d7,
     0x00d8,
     0x0172,
     0x00da,
     0x00db,
     0x00dc,
     0x0168,
     0x016a,
     0x00df,
     0x0101,
     0x00e1,
     0x00e2,
     0x00e3,
     0x00e4,
     0x00e5,
     0x00e6,
     0x012f,
     0x010d,
     0x00e9,
     0x0119,
     0x00eb,
     0x0117,
     0x00ed,
     0x00ee,
     0x012b,
     0x0111,
     0x0146,
     0x014d,
     0x0137,
     0x00f4,
     0x00f5,
     0x00f6,
     0x00f7,
     0x00f8,
     0x0173,
     0x00fa,
     0x00fb,
     0x00fc,
     0x0169,
     0x016b,
     0x02d9,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\x04",
     "\x05",
     "\x06",
     "\x07",
     "\x08",
     "\x09",
     "\x0a",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\x14",
     "\x15",
     "\x16",
     "\x17",
     "\x18",
     "\x19",
     "\x1a",
     "\x1b",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\x20",
     "\x21",
     "\x22",
     "\x23",
     "\x24",
     "\x25",
     "\x26",
     "\x27",
     "\x28",
     "\x29",
     "\x2a",
     "\x2b",
     "\x2c",
     "\x2d",
     "\x2e",
     "\x2f",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\x3a",
     "\x3b",
     "\x3c",
     "\x3d",
     "\x3e",
     "\x3f",
     "\x40",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\x5b",
     "\x5c",
     "\x5d",
     "\x5e",
     "\x5f",
     "\x60",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\x7b",
     "\x7c",
     "\x7d",
     "\x7e",
     "\x7f",
     "\xc2\x80",
     "\xc2\x81",
     "\xc2\x82",
     "\xc2\x83",
     "\xc2\x84",
     "\xc2\x85",
     "\xc2\x86",
     "\xc2\x87",
     "\xc2\x88",
     "\xc2\x89",
     "\xc2\x8a",
     "\xc2\x8b",
     "\xc2\x8c",
     "\xc2\x8d",
     "\xc2\x8e",
     "\xc2\x8f",
     "\xc2\x90",
     "\xc2\x91",
     "\xc2\x92",
     "\xc2\x93",
     "\xc2\x94",
     "\xc2\x95",
     "\xc2\x96",
     "\xc2\x97",
     "\xc2\x98",
     "\xc2\x99",
     "\xc2\x9a",
     "\xc2\x9b",
     "\xc2\x9c",
     "\xc2\x9d",
     "\xc2\x9e",
     "\xc2\x9f",
     "\xc2\xa0",
     "\xc4\x84",
     "\xc4\xb8",
     "\xc5\x96",
     "\xc2\xa4",
     "\xc4\xa8",
     "\xc4\xbb",
     "\xc2\xa7",
     "\xc2\xa8",
     "\xc5\xa0",
     "\xc4\x92",
     "\xc4\xa2",
     "\xc5\xa6",
     "\xc2\xad",
     "\xc5\xbd",
     "\xc2\xaf",
     "\xc2\xb0",
     "\xc4\x85",
     "\xcb\x9b",
     "\xc5\x97",
     "\xc2\xb4",
     "\xc4\xa9",
     "\xc4\xbc",
     "\xcb\x87",
     "\xc2\xb8",
     "\xc5\xa1",
     "\xc4\x93",
     "\xc4\xa3",
     "\xc5\xa7",
     "\xc5\x8a",
     "\xc5\xbe",
     "\xc5\x8b",
     "\xc4\x80",
     "\xc3\x81",
     "\xc3\x82",
     "\xc3\x83",
     "\xc3\x84",
     "\xc3\x85",
     "\xc3\x86",
     "\xc4\xae",
     "\xc4\x8c",
     "\xc3\x89",
     "\xc4\x98",
     "\xc3\x8b",
     "\xc4\x96",
     "\xc3\x8d",
     "\xc3\x8e",
     "\xc4\xaa",
     "\xc4\x90",
     "\xc5\x85",
     "\xc5\x8c",
     "\xc4\xb6",
     "\xc3\x94",
     "\xc3\x95",
     "\xc3\x96",
     "\xc3\x97",
     "\xc3\x98",
     "\xc5\xb2",
     "\xc3\x9a",
     "\xc3\x9b",
     "\xc3\x9c",
     "\xc5\xa8",
     "\xc5\xaa",
     "\xc3\x9f",
     "\xc4\x81",
     "\xc3\xa1",
     "\xc3\xa2",
     "\xc3\xa3",
     "\xc3\xa4",
     "\xc3\xa5",
     "\xc3\xa6",
     "\xc4\xaf",
     "\xc4\x8d",
     "\xc3\xa9",
     "\xc4\x99",
     "\xc3\xab",
     "\xc4\x97",
     "\xc3\xad",
     "\xc3\xae",
     "\xc4\xab",
     "\xc4\x91",
     "\xc5\x86",
     "\xc5\x8d",
     "\xc4\xb7",
     "\xc3\xb4",
     "\xc3\xb5",
     "\xc3\xb6",
     "\xc3\xb7",
     "\xc3\xb8",
     "\xc5\xb3",
     "\xc3\xba",
     "\xc3\xbb",
     "\xc3\xbc",
     "\xc5\xa9",
     "\xc5\xab",
     "\xcb\x99",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x04",
     0x00000005 => "\x05",
     0x00000006 => "\x06",
     0x00000007 => "\x07",
     0x00000008 => "\x08",
     0x00000009 => "\x09",
     0x0000000a => "\x0a",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x14",
     0x00000015 => "\x15",
     0x00000016 => "\x16",
     0x00000017 => "\x17",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x1a",
     0x0000001b => "\x1b",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x20",
     0x00000021 => "\x21",
     0x00000022 => "\x22",
     0x00000023 => "\x23",
     0x00000024 => "\x24",
     0x00000025 => "\x25",
     0x00000026 => "\x26",
     0x00000027 => "\x27",
     0x00000028 => "\x28",
     0x00000029 => "\x29",
     0x0000002a => "\x2a",
     0x0000002b => "\x2b",
     0x0000002c => "\x2c",
     0x0000002d => "\x2d",
     0x0000002e => "\x2e",
     0x0000002f => "\x2f",
     0x00000030 => "\x30",
     0x00000031 => "\x31",
     0x00000032 => "\x32",
     0x00000033 => "\x33",
     0x00000034 => "\x34",
     0x00000035 => "\x35",
     0x00000036 => "\x36",
     0x00000037 => "\x37",
     0x00000038 => "\x38",
     0x00000039 => "\x39",
     0x0000003a => "\x3a",
     0x0000003b => "\x3b",
     0x0000003c => "\x3c",
     0x0000003d => "\x3d",
     0x0000003e => "\x3e",
     0x0000003f => "\x3f",
     0x00000040 => "\x40",
     0x00000041 => "\x41",
     0x00000042 => "\x42",
     0x00000043 => "\x43",
     0x00000044 => "\x44",
     0x00000045 => "\x45",
     0x00000046 => "\x46",
     0x00000047 => "\x47",
     0x00000048 => "\x48",
     0x00000049 => "\x49",
     0x0000004a => "\x4a",
     0x0000004b => "\x4b",
     0x0000004c => "\x4c",
     0x0000004d => "\x4d",
     0x0000004e => "\x4e",
     0x0000004f => "\x4f",
     0x00000050 => "\x50",
     0x00000051 => "\x51",
     0x00000052 => "\x52",
     0x00000053 => "\x53",
     0x00000054 => "\x54",
     0x00000055 => "\x55",
     0x00000056 => "\x56",
     0x00000057 => "\x57",
     0x00000058 => "\x58",
     0x00000059 => "\x59",
     0x0000005a => "\x5a",
     0x0000005b => "\x5b",
     0x0000005c => "\x5c",
     0x0000005d => "\x5d",
     0x0000005e => "\x5e",
     0x0000005f => "\x5f",
     0x00000060 => "\x60",
     0x00000061 => "\x61",
     0x00000062 => "\x62",
     0x00000063 => "\x63",
     0x00000064 => "\x64",
     0x00000065 => "\x65",
     0x00000066 => "\x66",
     0x00000067 => "\x67",
     0x00000068 => "\x68",
     0x00000069 => "\x69",
     0x0000006a => "\x6a",
     0x0000006b => "\x6b",
     0x0000006c => "\x6c",
     0x0000006d => "\x6d",
     0x0000006e => "\x6e",
     0x0000006f => "\x6f",
     0x00000070 => "\x70",
     0x00000071 => "\x71",
     0x00000072 => "\x72",
     0x00000073 => "\x73",
     0x00000074 => "\x74",
     0x00000075 => "\x75",
     0x00000076 => "\x76",
     0x00000077 => "\x77",
     0x00000078 => "\x78",
     0x00000079 => "\x79",
     0x0000007a => "\x7a",
     0x0000007b => "\x7b",
     0x0000007c => "\x7c",
     0x0000007d => "\x7d",
     0x0000007e => "\x7e",
     0x0000007f => "\x7f",
     0x00000080 => "\x80",
     0x00000081 => "\x81",
     0x00000082 => "\x82",
     0x00000083 => "\x83",
     0x00000084 => "\x84",
     0x00000085 => "\x85",
     0x00000086 => "\x86",
     0x00000087 => "\x87",
     0x00000088 => "\x88",
     0x00000089 => "\x89",
     0x0000008a => "\x8a",
     0x0000008b => "\x8b",
     0x0000008c => "\x8c",
     0x0000008d => "\x8d",
     0x0000008e => "\x8e",
     0x0000008f => "\x8f",
     0x00000090 => "\x90",
     0x00000091 => "\x91",
     0x00000092 => "\x92",
     0x00000093 => "\x93",
     0x00000094 => "\x94",
     0x00000095 => "\x95",
     0x00000096 => "\x96",
     0x00000097 => "\x97",
     0x00000098 => "\x98",
     0x00000099 => "\x99",
     0x0000009a => "\x9a",
     0x0000009b => "\x9b",
     0x0000009c => "\x9c",
     0x0000009d => "\x9d",
     0x0000009e => "\x9e",
     0x0000009f => "\x9f",
     0x000000a0 => "\xa0",
     0x000000a4 => "\xa4",
     0x000000a7 => "\xa7",
     0x000000a8 => "\xa8",
     0x000000ad => "\xad",
     0x000000af => "\xaf",
     0x000000b0 => "\xb0",
     0x000000b4 => "\xb4",
     0x000000b8 => "\xb8",
     0x000000c1 => "\xc1",
     0x000000c2 => "\xc2",
     0x000000c3 => "\xc3",
     0x000000c4 => "\xc4",
     0x000000c5 => "\xc5",
     0x000000c6 => "\xc6",
     0x000000c9 => "\xc9",
     0x000000cb => "\xcb",
     0x000000cd => "\xcd",
     0x000000ce => "\xce",
     0x000000d4 => "\xd4",
     0x000000d5 => "\xd5",
     0x000000d6 => "\xd6",
     0x000000d7 => "\xd7",
     0x000000d8 => "\xd8",
     0x000000da => "\xda",
     0x000000db => "\xdb",
     0x000000dc => "\xdc",
     0x000000df => "\xdf",
     0x000000e1 => "\xe1",
     0x000000e2 => "\xe2",
     0x000000e3 => "\xe3",
     0x000000e4 => "\xe4",
     0x000000e5 => "\xe5",
     0x000000e6 => "\xe6",
     0x000000e9 => "\xe9",
     0x000000eb => "\xeb",
     0x000000ed => "\xed",
     0x000000ee => "\xee",
     0x000000f4 => "\xf4",
     0x000000f5 => "\xf5",
     0x000000f6 => "\xf6",
     0x000000f7 => "\xf7",
     0x000000f8 => "\xf8",
     0x000000fa => "\xfa",
     0x000000fb => "\xfb",
     0x000000fc => "\xfc",
     0x00000100 => "\xc0",
     0x00000101 => "\xe0",
     0x00000104 => "\xa1",
     0x00000105 => "\xb1",
     0x0000010c => "\xc8",
     0x0000010d => "\xe8",
     0x00000110 => "\xd0",
     0x00000111 => "\xf0",
     0x00000112 => "\xaa",
     0x00000113 => "\xba",
     0x00000116 => "\xcc",
     0x00000117 => "\xec",
     0x00000118 => "\xca",
     0x00000119 => "\xea",
     0x00000122 => "\xab",
     0x00000123 => "\xbb",
     0x00000128 => "\xa5",
     0x00000129 => "\xb5",
     0x0000012a => "\xcf",
     0x0000012b => "\xef",
     0x0000012e => "\xc7",
     0x0000012f => "\xe7",
     0x00000136 => "\xd3",
     0x00000137 => "\xf3",
     0x00000138 => "\xa2",
     0x0000013b => "\xa6",
     0x0000013c => "\xb6",
     0x00000145 => "\xd1",
     0x00000146 => "\xf1",
     0x0000014a => "\xbd",
     0x0000014b => "\xbf",
     0x0000014c => "\xd2",
     0x0000014d => "\xf2",
     0x00000156 => "\xa3",
     0x00000157 => "\xb3",
     0x00000160 => "\xa9",
     0x00000161 => "\xb9",
     0x00000166 => "\xac",
     0x00000167 => "\xbc",
     0x00000168 => "\xdd",
     0x00000169 => "\xfd",
     0x0000016a => "\xde",
     0x0000016b => "\xfe",
     0x00000172 => "\xd9",
     0x00000173 => "\xf9",
     0x0000017d => "\xae",
     0x0000017e => "\xbe",
     0x000002c7 => "\xb7",
     0x000002d9 => "\xff",
     0x000002db => "\xb2",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::ISO_8859_4 - Conversion routines for ISO-8859-4
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for ISO-8859-4.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
   source: ECMA registry
  alias ISO-IR-110
  alias ISO_8859-4:1988
  alias ISO_8859-4
  alias LATIN4
  alias L4
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  00000004 | END OF TRANSMISSION (EOT)
     05 |  00000005 | ENQUIRY (ENQ)
     06 |  00000006 | ACKNOWLEDGE (ACK)
     07 |  00000007 | BELL (BEL)
     08 |  00000008 | BACKSPACE (BS)
     09 |  00000009 | CHARACTER TABULATION (HT)
     0A |  0000000A | LINE FEED (LF)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  00000014 | DEVICE CONTROL FOUR (DC4)
     15 |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     16 |  00000016 | SYNCHRONOUS IDLE (SYN)
     17 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  0000001A | SUBSTITUTE (SUB)
     1B |  0000001B | ESCAPE (ESC)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000020 | SPACE
     21 |  00000021 | EXCLAMATION MARK
     22 |  00000022 | QUOTATION MARK
     23 |  00000023 | NUMBER SIGN
     24 |  00000024 | DOLLAR SIGN
     25 |  00000025 | PERCENT SIGN
     26 |  00000026 | AMPERSAND
     27 |  00000027 | APOSTROPHE
     28 |  00000028 | LEFT PARENTHESIS
     29 |  00000029 | RIGHT PARENTHESIS
     2A |  0000002A | ASTERISK
     2B |  0000002B | PLUS SIGN
     2C |  0000002C | COMMA
     2D |  0000002D | HYPHEN-MINUS
     2E |  0000002E | FULL STOP
     2F |  0000002F | SOLIDUS
     30 |  00000030 | DIGIT ZERO
     31 |  00000031 | DIGIT ONE
     32 |  00000032 | DIGIT TWO
     33 |  00000033 | DIGIT THREE
     34 |  00000034 | DIGIT FOUR
     35 |  00000035 | DIGIT FIVE
     36 |  00000036 | DIGIT SIX
     37 |  00000037 | DIGIT SEVEN
     38 |  00000038 | DIGIT EIGHT
     39 |  00000039 | DIGIT NINE
     3A |  0000003A | COLON
     3B |  0000003B | SEMICOLON
     3C |  0000003C | LESS-THAN SIGN
     3D |  0000003D | EQUALS SIGN
     3E |  0000003E | GREATER-THAN SIGN
     3F |  0000003F | QUESTION MARK
     40 |  00000040 | COMMERCIAL AT
     41 |  00000041 | LATIN CAPITAL LETTER A
     42 |  00000042 | LATIN CAPITAL LETTER B
     43 |  00000043 | LATIN CAPITAL LETTER C
     44 |  00000044 | LATIN CAPITAL LETTER D
     45 |  00000045 | LATIN CAPITAL LETTER E
     46 |  00000046 | LATIN CAPITAL LETTER F
     47 |  00000047 | LATIN CAPITAL LETTER G
     48 |  00000048 | LATIN CAPITAL LETTER H
     49 |  00000049 | LATIN CAPITAL LETTER I
     4A |  0000004A | LATIN CAPITAL LETTER J
     4B |  0000004B | LATIN CAPITAL LETTER K
     4C |  0000004C | LATIN CAPITAL LETTER L
     4D |  0000004D | LATIN CAPITAL LETTER M
     4E |  0000004E | LATIN CAPITAL LETTER N
     4F |  0000004F | LATIN CAPITAL LETTER O
     50 |  00000050 | LATIN CAPITAL LETTER P
     51 |  00000051 | LATIN CAPITAL LETTER Q
     52 |  00000052 | LATIN CAPITAL LETTER R
     53 |  00000053 | LATIN CAPITAL LETTER S
     54 |  00000054 | LATIN CAPITAL LETTER T
     55 |  00000055 | LATIN CAPITAL LETTER U
     56 |  00000056 | LATIN CAPITAL LETTER V
     57 |  00000057 | LATIN CAPITAL LETTER W
     58 |  00000058 | LATIN CAPITAL LETTER X
     59 |  00000059 | LATIN CAPITAL LETTER Y
     5A |  0000005A | LATIN CAPITAL LETTER Z
     5B |  0000005B | LEFT SQUARE BRACKET
     5C |  0000005C | REVERSE SOLIDUS
     5D |  0000005D | RIGHT SQUARE BRACKET
     5E |  0000005E | CIRCUMFLEX ACCENT
     5F |  0000005F | LOW LINE
     60 |  00000060 | GRAVE ACCENT
     61 |  00000061 | LATIN SMALL LETTER A
     62 |  00000062 | LATIN SMALL LETTER B
     63 |  00000063 | LATIN SMALL LETTER C
     64 |  00000064 | LATIN SMALL LETTER D
     65 |  00000065 | LATIN SMALL LETTER E
     66 |  00000066 | LATIN SMALL LETTER F
     67 |  00000067 | LATIN SMALL LETTER G
     68 |  00000068 | LATIN SMALL LETTER H
     69 |  00000069 | LATIN SMALL LETTER I
     6A |  0000006A | LATIN SMALL LETTER J
     6B |  0000006B | LATIN SMALL LETTER K
     6C |  0000006C | LATIN SMALL LETTER L
     6D |  0000006D | LATIN SMALL LETTER M
     6E |  0000006E | LATIN SMALL LETTER N
     6F |  0000006F | LATIN SMALL LETTER O
     70 |  00000070 | LATIN SMALL LETTER P
     71 |  00000071 | LATIN SMALL LETTER Q
     72 |  00000072 | LATIN SMALL LETTER R
     73 |  00000073 | LATIN SMALL LETTER S
     74 |  00000074 | LATIN SMALL LETTER T
     75 |  00000075 | LATIN SMALL LETTER U
     76 |  00000076 | LATIN SMALL LETTER V
     77 |  00000077 | LATIN SMALL LETTER W
     78 |  00000078 | LATIN SMALL LETTER X
     79 |  00000079 | LATIN SMALL LETTER Y
     7A |  0000007A | LATIN SMALL LETTER Z
     7B |  0000007B | LEFT CURLY BRACKET
     7C |  0000007C | VERTICAL LINE
     7D |  0000007D | RIGHT CURLY BRACKET
     7E |  0000007E | TILDE
     7F |  0000007F | DELETE (DEL)
     80 |  00000080 | PADDING CHARACTER (PAD)
     81 |  00000081 | HIGH OCTET PRESET (HOP)
     82 |  00000082 | BREAK PERMITTED HERE (BPH)
     83 |  00000083 | NO BREAK HERE (NBH)
     84 |  00000084 | INDEX (IND)
     85 |  00000085 | NEXT LINE (NEL)
     86 |  00000086 | START OF SELECTED AREA (SSA)
     87 |  00000087 | END OF SELECTED AREA (ESA)
     88 |  00000088 | CHARACTER TABULATION SET (HTS)
     89 |  00000089 | CHARACTER TABULATION WITH JUSTIFICATION (HTJ)
     8A |  0000008A | LINE TABULATION SET (VTS)
     8B |  0000008B | PARTIAL LINE FORWARD (PLD)
     8C |  0000008C | PARTIAL LINE BACKWARD (PLU)
     8D |  0000008D | REVERSE LINE FEED (RI)
     8E |  0000008E | SINGLE-SHIFT TWO (SS2)
     8F |  0000008F | SINGLE-SHIFT THREE (SS3)
     90 |  00000090 | DEVICE CONTROL STRING (DCS)
     91 |  00000091 | PRIVATE USE ONE (PU1)
     92 |  00000092 | PRIVATE USE TWO (PU2)
     93 |  00000093 | SET TRANSMIT STATE (STS)
     94 |  00000094 | CANCEL CHARACTER (CCH)
     95 |  00000095 | MESSAGE WAITING (MW)
     96 |  00000096 | START OF GUARDED AREA (SPA)
     97 |  00000097 | END OF GUARDED AREA (EPA)
     98 |  00000098 | START OF STRING (SOS)
     99 |  00000099 | SINGLE GRAPHIC CHARACTER INTRODUCER (SGCI)
     9A |  0000009A | SINGLE CHARACTER INTRODUCER (SCI)
     9B |  0000009B | CONTROL SEQUENCE INTRODUCER (CSI)
     9C |  0000009C | STRING TERMINATOR (ST)
     9D |  0000009D | OPERATING SYSTEM COMMAND (OSC)
     9E |  0000009E | PRIVACY MESSAGE (PM)
     9F |  0000009F | APPLICATION PROGRAM COMMAND (APC)
     A0 |  000000A0 | NO-BREAK SPACE
     A1 |  00000104 | LATIN CAPITAL LETTER A WITH OGONEK
     A2 |  00000138 | LATIN SMALL LETTER KRA (Greenlandic)
     A3 |  00000156 | LATIN CAPITAL LETTER R WITH CEDILLA
     A4 |  000000A4 | CURRENCY SIGN
     A5 |  00000128 | LATIN CAPITAL LETTER I WITH TILDE
     A6 |  0000013B | LATIN CAPITAL LETTER L WITH CEDILLA
     A7 |  000000A7 | SECTION SIGN
     A8 |  000000A8 | DIAERESIS
     A9 |  00000160 | LATIN CAPITAL LETTER S WITH CARON
     AA |  00000112 | LATIN CAPITAL LETTER E WITH MACRON
     AB |  00000122 | LATIN CAPITAL LETTER G WITH CEDILLA
     AC |  00000166 | LATIN CAPITAL LETTER T WITH STROKE
     AD |  000000AD | SOFT HYPHEN
     AE |  0000017D | LATIN CAPITAL LETTER Z WITH CARON
     AF |  000000AF | MACRON
     B0 |  000000B0 | DEGREE SIGN
     B1 |  00000105 | LATIN SMALL LETTER A WITH OGONEK
     B2 |  000002DB | OGONEK
     B3 |  00000157 | LATIN SMALL LETTER R WITH CEDILLA
     B4 |  000000B4 | ACUTE ACCENT
     B5 |  00000129 | LATIN SMALL LETTER I WITH TILDE
     B6 |  0000013C | LATIN SMALL LETTER L WITH CEDILLA
     B7 |  000002C7 | CARON (Mandarin Chinese third tone)
     B8 |  000000B8 | CEDILLA
     B9 |  00000161 | LATIN SMALL LETTER S WITH CARON
     BA |  00000113 | LATIN SMALL LETTER E WITH MACRON
     BB |  00000123 | LATIN SMALL LETTER G WITH CEDILLA
     BC |  00000167 | LATIN SMALL LETTER T WITH STROKE
     BD |  0000014A | LATIN CAPITAL LETTER ENG (Sami)
     BE |  0000017E | LATIN SMALL LETTER Z WITH CARON
     BF |  0000014B | LATIN SMALL LETTER ENG (Sami)
     C0 |  00000100 | LATIN CAPITAL LETTER A WITH MACRON
     C1 |  000000C1 | LATIN CAPITAL LETTER A WITH ACUTE
     C2 |  000000C2 | LATIN CAPITAL LETTER A WITH CIRCUMFLEX
     C3 |  000000C3 | LATIN CAPITAL LETTER A WITH TILDE
     C4 |  000000C4 | LATIN CAPITAL LETTER A WITH DIAERESIS
     C5 |  000000C5 | LATIN CAPITAL LETTER A WITH RING ABOVE
     C6 |  000000C6 | LATIN CAPITAL LETTER AE
     C7 |  0000012E | LATIN CAPITAL LETTER I WITH OGONEK
     C8 |  0000010C | LATIN CAPITAL LETTER C WITH CARON
     C9 |  000000C9 | LATIN CAPITAL LETTER E WITH ACUTE
     CA |  00000118 | LATIN CAPITAL LETTER E WITH OGONEK
     CB |  000000CB | LATIN CAPITAL LETTER E WITH DIAERESIS
     CC |  00000116 | LATIN CAPITAL LETTER E WITH DOT ABOVE
     CD |  000000CD | LATIN CAPITAL LETTER I WITH ACUTE
     CE |  000000CE | LATIN CAPITAL LETTER I WITH CIRCUMFLEX
     CF |  0000012A | LATIN CAPITAL LETTER I WITH MACRON
     D0 |  00000110 | LATIN CAPITAL LETTER D WITH STROKE
     D1 |  00000145 | LATIN CAPITAL LETTER N WITH CEDILLA
     D2 |  0000014C | LATIN CAPITAL LETTER O WITH MACRON
     D3 |  00000136 | LATIN CAPITAL LETTER K WITH CEDILLA
     D4 |  000000D4 | LATIN CAPITAL LETTER O WITH CIRCUMFLEX
     D5 |  000000D5 | LATIN CAPITAL LETTER O WITH TILDE
     D6 |  000000D6 | LATIN CAPITAL LETTER O WITH DIAERESIS
     D7 |  000000D7 | MULTIPLICATION SIGN
     D8 |  000000D8 | LATIN CAPITAL LETTER O WITH STROKE
     D9 |  00000172 | LATIN CAPITAL LETTER U WITH OGONEK
     DA |  000000DA | LATIN CAPITAL LETTER U WITH ACUTE
     DB |  000000DB | LATIN CAPITAL LETTER U WITH CIRCUMFLEX
     DC |  000000DC | LATIN CAPITAL LETTER U WITH DIAERESIS
     DD |  00000168 | LATIN CAPITAL LETTER U WITH TILDE
     DE |  0000016A | LATIN CAPITAL LETTER U WITH MACRON
     DF |  000000DF | LATIN SMALL LETTER SHARP S (German)
     E0 |  00000101 | LATIN SMALL LETTER A WITH MACRON
     E1 |  000000E1 | LATIN SMALL LETTER A WITH ACUTE
     E2 |  000000E2 | LATIN SMALL LETTER A WITH CIRCUMFLEX
     E3 |  000000E3 | LATIN SMALL LETTER A WITH TILDE
     E4 |  000000E4 | LATIN SMALL LETTER A WITH DIAERESIS
     E5 |  000000E5 | LATIN SMALL LETTER A WITH RING ABOVE
     E6 |  000000E6 | LATIN SMALL LETTER AE
     E7 |  0000012F | LATIN SMALL LETTER I WITH OGONEK
     E8 |  0000010D | LATIN SMALL LETTER C WITH CARON
     E9 |  000000E9 | LATIN SMALL LETTER E WITH ACUTE
     EA |  00000119 | LATIN SMALL LETTER E WITH OGONEK
     EB |  000000EB | LATIN SMALL LETTER E WITH DIAERESIS
     EC |  00000117 | LATIN SMALL LETTER E WITH DOT ABOVE
     ED |  000000ED | LATIN SMALL LETTER I WITH ACUTE
     EE |  000000EE | LATIN SMALL LETTER I WITH CIRCUMFLEX
     EF |  0000012B | LATIN SMALL LETTER I WITH MACRON
     F0 |  00000111 | LATIN SMALL LETTER D WITH STROKE
     F1 |  00000146 | LATIN SMALL LETTER N WITH CEDILLA
     F2 |  0000014D | LATIN SMALL LETTER O WITH MACRON
     F3 |  00000137 | LATIN SMALL LETTER K WITH CEDILLA
     F4 |  000000F4 | LATIN SMALL LETTER O WITH CIRCUMFLEX
     F5 |  000000F5 | LATIN SMALL LETTER O WITH TILDE
     F6 |  000000F6 | LATIN SMALL LETTER O WITH DIAERESIS
     F7 |  000000F7 | DIVISION SIGN
     F8 |  000000F8 | LATIN SMALL LETTER O WITH STROKE
     F9 |  00000173 | LATIN SMALL LETTER U WITH OGONEK
     FA |  000000FA | LATIN SMALL LETTER U WITH ACUTE
     FB |  000000FB | LATIN SMALL LETTER U WITH CIRCUMFLEX
     FC |  000000FC | LATIN SMALL LETTER U WITH DIAERESIS
     FD |  00000169 | LATIN SMALL LETTER U WITH TILDE
     FE |  0000016B | LATIN SMALL LETTER U WITH MACRON
     FF |  000002D9 | DOT ABOVE (Mandarin Chinese light tone)
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/ISO_8859_5.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for ISO-8859-5.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::ISO_8859_5;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x0004,
     0x0005,
     0x0006,
     0x0007,
     0x0008,
     0x0009,
     0x000a,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x0014,
     0x0015,
     0x0016,
     0x0017,
     0x0018,
     0x0019,
     0x001a,
     0x001b,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0020,
     0x0021,
     0x0022,
     0x0023,
     0x0024,
     0x0025,
     0x0026,
     0x0027,
     0x0028,
     0x0029,
     0x002a,
     0x002b,
     0x002c,
     0x002d,
     0x002e,
     0x002f,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x003a,
     0x003b,
     0x003c,
     0x003d,
     0x003e,
     0x003f,
     0x0040,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x005b,
     0x005c,
     0x005d,
     0x005e,
     0x005f,
     0x0060,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x007b,
     0x007c,
     0x007d,
     0x007e,
     0x007f,
     0x0080,
     0x0081,
     0x0082,
     0x0083,
     0x0084,
     0x0085,
     0x0086,
     0x0087,
     0x0088,
     0x0089,
     0x008a,
     0x008b,
     0x008c,
     0x008d,
     0x008e,
     0x008f,
     0x0090,
     0x0091,
     0x0092,
     0x0093,
     0x0094,
     0x0095,
     0x0096,
     0x0097,
     0x0098,
     0x0099,
     0x009a,
     0x009b,
     0x009c,
     0x009d,
     0x009e,
     0x009f,
     0x00a0,
     0x0401,
     0x0402,
     0x0403,
     0x0404,
     0x0405,
     0x0406,
     0x0407,
     0x0408,
     0x0409,
     0x040a,
     0x040b,
     0x040c,
     0x00ad,
     0x040e,
     0x040f,
     0x0410,
     0x0411,
     0x0412,
     0x0413,
     0x0414,
     0x0415,
     0x0416,
     0x0417,
     0x0418,
     0x0419,
     0x041a,
     0x041b,
     0x041c,
     0x041d,
     0x041e,
     0x041f,
     0x0420,
     0x0421,
     0x0422,
     0x0423,
     0x0424,
     0x0425,
     0x0426,
     0x0427,
     0x0428,
     0x0429,
     0x042a,
     0x042b,
     0x042c,
     0x042d,
     0x042e,
     0x042f,
     0x0430,
     0x0431,
     0x0432,
     0x0433,
     0x0434,
     0x0435,
     0x0436,
     0x0437,
     0x0438,
     0x0439,
     0x043a,
     0x043b,
     0x043c,
     0x043d,
     0x043e,
     0x043f,
     0x0440,
     0x0441,
     0x0442,
     0x0443,
     0x0444,
     0x0445,
     0x0446,
     0x0447,
     0x0448,
     0x0449,
     0x044a,
     0x044b,
     0x044c,
     0x044d,
     0x044e,
     0x044f,
     0x2116,
     0x0451,
     0x0452,
     0x0453,
     0x0454,
     0x0455,
     0x0456,
     0x0457,
     0x0458,
     0x0459,
     0x045a,
     0x045b,
     0x045c,
     0x00a7,
     0x045e,
     0x045f,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\x04",
     "\x05",
     "\x06",
     "\x07",
     "\x08",
     "\x09",
     "\x0a",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\x14",
     "\x15",
     "\x16",
     "\x17",
     "\x18",
     "\x19",
     "\x1a",
     "\x1b",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\x20",
     "\x21",
     "\x22",
     "\x23",
     "\x24",
     "\x25",
     "\x26",
     "\x27",
     "\x28",
     "\x29",
     "\x2a",
     "\x2b",
     "\x2c",
     "\x2d",
     "\x2e",
     "\x2f",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\x3a",
     "\x3b",
     "\x3c",
     "\x3d",
     "\x3e",
     "\x3f",
     "\x40",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\x5b",
     "\x5c",
     "\x5d",
     "\x5e",
     "\x5f",
     "\x60",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\x7b",
     "\x7c",
     "\x7d",
     "\x7e",
     "\x7f",
     "\xc2\x80",
     "\xc2\x81",
     "\xc2\x82",
     "\xc2\x83",
     "\xc2\x84",
     "\xc2\x85",
     "\xc2\x86",
     "\xc2\x87",
     "\xc2\x88",
     "\xc2\x89",
     "\xc2\x8a",
     "\xc2\x8b",
     "\xc2\x8c",
     "\xc2\x8d",
     "\xc2\x8e",
     "\xc2\x8f",
     "\xc2\x90",
     "\xc2\x91",
     "\xc2\x92",
     "\xc2\x93",
     "\xc2\x94",
     "\xc2\x95",
     "\xc2\x96",
     "\xc2\x97",
     "\xc2\x98",
     "\xc2\x99",
     "\xc2\x9a",
     "\xc2\x9b",
     "\xc2\x9c",
     "\xc2\x9d",
     "\xc2\x9e",
     "\xc2\x9f",
     "\xc2\xa0",
     "\xd0\x81",
     "\xd0\x82",
     "\xd0\x83",
     "\xd0\x84",
     "\xd0\x85",
     "\xd0\x86",
     "\xd0\x87",
     "\xd0\x88",
     "\xd0\x89",
     "\xd0\x8a",
     "\xd0\x8b",
     "\xd0\x8c",
     "\xc2\xad",
     "\xd0\x8e",
     "\xd0\x8f",
     "\xd0\x90",
     "\xd0\x91",
     "\xd0\x92",
     "\xd0\x93",
     "\xd0\x94",
     "\xd0\x95",
     "\xd0\x96",
     "\xd0\x97",
     "\xd0\x98",
     "\xd0\x99",
     "\xd0\x9a",
     "\xd0\x9b",
     "\xd0\x9c",
     "\xd0\x9d",
     "\xd0\x9e",
     "\xd0\x9f",
     "\xd0\xa0",
     "\xd0\xa1",
     "\xd0\xa2",
     "\xd0\xa3",
     "\xd0\xa4",
     "\xd0\xa5",
     "\xd0\xa6",
     "\xd0\xa7",
     "\xd0\xa8",
     "\xd0\xa9",
     "\xd0\xaa",
     "\xd0\xab",
     "\xd0\xac",
     "\xd0\xad",
     "\xd0\xae",
     "\xd0\xaf",
     "\xd0\xb0",
     "\xd0\xb1",
     "\xd0\xb2",
     "\xd0\xb3",
     "\xd0\xb4",
     "\xd0\xb5",
     "\xd0\xb6",
     "\xd0\xb7",
     "\xd0\xb8",
     "\xd0\xb9",
     "\xd0\xba",
     "\xd0\xbb",
     "\xd0\xbc",
     "\xd0\xbd",
     "\xd0\xbe",
     "\xd0\xbf",
     "\xd1\x80",
     "\xd1\x81",
     "\xd1\x82",
     "\xd1\x83",
     "\xd1\x84",
     "\xd1\x85",
     "\xd1\x86",
     "\xd1\x87",
     "\xd1\x88",
     "\xd1\x89",
     "\xd1\x8a",
     "\xd1\x8b",
     "\xd1\x8c",
     "\xd1\x8d",
     "\xd1\x8e",
     "\xd1\x8f",
     "\xe2\x84\x96",
     "\xd1\x91",
     "\xd1\x92",
     "\xd1\x93",
     "\xd1\x94",
     "\xd1\x95",
     "\xd1\x96",
     "\xd1\x97",
     "\xd1\x98",
     "\xd1\x99",
     "\xd1\x9a",
     "\xd1\x9b",
     "\xd1\x9c",
     "\xc2\xa7",
     "\xd1\x9e",
     "\xd1\x9f",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x04",
     0x00000005 => "\x05",
     0x00000006 => "\x06",
     0x00000007 => "\x07",
     0x00000008 => "\x08",
     0x00000009 => "\x09",
     0x0000000a => "\x0a",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x14",
     0x00000015 => "\x15",
     0x00000016 => "\x16",
     0x00000017 => "\x17",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x1a",
     0x0000001b => "\x1b",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x20",
     0x00000021 => "\x21",
     0x00000022 => "\x22",
     0x00000023 => "\x23",
     0x00000024 => "\x24",
     0x00000025 => "\x25",
     0x00000026 => "\x26",
     0x00000027 => "\x27",
     0x00000028 => "\x28",
     0x00000029 => "\x29",
     0x0000002a => "\x2a",
     0x0000002b => "\x2b",
     0x0000002c => "\x2c",
     0x0000002d => "\x2d",
     0x0000002e => "\x2e",
     0x0000002f => "\x2f",
     0x00000030 => "\x30",
     0x00000031 => "\x31",
     0x00000032 => "\x32",
     0x00000033 => "\x33",
     0x00000034 => "\x34",
     0x00000035 => "\x35",
     0x00000036 => "\x36",
     0x00000037 => "\x37",
     0x00000038 => "\x38",
     0x00000039 => "\x39",
     0x0000003a => "\x3a",
     0x0000003b => "\x3b",
     0x0000003c => "\x3c",
     0x0000003d => "\x3d",
     0x0000003e => "\x3e",
     0x0000003f => "\x3f",
     0x00000040 => "\x40",
     0x00000041 => "\x41",
     0x00000042 => "\x42",
     0x00000043 => "\x43",
     0x00000044 => "\x44",
     0x00000045 => "\x45",
     0x00000046 => "\x46",
     0x00000047 => "\x47",
     0x00000048 => "\x48",
     0x00000049 => "\x49",
     0x0000004a => "\x4a",
     0x0000004b => "\x4b",
     0x0000004c => "\x4c",
     0x0000004d => "\x4d",
     0x0000004e => "\x4e",
     0x0000004f => "\x4f",
     0x00000050 => "\x50",
     0x00000051 => "\x51",
     0x00000052 => "\x52",
     0x00000053 => "\x53",
     0x00000054 => "\x54",
     0x00000055 => "\x55",
     0x00000056 => "\x56",
     0x00000057 => "\x57",
     0x00000058 => "\x58",
     0x00000059 => "\x59",
     0x0000005a => "\x5a",
     0x0000005b => "\x5b",
     0x0000005c => "\x5c",
     0x0000005d => "\x5d",
     0x0000005e => "\x5e",
     0x0000005f => "\x5f",
     0x00000060 => "\x60",
     0x00000061 => "\x61",
     0x00000062 => "\x62",
     0x00000063 => "\x63",
     0x00000064 => "\x64",
     0x00000065 => "\x65",
     0x00000066 => "\x66",
     0x00000067 => "\x67",
     0x00000068 => "\x68",
     0x00000069 => "\x69",
     0x0000006a => "\x6a",
     0x0000006b => "\x6b",
     0x0000006c => "\x6c",
     0x0000006d => "\x6d",
     0x0000006e => "\x6e",
     0x0000006f => "\x6f",
     0x00000070 => "\x70",
     0x00000071 => "\x71",
     0x00000072 => "\x72",
     0x00000073 => "\x73",
     0x00000074 => "\x74",
     0x00000075 => "\x75",
     0x00000076 => "\x76",
     0x00000077 => "\x77",
     0x00000078 => "\x78",
     0x00000079 => "\x79",
     0x0000007a => "\x7a",
     0x0000007b => "\x7b",
     0x0000007c => "\x7c",
     0x0000007d => "\x7d",
     0x0000007e => "\x7e",
     0x0000007f => "\x7f",
     0x00000080 => "\x80",
     0x00000081 => "\x81",
     0x00000082 => "\x82",
     0x00000083 => "\x83",
     0x00000084 => "\x84",
     0x00000085 => "\x85",
     0x00000086 => "\x86",
     0x00000087 => "\x87",
     0x00000088 => "\x88",
     0x00000089 => "\x89",
     0x0000008a => "\x8a",
     0x0000008b => "\x8b",
     0x0000008c => "\x8c",
     0x0000008d => "\x8d",
     0x0000008e => "\x8e",
     0x0000008f => "\x8f",
     0x00000090 => "\x90",
     0x00000091 => "\x91",
     0x00000092 => "\x92",
     0x00000093 => "\x93",
     0x00000094 => "\x94",
     0x00000095 => "\x95",
     0x00000096 => "\x96",
     0x00000097 => "\x97",
     0x00000098 => "\x98",
     0x00000099 => "\x99",
     0x0000009a => "\x9a",
     0x0000009b => "\x9b",
     0x0000009c => "\x9c",
     0x0000009d => "\x9d",
     0x0000009e => "\x9e",
     0x0000009f => "\x9f",
     0x000000a0 => "\xa0",
     0x000000a7 => "\xfd",
     0x000000ad => "\xad",
     0x00000401 => "\xa1",
     0x00000402 => "\xa2",
     0x00000403 => "\xa3",
     0x00000404 => "\xa4",
     0x00000405 => "\xa5",
     0x00000406 => "\xa6",
     0x00000407 => "\xa7",
     0x00000408 => "\xa8",
     0x00000409 => "\xa9",
     0x0000040a => "\xaa",
     0x0000040b => "\xab",
     0x0000040c => "\xac",
     0x0000040e => "\xae",
     0x0000040f => "\xaf",
     0x00000410 => "\xb0",
     0x00000411 => "\xb1",
     0x00000412 => "\xb2",
     0x00000413 => "\xb3",
     0x00000414 => "\xb4",
     0x00000415 => "\xb5",
     0x00000416 => "\xb6",
     0x00000417 => "\xb7",
     0x00000418 => "\xb8",
     0x00000419 => "\xb9",
     0x0000041a => "\xba",
     0x0000041b => "\xbb",
     0x0000041c => "\xbc",
     0x0000041d => "\xbd",
     0x0000041e => "\xbe",
     0x0000041f => "\xbf",
     0x00000420 => "\xc0",
     0x00000421 => "\xc1",
     0x00000422 => "\xc2",
     0x00000423 => "\xc3",
     0x00000424 => "\xc4",
     0x00000425 => "\xc5",
     0x00000426 => "\xc6",
     0x00000427 => "\xc7",
     0x00000428 => "\xc8",
     0x00000429 => "\xc9",
     0x0000042a => "\xca",
     0x0000042b => "\xcb",
     0x0000042c => "\xcc",
     0x0000042d => "\xcd",
     0x0000042e => "\xce",
     0x0000042f => "\xcf",
     0x00000430 => "\xd0",
     0x00000431 => "\xd1",
     0x00000432 => "\xd2",
     0x00000433 => "\xd3",
     0x00000434 => "\xd4",
     0x00000435 => "\xd5",
     0x00000436 => "\xd6",
     0x00000437 => "\xd7",
     0x00000438 => "\xd8",
     0x00000439 => "\xd9",
     0x0000043a => "\xda",
     0x0000043b => "\xdb",
     0x0000043c => "\xdc",
     0x0000043d => "\xdd",
     0x0000043e => "\xde",
     0x0000043f => "\xdf",
     0x00000440 => "\xe0",
     0x00000441 => "\xe1",
     0x00000442 => "\xe2",
     0x00000443 => "\xe3",
     0x00000444 => "\xe4",
     0x00000445 => "\xe5",
     0x00000446 => "\xe6",
     0x00000447 => "\xe7",
     0x00000448 => "\xe8",
     0x00000449 => "\xe9",
     0x0000044a => "\xea",
     0x0000044b => "\xeb",
     0x0000044c => "\xec",
     0x0000044d => "\xed",
     0x0000044e => "\xee",
     0x0000044f => "\xef",
     0x00000451 => "\xf1",
     0x00000452 => "\xf2",
     0x00000453 => "\xf3",
     0x00000454 => "\xf4",
     0x00000455 => "\xf5",
     0x00000456 => "\xf6",
     0x00000457 => "\xf7",
     0x00000458 => "\xf8",
     0x00000459 => "\xf9",
     0x0000045a => "\xfa",
     0x0000045b => "\xfb",
     0x0000045c => "\xfc",
     0x0000045e => "\xfe",
     0x0000045f => "\xff",
     0x00002116 => "\xf0",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::ISO_8859_5 - Conversion routines for ISO-8859-5
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for ISO-8859-5.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
   source: ECMA registry
  alias ISO-IR-144
  alias ISO_8859-5:1988
  alias ISO_8859-5
  alias CYRILLIC
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  00000004 | END OF TRANSMISSION (EOT)
     05 |  00000005 | ENQUIRY (ENQ)
     06 |  00000006 | ACKNOWLEDGE (ACK)
     07 |  00000007 | BELL (BEL)
     08 |  00000008 | BACKSPACE (BS)
     09 |  00000009 | CHARACTER TABULATION (HT)
     0A |  0000000A | LINE FEED (LF)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  00000014 | DEVICE CONTROL FOUR (DC4)
     15 |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     16 |  00000016 | SYNCHRONOUS IDLE (SYN)
     17 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  0000001A | SUBSTITUTE (SUB)
     1B |  0000001B | ESCAPE (ESC)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000020 | SPACE
     21 |  00000021 | EXCLAMATION MARK
     22 |  00000022 | QUOTATION MARK
     23 |  00000023 | NUMBER SIGN
     24 |  00000024 | DOLLAR SIGN
     25 |  00000025 | PERCENT SIGN
     26 |  00000026 | AMPERSAND
     27 |  00000027 | APOSTROPHE
     28 |  00000028 | LEFT PARENTHESIS
     29 |  00000029 | RIGHT PARENTHESIS
     2A |  0000002A | ASTERISK
     2B |  0000002B | PLUS SIGN
     2C |  0000002C | COMMA
     2D |  0000002D | HYPHEN-MINUS
     2E |  0000002E | FULL STOP
     2F |  0000002F | SOLIDUS
     30 |  00000030 | DIGIT ZERO
     31 |  00000031 | DIGIT ONE
     32 |  00000032 | DIGIT TWO
     33 |  00000033 | DIGIT THREE
     34 |  00000034 | DIGIT FOUR
     35 |  00000035 | DIGIT FIVE
     36 |  00000036 | DIGIT SIX
     37 |  00000037 | DIGIT SEVEN
     38 |  00000038 | DIGIT EIGHT
     39 |  00000039 | DIGIT NINE
     3A |  0000003A | COLON
     3B |  0000003B | SEMICOLON
     3C |  0000003C | LESS-THAN SIGN
     3D |  0000003D | EQUALS SIGN
     3E |  0000003E | GREATER-THAN SIGN
     3F |  0000003F | QUESTION MARK
     40 |  00000040 | COMMERCIAL AT
     41 |  00000041 | LATIN CAPITAL LETTER A
     42 |  00000042 | LATIN CAPITAL LETTER B
     43 |  00000043 | LATIN CAPITAL LETTER C
     44 |  00000044 | LATIN CAPITAL LETTER D
     45 |  00000045 | LATIN CAPITAL LETTER E
     46 |  00000046 | LATIN CAPITAL LETTER F
     47 |  00000047 | LATIN CAPITAL LETTER G
     48 |  00000048 | LATIN CAPITAL LETTER H
     49 |  00000049 | LATIN CAPITAL LETTER I
     4A |  0000004A | LATIN CAPITAL LETTER J
     4B |  0000004B | LATIN CAPITAL LETTER K
     4C |  0000004C | LATIN CAPITAL LETTER L
     4D |  0000004D | LATIN CAPITAL LETTER M
     4E |  0000004E | LATIN CAPITAL LETTER N
     4F |  0000004F | LATIN CAPITAL LETTER O
     50 |  00000050 | LATIN CAPITAL LETTER P
     51 |  00000051 | LATIN CAPITAL LETTER Q
     52 |  00000052 | LATIN CAPITAL LETTER R
     53 |  00000053 | LATIN CAPITAL LETTER S
     54 |  00000054 | LATIN CAPITAL LETTER T
     55 |  00000055 | LATIN CAPITAL LETTER U
     56 |  00000056 | LATIN CAPITAL LETTER V
     57 |  00000057 | LATIN CAPITAL LETTER W
     58 |  00000058 | LATIN CAPITAL LETTER X
     59 |  00000059 | LATIN CAPITAL LETTER Y
     5A |  0000005A | LATIN CAPITAL LETTER Z
     5B |  0000005B | LEFT SQUARE BRACKET
     5C |  0000005C | REVERSE SOLIDUS
     5D |  0000005D | RIGHT SQUARE BRACKET
     5E |  0000005E | CIRCUMFLEX ACCENT
     5F |  0000005F | LOW LINE
     60 |  00000060 | GRAVE ACCENT
     61 |  00000061 | LATIN SMALL LETTER A
     62 |  00000062 | LATIN SMALL LETTER B
     63 |  00000063 | LATIN SMALL LETTER C
     64 |  00000064 | LATIN SMALL LETTER D
     65 |  00000065 | LATIN SMALL LETTER E
     66 |  00000066 | LATIN SMALL LETTER F
     67 |  00000067 | LATIN SMALL LETTER G
     68 |  00000068 | LATIN SMALL LETTER H
     69 |  00000069 | LATIN SMALL LETTER I
     6A |  0000006A | LATIN SMALL LETTER J
     6B |  0000006B | LATIN SMALL LETTER K
     6C |  0000006C | LATIN SMALL LETTER L
     6D |  0000006D | LATIN SMALL LETTER M
     6E |  0000006E | LATIN SMALL LETTER N
     6F |  0000006F | LATIN SMALL LETTER O
     70 |  00000070 | LATIN SMALL LETTER P
     71 |  00000071 | LATIN SMALL LETTER Q
     72 |  00000072 | LATIN SMALL LETTER R
     73 |  00000073 | LATIN SMALL LETTER S
     74 |  00000074 | LATIN SMALL LETTER T
     75 |  00000075 | LATIN SMALL LETTER U
     76 |  00000076 | LATIN SMALL LETTER V
     77 |  00000077 | LATIN SMALL LETTER W
     78 |  00000078 | LATIN SMALL LETTER X
     79 |  00000079 | LATIN SMALL LETTER Y
     7A |  0000007A | LATIN SMALL LETTER Z
     7B |  0000007B | LEFT CURLY BRACKET
     7C |  0000007C | VERTICAL LINE
     7D |  0000007D | RIGHT CURLY BRACKET
     7E |  0000007E | TILDE
     7F |  0000007F | DELETE (DEL)
     80 |  00000080 | PADDING CHARACTER (PAD)
     81 |  00000081 | HIGH OCTET PRESET (HOP)
     82 |  00000082 | BREAK PERMITTED HERE (BPH)
     83 |  00000083 | NO BREAK HERE (NBH)
     84 |  00000084 | INDEX (IND)
     85 |  00000085 | NEXT LINE (NEL)
     86 |  00000086 | START OF SELECTED AREA (SSA)
     87 |  00000087 | END OF SELECTED AREA (ESA)
     88 |  00000088 | CHARACTER TABULATION SET (HTS)
     89 |  00000089 | CHARACTER TABULATION WITH JUSTIFICATION (HTJ)
     8A |  0000008A | LINE TABULATION SET (VTS)
     8B |  0000008B | PARTIAL LINE FORWARD (PLD)
     8C |  0000008C | PARTIAL LINE BACKWARD (PLU)
     8D |  0000008D | REVERSE LINE FEED (RI)
     8E |  0000008E | SINGLE-SHIFT TWO (SS2)
     8F |  0000008F | SINGLE-SHIFT THREE (SS3)
     90 |  00000090 | DEVICE CONTROL STRING (DCS)
     91 |  00000091 | PRIVATE USE ONE (PU1)
     92 |  00000092 | PRIVATE USE TWO (PU2)
     93 |  00000093 | SET TRANSMIT STATE (STS)
     94 |  00000094 | CANCEL CHARACTER (CCH)
     95 |  00000095 | MESSAGE WAITING (MW)
     96 |  00000096 | START OF GUARDED AREA (SPA)
     97 |  00000097 | END OF GUARDED AREA (EPA)
     98 |  00000098 | START OF STRING (SOS)
     99 |  00000099 | SINGLE GRAPHIC CHARACTER INTRODUCER (SGCI)
     9A |  0000009A | SINGLE CHARACTER INTRODUCER (SCI)
     9B |  0000009B | CONTROL SEQUENCE INTRODUCER (CSI)
     9C |  0000009C | STRING TERMINATOR (ST)
     9D |  0000009D | OPERATING SYSTEM COMMAND (OSC)
     9E |  0000009E | PRIVACY MESSAGE (PM)
     9F |  0000009F | APPLICATION PROGRAM COMMAND (APC)
     A0 |  000000A0 | NO-BREAK SPACE
     A1 |  00000401 | CYRILLIC CAPITAL LETTER IO
     A2 |  00000402 | CYRILLIC CAPITAL LETTER DJE (Serbocroatian)
     A3 |  00000403 | CYRILLIC CAPITAL LETTER GJE
     A4 |  00000404 | CYRILLIC CAPITAL LETTER UKRAINIAN IE
     A5 |  00000405 | CYRILLIC CAPITAL LETTER DZE
     A6 |  00000406 | CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I
     A7 |  00000407 | CYRILLIC CAPITAL LETTER YI (Ukrainian)
     A8 |  00000408 | CYRILLIC CAPITAL LETTER JE
     A9 |  00000409 | CYRILLIC CAPITAL LETTER LJE
     AA |  0000040A | CYRILLIC CAPITAL LETTER NJE
     AB |  0000040B | CYRILLIC CAPITAL LETTER TSHE (Serbocroatian)
     AC |  0000040C | CYRILLIC CAPITAL LETTER KJE
     AD |  000000AD | SOFT HYPHEN
     AE |  0000040E | CYRILLIC CAPITAL LETTER SHORT U (Byelorussian)
     AF |  0000040F | CYRILLIC CAPITAL LETTER DZHE
     B0 |  00000410 | CYRILLIC CAPITAL LETTER A
     B1 |  00000411 | CYRILLIC CAPITAL LETTER BE
     B2 |  00000412 | CYRILLIC CAPITAL LETTER VE
     B3 |  00000413 | CYRILLIC CAPITAL LETTER GHE
     B4 |  00000414 | CYRILLIC CAPITAL LETTER DE
     B5 |  00000415 | CYRILLIC CAPITAL LETTER IE
     B6 |  00000416 | CYRILLIC CAPITAL LETTER ZHE
     B7 |  00000417 | CYRILLIC CAPITAL LETTER ZE
     B8 |  00000418 | CYRILLIC CAPITAL LETTER I
     B9 |  00000419 | CYRILLIC CAPITAL LETTER SHORT I
     BA |  0000041A | CYRILLIC CAPITAL LETTER KA
     BB |  0000041B | CYRILLIC CAPITAL LETTER EL
     BC |  0000041C | CYRILLIC CAPITAL LETTER EM
     BD |  0000041D | CYRILLIC CAPITAL LETTER EN
     BE |  0000041E | CYRILLIC CAPITAL LETTER O
     BF |  0000041F | CYRILLIC CAPITAL LETTER PE
     C0 |  00000420 | CYRILLIC CAPITAL LETTER ER
     C1 |  00000421 | CYRILLIC CAPITAL LETTER ES
     C2 |  00000422 | CYRILLIC CAPITAL LETTER TE
     C3 |  00000423 | CYRILLIC CAPITAL LETTER U
     C4 |  00000424 | CYRILLIC CAPITAL LETTER EF
     C5 |  00000425 | CYRILLIC CAPITAL LETTER HA
     C6 |  00000426 | CYRILLIC CAPITAL LETTER TSE
     C7 |  00000427 | CYRILLIC CAPITAL LETTER CHE
     C8 |  00000428 | CYRILLIC CAPITAL LETTER SHA
     C9 |  00000429 | CYRILLIC CAPITAL LETTER SHCHA
     CA |  0000042A | CYRILLIC CAPITAL LETTER HARD SIGN
     CB |  0000042B | CYRILLIC CAPITAL LETTER YERU
     CC |  0000042C | CYRILLIC CAPITAL LETTER SOFT SIGN
     CD |  0000042D | CYRILLIC CAPITAL LETTER E
     CE |  0000042E | CYRILLIC CAPITAL LETTER YU
     CF |  0000042F | CYRILLIC CAPITAL LETTER YA
     D0 |  00000430 | CYRILLIC SMALL LETTER A
     D1 |  00000431 | CYRILLIC SMALL LETTER BE
     D2 |  00000432 | CYRILLIC SMALL LETTER VE
     D3 |  00000433 | CYRILLIC SMALL LETTER GHE
     D4 |  00000434 | CYRILLIC SMALL LETTER DE
     D5 |  00000435 | CYRILLIC SMALL LETTER IE
     D6 |  00000436 | CYRILLIC SMALL LETTER ZHE
     D7 |  00000437 | CYRILLIC SMALL LETTER ZE
     D8 |  00000438 | CYRILLIC SMALL LETTER I
     D9 |  00000439 | CYRILLIC SMALL LETTER SHORT I
     DA |  0000043A | CYRILLIC SMALL LETTER KA
     DB |  0000043B | CYRILLIC SMALL LETTER EL
     DC |  0000043C | CYRILLIC SMALL LETTER EM
     DD |  0000043D | CYRILLIC SMALL LETTER EN
     DE |  0000043E | CYRILLIC SMALL LETTER O
     DF |  0000043F | CYRILLIC SMALL LETTER PE
     E0 |  00000440 | CYRILLIC SMALL LETTER ER
     E1 |  00000441 | CYRILLIC SMALL LETTER ES
     E2 |  00000442 | CYRILLIC SMALL LETTER TE
     E3 |  00000443 | CYRILLIC SMALL LETTER U
     E4 |  00000444 | CYRILLIC SMALL LETTER EF
     E5 |  00000445 | CYRILLIC SMALL LETTER HA
     E6 |  00000446 | CYRILLIC SMALL LETTER TSE
     E7 |  00000447 | CYRILLIC SMALL LETTER CHE
     E8 |  00000448 | CYRILLIC SMALL LETTER SHA
     E9 |  00000449 | CYRILLIC SMALL LETTER SHCHA
     EA |  0000044A | CYRILLIC SMALL LETTER HARD SIGN
     EB |  0000044B | CYRILLIC SMALL LETTER YERU
     EC |  0000044C | CYRILLIC SMALL LETTER SOFT SIGN
     ED |  0000044D | CYRILLIC SMALL LETTER E
     EE |  0000044E | CYRILLIC SMALL LETTER YU
     EF |  0000044F | CYRILLIC SMALL LETTER YA
     F0 |  00002116 | NUMERO SIGN
     F1 |  00000451 | CYRILLIC SMALL LETTER IO
     F2 |  00000452 | CYRILLIC SMALL LETTER DJE (Serbocroatian)
     F3 |  00000453 | CYRILLIC SMALL LETTER GJE
     F4 |  00000454 | CYRILLIC SMALL LETTER UKRAINIAN IE
     F5 |  00000455 | CYRILLIC SMALL LETTER DZE
     F6 |  00000456 | CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I
     F7 |  00000457 | CYRILLIC SMALL LETTER YI (Ukrainian)
     F8 |  00000458 | CYRILLIC SMALL LETTER JE
     F9 |  00000459 | CYRILLIC SMALL LETTER LJE
     FA |  0000045A | CYRILLIC SMALL LETTER NJE
     FB |  0000045B | CYRILLIC SMALL LETTER TSHE (Serbocroatian)
     FC |  0000045C | CYRILLIC SMALL LETTER KJE
     FD |  000000A7 | SECTION SIGN
     FE |  0000045E | CYRILLIC SMALL LETTER SHORT U (Byelorussian)
     FF |  0000045F | CYRILLIC SMALL LETTER DZHE
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/ISO_8859_6.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for ISO-8859-6.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::ISO_8859_6;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x0004,
     0x0005,
     0x0006,
     0x0007,
     0x0008,
     0x0009,
     0x000a,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x0014,
     0x0015,
     0x0016,
     0x0017,
     0x0018,
     0x0019,
     0x001a,
     0x001b,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0020,
     0x0021,
     0x0022,
     0x0023,
     0x0024,
     0x0025,
     0x0026,
     0x0027,
     0x0028,
     0x0029,
     0x002a,
     0x002b,
     0x002c,
     0x002d,
     0x002e,
     0x002f,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x003a,
     0x003b,
     0x003c,
     0x003d,
     0x003e,
     0x003f,
     0x0040,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x005b,
     0x005c,
     0x005d,
     0x005e,
     0x005f,
     0x0060,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x007b,
     0x007c,
     0x007d,
     0x007e,
     0x007f,
     0x0080,
     0x0081,
     0x0082,
     0x0083,
     0x0084,
     0x0085,
     0x0086,
     0x0087,
     0x0088,
     0x0089,
     0x008a,
     0x008b,
     0x008c,
     0x008d,
     0x008e,
     0x008f,
     0x0090,
     0x0091,
     0x0092,
     0x0093,
     0x0094,
     0x0095,
     0x0096,
     0x0097,
     0x0098,
     0x0099,
     0x009a,
     0x009b,
     0x009c,
     0x009d,
     0x009e,
     0x009f,
     0x00a0,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00a4,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x060c,
     0x00ad,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x061b,
     0xfffd,
     0xfffd,
     0xfffd,
     0x061f,
     0xfffd,
     0x0621,
     0x0622,
     0x0623,
     0x0624,
     0x0625,
     0x0626,
     0x0627,
     0x0628,
     0x0629,
     0x062a,
     0x062b,
     0x062c,
     0x062d,
     0x062e,
     0x062f,
     0x0630,
     0x0631,
     0x0632,
     0x0633,
     0x0634,
     0x0635,
     0x0636,
     0x0637,
     0x0638,
     0x0639,
     0x063a,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x0640,
     0x0641,
     0x0642,
     0x0643,
     0x0644,
     0x0645,
     0x0646,
     0x0647,
     0x0648,
     0x0649,
     0x064a,
     0x064b,
     0x064c,
     0x064d,
     0x064e,
     0x064f,
     0x0650,
     0x0651,
     0x0652,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\x04",
     "\x05",
     "\x06",
     "\x07",
     "\x08",
     "\x09",
     "\x0a",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\x14",
     "\x15",
     "\x16",
     "\x17",
     "\x18",
     "\x19",
     "\x1a",
     "\x1b",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\x20",
     "\x21",
     "\x22",
     "\x23",
     "\x24",
     "\x25",
     "\x26",
     "\x27",
     "\x28",
     "\x29",
     "\x2a",
     "\x2b",
     "\x2c",
     "\x2d",
     "\x2e",
     "\x2f",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\x3a",
     "\x3b",
     "\x3c",
     "\x3d",
     "\x3e",
     "\x3f",
     "\x40",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\x5b",
     "\x5c",
     "\x5d",
     "\x5e",
     "\x5f",
     "\x60",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\x7b",
     "\x7c",
     "\x7d",
     "\x7e",
     "\x7f",
     "\xc2\x80",
     "\xc2\x81",
     "\xc2\x82",
     "\xc2\x83",
     "\xc2\x84",
     "\xc2\x85",
     "\xc2\x86",
     "\xc2\x87",
     "\xc2\x88",
     "\xc2\x89",
     "\xc2\x8a",
     "\xc2\x8b",
     "\xc2\x8c",
     "\xc2\x8d",
     "\xc2\x8e",
     "\xc2\x8f",
     "\xc2\x90",
     "\xc2\x91",
     "\xc2\x92",
     "\xc2\x93",
     "\xc2\x94",
     "\xc2\x95",
     "\xc2\x96",
     "\xc2\x97",
     "\xc2\x98",
     "\xc2\x99",
     "\xc2\x9a",
     "\xc2\x9b",
     "\xc2\x9c",
     "\xc2\x9d",
     "\xc2\x9e",
     "\xc2\x9f",
     "\xc2\xa0",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc2\xa4",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xd8\x8c",
     "\xc2\xad",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xd8\x9b",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xd8\x9f",
     "\xef\xbf\xbd",
     "\xd8\xa1",
     "\xd8\xa2",
     "\xd8\xa3",
     "\xd8\xa4",
     "\xd8\xa5",
     "\xd8\xa6",
     "\xd8\xa7",
     "\xd8\xa8",
     "\xd8\xa9",
     "\xd8\xaa",
     "\xd8\xab",
     "\xd8\xac",
     "\xd8\xad",
     "\xd8\xae",
     "\xd8\xaf",
     "\xd8\xb0",
     "\xd8\xb1",
     "\xd8\xb2",
     "\xd8\xb3",
     "\xd8\xb4",
     "\xd8\xb5",
     "\xd8\xb6",
     "\xd8\xb7",
     "\xd8\xb8",
     "\xd8\xb9",
     "\xd8\xba",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xd9\x80",
     "\xd9\x81",
     "\xd9\x82",
     "\xd9\x83",
     "\xd9\x84",
     "\xd9\x85",
     "\xd9\x86",
     "\xd9\x87",
     "\xd9\x88",
     "\xd9\x89",
     "\xd9\x8a",
     "\xd9\x8b",
     "\xd9\x8c",
     "\xd9\x8d",
     "\xd9\x8e",
     "\xd9\x8f",
     "\xd9\x90",
     "\xd9\x91",
     "\xd9\x92",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x04",
     0x00000005 => "\x05",
     0x00000006 => "\x06",
     0x00000007 => "\x07",
     0x00000008 => "\x08",
     0x00000009 => "\x09",
     0x0000000a => "\x0a",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x14",
     0x00000015 => "\x15",
     0x00000016 => "\x16",
     0x00000017 => "\x17",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x1a",
     0x0000001b => "\x1b",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x20",
     0x00000021 => "\x21",
     0x00000022 => "\x22",
     0x00000023 => "\x23",
     0x00000024 => "\x24",
     0x00000025 => "\x25",
     0x00000026 => "\x26",
     0x00000027 => "\x27",
     0x00000028 => "\x28",
     0x00000029 => "\x29",
     0x0000002a => "\x2a",
     0x0000002b => "\x2b",
     0x0000002c => "\x2c",
     0x0000002d => "\x2d",
     0x0000002e => "\x2e",
     0x0000002f => "\x2f",
     0x00000030 => "\x30",
     0x00000031 => "\x31",
     0x00000032 => "\x32",
     0x00000033 => "\x33",
     0x00000034 => "\x34",
     0x00000035 => "\x35",
     0x00000036 => "\x36",
     0x00000037 => "\x37",
     0x00000038 => "\x38",
     0x00000039 => "\x39",
     0x0000003a => "\x3a",
     0x0000003b => "\x3b",
     0x0000003c => "\x3c",
     0x0000003d => "\x3d",
     0x0000003e => "\x3e",
     0x0000003f => "\x3f",
     0x00000040 => "\x40",
     0x00000041 => "\x41",
     0x00000042 => "\x42",
     0x00000043 => "\x43",
     0x00000044 => "\x44",
     0x00000045 => "\x45",
     0x00000046 => "\x46",
     0x00000047 => "\x47",
     0x00000048 => "\x48",
     0x00000049 => "\x49",
     0x0000004a => "\x4a",
     0x0000004b => "\x4b",
     0x0000004c => "\x4c",
     0x0000004d => "\x4d",
     0x0000004e => "\x4e",
     0x0000004f => "\x4f",
     0x00000050 => "\x50",
     0x00000051 => "\x51",
     0x00000052 => "\x52",
     0x00000053 => "\x53",
     0x00000054 => "\x54",
     0x00000055 => "\x55",
     0x00000056 => "\x56",
     0x00000057 => "\x57",
     0x00000058 => "\x58",
     0x00000059 => "\x59",
     0x0000005a => "\x5a",
     0x0000005b => "\x5b",
     0x0000005c => "\x5c",
     0x0000005d => "\x5d",
     0x0000005e => "\x5e",
     0x0000005f => "\x5f",
     0x00000060 => "\x60",
     0x00000061 => "\x61",
     0x00000062 => "\x62",
     0x00000063 => "\x63",
     0x00000064 => "\x64",
     0x00000065 => "\x65",
     0x00000066 => "\x66",
     0x00000067 => "\x67",
     0x00000068 => "\x68",
     0x00000069 => "\x69",
     0x0000006a => "\x6a",
     0x0000006b => "\x6b",
     0x0000006c => "\x6c",
     0x0000006d => "\x6d",
     0x0000006e => "\x6e",
     0x0000006f => "\x6f",
     0x00000070 => "\x70",
     0x00000071 => "\x71",
     0x00000072 => "\x72",
     0x00000073 => "\x73",
     0x00000074 => "\x74",
     0x00000075 => "\x75",
     0x00000076 => "\x76",
     0x00000077 => "\x77",
     0x00000078 => "\x78",
     0x00000079 => "\x79",
     0x0000007a => "\x7a",
     0x0000007b => "\x7b",
     0x0000007c => "\x7c",
     0x0000007d => "\x7d",
     0x0000007e => "\x7e",
     0x0000007f => "\x7f",
     0x00000080 => "\x80",
     0x00000081 => "\x81",
     0x00000082 => "\x82",
     0x00000083 => "\x83",
     0x00000084 => "\x84",
     0x00000085 => "\x85",
     0x00000086 => "\x86",
     0x00000087 => "\x87",
     0x00000088 => "\x88",
     0x00000089 => "\x89",
     0x0000008a => "\x8a",
     0x0000008b => "\x8b",
     0x0000008c => "\x8c",
     0x0000008d => "\x8d",
     0x0000008e => "\x8e",
     0x0000008f => "\x8f",
     0x00000090 => "\x90",
     0x00000091 => "\x91",
     0x00000092 => "\x92",
     0x00000093 => "\x93",
     0x00000094 => "\x94",
     0x00000095 => "\x95",
     0x00000096 => "\x96",
     0x00000097 => "\x97",
     0x00000098 => "\x98",
     0x00000099 => "\x99",
     0x0000009a => "\x9a",
     0x0000009b => "\x9b",
     0x0000009c => "\x9c",
     0x0000009d => "\x9d",
     0x0000009e => "\x9e",
     0x0000009f => "\x9f",
     0x000000a0 => "\xa0",
     0x000000a4 => "\xa4",
     0x000000ad => "\xad",
     0x0000060c => "\xac",
     0x0000061b => "\xbb",
     0x0000061f => "\xbf",
     0x00000621 => "\xc1",
     0x00000622 => "\xc2",
     0x00000623 => "\xc3",
     0x00000624 => "\xc4",
     0x00000625 => "\xc5",
     0x00000626 => "\xc6",
     0x00000627 => "\xc7",
     0x00000628 => "\xc8",
     0x00000629 => "\xc9",
     0x0000062a => "\xca",
     0x0000062b => "\xcb",
     0x0000062c => "\xcc",
     0x0000062d => "\xcd",
     0x0000062e => "\xce",
     0x0000062f => "\xcf",
     0x00000630 => "\xd0",
     0x00000631 => "\xd1",
     0x00000632 => "\xd2",
     0x00000633 => "\xd3",
     0x00000634 => "\xd4",
     0x00000635 => "\xd5",
     0x00000636 => "\xd6",
     0x00000637 => "\xd7",
     0x00000638 => "\xd8",
     0x00000639 => "\xd9",
     0x0000063a => "\xda",
     0x00000640 => "\xe0",
     0x00000641 => "\xe1",
     0x00000642 => "\xe2",
     0x00000643 => "\xe3",
     0x00000644 => "\xe4",
     0x00000645 => "\xe5",
     0x00000646 => "\xe6",
     0x00000647 => "\xe7",
     0x00000648 => "\xe8",
     0x00000649 => "\xe9",
     0x0000064a => "\xea",
     0x0000064b => "\xeb",
     0x0000064c => "\xec",
     0x0000064d => "\xed",
     0x0000064e => "\xee",
     0x0000064f => "\xef",
     0x00000650 => "\xf0",
     0x00000651 => "\xf1",
     0x00000652 => "\xf2",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::ISO_8859_6 - Conversion routines for ISO-8859-6
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for ISO-8859-6.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
   source: ECMA registry
  alias ISO-IR-127
  alias ISO_8859-6:1987
  alias ISO_8859-6
  alias ECMA-114
  alias ASMO-708
  alias ARABIC
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  00000004 | END OF TRANSMISSION (EOT)
     05 |  00000005 | ENQUIRY (ENQ)
     06 |  00000006 | ACKNOWLEDGE (ACK)
     07 |  00000007 | BELL (BEL)
     08 |  00000008 | BACKSPACE (BS)
     09 |  00000009 | CHARACTER TABULATION (HT)
     0A |  0000000A | LINE FEED (LF)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  00000014 | DEVICE CONTROL FOUR (DC4)
     15 |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     16 |  00000016 | SYNCHRONOUS IDLE (SYN)
     17 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  0000001A | SUBSTITUTE (SUB)
     1B |  0000001B | ESCAPE (ESC)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000020 | SPACE
     21 |  00000021 | EXCLAMATION MARK
     22 |  00000022 | QUOTATION MARK
     23 |  00000023 | NUMBER SIGN
     24 |  00000024 | DOLLAR SIGN
     25 |  00000025 | PERCENT SIGN
     26 |  00000026 | AMPERSAND
     27 |  00000027 | APOSTROPHE
     28 |  00000028 | LEFT PARENTHESIS
     29 |  00000029 | RIGHT PARENTHESIS
     2A |  0000002A | ASTERISK
     2B |  0000002B | PLUS SIGN
     2C |  0000002C | COMMA
     2D |  0000002D | HYPHEN-MINUS
     2E |  0000002E | FULL STOP
     2F |  0000002F | SOLIDUS
     30 |  00000030 | DIGIT ZERO
     31 |  00000031 | DIGIT ONE
     32 |  00000032 | DIGIT TWO
     33 |  00000033 | DIGIT THREE
     34 |  00000034 | DIGIT FOUR
     35 |  00000035 | DIGIT FIVE
     36 |  00000036 | DIGIT SIX
     37 |  00000037 | DIGIT SEVEN
     38 |  00000038 | DIGIT EIGHT
     39 |  00000039 | DIGIT NINE
     3A |  0000003A | COLON
     3B |  0000003B | SEMICOLON
     3C |  0000003C | LESS-THAN SIGN
     3D |  0000003D | EQUALS SIGN
     3E |  0000003E | GREATER-THAN SIGN
     3F |  0000003F | QUESTION MARK
     40 |  00000040 | COMMERCIAL AT
     41 |  00000041 | LATIN CAPITAL LETTER A
     42 |  00000042 | LATIN CAPITAL LETTER B
     43 |  00000043 | LATIN CAPITAL LETTER C
     44 |  00000044 | LATIN CAPITAL LETTER D
     45 |  00000045 | LATIN CAPITAL LETTER E
     46 |  00000046 | LATIN CAPITAL LETTER F
     47 |  00000047 | LATIN CAPITAL LETTER G
     48 |  00000048 | LATIN CAPITAL LETTER H
     49 |  00000049 | LATIN CAPITAL LETTER I
     4A |  0000004A | LATIN CAPITAL LETTER J
     4B |  0000004B | LATIN CAPITAL LETTER K
     4C |  0000004C | LATIN CAPITAL LETTER L
     4D |  0000004D | LATIN CAPITAL LETTER M
     4E |  0000004E | LATIN CAPITAL LETTER N
     4F |  0000004F | LATIN CAPITAL LETTER O
     50 |  00000050 | LATIN CAPITAL LETTER P
     51 |  00000051 | LATIN CAPITAL LETTER Q
     52 |  00000052 | LATIN CAPITAL LETTER R
     53 |  00000053 | LATIN CAPITAL LETTER S
     54 |  00000054 | LATIN CAPITAL LETTER T
     55 |  00000055 | LATIN CAPITAL LETTER U
     56 |  00000056 | LATIN CAPITAL LETTER V
     57 |  00000057 | LATIN CAPITAL LETTER W
     58 |  00000058 | LATIN CAPITAL LETTER X
     59 |  00000059 | LATIN CAPITAL LETTER Y
     5A |  0000005A | LATIN CAPITAL LETTER Z
     5B |  0000005B | LEFT SQUARE BRACKET
     5C |  0000005C | REVERSE SOLIDUS
     5D |  0000005D | RIGHT SQUARE BRACKET
     5E |  0000005E | CIRCUMFLEX ACCENT
     5F |  0000005F | LOW LINE
     60 |  00000060 | GRAVE ACCENT
     61 |  00000061 | LATIN SMALL LETTER A
     62 |  00000062 | LATIN SMALL LETTER B
     63 |  00000063 | LATIN SMALL LETTER C
     64 |  00000064 | LATIN SMALL LETTER D
     65 |  00000065 | LATIN SMALL LETTER E
     66 |  00000066 | LATIN SMALL LETTER F
     67 |  00000067 | LATIN SMALL LETTER G
     68 |  00000068 | LATIN SMALL LETTER H
     69 |  00000069 | LATIN SMALL LETTER I
     6A |  0000006A | LATIN SMALL LETTER J
     6B |  0000006B | LATIN SMALL LETTER K
     6C |  0000006C | LATIN SMALL LETTER L
     6D |  0000006D | LATIN SMALL LETTER M
     6E |  0000006E | LATIN SMALL LETTER N
     6F |  0000006F | LATIN SMALL LETTER O
     70 |  00000070 | LATIN SMALL LETTER P
     71 |  00000071 | LATIN SMALL LETTER Q
     72 |  00000072 | LATIN SMALL LETTER R
     73 |  00000073 | LATIN SMALL LETTER S
     74 |  00000074 | LATIN SMALL LETTER T
     75 |  00000075 | LATIN SMALL LETTER U
     76 |  00000076 | LATIN SMALL LETTER V
     77 |  00000077 | LATIN SMALL LETTER W
     78 |  00000078 | LATIN SMALL LETTER X
     79 |  00000079 | LATIN SMALL LETTER Y
     7A |  0000007A | LATIN SMALL LETTER Z
     7B |  0000007B | LEFT CURLY BRACKET
     7C |  0000007C | VERTICAL LINE
     7D |  0000007D | RIGHT CURLY BRACKET
     7E |  0000007E | TILDE
     7F |  0000007F | DELETE (DEL)
     80 |  00000080 | PADDING CHARACTER (PAD)
     81 |  00000081 | HIGH OCTET PRESET (HOP)
     82 |  00000082 | BREAK PERMITTED HERE (BPH)
     83 |  00000083 | NO BREAK HERE (NBH)
     84 |  00000084 | INDEX (IND)
     85 |  00000085 | NEXT LINE (NEL)
     86 |  00000086 | START OF SELECTED AREA (SSA)
     87 |  00000087 | END OF SELECTED AREA (ESA)
     88 |  00000088 | CHARACTER TABULATION SET (HTS)
     89 |  00000089 | CHARACTER TABULATION WITH JUSTIFICATION (HTJ)
     8A |  0000008A | LINE TABULATION SET (VTS)
     8B |  0000008B | PARTIAL LINE FORWARD (PLD)
     8C |  0000008C | PARTIAL LINE BACKWARD (PLU)
     8D |  0000008D | REVERSE LINE FEED (RI)
     8E |  0000008E | SINGLE-SHIFT TWO (SS2)
     8F |  0000008F | SINGLE-SHIFT THREE (SS3)
     90 |  00000090 | DEVICE CONTROL STRING (DCS)
     91 |  00000091 | PRIVATE USE ONE (PU1)
     92 |  00000092 | PRIVATE USE TWO (PU2)
     93 |  00000093 | SET TRANSMIT STATE (STS)
     94 |  00000094 | CANCEL CHARACTER (CCH)
     95 |  00000095 | MESSAGE WAITING (MW)
     96 |  00000096 | START OF GUARDED AREA (SPA)
     97 |  00000097 | END OF GUARDED AREA (EPA)
     98 |  00000098 | START OF STRING (SOS)
     99 |  00000099 | SINGLE GRAPHIC CHARACTER INTRODUCER (SGCI)
     9A |  0000009A | SINGLE CHARACTER INTRODUCER (SCI)
     9B |  0000009B | CONTROL SEQUENCE INTRODUCER (CSI)
     9C |  0000009C | STRING TERMINATOR (ST)
     9D |  0000009D | OPERATING SYSTEM COMMAND (OSC)
     9E |  0000009E | PRIVACY MESSAGE (PM)
     9F |  0000009F | APPLICATION PROGRAM COMMAND (APC)
     A0 |  000000A0 | NO-BREAK SPACE
     A4 |  000000A4 | CURRENCY SIGN
     AC |  0000060C | ARABIC COMMA
     AD |  000000AD | SOFT HYPHEN
     BB |  0000061B | ARABIC SEMICOLON
     BF |  0000061F | ARABIC QUESTION MARK
     C1 |  00000621 | ARABIC LETTER HAMZA
     C2 |  00000622 | ARABIC LETTER ALEF WITH MADDA ABOVE
     C3 |  00000623 | ARABIC LETTER ALEF WITH HAMZA ABOVE
     C4 |  00000624 | ARABIC LETTER WAW WITH HAMZA ABOVE
     C5 |  00000625 | ARABIC LETTER ALEF WITH HAMZA BELOW
     C6 |  00000626 | ARABIC LETTER YEH WITH HAMZA ABOVE
     C7 |  00000627 | ARABIC LETTER ALEF
     C8 |  00000628 | ARABIC LETTER BEH
     C9 |  00000629 | ARABIC LETTER TEH MARBUTA
     CA |  0000062A | ARABIC LETTER TEH
     CB |  0000062B | ARABIC LETTER THEH
     CC |  0000062C | ARABIC LETTER JEEM
     CD |  0000062D | ARABIC LETTER HAH
     CE |  0000062E | ARABIC LETTER KHAH
     CF |  0000062F | ARABIC LETTER DAL
     D0 |  00000630 | ARABIC LETTER THAL
     D1 |  00000631 | ARABIC LETTER REH
     D2 |  00000632 | ARABIC LETTER ZAIN
     D3 |  00000633 | ARABIC LETTER SEEN
     D4 |  00000634 | ARABIC LETTER SHEEN
     D5 |  00000635 | ARABIC LETTER SAD
     D6 |  00000636 | ARABIC LETTER DAD
     D7 |  00000637 | ARABIC LETTER TAH
     D8 |  00000638 | ARABIC LETTER ZAH
     D9 |  00000639 | ARABIC LETTER AIN
     DA |  0000063A | ARABIC LETTER GHAIN
     E0 |  00000640 | ARABIC TATWEEL
     E1 |  00000641 | ARABIC LETTER FEH
     E2 |  00000642 | ARABIC LETTER QAF
     E3 |  00000643 | ARABIC LETTER KAF
     E4 |  00000644 | ARABIC LETTER LAM
     E5 |  00000645 | ARABIC LETTER MEEM
     E6 |  00000646 | ARABIC LETTER NOON
     E7 |  00000647 | ARABIC LETTER HEH
     E8 |  00000648 | ARABIC LETTER WAW
     E9 |  00000649 | ARABIC LETTER ALEF MAKSURA
     EA |  0000064A | ARABIC LETTER YEH
     EB |  0000064B | ARABIC FATHATAN
     EC |  0000064C | ARABIC DAMMATAN
     ED |  0000064D | ARABIC KASRATAN
     EE |  0000064E | ARABIC FATHA
     EF |  0000064F | ARABIC DAMMA
     F0 |  00000650 | ARABIC KASRA
     F1 |  00000651 | ARABIC SHADDA
     F2 |  00000652 | ARABIC SUKUN
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/ISO_8859_7.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for ISO-8859-7.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::ISO_8859_7;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x0004,
     0x0005,
     0x0006,
     0x0007,
     0x0008,
     0x0009,
     0x000a,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x0014,
     0x0015,
     0x0016,
     0x0017,
     0x0018,
     0x0019,
     0x001a,
     0x001b,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0020,
     0x0021,
     0x0022,
     0x0023,
     0x0024,
     0x0025,
     0x0026,
     0x0027,
     0x0028,
     0x0029,
     0x002a,
     0x002b,
     0x002c,
     0x002d,
     0x002e,
     0x002f,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x003a,
     0x003b,
     0x003c,
     0x003d,
     0x003e,
     0x003f,
     0x0040,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x005b,
     0x005c,
     0x005d,
     0x005e,
     0x005f,
     0x0060,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x007b,
     0x007c,
     0x007d,
     0x007e,
     0x007f,
     0x0080,
     0x0081,
     0x0082,
     0x0083,
     0x0084,
     0x0085,
     0x0086,
     0x0087,
     0x0088,
     0x0089,
     0x008a,
     0x008b,
     0x008c,
     0x008d,
     0x008e,
     0x008f,
     0x0090,
     0x0091,
     0x0092,
     0x0093,
     0x0094,
     0x0095,
     0x0096,
     0x0097,
     0x0098,
     0x0099,
     0x009a,
     0x009b,
     0x009c,
     0x009d,
     0x009e,
     0x009f,
     0x00a0,
     0x2018,
     0x2019,
     0x00a3,
     0xfffd,
     0xfffd,
     0x00a6,
     0x00a7,
     0x00a8,
     0x00a9,
     0xfffd,
     0x00ab,
     0x00ac,
     0x00ad,
     0xfffd,
     0x2015,
     0x00b0,
     0x00b1,
     0x00b2,
     0x00b3,
     0x0384,
     0x0385,
     0x0386,
     0x00b7,
     0x0388,
     0x0389,
     0x038a,
     0x00bb,
     0x038c,
     0x00bd,
     0x038e,
     0x038f,
     0x0390,
     0x0391,
     0x0392,
     0x0393,
     0x0394,
     0x0395,
     0x0396,
     0x0397,
     0x0398,
     0x0399,
     0x039a,
     0x039b,
     0x039c,
     0x039d,
     0x039e,
     0x039f,
     0x03a0,
     0x03a1,
     0xfffd,
     0x03a3,
     0x03a4,
     0x03a5,
     0x03a6,
     0x03a7,
     0x03a8,
     0x03a9,
     0x03aa,
     0x03ab,
     0x03ac,
     0x03ad,
     0x03ae,
     0x03af,
     0x03b0,
     0x03b1,
     0x03b2,
     0x03b3,
     0x03b4,
     0x03b5,
     0x03b6,
     0x03b7,
     0x03b8,
     0x03b9,
     0x03ba,
     0x03bb,
     0x03bc,
     0x03bd,
     0x03be,
     0x03bf,
     0x03c0,
     0x03c1,
     0x03c2,
     0x03c3,
     0x03c4,
     0x03c5,
     0x03c6,
     0x03c7,
     0x03c8,
     0x03c9,
     0x03ca,
     0x03cb,
     0x03cc,
     0x03cd,
     0x03ce,
     0xfffd,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\x04",
     "\x05",
     "\x06",
     "\x07",
     "\x08",
     "\x09",
     "\x0a",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\x14",
     "\x15",
     "\x16",
     "\x17",
     "\x18",
     "\x19",
     "\x1a",
     "\x1b",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\x20",
     "\x21",
     "\x22",
     "\x23",
     "\x24",
     "\x25",
     "\x26",
     "\x27",
     "\x28",
     "\x29",
     "\x2a",
     "\x2b",
     "\x2c",
     "\x2d",
     "\x2e",
     "\x2f",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\x3a",
     "\x3b",
     "\x3c",
     "\x3d",
     "\x3e",
     "\x3f",
     "\x40",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\x5b",
     "\x5c",
     "\x5d",
     "\x5e",
     "\x5f",
     "\x60",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\x7b",
     "\x7c",
     "\x7d",
     "\x7e",
     "\x7f",
     "\xc2\x80",
     "\xc2\x81",
     "\xc2\x82",
     "\xc2\x83",
     "\xc2\x84",
     "\xc2\x85",
     "\xc2\x86",
     "\xc2\x87",
     "\xc2\x88",
     "\xc2\x89",
     "\xc2\x8a",
     "\xc2\x8b",
     "\xc2\x8c",
     "\xc2\x8d",
     "\xc2\x8e",
     "\xc2\x8f",
     "\xc2\x90",
     "\xc2\x91",
     "\xc2\x92",
     "\xc2\x93",
     "\xc2\x94",
     "\xc2\x95",
     "\xc2\x96",
     "\xc2\x97",
     "\xc2\x98",
     "\xc2\x99",
     "\xc2\x9a",
     "\xc2\x9b",
     "\xc2\x9c",
     "\xc2\x9d",
     "\xc2\x9e",
     "\xc2\x9f",
     "\xc2\xa0",
     "\xe2\x80\x98",
     "\xe2\x80\x99",
     "\xc2\xa3",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc2\xa6",
     "\xc2\xa7",
     "\xc2\xa8",
     "\xc2\xa9",
     "\xef\xbf\xbd",
     "\xc2\xab",
     "\xc2\xac",
     "\xc2\xad",
     "\xef\xbf\xbd",
     "\xe2\x80\x95",
     "\xc2\xb0",
     "\xc2\xb1",
     "\xc2\xb2",
     "\xc2\xb3",
     "\xce\x84",
     "\xce\x85",
     "\xce\x86",
     "\xc2\xb7",
     "\xce\x88",
     "\xce\x89",
     "\xce\x8a",
     "\xc2\xbb",
     "\xce\x8c",
     "\xc2\xbd",
     "\xce\x8e",
     "\xce\x8f",
     "\xce\x90",
     "\xce\x91",
     "\xce\x92",
     "\xce\x93",
     "\xce\x94",
     "\xce\x95",
     "\xce\x96",
     "\xce\x97",
     "\xce\x98",
     "\xce\x99",
     "\xce\x9a",
     "\xce\x9b",
     "\xce\x9c",
     "\xce\x9d",
     "\xce\x9e",
     "\xce\x9f",
     "\xce\xa0",
     "\xce\xa1",
     "\xef\xbf\xbd",
     "\xce\xa3",
     "\xce\xa4",
     "\xce\xa5",
     "\xce\xa6",
     "\xce\xa7",
     "\xce\xa8",
     "\xce\xa9",
     "\xce\xaa",
     "\xce\xab",
     "\xce\xac",
     "\xce\xad",
     "\xce\xae",
     "\xce\xaf",
     "\xce\xb0",
     "\xce\xb1",
     "\xce\xb2",
     "\xce\xb3",
     "\xce\xb4",
     "\xce\xb5",
     "\xce\xb6",
     "\xce\xb7",
     "\xce\xb8",
     "\xce\xb9",
     "\xce\xba",
     "\xce\xbb",
     "\xce\xbc",
     "\xce\xbd",
     "\xce\xbe",
     "\xce\xbf",
     "\xcf\x80",
     "\xcf\x81",
     "\xcf\x82",
     "\xcf\x83",
     "\xcf\x84",
     "\xcf\x85",
     "\xcf\x86",
     "\xcf\x87",
     "\xcf\x88",
     "\xcf\x89",
     "\xcf\x8a",
     "\xcf\x8b",
     "\xcf\x8c",
     "\xcf\x8d",
     "\xcf\x8e",
     "\xef\xbf\xbd",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x04",
     0x00000005 => "\x05",
     0x00000006 => "\x06",
     0x00000007 => "\x07",
     0x00000008 => "\x08",
     0x00000009 => "\x09",
     0x0000000a => "\x0a",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x14",
     0x00000015 => "\x15",
     0x00000016 => "\x16",
     0x00000017 => "\x17",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x1a",
     0x0000001b => "\x1b",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x20",
     0x00000021 => "\x21",
     0x00000022 => "\x22",
     0x00000023 => "\x23",
     0x00000024 => "\x24",
     0x00000025 => "\x25",
     0x00000026 => "\x26",
     0x00000027 => "\x27",
     0x00000028 => "\x28",
     0x00000029 => "\x29",
     0x0000002a => "\x2a",
     0x0000002b => "\x2b",
     0x0000002c => "\x2c",
     0x0000002d => "\x2d",
     0x0000002e => "\x2e",
     0x0000002f => "\x2f",
     0x00000030 => "\x30",
     0x00000031 => "\x31",
     0x00000032 => "\x32",
     0x00000033 => "\x33",
     0x00000034 => "\x34",
     0x00000035 => "\x35",
     0x00000036 => "\x36",
     0x00000037 => "\x37",
     0x00000038 => "\x38",
     0x00000039 => "\x39",
     0x0000003a => "\x3a",
     0x0000003b => "\x3b",
     0x0000003c => "\x3c",
     0x0000003d => "\x3d",
     0x0000003e => "\x3e",
     0x0000003f => "\x3f",
     0x00000040 => "\x40",
     0x00000041 => "\x41",
     0x00000042 => "\x42",
     0x00000043 => "\x43",
     0x00000044 => "\x44",
     0x00000045 => "\x45",
     0x00000046 => "\x46",
     0x00000047 => "\x47",
     0x00000048 => "\x48",
     0x00000049 => "\x49",
     0x0000004a => "\x4a",
     0x0000004b => "\x4b",
     0x0000004c => "\x4c",
     0x0000004d => "\x4d",
     0x0000004e => "\x4e",
     0x0000004f => "\x4f",
     0x00000050 => "\x50",
     0x00000051 => "\x51",
     0x00000052 => "\x52",
     0x00000053 => "\x53",
     0x00000054 => "\x54",
     0x00000055 => "\x55",
     0x00000056 => "\x56",
     0x00000057 => "\x57",
     0x00000058 => "\x58",
     0x00000059 => "\x59",
     0x0000005a => "\x5a",
     0x0000005b => "\x5b",
     0x0000005c => "\x5c",
     0x0000005d => "\x5d",
     0x0000005e => "\x5e",
     0x0000005f => "\x5f",
     0x00000060 => "\x60",
     0x00000061 => "\x61",
     0x00000062 => "\x62",
     0x00000063 => "\x63",
     0x00000064 => "\x64",
     0x00000065 => "\x65",
     0x00000066 => "\x66",
     0x00000067 => "\x67",
     0x00000068 => "\x68",
     0x00000069 => "\x69",
     0x0000006a => "\x6a",
     0x0000006b => "\x6b",
     0x0000006c => "\x6c",
     0x0000006d => "\x6d",
     0x0000006e => "\x6e",
     0x0000006f => "\x6f",
     0x00000070 => "\x70",
     0x00000071 => "\x71",
     0x00000072 => "\x72",
     0x00000073 => "\x73",
     0x00000074 => "\x74",
     0x00000075 => "\x75",
     0x00000076 => "\x76",
     0x00000077 => "\x77",
     0x00000078 => "\x78",
     0x00000079 => "\x79",
     0x0000007a => "\x7a",
     0x0000007b => "\x7b",
     0x0000007c => "\x7c",
     0x0000007d => "\x7d",
     0x0000007e => "\x7e",
     0x0000007f => "\x7f",
     0x00000080 => "\x80",
     0x00000081 => "\x81",
     0x00000082 => "\x82",
     0x00000083 => "\x83",
     0x00000084 => "\x84",
     0x00000085 => "\x85",
     0x00000086 => "\x86",
     0x00000087 => "\x87",
     0x00000088 => "\x88",
     0x00000089 => "\x89",
     0x0000008a => "\x8a",
     0x0000008b => "\x8b",
     0x0000008c => "\x8c",
     0x0000008d => "\x8d",
     0x0000008e => "\x8e",
     0x0000008f => "\x8f",
     0x00000090 => "\x90",
     0x00000091 => "\x91",
     0x00000092 => "\x92",
     0x00000093 => "\x93",
     0x00000094 => "\x94",
     0x00000095 => "\x95",
     0x00000096 => "\x96",
     0x00000097 => "\x97",
     0x00000098 => "\x98",
     0x00000099 => "\x99",
     0x0000009a => "\x9a",
     0x0000009b => "\x9b",
     0x0000009c => "\x9c",
     0x0000009d => "\x9d",
     0x0000009e => "\x9e",
     0x0000009f => "\x9f",
     0x000000a0 => "\xa0",
     0x000000a3 => "\xa3",
     0x000000a6 => "\xa6",
     0x000000a7 => "\xa7",
     0x000000a8 => "\xa8",
     0x000000a9 => "\xa9",
     0x000000ab => "\xab",
     0x000000ac => "\xac",
     0x000000ad => "\xad",
     0x000000b0 => "\xb0",
     0x000000b1 => "\xb1",
     0x000000b2 => "\xb2",
     0x000000b3 => "\xb3",
     0x000000b7 => "\xb7",
     0x000000bb => "\xbb",
     0x000000bd => "\xbd",
     0x00000384 => "\xb4",
     0x00000385 => "\xb5",
     0x00000386 => "\xb6",
     0x00000388 => "\xb8",
     0x00000389 => "\xb9",
     0x0000038a => "\xba",
     0x0000038c => "\xbc",
     0x0000038e => "\xbe",
     0x0000038f => "\xbf",
     0x00000390 => "\xc0",
     0x00000391 => "\xc1",
     0x00000392 => "\xc2",
     0x00000393 => "\xc3",
     0x00000394 => "\xc4",
     0x00000395 => "\xc5",
     0x00000396 => "\xc6",
     0x00000397 => "\xc7",
     0x00000398 => "\xc8",
     0x00000399 => "\xc9",
     0x0000039a => "\xca",
     0x0000039b => "\xcb",
     0x0000039c => "\xcc",
     0x0000039d => "\xcd",
     0x0000039e => "\xce",
     0x0000039f => "\xcf",
     0x000003a0 => "\xd0",
     0x000003a1 => "\xd1",
     0x000003a3 => "\xd3",
     0x000003a4 => "\xd4",
     0x000003a5 => "\xd5",
     0x000003a6 => "\xd6",
     0x000003a7 => "\xd7",
     0x000003a8 => "\xd8",
     0x000003a9 => "\xd9",
     0x000003aa => "\xda",
     0x000003ab => "\xdb",
     0x000003ac => "\xdc",
     0x000003ad => "\xdd",
     0x000003ae => "\xde",
     0x000003af => "\xdf",
     0x000003b0 => "\xe0",
     0x000003b1 => "\xe1",
     0x000003b2 => "\xe2",
     0x000003b3 => "\xe3",
     0x000003b4 => "\xe4",
     0x000003b5 => "\xe5",
     0x000003b6 => "\xe6",
     0x000003b7 => "\xe7",
     0x000003b8 => "\xe8",
     0x000003b9 => "\xe9",
     0x000003ba => "\xea",
     0x000003bb => "\xeb",
     0x000003bc => "\xec",
     0x000003bd => "\xed",
     0x000003be => "\xee",
     0x000003bf => "\xef",
     0x000003c0 => "\xf0",
     0x000003c1 => "\xf1",
     0x000003c2 => "\xf2",
     0x000003c3 => "\xf3",
     0x000003c4 => "\xf4",
     0x000003c5 => "\xf5",
     0x000003c6 => "\xf6",
     0x000003c7 => "\xf7",
     0x000003c8 => "\xf8",
     0x000003c9 => "\xf9",
     0x000003ca => "\xfa",
     0x000003cb => "\xfb",
     0x000003cc => "\xfc",
     0x000003cd => "\xfd",
     0x000003ce => "\xfe",
     0x00002015 => "\xaf",
     0x00002018 => "\xa1",
     0x00002019 => "\xa2",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::ISO_8859_7 - Conversion routines for ISO-8859-7
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for ISO-8859-7.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
   source: ECMA registry
  alias ISO-IR-126
  alias ISO_8859-7:1987
  alias ISO_8859-7
  alias ELOT_928
  alias ECMA-118
  alias GREEK
  alias GREEK8
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  00000004 | END OF TRANSMISSION (EOT)
     05 |  00000005 | ENQUIRY (ENQ)
     06 |  00000006 | ACKNOWLEDGE (ACK)
     07 |  00000007 | BELL (BEL)
     08 |  00000008 | BACKSPACE (BS)
     09 |  00000009 | CHARACTER TABULATION (HT)
     0A |  0000000A | LINE FEED (LF)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  00000014 | DEVICE CONTROL FOUR (DC4)
     15 |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     16 |  00000016 | SYNCHRONOUS IDLE (SYN)
     17 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  0000001A | SUBSTITUTE (SUB)
     1B |  0000001B | ESCAPE (ESC)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000020 | SPACE
     21 |  00000021 | EXCLAMATION MARK
     22 |  00000022 | QUOTATION MARK
     23 |  00000023 | NUMBER SIGN
     24 |  00000024 | DOLLAR SIGN
     25 |  00000025 | PERCENT SIGN
     26 |  00000026 | AMPERSAND
     27 |  00000027 | APOSTROPHE
     28 |  00000028 | LEFT PARENTHESIS
     29 |  00000029 | RIGHT PARENTHESIS
     2A |  0000002A | ASTERISK
     2B |  0000002B | PLUS SIGN
     2C |  0000002C | COMMA
     2D |  0000002D | HYPHEN-MINUS
     2E |  0000002E | FULL STOP
     2F |  0000002F | SOLIDUS
     30 |  00000030 | DIGIT ZERO
     31 |  00000031 | DIGIT ONE
     32 |  00000032 | DIGIT TWO
     33 |  00000033 | DIGIT THREE
     34 |  00000034 | DIGIT FOUR
     35 |  00000035 | DIGIT FIVE
     36 |  00000036 | DIGIT SIX
     37 |  00000037 | DIGIT SEVEN
     38 |  00000038 | DIGIT EIGHT
     39 |  00000039 | DIGIT NINE
     3A |  0000003A | COLON
     3B |  0000003B | SEMICOLON
     3C |  0000003C | LESS-THAN SIGN
     3D |  0000003D | EQUALS SIGN
     3E |  0000003E | GREATER-THAN SIGN
     3F |  0000003F | QUESTION MARK
     40 |  00000040 | COMMERCIAL AT
     41 |  00000041 | LATIN CAPITAL LETTER A
     42 |  00000042 | LATIN CAPITAL LETTER B
     43 |  00000043 | LATIN CAPITAL LETTER C
     44 |  00000044 | LATIN CAPITAL LETTER D
     45 |  00000045 | LATIN CAPITAL LETTER E
     46 |  00000046 | LATIN CAPITAL LETTER F
     47 |  00000047 | LATIN CAPITAL LETTER G
     48 |  00000048 | LATIN CAPITAL LETTER H
     49 |  00000049 | LATIN CAPITAL LETTER I
     4A |  0000004A | LATIN CAPITAL LETTER J
     4B |  0000004B | LATIN CAPITAL LETTER K
     4C |  0000004C | LATIN CAPITAL LETTER L
     4D |  0000004D | LATIN CAPITAL LETTER M
     4E |  0000004E | LATIN CAPITAL LETTER N
     4F |  0000004F | LATIN CAPITAL LETTER O
     50 |  00000050 | LATIN CAPITAL LETTER P
     51 |  00000051 | LATIN CAPITAL LETTER Q
     52 |  00000052 | LATIN CAPITAL LETTER R
     53 |  00000053 | LATIN CAPITAL LETTER S
     54 |  00000054 | LATIN CAPITAL LETTER T
     55 |  00000055 | LATIN CAPITAL LETTER U
     56 |  00000056 | LATIN CAPITAL LETTER V
     57 |  00000057 | LATIN CAPITAL LETTER W
     58 |  00000058 | LATIN CAPITAL LETTER X
     59 |  00000059 | LATIN CAPITAL LETTER Y
     5A |  0000005A | LATIN CAPITAL LETTER Z
     5B |  0000005B | LEFT SQUARE BRACKET
     5C |  0000005C | REVERSE SOLIDUS
     5D |  0000005D | RIGHT SQUARE BRACKET
     5E |  0000005E | CIRCUMFLEX ACCENT
     5F |  0000005F | LOW LINE
     60 |  00000060 | GRAVE ACCENT
     61 |  00000061 | LATIN SMALL LETTER A
     62 |  00000062 | LATIN SMALL LETTER B
     63 |  00000063 | LATIN SMALL LETTER C
     64 |  00000064 | LATIN SMALL LETTER D
     65 |  00000065 | LATIN SMALL LETTER E
     66 |  00000066 | LATIN SMALL LETTER F
     67 |  00000067 | LATIN SMALL LETTER G
     68 |  00000068 | LATIN SMALL LETTER H
     69 |  00000069 | LATIN SMALL LETTER I
     6A |  0000006A | LATIN SMALL LETTER J
     6B |  0000006B | LATIN SMALL LETTER K
     6C |  0000006C | LATIN SMALL LETTER L
     6D |  0000006D | LATIN SMALL LETTER M
     6E |  0000006E | LATIN SMALL LETTER N
     6F |  0000006F | LATIN SMALL LETTER O
     70 |  00000070 | LATIN SMALL LETTER P
     71 |  00000071 | LATIN SMALL LETTER Q
     72 |  00000072 | LATIN SMALL LETTER R
     73 |  00000073 | LATIN SMALL LETTER S
     74 |  00000074 | LATIN SMALL LETTER T
     75 |  00000075 | LATIN SMALL LETTER U
     76 |  00000076 | LATIN SMALL LETTER V
     77 |  00000077 | LATIN SMALL LETTER W
     78 |  00000078 | LATIN SMALL LETTER X
     79 |  00000079 | LATIN SMALL LETTER Y
     7A |  0000007A | LATIN SMALL LETTER Z
     7B |  0000007B | LEFT CURLY BRACKET
     7C |  0000007C | VERTICAL LINE
     7D |  0000007D | RIGHT CURLY BRACKET
     7E |  0000007E | TILDE
     7F |  0000007F | DELETE (DEL)
     80 |  00000080 | PADDING CHARACTER (PAD)
     81 |  00000081 | HIGH OCTET PRESET (HOP)
     82 |  00000082 | BREAK PERMITTED HERE (BPH)
     83 |  00000083 | NO BREAK HERE (NBH)
     84 |  00000084 | INDEX (IND)
     85 |  00000085 | NEXT LINE (NEL)
     86 |  00000086 | START OF SELECTED AREA (SSA)
     87 |  00000087 | END OF SELECTED AREA (ESA)
     88 |  00000088 | CHARACTER TABULATION SET (HTS)
     89 |  00000089 | CHARACTER TABULATION WITH JUSTIFICATION (HTJ)
     8A |  0000008A | LINE TABULATION SET (VTS)
     8B |  0000008B | PARTIAL LINE FORWARD (PLD)
     8C |  0000008C | PARTIAL LINE BACKWARD (PLU)
     8D |  0000008D | REVERSE LINE FEED (RI)
     8E |  0000008E | SINGLE-SHIFT TWO (SS2)
     8F |  0000008F | SINGLE-SHIFT THREE (SS3)
     90 |  00000090 | DEVICE CONTROL STRING (DCS)
     91 |  00000091 | PRIVATE USE ONE (PU1)
     92 |  00000092 | PRIVATE USE TWO (PU2)
     93 |  00000093 | SET TRANSMIT STATE (STS)
     94 |  00000094 | CANCEL CHARACTER (CCH)
     95 |  00000095 | MESSAGE WAITING (MW)
     96 |  00000096 | START OF GUARDED AREA (SPA)
     97 |  00000097 | END OF GUARDED AREA (EPA)
     98 |  00000098 | START OF STRING (SOS)
     99 |  00000099 | SINGLE GRAPHIC CHARACTER INTRODUCER (SGCI)
     9A |  0000009A | SINGLE CHARACTER INTRODUCER (SCI)
     9B |  0000009B | CONTROL SEQUENCE INTRODUCER (CSI)
     9C |  0000009C | STRING TERMINATOR (ST)
     9D |  0000009D | OPERATING SYSTEM COMMAND (OSC)
     9E |  0000009E | PRIVACY MESSAGE (PM)
     9F |  0000009F | APPLICATION PROGRAM COMMAND (APC)
     A0 |  000000A0 | NO-BREAK SPACE
     A1 |  00002018 | LEFT SINGLE QUOTATION MARK
     A2 |  00002019 | RIGHT SINGLE QUOTATION MARK
     A3 |  000000A3 | POUND SIGN
     A6 |  000000A6 | BROKEN BAR
     A7 |  000000A7 | SECTION SIGN
     A8 |  000000A8 | DIAERESIS
     A9 |  000000A9 | COPYRIGHT SIGN
     AB |  000000AB | LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
     AC |  000000AC | NOT SIGN
     AD |  000000AD | SOFT HYPHEN
     AF |  00002015 | HORIZONTAL BAR
     B0 |  000000B0 | DEGREE SIGN
     B1 |  000000B1 | PLUS-MINUS SIGN
     B2 |  000000B2 | SUPERSCRIPT TWO
     B3 |  000000B3 | SUPERSCRIPT THREE
     B4 |  00000384 | GREEK TONOS
     B5 |  00000385 | GREEK DIALYTIKA TONOS
     B6 |  00000386 | GREEK CAPITAL LETTER ALPHA WITH TONOS
     B7 |  000000B7 | MIDDLE DOT
     B8 |  00000388 | GREEK CAPITAL LETTER EPSILON WITH TONOS
     B9 |  00000389 | GREEK CAPITAL LETTER ETA WITH TONOS
     BA |  0000038A | GREEK CAPITAL LETTER IOTA WITH TONOS
     BB |  000000BB | RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
     BC |  0000038C | GREEK CAPITAL LETTER OMICRON WITH TONOS
     BD |  000000BD | VULGAR FRACTION ONE HALF
     BE |  0000038E | GREEK CAPITAL LETTER UPSILON WITH TONOS
     BF |  0000038F | GREEK CAPITAL LETTER OMEGA WITH TONOS
     C0 |  00000390 | GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS
     C1 |  00000391 | GREEK CAPITAL LETTER ALPHA
     C2 |  00000392 | GREEK CAPITAL LETTER BETA
     C3 |  00000393 | GREEK CAPITAL LETTER GAMMA
     C4 |  00000394 | GREEK CAPITAL LETTER DELTA
     C5 |  00000395 | GREEK CAPITAL LETTER EPSILON
     C6 |  00000396 | GREEK CAPITAL LETTER ZETA
     C7 |  00000397 | GREEK CAPITAL LETTER ETA
     C8 |  00000398 | GREEK CAPITAL LETTER THETA
     C9 |  00000399 | GREEK CAPITAL LETTER IOTA
     CA |  0000039A | GREEK CAPITAL LETTER KAPPA
     CB |  0000039B | GREEK CAPITAL LETTER LAMDA
     CC |  0000039C | GREEK CAPITAL LETTER MU
     CD |  0000039D | GREEK CAPITAL LETTER NU
     CE |  0000039E | GREEK CAPITAL LETTER XI
     CF |  0000039F | GREEK CAPITAL LETTER OMICRON
     D0 |  000003A0 | GREEK CAPITAL LETTER PI
     D1 |  000003A1 | GREEK CAPITAL LETTER RHO
     D3 |  000003A3 | GREEK CAPITAL LETTER SIGMA
     D4 |  000003A4 | GREEK CAPITAL LETTER TAU
     D5 |  000003A5 | GREEK CAPITAL LETTER UPSILON
     D6 |  000003A6 | GREEK CAPITAL LETTER PHI
     D7 |  000003A7 | GREEK CAPITAL LETTER CHI
     D8 |  000003A8 | GREEK CAPITAL LETTER PSI
     D9 |  000003A9 | GREEK CAPITAL LETTER OMEGA
     DA |  000003AA | GREEK CAPITAL LETTER IOTA WITH DIALYTIKA
     DB |  000003AB | GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA
     DC |  000003AC | GREEK SMALL LETTER ALPHA WITH TONOS
     DD |  000003AD | GREEK SMALL LETTER EPSILON WITH TONOS
     DE |  000003AE | GREEK SMALL LETTER ETA WITH TONOS
     DF |  000003AF | GREEK SMALL LETTER IOTA WITH TONOS
     E0 |  000003B0 | GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS
     E1 |  000003B1 | GREEK SMALL LETTER ALPHA
     E2 |  000003B2 | GREEK SMALL LETTER BETA
     E3 |  000003B3 | GREEK SMALL LETTER GAMMA
     E4 |  000003B4 | GREEK SMALL LETTER DELTA
     E5 |  000003B5 | GREEK SMALL LETTER EPSILON
     E6 |  000003B6 | GREEK SMALL LETTER ZETA
     E7 |  000003B7 | GREEK SMALL LETTER ETA
     E8 |  000003B8 | GREEK SMALL LETTER THETA
     E9 |  000003B9 | GREEK SMALL LETTER IOTA
     EA |  000003BA | GREEK SMALL LETTER KAPPA
     EB |  000003BB | GREEK SMALL LETTER LAMDA
     EC |  000003BC | GREEK SMALL LETTER MU
     ED |  000003BD | GREEK SMALL LETTER NU
     EE |  000003BE | GREEK SMALL LETTER XI
     EF |  000003BF | GREEK SMALL LETTER OMICRON
     F0 |  000003C0 | GREEK SMALL LETTER PI
     F1 |  000003C1 | GREEK SMALL LETTER RHO
     F2 |  000003C2 | GREEK SMALL LETTER FINAL SIGMA
     F3 |  000003C3 | GREEK SMALL LETTER SIGMA
     F4 |  000003C4 | GREEK SMALL LETTER TAU
     F5 |  000003C5 | GREEK SMALL LETTER UPSILON
     F6 |  000003C6 | GREEK SMALL LETTER PHI
     F7 |  000003C7 | GREEK SMALL LETTER CHI
     F8 |  000003C8 | GREEK SMALL LETTER PSI
     F9 |  000003C9 | GREEK SMALL LETTER OMEGA
     FA |  000003CA | GREEK SMALL LETTER IOTA WITH DIALYTIKA
     FB |  000003CB | GREEK SMALL LETTER UPSILON WITH DIALYTIKA
     FC |  000003CC | GREEK SMALL LETTER OMICRON WITH TONOS
     FD |  000003CD | GREEK SMALL LETTER UPSILON WITH TONOS
     FE |  000003CE | GREEK SMALL LETTER OMEGA WITH TONOS
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/ISO_8859_8.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for ISO-8859-8.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::ISO_8859_8;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x0004,
     0x0005,
     0x0006,
     0x0007,
     0x0008,
     0x0009,
     0x000a,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x0014,
     0x0015,
     0x0016,
     0x0017,
     0x0018,
     0x0019,
     0x001a,
     0x001b,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0020,
     0x0021,
     0x0022,
     0x0023,
     0x0024,
     0x0025,
     0x0026,
     0x0027,
     0x0028,
     0x0029,
     0x002a,
     0x002b,
     0x002c,
     0x002d,
     0x002e,
     0x002f,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x003a,
     0x003b,
     0x003c,
     0x003d,
     0x003e,
     0x003f,
     0x0040,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x005b,
     0x005c,
     0x005d,
     0x005e,
     0x005f,
     0x0060,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x007b,
     0x007c,
     0x007d,
     0x007e,
     0x007f,
     0x0080,
     0x0081,
     0x0082,
     0x0083,
     0x0084,
     0x0085,
     0x0086,
     0x0087,
     0x0088,
     0x0089,
     0x008a,
     0x008b,
     0x008c,
     0x008d,
     0x008e,
     0x008f,
     0x0090,
     0x0091,
     0x0092,
     0x0093,
     0x0094,
     0x0095,
     0x0096,
     0x0097,
     0x0098,
     0x0099,
     0x009a,
     0x009b,
     0x009c,
     0x009d,
     0x009e,
     0x009f,
     0x00a0,
     0xfffd,
     0x00a2,
     0x00a3,
     0x00a4,
     0x00a5,
     0x00a6,
     0x00a7,
     0x00a8,
     0x00a9,
     0x00d7,
     0x00ab,
     0x00ac,
     0x00ad,
     0x00ae,
     0x00af,
     0x00b0,
     0x00b1,
     0x00b2,
     0x00b3,
     0x00b4,
     0x00b5,
     0x00b6,
     0x00b7,
     0x00b8,
     0x00b9,
     0x00f7,
     0x00bb,
     0x00bc,
     0x00bd,
     0x00be,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x2017,
     0x05d0,
     0x05d1,
     0x05d2,
     0x05d3,
     0x05d4,
     0x05d5,
     0x05d6,
     0x05d7,
     0x05d8,
     0x05d9,
     0x05da,
     0x05db,
     0x05dc,
     0x05dd,
     0x05de,
     0x05df,
     0x05e0,
     0x05e1,
     0x05e2,
     0x05e3,
     0x05e4,
     0x05e5,
     0x05e6,
     0x05e7,
     0x05e8,
     0x05e9,
     0x05ea,
     0xfffd,
     0xfffd,
     0x200e,
     0x200f,
     0xfffd,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\x04",
     "\x05",
     "\x06",
     "\x07",
     "\x08",
     "\x09",
     "\x0a",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\x14",
     "\x15",
     "\x16",
     "\x17",
     "\x18",
     "\x19",
     "\x1a",
     "\x1b",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\x20",
     "\x21",
     "\x22",
     "\x23",
     "\x24",
     "\x25",
     "\x26",
     "\x27",
     "\x28",
     "\x29",
     "\x2a",
     "\x2b",
     "\x2c",
     "\x2d",
     "\x2e",
     "\x2f",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\x3a",
     "\x3b",
     "\x3c",
     "\x3d",
     "\x3e",
     "\x3f",
     "\x40",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\x5b",
     "\x5c",
     "\x5d",
     "\x5e",
     "\x5f",
     "\x60",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\x7b",
     "\x7c",
     "\x7d",
     "\x7e",
     "\x7f",
     "\xc2\x80",
     "\xc2\x81",
     "\xc2\x82",
     "\xc2\x83",
     "\xc2\x84",
     "\xc2\x85",
     "\xc2\x86",
     "\xc2\x87",
     "\xc2\x88",
     "\xc2\x89",
     "\xc2\x8a",
     "\xc2\x8b",
     "\xc2\x8c",
     "\xc2\x8d",
     "\xc2\x8e",
     "\xc2\x8f",
     "\xc2\x90",
     "\xc2\x91",
     "\xc2\x92",
     "\xc2\x93",
     "\xc2\x94",
     "\xc2\x95",
     "\xc2\x96",
     "\xc2\x97",
     "\xc2\x98",
     "\xc2\x99",
     "\xc2\x9a",
     "\xc2\x9b",
     "\xc2\x9c",
     "\xc2\x9d",
     "\xc2\x9e",
     "\xc2\x9f",
     "\xc2\xa0",
     "\xef\xbf\xbd",
     "\xc2\xa2",
     "\xc2\xa3",
     "\xc2\xa4",
     "\xc2\xa5",
     "\xc2\xa6",
     "\xc2\xa7",
     "\xc2\xa8",
     "\xc2\xa9",
     "\xc3\x97",
     "\xc2\xab",
     "\xc2\xac",
     "\xc2\xad",
     "\xc2\xae",
     "\xc2\xaf",
     "\xc2\xb0",
     "\xc2\xb1",
     "\xc2\xb2",
     "\xc2\xb3",
     "\xc2\xb4",
     "\xc2\xb5",
     "\xc2\xb6",
     "\xc2\xb7",
     "\xc2\xb8",
     "\xc2\xb9",
     "\xc3\xb7",
     "\xc2\xbb",
     "\xc2\xbc",
     "\xc2\xbd",
     "\xc2\xbe",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xe2\x80\x97",
     "\xd7\x90",
     "\xd7\x91",
     "\xd7\x92",
     "\xd7\x93",
     "\xd7\x94",
     "\xd7\x95",
     "\xd7\x96",
     "\xd7\x97",
     "\xd7\x98",
     "\xd7\x99",
     "\xd7\x9a",
     "\xd7\x9b",
     "\xd7\x9c",
     "\xd7\x9d",
     "\xd7\x9e",
     "\xd7\x9f",
     "\xd7\xa0",
     "\xd7\xa1",
     "\xd7\xa2",
     "\xd7\xa3",
     "\xd7\xa4",
     "\xd7\xa5",
     "\xd7\xa6",
     "\xd7\xa7",
     "\xd7\xa8",
     "\xd7\xa9",
     "\xd7\xaa",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xe2\x80\x8e",
     "\xe2\x80\x8f",
     "\xef\xbf\xbd",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x04",
     0x00000005 => "\x05",
     0x00000006 => "\x06",
     0x00000007 => "\x07",
     0x00000008 => "\x08",
     0x00000009 => "\x09",
     0x0000000a => "\x0a",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x14",
     0x00000015 => "\x15",
     0x00000016 => "\x16",
     0x00000017 => "\x17",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x1a",
     0x0000001b => "\x1b",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x20",
     0x00000021 => "\x21",
     0x00000022 => "\x22",
     0x00000023 => "\x23",
     0x00000024 => "\x24",
     0x00000025 => "\x25",
     0x00000026 => "\x26",
     0x00000027 => "\x27",
     0x00000028 => "\x28",
     0x00000029 => "\x29",
     0x0000002a => "\x2a",
     0x0000002b => "\x2b",
     0x0000002c => "\x2c",
     0x0000002d => "\x2d",
     0x0000002e => "\x2e",
     0x0000002f => "\x2f",
     0x00000030 => "\x30",
     0x00000031 => "\x31",
     0x00000032 => "\x32",
     0x00000033 => "\x33",
     0x00000034 => "\x34",
     0x00000035 => "\x35",
     0x00000036 => "\x36",
     0x00000037 => "\x37",
     0x00000038 => "\x38",
     0x00000039 => "\x39",
     0x0000003a => "\x3a",
     0x0000003b => "\x3b",
     0x0000003c => "\x3c",
     0x0000003d => "\x3d",
     0x0000003e => "\x3e",
     0x0000003f => "\x3f",
     0x00000040 => "\x40",
     0x00000041 => "\x41",
     0x00000042 => "\x42",
     0x00000043 => "\x43",
     0x00000044 => "\x44",
     0x00000045 => "\x45",
     0x00000046 => "\x46",
     0x00000047 => "\x47",
     0x00000048 => "\x48",
     0x00000049 => "\x49",
     0x0000004a => "\x4a",
     0x0000004b => "\x4b",
     0x0000004c => "\x4c",
     0x0000004d => "\x4d",
     0x0000004e => "\x4e",
     0x0000004f => "\x4f",
     0x00000050 => "\x50",
     0x00000051 => "\x51",
     0x00000052 => "\x52",
     0x00000053 => "\x53",
     0x00000054 => "\x54",
     0x00000055 => "\x55",
     0x00000056 => "\x56",
     0x00000057 => "\x57",
     0x00000058 => "\x58",
     0x00000059 => "\x59",
     0x0000005a => "\x5a",
     0x0000005b => "\x5b",
     0x0000005c => "\x5c",
     0x0000005d => "\x5d",
     0x0000005e => "\x5e",
     0x0000005f => "\x5f",
     0x00000060 => "\x60",
     0x00000061 => "\x61",
     0x00000062 => "\x62",
     0x00000063 => "\x63",
     0x00000064 => "\x64",
     0x00000065 => "\x65",
     0x00000066 => "\x66",
     0x00000067 => "\x67",
     0x00000068 => "\x68",
     0x00000069 => "\x69",
     0x0000006a => "\x6a",
     0x0000006b => "\x6b",
     0x0000006c => "\x6c",
     0x0000006d => "\x6d",
     0x0000006e => "\x6e",
     0x0000006f => "\x6f",
     0x00000070 => "\x70",
     0x00000071 => "\x71",
     0x00000072 => "\x72",
     0x00000073 => "\x73",
     0x00000074 => "\x74",
     0x00000075 => "\x75",
     0x00000076 => "\x76",
     0x00000077 => "\x77",
     0x00000078 => "\x78",
     0x00000079 => "\x79",
     0x0000007a => "\x7a",
     0x0000007b => "\x7b",
     0x0000007c => "\x7c",
     0x0000007d => "\x7d",
     0x0000007e => "\x7e",
     0x0000007f => "\x7f",
     0x00000080 => "\x80",
     0x00000081 => "\x81",
     0x00000082 => "\x82",
     0x00000083 => "\x83",
     0x00000084 => "\x84",
     0x00000085 => "\x85",
     0x00000086 => "\x86",
     0x00000087 => "\x87",
     0x00000088 => "\x88",
     0x00000089 => "\x89",
     0x0000008a => "\x8a",
     0x0000008b => "\x8b",
     0x0000008c => "\x8c",
     0x0000008d => "\x8d",
     0x0000008e => "\x8e",
     0x0000008f => "\x8f",
     0x00000090 => "\x90",
     0x00000091 => "\x91",
     0x00000092 => "\x92",
     0x00000093 => "\x93",
     0x00000094 => "\x94",
     0x00000095 => "\x95",
     0x00000096 => "\x96",
     0x00000097 => "\x97",
     0x00000098 => "\x98",
     0x00000099 => "\x99",
     0x0000009a => "\x9a",
     0x0000009b => "\x9b",
     0x0000009c => "\x9c",
     0x0000009d => "\x9d",
     0x0000009e => "\x9e",
     0x0000009f => "\x9f",
     0x000000a0 => "\xa0",
     0x000000a2 => "\xa2",
     0x000000a3 => "\xa3",
     0x000000a4 => "\xa4",
     0x000000a5 => "\xa5",
     0x000000a6 => "\xa6",
     0x000000a7 => "\xa7",
     0x000000a8 => "\xa8",
     0x000000a9 => "\xa9",
     0x000000ab => "\xab",
     0x000000ac => "\xac",
     0x000000ad => "\xad",
     0x000000ae => "\xae",
     0x000000af => "\xaf",
     0x000000b0 => "\xb0",
     0x000000b1 => "\xb1",
     0x000000b2 => "\xb2",
     0x000000b3 => "\xb3",
     0x000000b4 => "\xb4",
     0x000000b5 => "\xb5",
     0x000000b6 => "\xb6",
     0x000000b7 => "\xb7",
     0x000000b8 => "\xb8",
     0x000000b9 => "\xb9",
     0x000000bb => "\xbb",
     0x000000bc => "\xbc",
     0x000000bd => "\xbd",
     0x000000be => "\xbe",
     0x000000d7 => "\xaa",
     0x000000f7 => "\xba",
     0x000005d0 => "\xe0",
     0x000005d1 => "\xe1",
     0x000005d2 => "\xe2",
     0x000005d3 => "\xe3",
     0x000005d4 => "\xe4",
     0x000005d5 => "\xe5",
     0x000005d6 => "\xe6",
     0x000005d7 => "\xe7",
     0x000005d8 => "\xe8",
     0x000005d9 => "\xe9",
     0x000005da => "\xea",
     0x000005db => "\xeb",
     0x000005dc => "\xec",
     0x000005dd => "\xed",
     0x000005de => "\xee",
     0x000005df => "\xef",
     0x000005e0 => "\xf0",
     0x000005e1 => "\xf1",
     0x000005e2 => "\xf2",
     0x000005e3 => "\xf3",
     0x000005e4 => "\xf4",
     0x000005e5 => "\xf5",
     0x000005e6 => "\xf6",
     0x000005e7 => "\xf7",
     0x000005e8 => "\xf8",
     0x000005e9 => "\xf9",
     0x000005ea => "\xfa",
     0x0000200e => "\xfd",
     0x0000200f => "\xfe",
     0x00002017 => "\xdf",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::ISO_8859_8 - Conversion routines for ISO-8859-8
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for ISO-8859-8.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
   source: ECMA registry
  alias ISO-IR-138
  alias ISO_8859-8:1988
  alias ISO_8859-8
  alias HEBREW
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  00000004 | END OF TRANSMISSION (EOT)
     05 |  00000005 | ENQUIRY (ENQ)
     06 |  00000006 | ACKNOWLEDGE (ACK)
     07 |  00000007 | BELL (BEL)
     08 |  00000008 | BACKSPACE (BS)
     09 |  00000009 | CHARACTER TABULATION (HT)
     0A |  0000000A | LINE FEED (LF)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  00000014 | DEVICE CONTROL FOUR (DC4)
     15 |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     16 |  00000016 | SYNCHRONOUS IDLE (SYN)
     17 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  0000001A | SUBSTITUTE (SUB)
     1B |  0000001B | ESCAPE (ESC)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000020 | SPACE
     21 |  00000021 | EXCLAMATION MARK
     22 |  00000022 | QUOTATION MARK
     23 |  00000023 | NUMBER SIGN
     24 |  00000024 | DOLLAR SIGN
     25 |  00000025 | PERCENT SIGN
     26 |  00000026 | AMPERSAND
     27 |  00000027 | APOSTROPHE
     28 |  00000028 | LEFT PARENTHESIS
     29 |  00000029 | RIGHT PARENTHESIS
     2A |  0000002A | ASTERISK
     2B |  0000002B | PLUS SIGN
     2C |  0000002C | COMMA
     2D |  0000002D | HYPHEN-MINUS
     2E |  0000002E | FULL STOP
     2F |  0000002F | SOLIDUS
     30 |  00000030 | DIGIT ZERO
     31 |  00000031 | DIGIT ONE
     32 |  00000032 | DIGIT TWO
     33 |  00000033 | DIGIT THREE
     34 |  00000034 | DIGIT FOUR
     35 |  00000035 | DIGIT FIVE
     36 |  00000036 | DIGIT SIX
     37 |  00000037 | DIGIT SEVEN
     38 |  00000038 | DIGIT EIGHT
     39 |  00000039 | DIGIT NINE
     3A |  0000003A | COLON
     3B |  0000003B | SEMICOLON
     3C |  0000003C | LESS-THAN SIGN
     3D |  0000003D | EQUALS SIGN
     3E |  0000003E | GREATER-THAN SIGN
     3F |  0000003F | QUESTION MARK
     40 |  00000040 | COMMERCIAL AT
     41 |  00000041 | LATIN CAPITAL LETTER A
     42 |  00000042 | LATIN CAPITAL LETTER B
     43 |  00000043 | LATIN CAPITAL LETTER C
     44 |  00000044 | LATIN CAPITAL LETTER D
     45 |  00000045 | LATIN CAPITAL LETTER E
     46 |  00000046 | LATIN CAPITAL LETTER F
     47 |  00000047 | LATIN CAPITAL LETTER G
     48 |  00000048 | LATIN CAPITAL LETTER H
     49 |  00000049 | LATIN CAPITAL LETTER I
     4A |  0000004A | LATIN CAPITAL LETTER J
     4B |  0000004B | LATIN CAPITAL LETTER K
     4C |  0000004C | LATIN CAPITAL LETTER L
     4D |  0000004D | LATIN CAPITAL LETTER M
     4E |  0000004E | LATIN CAPITAL LETTER N
     4F |  0000004F | LATIN CAPITAL LETTER O
     50 |  00000050 | LATIN CAPITAL LETTER P
     51 |  00000051 | LATIN CAPITAL LETTER Q
     52 |  00000052 | LATIN CAPITAL LETTER R
     53 |  00000053 | LATIN CAPITAL LETTER S
     54 |  00000054 | LATIN CAPITAL LETTER T
     55 |  00000055 | LATIN CAPITAL LETTER U
     56 |  00000056 | LATIN CAPITAL LETTER V
     57 |  00000057 | LATIN CAPITAL LETTER W
     58 |  00000058 | LATIN CAPITAL LETTER X
     59 |  00000059 | LATIN CAPITAL LETTER Y
     5A |  0000005A | LATIN CAPITAL LETTER Z
     5B |  0000005B | LEFT SQUARE BRACKET
     5C |  0000005C | REVERSE SOLIDUS
     5D |  0000005D | RIGHT SQUARE BRACKET
     5E |  0000005E | CIRCUMFLEX ACCENT
     5F |  0000005F | LOW LINE
     60 |  00000060 | GRAVE ACCENT
     61 |  00000061 | LATIN SMALL LETTER A
     62 |  00000062 | LATIN SMALL LETTER B
     63 |  00000063 | LATIN SMALL LETTER C
     64 |  00000064 | LATIN SMALL LETTER D
     65 |  00000065 | LATIN SMALL LETTER E
     66 |  00000066 | LATIN SMALL LETTER F
     67 |  00000067 | LATIN SMALL LETTER G
     68 |  00000068 | LATIN SMALL LETTER H
     69 |  00000069 | LATIN SMALL LETTER I
     6A |  0000006A | LATIN SMALL LETTER J
     6B |  0000006B | LATIN SMALL LETTER K
     6C |  0000006C | LATIN SMALL LETTER L
     6D |  0000006D | LATIN SMALL LETTER M
     6E |  0000006E | LATIN SMALL LETTER N
     6F |  0000006F | LATIN SMALL LETTER O
     70 |  00000070 | LATIN SMALL LETTER P
     71 |  00000071 | LATIN SMALL LETTER Q
     72 |  00000072 | LATIN SMALL LETTER R
     73 |  00000073 | LATIN SMALL LETTER S
     74 |  00000074 | LATIN SMALL LETTER T
     75 |  00000075 | LATIN SMALL LETTER U
     76 |  00000076 | LATIN SMALL LETTER V
     77 |  00000077 | LATIN SMALL LETTER W
     78 |  00000078 | LATIN SMALL LETTER X
     79 |  00000079 | LATIN SMALL LETTER Y
     7A |  0000007A | LATIN SMALL LETTER Z
     7B |  0000007B | LEFT CURLY BRACKET
     7C |  0000007C | VERTICAL LINE
     7D |  0000007D | RIGHT CURLY BRACKET
     7E |  0000007E | TILDE
     7F |  0000007F | DELETE (DEL)
     80 |  00000080 | PADDING CHARACTER (PAD)
     81 |  00000081 | HIGH OCTET PRESET (HOP)
     82 |  00000082 | BREAK PERMITTED HERE (BPH)
     83 |  00000083 | NO BREAK HERE (NBH)
     84 |  00000084 | INDEX (IND)
     85 |  00000085 | NEXT LINE (NEL)
     86 |  00000086 | START OF SELECTED AREA (SSA)
     87 |  00000087 | END OF SELECTED AREA (ESA)
     88 |  00000088 | CHARACTER TABULATION SET (HTS)
     89 |  00000089 | CHARACTER TABULATION WITH JUSTIFICATION (HTJ)
     8A |  0000008A | LINE TABULATION SET (VTS)
     8B |  0000008B | PARTIAL LINE FORWARD (PLD)
     8C |  0000008C | PARTIAL LINE BACKWARD (PLU)
     8D |  0000008D | REVERSE LINE FEED (RI)
     8E |  0000008E | SINGLE-SHIFT TWO (SS2)
     8F |  0000008F | SINGLE-SHIFT THREE (SS3)
     90 |  00000090 | DEVICE CONTROL STRING (DCS)
     91 |  00000091 | PRIVATE USE ONE (PU1)
     92 |  00000092 | PRIVATE USE TWO (PU2)
     93 |  00000093 | SET TRANSMIT STATE (STS)
     94 |  00000094 | CANCEL CHARACTER (CCH)
     95 |  00000095 | MESSAGE WAITING (MW)
     96 |  00000096 | START OF GUARDED AREA (SPA)
     97 |  00000097 | END OF GUARDED AREA (EPA)
     98 |  00000098 | START OF STRING (SOS)
     99 |  00000099 | SINGLE GRAPHIC CHARACTER INTRODUCER (SGCI)
     9A |  0000009A | SINGLE CHARACTER INTRODUCER (SCI)
     9B |  0000009B | CONTROL SEQUENCE INTRODUCER (CSI)
     9C |  0000009C | STRING TERMINATOR (ST)
     9D |  0000009D | OPERATING SYSTEM COMMAND (OSC)
     9E |  0000009E | PRIVACY MESSAGE (PM)
     9F |  0000009F | APPLICATION PROGRAM COMMAND (APC)
     A0 |  000000A0 | NO-BREAK SPACE
     A2 |  000000A2 | CENT SIGN
     A3 |  000000A3 | POUND SIGN
     A4 |  000000A4 | CURRENCY SIGN
     A5 |  000000A5 | YEN SIGN
     A6 |  000000A6 | BROKEN BAR
     A7 |  000000A7 | SECTION SIGN
     A8 |  000000A8 | DIAERESIS
     A9 |  000000A9 | COPYRIGHT SIGN
     AA |  000000D7 | MULTIPLICATION SIGN
     AB |  000000AB | LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
     AC |  000000AC | NOT SIGN
     AD |  000000AD | SOFT HYPHEN
     AE |  000000AE | REGISTERED SIGN
     AF |  000000AF | MACRON
     B0 |  000000B0 | DEGREE SIGN
     B1 |  000000B1 | PLUS-MINUS SIGN
     B2 |  000000B2 | SUPERSCRIPT TWO
     B3 |  000000B3 | SUPERSCRIPT THREE
     B4 |  000000B4 | ACUTE ACCENT
     B5 |  000000B5 | MICRO SIGN
     B6 |  000000B6 | PILCROW SIGN
     B7 |  000000B7 | MIDDLE DOT
     B8 |  000000B8 | CEDILLA
     B9 |  000000B9 | SUPERSCRIPT ONE
     BA |  000000F7 | DIVISION SIGN
     BB |  000000BB | RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
     BC |  000000BC | VULGAR FRACTION ONE QUARTER
     BD |  000000BD | VULGAR FRACTION ONE HALF
     BE |  000000BE | VULGAR FRACTION THREE QUARTERS
     DF |  00002017 | DOUBLE LOW LINE
     E0 |  000005D0 | HEBREW LETTER ALEF
     E1 |  000005D1 | HEBREW LETTER BET
     E2 |  000005D2 | HEBREW LETTER GIMEL
     E3 |  000005D3 | HEBREW LETTER DALET
     E4 |  000005D4 | HEBREW LETTER HE
     E5 |  000005D5 | HEBREW LETTER VAV
     E6 |  000005D6 | HEBREW LETTER ZAYIN
     E7 |  000005D7 | HEBREW LETTER HET
     E8 |  000005D8 | HEBREW LETTER TET
     E9 |  000005D9 | HEBREW LETTER YOD
     EA |  000005DA | HEBREW LETTER FINAL KAF
     EB |  000005DB | HEBREW LETTER KAF
     EC |  000005DC | HEBREW LETTER LAMED
     ED |  000005DD | HEBREW LETTER FINAL MEM
     EE |  000005DE | HEBREW LETTER MEM
     EF |  000005DF | HEBREW LETTER FINAL NUN
     F0 |  000005E0 | HEBREW LETTER NUN
     F1 |  000005E1 | HEBREW LETTER SAMEKH
     F2 |  000005E2 | HEBREW LETTER AYIN
     F3 |  000005E3 | HEBREW LETTER FINAL PE
     F4 |  000005E4 | HEBREW LETTER PE
     F5 |  000005E5 | HEBREW LETTER FINAL TSADI
     F6 |  000005E6 | HEBREW LETTER TSADI
     F7 |  000005E7 | HEBREW LETTER QOF
     F8 |  000005E8 | HEBREW LETTER RESH
     F9 |  000005E9 | HEBREW LETTER SHIN
     FA |  000005EA | HEBREW LETTER TAV
     FD |  0000200E | LEFT-TO-RIGHT MARK
     FE |  0000200F | RIGHT-TO-LEFT MARK
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/ISO_8859_9.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for ISO-8859-9.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::ISO_8859_9;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x0004,
     0x0005,
     0x0006,
     0x0007,
     0x0008,
     0x0009,
     0x000a,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x0014,
     0x0015,
     0x0016,
     0x0017,
     0x0018,
     0x0019,
     0x001a,
     0x001b,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0020,
     0x0021,
     0x0022,
     0x0023,
     0x0024,
     0x0025,
     0x0026,
     0x0027,
     0x0028,
     0x0029,
     0x002a,
     0x002b,
     0x002c,
     0x002d,
     0x002e,
     0x002f,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x003a,
     0x003b,
     0x003c,
     0x003d,
     0x003e,
     0x003f,
     0x0040,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x005b,
     0x005c,
     0x005d,
     0x005e,
     0x005f,
     0x0060,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x007b,
     0x007c,
     0x007d,
     0x007e,
     0x007f,
     0x0080,
     0x0081,
     0x0082,
     0x0083,
     0x0084,
     0x0085,
     0x0086,
     0x0087,
     0x0088,
     0x0089,
     0x008a,
     0x008b,
     0x008c,
     0x008d,
     0x008e,
     0x008f,
     0x0090,
     0x0091,
     0x0092,
     0x0093,
     0x0094,
     0x0095,
     0x0096,
     0x0097,
     0x0098,
     0x0099,
     0x009a,
     0x009b,
     0x009c,
     0x009d,
     0x009e,
     0x009f,
     0x00a0,
     0x00a1,
     0x00a2,
     0x00a3,
     0x00a4,
     0x00a5,
     0x00a6,
     0x00a7,
     0x00a8,
     0x00a9,
     0x00aa,
     0x00ab,
     0x00ac,
     0x00ad,
     0x00ae,
     0x00af,
     0x00b0,
     0x00b1,
     0x00b2,
     0x00b3,
     0x00b4,
     0x00b5,
     0x00b6,
     0x00b7,
     0x00b8,
     0x00b9,
     0x00ba,
     0x00bb,
     0x00bc,
     0x00bd,
     0x00be,
     0x00bf,
     0x00c0,
     0x00c1,
     0x00c2,
     0x00c3,
     0x00c4,
     0x00c5,
     0x00c6,
     0x00c7,
     0x00c8,
     0x00c9,
     0x00ca,
     0x00cb,
     0x00cc,
     0x00cd,
     0x00ce,
     0x00cf,
     0x011e,
     0x00d1,
     0x00d2,
     0x00d3,
     0x00d4,
     0x00d5,
     0x00d6,
     0x00d7,
     0x00d8,
     0x00d9,
     0x00da,
     0x00db,
     0x00dc,
     0x0130,
     0x015e,
     0x00df,
     0x00e0,
     0x00e1,
     0x00e2,
     0x00e3,
     0x00e4,
     0x00e5,
     0x00e6,
     0x00e7,
     0x00e8,
     0x00e9,
     0x00ea,
     0x00eb,
     0x00ec,
     0x00ed,
     0x00ee,
     0x00ef,
     0x011f,
     0x00f1,
     0x00f2,
     0x00f3,
     0x00f4,
     0x00f5,
     0x00f6,
     0x00f7,
     0x00f8,
     0x00f9,
     0x00fa,
     0x00fb,
     0x00fc,
     0x0131,
     0x015f,
     0x00ff,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\x04",
     "\x05",
     "\x06",
     "\x07",
     "\x08",
     "\x09",
     "\x0a",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\x14",
     "\x15",
     "\x16",
     "\x17",
     "\x18",
     "\x19",
     "\x1a",
     "\x1b",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\x20",
     "\x21",
     "\x22",
     "\x23",
     "\x24",
     "\x25",
     "\x26",
     "\x27",
     "\x28",
     "\x29",
     "\x2a",
     "\x2b",
     "\x2c",
     "\x2d",
     "\x2e",
     "\x2f",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\x3a",
     "\x3b",
     "\x3c",
     "\x3d",
     "\x3e",
     "\x3f",
     "\x40",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\x5b",
     "\x5c",
     "\x5d",
     "\x5e",
     "\x5f",
     "\x60",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\x7b",
     "\x7c",
     "\x7d",
     "\x7e",
     "\x7f",
     "\xc2\x80",
     "\xc2\x81",
     "\xc2\x82",
     "\xc2\x83",
     "\xc2\x84",
     "\xc2\x85",
     "\xc2\x86",
     "\xc2\x87",
     "\xc2\x88",
     "\xc2\x89",
     "\xc2\x8a",
     "\xc2\x8b",
     "\xc2\x8c",
     "\xc2\x8d",
     "\xc2\x8e",
     "\xc2\x8f",
     "\xc2\x90",
     "\xc2\x91",
     "\xc2\x92",
     "\xc2\x93",
     "\xc2\x94",
     "\xc2\x95",
     "\xc2\x96",
     "\xc2\x97",
     "\xc2\x98",
     "\xc2\x99",
     "\xc2\x9a",
     "\xc2\x9b",
     "\xc2\x9c",
     "\xc2\x9d",
     "\xc2\x9e",
     "\xc2\x9f",
     "\xc2\xa0",
     "\xc2\xa1",
     "\xc2\xa2",
     "\xc2\xa3",
     "\xc2\xa4",
     "\xc2\xa5",
     "\xc2\xa6",
     "\xc2\xa7",
     "\xc2\xa8",
     "\xc2\xa9",
     "\xc2\xaa",
     "\xc2\xab",
     "\xc2\xac",
     "\xc2\xad",
     "\xc2\xae",
     "\xc2\xaf",
     "\xc2\xb0",
     "\xc2\xb1",
     "\xc2\xb2",
     "\xc2\xb3",
     "\xc2\xb4",
     "\xc2\xb5",
     "\xc2\xb6",
     "\xc2\xb7",
     "\xc2\xb8",
     "\xc2\xb9",
     "\xc2\xba",
     "\xc2\xbb",
     "\xc2\xbc",
     "\xc2\xbd",
     "\xc2\xbe",
     "\xc2\xbf",
     "\xc3\x80",
     "\xc3\x81",
     "\xc3\x82",
     "\xc3\x83",
     "\xc3\x84",
     "\xc3\x85",
     "\xc3\x86",
     "\xc3\x87",
     "\xc3\x88",
     "\xc3\x89",
     "\xc3\x8a",
     "\xc3\x8b",
     "\xc3\x8c",
     "\xc3\x8d",
     "\xc3\x8e",
     "\xc3\x8f",
     "\xc4\x9e",
     "\xc3\x91",
     "\xc3\x92",
     "\xc3\x93",
     "\xc3\x94",
     "\xc3\x95",
     "\xc3\x96",
     "\xc3\x97",
     "\xc3\x98",
     "\xc3\x99",
     "\xc3\x9a",
     "\xc3\x9b",
     "\xc3\x9c",
     "\xc4\xb0",
     "\xc5\x9e",
     "\xc3\x9f",
     "\xc3\xa0",
     "\xc3\xa1",
     "\xc3\xa2",
     "\xc3\xa3",
     "\xc3\xa4",
     "\xc3\xa5",
     "\xc3\xa6",
     "\xc3\xa7",
     "\xc3\xa8",
     "\xc3\xa9",
     "\xc3\xaa",
     "\xc3\xab",
     "\xc3\xac",
     "\xc3\xad",
     "\xc3\xae",
     "\xc3\xaf",
     "\xc4\x9f",
     "\xc3\xb1",
     "\xc3\xb2",
     "\xc3\xb3",
     "\xc3\xb4",
     "\xc3\xb5",
     "\xc3\xb6",
     "\xc3\xb7",
     "\xc3\xb8",
     "\xc3\xb9",
     "\xc3\xba",
     "\xc3\xbb",
     "\xc3\xbc",
     "\xc4\xb1",
     "\xc5\x9f",
     "\xc3\xbf",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x04",
     0x00000005 => "\x05",
     0x00000006 => "\x06",
     0x00000007 => "\x07",
     0x00000008 => "\x08",
     0x00000009 => "\x09",
     0x0000000a => "\x0a",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x14",
     0x00000015 => "\x15",
     0x00000016 => "\x16",
     0x00000017 => "\x17",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x1a",
     0x0000001b => "\x1b",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x20",
     0x00000021 => "\x21",
     0x00000022 => "\x22",
     0x00000023 => "\x23",
     0x00000024 => "\x24",
     0x00000025 => "\x25",
     0x00000026 => "\x26",
     0x00000027 => "\x27",
     0x00000028 => "\x28",
     0x00000029 => "\x29",
     0x0000002a => "\x2a",
     0x0000002b => "\x2b",
     0x0000002c => "\x2c",
     0x0000002d => "\x2d",
     0x0000002e => "\x2e",
     0x0000002f => "\x2f",
     0x00000030 => "\x30",
     0x00000031 => "\x31",
     0x00000032 => "\x32",
     0x00000033 => "\x33",
     0x00000034 => "\x34",
     0x00000035 => "\x35",
     0x00000036 => "\x36",
     0x00000037 => "\x37",
     0x00000038 => "\x38",
     0x00000039 => "\x39",
     0x0000003a => "\x3a",
     0x0000003b => "\x3b",
     0x0000003c => "\x3c",
     0x0000003d => "\x3d",
     0x0000003e => "\x3e",
     0x0000003f => "\x3f",
     0x00000040 => "\x40",
     0x00000041 => "\x41",
     0x00000042 => "\x42",
     0x00000043 => "\x43",
     0x00000044 => "\x44",
     0x00000045 => "\x45",
     0x00000046 => "\x46",
     0x00000047 => "\x47",
     0x00000048 => "\x48",
     0x00000049 => "\x49",
     0x0000004a => "\x4a",
     0x0000004b => "\x4b",
     0x0000004c => "\x4c",
     0x0000004d => "\x4d",
     0x0000004e => "\x4e",
     0x0000004f => "\x4f",
     0x00000050 => "\x50",
     0x00000051 => "\x51",
     0x00000052 => "\x52",
     0x00000053 => "\x53",
     0x00000054 => "\x54",
     0x00000055 => "\x55",
     0x00000056 => "\x56",
     0x00000057 => "\x57",
     0x00000058 => "\x58",
     0x00000059 => "\x59",
     0x0000005a => "\x5a",
     0x0000005b => "\x5b",
     0x0000005c => "\x5c",
     0x0000005d => "\x5d",
     0x0000005e => "\x5e",
     0x0000005f => "\x5f",
     0x00000060 => "\x60",
     0x00000061 => "\x61",
     0x00000062 => "\x62",
     0x00000063 => "\x63",
     0x00000064 => "\x64",
     0x00000065 => "\x65",
     0x00000066 => "\x66",
     0x00000067 => "\x67",
     0x00000068 => "\x68",
     0x00000069 => "\x69",
     0x0000006a => "\x6a",
     0x0000006b => "\x6b",
     0x0000006c => "\x6c",
     0x0000006d => "\x6d",
     0x0000006e => "\x6e",
     0x0000006f => "\x6f",
     0x00000070 => "\x70",
     0x00000071 => "\x71",
     0x00000072 => "\x72",
     0x00000073 => "\x73",
     0x00000074 => "\x74",
     0x00000075 => "\x75",
     0x00000076 => "\x76",
     0x00000077 => "\x77",
     0x00000078 => "\x78",
     0x00000079 => "\x79",
     0x0000007a => "\x7a",
     0x0000007b => "\x7b",
     0x0000007c => "\x7c",
     0x0000007d => "\x7d",
     0x0000007e => "\x7e",
     0x0000007f => "\x7f",
     0x00000080 => "\x80",
     0x00000081 => "\x81",
     0x00000082 => "\x82",
     0x00000083 => "\x83",
     0x00000084 => "\x84",
     0x00000085 => "\x85",
     0x00000086 => "\x86",
     0x00000087 => "\x87",
     0x00000088 => "\x88",
     0x00000089 => "\x89",
     0x0000008a => "\x8a",
     0x0000008b => "\x8b",
     0x0000008c => "\x8c",
     0x0000008d => "\x8d",
     0x0000008e => "\x8e",
     0x0000008f => "\x8f",
     0x00000090 => "\x90",
     0x00000091 => "\x91",
     0x00000092 => "\x92",
     0x00000093 => "\x93",
     0x00000094 => "\x94",
     0x00000095 => "\x95",
     0x00000096 => "\x96",
     0x00000097 => "\x97",
     0x00000098 => "\x98",
     0x00000099 => "\x99",
     0x0000009a => "\x9a",
     0x0000009b => "\x9b",
     0x0000009c => "\x9c",
     0x0000009d => "\x9d",
     0x0000009e => "\x9e",
     0x0000009f => "\x9f",
     0x000000a0 => "\xa0",
     0x000000a1 => "\xa1",
     0x000000a2 => "\xa2",
     0x000000a3 => "\xa3",
     0x000000a4 => "\xa4",
     0x000000a5 => "\xa5",
     0x000000a6 => "\xa6",
     0x000000a7 => "\xa7",
     0x000000a8 => "\xa8",
     0x000000a9 => "\xa9",
     0x000000aa => "\xaa",
     0x000000ab => "\xab",
     0x000000ac => "\xac",
     0x000000ad => "\xad",
     0x000000ae => "\xae",
     0x000000af => "\xaf",
     0x000000b0 => "\xb0",
     0x000000b1 => "\xb1",
     0x000000b2 => "\xb2",
     0x000000b3 => "\xb3",
     0x000000b4 => "\xb4",
     0x000000b5 => "\xb5",
     0x000000b6 => "\xb6",
     0x000000b7 => "\xb7",
     0x000000b8 => "\xb8",
     0x000000b9 => "\xb9",
     0x000000ba => "\xba",
     0x000000bb => "\xbb",
     0x000000bc => "\xbc",
     0x000000bd => "\xbd",
     0x000000be => "\xbe",
     0x000000bf => "\xbf",
     0x000000c0 => "\xc0",
     0x000000c1 => "\xc1",
     0x000000c2 => "\xc2",
     0x000000c3 => "\xc3",
     0x000000c4 => "\xc4",
     0x000000c5 => "\xc5",
     0x000000c6 => "\xc6",
     0x000000c7 => "\xc7",
     0x000000c8 => "\xc8",
     0x000000c9 => "\xc9",
     0x000000ca => "\xca",
     0x000000cb => "\xcb",
     0x000000cc => "\xcc",
     0x000000cd => "\xcd",
     0x000000ce => "\xce",
     0x000000cf => "\xcf",
     0x000000d1 => "\xd1",
     0x000000d2 => "\xd2",
     0x000000d3 => "\xd3",
     0x000000d4 => "\xd4",
     0x000000d5 => "\xd5",
     0x000000d6 => "\xd6",
     0x000000d7 => "\xd7",
     0x000000d8 => "\xd8",
     0x000000d9 => "\xd9",
     0x000000da => "\xda",
     0x000000db => "\xdb",
     0x000000dc => "\xdc",
     0x000000df => "\xdf",
     0x000000e0 => "\xe0",
     0x000000e1 => "\xe1",
     0x000000e2 => "\xe2",
     0x000000e3 => "\xe3",
     0x000000e4 => "\xe4",
     0x000000e5 => "\xe5",
     0x000000e6 => "\xe6",
     0x000000e7 => "\xe7",
     0x000000e8 => "\xe8",
     0x000000e9 => "\xe9",
     0x000000ea => "\xea",
     0x000000eb => "\xeb",
     0x000000ec => "\xec",
     0x000000ed => "\xed",
     0x000000ee => "\xee",
     0x000000ef => "\xef",
     0x000000f1 => "\xf1",
     0x000000f2 => "\xf2",
     0x000000f3 => "\xf3",
     0x000000f4 => "\xf4",
     0x000000f5 => "\xf5",
     0x000000f6 => "\xf6",
     0x000000f7 => "\xf7",
     0x000000f8 => "\xf8",
     0x000000f9 => "\xf9",
     0x000000fa => "\xfa",
     0x000000fb => "\xfb",
     0x000000fc => "\xfc",
     0x000000ff => "\xff",
     0x0000011e => "\xd0",
     0x0000011f => "\xf0",
     0x00000130 => "\xdd",
     0x00000131 => "\xfd",
     0x0000015e => "\xde",
     0x0000015f => "\xfe",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::ISO_8859_9 - Conversion routines for ISO-8859-9
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for ISO-8859-9.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
   source: ECMA registry
  alias ISO-IR-148
  alias ISO_8859-9:1989
  alias ISO_8859-9
  alias LATIN5
  alias L5
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  00000004 | END OF TRANSMISSION (EOT)
     05 |  00000005 | ENQUIRY (ENQ)
     06 |  00000006 | ACKNOWLEDGE (ACK)
     07 |  00000007 | BELL (BEL)
     08 |  00000008 | BACKSPACE (BS)
     09 |  00000009 | CHARACTER TABULATION (HT)
     0A |  0000000A | LINE FEED (LF)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  00000014 | DEVICE CONTROL FOUR (DC4)
     15 |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     16 |  00000016 | SYNCHRONOUS IDLE (SYN)
     17 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  0000001A | SUBSTITUTE (SUB)
     1B |  0000001B | ESCAPE (ESC)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000020 | SPACE
     21 |  00000021 | EXCLAMATION MARK
     22 |  00000022 | QUOTATION MARK
     23 |  00000023 | NUMBER SIGN
     24 |  00000024 | DOLLAR SIGN
     25 |  00000025 | PERCENT SIGN
     26 |  00000026 | AMPERSAND
     27 |  00000027 | APOSTROPHE
     28 |  00000028 | LEFT PARENTHESIS
     29 |  00000029 | RIGHT PARENTHESIS
     2A |  0000002A | ASTERISK
     2B |  0000002B | PLUS SIGN
     2C |  0000002C | COMMA
     2D |  0000002D | HYPHEN-MINUS
     2E |  0000002E | FULL STOP
     2F |  0000002F | SOLIDUS
     30 |  00000030 | DIGIT ZERO
     31 |  00000031 | DIGIT ONE
     32 |  00000032 | DIGIT TWO
     33 |  00000033 | DIGIT THREE
     34 |  00000034 | DIGIT FOUR
     35 |  00000035 | DIGIT FIVE
     36 |  00000036 | DIGIT SIX
     37 |  00000037 | DIGIT SEVEN
     38 |  00000038 | DIGIT EIGHT
     39 |  00000039 | DIGIT NINE
     3A |  0000003A | COLON
     3B |  0000003B | SEMICOLON
     3C |  0000003C | LESS-THAN SIGN
     3D |  0000003D | EQUALS SIGN
     3E |  0000003E | GREATER-THAN SIGN
     3F |  0000003F | QUESTION MARK
     40 |  00000040 | COMMERCIAL AT
     41 |  00000041 | LATIN CAPITAL LETTER A
     42 |  00000042 | LATIN CAPITAL LETTER B
     43 |  00000043 | LATIN CAPITAL LETTER C
     44 |  00000044 | LATIN CAPITAL LETTER D
     45 |  00000045 | LATIN CAPITAL LETTER E
     46 |  00000046 | LATIN CAPITAL LETTER F
     47 |  00000047 | LATIN CAPITAL LETTER G
     48 |  00000048 | LATIN CAPITAL LETTER H
     49 |  00000049 | LATIN CAPITAL LETTER I
     4A |  0000004A | LATIN CAPITAL LETTER J
     4B |  0000004B | LATIN CAPITAL LETTER K
     4C |  0000004C | LATIN CAPITAL LETTER L
     4D |  0000004D | LATIN CAPITAL LETTER M
     4E |  0000004E | LATIN CAPITAL LETTER N
     4F |  0000004F | LATIN CAPITAL LETTER O
     50 |  00000050 | LATIN CAPITAL LETTER P
     51 |  00000051 | LATIN CAPITAL LETTER Q
     52 |  00000052 | LATIN CAPITAL LETTER R
     53 |  00000053 | LATIN CAPITAL LETTER S
     54 |  00000054 | LATIN CAPITAL LETTER T
     55 |  00000055 | LATIN CAPITAL LETTER U
     56 |  00000056 | LATIN CAPITAL LETTER V
     57 |  00000057 | LATIN CAPITAL LETTER W
     58 |  00000058 | LATIN CAPITAL LETTER X
     59 |  00000059 | LATIN CAPITAL LETTER Y
     5A |  0000005A | LATIN CAPITAL LETTER Z
     5B |  0000005B | LEFT SQUARE BRACKET
     5C |  0000005C | REVERSE SOLIDUS
     5D |  0000005D | RIGHT SQUARE BRACKET
     5E |  0000005E | CIRCUMFLEX ACCENT
     5F |  0000005F | LOW LINE
     60 |  00000060 | GRAVE ACCENT
     61 |  00000061 | LATIN SMALL LETTER A
     62 |  00000062 | LATIN SMALL LETTER B
     63 |  00000063 | LATIN SMALL LETTER C
     64 |  00000064 | LATIN SMALL LETTER D
     65 |  00000065 | LATIN SMALL LETTER E
     66 |  00000066 | LATIN SMALL LETTER F
     67 |  00000067 | LATIN SMALL LETTER G
     68 |  00000068 | LATIN SMALL LETTER H
     69 |  00000069 | LATIN SMALL LETTER I
     6A |  0000006A | LATIN SMALL LETTER J
     6B |  0000006B | LATIN SMALL LETTER K
     6C |  0000006C | LATIN SMALL LETTER L
     6D |  0000006D | LATIN SMALL LETTER M
     6E |  0000006E | LATIN SMALL LETTER N
     6F |  0000006F | LATIN SMALL LETTER O
     70 |  00000070 | LATIN SMALL LETTER P
     71 |  00000071 | LATIN SMALL LETTER Q
     72 |  00000072 | LATIN SMALL LETTER R
     73 |  00000073 | LATIN SMALL LETTER S
     74 |  00000074 | LATIN SMALL LETTER T
     75 |  00000075 | LATIN SMALL LETTER U
     76 |  00000076 | LATIN SMALL LETTER V
     77 |  00000077 | LATIN SMALL LETTER W
     78 |  00000078 | LATIN SMALL LETTER X
     79 |  00000079 | LATIN SMALL LETTER Y
     7A |  0000007A | LATIN SMALL LETTER Z
     7B |  0000007B | LEFT CURLY BRACKET
     7C |  0000007C | VERTICAL LINE
     7D |  0000007D | RIGHT CURLY BRACKET
     7E |  0000007E | TILDE
     7F |  0000007F | DELETE (DEL)
     80 |  00000080 | PADDING CHARACTER (PAD)
     81 |  00000081 | HIGH OCTET PRESET (HOP)
     82 |  00000082 | BREAK PERMITTED HERE (BPH)
     83 |  00000083 | NO BREAK HERE (NBH)
     84 |  00000084 | INDEX (IND)
     85 |  00000085 | NEXT LINE (NEL)
     86 |  00000086 | START OF SELECTED AREA (SSA)
     87 |  00000087 | END OF SELECTED AREA (ESA)
     88 |  00000088 | CHARACTER TABULATION SET (HTS)
     89 |  00000089 | CHARACTER TABULATION WITH JUSTIFICATION (HTJ)
     8A |  0000008A | LINE TABULATION SET (VTS)
     8B |  0000008B | PARTIAL LINE FORWARD (PLD)
     8C |  0000008C | PARTIAL LINE BACKWARD (PLU)
     8D |  0000008D | REVERSE LINE FEED (RI)
     8E |  0000008E | SINGLE-SHIFT TWO (SS2)
     8F |  0000008F | SINGLE-SHIFT THREE (SS3)
     90 |  00000090 | DEVICE CONTROL STRING (DCS)
     91 |  00000091 | PRIVATE USE ONE (PU1)
     92 |  00000092 | PRIVATE USE TWO (PU2)
     93 |  00000093 | SET TRANSMIT STATE (STS)
     94 |  00000094 | CANCEL CHARACTER (CCH)
     95 |  00000095 | MESSAGE WAITING (MW)
     96 |  00000096 | START OF GUARDED AREA (SPA)
     97 |  00000097 | END OF GUARDED AREA (EPA)
     98 |  00000098 | START OF STRING (SOS)
     99 |  00000099 | SINGLE GRAPHIC CHARACTER INTRODUCER (SGCI)
     9A |  0000009A | SINGLE CHARACTER INTRODUCER (SCI)
     9B |  0000009B | CONTROL SEQUENCE INTRODUCER (CSI)
     9C |  0000009C | STRING TERMINATOR (ST)
     9D |  0000009D | OPERATING SYSTEM COMMAND (OSC)
     9E |  0000009E | PRIVACY MESSAGE (PM)
     9F |  0000009F | APPLICATION PROGRAM COMMAND (APC)
     A0 |  000000A0 | NO-BREAK SPACE
     A1 |  000000A1 | INVERTED EXCLAMATION MARK
     A2 |  000000A2 | CENT SIGN
     A3 |  000000A3 | POUND SIGN
     A4 |  000000A4 | CURRENCY SIGN
     A5 |  000000A5 | YEN SIGN
     A6 |  000000A6 | BROKEN BAR
     A7 |  000000A7 | SECTION SIGN
     A8 |  000000A8 | DIAERESIS
     A9 |  000000A9 | COPYRIGHT SIGN
     AA |  000000AA | FEMININE ORDINAL INDICATOR
     AB |  000000AB | LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
     AC |  000000AC | NOT SIGN
     AD |  000000AD | SOFT HYPHEN
     AE |  000000AE | REGISTERED SIGN
     AF |  000000AF | MACRON
     B0 |  000000B0 | DEGREE SIGN
     B1 |  000000B1 | PLUS-MINUS SIGN
     B2 |  000000B2 | SUPERSCRIPT TWO
     B3 |  000000B3 | SUPERSCRIPT THREE
     B4 |  000000B4 | ACUTE ACCENT
     B5 |  000000B5 | MICRO SIGN
     B6 |  000000B6 | PILCROW SIGN
     B7 |  000000B7 | MIDDLE DOT
     B8 |  000000B8 | CEDILLA
     B9 |  000000B9 | SUPERSCRIPT ONE
     BA |  000000BA | MASCULINE ORDINAL INDICATOR
     BB |  000000BB | RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
     BC |  000000BC | VULGAR FRACTION ONE QUARTER
     BD |  000000BD | VULGAR FRACTION ONE HALF
     BE |  000000BE | VULGAR FRACTION THREE QUARTERS
     BF |  000000BF | INVERTED QUESTION MARK
     C0 |  000000C0 | LATIN CAPITAL LETTER A WITH GRAVE
     C1 |  000000C1 | LATIN CAPITAL LETTER A WITH ACUTE
     C2 |  000000C2 | LATIN CAPITAL LETTER A WITH CIRCUMFLEX
     C3 |  000000C3 | LATIN CAPITAL LETTER A WITH TILDE
     C4 |  000000C4 | LATIN CAPITAL LETTER A WITH DIAERESIS
     C5 |  000000C5 | LATIN CAPITAL LETTER A WITH RING ABOVE
     C6 |  000000C6 | LATIN CAPITAL LETTER AE
     C7 |  000000C7 | LATIN CAPITAL LETTER C WITH CEDILLA
     C8 |  000000C8 | LATIN CAPITAL LETTER E WITH GRAVE
     C9 |  000000C9 | LATIN CAPITAL LETTER E WITH ACUTE
     CA |  000000CA | LATIN CAPITAL LETTER E WITH CIRCUMFLEX
     CB |  000000CB | LATIN CAPITAL LETTER E WITH DIAERESIS
     CC |  000000CC | LATIN CAPITAL LETTER I WITH GRAVE
     CD |  000000CD | LATIN CAPITAL LETTER I WITH ACUTE
     CE |  000000CE | LATIN CAPITAL LETTER I WITH CIRCUMFLEX
     CF |  000000CF | LATIN CAPITAL LETTER I WITH DIAERESIS
     D0 |  0000011E | LATIN CAPITAL LETTER G WITH BREVE
     D1 |  000000D1 | LATIN CAPITAL LETTER N WITH TILDE
     D2 |  000000D2 | LATIN CAPITAL LETTER O WITH GRAVE
     D3 |  000000D3 | LATIN CAPITAL LETTER O WITH ACUTE
     D4 |  000000D4 | LATIN CAPITAL LETTER O WITH CIRCUMFLEX
     D5 |  000000D5 | LATIN CAPITAL LETTER O WITH TILDE
     D6 |  000000D6 | LATIN CAPITAL LETTER O WITH DIAERESIS
     D7 |  000000D7 | MULTIPLICATION SIGN
     D8 |  000000D8 | LATIN CAPITAL LETTER O WITH STROKE
     D9 |  000000D9 | LATIN CAPITAL LETTER U WITH GRAVE
     DA |  000000DA | LATIN CAPITAL LETTER U WITH ACUTE
     DB |  000000DB | LATIN CAPITAL LETTER U WITH CIRCUMFLEX
     DC |  000000DC | LATIN CAPITAL LETTER U WITH DIAERESIS
     DD |  00000130 | LATIN CAPITAL LETTER I WITH DOT ABOVE
     DE |  0000015E | LATIN CAPITAL LETTER S WITH CEDILLA
     DF |  000000DF | LATIN SMALL LETTER SHARP S (German)
     E0 |  000000E0 | LATIN SMALL LETTER A WITH GRAVE
     E1 |  000000E1 | LATIN SMALL LETTER A WITH ACUTE
     E2 |  000000E2 | LATIN SMALL LETTER A WITH CIRCUMFLEX
     E3 |  000000E3 | LATIN SMALL LETTER A WITH TILDE
     E4 |  000000E4 | LATIN SMALL LETTER A WITH DIAERESIS
     E5 |  000000E5 | LATIN SMALL LETTER A WITH RING ABOVE
     E6 |  000000E6 | LATIN SMALL LETTER AE
     E7 |  000000E7 | LATIN SMALL LETTER C WITH CEDILLA
     E8 |  000000E8 | LATIN SMALL LETTER E WITH GRAVE
     E9 |  000000E9 | LATIN SMALL LETTER E WITH ACUTE
     EA |  000000EA | LATIN SMALL LETTER E WITH CIRCUMFLEX
     EB |  000000EB | LATIN SMALL LETTER E WITH DIAERESIS
     EC |  000000EC | LATIN SMALL LETTER I WITH GRAVE
     ED |  000000ED | LATIN SMALL LETTER I WITH ACUTE
     EE |  000000EE | LATIN SMALL LETTER I WITH CIRCUMFLEX
     EF |  000000EF | LATIN SMALL LETTER I WITH DIAERESIS
     F0 |  0000011F | LATIN SMALL LETTER G WITH BREVE
     F1 |  000000F1 | LATIN SMALL LETTER N WITH TILDE
     F2 |  000000F2 | LATIN SMALL LETTER O WITH GRAVE
     F3 |  000000F3 | LATIN SMALL LETTER O WITH ACUTE
     F4 |  000000F4 | LATIN SMALL LETTER O WITH CIRCUMFLEX
     F5 |  000000F5 | LATIN SMALL LETTER O WITH TILDE
     F6 |  000000F6 | LATIN SMALL LETTER O WITH DIAERESIS
     F7 |  000000F7 | DIVISION SIGN
     F8 |  000000F8 | LATIN SMALL LETTER O WITH STROKE
     F9 |  000000F9 | LATIN SMALL LETTER U WITH GRAVE
     FA |  000000FA | LATIN SMALL LETTER U WITH ACUTE
     FB |  000000FB | LATIN SMALL LETTER U WITH CIRCUMFLEX
     FC |  000000FC | LATIN SMALL LETTER U WITH DIAERESIS
     FD |  00000131 | LATIN SMALL LETTER DOTLESS I
     FE |  0000015F | LATIN SMALL LETTER S WITH CEDILLA
     FF |  000000FF | LATIN SMALL LETTER Y WITH DIAERESIS
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/KOI8_R.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for KOI8-R.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::KOI8_R;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x0004,
     0x0005,
     0x0006,
     0x0007,
     0x0008,
     0x0009,
     0x000a,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x0014,
     0x0015,
     0x0016,
     0x0017,
     0x0018,
     0x0019,
     0x001a,
     0x001b,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0020,
     0x0021,
     0x0022,
     0x0023,
     0x0024,
     0x0025,
     0x0026,
     0x0027,
     0x0028,
     0x0029,
     0x002a,
     0x002b,
     0x002c,
     0x002d,
     0x002e,
     0x002f,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x003a,
     0x003b,
     0x003c,
     0x003d,
     0x003e,
     0x003f,
     0x0040,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x005b,
     0x005c,
     0x005d,
     0x005e,
     0x005f,
     0x0060,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x007b,
     0x007c,
     0x007d,
     0x007e,
     0x007f,
     0x2500,
     0x2502,
     0x250c,
     0x2510,
     0x2514,
     0x2518,
     0x251c,
     0x2524,
     0x252c,
     0x2534,
     0x253c,
     0x2580,
     0x2584,
     0x2588,
     0x258c,
     0x2590,
     0x2591,
     0x2592,
     0x2593,
     0x2320,
     0x25a0,
     0x2219,
     0x221a,
     0x2248,
     0x2264,
     0x2265,
     0x00a0,
     0x2321,
     0x00b0,
     0x00b2,
     0x00b7,
     0x00f7,
     0x2550,
     0x2551,
     0x2552,
     0x0451,
     0x2553,
     0x2554,
     0x2555,
     0x2556,
     0x2557,
     0x2558,
     0x2559,
     0x255a,
     0x255b,
     0x255c,
     0x255d,
     0x255e,
     0x255f,
     0x2560,
     0x2561,
     0x0401,
     0x2562,
     0x2563,
     0x2564,
     0x2565,
     0x2566,
     0x2567,
     0x2568,
     0x2569,
     0x256a,
     0x256b,
     0x256c,
     0x00a9,
     0x044e,
     0x0430,
     0x0431,
     0x0446,
     0x0434,
     0x0435,
     0x0444,
     0x0433,
     0x0445,
     0x0438,
     0x0439,
     0x043a,
     0x043b,
     0x043c,
     0x043d,
     0x043e,
     0x043f,
     0x044f,
     0x0440,
     0x0441,
     0x0442,
     0x0443,
     0x0436,
     0x0432,
     0x044c,
     0x044b,
     0x0437,
     0x0448,
     0x044d,
     0x0449,
     0x0447,
     0x044a,
     0x042e,
     0x0410,
     0x0411,
     0x0426,
     0x0414,
     0x0415,
     0x0424,
     0x0413,
     0x0425,
     0x0418,
     0x0419,
     0x041a,
     0x041b,
     0x041c,
     0x041d,
     0x041e,
     0x041f,
     0x042f,
     0x0420,
     0x0421,
     0x0422,
     0x0423,
     0x0416,
     0x0412,
     0x042c,
     0x042b,
     0x0417,
     0x0428,
     0x042d,
     0x0429,
     0x0427,
     0x042a,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\x04",
     "\x05",
     "\x06",
     "\x07",
     "\x08",
     "\x09",
     "\x0a",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\x14",
     "\x15",
     "\x16",
     "\x17",
     "\x18",
     "\x19",
     "\x1a",
     "\x1b",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\x20",
     "\x21",
     "\x22",
     "\x23",
     "\x24",
     "\x25",
     "\x26",
     "\x27",
     "\x28",
     "\x29",
     "\x2a",
     "\x2b",
     "\x2c",
     "\x2d",
     "\x2e",
     "\x2f",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\x3a",
     "\x3b",
     "\x3c",
     "\x3d",
     "\x3e",
     "\x3f",
     "\x40",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\x5b",
     "\x5c",
     "\x5d",
     "\x5e",
     "\x5f",
     "\x60",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\x7b",
     "\x7c",
     "\x7d",
     "\x7e",
     "\x7f",
     "\xe2\x94\x80",
     "\xe2\x94\x82",
     "\xe2\x94\x8c",
     "\xe2\x94\x90",
     "\xe2\x94\x94",
     "\xe2\x94\x98",
     "\xe2\x94\x9c",
     "\xe2\x94\xa4",
     "\xe2\x94\xac",
     "\xe2\x94\xb4",
     "\xe2\x94\xbc",
     "\xe2\x96\x80",
     "\xe2\x96\x84",
     "\xe2\x96\x88",
     "\xe2\x96\x8c",
     "\xe2\x96\x90",
     "\xe2\x96\x91",
     "\xe2\x96\x92",
     "\xe2\x96\x93",
     "\xe2\x8c\xa0",
     "\xe2\x96\xa0",
     "\xe2\x88\x99",
     "\xe2\x88\x9a",
     "\xe2\x89\x88",
     "\xe2\x89\xa4",
     "\xe2\x89\xa5",
     "\xc2\xa0",
     "\xe2\x8c\xa1",
     "\xc2\xb0",
     "\xc2\xb2",
     "\xc2\xb7",
     "\xc3\xb7",
     "\xe2\x95\x90",
     "\xe2\x95\x91",
     "\xe2\x95\x92",
     "\xd1\x91",
     "\xe2\x95\x93",
     "\xe2\x95\x94",
     "\xe2\x95\x95",
     "\xe2\x95\x96",
     "\xe2\x95\x97",
     "\xe2\x95\x98",
     "\xe2\x95\x99",
     "\xe2\x95\x9a",
     "\xe2\x95\x9b",
     "\xe2\x95\x9c",
     "\xe2\x95\x9d",
     "\xe2\x95\x9e",
     "\xe2\x95\x9f",
     "\xe2\x95\xa0",
     "\xe2\x95\xa1",
     "\xd0\x81",
     "\xe2\x95\xa2",
     "\xe2\x95\xa3",
     "\xe2\x95\xa4",
     "\xe2\x95\xa5",
     "\xe2\x95\xa6",
     "\xe2\x95\xa7",
     "\xe2\x95\xa8",
     "\xe2\x95\xa9",
     "\xe2\x95\xaa",
     "\xe2\x95\xab",
     "\xe2\x95\xac",
     "\xc2\xa9",
     "\xd1\x8e",
     "\xd0\xb0",
     "\xd0\xb1",
     "\xd1\x86",
     "\xd0\xb4",
     "\xd0\xb5",
     "\xd1\x84",
     "\xd0\xb3",
     "\xd1\x85",
     "\xd0\xb8",
     "\xd0\xb9",
     "\xd0\xba",
     "\xd0\xbb",
     "\xd0\xbc",
     "\xd0\xbd",
     "\xd0\xbe",
     "\xd0\xbf",
     "\xd1\x8f",
     "\xd1\x80",
     "\xd1\x81",
     "\xd1\x82",
     "\xd1\x83",
     "\xd0\xb6",
     "\xd0\xb2",
     "\xd1\x8c",
     "\xd1\x8b",
     "\xd0\xb7",
     "\xd1\x88",
     "\xd1\x8d",
     "\xd1\x89",
     "\xd1\x87",
     "\xd1\x8a",
     "\xd0\xae",
     "\xd0\x90",
     "\xd0\x91",
     "\xd0\xa6",
     "\xd0\x94",
     "\xd0\x95",
     "\xd0\xa4",
     "\xd0\x93",
     "\xd0\xa5",
     "\xd0\x98",
     "\xd0\x99",
     "\xd0\x9a",
     "\xd0\x9b",
     "\xd0\x9c",
     "\xd0\x9d",
     "\xd0\x9e",
     "\xd0\x9f",
     "\xd0\xaf",
     "\xd0\xa0",
     "\xd0\xa1",
     "\xd0\xa2",
     "\xd0\xa3",
     "\xd0\x96",
     "\xd0\x92",
     "\xd0\xac",
     "\xd0\xab",
     "\xd0\x97",
     "\xd0\xa8",
     "\xd0\xad",
     "\xd0\xa9",
     "\xd0\xa7",
     "\xd0\xaa",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x04",
     0x00000005 => "\x05",
     0x00000006 => "\x06",
     0x00000007 => "\x07",
     0x00000008 => "\x08",
     0x00000009 => "\x09",
     0x0000000a => "\x0a",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x14",
     0x00000015 => "\x15",
     0x00000016 => "\x16",
     0x00000017 => "\x17",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x1a",
     0x0000001b => "\x1b",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x20",
     0x00000021 => "\x21",
     0x00000022 => "\x22",
     0x00000023 => "\x23",
     0x00000024 => "\x24",
     0x00000025 => "\x25",
     0x00000026 => "\x26",
     0x00000027 => "\x27",
     0x00000028 => "\x28",
     0x00000029 => "\x29",
     0x0000002a => "\x2a",
     0x0000002b => "\x2b",
     0x0000002c => "\x2c",
     0x0000002d => "\x2d",
     0x0000002e => "\x2e",
     0x0000002f => "\x2f",
     0x00000030 => "\x30",
     0x00000031 => "\x31",
     0x00000032 => "\x32",
     0x00000033 => "\x33",
     0x00000034 => "\x34",
     0x00000035 => "\x35",
     0x00000036 => "\x36",
     0x00000037 => "\x37",
     0x00000038 => "\x38",
     0x00000039 => "\x39",
     0x0000003a => "\x3a",
     0x0000003b => "\x3b",
     0x0000003c => "\x3c",
     0x0000003d => "\x3d",
     0x0000003e => "\x3e",
     0x0000003f => "\x3f",
     0x00000040 => "\x40",
     0x00000041 => "\x41",
     0x00000042 => "\x42",
     0x00000043 => "\x43",
     0x00000044 => "\x44",
     0x00000045 => "\x45",
     0x00000046 => "\x46",
     0x00000047 => "\x47",
     0x00000048 => "\x48",
     0x00000049 => "\x49",
     0x0000004a => "\x4a",
     0x0000004b => "\x4b",
     0x0000004c => "\x4c",
     0x0000004d => "\x4d",
     0x0000004e => "\x4e",
     0x0000004f => "\x4f",
     0x00000050 => "\x50",
     0x00000051 => "\x51",
     0x00000052 => "\x52",
     0x00000053 => "\x53",
     0x00000054 => "\x54",
     0x00000055 => "\x55",
     0x00000056 => "\x56",
     0x00000057 => "\x57",
     0x00000058 => "\x58",
     0x00000059 => "\x59",
     0x0000005a => "\x5a",
     0x0000005b => "\x5b",
     0x0000005c => "\x5c",
     0x0000005d => "\x5d",
     0x0000005e => "\x5e",
     0x0000005f => "\x5f",
     0x00000060 => "\x60",
     0x00000061 => "\x61",
     0x00000062 => "\x62",
     0x00000063 => "\x63",
     0x00000064 => "\x64",
     0x00000065 => "\x65",
     0x00000066 => "\x66",
     0x00000067 => "\x67",
     0x00000068 => "\x68",
     0x00000069 => "\x69",
     0x0000006a => "\x6a",
     0x0000006b => "\x6b",
     0x0000006c => "\x6c",
     0x0000006d => "\x6d",
     0x0000006e => "\x6e",
     0x0000006f => "\x6f",
     0x00000070 => "\x70",
     0x00000071 => "\x71",
     0x00000072 => "\x72",
     0x00000073 => "\x73",
     0x00000074 => "\x74",
     0x00000075 => "\x75",
     0x00000076 => "\x76",
     0x00000077 => "\x77",
     0x00000078 => "\x78",
     0x00000079 => "\x79",
     0x0000007a => "\x7a",
     0x0000007b => "\x7b",
     0x0000007c => "\x7c",
     0x0000007d => "\x7d",
     0x0000007e => "\x7e",
     0x0000007f => "\x7f",
     0x000000a0 => "\x9a",
     0x000000a9 => "\xbf",
     0x000000b0 => "\x9c",
     0x000000b2 => "\x9d",
     0x000000b7 => "\x9e",
     0x000000f7 => "\x9f",
     0x00000401 => "\xb3",
     0x00000410 => "\xe1",
     0x00000411 => "\xe2",
     0x00000412 => "\xf7",
     0x00000413 => "\xe7",
     0x00000414 => "\xe4",
     0x00000415 => "\xe5",
     0x00000416 => "\xf6",
     0x00000417 => "\xfa",
     0x00000418 => "\xe9",
     0x00000419 => "\xea",
     0x0000041a => "\xeb",
     0x0000041b => "\xec",
     0x0000041c => "\xed",
     0x0000041d => "\xee",
     0x0000041e => "\xef",
     0x0000041f => "\xf0",
     0x00000420 => "\xf2",
     0x00000421 => "\xf3",
     0x00000422 => "\xf4",
     0x00000423 => "\xf5",
     0x00000424 => "\xe6",
     0x00000425 => "\xe8",
     0x00000426 => "\xe3",
     0x00000427 => "\xfe",
     0x00000428 => "\xfb",
     0x00000429 => "\xfd",
     0x0000042a => "\xff",
     0x0000042b => "\xf9",
     0x0000042c => "\xf8",
     0x0000042d => "\xfc",
     0x0000042e => "\xe0",
     0x0000042f => "\xf1",
     0x00000430 => "\xc1",
     0x00000431 => "\xc2",
     0x00000432 => "\xd7",
     0x00000433 => "\xc7",
     0x00000434 => "\xc4",
     0x00000435 => "\xc5",
     0x00000436 => "\xd6",
     0x00000437 => "\xda",
     0x00000438 => "\xc9",
     0x00000439 => "\xca",
     0x0000043a => "\xcb",
     0x0000043b => "\xcc",
     0x0000043c => "\xcd",
     0x0000043d => "\xce",
     0x0000043e => "\xcf",
     0x0000043f => "\xd0",
     0x00000440 => "\xd2",
     0x00000441 => "\xd3",
     0x00000442 => "\xd4",
     0x00000443 => "\xd5",
     0x00000444 => "\xc6",
     0x00000445 => "\xc8",
     0x00000446 => "\xc3",
     0x00000447 => "\xde",
     0x00000448 => "\xdb",
     0x00000449 => "\xdd",
     0x0000044a => "\xdf",
     0x0000044b => "\xd9",
     0x0000044c => "\xd8",
     0x0000044d => "\xdc",
     0x0000044e => "\xc0",
     0x0000044f => "\xd1",
     0x00000451 => "\xa3",
     0x00002219 => "\x95",
     0x0000221a => "\x96",
     0x00002248 => "\x97",
     0x00002264 => "\x98",
     0x00002265 => "\x99",
     0x00002320 => "\x93",
     0x00002321 => "\x9b",
     0x00002500 => "\x80",
     0x00002502 => "\x81",
     0x0000250c => "\x82",
     0x00002510 => "\x83",
     0x00002514 => "\x84",
     0x00002518 => "\x85",
     0x0000251c => "\x86",
     0x00002524 => "\x87",
     0x0000252c => "\x88",
     0x00002534 => "\x89",
     0x0000253c => "\x8a",
     0x00002550 => "\xa0",
     0x00002551 => "\xa1",
     0x00002552 => "\xa2",
     0x00002553 => "\xa4",
     0x00002554 => "\xa5",
     0x00002555 => "\xa6",
     0x00002556 => "\xa7",
     0x00002557 => "\xa8",
     0x00002558 => "\xa9",
     0x00002559 => "\xaa",
     0x0000255a => "\xab",
     0x0000255b => "\xac",
     0x0000255c => "\xad",
     0x0000255d => "\xae",
     0x0000255e => "\xaf",
     0x0000255f => "\xb0",
     0x00002560 => "\xb1",
     0x00002561 => "\xb2",
     0x00002562 => "\xb4",
     0x00002563 => "\xb5",
     0x00002564 => "\xb6",
     0x00002565 => "\xb7",
     0x00002566 => "\xb8",
     0x00002567 => "\xb9",
     0x00002568 => "\xba",
     0x00002569 => "\xbb",
     0x0000256a => "\xbc",
     0x0000256b => "\xbd",
     0x0000256c => "\xbe",
     0x00002580 => "\x8b",
     0x00002584 => "\x8c",
     0x00002588 => "\x8d",
     0x0000258c => "\x8e",
     0x00002590 => "\x8f",
     0x00002591 => "\x90",
     0x00002592 => "\x91",
     0x00002593 => "\x92",
     0x000025a0 => "\x94",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::KOI8_R - Conversion routines for KOI8-R
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for KOI8-R.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
   source: RFC1489 via Gabor Kiss E<lt>kissg@sztaki.huE<gt>
   and Andrey A. Chernov E<lt>ache@astral.msk.suE<gt>
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  00000004 | END OF TRANSMISSION (EOT)
     05 |  00000005 | ENQUIRY (ENQ)
     06 |  00000006 | ACKNOWLEDGE (ACK)
     07 |  00000007 | BELL (BEL)
     08 |  00000008 | BACKSPACE (BS)
     09 |  00000009 | CHARACTER TABULATION (HT)
     0A |  0000000A | LINE FEED (LF)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  00000014 | DEVICE CONTROL FOUR (DC4)
     15 |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     16 |  00000016 | SYNCHRONOUS IDLE (SYN)
     17 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  0000001A | SUBSTITUTE (SUB)
     1B |  0000001B | ESCAPE (ESC)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000020 | SPACE
     21 |  00000021 | EXCLAMATION MARK
     22 |  00000022 | QUOTATION MARK
     23 |  00000023 | NUMBER SIGN
     24 |  00000024 | DOLLAR SIGN
     25 |  00000025 | PERCENT SIGN
     26 |  00000026 | AMPERSAND
     27 |  00000027 | APOSTROPHE
     28 |  00000028 | LEFT PARENTHESIS
     29 |  00000029 | RIGHT PARENTHESIS
     2A |  0000002A | ASTERISK
     2B |  0000002B | PLUS SIGN
     2C |  0000002C | COMMA
     2D |  0000002D | HYPHEN-MINUS
     2E |  0000002E | FULL STOP
     2F |  0000002F | SOLIDUS
     30 |  00000030 | DIGIT ZERO
     31 |  00000031 | DIGIT ONE
     32 |  00000032 | DIGIT TWO
     33 |  00000033 | DIGIT THREE
     34 |  00000034 | DIGIT FOUR
     35 |  00000035 | DIGIT FIVE
     36 |  00000036 | DIGIT SIX
     37 |  00000037 | DIGIT SEVEN
     38 |  00000038 | DIGIT EIGHT
     39 |  00000039 | DIGIT NINE
     3A |  0000003A | COLON
     3B |  0000003B | SEMICOLON
     3C |  0000003C | LESS-THAN SIGN
     3D |  0000003D | EQUALS SIGN
     3E |  0000003E | GREATER-THAN SIGN
     3F |  0000003F | QUESTION MARK
     40 |  00000040 | COMMERCIAL AT
     41 |  00000041 | LATIN CAPITAL LETTER A
     42 |  00000042 | LATIN CAPITAL LETTER B
     43 |  00000043 | LATIN CAPITAL LETTER C
     44 |  00000044 | LATIN CAPITAL LETTER D
     45 |  00000045 | LATIN CAPITAL LETTER E
     46 |  00000046 | LATIN CAPITAL LETTER F
     47 |  00000047 | LATIN CAPITAL LETTER G
     48 |  00000048 | LATIN CAPITAL LETTER H
     49 |  00000049 | LATIN CAPITAL LETTER I
     4A |  0000004A | LATIN CAPITAL LETTER J
     4B |  0000004B | LATIN CAPITAL LETTER K
     4C |  0000004C | LATIN CAPITAL LETTER L
     4D |  0000004D | LATIN CAPITAL LETTER M
     4E |  0000004E | LATIN CAPITAL LETTER N
     4F |  0000004F | LATIN CAPITAL LETTER O
     50 |  00000050 | LATIN CAPITAL LETTER P
     51 |  00000051 | LATIN CAPITAL LETTER Q
     52 |  00000052 | LATIN CAPITAL LETTER R
     53 |  00000053 | LATIN CAPITAL LETTER S
     54 |  00000054 | LATIN CAPITAL LETTER T
     55 |  00000055 | LATIN CAPITAL LETTER U
     56 |  00000056 | LATIN CAPITAL LETTER V
     57 |  00000057 | LATIN CAPITAL LETTER W
     58 |  00000058 | LATIN CAPITAL LETTER X
     59 |  00000059 | LATIN CAPITAL LETTER Y
     5A |  0000005A | LATIN CAPITAL LETTER Z
     5B |  0000005B | LEFT SQUARE BRACKET
     5C |  0000005C | REVERSE SOLIDUS
     5D |  0000005D | RIGHT SQUARE BRACKET
     5E |  0000005E | CIRCUMFLEX ACCENT
     5F |  0000005F | LOW LINE
     60 |  00000060 | GRAVE ACCENT
     61 |  00000061 | LATIN SMALL LETTER A
     62 |  00000062 | LATIN SMALL LETTER B
     63 |  00000063 | LATIN SMALL LETTER C
     64 |  00000064 | LATIN SMALL LETTER D
     65 |  00000065 | LATIN SMALL LETTER E
     66 |  00000066 | LATIN SMALL LETTER F
     67 |  00000067 | LATIN SMALL LETTER G
     68 |  00000068 | LATIN SMALL LETTER H
     69 |  00000069 | LATIN SMALL LETTER I
     6A |  0000006A | LATIN SMALL LETTER J
     6B |  0000006B | LATIN SMALL LETTER K
     6C |  0000006C | LATIN SMALL LETTER L
     6D |  0000006D | LATIN SMALL LETTER M
     6E |  0000006E | LATIN SMALL LETTER N
     6F |  0000006F | LATIN SMALL LETTER O
     70 |  00000070 | LATIN SMALL LETTER P
     71 |  00000071 | LATIN SMALL LETTER Q
     72 |  00000072 | LATIN SMALL LETTER R
     73 |  00000073 | LATIN SMALL LETTER S
     74 |  00000074 | LATIN SMALL LETTER T
     75 |  00000075 | LATIN SMALL LETTER U
     76 |  00000076 | LATIN SMALL LETTER V
     77 |  00000077 | LATIN SMALL LETTER W
     78 |  00000078 | LATIN SMALL LETTER X
     79 |  00000079 | LATIN SMALL LETTER Y
     7A |  0000007A | LATIN SMALL LETTER Z
     7B |  0000007B | LEFT CURLY BRACKET
     7C |  0000007C | VERTICAL LINE
     7D |  0000007D | RIGHT CURLY BRACKET
     7E |  0000007E | TILDE
     7F |  0000007F | DELETE (DEL)
     80 |  00002500 | BOX DRAWINGS LIGHT HORIZONTAL
     81 |  00002502 | BOX DRAWINGS LIGHT VERTICAL
     82 |  0000250C | BOX DRAWINGS LIGHT DOWN AND RIGHT
     83 |  00002510 | BOX DRAWINGS LIGHT DOWN AND LEFT
     84 |  00002514 | BOX DRAWINGS LIGHT UP AND RIGHT
     85 |  00002518 | BOX DRAWINGS LIGHT UP AND LEFT
     86 |  0000251C | BOX DRAWINGS LIGHT VERTICAL AND RIGHT
     87 |  00002524 | BOX DRAWINGS LIGHT VERTICAL AND LEFT
     88 |  0000252C | BOX DRAWINGS LIGHT DOWN AND HORIZONTAL
     89 |  00002534 | BOX DRAWINGS LIGHT UP AND HORIZONTAL
     8A |  0000253C | BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL
     8B |  00002580 | UPPER HALF BLOCK
     8C |  00002584 | LOWER HALF BLOCK
     8D |  00002588 | FULL BLOCK
     8E |  0000258C | LEFT HALF BLOCK
     8F |  00002590 | RIGHT HALF BLOCK
     90 |  00002591 | LIGHT SHADE
     91 |  00002592 | MEDIUM SHADE
     92 |  00002593 | DARK SHADE
     93 |  00002320 | TOP HALF INTEGRAL
     94 |  000025A0 | BLACK SQUARE
     95 |  00002219 | BULLET OPERATOR
     96 |  0000221A | SQUARE ROOT
     97 |  00002248 | ALMOST EQUAL TO
     98 |  00002264 | LESS-THAN OR EQUAL TO
     99 |  00002265 | GREATER-THAN OR EQUAL TO
     9A |  000000A0 | NO-BREAK SPACE
     9B |  00002321 | BOTTOM HALF INTEGRAL
     9C |  000000B0 | DEGREE SIGN
     9D |  000000B2 | SUPERSCRIPT TWO
     9E |  000000B7 | MIDDLE DOT
     9F |  000000F7 | DIVISION SIGN
     A0 |  00002550 | BOX DRAWINGS DOUBLE HORIZONTAL
     A1 |  00002551 | BOX DRAWINGS DOUBLE VERTICAL
     A2 |  00002552 | BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE
     A3 |  00000451 | CYRILLIC SMALL LETTER IO
     A4 |  00002553 | BOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLE
     A5 |  00002554 | BOX DRAWINGS DOUBLE DOWN AND RIGHT
     A6 |  00002555 | BOX DRAWINGS DOWN SINGLE AND LEFT DOUBLE
     A7 |  00002556 | BOX DRAWINGS DOWN DOUBLE AND LEFT SINGLE
     A8 |  00002557 | BOX DRAWINGS DOUBLE DOWN AND LEFT
     A9 |  00002558 | BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE
     AA |  00002559 | BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE
     AB |  0000255A | BOX DRAWINGS DOUBLE UP AND RIGHT
     AC |  0000255B | BOX DRAWINGS UP SINGLE AND LEFT DOUBLE
     AD |  0000255C | BOX DRAWINGS UP DOUBLE AND LEFT SINGLE
     AE |  0000255D | BOX DRAWINGS DOUBLE UP AND LEFT
     AF |  0000255E | BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE
     B0 |  0000255F | BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE
     B1 |  00002560 | BOX DRAWINGS DOUBLE VERTICAL AND RIGHT
     B2 |  00002561 | BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE
     B3 |  00000401 | CYRILLIC CAPITAL LETTER IO
     B4 |  00002562 | BOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLE
     B5 |  00002563 | BOX DRAWINGS DOUBLE VERTICAL AND LEFT
     B6 |  00002564 | BOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLE
     B7 |  00002565 | BOX DRAWINGS DOWN DOUBLE AND HORIZONTAL SINGLE
     B8 |  00002566 | BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL
     B9 |  00002567 | BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE
     BA |  00002568 | BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE
     BB |  00002569 | BOX DRAWINGS DOUBLE UP AND HORIZONTAL
     BC |  0000256A | BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE
     BD |  0000256B | BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLE
     BE |  0000256C | BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL
     BF |  000000A9 | COPYRIGHT SIGN
     C0 |  0000044E | CYRILLIC SMALL LETTER YU
     C1 |  00000430 | CYRILLIC SMALL LETTER A
     C2 |  00000431 | CYRILLIC SMALL LETTER BE
     C3 |  00000446 | CYRILLIC SMALL LETTER TSE
     C4 |  00000434 | CYRILLIC SMALL LETTER DE
     C5 |  00000435 | CYRILLIC SMALL LETTER IE
     C6 |  00000444 | CYRILLIC SMALL LETTER EF
     C7 |  00000433 | CYRILLIC SMALL LETTER GHE
     C8 |  00000445 | CYRILLIC SMALL LETTER HA
     C9 |  00000438 | CYRILLIC SMALL LETTER I
     CA |  00000439 | CYRILLIC SMALL LETTER SHORT I
     CB |  0000043A | CYRILLIC SMALL LETTER KA
     CC |  0000043B | CYRILLIC SMALL LETTER EL
     CD |  0000043C | CYRILLIC SMALL LETTER EM
     CE |  0000043D | CYRILLIC SMALL LETTER EN
     CF |  0000043E | CYRILLIC SMALL LETTER O
     D0 |  0000043F | CYRILLIC SMALL LETTER PE
     D1 |  0000044F | CYRILLIC SMALL LETTER YA
     D2 |  00000440 | CYRILLIC SMALL LETTER ER
     D3 |  00000441 | CYRILLIC SMALL LETTER ES
     D4 |  00000442 | CYRILLIC SMALL LETTER TE
     D5 |  00000443 | CYRILLIC SMALL LETTER U
     D6 |  00000436 | CYRILLIC SMALL LETTER ZHE
     D7 |  00000432 | CYRILLIC SMALL LETTER VE
     D8 |  0000044C | CYRILLIC SMALL LETTER SOFT SIGN
     D9 |  0000044B | CYRILLIC SMALL LETTER YERU
     DA |  00000437 | CYRILLIC SMALL LETTER ZE
     DB |  00000448 | CYRILLIC SMALL LETTER SHA
     DC |  0000044D | CYRILLIC SMALL LETTER E
     DD |  00000449 | CYRILLIC SMALL LETTER SHCHA
     DE |  00000447 | CYRILLIC SMALL LETTER CHE
     DF |  0000044A | CYRILLIC SMALL LETTER HARD SIGN
     E0 |  0000042E | CYRILLIC CAPITAL LETTER YU
     E1 |  00000410 | CYRILLIC CAPITAL LETTER A
     E2 |  00000411 | CYRILLIC CAPITAL LETTER BE
     E3 |  00000426 | CYRILLIC CAPITAL LETTER TSE
     E4 |  00000414 | CYRILLIC CAPITAL LETTER DE
     E5 |  00000415 | CYRILLIC CAPITAL LETTER IE
     E6 |  00000424 | CYRILLIC CAPITAL LETTER EF
     E7 |  00000413 | CYRILLIC CAPITAL LETTER GHE
     E8 |  00000425 | CYRILLIC CAPITAL LETTER HA
     E9 |  00000418 | CYRILLIC CAPITAL LETTER I
     EA |  00000419 | CYRILLIC CAPITAL LETTER SHORT I
     EB |  0000041A | CYRILLIC CAPITAL LETTER KA
     EC |  0000041B | CYRILLIC CAPITAL LETTER EL
     ED |  0000041C | CYRILLIC CAPITAL LETTER EM
     EE |  0000041D | CYRILLIC CAPITAL LETTER EN
     EF |  0000041E | CYRILLIC CAPITAL LETTER O
     F0 |  0000041F | CYRILLIC CAPITAL LETTER PE
     F1 |  0000042F | CYRILLIC CAPITAL LETTER YA
     F2 |  00000420 | CYRILLIC CAPITAL LETTER ER
     F3 |  00000421 | CYRILLIC CAPITAL LETTER ES
     F4 |  00000422 | CYRILLIC CAPITAL LETTER TE
     F5 |  00000423 | CYRILLIC CAPITAL LETTER U
     F6 |  00000416 | CYRILLIC CAPITAL LETTER ZHE
     F7 |  00000412 | CYRILLIC CAPITAL LETTER VE
     F8 |  0000042C | CYRILLIC CAPITAL LETTER SOFT SIGN
     F9 |  0000042B | CYRILLIC CAPITAL LETTER YERU
     FA |  00000417 | CYRILLIC CAPITAL LETTER ZE
     FB |  00000428 | CYRILLIC CAPITAL LETTER SHA
     FC |  0000042D | CYRILLIC CAPITAL LETTER E
     FD |  00000429 | CYRILLIC CAPITAL LETTER SHCHA
     FE |  00000427 | CYRILLIC CAPITAL LETTER CHE
     FF |  0000042A | CYRILLIC CAPITAL LETTER HARD SIGN
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/KOI8_RU.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for KOI8-RU.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::KOI8_RU;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x0004,
     0x0005,
     0x0006,
     0x0007,
     0x0008,
     0x0009,
     0x000a,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x0014,
     0x0015,
     0x0016,
     0x0017,
     0x0018,
     0x0019,
     0x001a,
     0x001b,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0020,
     0x0021,
     0x0022,
     0x0023,
     0x0024,
     0x0025,
     0x0026,
     0x0027,
     0x0028,
     0x0029,
     0x002a,
     0x002b,
     0x002c,
     0x002d,
     0x002e,
     0x002f,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x003a,
     0x003b,
     0x003c,
     0x003d,
     0x003e,
     0x003f,
     0x0040,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x005b,
     0x005c,
     0x005d,
     0x005e,
     0x005f,
     0x0060,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x007b,
     0x007c,
     0x007d,
     0x007e,
     0x007f,
     0x2500,
     0x2502,
     0x250c,
     0x2510,
     0x2514,
     0x2518,
     0x251c,
     0x2524,
     0x252c,
     0x2534,
     0x253c,
     0x2580,
     0x2584,
     0x2588,
     0x258c,
     0x2590,
     0x2591,
     0x2592,
     0x2593,
     0x2320,
     0x25a0,
     0x2219,
     0x221a,
     0x2248,
     0x2264,
     0x2265,
     0x00a0,
     0x2321,
     0x00b0,
     0x00b2,
     0x00b7,
     0x00f7,
     0x2550,
     0x2551,
     0x2552,
     0x0451,
     0x0454,
     0x2554,
     0x0456,
     0x0457,
     0x2557,
     0x2558,
     0x2559,
     0x255a,
     0x255b,
     0x0491,
     0x045e,
     0x255e,
     0x255f,
     0x2560,
     0x2561,
     0x0401,
     0x0404,
     0x2563,
     0x0406,
     0x0407,
     0x2566,
     0x2567,
     0x2568,
     0x2569,
     0x256a,
     0x0490,
     0x040e,
     0x00a9,
     0x044e,
     0x0430,
     0x0431,
     0x0446,
     0x0434,
     0x0435,
     0x0444,
     0x0433,
     0x0445,
     0x0438,
     0x0439,
     0x043a,
     0x043b,
     0x043c,
     0x043d,
     0x043e,
     0x043f,
     0x044f,
     0x0440,
     0x0441,
     0x0442,
     0x0443,
     0x0436,
     0x0432,
     0x044c,
     0x044b,
     0x0437,
     0x0448,
     0x044d,
     0x0449,
     0x0447,
     0x044a,
     0x042e,
     0x0410,
     0x0411,
     0x0426,
     0x0414,
     0x0415,
     0x0424,
     0x0413,
     0x0425,
     0x0418,
     0x0419,
     0x041a,
     0x041b,
     0x041c,
     0x041d,
     0x041e,
     0x041f,
     0x042f,
     0x0420,
     0x0421,
     0x0422,
     0x0423,
     0x0416,
     0x0412,
     0x042c,
     0x042b,
     0x0417,
     0x0428,
     0x042d,
     0x0429,
     0x0427,
     0x042a,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\x04",
     "\x05",
     "\x06",
     "\x07",
     "\x08",
     "\x09",
     "\x0a",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\x14",
     "\x15",
     "\x16",
     "\x17",
     "\x18",
     "\x19",
     "\x1a",
     "\x1b",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\x20",
     "\x21",
     "\x22",
     "\x23",
     "\x24",
     "\x25",
     "\x26",
     "\x27",
     "\x28",
     "\x29",
     "\x2a",
     "\x2b",
     "\x2c",
     "\x2d",
     "\x2e",
     "\x2f",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\x3a",
     "\x3b",
     "\x3c",
     "\x3d",
     "\x3e",
     "\x3f",
     "\x40",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\x5b",
     "\x5c",
     "\x5d",
     "\x5e",
     "\x5f",
     "\x60",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\x7b",
     "\x7c",
     "\x7d",
     "\x7e",
     "\x7f",
     "\xe2\x94\x80",
     "\xe2\x94\x82",
     "\xe2\x94\x8c",
     "\xe2\x94\x90",
     "\xe2\x94\x94",
     "\xe2\x94\x98",
     "\xe2\x94\x9c",
     "\xe2\x94\xa4",
     "\xe2\x94\xac",
     "\xe2\x94\xb4",
     "\xe2\x94\xbc",
     "\xe2\x96\x80",
     "\xe2\x96\x84",
     "\xe2\x96\x88",
     "\xe2\x96\x8c",
     "\xe2\x96\x90",
     "\xe2\x96\x91",
     "\xe2\x96\x92",
     "\xe2\x96\x93",
     "\xe2\x8c\xa0",
     "\xe2\x96\xa0",
     "\xe2\x88\x99",
     "\xe2\x88\x9a",
     "\xe2\x89\x88",
     "\xe2\x89\xa4",
     "\xe2\x89\xa5",
     "\xc2\xa0",
     "\xe2\x8c\xa1",
     "\xc2\xb0",
     "\xc2\xb2",
     "\xc2\xb7",
     "\xc3\xb7",
     "\xe2\x95\x90",
     "\xe2\x95\x91",
     "\xe2\x95\x92",
     "\xd1\x91",
     "\xd1\x94",
     "\xe2\x95\x94",
     "\xd1\x96",
     "\xd1\x97",
     "\xe2\x95\x97",
     "\xe2\x95\x98",
     "\xe2\x95\x99",
     "\xe2\x95\x9a",
     "\xe2\x95\x9b",
     "\xd2\x91",
     "\xd1\x9e",
     "\xe2\x95\x9e",
     "\xe2\x95\x9f",
     "\xe2\x95\xa0",
     "\xe2\x95\xa1",
     "\xd0\x81",
     "\xd0\x84",
     "\xe2\x95\xa3",
     "\xd0\x86",
     "\xd0\x87",
     "\xe2\x95\xa6",
     "\xe2\x95\xa7",
     "\xe2\x95\xa8",
     "\xe2\x95\xa9",
     "\xe2\x95\xaa",
     "\xd2\x90",
     "\xd0\x8e",
     "\xc2\xa9",
     "\xd1\x8e",
     "\xd0\xb0",
     "\xd0\xb1",
     "\xd1\x86",
     "\xd0\xb4",
     "\xd0\xb5",
     "\xd1\x84",
     "\xd0\xb3",
     "\xd1\x85",
     "\xd0\xb8",
     "\xd0\xb9",
     "\xd0\xba",
     "\xd0\xbb",
     "\xd0\xbc",
     "\xd0\xbd",
     "\xd0\xbe",
     "\xd0\xbf",
     "\xd1\x8f",
     "\xd1\x80",
     "\xd1\x81",
     "\xd1\x82",
     "\xd1\x83",
     "\xd0\xb6",
     "\xd0\xb2",
     "\xd1\x8c",
     "\xd1\x8b",
     "\xd0\xb7",
     "\xd1\x88",
     "\xd1\x8d",
     "\xd1\x89",
     "\xd1\x87",
     "\xd1\x8a",
     "\xd0\xae",
     "\xd0\x90",
     "\xd0\x91",
     "\xd0\xa6",
     "\xd0\x94",
     "\xd0\x95",
     "\xd0\xa4",
     "\xd0\x93",
     "\xd0\xa5",
     "\xd0\x98",
     "\xd0\x99",
     "\xd0\x9a",
     "\xd0\x9b",
     "\xd0\x9c",
     "\xd0\x9d",
     "\xd0\x9e",
     "\xd0\x9f",
     "\xd0\xaf",
     "\xd0\xa0",
     "\xd0\xa1",
     "\xd0\xa2",
     "\xd0\xa3",
     "\xd0\x96",
     "\xd0\x92",
     "\xd0\xac",
     "\xd0\xab",
     "\xd0\x97",
     "\xd0\xa8",
     "\xd0\xad",
     "\xd0\xa9",
     "\xd0\xa7",
     "\xd0\xaa",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x04",
     0x00000005 => "\x05",
     0x00000006 => "\x06",
     0x00000007 => "\x07",
     0x00000008 => "\x08",
     0x00000009 => "\x09",
     0x0000000a => "\x0a",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x14",
     0x00000015 => "\x15",
     0x00000016 => "\x16",
     0x00000017 => "\x17",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x1a",
     0x0000001b => "\x1b",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x20",
     0x00000021 => "\x21",
     0x00000022 => "\x22",
     0x00000023 => "\x23",
     0x00000024 => "\x24",
     0x00000025 => "\x25",
     0x00000026 => "\x26",
     0x00000027 => "\x27",
     0x00000028 => "\x28",
     0x00000029 => "\x29",
     0x0000002a => "\x2a",
     0x0000002b => "\x2b",
     0x0000002c => "\x2c",
     0x0000002d => "\x2d",
     0x0000002e => "\x2e",
     0x0000002f => "\x2f",
     0x00000030 => "\x30",
     0x00000031 => "\x31",
     0x00000032 => "\x32",
     0x00000033 => "\x33",
     0x00000034 => "\x34",
     0x00000035 => "\x35",
     0x00000036 => "\x36",
     0x00000037 => "\x37",
     0x00000038 => "\x38",
     0x00000039 => "\x39",
     0x0000003a => "\x3a",
     0x0000003b => "\x3b",
     0x0000003c => "\x3c",
     0x0000003d => "\x3d",
     0x0000003e => "\x3e",
     0x0000003f => "\x3f",
     0x00000040 => "\x40",
     0x00000041 => "\x41",
     0x00000042 => "\x42",
     0x00000043 => "\x43",
     0x00000044 => "\x44",
     0x00000045 => "\x45",
     0x00000046 => "\x46",
     0x00000047 => "\x47",
     0x00000048 => "\x48",
     0x00000049 => "\x49",
     0x0000004a => "\x4a",
     0x0000004b => "\x4b",
     0x0000004c => "\x4c",
     0x0000004d => "\x4d",
     0x0000004e => "\x4e",
     0x0000004f => "\x4f",
     0x00000050 => "\x50",
     0x00000051 => "\x51",
     0x00000052 => "\x52",
     0x00000053 => "\x53",
     0x00000054 => "\x54",
     0x00000055 => "\x55",
     0x00000056 => "\x56",
     0x00000057 => "\x57",
     0x00000058 => "\x58",
     0x00000059 => "\x59",
     0x0000005a => "\x5a",
     0x0000005b => "\x5b",
     0x0000005c => "\x5c",
     0x0000005d => "\x5d",
     0x0000005e => "\x5e",
     0x0000005f => "\x5f",
     0x00000060 => "\x60",
     0x00000061 => "\x61",
     0x00000062 => "\x62",
     0x00000063 => "\x63",
     0x00000064 => "\x64",
     0x00000065 => "\x65",
     0x00000066 => "\x66",
     0x00000067 => "\x67",
     0x00000068 => "\x68",
     0x00000069 => "\x69",
     0x0000006a => "\x6a",
     0x0000006b => "\x6b",
     0x0000006c => "\x6c",
     0x0000006d => "\x6d",
     0x0000006e => "\x6e",
     0x0000006f => "\x6f",
     0x00000070 => "\x70",
     0x00000071 => "\x71",
     0x00000072 => "\x72",
     0x00000073 => "\x73",
     0x00000074 => "\x74",
     0x00000075 => "\x75",
     0x00000076 => "\x76",
     0x00000077 => "\x77",
     0x00000078 => "\x78",
     0x00000079 => "\x79",
     0x0000007a => "\x7a",
     0x0000007b => "\x7b",
     0x0000007c => "\x7c",
     0x0000007d => "\x7d",
     0x0000007e => "\x7e",
     0x0000007f => "\x7f",
     0x000000a0 => "\x9a",
     0x000000a9 => "\xbf",
     0x000000b0 => "\x9c",
     0x000000b2 => "\x9d",
     0x000000b7 => "\x9e",
     0x000000f7 => "\x9f",
     0x00000401 => "\xb3",
     0x00000404 => "\xb4",
     0x00000406 => "\xb6",
     0x00000407 => "\xb7",
     0x0000040e => "\xbe",
     0x00000410 => "\xe1",
     0x00000411 => "\xe2",
     0x00000412 => "\xf7",
     0x00000413 => "\xe7",
     0x00000414 => "\xe4",
     0x00000415 => "\xe5",
     0x00000416 => "\xf6",
     0x00000417 => "\xfa",
     0x00000418 => "\xe9",
     0x00000419 => "\xea",
     0x0000041a => "\xeb",
     0x0000041b => "\xec",
     0x0000041c => "\xed",
     0x0000041d => "\xee",
     0x0000041e => "\xef",
     0x0000041f => "\xf0",
     0x00000420 => "\xf2",
     0x00000421 => "\xf3",
     0x00000422 => "\xf4",
     0x00000423 => "\xf5",
     0x00000424 => "\xe6",
     0x00000425 => "\xe8",
     0x00000426 => "\xe3",
     0x00000427 => "\xfe",
     0x00000428 => "\xfb",
     0x00000429 => "\xfd",
     0x0000042a => "\xff",
     0x0000042b => "\xf9",
     0x0000042c => "\xf8",
     0x0000042d => "\xfc",
     0x0000042e => "\xe0",
     0x0000042f => "\xf1",
     0x00000430 => "\xc1",
     0x00000431 => "\xc2",
     0x00000432 => "\xd7",
     0x00000433 => "\xc7",
     0x00000434 => "\xc4",
     0x00000435 => "\xc5",
     0x00000436 => "\xd6",
     0x00000437 => "\xda",
     0x00000438 => "\xc9",
     0x00000439 => "\xca",
     0x0000043a => "\xcb",
     0x0000043b => "\xcc",
     0x0000043c => "\xcd",
     0x0000043d => "\xce",
     0x0000043e => "\xcf",
     0x0000043f => "\xd0",
     0x00000440 => "\xd2",
     0x00000441 => "\xd3",
     0x00000442 => "\xd4",
     0x00000443 => "\xd5",
     0x00000444 => "\xc6",
     0x00000445 => "\xc8",
     0x00000446 => "\xc3",
     0x00000447 => "\xde",
     0x00000448 => "\xdb",
     0x00000449 => "\xdd",
     0x0000044a => "\xdf",
     0x0000044b => "\xd9",
     0x0000044c => "\xd8",
     0x0000044d => "\xdc",
     0x0000044e => "\xc0",
     0x0000044f => "\xd1",
     0x00000451 => "\xa3",
     0x00000454 => "\xa4",
     0x00000456 => "\xa6",
     0x00000457 => "\xa7",
     0x0000045e => "\xae",
     0x00000490 => "\xbd",
     0x00000491 => "\xad",
     0x00002219 => "\x95",
     0x0000221a => "\x96",
     0x00002248 => "\x97",
     0x00002264 => "\x98",
     0x00002265 => "\x99",
     0x00002320 => "\x93",
     0x00002321 => "\x9b",
     0x00002500 => "\x80",
     0x00002502 => "\x81",
     0x0000250c => "\x82",
     0x00002510 => "\x83",
     0x00002514 => "\x84",
     0x00002518 => "\x85",
     0x0000251c => "\x86",
     0x00002524 => "\x87",
     0x0000252c => "\x88",
     0x00002534 => "\x89",
     0x0000253c => "\x8a",
     0x00002550 => "\xa0",
     0x00002551 => "\xa1",
     0x00002552 => "\xa2",
     0x00002554 => "\xa5",
     0x00002557 => "\xa8",
     0x00002558 => "\xa9",
     0x00002559 => "\xaa",
     0x0000255a => "\xab",
     0x0000255b => "\xac",
     0x0000255e => "\xaf",
     0x0000255f => "\xb0",
     0x00002560 => "\xb1",
     0x00002561 => "\xb2",
     0x00002563 => "\xb5",
     0x00002566 => "\xb8",
     0x00002567 => "\xb9",
     0x00002568 => "\xba",
     0x00002569 => "\xbb",
     0x0000256a => "\xbc",
     0x00002580 => "\x8b",
     0x00002584 => "\x8c",
     0x00002588 => "\x8d",
     0x0000258c => "\x8e",
     0x00002590 => "\x8f",
     0x00002591 => "\x90",
     0x00002592 => "\x91",
     0x00002593 => "\x92",
     0x000025a0 => "\x94",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::KOI8_RU - Conversion routines for KOI8-RU
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for KOI8-RU.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
 
  This charmap has been generated automatically from GNU libiconv
  conversions.
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  00000004 | END OF TRANSMISSION (EOT)
     05 |  00000005 | ENQUIRY (ENQ)
     06 |  00000006 | ACKNOWLEDGE (ACK)
     07 |  00000007 | BELL (BEL)
     08 |  00000008 | BACKSPACE (BS)
     09 |  00000009 | CHARACTER TABULATION (HT)
     0A |  0000000A | LINE FEED (LF)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  00000014 | DEVICE CONTROL FOUR (DC4)
     15 |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     16 |  00000016 | SYNCHRONOUS IDLE (SYN)
     17 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  0000001A | SUBSTITUTE (SUB)
     1B |  0000001B | ESCAPE (ESC)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000020 | SPACE
     21 |  00000021 | EXCLAMATION MARK
     22 |  00000022 | QUOTATION MARK
     23 |  00000023 | NUMBER SIGN
     24 |  00000024 | DOLLAR SIGN
     25 |  00000025 | PERCENT SIGN
     26 |  00000026 | AMPERSAND
     27 |  00000027 | APOSTROPHE
     28 |  00000028 | LEFT PARENTHESIS
     29 |  00000029 | RIGHT PARENTHESIS
     2A |  0000002A | ASTERISK
     2B |  0000002B | PLUS SIGN
     2C |  0000002C | COMMA
     2D |  0000002D | HYPHEN-MINUS
     2E |  0000002E | FULL STOP
     2F |  0000002F | SOLIDUS
     30 |  00000030 | DIGIT ZERO
     31 |  00000031 | DIGIT ONE
     32 |  00000032 | DIGIT TWO
     33 |  00000033 | DIGIT THREE
     34 |  00000034 | DIGIT FOUR
     35 |  00000035 | DIGIT FIVE
     36 |  00000036 | DIGIT SIX
     37 |  00000037 | DIGIT SEVEN
     38 |  00000038 | DIGIT EIGHT
     39 |  00000039 | DIGIT NINE
     3A |  0000003A | COLON
     3B |  0000003B | SEMICOLON
     3C |  0000003C | LESS-THAN SIGN
     3D |  0000003D | EQUALS SIGN
     3E |  0000003E | GREATER-THAN SIGN
     3F |  0000003F | QUESTION MARK
     40 |  00000040 | COMMERCIAL AT
     41 |  00000041 | LATIN CAPITAL LETTER A
     42 |  00000042 | LATIN CAPITAL LETTER B
     43 |  00000043 | LATIN CAPITAL LETTER C
     44 |  00000044 | LATIN CAPITAL LETTER D
     45 |  00000045 | LATIN CAPITAL LETTER E
     46 |  00000046 | LATIN CAPITAL LETTER F
     47 |  00000047 | LATIN CAPITAL LETTER G
     48 |  00000048 | LATIN CAPITAL LETTER H
     49 |  00000049 | LATIN CAPITAL LETTER I
     4A |  0000004A | LATIN CAPITAL LETTER J
     4B |  0000004B | LATIN CAPITAL LETTER K
     4C |  0000004C | LATIN CAPITAL LETTER L
     4D |  0000004D | LATIN CAPITAL LETTER M
     4E |  0000004E | LATIN CAPITAL LETTER N
     4F |  0000004F | LATIN CAPITAL LETTER O
     50 |  00000050 | LATIN CAPITAL LETTER P
     51 |  00000051 | LATIN CAPITAL LETTER Q
     52 |  00000052 | LATIN CAPITAL LETTER R
     53 |  00000053 | LATIN CAPITAL LETTER S
     54 |  00000054 | LATIN CAPITAL LETTER T
     55 |  00000055 | LATIN CAPITAL LETTER U
     56 |  00000056 | LATIN CAPITAL LETTER V
     57 |  00000057 | LATIN CAPITAL LETTER W
     58 |  00000058 | LATIN CAPITAL LETTER X
     59 |  00000059 | LATIN CAPITAL LETTER Y
     5A |  0000005A | LATIN CAPITAL LETTER Z
     5B |  0000005B | LEFT SQUARE BRACKET
     5C |  0000005C | REVERSE SOLIDUS
     5D |  0000005D | RIGHT SQUARE BRACKET
     5E |  0000005E | CIRCUMFLEX ACCENT
     5F |  0000005F | LOW LINE
     60 |  00000060 | GRAVE ACCENT
     61 |  00000061 | LATIN SMALL LETTER A
     62 |  00000062 | LATIN SMALL LETTER B
     63 |  00000063 | LATIN SMALL LETTER C
     64 |  00000064 | LATIN SMALL LETTER D
     65 |  00000065 | LATIN SMALL LETTER E
     66 |  00000066 | LATIN SMALL LETTER F
     67 |  00000067 | LATIN SMALL LETTER G
     68 |  00000068 | LATIN SMALL LETTER H
     69 |  00000069 | LATIN SMALL LETTER I
     6A |  0000006A | LATIN SMALL LETTER J
     6B |  0000006B | LATIN SMALL LETTER K
     6C |  0000006C | LATIN SMALL LETTER L
     6D |  0000006D | LATIN SMALL LETTER M
     6E |  0000006E | LATIN SMALL LETTER N
     6F |  0000006F | LATIN SMALL LETTER O
     70 |  00000070 | LATIN SMALL LETTER P
     71 |  00000071 | LATIN SMALL LETTER Q
     72 |  00000072 | LATIN SMALL LETTER R
     73 |  00000073 | LATIN SMALL LETTER S
     74 |  00000074 | LATIN SMALL LETTER T
     75 |  00000075 | LATIN SMALL LETTER U
     76 |  00000076 | LATIN SMALL LETTER V
     77 |  00000077 | LATIN SMALL LETTER W
     78 |  00000078 | LATIN SMALL LETTER X
     79 |  00000079 | LATIN SMALL LETTER Y
     7A |  0000007A | LATIN SMALL LETTER Z
     7B |  0000007B | LEFT CURLY BRACKET
     7C |  0000007C | VERTICAL LINE
     7D |  0000007D | RIGHT CURLY BRACKET
     7E |  0000007E | TILDE
     7F |  0000007F | DELETE (DEL)
     80 |  00002500 | BOX DRAWINGS LIGHT HORIZONTAL
     81 |  00002502 | BOX DRAWINGS LIGHT VERTICAL
     82 |  0000250C | BOX DRAWINGS LIGHT DOWN AND RIGHT
     83 |  00002510 | BOX DRAWINGS LIGHT DOWN AND LEFT
     84 |  00002514 | BOX DRAWINGS LIGHT UP AND RIGHT
     85 |  00002518 | BOX DRAWINGS LIGHT UP AND LEFT
     86 |  0000251C | BOX DRAWINGS LIGHT VERTICAL AND RIGHT
     87 |  00002524 | BOX DRAWINGS LIGHT VERTICAL AND LEFT
     88 |  0000252C | BOX DRAWINGS LIGHT DOWN AND HORIZONTAL
     89 |  00002534 | BOX DRAWINGS LIGHT UP AND HORIZONTAL
     8A |  0000253C | BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL
     8B |  00002580 | UPPER HALF BLOCK
     8C |  00002584 | LOWER HALF BLOCK
     8D |  00002588 | FULL BLOCK
     8E |  0000258C | LEFT HALF BLOCK
     8F |  00002590 | RIGHT HALF BLOCK
     90 |  00002591 | LIGHT SHADE
     91 |  00002592 | MEDIUM SHADE
     92 |  00002593 | DARK SHADE
     93 |  00002320 | TOP HALF INTEGRAL
     94 |  000025A0 | BLACK SQUARE
     95 |  00002219 | BULLET OPERATOR
     96 |  0000221A | SQUARE ROOT
     97 |  00002248 | ALMOST EQUAL TO
     98 |  00002264 | LESS-THAN OR EQUAL TO
     99 |  00002265 | GREATER-THAN OR EQUAL TO
     9A |  000000A0 | NO-BREAK SPACE
     9B |  00002321 | BOTTOM HALF INTEGRAL
     9C |  000000B0 | DEGREE SIGN
     9D |  000000B2 | SUPERSCRIPT TWO
     9E |  000000B7 | MIDDLE DOT
     9F |  000000F7 | DIVISION SIGN
     A0 |  00002550 | BOX DRAWINGS DOUBLE HORIZONTAL
     A1 |  00002551 | BOX DRAWINGS DOUBLE VERTICAL
     A2 |  00002552 | BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE
     A3 |  00000451 | CYRILLIC SMALL LETTER IO
     A4 |  00000454 | CYRILLIC SMALL LETTER UKRAINIAN IE
     A5 |  00002554 | BOX DRAWINGS DOUBLE DOWN AND RIGHT
     A6 |  00000456 | CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I
     A7 |  00000457 | CYRILLIC SMALL LETTER YI
     A8 |  00002557 | BOX DRAWINGS DOUBLE DOWN AND LEFT
     A9 |  00002558 | BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE
     AA |  00002559 | BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE
     AB |  0000255A | BOX DRAWINGS DOUBLE UP AND RIGHT
     AC |  0000255B | BOX DRAWINGS UP SINGLE AND LEFT DOUBLE
     AD |  00000491 | CYRILLIC SMALL LETTER GHE WITH UPTURN
     AE |  0000045E | CYRILLIC SMALL LETTER SHORT U
     AF |  0000255E | BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE
     B0 |  0000255F | BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE
     B1 |  00002560 | BOX DRAWINGS DOUBLE VERTICAL AND RIGHT
     B2 |  00002561 | BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE
     B3 |  00000401 | CYRILLIC CAPITAL LETTER IO
     B4 |  00000404 | CYRILLIC CAPITAL LETTER UKRAINIAN IE
     B5 |  00002563 | BOX DRAWINGS DOUBLE VERTICAL AND LEFT
     B6 |  00000406 | CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I
     B7 |  00000407 | CYRILLIC CAPITAL LETTER YI
     B8 |  00002566 | BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL
     B9 |  00002567 | BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE
     BA |  00002568 | BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE
     BB |  00002569 | BOX DRAWINGS DOUBLE UP AND HORIZONTAL
     BC |  0000256A | BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE
     BD |  00000490 | CYRILLIC CAPITAL LETTER GHE WITH UPTURN
     BE |  0000040E | CYRILLIC CAPITAL LETTER SHORT U
     BF |  000000A9 | COPYRIGHT SIGN
     C0 |  0000044E | CYRILLIC SMALL LETTER YU
     C1 |  00000430 | CYRILLIC SMALL LETTER A
     C2 |  00000431 | CYRILLIC SMALL LETTER BE
     C3 |  00000446 | CYRILLIC SMALL LETTER TSE
     C4 |  00000434 | CYRILLIC SMALL LETTER DE
     C5 |  00000435 | CYRILLIC SMALL LETTER IE
     C6 |  00000444 | CYRILLIC SMALL LETTER EF
     C7 |  00000433 | CYRILLIC SMALL LETTER GHE
     C8 |  00000445 | CYRILLIC SMALL LETTER HA
     C9 |  00000438 | CYRILLIC SMALL LETTER I
     CA |  00000439 | CYRILLIC SMALL LETTER SHORT I
     CB |  0000043A | CYRILLIC SMALL LETTER KA
     CC |  0000043B | CYRILLIC SMALL LETTER EL
     CD |  0000043C | CYRILLIC SMALL LETTER EM
     CE |  0000043D | CYRILLIC SMALL LETTER EN
     CF |  0000043E | CYRILLIC SMALL LETTER O
     D0 |  0000043F | CYRILLIC SMALL LETTER PE
     D1 |  0000044F | CYRILLIC SMALL LETTER YA
     D2 |  00000440 | CYRILLIC SMALL LETTER ER
     D3 |  00000441 | CYRILLIC SMALL LETTER ES
     D4 |  00000442 | CYRILLIC SMALL LETTER TE
     D5 |  00000443 | CYRILLIC SMALL LETTER U
     D6 |  00000436 | CYRILLIC SMALL LETTER ZHE
     D7 |  00000432 | CYRILLIC SMALL LETTER VE
     D8 |  0000044C | CYRILLIC SMALL LETTER SOFT SIGN
     D9 |  0000044B | CYRILLIC SMALL LETTER YERU
     DA |  00000437 | CYRILLIC SMALL LETTER ZE
     DB |  00000448 | CYRILLIC SMALL LETTER SHA
     DC |  0000044D | CYRILLIC SMALL LETTER E
     DD |  00000449 | CYRILLIC SMALL LETTER SHCHA
     DE |  00000447 | CYRILLIC SMALL LETTER CHE
     DF |  0000044A | CYRILLIC SMALL LETTER HARD SIGN
     E0 |  0000042E | CYRILLIC CAPITAL LETTER YU
     E1 |  00000410 | CYRILLIC CAPITAL LETTER A
     E2 |  00000411 | CYRILLIC CAPITAL LETTER BE
     E3 |  00000426 | CYRILLIC CAPITAL LETTER TSE
     E4 |  00000414 | CYRILLIC CAPITAL LETTER DE
     E5 |  00000415 | CYRILLIC CAPITAL LETTER IE
     E6 |  00000424 | CYRILLIC CAPITAL LETTER EF
     E7 |  00000413 | CYRILLIC CAPITAL LETTER GHE
     E8 |  00000425 | CYRILLIC CAPITAL LETTER HA
     E9 |  00000418 | CYRILLIC CAPITAL LETTER I
     EA |  00000419 | CYRILLIC CAPITAL LETTER SHORT I
     EB |  0000041A | CYRILLIC CAPITAL LETTER KA
     EC |  0000041B | CYRILLIC CAPITAL LETTER EL
     ED |  0000041C | CYRILLIC CAPITAL LETTER EM
     EE |  0000041D | CYRILLIC CAPITAL LETTER EN
     EF |  0000041E | CYRILLIC CAPITAL LETTER O
     F0 |  0000041F | CYRILLIC CAPITAL LETTER PE
     F1 |  0000042F | CYRILLIC CAPITAL LETTER YA
     F2 |  00000420 | CYRILLIC CAPITAL LETTER ER
     F3 |  00000421 | CYRILLIC CAPITAL LETTER ES
     F4 |  00000422 | CYRILLIC CAPITAL LETTER TE
     F5 |  00000423 | CYRILLIC CAPITAL LETTER U
     F6 |  00000416 | CYRILLIC CAPITAL LETTER ZHE
     F7 |  00000412 | CYRILLIC CAPITAL LETTER VE
     F8 |  0000042C | CYRILLIC CAPITAL LETTER SOFT SIGN
     F9 |  0000042B | CYRILLIC CAPITAL LETTER YERU
     FA |  00000417 | CYRILLIC CAPITAL LETTER ZE
     FB |  00000428 | CYRILLIC CAPITAL LETTER SHA
     FC |  0000042D | CYRILLIC CAPITAL LETTER E
     FD |  00000429 | CYRILLIC CAPITAL LETTER SHCHA
     FE |  00000427 | CYRILLIC CAPITAL LETTER CHE
     FF |  0000042A | CYRILLIC CAPITAL LETTER HARD SIGN
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/KOI8_T.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for KOI8-T.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::KOI8_T;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x0004,
     0x0005,
     0x0006,
     0x0007,
     0x0008,
     0x0009,
     0x000a,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x0014,
     0x0015,
     0x0016,
     0x0017,
     0x0018,
     0x0019,
     0x001a,
     0x001b,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0020,
     0x0021,
     0x0022,
     0x0023,
     0x0024,
     0x0025,
     0x0026,
     0x0027,
     0x0028,
     0x0029,
     0x002a,
     0x002b,
     0x002c,
     0x002d,
     0x002e,
     0x002f,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x003a,
     0x003b,
     0x003c,
     0x003d,
     0x003e,
     0x003f,
     0x0040,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x005b,
     0x005c,
     0x005d,
     0x005e,
     0x005f,
     0x0060,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x007b,
     0x007c,
     0x007d,
     0x007e,
     0x007f,
     0x049b,
     0x0493,
     0x201a,
     0x0492,
     0x201e,
     0x2026,
     0x2020,
     0x2021,
     0xfffd,
     0x2030,
     0x04b3,
     0x2039,
     0x04b2,
     0x04b7,
     0x04b6,
     0xfffd,
     0x049a,
     0x2018,
     0x2019,
     0x201c,
     0x201d,
     0x2022,
     0x2013,
     0x2014,
     0xfffd,
     0x2122,
     0xfffd,
     0x203a,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x04ef,
     0x04ee,
     0x0451,
     0x00a4,
     0x04e3,
     0x00a6,
     0x00a7,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00ab,
     0x00ac,
     0x00ad,
     0x00ae,
     0xfffd,
     0x00b0,
     0x00b1,
     0x00b2,
     0x0401,
     0xfffd,
     0x04e2,
     0x00b6,
     0x00b7,
     0xfffd,
     0x2116,
     0xfffd,
     0x00bb,
     0xfffd,
     0xfffd,
     0xfffd,
     0x00a9,
     0x044e,
     0x0430,
     0x0431,
     0x0446,
     0x0434,
     0x0435,
     0x0444,
     0x0433,
     0x0445,
     0x0438,
     0x0439,
     0x043a,
     0x043b,
     0x043c,
     0x043d,
     0x043e,
     0x043f,
     0x044f,
     0x0440,
     0x0441,
     0x0442,
     0x0443,
     0x0436,
     0x0432,
     0x044c,
     0x044b,
     0x0437,
     0x0448,
     0x044d,
     0x0449,
     0x0447,
     0x044a,
     0x042e,
     0x0410,
     0x0411,
     0x0426,
     0x0414,
     0x0415,
     0x0424,
     0x0413,
     0x0425,
     0x0418,
     0x0419,
     0x041a,
     0x041b,
     0x041c,
     0x041d,
     0x041e,
     0x041f,
     0x042f,
     0x0420,
     0x0421,
     0x0422,
     0x0423,
     0x0416,
     0x0412,
     0x042c,
     0x042b,
     0x0417,
     0x0428,
     0x042d,
     0x0429,
     0x0427,
     0x042a,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\x04",
     "\x05",
     "\x06",
     "\x07",
     "\x08",
     "\x09",
     "\x0a",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\x14",
     "\x15",
     "\x16",
     "\x17",
     "\x18",
     "\x19",
     "\x1a",
     "\x1b",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\x20",
     "\x21",
     "\x22",
     "\x23",
     "\x24",
     "\x25",
     "\x26",
     "\x27",
     "\x28",
     "\x29",
     "\x2a",
     "\x2b",
     "\x2c",
     "\x2d",
     "\x2e",
     "\x2f",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\x3a",
     "\x3b",
     "\x3c",
     "\x3d",
     "\x3e",
     "\x3f",
     "\x40",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\x5b",
     "\x5c",
     "\x5d",
     "\x5e",
     "\x5f",
     "\x60",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\x7b",
     "\x7c",
     "\x7d",
     "\x7e",
     "\x7f",
     "\xd2\x9b",
     "\xd2\x93",
     "\xe2\x80\x9a",
     "\xd2\x92",
     "\xe2\x80\x9e",
     "\xe2\x80\xa6",
     "\xe2\x80\xa0",
     "\xe2\x80\xa1",
     "\xef\xbf\xbd",
     "\xe2\x80\xb0",
     "\xd2\xb3",
     "\xe2\x80\xb9",
     "\xd2\xb2",
     "\xd2\xb7",
     "\xd2\xb6",
     "\xef\xbf\xbd",
     "\xd2\x9a",
     "\xe2\x80\x98",
     "\xe2\x80\x99",
     "\xe2\x80\x9c",
     "\xe2\x80\x9d",
     "\xe2\x80\xa2",
     "\xe2\x80\x93",
     "\xe2\x80\x94",
     "\xef\xbf\xbd",
     "\xe2\x84\xa2",
     "\xef\xbf\xbd",
     "\xe2\x80\xba",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xd3\xaf",
     "\xd3\xae",
     "\xd1\x91",
     "\xc2\xa4",
     "\xd3\xa3",
     "\xc2\xa6",
     "\xc2\xa7",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc2\xab",
     "\xc2\xac",
     "\xc2\xad",
     "\xc2\xae",
     "\xef\xbf\xbd",
     "\xc2\xb0",
     "\xc2\xb1",
     "\xc2\xb2",
     "\xd0\x81",
     "\xef\xbf\xbd",
     "\xd3\xa2",
     "\xc2\xb6",
     "\xc2\xb7",
     "\xef\xbf\xbd",
     "\xe2\x84\x96",
     "\xef\xbf\xbd",
     "\xc2\xbb",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc2\xa9",
     "\xd1\x8e",
     "\xd0\xb0",
     "\xd0\xb1",
     "\xd1\x86",
     "\xd0\xb4",
     "\xd0\xb5",
     "\xd1\x84",
     "\xd0\xb3",
     "\xd1\x85",
     "\xd0\xb8",
     "\xd0\xb9",
     "\xd0\xba",
     "\xd0\xbb",
     "\xd0\xbc",
     "\xd0\xbd",
     "\xd0\xbe",
     "\xd0\xbf",
     "\xd1\x8f",
     "\xd1\x80",
     "\xd1\x81",
     "\xd1\x82",
     "\xd1\x83",
     "\xd0\xb6",
     "\xd0\xb2",
     "\xd1\x8c",
     "\xd1\x8b",
     "\xd0\xb7",
     "\xd1\x88",
     "\xd1\x8d",
     "\xd1\x89",
     "\xd1\x87",
     "\xd1\x8a",
     "\xd0\xae",
     "\xd0\x90",
     "\xd0\x91",
     "\xd0\xa6",
     "\xd0\x94",
     "\xd0\x95",
     "\xd0\xa4",
     "\xd0\x93",
     "\xd0\xa5",
     "\xd0\x98",
     "\xd0\x99",
     "\xd0\x9a",
     "\xd0\x9b",
     "\xd0\x9c",
     "\xd0\x9d",
     "\xd0\x9e",
     "\xd0\x9f",
     "\xd0\xaf",
     "\xd0\xa0",
     "\xd0\xa1",
     "\xd0\xa2",
     "\xd0\xa3",
     "\xd0\x96",
     "\xd0\x92",
     "\xd0\xac",
     "\xd0\xab",
     "\xd0\x97",
     "\xd0\xa8",
     "\xd0\xad",
     "\xd0\xa9",
     "\xd0\xa7",
     "\xd0\xaa",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x04",
     0x00000005 => "\x05",
     0x00000006 => "\x06",
     0x00000007 => "\x07",
     0x00000008 => "\x08",
     0x00000009 => "\x09",
     0x0000000a => "\x0a",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x14",
     0x00000015 => "\x15",
     0x00000016 => "\x16",
     0x00000017 => "\x17",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x1a",
     0x0000001b => "\x1b",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x20",
     0x00000021 => "\x21",
     0x00000022 => "\x22",
     0x00000023 => "\x23",
     0x00000024 => "\x24",
     0x00000025 => "\x25",
     0x00000026 => "\x26",
     0x00000027 => "\x27",
     0x00000028 => "\x28",
     0x00000029 => "\x29",
     0x0000002a => "\x2a",
     0x0000002b => "\x2b",
     0x0000002c => "\x2c",
     0x0000002d => "\x2d",
     0x0000002e => "\x2e",
     0x0000002f => "\x2f",
     0x00000030 => "\x30",
     0x00000031 => "\x31",
     0x00000032 => "\x32",
     0x00000033 => "\x33",
     0x00000034 => "\x34",
     0x00000035 => "\x35",
     0x00000036 => "\x36",
     0x00000037 => "\x37",
     0x00000038 => "\x38",
     0x00000039 => "\x39",
     0x0000003a => "\x3a",
     0x0000003b => "\x3b",
     0x0000003c => "\x3c",
     0x0000003d => "\x3d",
     0x0000003e => "\x3e",
     0x0000003f => "\x3f",
     0x00000040 => "\x40",
     0x00000041 => "\x41",
     0x00000042 => "\x42",
     0x00000043 => "\x43",
     0x00000044 => "\x44",
     0x00000045 => "\x45",
     0x00000046 => "\x46",
     0x00000047 => "\x47",
     0x00000048 => "\x48",
     0x00000049 => "\x49",
     0x0000004a => "\x4a",
     0x0000004b => "\x4b",
     0x0000004c => "\x4c",
     0x0000004d => "\x4d",
     0x0000004e => "\x4e",
     0x0000004f => "\x4f",
     0x00000050 => "\x50",
     0x00000051 => "\x51",
     0x00000052 => "\x52",
     0x00000053 => "\x53",
     0x00000054 => "\x54",
     0x00000055 => "\x55",
     0x00000056 => "\x56",
     0x00000057 => "\x57",
     0x00000058 => "\x58",
     0x00000059 => "\x59",
     0x0000005a => "\x5a",
     0x0000005b => "\x5b",
     0x0000005c => "\x5c",
     0x0000005d => "\x5d",
     0x0000005e => "\x5e",
     0x0000005f => "\x5f",
     0x00000060 => "\x60",
     0x00000061 => "\x61",
     0x00000062 => "\x62",
     0x00000063 => "\x63",
     0x00000064 => "\x64",
     0x00000065 => "\x65",
     0x00000066 => "\x66",
     0x00000067 => "\x67",
     0x00000068 => "\x68",
     0x00000069 => "\x69",
     0x0000006a => "\x6a",
     0x0000006b => "\x6b",
     0x0000006c => "\x6c",
     0x0000006d => "\x6d",
     0x0000006e => "\x6e",
     0x0000006f => "\x6f",
     0x00000070 => "\x70",
     0x00000071 => "\x71",
     0x00000072 => "\x72",
     0x00000073 => "\x73",
     0x00000074 => "\x74",
     0x00000075 => "\x75",
     0x00000076 => "\x76",
     0x00000077 => "\x77",
     0x00000078 => "\x78",
     0x00000079 => "\x79",
     0x0000007a => "\x7a",
     0x0000007b => "\x7b",
     0x0000007c => "\x7c",
     0x0000007d => "\x7d",
     0x0000007e => "\x7e",
     0x0000007f => "\x7f",
     0x000000a4 => "\xa4",
     0x000000a6 => "\xa6",
     0x000000a7 => "\xa7",
     0x000000a9 => "\xbf",
     0x000000ab => "\xab",
     0x000000ac => "\xac",
     0x000000ad => "\xad",
     0x000000ae => "\xae",
     0x000000b0 => "\xb0",
     0x000000b1 => "\xb1",
     0x000000b2 => "\xb2",
     0x000000b6 => "\xb6",
     0x000000b7 => "\xb7",
     0x000000bb => "\xbb",
     0x00000401 => "\xb3",
     0x00000410 => "\xe1",
     0x00000411 => "\xe2",
     0x00000412 => "\xf7",
     0x00000413 => "\xe7",
     0x00000414 => "\xe4",
     0x00000415 => "\xe5",
     0x00000416 => "\xf6",
     0x00000417 => "\xfa",
     0x00000418 => "\xe9",
     0x00000419 => "\xea",
     0x0000041a => "\xeb",
     0x0000041b => "\xec",
     0x0000041c => "\xed",
     0x0000041d => "\xee",
     0x0000041e => "\xef",
     0x0000041f => "\xf0",
     0x00000420 => "\xf2",
     0x00000421 => "\xf3",
     0x00000422 => "\xf4",
     0x00000423 => "\xf5",
     0x00000424 => "\xe6",
     0x00000425 => "\xe8",
     0x00000426 => "\xe3",
     0x00000427 => "\xfe",
     0x00000428 => "\xfb",
     0x00000429 => "\xfd",
     0x0000042a => "\xff",
     0x0000042b => "\xf9",
     0x0000042c => "\xf8",
     0x0000042d => "\xfc",
     0x0000042e => "\xe0",
     0x0000042f => "\xf1",
     0x00000430 => "\xc1",
     0x00000431 => "\xc2",
     0x00000432 => "\xd7",
     0x00000433 => "\xc7",
     0x00000434 => "\xc4",
     0x00000435 => "\xc5",
     0x00000436 => "\xd6",
     0x00000437 => "\xda",
     0x00000438 => "\xc9",
     0x00000439 => "\xca",
     0x0000043a => "\xcb",
     0x0000043b => "\xcc",
     0x0000043c => "\xcd",
     0x0000043d => "\xce",
     0x0000043e => "\xcf",
     0x0000043f => "\xd0",
     0x00000440 => "\xd2",
     0x00000441 => "\xd3",
     0x00000442 => "\xd4",
     0x00000443 => "\xd5",
     0x00000444 => "\xc6",
     0x00000445 => "\xc8",
     0x00000446 => "\xc3",
     0x00000447 => "\xde",
     0x00000448 => "\xdb",
     0x00000449 => "\xdd",
     0x0000044a => "\xdf",
     0x0000044b => "\xd9",
     0x0000044c => "\xd8",
     0x0000044d => "\xdc",
     0x0000044e => "\xc0",
     0x0000044f => "\xd1",
     0x00000451 => "\xa3",
     0x00000492 => "\x83",
     0x00000493 => "\x81",
     0x0000049a => "\x90",
     0x0000049b => "\x80",
     0x000004b2 => "\x8c",
     0x000004b3 => "\x8a",
     0x000004b6 => "\x8e",
     0x000004b7 => "\x8d",
     0x000004e2 => "\xb5",
     0x000004e3 => "\xa5",
     0x000004ee => "\xa2",
     0x000004ef => "\xa1",
     0x00002013 => "\x96",
     0x00002014 => "\x97",
     0x00002018 => "\x91",
     0x00002019 => "\x92",
     0x0000201a => "\x82",
     0x0000201c => "\x93",
     0x0000201d => "\x94",
     0x0000201e => "\x84",
     0x00002020 => "\x86",
     0x00002021 => "\x87",
     0x00002022 => "\x95",
     0x00002026 => "\x85",
     0x00002030 => "\x89",
     0x00002039 => "\x8b",
     0x0000203a => "\x9b",
     0x00002116 => "\xb9",
     0x00002122 => "\x99",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::KOI8_T - Conversion routines for KOI8-T
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for KOI8-T.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  Author: Michael Davis E<lt>tajik_fonts@iname.comE<gt>
  URL:    http://www.traveltajikistan.com/fonts
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL
     01 |  00000001 | START OF HEADING
     02 |  00000002 | START OF TEXT
     03 |  00000003 | END OF TEXT
     04 |  00000004 | END OF TRANSMISSION
     05 |  00000005 | ENQUIRY
     06 |  00000006 | ACKNOWLEDGE
     07 |  00000007 | BELL
     08 |  00000008 | BACKSPACE
     09 |  00000009 | HORIZONTAL TABULATION
     0A |  0000000A | LINE FEED
     0B |  0000000B | VERTICAL TABULATION
     0C |  0000000C | FORM FEED
     0D |  0000000D | CARRIAGE RETURN
     0E |  0000000E | SHIFT OUT
     0F |  0000000F | SHIFT IN
     10 |  00000010 | DATA LINK ESCAPE
     11 |  00000011 | DEVICE CONTROL ONE
     12 |  00000012 | DEVICE CONTROL TWO
     13 |  00000013 | DEVICE CONTROL THREE
     14 |  00000014 | DEVICE CONTROL FOUR
     15 |  00000015 | NEGATIVE ACKNOWLEDGE
     16 |  00000016 | SYNCHRONOUS IDLE
     17 |  00000017 | END OF TRANSMISSION BLOCK
     18 |  00000018 | CANCEL
     19 |  00000019 | END OF MEDIUM
     1A |  0000001A | SUBSTITUTE
     1B |  0000001B | ESCAPE
     1C |  0000001C | FILE SEPARATOR
     1D |  0000001D | GROUP SEPARATOR
     1E |  0000001E | RECORD SEPARATOR
     1F |  0000001F | UNIT SEPARATOR
     20 |  00000020 | SPACE
     21 |  00000021 | EXCLAMATION MARK
     22 |  00000022 | QUOTATION MARK
     23 |  00000023 | NUMBER SIGN
     24 |  00000024 | DOLLAR SIGN
     25 |  00000025 | PERCENT SIGN
     26 |  00000026 | AMPERSAND
     27 |  00000027 | APOSTROPHE
     28 |  00000028 | LEFT PARENTHESIS
     29 |  00000029 | RIGHT PARENTHESIS
     2A |  0000002A | ASTERISK
     2B |  0000002B | PLUS SIGN
     2C |  0000002C | COMMA
     2D |  0000002D | HYPHEN-MINUS
     2E |  0000002E | FULL STOP
     2F |  0000002F | SOLIDUS
     30 |  00000030 | DIGIT ZERO
     31 |  00000031 | DIGIT ONE
     32 |  00000032 | DIGIT TWO
     33 |  00000033 | DIGIT THREE
     34 |  00000034 | DIGIT FOUR
     35 |  00000035 | DIGIT FIVE
     36 |  00000036 | DIGIT SIX
     37 |  00000037 | DIGIT SEVEN
     38 |  00000038 | DIGIT EIGHT
     39 |  00000039 | DIGIT NINE
     3A |  0000003A | COLON
     3B |  0000003B | SEMICOLON
     3C |  0000003C | LESS-THAN SIGN
     3D |  0000003D | EQUALS SIGN
     3E |  0000003E | GREATER-THAN SIGN
     3F |  0000003F | QUESTION MARK
     40 |  00000040 | COMMERCIAL AT
     41 |  00000041 | LATIN CAPITAL LETTER A
     42 |  00000042 | LATIN CAPITAL LETTER B
     43 |  00000043 | LATIN CAPITAL LETTER C
     44 |  00000044 | LATIN CAPITAL LETTER D
     45 |  00000045 | LATIN CAPITAL LETTER E
     46 |  00000046 | LATIN CAPITAL LETTER F
     47 |  00000047 | LATIN CAPITAL LETTER G
     48 |  00000048 | LATIN CAPITAL LETTER H
     49 |  00000049 | LATIN CAPITAL LETTER I
     4A |  0000004A | LATIN CAPITAL LETTER J
     4B |  0000004B | LATIN CAPITAL LETTER K
     4C |  0000004C | LATIN CAPITAL LETTER L
     4D |  0000004D | LATIN CAPITAL LETTER M
     4E |  0000004E | LATIN CAPITAL LETTER N
     4F |  0000004F | LATIN CAPITAL LETTER O
     50 |  00000050 | LATIN CAPITAL LETTER P
     51 |  00000051 | LATIN CAPITAL LETTER Q
     52 |  00000052 | LATIN CAPITAL LETTER R
     53 |  00000053 | LATIN CAPITAL LETTER S
     54 |  00000054 | LATIN CAPITAL LETTER T
     55 |  00000055 | LATIN CAPITAL LETTER U
     56 |  00000056 | LATIN CAPITAL LETTER V
     57 |  00000057 | LATIN CAPITAL LETTER W
     58 |  00000058 | LATIN CAPITAL LETTER X
     59 |  00000059 | LATIN CAPITAL LETTER Y
     5A |  0000005A | LATIN CAPITAL LETTER Z
     5B |  0000005B | LEFT SQUARE BRACKET
     5C |  0000005C | REVERSE SOLIDUS
     5D |  0000005D | RIGHT SQUARE BRACKET
     5E |  0000005E | CIRCUMFLEX ACCENT
     5F |  0000005F | LOW LINE
     60 |  00000060 | GRAVE ACCENT
     61 |  00000061 | LATIN SMALL LETTER A
     62 |  00000062 | LATIN SMALL LETTER B
     63 |  00000063 | LATIN SMALL LETTER C
     64 |  00000064 | LATIN SMALL LETTER D
     65 |  00000065 | LATIN SMALL LETTER E
     66 |  00000066 | LATIN SMALL LETTER F
     67 |  00000067 | LATIN SMALL LETTER G
     68 |  00000068 | LATIN SMALL LETTER H
     69 |  00000069 | LATIN SMALL LETTER I
     6A |  0000006A | LATIN SMALL LETTER J
     6B |  0000006B | LATIN SMALL LETTER K
     6C |  0000006C | LATIN SMALL LETTER L
     6D |  0000006D | LATIN SMALL LETTER M
     6E |  0000006E | LATIN SMALL LETTER N
     6F |  0000006F | LATIN SMALL LETTER O
     70 |  00000070 | LATIN SMALL LETTER P
     71 |  00000071 | LATIN SMALL LETTER Q
     72 |  00000072 | LATIN SMALL LETTER R
     73 |  00000073 | LATIN SMALL LETTER S
     74 |  00000074 | LATIN SMALL LETTER T
     75 |  00000075 | LATIN SMALL LETTER U
     76 |  00000076 | LATIN SMALL LETTER V
     77 |  00000077 | LATIN SMALL LETTER W
     78 |  00000078 | LATIN SMALL LETTER X
     79 |  00000079 | LATIN SMALL LETTER Y
     7A |  0000007A | LATIN SMALL LETTER Z
     7B |  0000007B | LEFT CURLY BRACKET
     7C |  0000007C | VERTICAL LINE
     7D |  0000007D | RIGHT CURLY BRACKET
     7E |  0000007E | TILDE
     7F |  0000007F | DELETE
     80 |  0000049B | CYRILLIC SMALL LETTER KA WITH DESCENDER
     81 |  00000493 | CYRILLIC SMALL LETTER GHE WITH STROKE
     82 |  0000201A | SINGLE LOW-9 QUOTATION MARK
     83 |  00000492 | CYRILLIC CAPITAL LETTER GHE WITH STROKE
     84 |  0000201E | DOUBLE LOW-9 QUOTATION MARK
     85 |  00002026 | HORIZONTAL ELLIPSIS
     86 |  00002020 | DAGGER
     87 |  00002021 | DOUBLE DAGGER
     89 |  00002030 | PER MILLE SIGN
     8A |  000004B3 | CYRILLIC SMALL LETTER HA WITH DESCENDER
     8B |  00002039 | SINGLE LEFT-POINTING ANGLE QUOTATION MARK
     8C |  000004B2 | CYRILLIC CAPITAL LETTER HA WITH DESCENDER
     8D |  000004B7 | CYRILLIC SMALL LETTER CHE WITH DESCENDER
     8E |  000004B6 | CYRILLIC CAPITAL LETTER CHE WITH DESCENDER
     90 |  0000049A | CYRILLIC CAPITAL LETTER KA WITH DESCENDER
     91 |  00002018 | LEFT SINGLE QUOTATION MARK
     92 |  00002019 | RIGHT SINGLE QUOTATION MARK
     93 |  0000201C | LEFT DOUBLE QUOTATION MARK
     94 |  0000201D | RIGHT DOUBLE QUOTATION MARK
     95 |  00002022 | BULLET
     96 |  00002013 | EN DASH
     97 |  00002014 | EM DASH
     99 |  00002122 | TRADE MARK SIGN
     9B |  0000203A | SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
     A1 |  000004EF | CYRILLIC SMALL LETTER U WITH MACRON
     A2 |  000004EE | CYRILLIC CAPITAL LETTER U WITH MACRON
     A3 |  00000451 | CYRILLIC SMALL LETTER IO
     A4 |  000000A4 | CURRENCY SIGN
     A5 |  000004E3 | CYRILLIC SMALL LETTER I WITH MACRON
     A6 |  000000A6 | BROKEN BAR
     A7 |  000000A7 | SECTION SIGN
     AB |  000000AB | LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
     AC |  000000AC | NOT SIGN
     AD |  000000AD | SOFT HYPHEN
     AE |  000000AE | REGISTERED SIGN
     B0 |  000000B0 | DEGREE SIGN
     B1 |  000000B1 | PLUS-MINUS SIGN
     B2 |  000000B2 | SUPERSCRIPT TWO
     B3 |  00000401 | CYRILLIC CAPITAL LETTER IE
     B5 |  000004E2 | CYRILLIC CAPITAL LETTER I WITH MACRON
     B6 |  000000B6 | PILCROW SIGN
     B7 |  000000B7 | MIDDLE DOT
     B9 |  00002116 | NUMERO SIGN
     BB |  000000BB | RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
     BF |  000000A9 | COPYRIGHT SIGN
     C0 |  0000044E | CYRILLIC SMALL LETTER YU
     C1 |  00000430 | CYRILLIC SMALL LETTER A
     C2 |  00000431 | CYRILLIC SMALL LETTER BE
     C3 |  00000446 | CYRILLIC SMALL LETTER TSE
     C4 |  00000434 | CYRILLIC SMALL LETTER DE
     C5 |  00000435 | CYRILLIC SMALL LETTER IE
     C6 |  00000444 | CYRILLIC SMALL LETTER EF
     C7 |  00000433 | CYRILLIC SMALL LETTER GHE
     C8 |  00000445 | CYRILLIC SMALL LETTER HA
     C9 |  00000438 | CYRILLIC SMALL LETTER I
     CA |  00000439 | CYRILLIC SMALL LETTER SHORT I
     CB |  0000043A | CYRILLIC SMALL LETTER KA
     CC |  0000043B | CYRILLIC SMALL LETTER EL
     CD |  0000043C | CYRILLIC SMALL LETTER EM
     CE |  0000043D | CYRILLIC SMALL LETTER EN
     CF |  0000043E | CYRILLIC SMALL LETTER O
     D0 |  0000043F | CYRILLIC SMALL LETTER PE
     D1 |  0000044F | CYRILLIC SMALL LETTER YA
     D2 |  00000440 | CYRILLIC SMALL LETTER ER
     D3 |  00000441 | CYRILLIC SMALL LETTER ES
     D4 |  00000442 | CYRILLIC SMALL LETTER TE
     D5 |  00000443 | CYRILLIC SMALL LETTER U
     D6 |  00000436 | CYRILLIC SMALL LETTER ZHE
     D7 |  00000432 | CYRILLIC SMALL LETTER VE
     D8 |  0000044C | CYRILLIC SMALL LETTER SOFT SIGN
     D9 |  0000044B | CYRILLIC SMALL LETTER YERU
     DA |  00000437 | CYRILLIC SMALL LETTER ZE
     DB |  00000448 | CYRILLIC SMALL LETTER SHA
     DC |  0000044D | CYRILLIC SMALL LETTER E
     DD |  00000449 | CYRILLIC SMALL LETTER SHCHA
     DE |  00000447 | CYRILLIC SMALL LETTER CHE
     DF |  0000044A | CYRILLIC SMALL LETTER HARD SIGN
     E0 |  0000042E | CYRILLIC CAPITAL LETTER YU
     E1 |  00000410 | CYRILLIC CAPITAL LETTER A
     E2 |  00000411 | CYRILLIC CAPITAL LETTER BE
     E3 |  00000426 | CYRILLIC CAPITAL LETTER TSE
     E4 |  00000414 | CYRILLIC CAPITAL LETTER DE
     E5 |  00000415 | CYRILLIC CAPITAL LETTER IE
     E6 |  00000424 | CYRILLIC CAPITAL LETTER EF
     E7 |  00000413 | CYRILLIC CAPITAL LETTER GHE
     E8 |  00000425 | CYRILLIC CAPITAL LETTER HA
     E9 |  00000418 | CYRILLIC CAPITAL LETTER I
     EA |  00000419 | CYRILLIC CAPITAL LETTER SHORT I
     EB |  0000041A | CYRILLIC CAPITAL LETTER KA
     EC |  0000041B | CYRILLIC CAPITAL LETTER EL
     ED |  0000041C | CYRILLIC CAPITAL LETTER EM
     EE |  0000041D | CYRILLIC CAPITAL LETTER EN
     EF |  0000041E | CYRILLIC CAPITAL LETTER O
     F0 |  0000041F | CYRILLIC CAPITAL LETTER PE
     F1 |  0000042F | CYRILLIC CAPITAL LETTER YA
     F2 |  00000420 | CYRILLIC CAPITAL LETTER ER
     F3 |  00000421 | CYRILLIC CAPITAL LETTER ES
     F4 |  00000422 | CYRILLIC CAPITAL LETTER TE
     F5 |  00000423 | CYRILLIC CAPITAL LETTER U
     F6 |  00000416 | CYRILLIC CAPITAL LETTER ZHE
     F7 |  00000412 | CYRILLIC CAPITAL LETTER VE
     F8 |  0000042C | CYRILLIC CAPITAL LETTER SOFT SIGN
     F9 |  0000042B | CYRILLIC CAPITAL LETTER YERU
     FA |  00000417 | CYRILLIC CAPITAL LETTER ZE
     FB |  00000428 | CYRILLIC CAPITAL LETTER SHA
     FC |  0000042D | CYRILLIC CAPITAL LETTER E
     FD |  00000429 | CYRILLIC CAPITAL LETTER SHCHA
     FE |  00000427 | CYRILLIC CAPITAL LETTER CHE
     FF |  0000042A | CYRILLIC CAPITAL LETTER HARD SIGN
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/KOI8_U.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for KOI8-U.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::KOI8_U;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x0004,
     0x0005,
     0x0006,
     0x0007,
     0x0008,
     0x0009,
     0x000a,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x0014,
     0x0015,
     0x0016,
     0x0017,
     0x0018,
     0x0019,
     0x001a,
     0x001b,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0020,
     0x0021,
     0x0022,
     0x0023,
     0x0024,
     0x0025,
     0x0026,
     0x0027,
     0x0028,
     0x0029,
     0x002a,
     0x002b,
     0x002c,
     0x002d,
     0x002e,
     0x002f,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x003a,
     0x003b,
     0x003c,
     0x003d,
     0x003e,
     0x003f,
     0x0040,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x005b,
     0x005c,
     0x005d,
     0x005e,
     0x005f,
     0x0060,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x007b,
     0x007c,
     0x007d,
     0x007e,
     0x007f,
     0x2500,
     0x2502,
     0x250c,
     0x2510,
     0x2514,
     0x2518,
     0x251c,
     0x2524,
     0x252c,
     0x2534,
     0x253c,
     0x2580,
     0x2584,
     0x2588,
     0x258c,
     0x2590,
     0x2591,
     0x2592,
     0x2593,
     0x2320,
     0x25a0,
     0x2219,
     0x221a,
     0x2248,
     0x2264,
     0x2265,
     0x00a0,
     0x2321,
     0x00b0,
     0x00b2,
     0x00b7,
     0x00f7,
     0x2550,
     0x2551,
     0x2552,
     0x0451,
     0x0454,
     0x2554,
     0x0456,
     0x0457,
     0x2557,
     0x2558,
     0x2559,
     0x255a,
     0x255b,
     0x0491,
     0x255d,
     0x255e,
     0x255f,
     0x2560,
     0x2561,
     0x0401,
     0x0404,
     0x2563,
     0x0406,
     0x0407,
     0x2566,
     0x2567,
     0x2568,
     0x2569,
     0x256a,
     0x0490,
     0x256c,
     0x00a9,
     0x044e,
     0x0430,
     0x0431,
     0x0446,
     0x0434,
     0x0435,
     0x0444,
     0x0433,
     0x0445,
     0x0438,
     0x0439,
     0x043a,
     0x043b,
     0x043c,
     0x043d,
     0x043e,
     0x043f,
     0x044f,
     0x0440,
     0x0441,
     0x0442,
     0x0443,
     0x0436,
     0x0432,
     0x044c,
     0x044b,
     0x0437,
     0x0448,
     0x044d,
     0x0449,
     0x0447,
     0x044a,
     0x042e,
     0x0410,
     0x0411,
     0x0426,
     0x0414,
     0x0415,
     0x0424,
     0x0413,
     0x0425,
     0x0418,
     0x0419,
     0x041a,
     0x041b,
     0x041c,
     0x041d,
     0x041e,
     0x041f,
     0x042f,
     0x0420,
     0x0421,
     0x0422,
     0x0423,
     0x0416,
     0x0412,
     0x042c,
     0x042b,
     0x0417,
     0x0428,
     0x042d,
     0x0429,
     0x0427,
     0x042a,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\x04",
     "\x05",
     "\x06",
     "\x07",
     "\x08",
     "\x09",
     "\x0a",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\x14",
     "\x15",
     "\x16",
     "\x17",
     "\x18",
     "\x19",
     "\x1a",
     "\x1b",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\x20",
     "\x21",
     "\x22",
     "\x23",
     "\x24",
     "\x25",
     "\x26",
     "\x27",
     "\x28",
     "\x29",
     "\x2a",
     "\x2b",
     "\x2c",
     "\x2d",
     "\x2e",
     "\x2f",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\x3a",
     "\x3b",
     "\x3c",
     "\x3d",
     "\x3e",
     "\x3f",
     "\x40",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\x5b",
     "\x5c",
     "\x5d",
     "\x5e",
     "\x5f",
     "\x60",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\x7b",
     "\x7c",
     "\x7d",
     "\x7e",
     "\x7f",
     "\xe2\x94\x80",
     "\xe2\x94\x82",
     "\xe2\x94\x8c",
     "\xe2\x94\x90",
     "\xe2\x94\x94",
     "\xe2\x94\x98",
     "\xe2\x94\x9c",
     "\xe2\x94\xa4",
     "\xe2\x94\xac",
     "\xe2\x94\xb4",
     "\xe2\x94\xbc",
     "\xe2\x96\x80",
     "\xe2\x96\x84",
     "\xe2\x96\x88",
     "\xe2\x96\x8c",
     "\xe2\x96\x90",
     "\xe2\x96\x91",
     "\xe2\x96\x92",
     "\xe2\x96\x93",
     "\xe2\x8c\xa0",
     "\xe2\x96\xa0",
     "\xe2\x88\x99",
     "\xe2\x88\x9a",
     "\xe2\x89\x88",
     "\xe2\x89\xa4",
     "\xe2\x89\xa5",
     "\xc2\xa0",
     "\xe2\x8c\xa1",
     "\xc2\xb0",
     "\xc2\xb2",
     "\xc2\xb7",
     "\xc3\xb7",
     "\xe2\x95\x90",
     "\xe2\x95\x91",
     "\xe2\x95\x92",
     "\xd1\x91",
     "\xd1\x94",
     "\xe2\x95\x94",
     "\xd1\x96",
     "\xd1\x97",
     "\xe2\x95\x97",
     "\xe2\x95\x98",
     "\xe2\x95\x99",
     "\xe2\x95\x9a",
     "\xe2\x95\x9b",
     "\xd2\x91",
     "\xe2\x95\x9d",
     "\xe2\x95\x9e",
     "\xe2\x95\x9f",
     "\xe2\x95\xa0",
     "\xe2\x95\xa1",
     "\xd0\x81",
     "\xd0\x84",
     "\xe2\x95\xa3",
     "\xd0\x86",
     "\xd0\x87",
     "\xe2\x95\xa6",
     "\xe2\x95\xa7",
     "\xe2\x95\xa8",
     "\xe2\x95\xa9",
     "\xe2\x95\xaa",
     "\xd2\x90",
     "\xe2\x95\xac",
     "\xc2\xa9",
     "\xd1\x8e",
     "\xd0\xb0",
     "\xd0\xb1",
     "\xd1\x86",
     "\xd0\xb4",
     "\xd0\xb5",
     "\xd1\x84",
     "\xd0\xb3",
     "\xd1\x85",
     "\xd0\xb8",
     "\xd0\xb9",
     "\xd0\xba",
     "\xd0\xbb",
     "\xd0\xbc",
     "\xd0\xbd",
     "\xd0\xbe",
     "\xd0\xbf",
     "\xd1\x8f",
     "\xd1\x80",
     "\xd1\x81",
     "\xd1\x82",
     "\xd1\x83",
     "\xd0\xb6",
     "\xd0\xb2",
     "\xd1\x8c",
     "\xd1\x8b",
     "\xd0\xb7",
     "\xd1\x88",
     "\xd1\x8d",
     "\xd1\x89",
     "\xd1\x87",
     "\xd1\x8a",
     "\xd0\xae",
     "\xd0\x90",
     "\xd0\x91",
     "\xd0\xa6",
     "\xd0\x94",
     "\xd0\x95",
     "\xd0\xa4",
     "\xd0\x93",
     "\xd0\xa5",
     "\xd0\x98",
     "\xd0\x99",
     "\xd0\x9a",
     "\xd0\x9b",
     "\xd0\x9c",
     "\xd0\x9d",
     "\xd0\x9e",
     "\xd0\x9f",
     "\xd0\xaf",
     "\xd0\xa0",
     "\xd0\xa1",
     "\xd0\xa2",
     "\xd0\xa3",
     "\xd0\x96",
     "\xd0\x92",
     "\xd0\xac",
     "\xd0\xab",
     "\xd0\x97",
     "\xd0\xa8",
     "\xd0\xad",
     "\xd0\xa9",
     "\xd0\xa7",
     "\xd0\xaa",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x04",
     0x00000005 => "\x05",
     0x00000006 => "\x06",
     0x00000007 => "\x07",
     0x00000008 => "\x08",
     0x00000009 => "\x09",
     0x0000000a => "\x0a",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x14",
     0x00000015 => "\x15",
     0x00000016 => "\x16",
     0x00000017 => "\x17",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x1a",
     0x0000001b => "\x1b",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x20",
     0x00000021 => "\x21",
     0x00000022 => "\x22",
     0x00000023 => "\x23",
     0x00000024 => "\x24",
     0x00000025 => "\x25",
     0x00000026 => "\x26",
     0x00000027 => "\x27",
     0x00000028 => "\x28",
     0x00000029 => "\x29",
     0x0000002a => "\x2a",
     0x0000002b => "\x2b",
     0x0000002c => "\x2c",
     0x0000002d => "\x2d",
     0x0000002e => "\x2e",
     0x0000002f => "\x2f",
     0x00000030 => "\x30",
     0x00000031 => "\x31",
     0x00000032 => "\x32",
     0x00000033 => "\x33",
     0x00000034 => "\x34",
     0x00000035 => "\x35",
     0x00000036 => "\x36",
     0x00000037 => "\x37",
     0x00000038 => "\x38",
     0x00000039 => "\x39",
     0x0000003a => "\x3a",
     0x0000003b => "\x3b",
     0x0000003c => "\x3c",
     0x0000003d => "\x3d",
     0x0000003e => "\x3e",
     0x0000003f => "\x3f",
     0x00000040 => "\x40",
     0x00000041 => "\x41",
     0x00000042 => "\x42",
     0x00000043 => "\x43",
     0x00000044 => "\x44",
     0x00000045 => "\x45",
     0x00000046 => "\x46",
     0x00000047 => "\x47",
     0x00000048 => "\x48",
     0x00000049 => "\x49",
     0x0000004a => "\x4a",
     0x0000004b => "\x4b",
     0x0000004c => "\x4c",
     0x0000004d => "\x4d",
     0x0000004e => "\x4e",
     0x0000004f => "\x4f",
     0x00000050 => "\x50",
     0x00000051 => "\x51",
     0x00000052 => "\x52",
     0x00000053 => "\x53",
     0x00000054 => "\x54",
     0x00000055 => "\x55",
     0x00000056 => "\x56",
     0x00000057 => "\x57",
     0x00000058 => "\x58",
     0x00000059 => "\x59",
     0x0000005a => "\x5a",
     0x0000005b => "\x5b",
     0x0000005c => "\x5c",
     0x0000005d => "\x5d",
     0x0000005e => "\x5e",
     0x0000005f => "\x5f",
     0x00000060 => "\x60",
     0x00000061 => "\x61",
     0x00000062 => "\x62",
     0x00000063 => "\x63",
     0x00000064 => "\x64",
     0x00000065 => "\x65",
     0x00000066 => "\x66",
     0x00000067 => "\x67",
     0x00000068 => "\x68",
     0x00000069 => "\x69",
     0x0000006a => "\x6a",
     0x0000006b => "\x6b",
     0x0000006c => "\x6c",
     0x0000006d => "\x6d",
     0x0000006e => "\x6e",
     0x0000006f => "\x6f",
     0x00000070 => "\x70",
     0x00000071 => "\x71",
     0x00000072 => "\x72",
     0x00000073 => "\x73",
     0x00000074 => "\x74",
     0x00000075 => "\x75",
     0x00000076 => "\x76",
     0x00000077 => "\x77",
     0x00000078 => "\x78",
     0x00000079 => "\x79",
     0x0000007a => "\x7a",
     0x0000007b => "\x7b",
     0x0000007c => "\x7c",
     0x0000007d => "\x7d",
     0x0000007e => "\x7e",
     0x0000007f => "\x7f",
     0x000000a0 => "\x9a",
     0x000000a9 => "\xbf",
     0x000000b0 => "\x9c",
     0x000000b2 => "\x9d",
     0x000000b7 => "\x9e",
     0x000000f7 => "\x9f",
     0x00000401 => "\xb3",
     0x00000404 => "\xb4",
     0x00000406 => "\xb6",
     0x00000407 => "\xb7",
     0x00000410 => "\xe1",
     0x00000411 => "\xe2",
     0x00000412 => "\xf7",
     0x00000413 => "\xe7",
     0x00000414 => "\xe4",
     0x00000415 => "\xe5",
     0x00000416 => "\xf6",
     0x00000417 => "\xfa",
     0x00000418 => "\xe9",
     0x00000419 => "\xea",
     0x0000041a => "\xeb",
     0x0000041b => "\xec",
     0x0000041c => "\xed",
     0x0000041d => "\xee",
     0x0000041e => "\xef",
     0x0000041f => "\xf0",
     0x00000420 => "\xf2",
     0x00000421 => "\xf3",
     0x00000422 => "\xf4",
     0x00000423 => "\xf5",
     0x00000424 => "\xe6",
     0x00000425 => "\xe8",
     0x00000426 => "\xe3",
     0x00000427 => "\xfe",
     0x00000428 => "\xfb",
     0x00000429 => "\xfd",
     0x0000042a => "\xff",
     0x0000042b => "\xf9",
     0x0000042c => "\xf8",
     0x0000042d => "\xfc",
     0x0000042e => "\xe0",
     0x0000042f => "\xf1",
     0x00000430 => "\xc1",
     0x00000431 => "\xc2",
     0x00000432 => "\xd7",
     0x00000433 => "\xc7",
     0x00000434 => "\xc4",
     0x00000435 => "\xc5",
     0x00000436 => "\xd6",
     0x00000437 => "\xda",
     0x00000438 => "\xc9",
     0x00000439 => "\xca",
     0x0000043a => "\xcb",
     0x0000043b => "\xcc",
     0x0000043c => "\xcd",
     0x0000043d => "\xce",
     0x0000043e => "\xcf",
     0x0000043f => "\xd0",
     0x00000440 => "\xd2",
     0x00000441 => "\xd3",
     0x00000442 => "\xd4",
     0x00000443 => "\xd5",
     0x00000444 => "\xc6",
     0x00000445 => "\xc8",
     0x00000446 => "\xc3",
     0x00000447 => "\xde",
     0x00000448 => "\xdb",
     0x00000449 => "\xdd",
     0x0000044a => "\xdf",
     0x0000044b => "\xd9",
     0x0000044c => "\xd8",
     0x0000044d => "\xdc",
     0x0000044e => "\xc0",
     0x0000044f => "\xd1",
     0x00000451 => "\xa3",
     0x00000454 => "\xa4",
     0x00000456 => "\xa6",
     0x00000457 => "\xa7",
     0x00000490 => "\xbd",
     0x00000491 => "\xad",
     0x00002219 => "\x95",
     0x0000221a => "\x96",
     0x00002248 => "\x97",
     0x00002264 => "\x98",
     0x00002265 => "\x99",
     0x00002320 => "\x93",
     0x00002321 => "\x9b",
     0x00002500 => "\x80",
     0x00002502 => "\x81",
     0x0000250c => "\x82",
     0x00002510 => "\x83",
     0x00002514 => "\x84",
     0x00002518 => "\x85",
     0x0000251c => "\x86",
     0x00002524 => "\x87",
     0x0000252c => "\x88",
     0x00002534 => "\x89",
     0x0000253c => "\x8a",
     0x00002550 => "\xa0",
     0x00002551 => "\xa1",
     0x00002552 => "\xa2",
     0x00002554 => "\xa5",
     0x00002557 => "\xa8",
     0x00002558 => "\xa9",
     0x00002559 => "\xaa",
     0x0000255a => "\xab",
     0x0000255b => "\xac",
     0x0000255d => "\xae",
     0x0000255e => "\xaf",
     0x0000255f => "\xb0",
     0x00002560 => "\xb1",
     0x00002561 => "\xb2",
     0x00002563 => "\xb5",
     0x00002566 => "\xb8",
     0x00002567 => "\xb9",
     0x00002568 => "\xba",
     0x00002569 => "\xbb",
     0x0000256a => "\xbc",
     0x0000256c => "\xbe",
     0x00002580 => "\x8b",
     0x00002584 => "\x8c",
     0x00002588 => "\x8d",
     0x0000258c => "\x8e",
     0x00002590 => "\x8f",
     0x00002591 => "\x90",
     0x00002592 => "\x91",
     0x00002593 => "\x92",
     0x000025a0 => "\x94",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::KOI8_U - Conversion routines for KOI8-U
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for KOI8-U.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.1
   source: RFC 2319
   source: http://www.net.ua/KOI8-U/
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  00000004 | END OF TRANSMISSION (EOT)
     05 |  00000005 | ENQUIRY (ENQ)
     06 |  00000006 | ACKNOWLEDGE (ACK)
     07 |  00000007 | BELL (BEL)
     08 |  00000008 | BACKSPACE (BS)
     09 |  00000009 | CHARACTER TABULATION (HT)
     0A |  0000000A | LINE FEED (LF)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  00000014 | DEVICE CONTROL FOUR (DC4)
     15 |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     16 |  00000016 | SYNCHRONOUS IDLE (SYN)
     17 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  0000001A | SUBSTITUTE (SUB)
     1B |  0000001B | ESCAPE (ESC)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000020 | SPACE
     21 |  00000021 | EXCLAMATION MARK
     22 |  00000022 | QUOTATION MARK
     23 |  00000023 | NUMBER SIGN
     24 |  00000024 | DOLLAR SIGN
     25 |  00000025 | PERCENT SIGN
     26 |  00000026 | AMPERSAND
     27 |  00000027 | APOSTROPHE
     28 |  00000028 | LEFT PARENTHESIS
     29 |  00000029 | RIGHT PARENTHESIS
     2A |  0000002A | ASTERISK
     2B |  0000002B | PLUS SIGN
     2C |  0000002C | COMMA
     2D |  0000002D | HYPHEN-MINUS
     2E |  0000002E | FULL STOP
     2F |  0000002F | SOLIDUS
     30 |  00000030 | DIGIT ZERO
     31 |  00000031 | DIGIT ONE
     32 |  00000032 | DIGIT TWO
     33 |  00000033 | DIGIT THREE
     34 |  00000034 | DIGIT FOUR
     35 |  00000035 | DIGIT FIVE
     36 |  00000036 | DIGIT SIX
     37 |  00000037 | DIGIT SEVEN
     38 |  00000038 | DIGIT EIGHT
     39 |  00000039 | DIGIT NINE
     3A |  0000003A | COLON
     3B |  0000003B | SEMICOLON
     3C |  0000003C | LESS-THAN SIGN
     3D |  0000003D | EQUALS SIGN
     3E |  0000003E | GREATER-THAN SIGN
     3F |  0000003F | QUESTION MARK
     40 |  00000040 | COMMERCIAL AT
     41 |  00000041 | LATIN CAPITAL LETTER A
     42 |  00000042 | LATIN CAPITAL LETTER B
     43 |  00000043 | LATIN CAPITAL LETTER C
     44 |  00000044 | LATIN CAPITAL LETTER D
     45 |  00000045 | LATIN CAPITAL LETTER E
     46 |  00000046 | LATIN CAPITAL LETTER F
     47 |  00000047 | LATIN CAPITAL LETTER G
     48 |  00000048 | LATIN CAPITAL LETTER H
     49 |  00000049 | LATIN CAPITAL LETTER I
     4A |  0000004A | LATIN CAPITAL LETTER J
     4B |  0000004B | LATIN CAPITAL LETTER K
     4C |  0000004C | LATIN CAPITAL LETTER L
     4D |  0000004D | LATIN CAPITAL LETTER M
     4E |  0000004E | LATIN CAPITAL LETTER N
     4F |  0000004F | LATIN CAPITAL LETTER O
     50 |  00000050 | LATIN CAPITAL LETTER P
     51 |  00000051 | LATIN CAPITAL LETTER Q
     52 |  00000052 | LATIN CAPITAL LETTER R
     53 |  00000053 | LATIN CAPITAL LETTER S
     54 |  00000054 | LATIN CAPITAL LETTER T
     55 |  00000055 | LATIN CAPITAL LETTER U
     56 |  00000056 | LATIN CAPITAL LETTER V
     57 |  00000057 | LATIN CAPITAL LETTER W
     58 |  00000058 | LATIN CAPITAL LETTER X
     59 |  00000059 | LATIN CAPITAL LETTER Y
     5A |  0000005A | LATIN CAPITAL LETTER Z
     5B |  0000005B | LEFT SQUARE BRACKET
     5C |  0000005C | REVERSE SOLIDUS
     5D |  0000005D | RIGHT SQUARE BRACKET
     5E |  0000005E | CIRCUMFLEX ACCENT
     5F |  0000005F | LOW LINE
     60 |  00000060 | GRAVE ACCENT
     61 |  00000061 | LATIN SMALL LETTER A
     62 |  00000062 | LATIN SMALL LETTER B
     63 |  00000063 | LATIN SMALL LETTER C
     64 |  00000064 | LATIN SMALL LETTER D
     65 |  00000065 | LATIN SMALL LETTER E
     66 |  00000066 | LATIN SMALL LETTER F
     67 |  00000067 | LATIN SMALL LETTER G
     68 |  00000068 | LATIN SMALL LETTER H
     69 |  00000069 | LATIN SMALL LETTER I
     6A |  0000006A | LATIN SMALL LETTER J
     6B |  0000006B | LATIN SMALL LETTER K
     6C |  0000006C | LATIN SMALL LETTER L
     6D |  0000006D | LATIN SMALL LETTER M
     6E |  0000006E | LATIN SMALL LETTER N
     6F |  0000006F | LATIN SMALL LETTER O
     70 |  00000070 | LATIN SMALL LETTER P
     71 |  00000071 | LATIN SMALL LETTER Q
     72 |  00000072 | LATIN SMALL LETTER R
     73 |  00000073 | LATIN SMALL LETTER S
     74 |  00000074 | LATIN SMALL LETTER T
     75 |  00000075 | LATIN SMALL LETTER U
     76 |  00000076 | LATIN SMALL LETTER V
     77 |  00000077 | LATIN SMALL LETTER W
     78 |  00000078 | LATIN SMALL LETTER X
     79 |  00000079 | LATIN SMALL LETTER Y
     7A |  0000007A | LATIN SMALL LETTER Z
     7B |  0000007B | LEFT CURLY BRACKET
     7C |  0000007C | VERTICAL LINE
     7D |  0000007D | RIGHT CURLY BRACKET
     7E |  0000007E | TILDE
     7F |  0000007F | DELETE (DEL)
     80 |  00002500 | BOX DRAWINGS LIGHT HORIZONTAL
     81 |  00002502 | BOX DRAWINGS LIGHT VERTICAL
     82 |  0000250C | BOX DRAWINGS LIGHT DOWN AND RIGHT
     83 |  00002510 | BOX DRAWINGS LIGHT DOWN AND LEFT
     84 |  00002514 | BOX DRAWINGS LIGHT UP AND RIGHT
     85 |  00002518 | BOX DRAWINGS LIGHT UP AND LEFT
     86 |  0000251C | BOX DRAWINGS LIGHT VERTICAL AND RIGHT
     87 |  00002524 | BOX DRAWINGS LIGHT VERTICAL AND LEFT
     88 |  0000252C | BOX DRAWINGS LIGHT DOWN AND HORIZONTAL
     89 |  00002534 | BOX DRAWINGS LIGHT UP AND HORIZONTAL
     8A |  0000253C | BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL
     8B |  00002580 | UPPER HALF BLOCK
     8C |  00002584 | LOWER HALF BLOCK
     8D |  00002588 | FULL BLOCK
     8E |  0000258C | LEFT HALF BLOCK
     8F |  00002590 | RIGHT HALF BLOCK
     90 |  00002591 | LIGHT SHADE
     91 |  00002592 | MEDIUM SHADE
     92 |  00002593 | DARK SHADE
     93 |  00002320 | TOP HALF INTEGRAL
     94 |  000025A0 | BLACK SQUARE
     95 |  00002219 | BULLET OPERATOR
     96 |  0000221A | SQUARE ROOT
     97 |  00002248 | ALMOST EQUAL TO
     98 |  00002264 | LESS THAN OR EQUAL TO
     99 |  00002265 | GREATER THAN OR EQUAL TO
     9A |  000000A0 | NO-BREAK SPACE
     9B |  00002321 | BOTTOM HALF INTEGRAL
     9C |  000000B0 | DEGREE SIGN
     9D |  000000B2 | SUPERSCRIPT DIGIT TWO
     9E |  000000B7 | MIDDLE DOT
     9F |  000000F7 | DIVISION SIGN
     A0 |  00002550 | BOX DRAWINGS DOUBLE HORIZONTAL
     A1 |  00002551 | BOX DRAWINGS DOUBLE VERTICAL
     A2 |  00002552 | BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE
     A3 |  00000451 | CYRILLIC SMALL LETTER IO
     A4 |  00000454 | CYRILLIC SMALL LETTER UKRAINIAN IE
     A5 |  00002554 | BOX DRAWINGS DOUBLE DOWN AND RIGHT
     A6 |  00000456 | CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I
     A7 |  00000457 | CYRILLIC SMALL LETTER YI (Ukrainian)
     A8 |  00002557 | BOX DRAWINGS DOUBLE DOWN AND LEFT
     A9 |  00002558 | BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE
     AA |  00002559 | BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE
     AB |  0000255A | BOX DRAWINGS DOUBLE UP AND RIGHT
     AC |  0000255B | BOX DRAWINGS UP SINGLE AND LEFT DOUBLE
     AD |  00000491 | CYRILLIC SMALL LETTER GHE WITH UPTURN
     AE |  0000255D | BOX DRAWINGS  DOUBLE UP AND LEFT
     AF |  0000255E | BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE
     B0 |  0000255F | BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE
     B1 |  00002560 | BOX DRAWINGS DOUBLE VERTICAL AND RIGHT
     B2 |  00002561 | BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE
     B3 |  00000401 | CYRILLIC CAPITAL LETTER IO
     B4 |  00000404 | CYRILLIC CAPITAL LETTER UKRAINIAN IE
     B5 |  00002563 | DOUBLE VERTICAL AND LEFT
     B6 |  00000406 | CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I
     B7 |  00000407 | CYRILLIC CAPITAL LETTER YI (Ukrainian)
     B8 |  00002566 | BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL
     B9 |  00002567 | BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE
     BA |  00002568 | BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE
     BB |  00002569 | BOX DRAWINGS DOUBLE UP AND HORIZONTAL
     BC |  0000256A | BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE
     BD |  00000490 | CYRILLIC CAPITAL LETTER GHE WITH UPTURN
     BE |  0000256C | BOX DRAWINGS  DOUBLE VERTICAL AND HORIZONTAL
     BF |  000000A9 | COPYRIGHT SIGN
     C0 |  0000044E | CYRILLIC SMALL LETTER YU
     C1 |  00000430 | CYRILLIC SMALL LETTER A
     C2 |  00000431 | CYRILLIC SMALL LETTER BE
     C3 |  00000446 | CYRILLIC SMALL LETTER TSE
     C4 |  00000434 | CYRILLIC SMALL LETTER DE
     C5 |  00000435 | CYRILLIC SMALL LETTER IE
     C6 |  00000444 | CYRILLIC SMALL LETTER EF
     C7 |  00000433 | CYRILLIC SMALL LETTER GHE
     C8 |  00000445 | CYRILLIC SMALL LETTER HA
     C9 |  00000438 | CYRILLIC SMALL LETTER I
     CA |  00000439 | CYRILLIC SMALL LETTER SHORT I
     CB |  0000043A | CYRILLIC SMALL LETTER KA
     CC |  0000043B | CYRILLIC SMALL LETTER EL
     CD |  0000043C | CYRILLIC SMALL LETTER EM
     CE |  0000043D | CYRILLIC SMALL LETTER EN
     CF |  0000043E | CYRILLIC SMALL LETTER O
     D0 |  0000043F | CYRILLIC SMALL LETTER PE
     D1 |  0000044F | CYRILLIC SMALL LETTER YA
     D2 |  00000440 | CYRILLIC SMALL LETTER ER
     D3 |  00000441 | CYRILLIC SMALL LETTER ES
     D4 |  00000442 | CYRILLIC SMALL LETTER TE
     D5 |  00000443 | CYRILLIC SMALL LETTER U
     D6 |  00000436 | CYRILLIC SMALL LETTER ZHE
     D7 |  00000432 | CYRILLIC SMALL LETTER VE
     D8 |  0000044C | CYRILLIC SMALL LETTER SOFT SIGN
     D9 |  0000044B | CYRILLIC SMALL LETTER YERU
     DA |  00000437 | CYRILLIC SMALL LETTER ZE
     DB |  00000448 | CYRILLIC SMALL LETTER SHA
     DC |  0000044D | CYRILLIC SMALL LETTER E
     DD |  00000449 | CYRILLIC SMALL LETTER SHCHA
     DE |  00000447 | CYRILLIC SMALL LETTER CHE
     DF |  0000044A | CYRILLIC SMALL LETTER HARD SIGN
     E0 |  0000042E | CYRILLIC CAPITAL LETTER YU
     E1 |  00000410 | CYRILLIC CAPITAL LETTER A
     E2 |  00000411 | CYRILLIC CAPITAL LETTER BE
     E3 |  00000426 | CYRILLIC CAPITAL LETTER TSE
     E4 |  00000414 | CYRILLIC CAPITAL LETTER DE
     E5 |  00000415 | CYRILLIC CAPITAL LETTER IE
     E6 |  00000424 | CYRILLIC CAPITAL LETTER EF
     E7 |  00000413 | CYRILLIC CAPITAL LETTER GHE
     E8 |  00000425 | CYRILLIC CAPITAL LETTER HA
     E9 |  00000418 | CYRILLIC CAPITAL LETTER I
     EA |  00000419 | CYRILLIC CAPITAL LETTER SHORT I
     EB |  0000041A | CYRILLIC CAPITAL LETTER KA
     EC |  0000041B | CYRILLIC CAPITAL LETTER EL
     ED |  0000041C | CYRILLIC CAPITAL LETTER EM
     EE |  0000041D | CYRILLIC CAPITAL LETTER EN
     EF |  0000041E | CYRILLIC CAPITAL LETTER O
     F0 |  0000041F | CYRILLIC CAPITAL LETTER PE
     F1 |  0000042F | CYRILLIC CAPITAL LETTER YA
     F2 |  00000420 | CYRILLIC CAPITAL LETTER ER
     F3 |  00000421 | CYRILLIC CAPITAL LETTER ES
     F4 |  00000422 | CYRILLIC CAPITAL LETTER TE
     F5 |  00000423 | CYRILLIC CAPITAL LETTER U
     F6 |  00000416 | CYRILLIC CAPITAL LETTER ZHE
     F7 |  00000412 | CYRILLIC CAPITAL LETTER VE
     F8 |  0000042C | CYRILLIC CAPITAL LETTER SOFT SIGN
     F9 |  0000042B | CYRILLIC CAPITAL LETTER YERU
     FA |  00000417 | CYRILLIC CAPITAL LETTER ZE
     FB |  00000428 | CYRILLIC CAPITAL LETTER SHA
     FC |  0000042D | CYRILLIC CAPITAL LETTER E
     FD |  00000429 | CYRILLIC CAPITAL LETTER SHCHA
     FE |  00000427 | CYRILLIC CAPITAL LETTER CHE
     FF |  0000042A | CYRILLIC CAPITAL LETTER HARD SIGN
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/KOI_8.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for KOI-8.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::KOI_8;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x0004,
     0x0005,
     0x0006,
     0x0007,
     0x0008,
     0x0009,
     0x000a,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x0014,
     0x0015,
     0x0016,
     0x0017,
     0x0018,
     0x0019,
     0x001a,
     0x001b,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0020,
     0x0021,
     0x0022,
     0x0023,
     0x0024,
     0x0025,
     0x0026,
     0x0027,
     0x0028,
     0x0029,
     0x002a,
     0x002b,
     0x002c,
     0x002d,
     0x002e,
     0x002f,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x003a,
     0x003b,
     0x003c,
     0x003d,
     0x003e,
     0x003f,
     0x0040,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x005b,
     0x005c,
     0x005d,
     0x005e,
     0x005f,
     0x0060,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x007b,
     0x007c,
     0x007d,
     0x007e,
     0x007f,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x044e,
     0x0430,
     0x0431,
     0x0446,
     0x0434,
     0x0435,
     0x0444,
     0x0433,
     0x0445,
     0x0438,
     0x0439,
     0x043a,
     0x043b,
     0x043c,
     0x043d,
     0x043e,
     0x043f,
     0x044f,
     0x0440,
     0x0441,
     0x0442,
     0x0443,
     0x0436,
     0x0432,
     0x044c,
     0x044b,
     0x0437,
     0x0448,
     0x044d,
     0x0449,
     0x0447,
     0x044a,
     0x042e,
     0x0410,
     0x0411,
     0x0426,
     0x0414,
     0x0415,
     0x0424,
     0x0413,
     0x0425,
     0x0418,
     0x0419,
     0x041a,
     0x041b,
     0x041c,
     0x041d,
     0x041e,
     0x041f,
     0x042f,
     0x0420,
     0x0421,
     0x0422,
     0x0423,
     0x0416,
     0x0412,
     0x042c,
     0x042b,
     0x0417,
     0x0428,
     0x042d,
     0x0429,
     0x0427,
     0xfffd,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\x04",
     "\x05",
     "\x06",
     "\x07",
     "\x08",
     "\x09",
     "\x0a",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\x14",
     "\x15",
     "\x16",
     "\x17",
     "\x18",
     "\x19",
     "\x1a",
     "\x1b",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\x20",
     "\x21",
     "\x22",
     "\x23",
     "\x24",
     "\x25",
     "\x26",
     "\x27",
     "\x28",
     "\x29",
     "\x2a",
     "\x2b",
     "\x2c",
     "\x2d",
     "\x2e",
     "\x2f",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\x3a",
     "\x3b",
     "\x3c",
     "\x3d",
     "\x3e",
     "\x3f",
     "\x40",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\x5b",
     "\x5c",
     "\x5d",
     "\x5e",
     "\x5f",
     "\x60",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\x7b",
     "\x7c",
     "\x7d",
     "\x7e",
     "\x7f",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xd1\x8e",
     "\xd0\xb0",
     "\xd0\xb1",
     "\xd1\x86",
     "\xd0\xb4",
     "\xd0\xb5",
     "\xd1\x84",
     "\xd0\xb3",
     "\xd1\x85",
     "\xd0\xb8",
     "\xd0\xb9",
     "\xd0\xba",
     "\xd0\xbb",
     "\xd0\xbc",
     "\xd0\xbd",
     "\xd0\xbe",
     "\xd0\xbf",
     "\xd1\x8f",
     "\xd1\x80",
     "\xd1\x81",
     "\xd1\x82",
     "\xd1\x83",
     "\xd0\xb6",
     "\xd0\xb2",
     "\xd1\x8c",
     "\xd1\x8b",
     "\xd0\xb7",
     "\xd1\x88",
     "\xd1\x8d",
     "\xd1\x89",
     "\xd1\x87",
     "\xd1\x8a",
     "\xd0\xae",
     "\xd0\x90",
     "\xd0\x91",
     "\xd0\xa6",
     "\xd0\x94",
     "\xd0\x95",
     "\xd0\xa4",
     "\xd0\x93",
     "\xd0\xa5",
     "\xd0\x98",
     "\xd0\x99",
     "\xd0\x9a",
     "\xd0\x9b",
     "\xd0\x9c",
     "\xd0\x9d",
     "\xd0\x9e",
     "\xd0\x9f",
     "\xd0\xaf",
     "\xd0\xa0",
     "\xd0\xa1",
     "\xd0\xa2",
     "\xd0\xa3",
     "\xd0\x96",
     "\xd0\x92",
     "\xd0\xac",
     "\xd0\xab",
     "\xd0\x97",
     "\xd0\xa8",
     "\xd0\xad",
     "\xd0\xa9",
     "\xd0\xa7",
     "\xef\xbf\xbd",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x04",
     0x00000005 => "\x05",
     0x00000006 => "\x06",
     0x00000007 => "\x07",
     0x00000008 => "\x08",
     0x00000009 => "\x09",
     0x0000000a => "\x0a",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x14",
     0x00000015 => "\x15",
     0x00000016 => "\x16",
     0x00000017 => "\x17",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x1a",
     0x0000001b => "\x1b",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x20",
     0x00000021 => "\x21",
     0x00000022 => "\x22",
     0x00000023 => "\x23",
     0x00000024 => "\x24",
     0x00000025 => "\x25",
     0x00000026 => "\x26",
     0x00000027 => "\x27",
     0x00000028 => "\x28",
     0x00000029 => "\x29",
     0x0000002a => "\x2a",
     0x0000002b => "\x2b",
     0x0000002c => "\x2c",
     0x0000002d => "\x2d",
     0x0000002e => "\x2e",
     0x0000002f => "\x2f",
     0x00000030 => "\x30",
     0x00000031 => "\x31",
     0x00000032 => "\x32",
     0x00000033 => "\x33",
     0x00000034 => "\x34",
     0x00000035 => "\x35",
     0x00000036 => "\x36",
     0x00000037 => "\x37",
     0x00000038 => "\x38",
     0x00000039 => "\x39",
     0x0000003a => "\x3a",
     0x0000003b => "\x3b",
     0x0000003c => "\x3c",
     0x0000003d => "\x3d",
     0x0000003e => "\x3e",
     0x0000003f => "\x3f",
     0x00000040 => "\x40",
     0x00000041 => "\x41",
     0x00000042 => "\x42",
     0x00000043 => "\x43",
     0x00000044 => "\x44",
     0x00000045 => "\x45",
     0x00000046 => "\x46",
     0x00000047 => "\x47",
     0x00000048 => "\x48",
     0x00000049 => "\x49",
     0x0000004a => "\x4a",
     0x0000004b => "\x4b",
     0x0000004c => "\x4c",
     0x0000004d => "\x4d",
     0x0000004e => "\x4e",
     0x0000004f => "\x4f",
     0x00000050 => "\x50",
     0x00000051 => "\x51",
     0x00000052 => "\x52",
     0x00000053 => "\x53",
     0x00000054 => "\x54",
     0x00000055 => "\x55",
     0x00000056 => "\x56",
     0x00000057 => "\x57",
     0x00000058 => "\x58",
     0x00000059 => "\x59",
     0x0000005a => "\x5a",
     0x0000005b => "\x5b",
     0x0000005c => "\x5c",
     0x0000005d => "\x5d",
     0x0000005e => "\x5e",
     0x0000005f => "\x5f",
     0x00000060 => "\x60",
     0x00000061 => "\x61",
     0x00000062 => "\x62",
     0x00000063 => "\x63",
     0x00000064 => "\x64",
     0x00000065 => "\x65",
     0x00000066 => "\x66",
     0x00000067 => "\x67",
     0x00000068 => "\x68",
     0x00000069 => "\x69",
     0x0000006a => "\x6a",
     0x0000006b => "\x6b",
     0x0000006c => "\x6c",
     0x0000006d => "\x6d",
     0x0000006e => "\x6e",
     0x0000006f => "\x6f",
     0x00000070 => "\x70",
     0x00000071 => "\x71",
     0x00000072 => "\x72",
     0x00000073 => "\x73",
     0x00000074 => "\x74",
     0x00000075 => "\x75",
     0x00000076 => "\x76",
     0x00000077 => "\x77",
     0x00000078 => "\x78",
     0x00000079 => "\x79",
     0x0000007a => "\x7a",
     0x0000007b => "\x7b",
     0x0000007c => "\x7c",
     0x0000007d => "\x7d",
     0x0000007e => "\x7e",
     0x0000007f => "\x7f",
     0x00000410 => "\xe1",
     0x00000411 => "\xe2",
     0x00000412 => "\xf7",
     0x00000413 => "\xe7",
     0x00000414 => "\xe4",
     0x00000415 => "\xe5",
     0x00000416 => "\xf6",
     0x00000417 => "\xfa",
     0x00000418 => "\xe9",
     0x00000419 => "\xea",
     0x0000041a => "\xeb",
     0x0000041b => "\xec",
     0x0000041c => "\xed",
     0x0000041d => "\xee",
     0x0000041e => "\xef",
     0x0000041f => "\xf0",
     0x00000420 => "\xf2",
     0x00000421 => "\xf3",
     0x00000422 => "\xf4",
     0x00000423 => "\xf5",
     0x00000424 => "\xe6",
     0x00000425 => "\xe8",
     0x00000426 => "\xe3",
     0x00000427 => "\xfe",
     0x00000428 => "\xfb",
     0x00000429 => "\xfd",
     0x0000042b => "\xf9",
     0x0000042c => "\xf8",
     0x0000042d => "\xfc",
     0x0000042e => "\xe0",
     0x0000042f => "\xf1",
     0x00000430 => "\xc1",
     0x00000431 => "\xc2",
     0x00000432 => "\xd7",
     0x00000433 => "\xc7",
     0x00000434 => "\xc4",
     0x00000435 => "\xc5",
     0x00000436 => "\xd6",
     0x00000437 => "\xda",
     0x00000438 => "\xc9",
     0x00000439 => "\xca",
     0x0000043a => "\xcb",
     0x0000043b => "\xcc",
     0x0000043c => "\xcd",
     0x0000043d => "\xce",
     0x0000043e => "\xcf",
     0x0000043f => "\xd0",
     0x00000440 => "\xd2",
     0x00000441 => "\xd3",
     0x00000442 => "\xd4",
     0x00000443 => "\xd5",
     0x00000444 => "\xc6",
     0x00000445 => "\xc8",
     0x00000446 => "\xc3",
     0x00000447 => "\xde",
     0x00000448 => "\xdb",
     0x00000449 => "\xdd",
     0x0000044a => "\xdf",
     0x0000044b => "\xd9",
     0x0000044c => "\xd8",
     0x0000044d => "\xdc",
     0x0000044e => "\xc0",
     0x0000044f => "\xd1",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::KOI_8 - Conversion routines for KOI-8
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for KOI-8.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
   source: Andrey A. Chernov E<lt>ache@astral.msk.suE<gt>
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  00000004 | END OF TRANSMISSION (EOT)
     05 |  00000005 | ENQUIRY (ENQ)
     06 |  00000006 | ACKNOWLEDGE (ACK)
     07 |  00000007 | BELL (BEL)
     08 |  00000008 | BACKSPACE (BS)
     09 |  00000009 | CHARACTER TABULATION (HT)
     0A |  0000000A | LINE FEED (LF)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  00000014 | DEVICE CONTROL FOUR (DC4)
     15 |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     16 |  00000016 | SYNCHRONOUS IDLE (SYN)
     17 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  0000001A | SUBSTITUTE (SUB)
     1B |  0000001B | ESCAPE (ESC)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000020 | SPACE
     21 |  00000021 | EXCLAMATION MARK
     22 |  00000022 | QUOTATION MARK
     23 |  00000023 | NUMBER SIGN
     24 |  00000024 | DOLLAR SIGN
     25 |  00000025 | PERCENT SIGN
     26 |  00000026 | AMPERSAND
     27 |  00000027 | APOSTROPHE
     28 |  00000028 | LEFT PARENTHESIS
     29 |  00000029 | RIGHT PARENTHESIS
     2A |  0000002A | ASTERISK
     2B |  0000002B | PLUS SIGN
     2C |  0000002C | COMMA
     2D |  0000002D | HYPHEN-MINUS
     2E |  0000002E | FULL STOP
     2F |  0000002F | SOLIDUS
     30 |  00000030 | DIGIT ZERO
     31 |  00000031 | DIGIT ONE
     32 |  00000032 | DIGIT TWO
     33 |  00000033 | DIGIT THREE
     34 |  00000034 | DIGIT FOUR
     35 |  00000035 | DIGIT FIVE
     36 |  00000036 | DIGIT SIX
     37 |  00000037 | DIGIT SEVEN
     38 |  00000038 | DIGIT EIGHT
     39 |  00000039 | DIGIT NINE
     3A |  0000003A | COLON
     3B |  0000003B | SEMICOLON
     3C |  0000003C | LESS-THAN SIGN
     3D |  0000003D | EQUALS SIGN
     3E |  0000003E | GREATER-THAN SIGN
     3F |  0000003F | QUESTION MARK
     40 |  00000040 | COMMERCIAL AT
     41 |  00000041 | LATIN CAPITAL LETTER A
     42 |  00000042 | LATIN CAPITAL LETTER B
     43 |  00000043 | LATIN CAPITAL LETTER C
     44 |  00000044 | LATIN CAPITAL LETTER D
     45 |  00000045 | LATIN CAPITAL LETTER E
     46 |  00000046 | LATIN CAPITAL LETTER F
     47 |  00000047 | LATIN CAPITAL LETTER G
     48 |  00000048 | LATIN CAPITAL LETTER H
     49 |  00000049 | LATIN CAPITAL LETTER I
     4A |  0000004A | LATIN CAPITAL LETTER J
     4B |  0000004B | LATIN CAPITAL LETTER K
     4C |  0000004C | LATIN CAPITAL LETTER L
     4D |  0000004D | LATIN CAPITAL LETTER M
     4E |  0000004E | LATIN CAPITAL LETTER N
     4F |  0000004F | LATIN CAPITAL LETTER O
     50 |  00000050 | LATIN CAPITAL LETTER P
     51 |  00000051 | LATIN CAPITAL LETTER Q
     52 |  00000052 | LATIN CAPITAL LETTER R
     53 |  00000053 | LATIN CAPITAL LETTER S
     54 |  00000054 | LATIN CAPITAL LETTER T
     55 |  00000055 | LATIN CAPITAL LETTER U
     56 |  00000056 | LATIN CAPITAL LETTER V
     57 |  00000057 | LATIN CAPITAL LETTER W
     58 |  00000058 | LATIN CAPITAL LETTER X
     59 |  00000059 | LATIN CAPITAL LETTER Y
     5A |  0000005A | LATIN CAPITAL LETTER Z
     5B |  0000005B | LEFT SQUARE BRACKET
     5C |  0000005C | REVERSE SOLIDUS
     5D |  0000005D | RIGHT SQUARE BRACKET
     5E |  0000005E | CIRCUMFLEX ACCENT
     5F |  0000005F | LOW LINE
     60 |  00000060 | GRAVE ACCENT
     61 |  00000061 | LATIN SMALL LETTER A
     62 |  00000062 | LATIN SMALL LETTER B
     63 |  00000063 | LATIN SMALL LETTER C
     64 |  00000064 | LATIN SMALL LETTER D
     65 |  00000065 | LATIN SMALL LETTER E
     66 |  00000066 | LATIN SMALL LETTER F
     67 |  00000067 | LATIN SMALL LETTER G
     68 |  00000068 | LATIN SMALL LETTER H
     69 |  00000069 | LATIN SMALL LETTER I
     6A |  0000006A | LATIN SMALL LETTER J
     6B |  0000006B | LATIN SMALL LETTER K
     6C |  0000006C | LATIN SMALL LETTER L
     6D |  0000006D | LATIN SMALL LETTER M
     6E |  0000006E | LATIN SMALL LETTER N
     6F |  0000006F | LATIN SMALL LETTER O
     70 |  00000070 | LATIN SMALL LETTER P
     71 |  00000071 | LATIN SMALL LETTER Q
     72 |  00000072 | LATIN SMALL LETTER R
     73 |  00000073 | LATIN SMALL LETTER S
     74 |  00000074 | LATIN SMALL LETTER T
     75 |  00000075 | LATIN SMALL LETTER U
     76 |  00000076 | LATIN SMALL LETTER V
     77 |  00000077 | LATIN SMALL LETTER W
     78 |  00000078 | LATIN SMALL LETTER X
     79 |  00000079 | LATIN SMALL LETTER Y
     7A |  0000007A | LATIN SMALL LETTER Z
     7B |  0000007B | LEFT CURLY BRACKET
     7C |  0000007C | VERTICAL LINE
     7D |  0000007D | RIGHT CURLY BRACKET
     7E |  0000007E | TILDE
     7F |  0000007F | DELETE (DEL)
     C0 |  0000044E | CYRILLIC SMALL LETTER YU
     C1 |  00000430 | CYRILLIC SMALL LETTER A
     C2 |  00000431 | CYRILLIC SMALL LETTER BE
     C3 |  00000446 | CYRILLIC SMALL LETTER TSE
     C4 |  00000434 | CYRILLIC SMALL LETTER DE
     C5 |  00000435 | CYRILLIC SMALL LETTER IE
     C6 |  00000444 | CYRILLIC SMALL LETTER EF
     C7 |  00000433 | CYRILLIC SMALL LETTER GHE
     C8 |  00000445 | CYRILLIC SMALL LETTER HA
     C9 |  00000438 | CYRILLIC SMALL LETTER I
     CA |  00000439 | CYRILLIC SMALL LETTER SHORT I
     CB |  0000043A | CYRILLIC SMALL LETTER KA
     CC |  0000043B | CYRILLIC SMALL LETTER EL
     CD |  0000043C | CYRILLIC SMALL LETTER EM
     CE |  0000043D | CYRILLIC SMALL LETTER EN
     CF |  0000043E | CYRILLIC SMALL LETTER O
     D0 |  0000043F | CYRILLIC SMALL LETTER PE
     D1 |  0000044F | CYRILLIC SMALL LETTER YA
     D2 |  00000440 | CYRILLIC SMALL LETTER ER
     D3 |  00000441 | CYRILLIC SMALL LETTER ES
     D4 |  00000442 | CYRILLIC SMALL LETTER TE
     D5 |  00000443 | CYRILLIC SMALL LETTER U
     D6 |  00000436 | CYRILLIC SMALL LETTER ZHE
     D7 |  00000432 | CYRILLIC SMALL LETTER VE
     D8 |  0000044C | CYRILLIC SMALL LETTER SOFT SIGN
     D9 |  0000044B | CYRILLIC SMALL LETTER YERU
     DA |  00000437 | CYRILLIC SMALL LETTER ZE
     DB |  00000448 | CYRILLIC SMALL LETTER SHA
     DC |  0000044D | CYRILLIC SMALL LETTER E
     DD |  00000449 | CYRILLIC SMALL LETTER SHCHA
     DE |  00000447 | CYRILLIC SMALL LETTER CHE
     DF |  0000044A | CYRILLIC SMALL LETTER HARD SIGN
     E0 |  0000042E | CYRILLIC CAPITAL LETTER YU
     E1 |  00000410 | CYRILLIC CAPITAL LETTER A
     E2 |  00000411 | CYRILLIC CAPITAL LETTER BE
     E3 |  00000426 | CYRILLIC CAPITAL LETTER TSE
     E4 |  00000414 | CYRILLIC CAPITAL LETTER DE
     E5 |  00000415 | CYRILLIC CAPITAL LETTER IE
     E6 |  00000424 | CYRILLIC CAPITAL LETTER EF
     E7 |  00000413 | CYRILLIC CAPITAL LETTER GHE
     E8 |  00000425 | CYRILLIC CAPITAL LETTER HA
     E9 |  00000418 | CYRILLIC CAPITAL LETTER I
     EA |  00000419 | CYRILLIC CAPITAL LETTER SHORT I
     EB |  0000041A | CYRILLIC CAPITAL LETTER KA
     EC |  0000041B | CYRILLIC CAPITAL LETTER EL
     ED |  0000041C | CYRILLIC CAPITAL LETTER EM
     EE |  0000041D | CYRILLIC CAPITAL LETTER EN
     EF |  0000041E | CYRILLIC CAPITAL LETTER O
     F0 |  0000041F | CYRILLIC CAPITAL LETTER PE
     F1 |  0000042F | CYRILLIC CAPITAL LETTER YA
     F2 |  00000420 | CYRILLIC CAPITAL LETTER ER
     F3 |  00000421 | CYRILLIC CAPITAL LETTER ES
     F4 |  00000422 | CYRILLIC CAPITAL LETTER TE
     F5 |  00000423 | CYRILLIC CAPITAL LETTER U
     F6 |  00000416 | CYRILLIC CAPITAL LETTER ZHE
     F7 |  00000412 | CYRILLIC CAPITAL LETTER VE
     F8 |  0000042C | CYRILLIC CAPITAL LETTER SOFT SIGN
     F9 |  0000042B | CYRILLIC CAPITAL LETTER YERU
     FA |  00000417 | CYRILLIC CAPITAL LETTER ZE
     FB |  00000428 | CYRILLIC CAPITAL LETTER SHA
     FC |  0000042D | CYRILLIC CAPITAL LETTER E
     FD |  00000429 | CYRILLIC CAPITAL LETTER SHCHA
     FE |  00000427 | CYRILLIC CAPITAL LETTER CHE
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/LATIN_GREEK.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for LATIN-GREEK.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::LATIN_GREEK;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x0004,
     0x0005,
     0x0006,
     0x0007,
     0x0008,
     0x0009,
     0x000a,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x0014,
     0x0015,
     0x0016,
     0x0017,
     0x0018,
     0x0019,
     0x001a,
     0x001b,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0020,
     0x0021,
     0x0022,
     0x00a3,
     0x0024,
     0x0025,
     0x0026,
     0x0027,
     0x0028,
     0x0029,
     0x002a,
     0x002b,
     0x002c,
     0x002d,
     0x002e,
     0x002f,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x003a,
     0x003b,
     0x003c,
     0x003d,
     0x003e,
     0x003f,
     0x0040,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x005b,
     0x005c,
     0x005d,
     0x005e,
     0x005f,
     0x0060,
     0x0391,
     0x0392,
     0x03a8,
     0x0394,
     0x0395,
     0x03a6,
     0x0393,
     0x0397,
     0x0399,
     0x039e,
     0x039a,
     0x039b,
     0x039c,
     0x039d,
     0x039f,
     0x03a0,
     0xfffd,
     0x03a1,
     0x03a3,
     0x03a4,
     0x0398,
     0x03a9,
     0x00b7,
     0x03a7,
     0x03a5,
     0x0396,
     0x007b,
     0x007c,
     0x007d,
     0x00a8,
     0x007f,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\x04",
     "\x05",
     "\x06",
     "\x07",
     "\x08",
     "\x09",
     "\x0a",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\x14",
     "\x15",
     "\x16",
     "\x17",
     "\x18",
     "\x19",
     "\x1a",
     "\x1b",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\x20",
     "\x21",
     "\x22",
     "\xc2\xa3",
     "\x24",
     "\x25",
     "\x26",
     "\x27",
     "\x28",
     "\x29",
     "\x2a",
     "\x2b",
     "\x2c",
     "\x2d",
     "\x2e",
     "\x2f",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\x3a",
     "\x3b",
     "\x3c",
     "\x3d",
     "\x3e",
     "\x3f",
     "\x40",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\x5b",
     "\x5c",
     "\x5d",
     "\x5e",
     "\x5f",
     "\x60",
     "\xce\x91",
     "\xce\x92",
     "\xce\xa8",
     "\xce\x94",
     "\xce\x95",
     "\xce\xa6",
     "\xce\x93",
     "\xce\x97",
     "\xce\x99",
     "\xce\x9e",
     "\xce\x9a",
     "\xce\x9b",
     "\xce\x9c",
     "\xce\x9d",
     "\xce\x9f",
     "\xce\xa0",
     "\xef\xbf\xbd",
     "\xce\xa1",
     "\xce\xa3",
     "\xce\xa4",
     "\xce\x98",
     "\xce\xa9",
     "\xc2\xb7",
     "\xce\xa7",
     "\xce\xa5",
     "\xce\x96",
     "\x7b",
     "\x7c",
     "\x7d",
     "\xc2\xa8",
     "\x7f",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x04",
     0x00000005 => "\x05",
     0x00000006 => "\x06",
     0x00000007 => "\x07",
     0x00000008 => "\x08",
     0x00000009 => "\x09",
     0x0000000a => "\x0a",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x14",
     0x00000015 => "\x15",
     0x00000016 => "\x16",
     0x00000017 => "\x17",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x1a",
     0x0000001b => "\x1b",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x20",
     0x00000021 => "\x21",
     0x00000022 => "\x22",
     0x00000024 => "\x24",
     0x00000025 => "\x25",
     0x00000026 => "\x26",
     0x00000027 => "\x27",
     0x00000028 => "\x28",
     0x00000029 => "\x29",
     0x0000002a => "\x2a",
     0x0000002b => "\x2b",
     0x0000002c => "\x2c",
     0x0000002d => "\x2d",
     0x0000002e => "\x2e",
     0x0000002f => "\x2f",
     0x00000030 => "\x30",
     0x00000031 => "\x31",
     0x00000032 => "\x32",
     0x00000033 => "\x33",
     0x00000034 => "\x34",
     0x00000035 => "\x35",
     0x00000036 => "\x36",
     0x00000037 => "\x37",
     0x00000038 => "\x38",
     0x00000039 => "\x39",
     0x0000003a => "\x3a",
     0x0000003b => "\x3b",
     0x0000003c => "\x3c",
     0x0000003d => "\x3d",
     0x0000003e => "\x3e",
     0x0000003f => "\x3f",
     0x00000040 => "\x40",
     0x00000041 => "\x41",
     0x00000042 => "\x42",
     0x00000043 => "\x43",
     0x00000044 => "\x44",
     0x00000045 => "\x45",
     0x00000046 => "\x46",
     0x00000047 => "\x47",
     0x00000048 => "\x48",
     0x00000049 => "\x49",
     0x0000004a => "\x4a",
     0x0000004b => "\x4b",
     0x0000004c => "\x4c",
     0x0000004d => "\x4d",
     0x0000004e => "\x4e",
     0x0000004f => "\x4f",
     0x00000050 => "\x50",
     0x00000051 => "\x51",
     0x00000052 => "\x52",
     0x00000053 => "\x53",
     0x00000054 => "\x54",
     0x00000055 => "\x55",
     0x00000056 => "\x56",
     0x00000057 => "\x57",
     0x00000058 => "\x58",
     0x00000059 => "\x59",
     0x0000005a => "\x5a",
     0x0000005b => "\x5b",
     0x0000005c => "\x5c",
     0x0000005d => "\x5d",
     0x0000005e => "\x5e",
     0x0000005f => "\x5f",
     0x00000060 => "\x60",
     0x0000007b => "\x7b",
     0x0000007c => "\x7c",
     0x0000007d => "\x7d",
     0x0000007f => "\x7f",
     0x000000a3 => "\x23",
     0x000000a8 => "\x7e",
     0x000000b7 => "\x77",
     0x00000391 => "\x61",
     0x00000392 => "\x62",
     0x00000393 => "\x67",
     0x00000394 => "\x64",
     0x00000395 => "\x65",
     0x00000396 => "\x7a",
     0x00000397 => "\x68",
     0x00000398 => "\x75",
     0x00000399 => "\x69",
     0x0000039a => "\x6b",
     0x0000039b => "\x6c",
     0x0000039c => "\x6d",
     0x0000039d => "\x6e",
     0x0000039e => "\x6a",
     0x0000039f => "\x6f",
     0x000003a0 => "\x70",
     0x000003a1 => "\x72",
     0x000003a3 => "\x73",
     0x000003a4 => "\x74",
     0x000003a5 => "\x79",
     0x000003a6 => "\x66",
     0x000003a7 => "\x78",
     0x000003a8 => "\x63",
     0x000003a9 => "\x76",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::LATIN_GREEK - Conversion routines for LATIN_GREEK
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for LATIN-GREEK.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
   source: ECMA registry
  alias ISO-IR-19
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  00000004 | END OF TRANSMISSION (EOT)
     05 |  00000005 | ENQUIRY (ENQ)
     06 |  00000006 | ACKNOWLEDGE (ACK)
     07 |  00000007 | BELL (BEL)
     08 |  00000008 | BACKSPACE (BS)
     09 |  00000009 | CHARACTER TABULATION (HT)
     0A |  0000000A | LINE FEED (LF)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  00000014 | DEVICE CONTROL FOUR (DC4)
     15 |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     16 |  00000016 | SYNCHRONOUS IDLE (SYN)
     17 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  0000001A | SUBSTITUTE (SUB)
     1B |  0000001B | ESCAPE (ESC)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000020 | SPACE
     21 |  00000021 | EXCLAMATION MARK
     22 |  00000022 | QUOTATION MARK
     23 |  000000A3 | POUND SIGN
     24 |  00000024 | DOLLAR SIGN
     25 |  00000025 | PERCENT SIGN
     26 |  00000026 | AMPERSAND
     27 |  00000027 | APOSTROPHE
     28 |  00000028 | LEFT PARENTHESIS
     29 |  00000029 | RIGHT PARENTHESIS
     2A |  0000002A | ASTERISK
     2B |  0000002B | PLUS SIGN
     2C |  0000002C | COMMA
     2D |  0000002D | HYPHEN-MINUS
     2E |  0000002E | FULL STOP
     2F |  0000002F | SOLIDUS
     30 |  00000030 | DIGIT ZERO
     31 |  00000031 | DIGIT ONE
     32 |  00000032 | DIGIT TWO
     33 |  00000033 | DIGIT THREE
     34 |  00000034 | DIGIT FOUR
     35 |  00000035 | DIGIT FIVE
     36 |  00000036 | DIGIT SIX
     37 |  00000037 | DIGIT SEVEN
     38 |  00000038 | DIGIT EIGHT
     39 |  00000039 | DIGIT NINE
     3A |  0000003A | COLON
     3B |  0000003B | SEMICOLON
     3C |  0000003C | LESS-THAN SIGN
     3D |  0000003D | EQUALS SIGN
     3E |  0000003E | GREATER-THAN SIGN
     3F |  0000003F | QUESTION MARK
     40 |  00000040 | COMMERCIAL AT
     41 |  00000041 | LATIN CAPITAL LETTER A
     42 |  00000042 | LATIN CAPITAL LETTER B
     43 |  00000043 | LATIN CAPITAL LETTER C
     44 |  00000044 | LATIN CAPITAL LETTER D
     45 |  00000045 | LATIN CAPITAL LETTER E
     46 |  00000046 | LATIN CAPITAL LETTER F
     47 |  00000047 | LATIN CAPITAL LETTER G
     48 |  00000048 | LATIN CAPITAL LETTER H
     49 |  00000049 | LATIN CAPITAL LETTER I
     4A |  0000004A | LATIN CAPITAL LETTER J
     4B |  0000004B | LATIN CAPITAL LETTER K
     4C |  0000004C | LATIN CAPITAL LETTER L
     4D |  0000004D | LATIN CAPITAL LETTER M
     4E |  0000004E | LATIN CAPITAL LETTER N
     4F |  0000004F | LATIN CAPITAL LETTER O
     50 |  00000050 | LATIN CAPITAL LETTER P
     51 |  00000051 | LATIN CAPITAL LETTER Q
     52 |  00000052 | LATIN CAPITAL LETTER R
     53 |  00000053 | LATIN CAPITAL LETTER S
     54 |  00000054 | LATIN CAPITAL LETTER T
     55 |  00000055 | LATIN CAPITAL LETTER U
     56 |  00000056 | LATIN CAPITAL LETTER V
     57 |  00000057 | LATIN CAPITAL LETTER W
     58 |  00000058 | LATIN CAPITAL LETTER X
     59 |  00000059 | LATIN CAPITAL LETTER Y
     5A |  0000005A | LATIN CAPITAL LETTER Z
     5B |  0000005B | LEFT SQUARE BRACKET
     5C |  0000005C | REVERSE SOLIDUS
     5D |  0000005D | RIGHT SQUARE BRACKET
     5E |  0000005E | CIRCUMFLEX ACCENT
     5F |  0000005F | LOW LINE
     60 |  00000060 | GRAVE ACCENT
     61 |  00000391 | GREEK CAPITAL LETTER ALPHA
     62 |  00000392 | GREEK CAPITAL LETTER BETA
     63 |  000003A8 | GREEK CAPITAL LETTER PSI
     64 |  00000394 | GREEK CAPITAL LETTER DELTA
     65 |  00000395 | GREEK CAPITAL LETTER EPSILON
     66 |  000003A6 | GREEK CAPITAL LETTER PHI
     67 |  00000393 | GREEK CAPITAL LETTER GAMMA
     68 |  00000397 | GREEK CAPITAL LETTER ETA
     69 |  00000399 | GREEK CAPITAL LETTER IOTA
     6A |  0000039E | GREEK CAPITAL LETTER XI
     6B |  0000039A | GREEK CAPITAL LETTER KAPPA
     6C |  0000039B | GREEK CAPITAL LETTER LAMDA
     6D |  0000039C | GREEK CAPITAL LETTER MU
     6E |  0000039D | GREEK CAPITAL LETTER NU
     6F |  0000039F | GREEK CAPITAL LETTER OMICRON
     70 |  000003A0 | GREEK CAPITAL LETTER PI
     72 |  000003A1 | GREEK CAPITAL LETTER RHO
     73 |  000003A3 | GREEK CAPITAL LETTER SIGMA
     74 |  000003A4 | GREEK CAPITAL LETTER TAU
     75 |  00000398 | GREEK CAPITAL LETTER THETA
     76 |  000003A9 | GREEK CAPITAL LETTER OMEGA
     77 |  000000B7 | MIDDLE DOT
     78 |  000003A7 | GREEK CAPITAL LETTER CHI
     79 |  000003A5 | GREEK CAPITAL LETTER UPSILON
     7A |  00000396 | GREEK CAPITAL LETTER ZETA
     7B |  0000007B | LEFT CURLY BRACKET
     7C |  0000007C | VERTICAL LINE
     7D |  0000007D | RIGHT CURLY BRACKET
     7E |  000000A8 | DIAERESIS
     7F |  0000007F | DELETE (DEL)
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/LATIN_GREEK_1.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for LATIN-GREEK-1.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::LATIN_GREEK_1;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x0004,
     0x0005,
     0x0006,
     0x0007,
     0x0008,
     0x0009,
     0x000a,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x0014,
     0x0015,
     0x0016,
     0x0017,
     0x0018,
     0x0019,
     0x001a,
     0x001b,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0020,
     0x039e,
     0x0022,
     0x0393,
     0x00a4,
     0x0025,
     0x0026,
     0x0027,
     0x0028,
     0x0029,
     0x002a,
     0x002b,
     0x002c,
     0x002d,
     0x002e,
     0x002f,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x03a8,
     0x003b,
     0x003c,
     0x003d,
     0x003e,
     0x03a0,
     0x0394,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x03a9,
     0x0398,
     0x03a6,
     0x039b,
     0x03a3,
     0x0060,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x007b,
     0x007c,
     0x007d,
     0x203e,
     0x007f,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\x04",
     "\x05",
     "\x06",
     "\x07",
     "\x08",
     "\x09",
     "\x0a",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\x14",
     "\x15",
     "\x16",
     "\x17",
     "\x18",
     "\x19",
     "\x1a",
     "\x1b",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\x20",
     "\xce\x9e",
     "\x22",
     "\xce\x93",
     "\xc2\xa4",
     "\x25",
     "\x26",
     "\x27",
     "\x28",
     "\x29",
     "\x2a",
     "\x2b",
     "\x2c",
     "\x2d",
     "\x2e",
     "\x2f",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\xce\xa8",
     "\x3b",
     "\x3c",
     "\x3d",
     "\x3e",
     "\xce\xa0",
     "\xce\x94",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\xce\xa9",
     "\xce\x98",
     "\xce\xa6",
     "\xce\x9b",
     "\xce\xa3",
     "\x60",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\x7b",
     "\x7c",
     "\x7d",
     "\xe2\x80\xbe",
     "\x7f",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x04",
     0x00000005 => "\x05",
     0x00000006 => "\x06",
     0x00000007 => "\x07",
     0x00000008 => "\x08",
     0x00000009 => "\x09",
     0x0000000a => "\x0a",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x14",
     0x00000015 => "\x15",
     0x00000016 => "\x16",
     0x00000017 => "\x17",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x1a",
     0x0000001b => "\x1b",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x20",
     0x00000022 => "\x22",
     0x00000025 => "\x25",
     0x00000026 => "\x26",
     0x00000027 => "\x27",
     0x00000028 => "\x28",
     0x00000029 => "\x29",
     0x0000002a => "\x2a",
     0x0000002b => "\x2b",
     0x0000002c => "\x2c",
     0x0000002d => "\x2d",
     0x0000002e => "\x2e",
     0x0000002f => "\x2f",
     0x00000030 => "\x30",
     0x00000031 => "\x31",
     0x00000032 => "\x32",
     0x00000033 => "\x33",
     0x00000034 => "\x34",
     0x00000035 => "\x35",
     0x00000036 => "\x36",
     0x00000037 => "\x37",
     0x00000038 => "\x38",
     0x00000039 => "\x39",
     0x0000003b => "\x3b",
     0x0000003c => "\x3c",
     0x0000003d => "\x3d",
     0x0000003e => "\x3e",
     0x00000041 => "\x41",
     0x00000042 => "\x42",
     0x00000043 => "\x43",
     0x00000044 => "\x44",
     0x00000045 => "\x45",
     0x00000046 => "\x46",
     0x00000047 => "\x47",
     0x00000048 => "\x48",
     0x00000049 => "\x49",
     0x0000004a => "\x4a",
     0x0000004b => "\x4b",
     0x0000004c => "\x4c",
     0x0000004d => "\x4d",
     0x0000004e => "\x4e",
     0x0000004f => "\x4f",
     0x00000050 => "\x50",
     0x00000051 => "\x51",
     0x00000052 => "\x52",
     0x00000053 => "\x53",
     0x00000054 => "\x54",
     0x00000055 => "\x55",
     0x00000056 => "\x56",
     0x00000057 => "\x57",
     0x00000058 => "\x58",
     0x00000059 => "\x59",
     0x0000005a => "\x5a",
     0x00000060 => "\x60",
     0x00000061 => "\x61",
     0x00000062 => "\x62",
     0x00000063 => "\x63",
     0x00000064 => "\x64",
     0x00000065 => "\x65",
     0x00000066 => "\x66",
     0x00000067 => "\x67",
     0x00000068 => "\x68",
     0x00000069 => "\x69",
     0x0000006a => "\x6a",
     0x0000006b => "\x6b",
     0x0000006c => "\x6c",
     0x0000006d => "\x6d",
     0x0000006e => "\x6e",
     0x0000006f => "\x6f",
     0x00000070 => "\x70",
     0x00000071 => "\x71",
     0x00000072 => "\x72",
     0x00000073 => "\x73",
     0x00000074 => "\x74",
     0x00000075 => "\x75",
     0x00000076 => "\x76",
     0x00000077 => "\x77",
     0x00000078 => "\x78",
     0x00000079 => "\x79",
     0x0000007a => "\x7a",
     0x0000007b => "\x7b",
     0x0000007c => "\x7c",
     0x0000007d => "\x7d",
     0x0000007f => "\x7f",
     0x000000a4 => "\x24",
     0x00000393 => "\x23",
     0x00000394 => "\x40",
     0x00000398 => "\x5c",
     0x0000039b => "\x5e",
     0x0000039e => "\x21",
     0x000003a0 => "\x3f",
     0x000003a3 => "\x5f",
     0x000003a6 => "\x5d",
     0x000003a8 => "\x3a",
     0x000003a9 => "\x5b",
     0x0000203e => "\x7e",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::LATIN_GREEK_1 - Conversion routines for LATIN_GREEK_1
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for LATIN-GREEK-1.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
   source: ECMA registry
  alias ISO-IR-27
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  00000004 | END OF TRANSMISSION (EOT)
     05 |  00000005 | ENQUIRY (ENQ)
     06 |  00000006 | ACKNOWLEDGE (ACK)
     07 |  00000007 | BELL (BEL)
     08 |  00000008 | BACKSPACE (BS)
     09 |  00000009 | CHARACTER TABULATION (HT)
     0A |  0000000A | LINE FEED (LF)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  00000014 | DEVICE CONTROL FOUR (DC4)
     15 |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     16 |  00000016 | SYNCHRONOUS IDLE (SYN)
     17 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  0000001A | SUBSTITUTE (SUB)
     1B |  0000001B | ESCAPE (ESC)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000020 | SPACE
     21 |  0000039E | GREEK CAPITAL LETTER XI
     22 |  00000022 | QUOTATION MARK
     23 |  00000393 | GREEK CAPITAL LETTER GAMMA
     24 |  000000A4 | CURRENCY SIGN
     25 |  00000025 | PERCENT SIGN
     26 |  00000026 | AMPERSAND
     27 |  00000027 | APOSTROPHE
     28 |  00000028 | LEFT PARENTHESIS
     29 |  00000029 | RIGHT PARENTHESIS
     2A |  0000002A | ASTERISK
     2B |  0000002B | PLUS SIGN
     2C |  0000002C | COMMA
     2D |  0000002D | HYPHEN-MINUS
     2E |  0000002E | FULL STOP
     2F |  0000002F | SOLIDUS
     30 |  00000030 | DIGIT ZERO
     31 |  00000031 | DIGIT ONE
     32 |  00000032 | DIGIT TWO
     33 |  00000033 | DIGIT THREE
     34 |  00000034 | DIGIT FOUR
     35 |  00000035 | DIGIT FIVE
     36 |  00000036 | DIGIT SIX
     37 |  00000037 | DIGIT SEVEN
     38 |  00000038 | DIGIT EIGHT
     39 |  00000039 | DIGIT NINE
     3A |  000003A8 | GREEK CAPITAL LETTER PSI
     3B |  0000003B | SEMICOLON
     3C |  0000003C | LESS-THAN SIGN
     3D |  0000003D | EQUALS SIGN
     3E |  0000003E | GREATER-THAN SIGN
     3F |  000003A0 | GREEK CAPITAL LETTER PI
     40 |  00000394 | GREEK CAPITAL LETTER DELTA
     41 |  00000041 | LATIN CAPITAL LETTER A
     42 |  00000042 | LATIN CAPITAL LETTER B
     43 |  00000043 | LATIN CAPITAL LETTER C
     44 |  00000044 | LATIN CAPITAL LETTER D
     45 |  00000045 | LATIN CAPITAL LETTER E
     46 |  00000046 | LATIN CAPITAL LETTER F
     47 |  00000047 | LATIN CAPITAL LETTER G
     48 |  00000048 | LATIN CAPITAL LETTER H
     49 |  00000049 | LATIN CAPITAL LETTER I
     4A |  0000004A | LATIN CAPITAL LETTER J
     4B |  0000004B | LATIN CAPITAL LETTER K
     4C |  0000004C | LATIN CAPITAL LETTER L
     4D |  0000004D | LATIN CAPITAL LETTER M
     4E |  0000004E | LATIN CAPITAL LETTER N
     4F |  0000004F | LATIN CAPITAL LETTER O
     50 |  00000050 | LATIN CAPITAL LETTER P
     51 |  00000051 | LATIN CAPITAL LETTER Q
     52 |  00000052 | LATIN CAPITAL LETTER R
     53 |  00000053 | LATIN CAPITAL LETTER S
     54 |  00000054 | LATIN CAPITAL LETTER T
     55 |  00000055 | LATIN CAPITAL LETTER U
     56 |  00000056 | LATIN CAPITAL LETTER V
     57 |  00000057 | LATIN CAPITAL LETTER W
     58 |  00000058 | LATIN CAPITAL LETTER X
     59 |  00000059 | LATIN CAPITAL LETTER Y
     5A |  0000005A | LATIN CAPITAL LETTER Z
     5B |  000003A9 | GREEK CAPITAL LETTER OMEGA
     5C |  00000398 | GREEK CAPITAL LETTER THETA
     5D |  000003A6 | GREEK CAPITAL LETTER PHI
     5E |  0000039B | GREEK CAPITAL LETTER LAMDA
     5F |  000003A3 | GREEK CAPITAL LETTER SIGMA
     60 |  00000060 | GRAVE ACCENT
     61 |  00000061 | LATIN SMALL LETTER A
     62 |  00000062 | LATIN SMALL LETTER B
     63 |  00000063 | LATIN SMALL LETTER C
     64 |  00000064 | LATIN SMALL LETTER D
     65 |  00000065 | LATIN SMALL LETTER E
     66 |  00000066 | LATIN SMALL LETTER F
     67 |  00000067 | LATIN SMALL LETTER G
     68 |  00000068 | LATIN SMALL LETTER H
     69 |  00000069 | LATIN SMALL LETTER I
     6A |  0000006A | LATIN SMALL LETTER J
     6B |  0000006B | LATIN SMALL LETTER K
     6C |  0000006C | LATIN SMALL LETTER L
     6D |  0000006D | LATIN SMALL LETTER M
     6E |  0000006E | LATIN SMALL LETTER N
     6F |  0000006F | LATIN SMALL LETTER O
     70 |  00000070 | LATIN SMALL LETTER P
     71 |  00000071 | LATIN SMALL LETTER Q
     72 |  00000072 | LATIN SMALL LETTER R
     73 |  00000073 | LATIN SMALL LETTER S
     74 |  00000074 | LATIN SMALL LETTER T
     75 |  00000075 | LATIN SMALL LETTER U
     76 |  00000076 | LATIN SMALL LETTER V
     77 |  00000077 | LATIN SMALL LETTER W
     78 |  00000078 | LATIN SMALL LETTER X
     79 |  00000079 | LATIN SMALL LETTER Y
     7A |  0000007A | LATIN SMALL LETTER Z
     7B |  0000007B | LEFT CURLY BRACKET
     7C |  0000007C | VERTICAL LINE
     7D |  0000007D | RIGHT CURLY BRACKET
     7E |  0000203E | OVERLINE
     7F |  0000007F | DELETE (DEL)
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/MACARABIC.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for MACARABIC.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::MACARABIC;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x0004,
     0x0005,
     0x0006,
     0x0007,
     0x0008,
     0x0009,
     0x000a,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x0014,
     0x0015,
     0x0016,
     0x0017,
     0x0018,
     0x0019,
     0x001a,
     0x001b,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0020,
     0x0021,
     0x0022,
     0x0023,
     0x0024,
     0x0025,
     0x0026,
     0x0027,
     0x0028,
     0x0029,
     0x002a,
     0x002b,
     0x002c,
     0x002d,
     0x002e,
     0x002f,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x003a,
     0x003b,
     0x003c,
     0x003d,
     0x003e,
     0x003f,
     0x0040,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x005b,
     0x005c,
     0x005d,
     0x005e,
     0x005f,
     0x0060,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x007b,
     0x007c,
     0x007d,
     0x007e,
     0x007f,
     0x00c4,
     0x00a0,
     0x00c7,
     0x00c9,
     0x00d1,
     0x00d6,
     0x00dc,
     0x00e1,
     0x00e0,
     0x00e2,
     0x00e4,
     0x06ba,
     0x00ab,
     0x00e7,
     0x00e9,
     0x00e8,
     0x00ea,
     0x00eb,
     0x00ed,
     0x2026,
     0x00ee,
     0x00ef,
     0x00f1,
     0x00f3,
     0x00bb,
     0x00f4,
     0x00f6,
     0x00f7,
     0x00fa,
     0x00f9,
     0x00fb,
     0x00fc,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x066a,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x060c,
     0xfffd,
     0xfffd,
     0xfffd,
     0x0660,
     0x0661,
     0x0662,
     0x0663,
     0x0664,
     0x0665,
     0x0666,
     0x0667,
     0x0668,
     0x0669,
     0xfffd,
     0x061b,
     0xfffd,
     0xfffd,
     0xfffd,
     0x061f,
     0x066d,
     0x0621,
     0x0622,
     0x0623,
     0x0624,
     0x0625,
     0x0626,
     0x0627,
     0x0628,
     0x0629,
     0x062a,
     0x062b,
     0x062c,
     0x062d,
     0x062e,
     0x062f,
     0x0630,
     0x0631,
     0x0632,
     0x0633,
     0x0634,
     0x0635,
     0x0636,
     0x0637,
     0x0638,
     0x0639,
     0x063a,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x0640,
     0x0641,
     0x0642,
     0x0643,
     0x0644,
     0x0645,
     0x0646,
     0x0647,
     0x0648,
     0x0649,
     0x064a,
     0x064b,
     0x064c,
     0x064d,
     0x064e,
     0x064f,
     0x0650,
     0x0651,
     0x0652,
     0x067e,
     0x0679,
     0x0686,
     0x06d5,
     0x06a4,
     0x06af,
     0x0688,
     0x0691,
     0xfffd,
     0xfffd,
     0xfffd,
     0x0698,
     0x06d2,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\x04",
     "\x05",
     "\x06",
     "\x07",
     "\x08",
     "\x09",
     "\x0a",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\x14",
     "\x15",
     "\x16",
     "\x17",
     "\x18",
     "\x19",
     "\x1a",
     "\x1b",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\x20",
     "\x21",
     "\x22",
     "\x23",
     "\x24",
     "\x25",
     "\x26",
     "\x27",
     "\x28",
     "\x29",
     "\x2a",
     "\x2b",
     "\x2c",
     "\x2d",
     "\x2e",
     "\x2f",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\x3a",
     "\x3b",
     "\x3c",
     "\x3d",
     "\x3e",
     "\x3f",
     "\x40",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\x5b",
     "\x5c",
     "\x5d",
     "\x5e",
     "\x5f",
     "\x60",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\x7b",
     "\x7c",
     "\x7d",
     "\x7e",
     "\x7f",
     "\xc3\x84",
     "\xc2\xa0",
     "\xc3\x87",
     "\xc3\x89",
     "\xc3\x91",
     "\xc3\x96",
     "\xc3\x9c",
     "\xc3\xa1",
     "\xc3\xa0",
     "\xc3\xa2",
     "\xc3\xa4",
     "\xda\xba",
     "\xc2\xab",
     "\xc3\xa7",
     "\xc3\xa9",
     "\xc3\xa8",
     "\xc3\xaa",
     "\xc3\xab",
     "\xc3\xad",
     "\xe2\x80\xa6",
     "\xc3\xae",
     "\xc3\xaf",
     "\xc3\xb1",
     "\xc3\xb3",
     "\xc2\xbb",
     "\xc3\xb4",
     "\xc3\xb6",
     "\xc3\xb7",
     "\xc3\xba",
     "\xc3\xb9",
     "\xc3\xbb",
     "\xc3\xbc",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xd9\xaa",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xd8\x8c",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xd9\xa0",
     "\xd9\xa1",
     "\xd9\xa2",
     "\xd9\xa3",
     "\xd9\xa4",
     "\xd9\xa5",
     "\xd9\xa6",
     "\xd9\xa7",
     "\xd9\xa8",
     "\xd9\xa9",
     "\xef\xbf\xbd",
     "\xd8\x9b",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xd8\x9f",
     "\xd9\xad",
     "\xd8\xa1",
     "\xd8\xa2",
     "\xd8\xa3",
     "\xd8\xa4",
     "\xd8\xa5",
     "\xd8\xa6",
     "\xd8\xa7",
     "\xd8\xa8",
     "\xd8\xa9",
     "\xd8\xaa",
     "\xd8\xab",
     "\xd8\xac",
     "\xd8\xad",
     "\xd8\xae",
     "\xd8\xaf",
     "\xd8\xb0",
     "\xd8\xb1",
     "\xd8\xb2",
     "\xd8\xb3",
     "\xd8\xb4",
     "\xd8\xb5",
     "\xd8\xb6",
     "\xd8\xb7",
     "\xd8\xb8",
     "\xd8\xb9",
     "\xd8\xba",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xd9\x80",
     "\xd9\x81",
     "\xd9\x82",
     "\xd9\x83",
     "\xd9\x84",
     "\xd9\x85",
     "\xd9\x86",
     "\xd9\x87",
     "\xd9\x88",
     "\xd9\x89",
     "\xd9\x8a",
     "\xd9\x8b",
     "\xd9\x8c",
     "\xd9\x8d",
     "\xd9\x8e",
     "\xd9\x8f",
     "\xd9\x90",
     "\xd9\x91",
     "\xd9\x92",
     "\xd9\xbe",
     "\xd9\xb9",
     "\xda\x86",
     "\xdb\x95",
     "\xda\xa4",
     "\xda\xaf",
     "\xda\x88",
     "\xda\x91",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xda\x98",
     "\xdb\x92",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x04",
     0x00000005 => "\x05",
     0x00000006 => "\x06",
     0x00000007 => "\x07",
     0x00000008 => "\x08",
     0x00000009 => "\x09",
     0x0000000a => "\x0a",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x14",
     0x00000015 => "\x15",
     0x00000016 => "\x16",
     0x00000017 => "\x17",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x1a",
     0x0000001b => "\x1b",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x20",
     0x00000021 => "\x21",
     0x00000022 => "\x22",
     0x00000023 => "\x23",
     0x00000024 => "\x24",
     0x00000025 => "\x25",
     0x00000026 => "\x26",
     0x00000027 => "\x27",
     0x00000028 => "\x28",
     0x00000029 => "\x29",
     0x0000002a => "\x2a",
     0x0000002b => "\x2b",
     0x0000002c => "\x2c",
     0x0000002d => "\x2d",
     0x0000002e => "\x2e",
     0x0000002f => "\x2f",
     0x00000030 => "\x30",
     0x00000031 => "\x31",
     0x00000032 => "\x32",
     0x00000033 => "\x33",
     0x00000034 => "\x34",
     0x00000035 => "\x35",
     0x00000036 => "\x36",
     0x00000037 => "\x37",
     0x00000038 => "\x38",
     0x00000039 => "\x39",
     0x0000003a => "\x3a",
     0x0000003b => "\x3b",
     0x0000003c => "\x3c",
     0x0000003d => "\x3d",
     0x0000003e => "\x3e",
     0x0000003f => "\x3f",
     0x00000040 => "\x40",
     0x00000041 => "\x41",
     0x00000042 => "\x42",
     0x00000043 => "\x43",
     0x00000044 => "\x44",
     0x00000045 => "\x45",
     0x00000046 => "\x46",
     0x00000047 => "\x47",
     0x00000048 => "\x48",
     0x00000049 => "\x49",
     0x0000004a => "\x4a",
     0x0000004b => "\x4b",
     0x0000004c => "\x4c",
     0x0000004d => "\x4d",
     0x0000004e => "\x4e",
     0x0000004f => "\x4f",
     0x00000050 => "\x50",
     0x00000051 => "\x51",
     0x00000052 => "\x52",
     0x00000053 => "\x53",
     0x00000054 => "\x54",
     0x00000055 => "\x55",
     0x00000056 => "\x56",
     0x00000057 => "\x57",
     0x00000058 => "\x58",
     0x00000059 => "\x59",
     0x0000005a => "\x5a",
     0x0000005b => "\x5b",
     0x0000005c => "\x5c",
     0x0000005d => "\x5d",
     0x0000005e => "\x5e",
     0x0000005f => "\x5f",
     0x00000060 => "\x60",
     0x00000061 => "\x61",
     0x00000062 => "\x62",
     0x00000063 => "\x63",
     0x00000064 => "\x64",
     0x00000065 => "\x65",
     0x00000066 => "\x66",
     0x00000067 => "\x67",
     0x00000068 => "\x68",
     0x00000069 => "\x69",
     0x0000006a => "\x6a",
     0x0000006b => "\x6b",
     0x0000006c => "\x6c",
     0x0000006d => "\x6d",
     0x0000006e => "\x6e",
     0x0000006f => "\x6f",
     0x00000070 => "\x70",
     0x00000071 => "\x71",
     0x00000072 => "\x72",
     0x00000073 => "\x73",
     0x00000074 => "\x74",
     0x00000075 => "\x75",
     0x00000076 => "\x76",
     0x00000077 => "\x77",
     0x00000078 => "\x78",
     0x00000079 => "\x79",
     0x0000007a => "\x7a",
     0x0000007b => "\x7b",
     0x0000007c => "\x7c",
     0x0000007d => "\x7d",
     0x0000007e => "\x7e",
     0x0000007f => "\x7f",
     0x000000a0 => "\x81",
     0x000000ab => "\x8c",
     0x000000bb => "\x98",
     0x000000c4 => "\x80",
     0x000000c7 => "\x82",
     0x000000c9 => "\x83",
     0x000000d1 => "\x84",
     0x000000d6 => "\x85",
     0x000000dc => "\x86",
     0x000000e0 => "\x88",
     0x000000e1 => "\x87",
     0x000000e2 => "\x89",
     0x000000e4 => "\x8a",
     0x000000e7 => "\x8d",
     0x000000e8 => "\x8f",
     0x000000e9 => "\x8e",
     0x000000ea => "\x90",
     0x000000eb => "\x91",
     0x000000ed => "\x92",
     0x000000ee => "\x94",
     0x000000ef => "\x95",
     0x000000f1 => "\x96",
     0x000000f3 => "\x97",
     0x000000f4 => "\x99",
     0x000000f6 => "\x9a",
     0x000000f7 => "\x9b",
     0x000000f9 => "\x9d",
     0x000000fa => "\x9c",
     0x000000fb => "\x9e",
     0x000000fc => "\x9f",
     0x0000060c => "\xac",
     0x0000061b => "\xbb",
     0x0000061f => "\xbf",
     0x00000621 => "\xc1",
     0x00000622 => "\xc2",
     0x00000623 => "\xc3",
     0x00000624 => "\xc4",
     0x00000625 => "\xc5",
     0x00000626 => "\xc6",
     0x00000627 => "\xc7",
     0x00000628 => "\xc8",
     0x00000629 => "\xc9",
     0x0000062a => "\xca",
     0x0000062b => "\xcb",
     0x0000062c => "\xcc",
     0x0000062d => "\xcd",
     0x0000062e => "\xce",
     0x0000062f => "\xcf",
     0x00000630 => "\xd0",
     0x00000631 => "\xd1",
     0x00000632 => "\xd2",
     0x00000633 => "\xd3",
     0x00000634 => "\xd4",
     0x00000635 => "\xd5",
     0x00000636 => "\xd6",
     0x00000637 => "\xd7",
     0x00000638 => "\xd8",
     0x00000639 => "\xd9",
     0x0000063a => "\xda",
     0x00000640 => "\xe0",
     0x00000641 => "\xe1",
     0x00000642 => "\xe2",
     0x00000643 => "\xe3",
     0x00000644 => "\xe4",
     0x00000645 => "\xe5",
     0x00000646 => "\xe6",
     0x00000647 => "\xe7",
     0x00000648 => "\xe8",
     0x00000649 => "\xe9",
     0x0000064a => "\xea",
     0x0000064b => "\xeb",
     0x0000064c => "\xec",
     0x0000064d => "\xed",
     0x0000064e => "\xee",
     0x0000064f => "\xef",
     0x00000650 => "\xf0",
     0x00000651 => "\xf1",
     0x00000652 => "\xf2",
     0x00000660 => "\xb0",
     0x00000661 => "\xb1",
     0x00000662 => "\xb2",
     0x00000663 => "\xb3",
     0x00000664 => "\xb4",
     0x00000665 => "\xb5",
     0x00000666 => "\xb6",
     0x00000667 => "\xb7",
     0x00000668 => "\xb8",
     0x00000669 => "\xb9",
     0x0000066a => "\xa5",
     0x0000066d => "\xc0",
     0x00000679 => "\xf4",
     0x0000067e => "\xf3",
     0x00000686 => "\xf5",
     0x00000688 => "\xf9",
     0x00000691 => "\xfa",
     0x00000698 => "\xfe",
     0x000006a4 => "\xf7",
     0x000006af => "\xf8",
     0x000006ba => "\x8b",
     0x000006d2 => "\xff",
     0x000006d5 => "\xf6",
     0x00002026 => "\x93",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::MACARABIC - Conversion routines for MACARABIC
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for MACARABIC.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
 
  This charmap has been generated automatically from GNU libiconv
  conversions.
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  00000004 | END OF TRANSMISSION (EOT)
     05 |  00000005 | ENQUIRY (ENQ)
     06 |  00000006 | ACKNOWLEDGE (ACK)
     07 |  00000007 | BELL (BEL)
     08 |  00000008 | BACKSPACE (BS)
     09 |  00000009 | CHARACTER TABULATION (HT)
     0A |  0000000A | LINE FEED (LF)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  00000014 | DEVICE CONTROL FOUR (DC4)
     15 |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     16 |  00000016 | SYNCHRONOUS IDLE (SYN)
     17 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  0000001A | SUBSTITUTE (SUB)
     1B |  0000001B | ESCAPE (ESC)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000020 | SPACE
     21 |  00000021 | EXCLAMATION MARK
     22 |  00000022 | QUOTATION MARK
     23 |  00000023 | NUMBER SIGN
     24 |  00000024 | DOLLAR SIGN
     25 |  00000025 | PERCENT SIGN
     26 |  00000026 | AMPERSAND
     27 |  00000027 | APOSTROPHE
     28 |  00000028 | LEFT PARENTHESIS
     29 |  00000029 | RIGHT PARENTHESIS
     2A |  0000002A | ASTERISK
     2B |  0000002B | PLUS SIGN
     2C |  0000002C | COMMA
     2D |  0000002D | HYPHEN-MINUS
     2E |  0000002E | FULL STOP
     2F |  0000002F | SOLIDUS
     30 |  00000030 | DIGIT ZERO
     31 |  00000031 | DIGIT ONE
     32 |  00000032 | DIGIT TWO
     33 |  00000033 | DIGIT THREE
     34 |  00000034 | DIGIT FOUR
     35 |  00000035 | DIGIT FIVE
     36 |  00000036 | DIGIT SIX
     37 |  00000037 | DIGIT SEVEN
     38 |  00000038 | DIGIT EIGHT
     39 |  00000039 | DIGIT NINE
     3A |  0000003A | COLON
     3B |  0000003B | SEMICOLON
     3C |  0000003C | LESS-THAN SIGN
     3D |  0000003D | EQUALS SIGN
     3E |  0000003E | GREATER-THAN SIGN
     3F |  0000003F | QUESTION MARK
     40 |  00000040 | COMMERCIAL AT
     41 |  00000041 | LATIN CAPITAL LETTER A
     42 |  00000042 | LATIN CAPITAL LETTER B
     43 |  00000043 | LATIN CAPITAL LETTER C
     44 |  00000044 | LATIN CAPITAL LETTER D
     45 |  00000045 | LATIN CAPITAL LETTER E
     46 |  00000046 | LATIN CAPITAL LETTER F
     47 |  00000047 | LATIN CAPITAL LETTER G
     48 |  00000048 | LATIN CAPITAL LETTER H
     49 |  00000049 | LATIN CAPITAL LETTER I
     4A |  0000004A | LATIN CAPITAL LETTER J
     4B |  0000004B | LATIN CAPITAL LETTER K
     4C |  0000004C | LATIN CAPITAL LETTER L
     4D |  0000004D | LATIN CAPITAL LETTER M
     4E |  0000004E | LATIN CAPITAL LETTER N
     4F |  0000004F | LATIN CAPITAL LETTER O
     50 |  00000050 | LATIN CAPITAL LETTER P
     51 |  00000051 | LATIN CAPITAL LETTER Q
     52 |  00000052 | LATIN CAPITAL LETTER R
     53 |  00000053 | LATIN CAPITAL LETTER S
     54 |  00000054 | LATIN CAPITAL LETTER T
     55 |  00000055 | LATIN CAPITAL LETTER U
     56 |  00000056 | LATIN CAPITAL LETTER V
     57 |  00000057 | LATIN CAPITAL LETTER W
     58 |  00000058 | LATIN CAPITAL LETTER X
     59 |  00000059 | LATIN CAPITAL LETTER Y
     5A |  0000005A | LATIN CAPITAL LETTER Z
     5B |  0000005B | LEFT SQUARE BRACKET
     5C |  0000005C | REVERSE SOLIDUS
     5D |  0000005D | RIGHT SQUARE BRACKET
     5E |  0000005E | CIRCUMFLEX ACCENT
     5F |  0000005F | LOW LINE
     60 |  00000060 | GRAVE ACCENT
     61 |  00000061 | LATIN SMALL LETTER A
     62 |  00000062 | LATIN SMALL LETTER B
     63 |  00000063 | LATIN SMALL LETTER C
     64 |  00000064 | LATIN SMALL LETTER D
     65 |  00000065 | LATIN SMALL LETTER E
     66 |  00000066 | LATIN SMALL LETTER F
     67 |  00000067 | LATIN SMALL LETTER G
     68 |  00000068 | LATIN SMALL LETTER H
     69 |  00000069 | LATIN SMALL LETTER I
     6A |  0000006A | LATIN SMALL LETTER J
     6B |  0000006B | LATIN SMALL LETTER K
     6C |  0000006C | LATIN SMALL LETTER L
     6D |  0000006D | LATIN SMALL LETTER M
     6E |  0000006E | LATIN SMALL LETTER N
     6F |  0000006F | LATIN SMALL LETTER O
     70 |  00000070 | LATIN SMALL LETTER P
     71 |  00000071 | LATIN SMALL LETTER Q
     72 |  00000072 | LATIN SMALL LETTER R
     73 |  00000073 | LATIN SMALL LETTER S
     74 |  00000074 | LATIN SMALL LETTER T
     75 |  00000075 | LATIN SMALL LETTER U
     76 |  00000076 | LATIN SMALL LETTER V
     77 |  00000077 | LATIN SMALL LETTER W
     78 |  00000078 | LATIN SMALL LETTER X
     79 |  00000079 | LATIN SMALL LETTER Y
     7A |  0000007A | LATIN SMALL LETTER Z
     7B |  0000007B | LEFT CURLY BRACKET
     7C |  0000007C | VERTICAL LINE
     7D |  0000007D | RIGHT CURLY BRACKET
     7E |  0000007E | TILDE
     7F |  0000007F | DELETE (DEL)
     80 |  000000C4 | LATIN CAPITAL LETTER A WITH DIAERESIS
     81 |  000000A0 | NO-BREAK SPACE
     82 |  000000C7 | LATIN CAPITAL LETTER C WITH CEDILLA
     83 |  000000C9 | LATIN CAPITAL LETTER E WITH ACUTE
     84 |  000000D1 | LATIN CAPITAL LETTER N WITH TILDE
     85 |  000000D6 | LATIN CAPITAL LETTER O WITH DIAERESIS
     86 |  000000DC | LATIN CAPITAL LETTER U WITH DIAERESIS
     87 |  000000E1 | LATIN SMALL LETTER A WITH ACUTE
     88 |  000000E0 | LATIN SMALL LETTER A WITH GRAVE
     89 |  000000E2 | LATIN SMALL LETTER A WITH CIRCUMFLEX
     8A |  000000E4 | LATIN SMALL LETTER A WITH DIAERESIS
     8B |  000006BA | ARABIC LETTER NOON GHUNNA
     8C |  000000AB | LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
     8D |  000000E7 | LATIN SMALL LETTER C WITH CEDILLA
     8E |  000000E9 | LATIN SMALL LETTER E WITH ACUTE
     8F |  000000E8 | LATIN SMALL LETTER E WITH GRAVE
     90 |  000000EA | LATIN SMALL LETTER E WITH CIRCUMFLEX
     91 |  000000EB | LATIN SMALL LETTER E WITH DIAERESIS
     92 |  000000ED | LATIN SMALL LETTER I WITH ACUTE
     93 |  00002026 | HORIZONTAL ELLIPSIS
     94 |  000000EE | LATIN SMALL LETTER I WITH CIRCUMFLEX
     95 |  000000EF | LATIN SMALL LETTER I WITH DIAERESIS
     96 |  000000F1 | LATIN SMALL LETTER N WITH TILDE
     97 |  000000F3 | LATIN SMALL LETTER O WITH ACUTE
     98 |  000000BB | RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
     99 |  000000F4 | LATIN SMALL LETTER O WITH CIRCUMFLEX
     9A |  000000F6 | LATIN SMALL LETTER O WITH DIAERESIS
     9B |  000000F7 | DIVISION SIGN
     9C |  000000FA | LATIN SMALL LETTER U WITH ACUTE
     9D |  000000F9 | LATIN SMALL LETTER U WITH GRAVE
     9E |  000000FB | LATIN SMALL LETTER U WITH CIRCUMFLEX
     9F |  000000FC | LATIN SMALL LETTER U WITH DIAERESIS
     A5 |  0000066A | ARABIC PERCENT SIGN
     AC |  0000060C | ARABIC COMMA
     B0 |  00000660 | ARABIC-INDIC DIGIT ZERO
     B1 |  00000661 | ARABIC-INDIC DIGIT ONE
     B2 |  00000662 | ARABIC-INDIC DIGIT TWO
     B3 |  00000663 | ARABIC-INDIC DIGIT THREE
     B4 |  00000664 | ARABIC-INDIC DIGIT FOUR
     B5 |  00000665 | ARABIC-INDIC DIGIT FIVE
     B6 |  00000666 | ARABIC-INDIC DIGIT SIX
     B7 |  00000667 | ARABIC-INDIC DIGIT SEVEN
     B8 |  00000668 | ARABIC-INDIC DIGIT EIGHT
     B9 |  00000669 | ARABIC-INDIC DIGIT NINE
     BB |  0000061B | ARABIC SEMICOLON
     BF |  0000061F | ARABIC QUESTION MARK
     C0 |  0000066D | ARABIC FIVE POINTED STAR
     C1 |  00000621 | ARABIC LETTER HAMZA
     C2 |  00000622 | ARABIC LETTER ALEF WITH MADDA ABOVE
     C3 |  00000623 | ARABIC LETTER ALEF WITH HAMZA ABOVE
     C4 |  00000624 | ARABIC LETTER WAW WITH HAMZA ABOVE
     C5 |  00000625 | ARABIC LETTER ALEF WITH HAMZA BELOW
     C6 |  00000626 | ARABIC LETTER YEH WITH HAMZA ABOVE
     C7 |  00000627 | ARABIC LETTER ALEF
     C8 |  00000628 | ARABIC LETTER BEH
     C9 |  00000629 | ARABIC LETTER TEH MARBUTA
     CA |  0000062A | ARABIC LETTER TEH
     CB |  0000062B | ARABIC LETTER THEH
     CC |  0000062C | ARABIC LETTER JEEM
     CD |  0000062D | ARABIC LETTER HAH
     CE |  0000062E | ARABIC LETTER KHAH
     CF |  0000062F | ARABIC LETTER DAL
     D0 |  00000630 | ARABIC LETTER THAL
     D1 |  00000631 | ARABIC LETTER REH
     D2 |  00000632 | ARABIC LETTER ZAIN
     D3 |  00000633 | ARABIC LETTER SEEN
     D4 |  00000634 | ARABIC LETTER SHEEN
     D5 |  00000635 | ARABIC LETTER SAD
     D6 |  00000636 | ARABIC LETTER DAD
     D7 |  00000637 | ARABIC LETTER TAH
     D8 |  00000638 | ARABIC LETTER ZAH
     D9 |  00000639 | ARABIC LETTER AIN
     DA |  0000063A | ARABIC LETTER GHAIN
     E0 |  00000640 | ARABIC TATWEEL
     E1 |  00000641 | ARABIC LETTER FEH
     E2 |  00000642 | ARABIC LETTER QAF
     E3 |  00000643 | ARABIC LETTER KAF
     E4 |  00000644 | ARABIC LETTER LAM
     E5 |  00000645 | ARABIC LETTER MEEM
     E6 |  00000646 | ARABIC LETTER NOON
     E7 |  00000647 | ARABIC LETTER HEH
     E8 |  00000648 | ARABIC LETTER WAW
     E9 |  00000649 | ARABIC LETTER ALEF MAKSURA
     EA |  0000064A | ARABIC LETTER YEH
     EB |  0000064B | ARABIC FATHATAN
     EC |  0000064C | ARABIC DAMMATAN
     ED |  0000064D | ARABIC KASRATAN
     EE |  0000064E | ARABIC FATHA
     EF |  0000064F | ARABIC DAMMA
     F0 |  00000650 | ARABIC KASRA
     F1 |  00000651 | ARABIC SHADDA
     F2 |  00000652 | ARABIC SUKUN
     F3 |  0000067E | ARABIC LETTER PEH
     F4 |  00000679 | ARABIC LETTER TTEH
     F5 |  00000686 | ARABIC LETTER TCHEH
     F6 |  000006D5 | ARABIC LETTER AE
     F7 |  000006A4 | ARABIC LETTER VEH
     F8 |  000006AF | ARABIC LETTER GAF
     F9 |  00000688 | ARABIC LETTER DDAL
     FA |  00000691 | ARABIC LETTER RREH
     FE |  00000698 | ARABIC LETTER JEH
     FF |  000006D2 | ARABIC LETTER YEH BARREE
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/MACCROATIAN.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for MACCROATIAN.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::MACCROATIAN;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x0004,
     0x0005,
     0x0006,
     0x0007,
     0x0008,
     0x0009,
     0x000a,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x0014,
     0x0015,
     0x0016,
     0x0017,
     0x0018,
     0x0019,
     0x001a,
     0x001b,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0020,
     0x0021,
     0x0022,
     0x0023,
     0x0024,
     0x0025,
     0x0026,
     0x0027,
     0x0028,
     0x0029,
     0x002a,
     0x002b,
     0x002c,
     0x002d,
     0x002e,
     0x002f,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x003a,
     0x003b,
     0x003c,
     0x003d,
     0x003e,
     0x003f,
     0x0040,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x005b,
     0x005c,
     0x005d,
     0x005e,
     0x005f,
     0x0060,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x007b,
     0x007c,
     0x007d,
     0x007e,
     0x007f,
     0x00c4,
     0x00c5,
     0x00c7,
     0x00c9,
     0x00d1,
     0x00d6,
     0x00dc,
     0x00e1,
     0x00e0,
     0x00e2,
     0x00e4,
     0x00e3,
     0x00e5,
     0x00e7,
     0x00e9,
     0x00e8,
     0x00ea,
     0x00eb,
     0x00ed,
     0x00ec,
     0x00ee,
     0x00ef,
     0x00f1,
     0x00f3,
     0x00f2,
     0x00f4,
     0x00f6,
     0x00f5,
     0x00fa,
     0x00f9,
     0x00fb,
     0x00fc,
     0x2020,
     0x00b0,
     0x00a2,
     0x00a3,
     0x00a7,
     0x2022,
     0x00b6,
     0x00df,
     0x00ae,
     0x0160,
     0x2122,
     0x00b4,
     0x00a8,
     0x2260,
     0x017d,
     0x00d8,
     0x221e,
     0x00b1,
     0x2264,
     0x2265,
     0x2206,
     0x00b5,
     0x2202,
     0x2211,
     0x220f,
     0x0161,
     0x222b,
     0x00aa,
     0x00ba,
     0x2126,
     0x017e,
     0x00f8,
     0x00bf,
     0x00a1,
     0x00ac,
     0x221a,
     0x0192,
     0x2248,
     0x0106,
     0x00ab,
     0x010c,
     0x2026,
     0x00a0,
     0x00c0,
     0x00c3,
     0x00d5,
     0x0152,
     0x0153,
     0x0110,
     0x2014,
     0x201c,
     0x201d,
     0x2018,
     0x2019,
     0x00f7,
     0x25ca,
     0xfffd,
     0x00a9,
     0x2044,
     0x00a4,
     0x2039,
     0x203a,
     0x00c6,
     0x00bb,
     0x2013,
     0x00b7,
     0x201a,
     0x201e,
     0x2030,
     0x00c2,
     0x0107,
     0x00c1,
     0x010d,
     0x00c8,
     0x00cd,
     0x00ce,
     0x00cf,
     0x00cc,
     0x00d3,
     0x00d4,
     0x0111,
     0x00d2,
     0x00da,
     0x00db,
     0x00d9,
     0x0131,
     0x02c6,
     0x02dc,
     0x00af,
     0x03c0,
     0x00cb,
     0x02da,
     0x00b8,
     0x00ca,
     0x00e6,
     0x02c7,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\x04",
     "\x05",
     "\x06",
     "\x07",
     "\x08",
     "\x09",
     "\x0a",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\x14",
     "\x15",
     "\x16",
     "\x17",
     "\x18",
     "\x19",
     "\x1a",
     "\x1b",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\x20",
     "\x21",
     "\x22",
     "\x23",
     "\x24",
     "\x25",
     "\x26",
     "\x27",
     "\x28",
     "\x29",
     "\x2a",
     "\x2b",
     "\x2c",
     "\x2d",
     "\x2e",
     "\x2f",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\x3a",
     "\x3b",
     "\x3c",
     "\x3d",
     "\x3e",
     "\x3f",
     "\x40",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\x5b",
     "\x5c",
     "\x5d",
     "\x5e",
     "\x5f",
     "\x60",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\x7b",
     "\x7c",
     "\x7d",
     "\x7e",
     "\x7f",
     "\xc3\x84",
     "\xc3\x85",
     "\xc3\x87",
     "\xc3\x89",
     "\xc3\x91",
     "\xc3\x96",
     "\xc3\x9c",
     "\xc3\xa1",
     "\xc3\xa0",
     "\xc3\xa2",
     "\xc3\xa4",
     "\xc3\xa3",
     "\xc3\xa5",
     "\xc3\xa7",
     "\xc3\xa9",
     "\xc3\xa8",
     "\xc3\xaa",
     "\xc3\xab",
     "\xc3\xad",
     "\xc3\xac",
     "\xc3\xae",
     "\xc3\xaf",
     "\xc3\xb1",
     "\xc3\xb3",
     "\xc3\xb2",
     "\xc3\xb4",
     "\xc3\xb6",
     "\xc3\xb5",
     "\xc3\xba",
     "\xc3\xb9",
     "\xc3\xbb",
     "\xc3\xbc",
     "\xe2\x80\xa0",
     "\xc2\xb0",
     "\xc2\xa2",
     "\xc2\xa3",
     "\xc2\xa7",
     "\xe2\x80\xa2",
     "\xc2\xb6",
     "\xc3\x9f",
     "\xc2\xae",
     "\xc5\xa0",
     "\xe2\x84\xa2",
     "\xc2\xb4",
     "\xc2\xa8",
     "\xe2\x89\xa0",
     "\xc5\xbd",
     "\xc3\x98",
     "\xe2\x88\x9e",
     "\xc2\xb1",
     "\xe2\x89\xa4",
     "\xe2\x89\xa5",
     "\xe2\x88\x86",
     "\xc2\xb5",
     "\xe2\x88\x82",
     "\xe2\x88\x91",
     "\xe2\x88\x8f",
     "\xc5\xa1",
     "\xe2\x88\xab",
     "\xc2\xaa",
     "\xc2\xba",
     "\xe2\x84\xa6",
     "\xc5\xbe",
     "\xc3\xb8",
     "\xc2\xbf",
     "\xc2\xa1",
     "\xc2\xac",
     "\xe2\x88\x9a",
     "\xc6\x92",
     "\xe2\x89\x88",
     "\xc4\x86",
     "\xc2\xab",
     "\xc4\x8c",
     "\xe2\x80\xa6",
     "\xc2\xa0",
     "\xc3\x80",
     "\xc3\x83",
     "\xc3\x95",
     "\xc5\x92",
     "\xc5\x93",
     "\xc4\x90",
     "\xe2\x80\x94",
     "\xe2\x80\x9c",
     "\xe2\x80\x9d",
     "\xe2\x80\x98",
     "\xe2\x80\x99",
     "\xc3\xb7",
     "\xe2\x97\x8a",
     "\xef\xbf\xbd",
     "\xc2\xa9",
     "\xe2\x81\x84",
     "\xc2\xa4",
     "\xe2\x80\xb9",
     "\xe2\x80\xba",
     "\xc3\x86",
     "\xc2\xbb",
     "\xe2\x80\x93",
     "\xc2\xb7",
     "\xe2\x80\x9a",
     "\xe2\x80\x9e",
     "\xe2\x80\xb0",
     "\xc3\x82",
     "\xc4\x87",
     "\xc3\x81",
     "\xc4\x8d",
     "\xc3\x88",
     "\xc3\x8d",
     "\xc3\x8e",
     "\xc3\x8f",
     "\xc3\x8c",
     "\xc3\x93",
     "\xc3\x94",
     "\xc4\x91",
     "\xc3\x92",
     "\xc3\x9a",
     "\xc3\x9b",
     "\xc3\x99",
     "\xc4\xb1",
     "\xcb\x86",
     "\xcb\x9c",
     "\xc2\xaf",
     "\xcf\x80",
     "\xc3\x8b",
     "\xcb\x9a",
     "\xc2\xb8",
     "\xc3\x8a",
     "\xc3\xa6",
     "\xcb\x87",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x04",
     0x00000005 => "\x05",
     0x00000006 => "\x06",
     0x00000007 => "\x07",
     0x00000008 => "\x08",
     0x00000009 => "\x09",
     0x0000000a => "\x0a",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x14",
     0x00000015 => "\x15",
     0x00000016 => "\x16",
     0x00000017 => "\x17",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x1a",
     0x0000001b => "\x1b",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x20",
     0x00000021 => "\x21",
     0x00000022 => "\x22",
     0x00000023 => "\x23",
     0x00000024 => "\x24",
     0x00000025 => "\x25",
     0x00000026 => "\x26",
     0x00000027 => "\x27",
     0x00000028 => "\x28",
     0x00000029 => "\x29",
     0x0000002a => "\x2a",
     0x0000002b => "\x2b",
     0x0000002c => "\x2c",
     0x0000002d => "\x2d",
     0x0000002e => "\x2e",
     0x0000002f => "\x2f",
     0x00000030 => "\x30",
     0x00000031 => "\x31",
     0x00000032 => "\x32",
     0x00000033 => "\x33",
     0x00000034 => "\x34",
     0x00000035 => "\x35",
     0x00000036 => "\x36",
     0x00000037 => "\x37",
     0x00000038 => "\x38",
     0x00000039 => "\x39",
     0x0000003a => "\x3a",
     0x0000003b => "\x3b",
     0x0000003c => "\x3c",
     0x0000003d => "\x3d",
     0x0000003e => "\x3e",
     0x0000003f => "\x3f",
     0x00000040 => "\x40",
     0x00000041 => "\x41",
     0x00000042 => "\x42",
     0x00000043 => "\x43",
     0x00000044 => "\x44",
     0x00000045 => "\x45",
     0x00000046 => "\x46",
     0x00000047 => "\x47",
     0x00000048 => "\x48",
     0x00000049 => "\x49",
     0x0000004a => "\x4a",
     0x0000004b => "\x4b",
     0x0000004c => "\x4c",
     0x0000004d => "\x4d",
     0x0000004e => "\x4e",
     0x0000004f => "\x4f",
     0x00000050 => "\x50",
     0x00000051 => "\x51",
     0x00000052 => "\x52",
     0x00000053 => "\x53",
     0x00000054 => "\x54",
     0x00000055 => "\x55",
     0x00000056 => "\x56",
     0x00000057 => "\x57",
     0x00000058 => "\x58",
     0x00000059 => "\x59",
     0x0000005a => "\x5a",
     0x0000005b => "\x5b",
     0x0000005c => "\x5c",
     0x0000005d => "\x5d",
     0x0000005e => "\x5e",
     0x0000005f => "\x5f",
     0x00000060 => "\x60",
     0x00000061 => "\x61",
     0x00000062 => "\x62",
     0x00000063 => "\x63",
     0x00000064 => "\x64",
     0x00000065 => "\x65",
     0x00000066 => "\x66",
     0x00000067 => "\x67",
     0x00000068 => "\x68",
     0x00000069 => "\x69",
     0x0000006a => "\x6a",
     0x0000006b => "\x6b",
     0x0000006c => "\x6c",
     0x0000006d => "\x6d",
     0x0000006e => "\x6e",
     0x0000006f => "\x6f",
     0x00000070 => "\x70",
     0x00000071 => "\x71",
     0x00000072 => "\x72",
     0x00000073 => "\x73",
     0x00000074 => "\x74",
     0x00000075 => "\x75",
     0x00000076 => "\x76",
     0x00000077 => "\x77",
     0x00000078 => "\x78",
     0x00000079 => "\x79",
     0x0000007a => "\x7a",
     0x0000007b => "\x7b",
     0x0000007c => "\x7c",
     0x0000007d => "\x7d",
     0x0000007e => "\x7e",
     0x0000007f => "\x7f",
     0x000000a0 => "\xca",
     0x000000a1 => "\xc1",
     0x000000a2 => "\xa2",
     0x000000a3 => "\xa3",
     0x000000a4 => "\xdb",
     0x000000a7 => "\xa4",
     0x000000a8 => "\xac",
     0x000000a9 => "\xd9",
     0x000000aa => "\xbb",
     0x000000ab => "\xc7",
     0x000000ac => "\xc2",
     0x000000ae => "\xa8",
     0x000000af => "\xf8",
     0x000000b0 => "\xa1",
     0x000000b1 => "\xb1",
     0x000000b4 => "\xab",
     0x000000b5 => "\xb5",
     0x000000b6 => "\xa6",
     0x000000b7 => "\xe1",
     0x000000b8 => "\xfc",
     0x000000ba => "\xbc",
     0x000000bb => "\xdf",
     0x000000bf => "\xc0",
     0x000000c0 => "\xcb",
     0x000000c1 => "\xe7",
     0x000000c2 => "\xe5",
     0x000000c3 => "\xcc",
     0x000000c4 => "\x80",
     0x000000c5 => "\x81",
     0x000000c6 => "\xde",
     0x000000c7 => "\x82",
     0x000000c8 => "\xe9",
     0x000000c9 => "\x83",
     0x000000ca => "\xfd",
     0x000000cb => "\xfa",
     0x000000cc => "\xed",
     0x000000cd => "\xea",
     0x000000ce => "\xeb",
     0x000000cf => "\xec",
     0x000000d1 => "\x84",
     0x000000d2 => "\xf1",
     0x000000d3 => "\xee",
     0x000000d4 => "\xef",
     0x000000d5 => "\xcd",
     0x000000d6 => "\x85",
     0x000000d8 => "\xaf",
     0x000000d9 => "\xf4",
     0x000000da => "\xf2",
     0x000000db => "\xf3",
     0x000000dc => "\x86",
     0x000000df => "\xa7",
     0x000000e0 => "\x88",
     0x000000e1 => "\x87",
     0x000000e2 => "\x89",
     0x000000e3 => "\x8b",
     0x000000e4 => "\x8a",
     0x000000e5 => "\x8c",
     0x000000e6 => "\xfe",
     0x000000e7 => "\x8d",
     0x000000e8 => "\x8f",
     0x000000e9 => "\x8e",
     0x000000ea => "\x90",
     0x000000eb => "\x91",
     0x000000ec => "\x93",
     0x000000ed => "\x92",
     0x000000ee => "\x94",
     0x000000ef => "\x95",
     0x000000f1 => "\x96",
     0x000000f2 => "\x98",
     0x000000f3 => "\x97",
     0x000000f4 => "\x99",
     0x000000f5 => "\x9b",
     0x000000f6 => "\x9a",
     0x000000f7 => "\xd6",
     0x000000f8 => "\xbf",
     0x000000f9 => "\x9d",
     0x000000fa => "\x9c",
     0x000000fb => "\x9e",
     0x000000fc => "\x9f",
     0x00000106 => "\xc6",
     0x00000107 => "\xe6",
     0x0000010c => "\xc8",
     0x0000010d => "\xe8",
     0x00000110 => "\xd0",
     0x00000111 => "\xf0",
     0x00000131 => "\xf5",
     0x00000152 => "\xce",
     0x00000153 => "\xcf",
     0x00000160 => "\xa9",
     0x00000161 => "\xb9",
     0x0000017d => "\xae",
     0x0000017e => "\xbe",
     0x00000192 => "\xc4",
     0x000002c6 => "\xf6",
     0x000002c7 => "\xff",
     0x000002da => "\xfb",
     0x000002dc => "\xf7",
     0x000003c0 => "\xf9",
     0x00002013 => "\xe0",
     0x00002014 => "\xd1",
     0x00002018 => "\xd4",
     0x00002019 => "\xd5",
     0x0000201a => "\xe2",
     0x0000201c => "\xd2",
     0x0000201d => "\xd3",
     0x0000201e => "\xe3",
     0x00002020 => "\xa0",
     0x00002022 => "\xa5",
     0x00002026 => "\xc9",
     0x00002030 => "\xe4",
     0x00002039 => "\xdc",
     0x0000203a => "\xdd",
     0x00002044 => "\xda",
     0x00002122 => "\xaa",
     0x00002126 => "\xbd",
     0x00002202 => "\xb6",
     0x00002206 => "\xb4",
     0x0000220f => "\xb8",
     0x00002211 => "\xb7",
     0x0000221a => "\xc3",
     0x0000221e => "\xb0",
     0x0000222b => "\xba",
     0x00002248 => "\xc5",
     0x00002260 => "\xad",
     0x00002264 => "\xb2",
     0x00002265 => "\xb3",
     0x000025ca => "\xd7",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::MACCROATIAN - Conversion routines for MACCROATIAN
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for MACCROATIAN.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
 
  This charmap has been generated automatically from GNU libiconv
  conversions.
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  00000004 | END OF TRANSMISSION (EOT)
     05 |  00000005 | ENQUIRY (ENQ)
     06 |  00000006 | ACKNOWLEDGE (ACK)
     07 |  00000007 | BELL (BEL)
     08 |  00000008 | BACKSPACE (BS)
     09 |  00000009 | CHARACTER TABULATION (HT)
     0A |  0000000A | LINE FEED (LF)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  00000014 | DEVICE CONTROL FOUR (DC4)
     15 |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     16 |  00000016 | SYNCHRONOUS IDLE (SYN)
     17 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  0000001A | SUBSTITUTE (SUB)
     1B |  0000001B | ESCAPE (ESC)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000020 | SPACE
     21 |  00000021 | EXCLAMATION MARK
     22 |  00000022 | QUOTATION MARK
     23 |  00000023 | NUMBER SIGN
     24 |  00000024 | DOLLAR SIGN
     25 |  00000025 | PERCENT SIGN
     26 |  00000026 | AMPERSAND
     27 |  00000027 | APOSTROPHE
     28 |  00000028 | LEFT PARENTHESIS
     29 |  00000029 | RIGHT PARENTHESIS
     2A |  0000002A | ASTERISK
     2B |  0000002B | PLUS SIGN
     2C |  0000002C | COMMA
     2D |  0000002D | HYPHEN-MINUS
     2E |  0000002E | FULL STOP
     2F |  0000002F | SOLIDUS
     30 |  00000030 | DIGIT ZERO
     31 |  00000031 | DIGIT ONE
     32 |  00000032 | DIGIT TWO
     33 |  00000033 | DIGIT THREE
     34 |  00000034 | DIGIT FOUR
     35 |  00000035 | DIGIT FIVE
     36 |  00000036 | DIGIT SIX
     37 |  00000037 | DIGIT SEVEN
     38 |  00000038 | DIGIT EIGHT
     39 |  00000039 | DIGIT NINE
     3A |  0000003A | COLON
     3B |  0000003B | SEMICOLON
     3C |  0000003C | LESS-THAN SIGN
     3D |  0000003D | EQUALS SIGN
     3E |  0000003E | GREATER-THAN SIGN
     3F |  0000003F | QUESTION MARK
     40 |  00000040 | COMMERCIAL AT
     41 |  00000041 | LATIN CAPITAL LETTER A
     42 |  00000042 | LATIN CAPITAL LETTER B
     43 |  00000043 | LATIN CAPITAL LETTER C
     44 |  00000044 | LATIN CAPITAL LETTER D
     45 |  00000045 | LATIN CAPITAL LETTER E
     46 |  00000046 | LATIN CAPITAL LETTER F
     47 |  00000047 | LATIN CAPITAL LETTER G
     48 |  00000048 | LATIN CAPITAL LETTER H
     49 |  00000049 | LATIN CAPITAL LETTER I
     4A |  0000004A | LATIN CAPITAL LETTER J
     4B |  0000004B | LATIN CAPITAL LETTER K
     4C |  0000004C | LATIN CAPITAL LETTER L
     4D |  0000004D | LATIN CAPITAL LETTER M
     4E |  0000004E | LATIN CAPITAL LETTER N
     4F |  0000004F | LATIN CAPITAL LETTER O
     50 |  00000050 | LATIN CAPITAL LETTER P
     51 |  00000051 | LATIN CAPITAL LETTER Q
     52 |  00000052 | LATIN CAPITAL LETTER R
     53 |  00000053 | LATIN CAPITAL LETTER S
     54 |  00000054 | LATIN CAPITAL LETTER T
     55 |  00000055 | LATIN CAPITAL LETTER U
     56 |  00000056 | LATIN CAPITAL LETTER V
     57 |  00000057 | LATIN CAPITAL LETTER W
     58 |  00000058 | LATIN CAPITAL LETTER X
     59 |  00000059 | LATIN CAPITAL LETTER Y
     5A |  0000005A | LATIN CAPITAL LETTER Z
     5B |  0000005B | LEFT SQUARE BRACKET
     5C |  0000005C | REVERSE SOLIDUS
     5D |  0000005D | RIGHT SQUARE BRACKET
     5E |  0000005E | CIRCUMFLEX ACCENT
     5F |  0000005F | LOW LINE
     60 |  00000060 | GRAVE ACCENT
     61 |  00000061 | LATIN SMALL LETTER A
     62 |  00000062 | LATIN SMALL LETTER B
     63 |  00000063 | LATIN SMALL LETTER C
     64 |  00000064 | LATIN SMALL LETTER D
     65 |  00000065 | LATIN SMALL LETTER E
     66 |  00000066 | LATIN SMALL LETTER F
     67 |  00000067 | LATIN SMALL LETTER G
     68 |  00000068 | LATIN SMALL LETTER H
     69 |  00000069 | LATIN SMALL LETTER I
     6A |  0000006A | LATIN SMALL LETTER J
     6B |  0000006B | LATIN SMALL LETTER K
     6C |  0000006C | LATIN SMALL LETTER L
     6D |  0000006D | LATIN SMALL LETTER M
     6E |  0000006E | LATIN SMALL LETTER N
     6F |  0000006F | LATIN SMALL LETTER O
     70 |  00000070 | LATIN SMALL LETTER P
     71 |  00000071 | LATIN SMALL LETTER Q
     72 |  00000072 | LATIN SMALL LETTER R
     73 |  00000073 | LATIN SMALL LETTER S
     74 |  00000074 | LATIN SMALL LETTER T
     75 |  00000075 | LATIN SMALL LETTER U
     76 |  00000076 | LATIN SMALL LETTER V
     77 |  00000077 | LATIN SMALL LETTER W
     78 |  00000078 | LATIN SMALL LETTER X
     79 |  00000079 | LATIN SMALL LETTER Y
     7A |  0000007A | LATIN SMALL LETTER Z
     7B |  0000007B | LEFT CURLY BRACKET
     7C |  0000007C | VERTICAL LINE
     7D |  0000007D | RIGHT CURLY BRACKET
     7E |  0000007E | TILDE
     7F |  0000007F | DELETE (DEL)
     80 |  000000C4 | LATIN CAPITAL LETTER A WITH DIAERESIS
     81 |  000000C5 | LATIN CAPITAL LETTER A WITH RING ABOVE
     82 |  000000C7 | LATIN CAPITAL LETTER C WITH CEDILLA
     83 |  000000C9 | LATIN CAPITAL LETTER E WITH ACUTE
     84 |  000000D1 | LATIN CAPITAL LETTER N WITH TILDE
     85 |  000000D6 | LATIN CAPITAL LETTER O WITH DIAERESIS
     86 |  000000DC | LATIN CAPITAL LETTER U WITH DIAERESIS
     87 |  000000E1 | LATIN SMALL LETTER A WITH ACUTE
     88 |  000000E0 | LATIN SMALL LETTER A WITH GRAVE
     89 |  000000E2 | LATIN SMALL LETTER A WITH CIRCUMFLEX
     8A |  000000E4 | LATIN SMALL LETTER A WITH DIAERESIS
     8B |  000000E3 | LATIN SMALL LETTER A WITH TILDE
     8C |  000000E5 | LATIN SMALL LETTER A WITH RING ABOVE
     8D |  000000E7 | LATIN SMALL LETTER C WITH CEDILLA
     8E |  000000E9 | LATIN SMALL LETTER E WITH ACUTE
     8F |  000000E8 | LATIN SMALL LETTER E WITH GRAVE
     90 |  000000EA | LATIN SMALL LETTER E WITH CIRCUMFLEX
     91 |  000000EB | LATIN SMALL LETTER E WITH DIAERESIS
     92 |  000000ED | LATIN SMALL LETTER I WITH ACUTE
     93 |  000000EC | LATIN SMALL LETTER I WITH GRAVE
     94 |  000000EE | LATIN SMALL LETTER I WITH CIRCUMFLEX
     95 |  000000EF | LATIN SMALL LETTER I WITH DIAERESIS
     96 |  000000F1 | LATIN SMALL LETTER N WITH TILDE
     97 |  000000F3 | LATIN SMALL LETTER O WITH ACUTE
     98 |  000000F2 | LATIN SMALL LETTER O WITH GRAVE
     99 |  000000F4 | LATIN SMALL LETTER O WITH CIRCUMFLEX
     9A |  000000F6 | LATIN SMALL LETTER O WITH DIAERESIS
     9B |  000000F5 | LATIN SMALL LETTER O WITH TILDE
     9C |  000000FA | LATIN SMALL LETTER U WITH ACUTE
     9D |  000000F9 | LATIN SMALL LETTER U WITH GRAVE
     9E |  000000FB | LATIN SMALL LETTER U WITH CIRCUMFLEX
     9F |  000000FC | LATIN SMALL LETTER U WITH DIAERESIS
     A0 |  00002020 | DAGGER
     A1 |  000000B0 | DEGREE SIGN
     A2 |  000000A2 | CENT SIGN
     A3 |  000000A3 | POUND SIGN
     A4 |  000000A7 | SECTION SIGN
     A5 |  00002022 | BULLET
     A6 |  000000B6 | PILCROW SIGN
     A7 |  000000DF | LATIN SMALL LETTER SHARP S
     A8 |  000000AE | REGISTERED SIGN
     A9 |  00000160 | LATIN CAPITAL LETTER S WITH CARON
     AA |  00002122 | TRADE MARK SIGN
     AB |  000000B4 | ACUTE ACCENT
     AC |  000000A8 | DIAERESIS
     AD |  00002260 | NOT EQUAL TO
     AE |  0000017D | LATIN CAPITAL LETTER Z WITH CARON
     AF |  000000D8 | LATIN CAPITAL LETTER O WITH STROKE
     B0 |  0000221E | INFINITY
     B1 |  000000B1 | PLUS-MINUS SIGN
     B2 |  00002264 | LESS-THAN OR EQUAL TO
     B3 |  00002265 | GREATER-THAN OR EQUAL TO
     B4 |  00002206 | INCREMENT
     B5 |  000000B5 | MICRO SIGN
     B6 |  00002202 | PARTIAL DIFFERENTIAL
     B7 |  00002211 | N-ARY SUMMATION
     B8 |  0000220F | N-ARY PRODUCT
     B9 |  00000161 | LATIN SMALL LETTER S WITH CARON
     BA |  0000222B | INTEGRAL
     BB |  000000AA | FEMININE ORDINAL INDICATOR
     BC |  000000BA | MASCULINE ORDINAL INDICATOR
     BD |  00002126 | OHM SIGN
     BE |  0000017E | LATIN SMALL LETTER Z WITH CARON
     BF |  000000F8 | LATIN SMALL LETTER O WITH STROKE
     C0 |  000000BF | INVERTED QUESTION MARK
     C1 |  000000A1 | INVERTED EXCLAMATION MARK
     C2 |  000000AC | NOT SIGN
     C3 |  0000221A | SQUARE ROOT
     C4 |  00000192 | LATIN SMALL LETTER F WITH HOOK
     C5 |  00002248 | ALMOST EQUAL TO
     C6 |  00000106 | LATIN CAPITAL LETTER C WITH ACUTE
     C7 |  000000AB | LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
     C8 |  0000010C | LATIN CAPITAL LETTER C WITH CARON
     C9 |  00002026 | HORIZONTAL ELLIPSIS
     CA |  000000A0 | NO-BREAK SPACE
     CB |  000000C0 | LATIN CAPITAL LETTER A WITH GRAVE
     CC |  000000C3 | LATIN CAPITAL LETTER A WITH TILDE
     CD |  000000D5 | LATIN CAPITAL LETTER O WITH TILDE
     CE |  00000152 | LATIN CAPITAL LIGATURE OE
     CF |  00000153 | LATIN SMALL LIGATURE OE
     D0 |  00000110 | LATIN CAPITAL LETTER D WITH STROKE
     D1 |  00002014 | EM DASH
     D2 |  0000201C | LEFT DOUBLE QUOTATION MARK
     D3 |  0000201D | RIGHT DOUBLE QUOTATION MARK
     D4 |  00002018 | LEFT SINGLE QUOTATION MARK
     D5 |  00002019 | RIGHT SINGLE QUOTATION MARK
     D6 |  000000F7 | DIVISION SIGN
     D7 |  000025CA | LOZENGE
     D9 |  000000A9 | COPYRIGHT SIGN
     DA |  00002044 | FRACTION SLASH
     DB |  000000A4 | CURRENCY SIGN
     DC |  00002039 | SINGLE LEFT-POINTING ANGLE QUOTATION MARK
     DD |  0000203A | SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
     DE |  000000C6 | LATIN CAPITAL LETTER AE
     DF |  000000BB | RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
     E0 |  00002013 | EN DASH
     E1 |  000000B7 | MIDDLE DOT
     E2 |  0000201A | SINGLE LOW-9 QUOTATION MARK
     E3 |  0000201E | DOUBLE LOW-9 QUOTATION MARK
     E4 |  00002030 | PER MILLE SIGN
     E5 |  000000C2 | LATIN CAPITAL LETTER A WITH CIRCUMFLEX
     E6 |  00000107 | LATIN SMALL LETTER C WITH ACUTE
     E7 |  000000C1 | LATIN CAPITAL LETTER A WITH ACUTE
     E8 |  0000010D | LATIN SMALL LETTER C WITH CARON
     E9 |  000000C8 | LATIN CAPITAL LETTER E WITH GRAVE
     EA |  000000CD | LATIN CAPITAL LETTER I WITH ACUTE
     EB |  000000CE | LATIN CAPITAL LETTER I WITH CIRCUMFLEX
     EC |  000000CF | LATIN CAPITAL LETTER I WITH DIAERESIS
     ED |  000000CC | LATIN CAPITAL LETTER I WITH GRAVE
     EE |  000000D3 | LATIN CAPITAL LETTER O WITH ACUTE
     EF |  000000D4 | LATIN CAPITAL LETTER O WITH CIRCUMFLEX
     F0 |  00000111 | LATIN SMALL LETTER D WITH STROKE
     F1 |  000000D2 | LATIN CAPITAL LETTER O WITH GRAVE
     F2 |  000000DA | LATIN CAPITAL LETTER U WITH ACUTE
     F3 |  000000DB | LATIN CAPITAL LETTER U WITH CIRCUMFLEX
     F4 |  000000D9 | LATIN CAPITAL LETTER U WITH GRAVE
     F5 |  00000131 | LATIN SMALL LETTER DOTLESS I
     F6 |  000002C6 | MODIFIER LETTER CIRCUMFLEX ACCENT
     F7 |  000002DC | SMALL TILDE
     F8 |  000000AF | MACRON
     F9 |  000003C0 | GREEK SMALL LETTER PI
     FA |  000000CB | LATIN CAPITAL LETTER E WITH DIAERESIS
     FB |  000002DA | RING ABOVE
     FC |  000000B8 | CEDILLA
     FD |  000000CA | LATIN CAPITAL LETTER E WITH CIRCUMFLEX
     FE |  000000E6 | LATIN SMALL LETTER AE
     FF |  000002C7 | CARON
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/MACCYRILLIC.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for MACCYRILLIC.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::MACCYRILLIC;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x0004,
     0x0005,
     0x0006,
     0x0007,
     0x0008,
     0x0009,
     0x000a,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x0014,
     0x0015,
     0x0016,
     0x0017,
     0x0018,
     0x0019,
     0x001a,
     0x001b,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0020,
     0x0021,
     0x0022,
     0x0023,
     0x0024,
     0x0025,
     0x0026,
     0x0027,
     0x0028,
     0x0029,
     0x002a,
     0x002b,
     0x002c,
     0x002d,
     0x002e,
     0x002f,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x003a,
     0x003b,
     0x003c,
     0x003d,
     0x003e,
     0x003f,
     0x0040,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x005b,
     0x005c,
     0x005d,
     0x005e,
     0x005f,
     0x0060,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x007b,
     0x007c,
     0x007d,
     0x007e,
     0x007f,
     0x0410,
     0x0411,
     0x0412,
     0x0413,
     0x0414,
     0x0415,
     0x0416,
     0x0417,
     0x0418,
     0x0419,
     0x041a,
     0x041b,
     0x041c,
     0x041d,
     0x041e,
     0x041f,
     0x0420,
     0x0421,
     0x0422,
     0x0423,
     0x0424,
     0x0425,
     0x0426,
     0x0427,
     0x0428,
     0x0429,
     0x042a,
     0x042b,
     0x042c,
     0x042d,
     0x042e,
     0x042f,
     0x2020,
     0x00b0,
     0x00a2,
     0x00a3,
     0x00a7,
     0x2022,
     0x00b6,
     0x0406,
     0x00ae,
     0x00a9,
     0x2122,
     0x0402,
     0x0452,
     0x2260,
     0x0403,
     0x0453,
     0x221e,
     0x00b1,
     0x2264,
     0x2265,
     0x0456,
     0x00b5,
     0x2202,
     0x0408,
     0x0404,
     0x0454,
     0x0407,
     0x0457,
     0x0409,
     0x0459,
     0x040a,
     0x045a,
     0x0458,
     0x0405,
     0x00ac,
     0x221a,
     0x0192,
     0x2248,
     0x2206,
     0x00ab,
     0x00bb,
     0x2026,
     0x00a0,
     0x040b,
     0x045b,
     0x040c,
     0x045c,
     0x0455,
     0x2013,
     0x2014,
     0x201c,
     0x201d,
     0x2018,
     0x2019,
     0x00f7,
     0x201e,
     0x040e,
     0x045e,
     0x040f,
     0x045f,
     0x2116,
     0x0401,
     0x0451,
     0x044f,
     0x0430,
     0x0431,
     0x0432,
     0x0433,
     0x0434,
     0x0435,
     0x0436,
     0x0437,
     0x0438,
     0x0439,
     0x043a,
     0x043b,
     0x043c,
     0x043d,
     0x043e,
     0x043f,
     0x0440,
     0x0441,
     0x0442,
     0x0443,
     0x0444,
     0x0445,
     0x0446,
     0x0447,
     0x0448,
     0x0449,
     0x044a,
     0x044b,
     0x044c,
     0x044d,
     0x044e,
     0x00a4,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\x04",
     "\x05",
     "\x06",
     "\x07",
     "\x08",
     "\x09",
     "\x0a",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\x14",
     "\x15",
     "\x16",
     "\x17",
     "\x18",
     "\x19",
     "\x1a",
     "\x1b",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\x20",
     "\x21",
     "\x22",
     "\x23",
     "\x24",
     "\x25",
     "\x26",
     "\x27",
     "\x28",
     "\x29",
     "\x2a",
     "\x2b",
     "\x2c",
     "\x2d",
     "\x2e",
     "\x2f",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\x3a",
     "\x3b",
     "\x3c",
     "\x3d",
     "\x3e",
     "\x3f",
     "\x40",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\x5b",
     "\x5c",
     "\x5d",
     "\x5e",
     "\x5f",
     "\x60",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\x7b",
     "\x7c",
     "\x7d",
     "\x7e",
     "\x7f",
     "\xd0\x90",
     "\xd0\x91",
     "\xd0\x92",
     "\xd0\x93",
     "\xd0\x94",
     "\xd0\x95",
     "\xd0\x96",
     "\xd0\x97",
     "\xd0\x98",
     "\xd0\x99",
     "\xd0\x9a",
     "\xd0\x9b",
     "\xd0\x9c",
     "\xd0\x9d",
     "\xd0\x9e",
     "\xd0\x9f",
     "\xd0\xa0",
     "\xd0\xa1",
     "\xd0\xa2",
     "\xd0\xa3",
     "\xd0\xa4",
     "\xd0\xa5",
     "\xd0\xa6",
     "\xd0\xa7",
     "\xd0\xa8",
     "\xd0\xa9",
     "\xd0\xaa",
     "\xd0\xab",
     "\xd0\xac",
     "\xd0\xad",
     "\xd0\xae",
     "\xd0\xaf",
     "\xe2\x80\xa0",
     "\xc2\xb0",
     "\xc2\xa2",
     "\xc2\xa3",
     "\xc2\xa7",
     "\xe2\x80\xa2",
     "\xc2\xb6",
     "\xd0\x86",
     "\xc2\xae",
     "\xc2\xa9",
     "\xe2\x84\xa2",
     "\xd0\x82",
     "\xd1\x92",
     "\xe2\x89\xa0",
     "\xd0\x83",
     "\xd1\x93",
     "\xe2\x88\x9e",
     "\xc2\xb1",
     "\xe2\x89\xa4",
     "\xe2\x89\xa5",
     "\xd1\x96",
     "\xc2\xb5",
     "\xe2\x88\x82",
     "\xd0\x88",
     "\xd0\x84",
     "\xd1\x94",
     "\xd0\x87",
     "\xd1\x97",
     "\xd0\x89",
     "\xd1\x99",
     "\xd0\x8a",
     "\xd1\x9a",
     "\xd1\x98",
     "\xd0\x85",
     "\xc2\xac",
     "\xe2\x88\x9a",
     "\xc6\x92",
     "\xe2\x89\x88",
     "\xe2\x88\x86",
     "\xc2\xab",
     "\xc2\xbb",
     "\xe2\x80\xa6",
     "\xc2\xa0",
     "\xd0\x8b",
     "\xd1\x9b",
     "\xd0\x8c",
     "\xd1\x9c",
     "\xd1\x95",
     "\xe2\x80\x93",
     "\xe2\x80\x94",
     "\xe2\x80\x9c",
     "\xe2\x80\x9d",
     "\xe2\x80\x98",
     "\xe2\x80\x99",
     "\xc3\xb7",
     "\xe2\x80\x9e",
     "\xd0\x8e",
     "\xd1\x9e",
     "\xd0\x8f",
     "\xd1\x9f",
     "\xe2\x84\x96",
     "\xd0\x81",
     "\xd1\x91",
     "\xd1\x8f",
     "\xd0\xb0",
     "\xd0\xb1",
     "\xd0\xb2",
     "\xd0\xb3",
     "\xd0\xb4",
     "\xd0\xb5",
     "\xd0\xb6",
     "\xd0\xb7",
     "\xd0\xb8",
     "\xd0\xb9",
     "\xd0\xba",
     "\xd0\xbb",
     "\xd0\xbc",
     "\xd0\xbd",
     "\xd0\xbe",
     "\xd0\xbf",
     "\xd1\x80",
     "\xd1\x81",
     "\xd1\x82",
     "\xd1\x83",
     "\xd1\x84",
     "\xd1\x85",
     "\xd1\x86",
     "\xd1\x87",
     "\xd1\x88",
     "\xd1\x89",
     "\xd1\x8a",
     "\xd1\x8b",
     "\xd1\x8c",
     "\xd1\x8d",
     "\xd1\x8e",
     "\xc2\xa4",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x04",
     0x00000005 => "\x05",
     0x00000006 => "\x06",
     0x00000007 => "\x07",
     0x00000008 => "\x08",
     0x00000009 => "\x09",
     0x0000000a => "\x0a",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x14",
     0x00000015 => "\x15",
     0x00000016 => "\x16",
     0x00000017 => "\x17",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x1a",
     0x0000001b => "\x1b",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x20",
     0x00000021 => "\x21",
     0x00000022 => "\x22",
     0x00000023 => "\x23",
     0x00000024 => "\x24",
     0x00000025 => "\x25",
     0x00000026 => "\x26",
     0x00000027 => "\x27",
     0x00000028 => "\x28",
     0x00000029 => "\x29",
     0x0000002a => "\x2a",
     0x0000002b => "\x2b",
     0x0000002c => "\x2c",
     0x0000002d => "\x2d",
     0x0000002e => "\x2e",
     0x0000002f => "\x2f",
     0x00000030 => "\x30",
     0x00000031 => "\x31",
     0x00000032 => "\x32",
     0x00000033 => "\x33",
     0x00000034 => "\x34",
     0x00000035 => "\x35",
     0x00000036 => "\x36",
     0x00000037 => "\x37",
     0x00000038 => "\x38",
     0x00000039 => "\x39",
     0x0000003a => "\x3a",
     0x0000003b => "\x3b",
     0x0000003c => "\x3c",
     0x0000003d => "\x3d",
     0x0000003e => "\x3e",
     0x0000003f => "\x3f",
     0x00000040 => "\x40",
     0x00000041 => "\x41",
     0x00000042 => "\x42",
     0x00000043 => "\x43",
     0x00000044 => "\x44",
     0x00000045 => "\x45",
     0x00000046 => "\x46",
     0x00000047 => "\x47",
     0x00000048 => "\x48",
     0x00000049 => "\x49",
     0x0000004a => "\x4a",
     0x0000004b => "\x4b",
     0x0000004c => "\x4c",
     0x0000004d => "\x4d",
     0x0000004e => "\x4e",
     0x0000004f => "\x4f",
     0x00000050 => "\x50",
     0x00000051 => "\x51",
     0x00000052 => "\x52",
     0x00000053 => "\x53",
     0x00000054 => "\x54",
     0x00000055 => "\x55",
     0x00000056 => "\x56",
     0x00000057 => "\x57",
     0x00000058 => "\x58",
     0x00000059 => "\x59",
     0x0000005a => "\x5a",
     0x0000005b => "\x5b",
     0x0000005c => "\x5c",
     0x0000005d => "\x5d",
     0x0000005e => "\x5e",
     0x0000005f => "\x5f",
     0x00000060 => "\x60",
     0x00000061 => "\x61",
     0x00000062 => "\x62",
     0x00000063 => "\x63",
     0x00000064 => "\x64",
     0x00000065 => "\x65",
     0x00000066 => "\x66",
     0x00000067 => "\x67",
     0x00000068 => "\x68",
     0x00000069 => "\x69",
     0x0000006a => "\x6a",
     0x0000006b => "\x6b",
     0x0000006c => "\x6c",
     0x0000006d => "\x6d",
     0x0000006e => "\x6e",
     0x0000006f => "\x6f",
     0x00000070 => "\x70",
     0x00000071 => "\x71",
     0x00000072 => "\x72",
     0x00000073 => "\x73",
     0x00000074 => "\x74",
     0x00000075 => "\x75",
     0x00000076 => "\x76",
     0x00000077 => "\x77",
     0x00000078 => "\x78",
     0x00000079 => "\x79",
     0x0000007a => "\x7a",
     0x0000007b => "\x7b",
     0x0000007c => "\x7c",
     0x0000007d => "\x7d",
     0x0000007e => "\x7e",
     0x0000007f => "\x7f",
     0x000000a0 => "\xca",
     0x000000a2 => "\xa2",
     0x000000a3 => "\xa3",
     0x000000a4 => "\xff",
     0x000000a7 => "\xa4",
     0x000000a9 => "\xa9",
     0x000000ab => "\xc7",
     0x000000ac => "\xc2",
     0x000000ae => "\xa8",
     0x000000b0 => "\xa1",
     0x000000b1 => "\xb1",
     0x000000b5 => "\xb5",
     0x000000b6 => "\xa6",
     0x000000bb => "\xc8",
     0x000000f7 => "\xd6",
     0x00000192 => "\xc4",
     0x00000401 => "\xdd",
     0x00000402 => "\xab",
     0x00000403 => "\xae",
     0x00000404 => "\xb8",
     0x00000405 => "\xc1",
     0x00000406 => "\xa7",
     0x00000407 => "\xba",
     0x00000408 => "\xb7",
     0x00000409 => "\xbc",
     0x0000040a => "\xbe",
     0x0000040b => "\xcb",
     0x0000040c => "\xcd",
     0x0000040e => "\xd8",
     0x0000040f => "\xda",
     0x00000410 => "\x80",
     0x00000411 => "\x81",
     0x00000412 => "\x82",
     0x00000413 => "\x83",
     0x00000414 => "\x84",
     0x00000415 => "\x85",
     0x00000416 => "\x86",
     0x00000417 => "\x87",
     0x00000418 => "\x88",
     0x00000419 => "\x89",
     0x0000041a => "\x8a",
     0x0000041b => "\x8b",
     0x0000041c => "\x8c",
     0x0000041d => "\x8d",
     0x0000041e => "\x8e",
     0x0000041f => "\x8f",
     0x00000420 => "\x90",
     0x00000421 => "\x91",
     0x00000422 => "\x92",
     0x00000423 => "\x93",
     0x00000424 => "\x94",
     0x00000425 => "\x95",
     0x00000426 => "\x96",
     0x00000427 => "\x97",
     0x00000428 => "\x98",
     0x00000429 => "\x99",
     0x0000042a => "\x9a",
     0x0000042b => "\x9b",
     0x0000042c => "\x9c",
     0x0000042d => "\x9d",
     0x0000042e => "\x9e",
     0x0000042f => "\x9f",
     0x00000430 => "\xe0",
     0x00000431 => "\xe1",
     0x00000432 => "\xe2",
     0x00000433 => "\xe3",
     0x00000434 => "\xe4",
     0x00000435 => "\xe5",
     0x00000436 => "\xe6",
     0x00000437 => "\xe7",
     0x00000438 => "\xe8",
     0x00000439 => "\xe9",
     0x0000043a => "\xea",
     0x0000043b => "\xeb",
     0x0000043c => "\xec",
     0x0000043d => "\xed",
     0x0000043e => "\xee",
     0x0000043f => "\xef",
     0x00000440 => "\xf0",
     0x00000441 => "\xf1",
     0x00000442 => "\xf2",
     0x00000443 => "\xf3",
     0x00000444 => "\xf4",
     0x00000445 => "\xf5",
     0x00000446 => "\xf6",
     0x00000447 => "\xf7",
     0x00000448 => "\xf8",
     0x00000449 => "\xf9",
     0x0000044a => "\xfa",
     0x0000044b => "\xfb",
     0x0000044c => "\xfc",
     0x0000044d => "\xfd",
     0x0000044e => "\xfe",
     0x0000044f => "\xdf",
     0x00000451 => "\xde",
     0x00000452 => "\xac",
     0x00000453 => "\xaf",
     0x00000454 => "\xb9",
     0x00000455 => "\xcf",
     0x00000456 => "\xb4",
     0x00000457 => "\xbb",
     0x00000458 => "\xc0",
     0x00000459 => "\xbd",
     0x0000045a => "\xbf",
     0x0000045b => "\xcc",
     0x0000045c => "\xce",
     0x0000045e => "\xd9",
     0x0000045f => "\xdb",
     0x00002013 => "\xd0",
     0x00002014 => "\xd1",
     0x00002018 => "\xd4",
     0x00002019 => "\xd5",
     0x0000201c => "\xd2",
     0x0000201d => "\xd3",
     0x0000201e => "\xd7",
     0x00002020 => "\xa0",
     0x00002022 => "\xa5",
     0x00002026 => "\xc9",
     0x00002116 => "\xdc",
     0x00002122 => "\xaa",
     0x00002202 => "\xb6",
     0x00002206 => "\xc6",
     0x0000221a => "\xc3",
     0x0000221e => "\xb0",
     0x00002248 => "\xc5",
     0x00002260 => "\xad",
     0x00002264 => "\xb2",
     0x00002265 => "\xb3",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::MACCYRILLIC - Conversion routines for MACCYRILLIC
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for MACCYRILLIC.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
 
  This charmap has been generated automatically from GNU libiconv
  conversions.
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  00000004 | END OF TRANSMISSION (EOT)
     05 |  00000005 | ENQUIRY (ENQ)
     06 |  00000006 | ACKNOWLEDGE (ACK)
     07 |  00000007 | BELL (BEL)
     08 |  00000008 | BACKSPACE (BS)
     09 |  00000009 | CHARACTER TABULATION (HT)
     0A |  0000000A | LINE FEED (LF)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  00000014 | DEVICE CONTROL FOUR (DC4)
     15 |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     16 |  00000016 | SYNCHRONOUS IDLE (SYN)
     17 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  0000001A | SUBSTITUTE (SUB)
     1B |  0000001B | ESCAPE (ESC)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000020 | SPACE
     21 |  00000021 | EXCLAMATION MARK
     22 |  00000022 | QUOTATION MARK
     23 |  00000023 | NUMBER SIGN
     24 |  00000024 | DOLLAR SIGN
     25 |  00000025 | PERCENT SIGN
     26 |  00000026 | AMPERSAND
     27 |  00000027 | APOSTROPHE
     28 |  00000028 | LEFT PARENTHESIS
     29 |  00000029 | RIGHT PARENTHESIS
     2A |  0000002A | ASTERISK
     2B |  0000002B | PLUS SIGN
     2C |  0000002C | COMMA
     2D |  0000002D | HYPHEN-MINUS
     2E |  0000002E | FULL STOP
     2F |  0000002F | SOLIDUS
     30 |  00000030 | DIGIT ZERO
     31 |  00000031 | DIGIT ONE
     32 |  00000032 | DIGIT TWO
     33 |  00000033 | DIGIT THREE
     34 |  00000034 | DIGIT FOUR
     35 |  00000035 | DIGIT FIVE
     36 |  00000036 | DIGIT SIX
     37 |  00000037 | DIGIT SEVEN
     38 |  00000038 | DIGIT EIGHT
     39 |  00000039 | DIGIT NINE
     3A |  0000003A | COLON
     3B |  0000003B | SEMICOLON
     3C |  0000003C | LESS-THAN SIGN
     3D |  0000003D | EQUALS SIGN
     3E |  0000003E | GREATER-THAN SIGN
     3F |  0000003F | QUESTION MARK
     40 |  00000040 | COMMERCIAL AT
     41 |  00000041 | LATIN CAPITAL LETTER A
     42 |  00000042 | LATIN CAPITAL LETTER B
     43 |  00000043 | LATIN CAPITAL LETTER C
     44 |  00000044 | LATIN CAPITAL LETTER D
     45 |  00000045 | LATIN CAPITAL LETTER E
     46 |  00000046 | LATIN CAPITAL LETTER F
     47 |  00000047 | LATIN CAPITAL LETTER G
     48 |  00000048 | LATIN CAPITAL LETTER H
     49 |  00000049 | LATIN CAPITAL LETTER I
     4A |  0000004A | LATIN CAPITAL LETTER J
     4B |  0000004B | LATIN CAPITAL LETTER K
     4C |  0000004C | LATIN CAPITAL LETTER L
     4D |  0000004D | LATIN CAPITAL LETTER M
     4E |  0000004E | LATIN CAPITAL LETTER N
     4F |  0000004F | LATIN CAPITAL LETTER O
     50 |  00000050 | LATIN CAPITAL LETTER P
     51 |  00000051 | LATIN CAPITAL LETTER Q
     52 |  00000052 | LATIN CAPITAL LETTER R
     53 |  00000053 | LATIN CAPITAL LETTER S
     54 |  00000054 | LATIN CAPITAL LETTER T
     55 |  00000055 | LATIN CAPITAL LETTER U
     56 |  00000056 | LATIN CAPITAL LETTER V
     57 |  00000057 | LATIN CAPITAL LETTER W
     58 |  00000058 | LATIN CAPITAL LETTER X
     59 |  00000059 | LATIN CAPITAL LETTER Y
     5A |  0000005A | LATIN CAPITAL LETTER Z
     5B |  0000005B | LEFT SQUARE BRACKET
     5C |  0000005C | REVERSE SOLIDUS
     5D |  0000005D | RIGHT SQUARE BRACKET
     5E |  0000005E | CIRCUMFLEX ACCENT
     5F |  0000005F | LOW LINE
     60 |  00000060 | GRAVE ACCENT
     61 |  00000061 | LATIN SMALL LETTER A
     62 |  00000062 | LATIN SMALL LETTER B
     63 |  00000063 | LATIN SMALL LETTER C
     64 |  00000064 | LATIN SMALL LETTER D
     65 |  00000065 | LATIN SMALL LETTER E
     66 |  00000066 | LATIN SMALL LETTER F
     67 |  00000067 | LATIN SMALL LETTER G
     68 |  00000068 | LATIN SMALL LETTER H
     69 |  00000069 | LATIN SMALL LETTER I
     6A |  0000006A | LATIN SMALL LETTER J
     6B |  0000006B | LATIN SMALL LETTER K
     6C |  0000006C | LATIN SMALL LETTER L
     6D |  0000006D | LATIN SMALL LETTER M
     6E |  0000006E | LATIN SMALL LETTER N
     6F |  0000006F | LATIN SMALL LETTER O
     70 |  00000070 | LATIN SMALL LETTER P
     71 |  00000071 | LATIN SMALL LETTER Q
     72 |  00000072 | LATIN SMALL LETTER R
     73 |  00000073 | LATIN SMALL LETTER S
     74 |  00000074 | LATIN SMALL LETTER T
     75 |  00000075 | LATIN SMALL LETTER U
     76 |  00000076 | LATIN SMALL LETTER V
     77 |  00000077 | LATIN SMALL LETTER W
     78 |  00000078 | LATIN SMALL LETTER X
     79 |  00000079 | LATIN SMALL LETTER Y
     7A |  0000007A | LATIN SMALL LETTER Z
     7B |  0000007B | LEFT CURLY BRACKET
     7C |  0000007C | VERTICAL LINE
     7D |  0000007D | RIGHT CURLY BRACKET
     7E |  0000007E | TILDE
     7F |  0000007F | DELETE (DEL)
     80 |  00000410 | CYRILLIC CAPITAL LETTER A
     81 |  00000411 | CYRILLIC CAPITAL LETTER BE
     82 |  00000412 | CYRILLIC CAPITAL LETTER VE
     83 |  00000413 | CYRILLIC CAPITAL LETTER GHE
     84 |  00000414 | CYRILLIC CAPITAL LETTER DE
     85 |  00000415 | CYRILLIC CAPITAL LETTER IE
     86 |  00000416 | CYRILLIC CAPITAL LETTER ZHE
     87 |  00000417 | CYRILLIC CAPITAL LETTER ZE
     88 |  00000418 | CYRILLIC CAPITAL LETTER I
     89 |  00000419 | CYRILLIC CAPITAL LETTER SHORT I
     8A |  0000041A | CYRILLIC CAPITAL LETTER KA
     8B |  0000041B | CYRILLIC CAPITAL LETTER EL
     8C |  0000041C | CYRILLIC CAPITAL LETTER EM
     8D |  0000041D | CYRILLIC CAPITAL LETTER EN
     8E |  0000041E | CYRILLIC CAPITAL LETTER O
     8F |  0000041F | CYRILLIC CAPITAL LETTER PE
     90 |  00000420 | CYRILLIC CAPITAL LETTER ER
     91 |  00000421 | CYRILLIC CAPITAL LETTER ES
     92 |  00000422 | CYRILLIC CAPITAL LETTER TE
     93 |  00000423 | CYRILLIC CAPITAL LETTER U
     94 |  00000424 | CYRILLIC CAPITAL LETTER EF
     95 |  00000425 | CYRILLIC CAPITAL LETTER HA
     96 |  00000426 | CYRILLIC CAPITAL LETTER TSE
     97 |  00000427 | CYRILLIC CAPITAL LETTER CHE
     98 |  00000428 | CYRILLIC CAPITAL LETTER SHA
     99 |  00000429 | CYRILLIC CAPITAL LETTER SHCHA
     9A |  0000042A | CYRILLIC CAPITAL LETTER HARD SIGN
     9B |  0000042B | CYRILLIC CAPITAL LETTER YERU
     9C |  0000042C | CYRILLIC CAPITAL LETTER SOFT SIGN
     9D |  0000042D | CYRILLIC CAPITAL LETTER E
     9E |  0000042E | CYRILLIC CAPITAL LETTER YU
     9F |  0000042F | CYRILLIC CAPITAL LETTER YA
     A0 |  00002020 | DAGGER
     A1 |  000000B0 | DEGREE SIGN
     A2 |  000000A2 | CENT SIGN
     A3 |  000000A3 | POUND SIGN
     A4 |  000000A7 | SECTION SIGN
     A5 |  00002022 | BULLET
     A6 |  000000B6 | PILCROW SIGN
     A7 |  00000406 | CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I
     A8 |  000000AE | REGISTERED SIGN
     A9 |  000000A9 | COPYRIGHT SIGN
     AA |  00002122 | TRADE MARK SIGN
     AB |  00000402 | CYRILLIC CAPITAL LETTER DJE
     AC |  00000452 | CYRILLIC SMALL LETTER DJE
     AD |  00002260 | NOT EQUAL TO
     AE |  00000403 | CYRILLIC CAPITAL LETTER GJE
     AF |  00000453 | CYRILLIC SMALL LETTER GJE
     B0 |  0000221E | INFINITY
     B1 |  000000B1 | PLUS-MINUS SIGN
     B2 |  00002264 | LESS-THAN OR EQUAL TO
     B3 |  00002265 | GREATER-THAN OR EQUAL TO
     B4 |  00000456 | CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I
     B5 |  000000B5 | MICRO SIGN
     B6 |  00002202 | PARTIAL DIFFERENTIAL
     B7 |  00000408 | CYRILLIC CAPITAL LETTER JE
     B8 |  00000404 | CYRILLIC CAPITAL LETTER UKRAINIAN IE
     B9 |  00000454 | CYRILLIC SMALL LETTER UKRAINIAN IE
     BA |  00000407 | CYRILLIC CAPITAL LETTER YI
     BB |  00000457 | CYRILLIC SMALL LETTER YI
     BC |  00000409 | CYRILLIC CAPITAL LETTER LJE
     BD |  00000459 | CYRILLIC SMALL LETTER LJE
     BE |  0000040A | CYRILLIC CAPITAL LETTER NJE
     BF |  0000045A | CYRILLIC SMALL LETTER NJE
     C0 |  00000458 | CYRILLIC SMALL LETTER JE
     C1 |  00000405 | CYRILLIC CAPITAL LETTER DZE
     C2 |  000000AC | NOT SIGN
     C3 |  0000221A | SQUARE ROOT
     C4 |  00000192 | LATIN SMALL LETTER F WITH HOOK
     C5 |  00002248 | ALMOST EQUAL TO
     C6 |  00002206 | INCREMENT
     C7 |  000000AB | LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
     C8 |  000000BB | RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
     C9 |  00002026 | HORIZONTAL ELLIPSIS
     CA |  000000A0 | NO-BREAK SPACE
     CB |  0000040B | CYRILLIC CAPITAL LETTER TSHE
     CC |  0000045B | CYRILLIC SMALL LETTER TSHE
     CD |  0000040C | CYRILLIC CAPITAL LETTER KJE
     CE |  0000045C | CYRILLIC SMALL LETTER KJE
     CF |  00000455 | CYRILLIC SMALL LETTER DZE
     D0 |  00002013 | EN DASH
     D1 |  00002014 | EM DASH
     D2 |  0000201C | LEFT DOUBLE QUOTATION MARK
     D3 |  0000201D | RIGHT DOUBLE QUOTATION MARK
     D4 |  00002018 | LEFT SINGLE QUOTATION MARK
     D5 |  00002019 | RIGHT SINGLE QUOTATION MARK
     D6 |  000000F7 | DIVISION SIGN
     D7 |  0000201E | DOUBLE LOW-9 QUOTATION MARK
     D8 |  0000040E | CYRILLIC CAPITAL LETTER SHORT U
     D9 |  0000045E | CYRILLIC SMALL LETTER SHORT U
     DA |  0000040F | CYRILLIC CAPITAL LETTER DZHE
     DB |  0000045F | CYRILLIC SMALL LETTER DZHE
     DC |  00002116 | NUMERO SIGN
     DD |  00000401 | CYRILLIC CAPITAL LETTER IO
     DE |  00000451 | CYRILLIC SMALL LETTER IO
     DF |  0000044F | CYRILLIC SMALL LETTER YA
     E0 |  00000430 | CYRILLIC SMALL LETTER A
     E1 |  00000431 | CYRILLIC SMALL LETTER BE
     E2 |  00000432 | CYRILLIC SMALL LETTER VE
     E3 |  00000433 | CYRILLIC SMALL LETTER GHE
     E4 |  00000434 | CYRILLIC SMALL LETTER DE
     E5 |  00000435 | CYRILLIC SMALL LETTER IE
     E6 |  00000436 | CYRILLIC SMALL LETTER ZHE
     E7 |  00000437 | CYRILLIC SMALL LETTER ZE
     E8 |  00000438 | CYRILLIC SMALL LETTER I
     E9 |  00000439 | CYRILLIC SMALL LETTER SHORT I
     EA |  0000043A | CYRILLIC SMALL LETTER KA
     EB |  0000043B | CYRILLIC SMALL LETTER EL
     EC |  0000043C | CYRILLIC SMALL LETTER EM
     ED |  0000043D | CYRILLIC SMALL LETTER EN
     EE |  0000043E | CYRILLIC SMALL LETTER O
     EF |  0000043F | CYRILLIC SMALL LETTER PE
     F0 |  00000440 | CYRILLIC SMALL LETTER ER
     F1 |  00000441 | CYRILLIC SMALL LETTER ES
     F2 |  00000442 | CYRILLIC SMALL LETTER TE
     F3 |  00000443 | CYRILLIC SMALL LETTER U
     F4 |  00000444 | CYRILLIC SMALL LETTER EF
     F5 |  00000445 | CYRILLIC SMALL LETTER HA
     F6 |  00000446 | CYRILLIC SMALL LETTER TSE
     F7 |  00000447 | CYRILLIC SMALL LETTER CHE
     F8 |  00000448 | CYRILLIC SMALL LETTER SHA
     F9 |  00000449 | CYRILLIC SMALL LETTER SHCHA
     FA |  0000044A | CYRILLIC SMALL LETTER HARD SIGN
     FB |  0000044B | CYRILLIC SMALL LETTER YERU
     FC |  0000044C | CYRILLIC SMALL LETTER SOFT SIGN
     FD |  0000044D | CYRILLIC SMALL LETTER E
     FE |  0000044E | CYRILLIC SMALL LETTER YU
     FF |  000000A4 | CURRENCY SIGN
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/MACGREEK.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for MACGREEK.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::MACGREEK;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x0004,
     0x0005,
     0x0006,
     0x0007,
     0x0008,
     0x0009,
     0x000a,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x0014,
     0x0015,
     0x0016,
     0x0017,
     0x0018,
     0x0019,
     0x001a,
     0x001b,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0020,
     0x0021,
     0x0022,
     0x0023,
     0x0024,
     0x0025,
     0x0026,
     0x0027,
     0x0028,
     0x0029,
     0x002a,
     0x002b,
     0x002c,
     0x002d,
     0x002e,
     0x002f,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x003a,
     0x003b,
     0x003c,
     0x003d,
     0x003e,
     0x003f,
     0x0040,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x005b,
     0x005c,
     0x005d,
     0x005e,
     0x005f,
     0x0060,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x007b,
     0x007c,
     0x007d,
     0x007e,
     0x007f,
     0x00c4,
     0x00b9,
     0x00b2,
     0x00c9,
     0x00b3,
     0x00d6,
     0x00dc,
     0x0385,
     0x00e0,
     0x00e2,
     0x00e4,
     0x0384,
     0x00a8,
     0x00e7,
     0x00e9,
     0x00e8,
     0x00ea,
     0x00eb,
     0x00a3,
     0x2122,
     0x00ee,
     0x00ef,
     0x2022,
     0x00bd,
     0x2030,
     0x00f4,
     0x00f6,
     0x00a6,
     0x00ad,
     0x00f9,
     0x00fb,
     0x00fc,
     0x2020,
     0x0393,
     0x0394,
     0x0398,
     0x039b,
     0x039e,
     0x03a0,
     0x00df,
     0x00ae,
     0x00a9,
     0x03a3,
     0x03aa,
     0x00a7,
     0x2260,
     0x00b0,
     0x0387,
     0x0391,
     0x00b1,
     0x2264,
     0x2265,
     0x00a5,
     0x0392,
     0x0395,
     0x0396,
     0x0397,
     0x0399,
     0x039a,
     0x039c,
     0x03a6,
     0x03ab,
     0x03a8,
     0x03a9,
     0x03ac,
     0x039d,
     0x00ac,
     0x039f,
     0x03a1,
     0x2248,
     0x03a4,
     0x00ab,
     0x00bb,
     0x2026,
     0x00a0,
     0x03a5,
     0x03a7,
     0x0386,
     0x0388,
     0x0153,
     0x2013,
     0x2015,
     0x201c,
     0x201d,
     0x2018,
     0x2019,
     0x00f7,
     0x0389,
     0x038a,
     0x038c,
     0x038e,
     0x03ad,
     0x03ae,
     0x03af,
     0x03cc,
     0x038f,
     0x03cd,
     0x03b1,
     0x03b2,
     0x03c8,
     0x03b4,
     0x03b5,
     0x03c6,
     0x03b3,
     0x03b7,
     0x03b9,
     0x03be,
     0x03ba,
     0x03bb,
     0x03bc,
     0x03bd,
     0x03bf,
     0x03c0,
     0x03ce,
     0x03c1,
     0x03c3,
     0x03c4,
     0x03b8,
     0x03c9,
     0x03c2,
     0x03c7,
     0x03c5,
     0x03b6,
     0x03ca,
     0x03cb,
     0x0390,
     0x03b0,
     0xfffd,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\x04",
     "\x05",
     "\x06",
     "\x07",
     "\x08",
     "\x09",
     "\x0a",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\x14",
     "\x15",
     "\x16",
     "\x17",
     "\x18",
     "\x19",
     "\x1a",
     "\x1b",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\x20",
     "\x21",
     "\x22",
     "\x23",
     "\x24",
     "\x25",
     "\x26",
     "\x27",
     "\x28",
     "\x29",
     "\x2a",
     "\x2b",
     "\x2c",
     "\x2d",
     "\x2e",
     "\x2f",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\x3a",
     "\x3b",
     "\x3c",
     "\x3d",
     "\x3e",
     "\x3f",
     "\x40",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\x5b",
     "\x5c",
     "\x5d",
     "\x5e",
     "\x5f",
     "\x60",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\x7b",
     "\x7c",
     "\x7d",
     "\x7e",
     "\x7f",
     "\xc3\x84",
     "\xc2\xb9",
     "\xc2\xb2",
     "\xc3\x89",
     "\xc2\xb3",
     "\xc3\x96",
     "\xc3\x9c",
     "\xce\x85",
     "\xc3\xa0",
     "\xc3\xa2",
     "\xc3\xa4",
     "\xce\x84",
     "\xc2\xa8",
     "\xc3\xa7",
     "\xc3\xa9",
     "\xc3\xa8",
     "\xc3\xaa",
     "\xc3\xab",
     "\xc2\xa3",
     "\xe2\x84\xa2",
     "\xc3\xae",
     "\xc3\xaf",
     "\xe2\x80\xa2",
     "\xc2\xbd",
     "\xe2\x80\xb0",
     "\xc3\xb4",
     "\xc3\xb6",
     "\xc2\xa6",
     "\xc2\xad",
     "\xc3\xb9",
     "\xc3\xbb",
     "\xc3\xbc",
     "\xe2\x80\xa0",
     "\xce\x93",
     "\xce\x94",
     "\xce\x98",
     "\xce\x9b",
     "\xce\x9e",
     "\xce\xa0",
     "\xc3\x9f",
     "\xc2\xae",
     "\xc2\xa9",
     "\xce\xa3",
     "\xce\xaa",
     "\xc2\xa7",
     "\xe2\x89\xa0",
     "\xc2\xb0",
     "\xce\x87",
     "\xce\x91",
     "\xc2\xb1",
     "\xe2\x89\xa4",
     "\xe2\x89\xa5",
     "\xc2\xa5",
     "\xce\x92",
     "\xce\x95",
     "\xce\x96",
     "\xce\x97",
     "\xce\x99",
     "\xce\x9a",
     "\xce\x9c",
     "\xce\xa6",
     "\xce\xab",
     "\xce\xa8",
     "\xce\xa9",
     "\xce\xac",
     "\xce\x9d",
     "\xc2\xac",
     "\xce\x9f",
     "\xce\xa1",
     "\xe2\x89\x88",
     "\xce\xa4",
     "\xc2\xab",
     "\xc2\xbb",
     "\xe2\x80\xa6",
     "\xc2\xa0",
     "\xce\xa5",
     "\xce\xa7",
     "\xce\x86",
     "\xce\x88",
     "\xc5\x93",
     "\xe2\x80\x93",
     "\xe2\x80\x95",
     "\xe2\x80\x9c",
     "\xe2\x80\x9d",
     "\xe2\x80\x98",
     "\xe2\x80\x99",
     "\xc3\xb7",
     "\xce\x89",
     "\xce\x8a",
     "\xce\x8c",
     "\xce\x8e",
     "\xce\xad",
     "\xce\xae",
     "\xce\xaf",
     "\xcf\x8c",
     "\xce\x8f",
     "\xcf\x8d",
     "\xce\xb1",
     "\xce\xb2",
     "\xcf\x88",
     "\xce\xb4",
     "\xce\xb5",
     "\xcf\x86",
     "\xce\xb3",
     "\xce\xb7",
     "\xce\xb9",
     "\xce\xbe",
     "\xce\xba",
     "\xce\xbb",
     "\xce\xbc",
     "\xce\xbd",
     "\xce\xbf",
     "\xcf\x80",
     "\xcf\x8e",
     "\xcf\x81",
     "\xcf\x83",
     "\xcf\x84",
     "\xce\xb8",
     "\xcf\x89",
     "\xcf\x82",
     "\xcf\x87",
     "\xcf\x85",
     "\xce\xb6",
     "\xcf\x8a",
     "\xcf\x8b",
     "\xce\x90",
     "\xce\xb0",
     "\xef\xbf\xbd",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x04",
     0x00000005 => "\x05",
     0x00000006 => "\x06",
     0x00000007 => "\x07",
     0x00000008 => "\x08",
     0x00000009 => "\x09",
     0x0000000a => "\x0a",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x14",
     0x00000015 => "\x15",
     0x00000016 => "\x16",
     0x00000017 => "\x17",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x1a",
     0x0000001b => "\x1b",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x20",
     0x00000021 => "\x21",
     0x00000022 => "\x22",
     0x00000023 => "\x23",
     0x00000024 => "\x24",
     0x00000025 => "\x25",
     0x00000026 => "\x26",
     0x00000027 => "\x27",
     0x00000028 => "\x28",
     0x00000029 => "\x29",
     0x0000002a => "\x2a",
     0x0000002b => "\x2b",
     0x0000002c => "\x2c",
     0x0000002d => "\x2d",
     0x0000002e => "\x2e",
     0x0000002f => "\x2f",
     0x00000030 => "\x30",
     0x00000031 => "\x31",
     0x00000032 => "\x32",
     0x00000033 => "\x33",
     0x00000034 => "\x34",
     0x00000035 => "\x35",
     0x00000036 => "\x36",
     0x00000037 => "\x37",
     0x00000038 => "\x38",
     0x00000039 => "\x39",
     0x0000003a => "\x3a",
     0x0000003b => "\x3b",
     0x0000003c => "\x3c",
     0x0000003d => "\x3d",
     0x0000003e => "\x3e",
     0x0000003f => "\x3f",
     0x00000040 => "\x40",
     0x00000041 => "\x41",
     0x00000042 => "\x42",
     0x00000043 => "\x43",
     0x00000044 => "\x44",
     0x00000045 => "\x45",
     0x00000046 => "\x46",
     0x00000047 => "\x47",
     0x00000048 => "\x48",
     0x00000049 => "\x49",
     0x0000004a => "\x4a",
     0x0000004b => "\x4b",
     0x0000004c => "\x4c",
     0x0000004d => "\x4d",
     0x0000004e => "\x4e",
     0x0000004f => "\x4f",
     0x00000050 => "\x50",
     0x00000051 => "\x51",
     0x00000052 => "\x52",
     0x00000053 => "\x53",
     0x00000054 => "\x54",
     0x00000055 => "\x55",
     0x00000056 => "\x56",
     0x00000057 => "\x57",
     0x00000058 => "\x58",
     0x00000059 => "\x59",
     0x0000005a => "\x5a",
     0x0000005b => "\x5b",
     0x0000005c => "\x5c",
     0x0000005d => "\x5d",
     0x0000005e => "\x5e",
     0x0000005f => "\x5f",
     0x00000060 => "\x60",
     0x00000061 => "\x61",
     0x00000062 => "\x62",
     0x00000063 => "\x63",
     0x00000064 => "\x64",
     0x00000065 => "\x65",
     0x00000066 => "\x66",
     0x00000067 => "\x67",
     0x00000068 => "\x68",
     0x00000069 => "\x69",
     0x0000006a => "\x6a",
     0x0000006b => "\x6b",
     0x0000006c => "\x6c",
     0x0000006d => "\x6d",
     0x0000006e => "\x6e",
     0x0000006f => "\x6f",
     0x00000070 => "\x70",
     0x00000071 => "\x71",
     0x00000072 => "\x72",
     0x00000073 => "\x73",
     0x00000074 => "\x74",
     0x00000075 => "\x75",
     0x00000076 => "\x76",
     0x00000077 => "\x77",
     0x00000078 => "\x78",
     0x00000079 => "\x79",
     0x0000007a => "\x7a",
     0x0000007b => "\x7b",
     0x0000007c => "\x7c",
     0x0000007d => "\x7d",
     0x0000007e => "\x7e",
     0x0000007f => "\x7f",
     0x000000a0 => "\xca",
     0x000000a3 => "\x92",
     0x000000a5 => "\xb4",
     0x000000a6 => "\x9b",
     0x000000a7 => "\xac",
     0x000000a8 => "\x8c",
     0x000000a9 => "\xa9",
     0x000000ab => "\xc7",
     0x000000ac => "\xc2",
     0x000000ad => "\x9c",
     0x000000ae => "\xa8",
     0x000000b0 => "\xae",
     0x000000b1 => "\xb1",
     0x000000b2 => "\x82",
     0x000000b3 => "\x84",
     0x000000b9 => "\x81",
     0x000000bb => "\xc8",
     0x000000bd => "\x97",
     0x000000c4 => "\x80",
     0x000000c9 => "\x83",
     0x000000d6 => "\x85",
     0x000000dc => "\x86",
     0x000000df => "\xa7",
     0x000000e0 => "\x88",
     0x000000e2 => "\x89",
     0x000000e4 => "\x8a",
     0x000000e7 => "\x8d",
     0x000000e8 => "\x8f",
     0x000000e9 => "\x8e",
     0x000000ea => "\x90",
     0x000000eb => "\x91",
     0x000000ee => "\x94",
     0x000000ef => "\x95",
     0x000000f4 => "\x99",
     0x000000f6 => "\x9a",
     0x000000f7 => "\xd6",
     0x000000f9 => "\x9d",
     0x000000fb => "\x9e",
     0x000000fc => "\x9f",
     0x00000153 => "\xcf",
     0x00000384 => "\x8b",
     0x00000385 => "\x87",
     0x00000386 => "\xcd",
     0x00000387 => "\xaf",
     0x00000388 => "\xce",
     0x00000389 => "\xd7",
     0x0000038a => "\xd8",
     0x0000038c => "\xd9",
     0x0000038e => "\xda",
     0x0000038f => "\xdf",
     0x00000390 => "\xfd",
     0x00000391 => "\xb0",
     0x00000392 => "\xb5",
     0x00000393 => "\xa1",
     0x00000394 => "\xa2",
     0x00000395 => "\xb6",
     0x00000396 => "\xb7",
     0x00000397 => "\xb8",
     0x00000398 => "\xa3",
     0x00000399 => "\xb9",
     0x0000039a => "\xba",
     0x0000039b => "\xa4",
     0x0000039c => "\xbb",
     0x0000039d => "\xc1",
     0x0000039e => "\xa5",
     0x0000039f => "\xc3",
     0x000003a0 => "\xa6",
     0x000003a1 => "\xc4",
     0x000003a3 => "\xaa",
     0x000003a4 => "\xc6",
     0x000003a5 => "\xcb",
     0x000003a6 => "\xbc",
     0x000003a7 => "\xcc",
     0x000003a8 => "\xbe",
     0x000003a9 => "\xbf",
     0x000003aa => "\xab",
     0x000003ab => "\xbd",
     0x000003ac => "\xc0",
     0x000003ad => "\xdb",
     0x000003ae => "\xdc",
     0x000003af => "\xdd",
     0x000003b0 => "\xfe",
     0x000003b1 => "\xe1",
     0x000003b2 => "\xe2",
     0x000003b3 => "\xe7",
     0x000003b4 => "\xe4",
     0x000003b5 => "\xe5",
     0x000003b6 => "\xfa",
     0x000003b7 => "\xe8",
     0x000003b8 => "\xf5",
     0x000003b9 => "\xe9",
     0x000003ba => "\xeb",
     0x000003bb => "\xec",
     0x000003bc => "\xed",
     0x000003bd => "\xee",
     0x000003be => "\xea",
     0x000003bf => "\xef",
     0x000003c0 => "\xf0",
     0x000003c1 => "\xf2",
     0x000003c2 => "\xf7",
     0x000003c3 => "\xf3",
     0x000003c4 => "\xf4",
     0x000003c5 => "\xf9",
     0x000003c6 => "\xe6",
     0x000003c7 => "\xf8",
     0x000003c8 => "\xe3",
     0x000003c9 => "\xf6",
     0x000003ca => "\xfb",
     0x000003cb => "\xfc",
     0x000003cc => "\xde",
     0x000003cd => "\xe0",
     0x000003ce => "\xf1",
     0x00002013 => "\xd0",
     0x00002015 => "\xd1",
     0x00002018 => "\xd4",
     0x00002019 => "\xd5",
     0x0000201c => "\xd2",
     0x0000201d => "\xd3",
     0x00002020 => "\xa0",
     0x00002022 => "\x96",
     0x00002026 => "\xc9",
     0x00002030 => "\x98",
     0x00002122 => "\x93",
     0x00002248 => "\xc5",
     0x00002260 => "\xad",
     0x00002264 => "\xb2",
     0x00002265 => "\xb3",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::MACGREEK - Conversion routines for MACGREEK
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for MACGREEK.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
 
  This charmap has been generated automatically from GNU libiconv
  conversions.
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  00000004 | END OF TRANSMISSION (EOT)
     05 |  00000005 | ENQUIRY (ENQ)
     06 |  00000006 | ACKNOWLEDGE (ACK)
     07 |  00000007 | BELL (BEL)
     08 |  00000008 | BACKSPACE (BS)
     09 |  00000009 | CHARACTER TABULATION (HT)
     0A |  0000000A | LINE FEED (LF)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  00000014 | DEVICE CONTROL FOUR (DC4)
     15 |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     16 |  00000016 | SYNCHRONOUS IDLE (SYN)
     17 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  0000001A | SUBSTITUTE (SUB)
     1B |  0000001B | ESCAPE (ESC)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000020 | SPACE
     21 |  00000021 | EXCLAMATION MARK
     22 |  00000022 | QUOTATION MARK
     23 |  00000023 | NUMBER SIGN
     24 |  00000024 | DOLLAR SIGN
     25 |  00000025 | PERCENT SIGN
     26 |  00000026 | AMPERSAND
     27 |  00000027 | APOSTROPHE
     28 |  00000028 | LEFT PARENTHESIS
     29 |  00000029 | RIGHT PARENTHESIS
     2A |  0000002A | ASTERISK
     2B |  0000002B | PLUS SIGN
     2C |  0000002C | COMMA
     2D |  0000002D | HYPHEN-MINUS
     2E |  0000002E | FULL STOP
     2F |  0000002F | SOLIDUS
     30 |  00000030 | DIGIT ZERO
     31 |  00000031 | DIGIT ONE
     32 |  00000032 | DIGIT TWO
     33 |  00000033 | DIGIT THREE
     34 |  00000034 | DIGIT FOUR
     35 |  00000035 | DIGIT FIVE
     36 |  00000036 | DIGIT SIX
     37 |  00000037 | DIGIT SEVEN
     38 |  00000038 | DIGIT EIGHT
     39 |  00000039 | DIGIT NINE
     3A |  0000003A | COLON
     3B |  0000003B | SEMICOLON
     3C |  0000003C | LESS-THAN SIGN
     3D |  0000003D | EQUALS SIGN
     3E |  0000003E | GREATER-THAN SIGN
     3F |  0000003F | QUESTION MARK
     40 |  00000040 | COMMERCIAL AT
     41 |  00000041 | LATIN CAPITAL LETTER A
     42 |  00000042 | LATIN CAPITAL LETTER B
     43 |  00000043 | LATIN CAPITAL LETTER C
     44 |  00000044 | LATIN CAPITAL LETTER D
     45 |  00000045 | LATIN CAPITAL LETTER E
     46 |  00000046 | LATIN CAPITAL LETTER F
     47 |  00000047 | LATIN CAPITAL LETTER G
     48 |  00000048 | LATIN CAPITAL LETTER H
     49 |  00000049 | LATIN CAPITAL LETTER I
     4A |  0000004A | LATIN CAPITAL LETTER J
     4B |  0000004B | LATIN CAPITAL LETTER K
     4C |  0000004C | LATIN CAPITAL LETTER L
     4D |  0000004D | LATIN CAPITAL LETTER M
     4E |  0000004E | LATIN CAPITAL LETTER N
     4F |  0000004F | LATIN CAPITAL LETTER O
     50 |  00000050 | LATIN CAPITAL LETTER P
     51 |  00000051 | LATIN CAPITAL LETTER Q
     52 |  00000052 | LATIN CAPITAL LETTER R
     53 |  00000053 | LATIN CAPITAL LETTER S
     54 |  00000054 | LATIN CAPITAL LETTER T
     55 |  00000055 | LATIN CAPITAL LETTER U
     56 |  00000056 | LATIN CAPITAL LETTER V
     57 |  00000057 | LATIN CAPITAL LETTER W
     58 |  00000058 | LATIN CAPITAL LETTER X
     59 |  00000059 | LATIN CAPITAL LETTER Y
     5A |  0000005A | LATIN CAPITAL LETTER Z
     5B |  0000005B | LEFT SQUARE BRACKET
     5C |  0000005C | REVERSE SOLIDUS
     5D |  0000005D | RIGHT SQUARE BRACKET
     5E |  0000005E | CIRCUMFLEX ACCENT
     5F |  0000005F | LOW LINE
     60 |  00000060 | GRAVE ACCENT
     61 |  00000061 | LATIN SMALL LETTER A
     62 |  00000062 | LATIN SMALL LETTER B
     63 |  00000063 | LATIN SMALL LETTER C
     64 |  00000064 | LATIN SMALL LETTER D
     65 |  00000065 | LATIN SMALL LETTER E
     66 |  00000066 | LATIN SMALL LETTER F
     67 |  00000067 | LATIN SMALL LETTER G
     68 |  00000068 | LATIN SMALL LETTER H
     69 |  00000069 | LATIN SMALL LETTER I
     6A |  0000006A | LATIN SMALL LETTER J
     6B |  0000006B | LATIN SMALL LETTER K
     6C |  0000006C | LATIN SMALL LETTER L
     6D |  0000006D | LATIN SMALL LETTER M
     6E |  0000006E | LATIN SMALL LETTER N
     6F |  0000006F | LATIN SMALL LETTER O
     70 |  00000070 | LATIN SMALL LETTER P
     71 |  00000071 | LATIN SMALL LETTER Q
     72 |  00000072 | LATIN SMALL LETTER R
     73 |  00000073 | LATIN SMALL LETTER S
     74 |  00000074 | LATIN SMALL LETTER T
     75 |  00000075 | LATIN SMALL LETTER U
     76 |  00000076 | LATIN SMALL LETTER V
     77 |  00000077 | LATIN SMALL LETTER W
     78 |  00000078 | LATIN SMALL LETTER X
     79 |  00000079 | LATIN SMALL LETTER Y
     7A |  0000007A | LATIN SMALL LETTER Z
     7B |  0000007B | LEFT CURLY BRACKET
     7C |  0000007C | VERTICAL LINE
     7D |  0000007D | RIGHT CURLY BRACKET
     7E |  0000007E | TILDE
     7F |  0000007F | DELETE (DEL)
     80 |  000000C4 | LATIN CAPITAL LETTER A WITH DIAERESIS
     81 |  000000B9 | SUPERSCRIPT ONE
     82 |  000000B2 | SUPERSCRIPT TWO
     83 |  000000C9 | LATIN CAPITAL LETTER E WITH ACUTE
     84 |  000000B3 | SUPERSCRIPT THREE
     85 |  000000D6 | LATIN CAPITAL LETTER O WITH DIAERESIS
     86 |  000000DC | LATIN CAPITAL LETTER U WITH DIAERESIS
     87 |  00000385 | GREEK DIALYTIKA TONOS
     88 |  000000E0 | LATIN SMALL LETTER A WITH GRAVE
     89 |  000000E2 | LATIN SMALL LETTER A WITH CIRCUMFLEX
     8A |  000000E4 | LATIN SMALL LETTER A WITH DIAERESIS
     8B |  00000384 | GREEK TONOS
     8C |  000000A8 | DIAERESIS
     8D |  000000E7 | LATIN SMALL LETTER C WITH CEDILLA
     8E |  000000E9 | LATIN SMALL LETTER E WITH ACUTE
     8F |  000000E8 | LATIN SMALL LETTER E WITH GRAVE
     90 |  000000EA | LATIN SMALL LETTER E WITH CIRCUMFLEX
     91 |  000000EB | LATIN SMALL LETTER E WITH DIAERESIS
     92 |  000000A3 | POUND SIGN
     93 |  00002122 | TRADE MARK SIGN
     94 |  000000EE | LATIN SMALL LETTER I WITH CIRCUMFLEX
     95 |  000000EF | LATIN SMALL LETTER I WITH DIAERESIS
     96 |  00002022 | BULLET
     97 |  000000BD | VULGAR FRACTION ONE HALF
     98 |  00002030 | PER MILLE SIGN
     99 |  000000F4 | LATIN SMALL LETTER O WITH CIRCUMFLEX
     9A |  000000F6 | LATIN SMALL LETTER O WITH DIAERESIS
     9B |  000000A6 | BROKEN BAR
     9C |  000000AD | SOFT HYPHEN
     9D |  000000F9 | LATIN SMALL LETTER U WITH GRAVE
     9E |  000000FB | LATIN SMALL LETTER U WITH CIRCUMFLEX
     9F |  000000FC | LATIN SMALL LETTER U WITH DIAERESIS
     A0 |  00002020 | DAGGER
     A1 |  00000393 | GREEK CAPITAL LETTER GAMMA
     A2 |  00000394 | GREEK CAPITAL LETTER DELTA
     A3 |  00000398 | GREEK CAPITAL LETTER THETA
     A4 |  0000039B | GREEK CAPITAL LETTER LAMDA
     A5 |  0000039E | GREEK CAPITAL LETTER XI
     A6 |  000003A0 | GREEK CAPITAL LETTER PI
     A7 |  000000DF | LATIN SMALL LETTER SHARP S
     A8 |  000000AE | REGISTERED SIGN
     A9 |  000000A9 | COPYRIGHT SIGN
     AA |  000003A3 | GREEK CAPITAL LETTER SIGMA
     AB |  000003AA | GREEK CAPITAL LETTER IOTA WITH DIALYTIKA
     AC |  000000A7 | SECTION SIGN
     AD |  00002260 | NOT EQUAL TO
     AE |  000000B0 | DEGREE SIGN
     AF |  00000387 | GREEK ANO TELEIA
     B0 |  00000391 | GREEK CAPITAL LETTER ALPHA
     B1 |  000000B1 | PLUS-MINUS SIGN
     B2 |  00002264 | LESS-THAN OR EQUAL TO
     B3 |  00002265 | GREATER-THAN OR EQUAL TO
     B4 |  000000A5 | YEN SIGN
     B5 |  00000392 | GREEK CAPITAL LETTER BETA
     B6 |  00000395 | GREEK CAPITAL LETTER EPSILON
     B7 |  00000396 | GREEK CAPITAL LETTER ZETA
     B8 |  00000397 | GREEK CAPITAL LETTER ETA
     B9 |  00000399 | GREEK CAPITAL LETTER IOTA
     BA |  0000039A | GREEK CAPITAL LETTER KAPPA
     BB |  0000039C | GREEK CAPITAL LETTER MU
     BC |  000003A6 | GREEK CAPITAL LETTER PHI
     BD |  000003AB | GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA
     BE |  000003A8 | GREEK CAPITAL LETTER PSI
     BF |  000003A9 | GREEK CAPITAL LETTER OMEGA
     C0 |  000003AC | GREEK SMALL LETTER ALPHA WITH TONOS
     C1 |  0000039D | GREEK CAPITAL LETTER NU
     C2 |  000000AC | NOT SIGN
     C3 |  0000039F | GREEK CAPITAL LETTER OMICRON
     C4 |  000003A1 | GREEK CAPITAL LETTER RHO
     C5 |  00002248 | ALMOST EQUAL TO
     C6 |  000003A4 | GREEK CAPITAL LETTER TAU
     C7 |  000000AB | LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
     C8 |  000000BB | RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
     C9 |  00002026 | HORIZONTAL ELLIPSIS
     CA |  000000A0 | NO-BREAK SPACE
     CB |  000003A5 | GREEK CAPITAL LETTER UPSILON
     CC |  000003A7 | GREEK CAPITAL LETTER CHI
     CD |  00000386 | GREEK CAPITAL LETTER ALPHA WITH TONOS
     CE |  00000388 | GREEK CAPITAL LETTER EPSILON WITH TONOS
     CF |  00000153 | LATIN SMALL LIGATURE OE
     D0 |  00002013 | EN DASH
     D1 |  00002015 | HORIZONTAL BAR
     D2 |  0000201C | LEFT DOUBLE QUOTATION MARK
     D3 |  0000201D | RIGHT DOUBLE QUOTATION MARK
     D4 |  00002018 | LEFT SINGLE QUOTATION MARK
     D5 |  00002019 | RIGHT SINGLE QUOTATION MARK
     D6 |  000000F7 | DIVISION SIGN
     D7 |  00000389 | GREEK CAPITAL LETTER ETA WITH TONOS
     D8 |  0000038A | GREEK CAPITAL LETTER IOTA WITH TONOS
     D9 |  0000038C | GREEK CAPITAL LETTER OMICRON WITH TONOS
     DA |  0000038E | GREEK CAPITAL LETTER UPSILON WITH TONOS
     DB |  000003AD | GREEK SMALL LETTER EPSILON WITH TONOS
     DC |  000003AE | GREEK SMALL LETTER ETA WITH TONOS
     DD |  000003AF | GREEK SMALL LETTER IOTA WITH TONOS
     DE |  000003CC | GREEK SMALL LETTER OMICRON WITH TONOS
     DF |  0000038F | GREEK CAPITAL LETTER OMEGA WITH TONOS
     E0 |  000003CD | GREEK SMALL LETTER UPSILON WITH TONOS
     E1 |  000003B1 | GREEK SMALL LETTER ALPHA
     E2 |  000003B2 | GREEK SMALL LETTER BETA
     E3 |  000003C8 | GREEK SMALL LETTER PSI
     E4 |  000003B4 | GREEK SMALL LETTER DELTA
     E5 |  000003B5 | GREEK SMALL LETTER EPSILON
     E6 |  000003C6 | GREEK SMALL LETTER PHI
     E7 |  000003B3 | GREEK SMALL LETTER GAMMA
     E8 |  000003B7 | GREEK SMALL LETTER ETA
     E9 |  000003B9 | GREEK SMALL LETTER IOTA
     EA |  000003BE | GREEK SMALL LETTER XI
     EB |  000003BA | GREEK SMALL LETTER KAPPA
     EC |  000003BB | GREEK SMALL LETTER LAMDA
     ED |  000003BC | GREEK SMALL LETTER MU
     EE |  000003BD | GREEK SMALL LETTER NU
     EF |  000003BF | GREEK SMALL LETTER OMICRON
     F0 |  000003C0 | GREEK SMALL LETTER PI
     F1 |  000003CE | GREEK SMALL LETTER OMEGA WITH TONOS
     F2 |  000003C1 | GREEK SMALL LETTER RHO
     F3 |  000003C3 | GREEK SMALL LETTER SIGMA
     F4 |  000003C4 | GREEK SMALL LETTER TAU
     F5 |  000003B8 | GREEK SMALL LETTER THETA
     F6 |  000003C9 | GREEK SMALL LETTER OMEGA
     F7 |  000003C2 | GREEK SMALL LETTER FINAL SIGMA
     F8 |  000003C7 | GREEK SMALL LETTER CHI
     F9 |  000003C5 | GREEK SMALL LETTER UPSILON
     FA |  000003B6 | GREEK SMALL LETTER ZETA
     FB |  000003CA | GREEK SMALL LETTER IOTA WITH DIALYTIKA
     FC |  000003CB | GREEK SMALL LETTER UPSILON WITH DIALYTIKA
     FD |  00000390 | GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS
     FE |  000003B0 | GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/MACHEBREW.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for MACHEBREW.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::MACHEBREW;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x0004,
     0x0005,
     0x0006,
     0x0007,
     0x0008,
     0x0009,
     0x000a,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x0014,
     0x0015,
     0x0016,
     0x0017,
     0x0018,
     0x0019,
     0x001a,
     0x001b,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0020,
     0x0021,
     0x0022,
     0x0023,
     0x0024,
     0x0025,
     0x0026,
     0x0027,
     0x0028,
     0x0029,
     0x002a,
     0x002b,
     0x002c,
     0x002d,
     0x002e,
     0x002f,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x003a,
     0x003b,
     0x003c,
     0x003d,
     0x003e,
     0x003f,
     0x0040,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x005b,
     0x005c,
     0x005d,
     0x005e,
     0x005f,
     0x0060,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x007b,
     0x007c,
     0x007d,
     0x007e,
     0x007f,
     0x00c4,
     0xfb1f,
     0x00c7,
     0x00c9,
     0x00d1,
     0x00d6,
     0x00dc,
     0x00e1,
     0x00e0,
     0x00e2,
     0x00e4,
     0x00e3,
     0x00e5,
     0x00e7,
     0x00e9,
     0x00e8,
     0x00ea,
     0x00eb,
     0x00ed,
     0x00ec,
     0x00ee,
     0x00ef,
     0x00f1,
     0x00f3,
     0x00f2,
     0x00f4,
     0x00f6,
     0x00f5,
     0x00fa,
     0x00f9,
     0x00fb,
     0x00fc,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x20aa,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x201e,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x05bc,
     0xfb4b,
     0xfb35,
     0x2026,
     0x00a0,
     0x05b8,
     0x05b7,
     0x05b5,
     0x05b6,
     0x05b4,
     0x2013,
     0x2014,
     0x201c,
     0x201d,
     0x2018,
     0x2019,
     0xfb2a,
     0xfb2b,
     0x05bf,
     0x05b0,
     0x05b2,
     0x05b1,
     0x05bb,
     0x05b9,
     0xfffd,
     0x05b3,
     0x05d0,
     0x05d1,
     0x05d2,
     0x05d3,
     0x05d4,
     0x05d5,
     0x05d6,
     0x05d7,
     0x05d8,
     0x05d9,
     0x05da,
     0x05db,
     0x05dc,
     0x05dd,
     0x05de,
     0x05df,
     0x05e0,
     0x05e1,
     0x05e2,
     0x05e3,
     0x05e4,
     0x05e5,
     0x05e6,
     0x05e7,
     0x05e8,
     0x05e9,
     0x05ea,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\x04",
     "\x05",
     "\x06",
     "\x07",
     "\x08",
     "\x09",
     "\x0a",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\x14",
     "\x15",
     "\x16",
     "\x17",
     "\x18",
     "\x19",
     "\x1a",
     "\x1b",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\x20",
     "\x21",
     "\x22",
     "\x23",
     "\x24",
     "\x25",
     "\x26",
     "\x27",
     "\x28",
     "\x29",
     "\x2a",
     "\x2b",
     "\x2c",
     "\x2d",
     "\x2e",
     "\x2f",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\x3a",
     "\x3b",
     "\x3c",
     "\x3d",
     "\x3e",
     "\x3f",
     "\x40",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\x5b",
     "\x5c",
     "\x5d",
     "\x5e",
     "\x5f",
     "\x60",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\x7b",
     "\x7c",
     "\x7d",
     "\x7e",
     "\x7f",
     "\xc3\x84",
     "\xef\xac\x9f",
     "\xc3\x87",
     "\xc3\x89",
     "\xc3\x91",
     "\xc3\x96",
     "\xc3\x9c",
     "\xc3\xa1",
     "\xc3\xa0",
     "\xc3\xa2",
     "\xc3\xa4",
     "\xc3\xa3",
     "\xc3\xa5",
     "\xc3\xa7",
     "\xc3\xa9",
     "\xc3\xa8",
     "\xc3\xaa",
     "\xc3\xab",
     "\xc3\xad",
     "\xc3\xac",
     "\xc3\xae",
     "\xc3\xaf",
     "\xc3\xb1",
     "\xc3\xb3",
     "\xc3\xb2",
     "\xc3\xb4",
     "\xc3\xb6",
     "\xc3\xb5",
     "\xc3\xba",
     "\xc3\xb9",
     "\xc3\xbb",
     "\xc3\xbc",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xe2\x82\xaa",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xe2\x80\x9e",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xd6\xbc",
     "\xef\xad\x8b",
     "\xef\xac\xb5",
     "\xe2\x80\xa6",
     "\xc2\xa0",
     "\xd6\xb8",
     "\xd6\xb7",
     "\xd6\xb5",
     "\xd6\xb6",
     "\xd6\xb4",
     "\xe2\x80\x93",
     "\xe2\x80\x94",
     "\xe2\x80\x9c",
     "\xe2\x80\x9d",
     "\xe2\x80\x98",
     "\xe2\x80\x99",
     "\xef\xac\xaa",
     "\xef\xac\xab",
     "\xd6\xbf",
     "\xd6\xb0",
     "\xd6\xb2",
     "\xd6\xb1",
     "\xd6\xbb",
     "\xd6\xb9",
     "\xef\xbf\xbd",
     "\xd6\xb3",
     "\xd7\x90",
     "\xd7\x91",
     "\xd7\x92",
     "\xd7\x93",
     "\xd7\x94",
     "\xd7\x95",
     "\xd7\x96",
     "\xd7\x97",
     "\xd7\x98",
     "\xd7\x99",
     "\xd7\x9a",
     "\xd7\x9b",
     "\xd7\x9c",
     "\xd7\x9d",
     "\xd7\x9e",
     "\xd7\x9f",
     "\xd7\xa0",
     "\xd7\xa1",
     "\xd7\xa2",
     "\xd7\xa3",
     "\xd7\xa4",
     "\xd7\xa5",
     "\xd7\xa6",
     "\xd7\xa7",
     "\xd7\xa8",
     "\xd7\xa9",
     "\xd7\xaa",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x04",
     0x00000005 => "\x05",
     0x00000006 => "\x06",
     0x00000007 => "\x07",
     0x00000008 => "\x08",
     0x00000009 => "\x09",
     0x0000000a => "\x0a",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x14",
     0x00000015 => "\x15",
     0x00000016 => "\x16",
     0x00000017 => "\x17",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x1a",
     0x0000001b => "\x1b",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x20",
     0x00000021 => "\x21",
     0x00000022 => "\x22",
     0x00000023 => "\x23",
     0x00000024 => "\x24",
     0x00000025 => "\x25",
     0x00000026 => "\x26",
     0x00000027 => "\x27",
     0x00000028 => "\x28",
     0x00000029 => "\x29",
     0x0000002a => "\x2a",
     0x0000002b => "\x2b",
     0x0000002c => "\x2c",
     0x0000002d => "\x2d",
     0x0000002e => "\x2e",
     0x0000002f => "\x2f",
     0x00000030 => "\x30",
     0x00000031 => "\x31",
     0x00000032 => "\x32",
     0x00000033 => "\x33",
     0x00000034 => "\x34",
     0x00000035 => "\x35",
     0x00000036 => "\x36",
     0x00000037 => "\x37",
     0x00000038 => "\x38",
     0x00000039 => "\x39",
     0x0000003a => "\x3a",
     0x0000003b => "\x3b",
     0x0000003c => "\x3c",
     0x0000003d => "\x3d",
     0x0000003e => "\x3e",
     0x0000003f => "\x3f",
     0x00000040 => "\x40",
     0x00000041 => "\x41",
     0x00000042 => "\x42",
     0x00000043 => "\x43",
     0x00000044 => "\x44",
     0x00000045 => "\x45",
     0x00000046 => "\x46",
     0x00000047 => "\x47",
     0x00000048 => "\x48",
     0x00000049 => "\x49",
     0x0000004a => "\x4a",
     0x0000004b => "\x4b",
     0x0000004c => "\x4c",
     0x0000004d => "\x4d",
     0x0000004e => "\x4e",
     0x0000004f => "\x4f",
     0x00000050 => "\x50",
     0x00000051 => "\x51",
     0x00000052 => "\x52",
     0x00000053 => "\x53",
     0x00000054 => "\x54",
     0x00000055 => "\x55",
     0x00000056 => "\x56",
     0x00000057 => "\x57",
     0x00000058 => "\x58",
     0x00000059 => "\x59",
     0x0000005a => "\x5a",
     0x0000005b => "\x5b",
     0x0000005c => "\x5c",
     0x0000005d => "\x5d",
     0x0000005e => "\x5e",
     0x0000005f => "\x5f",
     0x00000060 => "\x60",
     0x00000061 => "\x61",
     0x00000062 => "\x62",
     0x00000063 => "\x63",
     0x00000064 => "\x64",
     0x00000065 => "\x65",
     0x00000066 => "\x66",
     0x00000067 => "\x67",
     0x00000068 => "\x68",
     0x00000069 => "\x69",
     0x0000006a => "\x6a",
     0x0000006b => "\x6b",
     0x0000006c => "\x6c",
     0x0000006d => "\x6d",
     0x0000006e => "\x6e",
     0x0000006f => "\x6f",
     0x00000070 => "\x70",
     0x00000071 => "\x71",
     0x00000072 => "\x72",
     0x00000073 => "\x73",
     0x00000074 => "\x74",
     0x00000075 => "\x75",
     0x00000076 => "\x76",
     0x00000077 => "\x77",
     0x00000078 => "\x78",
     0x00000079 => "\x79",
     0x0000007a => "\x7a",
     0x0000007b => "\x7b",
     0x0000007c => "\x7c",
     0x0000007d => "\x7d",
     0x0000007e => "\x7e",
     0x0000007f => "\x7f",
     0x000000a0 => "\xca",
     0x000000c4 => "\x80",
     0x000000c7 => "\x82",
     0x000000c9 => "\x83",
     0x000000d1 => "\x84",
     0x000000d6 => "\x85",
     0x000000dc => "\x86",
     0x000000e0 => "\x88",
     0x000000e1 => "\x87",
     0x000000e2 => "\x89",
     0x000000e3 => "\x8b",
     0x000000e4 => "\x8a",
     0x000000e5 => "\x8c",
     0x000000e7 => "\x8d",
     0x000000e8 => "\x8f",
     0x000000e9 => "\x8e",
     0x000000ea => "\x90",
     0x000000eb => "\x91",
     0x000000ec => "\x93",
     0x000000ed => "\x92",
     0x000000ee => "\x94",
     0x000000ef => "\x95",
     0x000000f1 => "\x96",
     0x000000f2 => "\x98",
     0x000000f3 => "\x97",
     0x000000f4 => "\x99",
     0x000000f5 => "\x9b",
     0x000000f6 => "\x9a",
     0x000000f9 => "\x9d",
     0x000000fa => "\x9c",
     0x000000fb => "\x9e",
     0x000000fc => "\x9f",
     0x000005b0 => "\xd9",
     0x000005b1 => "\xdb",
     0x000005b2 => "\xda",
     0x000005b3 => "\xdf",
     0x000005b4 => "\xcf",
     0x000005b5 => "\xcd",
     0x000005b6 => "\xce",
     0x000005b7 => "\xcc",
     0x000005b8 => "\xcb",
     0x000005b9 => "\xdd",
     0x000005bb => "\xdc",
     0x000005bc => "\xc6",
     0x000005bf => "\xd8",
     0x000005d0 => "\xe0",
     0x000005d1 => "\xe1",
     0x000005d2 => "\xe2",
     0x000005d3 => "\xe3",
     0x000005d4 => "\xe4",
     0x000005d5 => "\xe5",
     0x000005d6 => "\xe6",
     0x000005d7 => "\xe7",
     0x000005d8 => "\xe8",
     0x000005d9 => "\xe9",
     0x000005da => "\xea",
     0x000005db => "\xeb",
     0x000005dc => "\xec",
     0x000005dd => "\xed",
     0x000005de => "\xee",
     0x000005df => "\xef",
     0x000005e0 => "\xf0",
     0x000005e1 => "\xf1",
     0x000005e2 => "\xf2",
     0x000005e3 => "\xf3",
     0x000005e4 => "\xf4",
     0x000005e5 => "\xf5",
     0x000005e6 => "\xf6",
     0x000005e7 => "\xf7",
     0x000005e8 => "\xf8",
     0x000005e9 => "\xf9",
     0x000005ea => "\xfa",
     0x00002013 => "\xd0",
     0x00002014 => "\xd1",
     0x00002018 => "\xd4",
     0x00002019 => "\xd5",
     0x0000201c => "\xd2",
     0x0000201d => "\xd3",
     0x0000201e => "\xc1",
     0x00002026 => "\xc9",
     0x000020aa => "\xa6",
     0x0000fb1f => "\x81",
     0x0000fb2a => "\xd6",
     0x0000fb2b => "\xd7",
     0x0000fb35 => "\xc8",
     0x0000fb4b => "\xc7",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::MACHEBREW - Conversion routines for MACHEBREW
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for MACHEBREW.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
 
  This charmap has been generated automatically from GNU libiconv
  conversions.
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  00000004 | END OF TRANSMISSION (EOT)
     05 |  00000005 | ENQUIRY (ENQ)
     06 |  00000006 | ACKNOWLEDGE (ACK)
     07 |  00000007 | BELL (BEL)
     08 |  00000008 | BACKSPACE (BS)
     09 |  00000009 | CHARACTER TABULATION (HT)
     0A |  0000000A | LINE FEED (LF)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  00000014 | DEVICE CONTROL FOUR (DC4)
     15 |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     16 |  00000016 | SYNCHRONOUS IDLE (SYN)
     17 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  0000001A | SUBSTITUTE (SUB)
     1B |  0000001B | ESCAPE (ESC)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000020 | SPACE
     21 |  00000021 | EXCLAMATION MARK
     22 |  00000022 | QUOTATION MARK
     23 |  00000023 | NUMBER SIGN
     24 |  00000024 | DOLLAR SIGN
     25 |  00000025 | PERCENT SIGN
     26 |  00000026 | AMPERSAND
     27 |  00000027 | APOSTROPHE
     28 |  00000028 | LEFT PARENTHESIS
     29 |  00000029 | RIGHT PARENTHESIS
     2A |  0000002A | ASTERISK
     2B |  0000002B | PLUS SIGN
     2C |  0000002C | COMMA
     2D |  0000002D | HYPHEN-MINUS
     2E |  0000002E | FULL STOP
     2F |  0000002F | SOLIDUS
     30 |  00000030 | DIGIT ZERO
     31 |  00000031 | DIGIT ONE
     32 |  00000032 | DIGIT TWO
     33 |  00000033 | DIGIT THREE
     34 |  00000034 | DIGIT FOUR
     35 |  00000035 | DIGIT FIVE
     36 |  00000036 | DIGIT SIX
     37 |  00000037 | DIGIT SEVEN
     38 |  00000038 | DIGIT EIGHT
     39 |  00000039 | DIGIT NINE
     3A |  0000003A | COLON
     3B |  0000003B | SEMICOLON
     3C |  0000003C | LESS-THAN SIGN
     3D |  0000003D | EQUALS SIGN
     3E |  0000003E | GREATER-THAN SIGN
     3F |  0000003F | QUESTION MARK
     40 |  00000040 | COMMERCIAL AT
     41 |  00000041 | LATIN CAPITAL LETTER A
     42 |  00000042 | LATIN CAPITAL LETTER B
     43 |  00000043 | LATIN CAPITAL LETTER C
     44 |  00000044 | LATIN CAPITAL LETTER D
     45 |  00000045 | LATIN CAPITAL LETTER E
     46 |  00000046 | LATIN CAPITAL LETTER F
     47 |  00000047 | LATIN CAPITAL LETTER G
     48 |  00000048 | LATIN CAPITAL LETTER H
     49 |  00000049 | LATIN CAPITAL LETTER I
     4A |  0000004A | LATIN CAPITAL LETTER J
     4B |  0000004B | LATIN CAPITAL LETTER K
     4C |  0000004C | LATIN CAPITAL LETTER L
     4D |  0000004D | LATIN CAPITAL LETTER M
     4E |  0000004E | LATIN CAPITAL LETTER N
     4F |  0000004F | LATIN CAPITAL LETTER O
     50 |  00000050 | LATIN CAPITAL LETTER P
     51 |  00000051 | LATIN CAPITAL LETTER Q
     52 |  00000052 | LATIN CAPITAL LETTER R
     53 |  00000053 | LATIN CAPITAL LETTER S
     54 |  00000054 | LATIN CAPITAL LETTER T
     55 |  00000055 | LATIN CAPITAL LETTER U
     56 |  00000056 | LATIN CAPITAL LETTER V
     57 |  00000057 | LATIN CAPITAL LETTER W
     58 |  00000058 | LATIN CAPITAL LETTER X
     59 |  00000059 | LATIN CAPITAL LETTER Y
     5A |  0000005A | LATIN CAPITAL LETTER Z
     5B |  0000005B | LEFT SQUARE BRACKET
     5C |  0000005C | REVERSE SOLIDUS
     5D |  0000005D | RIGHT SQUARE BRACKET
     5E |  0000005E | CIRCUMFLEX ACCENT
     5F |  0000005F | LOW LINE
     60 |  00000060 | GRAVE ACCENT
     61 |  00000061 | LATIN SMALL LETTER A
     62 |  00000062 | LATIN SMALL LETTER B
     63 |  00000063 | LATIN SMALL LETTER C
     64 |  00000064 | LATIN SMALL LETTER D
     65 |  00000065 | LATIN SMALL LETTER E
     66 |  00000066 | LATIN SMALL LETTER F
     67 |  00000067 | LATIN SMALL LETTER G
     68 |  00000068 | LATIN SMALL LETTER H
     69 |  00000069 | LATIN SMALL LETTER I
     6A |  0000006A | LATIN SMALL LETTER J
     6B |  0000006B | LATIN SMALL LETTER K
     6C |  0000006C | LATIN SMALL LETTER L
     6D |  0000006D | LATIN SMALL LETTER M
     6E |  0000006E | LATIN SMALL LETTER N
     6F |  0000006F | LATIN SMALL LETTER O
     70 |  00000070 | LATIN SMALL LETTER P
     71 |  00000071 | LATIN SMALL LETTER Q
     72 |  00000072 | LATIN SMALL LETTER R
     73 |  00000073 | LATIN SMALL LETTER S
     74 |  00000074 | LATIN SMALL LETTER T
     75 |  00000075 | LATIN SMALL LETTER U
     76 |  00000076 | LATIN SMALL LETTER V
     77 |  00000077 | LATIN SMALL LETTER W
     78 |  00000078 | LATIN SMALL LETTER X
     79 |  00000079 | LATIN SMALL LETTER Y
     7A |  0000007A | LATIN SMALL LETTER Z
     7B |  0000007B | LEFT CURLY BRACKET
     7C |  0000007C | VERTICAL LINE
     7D |  0000007D | RIGHT CURLY BRACKET
     7E |  0000007E | TILDE
     7F |  0000007F | DELETE (DEL)
     80 |  000000C4 | LATIN CAPITAL LETTER A WITH DIAERESIS
     81 |  0000FB1F | HEBREW LIGATURE YIDDISH YOD YOD PATAH
     82 |  000000C7 | LATIN CAPITAL LETTER C WITH CEDILLA
     83 |  000000C9 | LATIN CAPITAL LETTER E WITH ACUTE
     84 |  000000D1 | LATIN CAPITAL LETTER N WITH TILDE
     85 |  000000D6 | LATIN CAPITAL LETTER O WITH DIAERESIS
     86 |  000000DC | LATIN CAPITAL LETTER U WITH DIAERESIS
     87 |  000000E1 | LATIN SMALL LETTER A WITH ACUTE
     88 |  000000E0 | LATIN SMALL LETTER A WITH GRAVE
     89 |  000000E2 | LATIN SMALL LETTER A WITH CIRCUMFLEX
     8A |  000000E4 | LATIN SMALL LETTER A WITH DIAERESIS
     8B |  000000E3 | LATIN SMALL LETTER A WITH TILDE
     8C |  000000E5 | LATIN SMALL LETTER A WITH RING ABOVE
     8D |  000000E7 | LATIN SMALL LETTER C WITH CEDILLA
     8E |  000000E9 | LATIN SMALL LETTER E WITH ACUTE
     8F |  000000E8 | LATIN SMALL LETTER E WITH GRAVE
     90 |  000000EA | LATIN SMALL LETTER E WITH CIRCUMFLEX
     91 |  000000EB | LATIN SMALL LETTER E WITH DIAERESIS
     92 |  000000ED | LATIN SMALL LETTER I WITH ACUTE
     93 |  000000EC | LATIN SMALL LETTER I WITH GRAVE
     94 |  000000EE | LATIN SMALL LETTER I WITH CIRCUMFLEX
     95 |  000000EF | LATIN SMALL LETTER I WITH DIAERESIS
     96 |  000000F1 | LATIN SMALL LETTER N WITH TILDE
     97 |  000000F3 | LATIN SMALL LETTER O WITH ACUTE
     98 |  000000F2 | LATIN SMALL LETTER O WITH GRAVE
     99 |  000000F4 | LATIN SMALL LETTER O WITH CIRCUMFLEX
     9A |  000000F6 | LATIN SMALL LETTER O WITH DIAERESIS
     9B |  000000F5 | LATIN SMALL LETTER O WITH TILDE
     9C |  000000FA | LATIN SMALL LETTER U WITH ACUTE
     9D |  000000F9 | LATIN SMALL LETTER U WITH GRAVE
     9E |  000000FB | LATIN SMALL LETTER U WITH CIRCUMFLEX
     9F |  000000FC | LATIN SMALL LETTER U WITH DIAERESIS
     A6 |  000020AA | NEW SHEQEL SIGN
     C1 |  0000201E | DOUBLE LOW-9 QUOTATION MARK
     C6 |  000005BC | HEBREW POINT DAGESH OR MAPIQ
     C7 |  0000FB4B | HEBREW LETTER VAV WITH HOLAM
     C8 |  0000FB35 | HEBREW LETTER VAV WITH DAGESH
     C9 |  00002026 | HORIZONTAL ELLIPSIS
     CA |  000000A0 | NO-BREAK SPACE
     CB |  000005B8 | HEBREW POINT QAMATS
     CC |  000005B7 | HEBREW POINT PATAH
     CD |  000005B5 | HEBREW POINT TSERE
     CE |  000005B6 | HEBREW POINT SEGOL
     CF |  000005B4 | HEBREW POINT HIRIQ
     D0 |  00002013 | EN DASH
     D1 |  00002014 | EM DASH
     D2 |  0000201C | LEFT DOUBLE QUOTATION MARK
     D3 |  0000201D | RIGHT DOUBLE QUOTATION MARK
     D4 |  00002018 | LEFT SINGLE QUOTATION MARK
     D5 |  00002019 | RIGHT SINGLE QUOTATION MARK
     D6 |  0000FB2A | HEBREW LETTER SHIN WITH SHIN DOT
     D7 |  0000FB2B | HEBREW LETTER SHIN WITH SIN DOT
     D8 |  000005BF | HEBREW POINT RAFE
     D9 |  000005B0 | HEBREW POINT SHEVA
     DA |  000005B2 | HEBREW POINT HATAF PATAH
     DB |  000005B1 | HEBREW POINT HATAF SEGOL
     DC |  000005BB | HEBREW POINT QUBUTS
     DD |  000005B9 | HEBREW POINT HOLAM
     DF |  000005B3 | HEBREW POINT HATAF QAMATS
     E0 |  000005D0 | HEBREW LETTER ALEF
     E1 |  000005D1 | HEBREW LETTER BET
     E2 |  000005D2 | HEBREW LETTER GIMEL
     E3 |  000005D3 | HEBREW LETTER DALET
     E4 |  000005D4 | HEBREW LETTER HE
     E5 |  000005D5 | HEBREW LETTER VAV
     E6 |  000005D6 | HEBREW LETTER ZAYIN
     E7 |  000005D7 | HEBREW LETTER HET
     E8 |  000005D8 | HEBREW LETTER TET
     E9 |  000005D9 | HEBREW LETTER YOD
     EA |  000005DA | HEBREW LETTER FINAL KAF
     EB |  000005DB | HEBREW LETTER KAF
     EC |  000005DC | HEBREW LETTER LAMED
     ED |  000005DD | HEBREW LETTER FINAL MEM
     EE |  000005DE | HEBREW LETTER MEM
     EF |  000005DF | HEBREW LETTER FINAL NUN
     F0 |  000005E0 | HEBREW LETTER NUN
     F1 |  000005E1 | HEBREW LETTER SAMEKH
     F2 |  000005E2 | HEBREW LETTER AYIN
     F3 |  000005E3 | HEBREW LETTER FINAL PE
     F4 |  000005E4 | HEBREW LETTER PE
     F5 |  000005E5 | HEBREW LETTER FINAL TSADI
     F6 |  000005E6 | HEBREW LETTER TSADI
     F7 |  000005E7 | HEBREW LETTER QOF
     F8 |  000005E8 | HEBREW LETTER RESH
     F9 |  000005E9 | HEBREW LETTER SHIN
     FA |  000005EA | HEBREW LETTER TAV
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/MACICELAND.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for MACICELAND.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::MACICELAND;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x0004,
     0x0005,
     0x0006,
     0x0007,
     0x0008,
     0x0009,
     0x000a,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x0014,
     0x0015,
     0x0016,
     0x0017,
     0x0018,
     0x0019,
     0x001a,
     0x001b,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0020,
     0x0021,
     0x0022,
     0x0023,
     0x0024,
     0x0025,
     0x0026,
     0x0027,
     0x0028,
     0x0029,
     0x002a,
     0x002b,
     0x002c,
     0x002d,
     0x002e,
     0x002f,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x003a,
     0x003b,
     0x003c,
     0x003d,
     0x003e,
     0x003f,
     0x0040,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x005b,
     0x005c,
     0x005d,
     0x005e,
     0x005f,
     0x0060,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x007b,
     0x007c,
     0x007d,
     0x007e,
     0x007f,
     0x00c4,
     0x00c5,
     0x00c7,
     0x00c9,
     0x00d1,
     0x00d6,
     0x00dc,
     0x00e1,
     0x00e0,
     0x00e2,
     0x00e4,
     0x00e3,
     0x00e5,
     0x00e7,
     0x00e9,
     0x00e8,
     0x00ea,
     0x00eb,
     0x00ed,
     0x00ec,
     0x00ee,
     0x00ef,
     0x00f1,
     0x00f3,
     0x00f2,
     0x00f4,
     0x00f6,
     0x00f5,
     0x00fa,
     0x00f9,
     0x00fb,
     0x00fc,
     0x00dd,
     0x00b0,
     0x00a2,
     0x00a3,
     0x00a7,
     0x2022,
     0x00b6,
     0x00df,
     0x00ae,
     0x00a9,
     0x2122,
     0x00b4,
     0x00a8,
     0x2260,
     0x00c6,
     0x00d8,
     0x221e,
     0x00b1,
     0x2264,
     0x2265,
     0x00a5,
     0x00b5,
     0x2202,
     0x2211,
     0x220f,
     0x03c0,
     0x222b,
     0x00aa,
     0x00ba,
     0x2126,
     0x00e6,
     0x00f8,
     0x00bf,
     0x00a1,
     0x00ac,
     0x221a,
     0x0192,
     0x2248,
     0x2206,
     0x00ab,
     0x00bb,
     0x2026,
     0x00a0,
     0x00c0,
     0x00c3,
     0x00d5,
     0x0152,
     0x0153,
     0x2013,
     0x2014,
     0x201c,
     0x201d,
     0x2018,
     0x2019,
     0x00f7,
     0x25ca,
     0x00ff,
     0x0178,
     0x2044,
     0x00a4,
     0x00d0,
     0x00f0,
     0x00de,
     0x00fe,
     0x00fd,
     0x00b7,
     0x201a,
     0x201e,
     0x2030,
     0x00c2,
     0x00ca,
     0x00c1,
     0x00cb,
     0x00c8,
     0x00cd,
     0x00ce,
     0x00cf,
     0x00cc,
     0x00d3,
     0x00d4,
     0xfffd,
     0x00d2,
     0x00da,
     0x00db,
     0x00d9,
     0x0131,
     0x02c6,
     0x02dc,
     0x00af,
     0x02d8,
     0x02d9,
     0x02da,
     0x00b8,
     0x02dd,
     0x02db,
     0x02c7,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\x04",
     "\x05",
     "\x06",
     "\x07",
     "\x08",
     "\x09",
     "\x0a",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\x14",
     "\x15",
     "\x16",
     "\x17",
     "\x18",
     "\x19",
     "\x1a",
     "\x1b",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\x20",
     "\x21",
     "\x22",
     "\x23",
     "\x24",
     "\x25",
     "\x26",
     "\x27",
     "\x28",
     "\x29",
     "\x2a",
     "\x2b",
     "\x2c",
     "\x2d",
     "\x2e",
     "\x2f",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\x3a",
     "\x3b",
     "\x3c",
     "\x3d",
     "\x3e",
     "\x3f",
     "\x40",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\x5b",
     "\x5c",
     "\x5d",
     "\x5e",
     "\x5f",
     "\x60",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\x7b",
     "\x7c",
     "\x7d",
     "\x7e",
     "\x7f",
     "\xc3\x84",
     "\xc3\x85",
     "\xc3\x87",
     "\xc3\x89",
     "\xc3\x91",
     "\xc3\x96",
     "\xc3\x9c",
     "\xc3\xa1",
     "\xc3\xa0",
     "\xc3\xa2",
     "\xc3\xa4",
     "\xc3\xa3",
     "\xc3\xa5",
     "\xc3\xa7",
     "\xc3\xa9",
     "\xc3\xa8",
     "\xc3\xaa",
     "\xc3\xab",
     "\xc3\xad",
     "\xc3\xac",
     "\xc3\xae",
     "\xc3\xaf",
     "\xc3\xb1",
     "\xc3\xb3",
     "\xc3\xb2",
     "\xc3\xb4",
     "\xc3\xb6",
     "\xc3\xb5",
     "\xc3\xba",
     "\xc3\xb9",
     "\xc3\xbb",
     "\xc3\xbc",
     "\xc3\x9d",
     "\xc2\xb0",
     "\xc2\xa2",
     "\xc2\xa3",
     "\xc2\xa7",
     "\xe2\x80\xa2",
     "\xc2\xb6",
     "\xc3\x9f",
     "\xc2\xae",
     "\xc2\xa9",
     "\xe2\x84\xa2",
     "\xc2\xb4",
     "\xc2\xa8",
     "\xe2\x89\xa0",
     "\xc3\x86",
     "\xc3\x98",
     "\xe2\x88\x9e",
     "\xc2\xb1",
     "\xe2\x89\xa4",
     "\xe2\x89\xa5",
     "\xc2\xa5",
     "\xc2\xb5",
     "\xe2\x88\x82",
     "\xe2\x88\x91",
     "\xe2\x88\x8f",
     "\xcf\x80",
     "\xe2\x88\xab",
     "\xc2\xaa",
     "\xc2\xba",
     "\xe2\x84\xa6",
     "\xc3\xa6",
     "\xc3\xb8",
     "\xc2\xbf",
     "\xc2\xa1",
     "\xc2\xac",
     "\xe2\x88\x9a",
     "\xc6\x92",
     "\xe2\x89\x88",
     "\xe2\x88\x86",
     "\xc2\xab",
     "\xc2\xbb",
     "\xe2\x80\xa6",
     "\xc2\xa0",
     "\xc3\x80",
     "\xc3\x83",
     "\xc3\x95",
     "\xc5\x92",
     "\xc5\x93",
     "\xe2\x80\x93",
     "\xe2\x80\x94",
     "\xe2\x80\x9c",
     "\xe2\x80\x9d",
     "\xe2\x80\x98",
     "\xe2\x80\x99",
     "\xc3\xb7",
     "\xe2\x97\x8a",
     "\xc3\xbf",
     "\xc5\xb8",
     "\xe2\x81\x84",
     "\xc2\xa4",
     "\xc3\x90",
     "\xc3\xb0",
     "\xc3\x9e",
     "\xc3\xbe",
     "\xc3\xbd",
     "\xc2\xb7",
     "\xe2\x80\x9a",
     "\xe2\x80\x9e",
     "\xe2\x80\xb0",
     "\xc3\x82",
     "\xc3\x8a",
     "\xc3\x81",
     "\xc3\x8b",
     "\xc3\x88",
     "\xc3\x8d",
     "\xc3\x8e",
     "\xc3\x8f",
     "\xc3\x8c",
     "\xc3\x93",
     "\xc3\x94",
     "\xef\xbf\xbd",
     "\xc3\x92",
     "\xc3\x9a",
     "\xc3\x9b",
     "\xc3\x99",
     "\xc4\xb1",
     "\xcb\x86",
     "\xcb\x9c",
     "\xc2\xaf",
     "\xcb\x98",
     "\xcb\x99",
     "\xcb\x9a",
     "\xc2\xb8",
     "\xcb\x9d",
     "\xcb\x9b",
     "\xcb\x87",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x04",
     0x00000005 => "\x05",
     0x00000006 => "\x06",
     0x00000007 => "\x07",
     0x00000008 => "\x08",
     0x00000009 => "\x09",
     0x0000000a => "\x0a",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x14",
     0x00000015 => "\x15",
     0x00000016 => "\x16",
     0x00000017 => "\x17",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x1a",
     0x0000001b => "\x1b",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x20",
     0x00000021 => "\x21",
     0x00000022 => "\x22",
     0x00000023 => "\x23",
     0x00000024 => "\x24",
     0x00000025 => "\x25",
     0x00000026 => "\x26",
     0x00000027 => "\x27",
     0x00000028 => "\x28",
     0x00000029 => "\x29",
     0x0000002a => "\x2a",
     0x0000002b => "\x2b",
     0x0000002c => "\x2c",
     0x0000002d => "\x2d",
     0x0000002e => "\x2e",
     0x0000002f => "\x2f",
     0x00000030 => "\x30",
     0x00000031 => "\x31",
     0x00000032 => "\x32",
     0x00000033 => "\x33",
     0x00000034 => "\x34",
     0x00000035 => "\x35",
     0x00000036 => "\x36",
     0x00000037 => "\x37",
     0x00000038 => "\x38",
     0x00000039 => "\x39",
     0x0000003a => "\x3a",
     0x0000003b => "\x3b",
     0x0000003c => "\x3c",
     0x0000003d => "\x3d",
     0x0000003e => "\x3e",
     0x0000003f => "\x3f",
     0x00000040 => "\x40",
     0x00000041 => "\x41",
     0x00000042 => "\x42",
     0x00000043 => "\x43",
     0x00000044 => "\x44",
     0x00000045 => "\x45",
     0x00000046 => "\x46",
     0x00000047 => "\x47",
     0x00000048 => "\x48",
     0x00000049 => "\x49",
     0x0000004a => "\x4a",
     0x0000004b => "\x4b",
     0x0000004c => "\x4c",
     0x0000004d => "\x4d",
     0x0000004e => "\x4e",
     0x0000004f => "\x4f",
     0x00000050 => "\x50",
     0x00000051 => "\x51",
     0x00000052 => "\x52",
     0x00000053 => "\x53",
     0x00000054 => "\x54",
     0x00000055 => "\x55",
     0x00000056 => "\x56",
     0x00000057 => "\x57",
     0x00000058 => "\x58",
     0x00000059 => "\x59",
     0x0000005a => "\x5a",
     0x0000005b => "\x5b",
     0x0000005c => "\x5c",
     0x0000005d => "\x5d",
     0x0000005e => "\x5e",
     0x0000005f => "\x5f",
     0x00000060 => "\x60",
     0x00000061 => "\x61",
     0x00000062 => "\x62",
     0x00000063 => "\x63",
     0x00000064 => "\x64",
     0x00000065 => "\x65",
     0x00000066 => "\x66",
     0x00000067 => "\x67",
     0x00000068 => "\x68",
     0x00000069 => "\x69",
     0x0000006a => "\x6a",
     0x0000006b => "\x6b",
     0x0000006c => "\x6c",
     0x0000006d => "\x6d",
     0x0000006e => "\x6e",
     0x0000006f => "\x6f",
     0x00000070 => "\x70",
     0x00000071 => "\x71",
     0x00000072 => "\x72",
     0x00000073 => "\x73",
     0x00000074 => "\x74",
     0x00000075 => "\x75",
     0x00000076 => "\x76",
     0x00000077 => "\x77",
     0x00000078 => "\x78",
     0x00000079 => "\x79",
     0x0000007a => "\x7a",
     0x0000007b => "\x7b",
     0x0000007c => "\x7c",
     0x0000007d => "\x7d",
     0x0000007e => "\x7e",
     0x0000007f => "\x7f",
     0x000000a0 => "\xca",
     0x000000a1 => "\xc1",
     0x000000a2 => "\xa2",
     0x000000a3 => "\xa3",
     0x000000a4 => "\xdb",
     0x000000a5 => "\xb4",
     0x000000a7 => "\xa4",
     0x000000a8 => "\xac",
     0x000000a9 => "\xa9",
     0x000000aa => "\xbb",
     0x000000ab => "\xc7",
     0x000000ac => "\xc2",
     0x000000ae => "\xa8",
     0x000000af => "\xf8",
     0x000000b0 => "\xa1",
     0x000000b1 => "\xb1",
     0x000000b4 => "\xab",
     0x000000b5 => "\xb5",
     0x000000b6 => "\xa6",
     0x000000b7 => "\xe1",
     0x000000b8 => "\xfc",
     0x000000ba => "\xbc",
     0x000000bb => "\xc8",
     0x000000bf => "\xc0",
     0x000000c0 => "\xcb",
     0x000000c1 => "\xe7",
     0x000000c2 => "\xe5",
     0x000000c3 => "\xcc",
     0x000000c4 => "\x80",
     0x000000c5 => "\x81",
     0x000000c6 => "\xae",
     0x000000c7 => "\x82",
     0x000000c8 => "\xe9",
     0x000000c9 => "\x83",
     0x000000ca => "\xe6",
     0x000000cb => "\xe8",
     0x000000cc => "\xed",
     0x000000cd => "\xea",
     0x000000ce => "\xeb",
     0x000000cf => "\xec",
     0x000000d0 => "\xdc",
     0x000000d1 => "\x84",
     0x000000d2 => "\xf1",
     0x000000d3 => "\xee",
     0x000000d4 => "\xef",
     0x000000d5 => "\xcd",
     0x000000d6 => "\x85",
     0x000000d8 => "\xaf",
     0x000000d9 => "\xf4",
     0x000000da => "\xf2",
     0x000000db => "\xf3",
     0x000000dc => "\x86",
     0x000000dd => "\xa0",
     0x000000de => "\xde",
     0x000000df => "\xa7",
     0x000000e0 => "\x88",
     0x000000e1 => "\x87",
     0x000000e2 => "\x89",
     0x000000e3 => "\x8b",
     0x000000e4 => "\x8a",
     0x000000e5 => "\x8c",
     0x000000e6 => "\xbe",
     0x000000e7 => "\x8d",
     0x000000e8 => "\x8f",
     0x000000e9 => "\x8e",
     0x000000ea => "\x90",
     0x000000eb => "\x91",
     0x000000ec => "\x93",
     0x000000ed => "\x92",
     0x000000ee => "\x94",
     0x000000ef => "\x95",
     0x000000f0 => "\xdd",
     0x000000f1 => "\x96",
     0x000000f2 => "\x98",
     0x000000f3 => "\x97",
     0x000000f4 => "\x99",
     0x000000f5 => "\x9b",
     0x000000f6 => "\x9a",
     0x000000f7 => "\xd6",
     0x000000f8 => "\xbf",
     0x000000f9 => "\x9d",
     0x000000fa => "\x9c",
     0x000000fb => "\x9e",
     0x000000fc => "\x9f",
     0x000000fd => "\xe0",
     0x000000fe => "\xdf",
     0x000000ff => "\xd8",
     0x00000131 => "\xf5",
     0x00000152 => "\xce",
     0x00000153 => "\xcf",
     0x00000178 => "\xd9",
     0x00000192 => "\xc4",
     0x000002c6 => "\xf6",
     0x000002c7 => "\xff",
     0x000002d8 => "\xf9",
     0x000002d9 => "\xfa",
     0x000002da => "\xfb",
     0x000002db => "\xfe",
     0x000002dc => "\xf7",
     0x000002dd => "\xfd",
     0x000003c0 => "\xb9",
     0x00002013 => "\xd0",
     0x00002014 => "\xd1",
     0x00002018 => "\xd4",
     0x00002019 => "\xd5",
     0x0000201a => "\xe2",
     0x0000201c => "\xd2",
     0x0000201d => "\xd3",
     0x0000201e => "\xe3",
     0x00002022 => "\xa5",
     0x00002026 => "\xc9",
     0x00002030 => "\xe4",
     0x00002044 => "\xda",
     0x00002122 => "\xaa",
     0x00002126 => "\xbd",
     0x00002202 => "\xb6",
     0x00002206 => "\xc6",
     0x0000220f => "\xb8",
     0x00002211 => "\xb7",
     0x0000221a => "\xc3",
     0x0000221e => "\xb0",
     0x0000222b => "\xba",
     0x00002248 => "\xc5",
     0x00002260 => "\xad",
     0x00002264 => "\xb2",
     0x00002265 => "\xb3",
     0x000025ca => "\xd7",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::MACICELAND - Conversion routines for MACICELAND
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for MACICELAND.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
 
  This charmap has been generated automatically from GNU libiconv
  conversions.
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  00000004 | END OF TRANSMISSION (EOT)
     05 |  00000005 | ENQUIRY (ENQ)
     06 |  00000006 | ACKNOWLEDGE (ACK)
     07 |  00000007 | BELL (BEL)
     08 |  00000008 | BACKSPACE (BS)
     09 |  00000009 | CHARACTER TABULATION (HT)
     0A |  0000000A | LINE FEED (LF)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  00000014 | DEVICE CONTROL FOUR (DC4)
     15 |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     16 |  00000016 | SYNCHRONOUS IDLE (SYN)
     17 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  0000001A | SUBSTITUTE (SUB)
     1B |  0000001B | ESCAPE (ESC)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000020 | SPACE
     21 |  00000021 | EXCLAMATION MARK
     22 |  00000022 | QUOTATION MARK
     23 |  00000023 | NUMBER SIGN
     24 |  00000024 | DOLLAR SIGN
     25 |  00000025 | PERCENT SIGN
     26 |  00000026 | AMPERSAND
     27 |  00000027 | APOSTROPHE
     28 |  00000028 | LEFT PARENTHESIS
     29 |  00000029 | RIGHT PARENTHESIS
     2A |  0000002A | ASTERISK
     2B |  0000002B | PLUS SIGN
     2C |  0000002C | COMMA
     2D |  0000002D | HYPHEN-MINUS
     2E |  0000002E | FULL STOP
     2F |  0000002F | SOLIDUS
     30 |  00000030 | DIGIT ZERO
     31 |  00000031 | DIGIT ONE
     32 |  00000032 | DIGIT TWO
     33 |  00000033 | DIGIT THREE
     34 |  00000034 | DIGIT FOUR
     35 |  00000035 | DIGIT FIVE
     36 |  00000036 | DIGIT SIX
     37 |  00000037 | DIGIT SEVEN
     38 |  00000038 | DIGIT EIGHT
     39 |  00000039 | DIGIT NINE
     3A |  0000003A | COLON
     3B |  0000003B | SEMICOLON
     3C |  0000003C | LESS-THAN SIGN
     3D |  0000003D | EQUALS SIGN
     3E |  0000003E | GREATER-THAN SIGN
     3F |  0000003F | QUESTION MARK
     40 |  00000040 | COMMERCIAL AT
     41 |  00000041 | LATIN CAPITAL LETTER A
     42 |  00000042 | LATIN CAPITAL LETTER B
     43 |  00000043 | LATIN CAPITAL LETTER C
     44 |  00000044 | LATIN CAPITAL LETTER D
     45 |  00000045 | LATIN CAPITAL LETTER E
     46 |  00000046 | LATIN CAPITAL LETTER F
     47 |  00000047 | LATIN CAPITAL LETTER G
     48 |  00000048 | LATIN CAPITAL LETTER H
     49 |  00000049 | LATIN CAPITAL LETTER I
     4A |  0000004A | LATIN CAPITAL LETTER J
     4B |  0000004B | LATIN CAPITAL LETTER K
     4C |  0000004C | LATIN CAPITAL LETTER L
     4D |  0000004D | LATIN CAPITAL LETTER M
     4E |  0000004E | LATIN CAPITAL LETTER N
     4F |  0000004F | LATIN CAPITAL LETTER O
     50 |  00000050 | LATIN CAPITAL LETTER P
     51 |  00000051 | LATIN CAPITAL LETTER Q
     52 |  00000052 | LATIN CAPITAL LETTER R
     53 |  00000053 | LATIN CAPITAL LETTER S
     54 |  00000054 | LATIN CAPITAL LETTER T
     55 |  00000055 | LATIN CAPITAL LETTER U
     56 |  00000056 | LATIN CAPITAL LETTER V
     57 |  00000057 | LATIN CAPITAL LETTER W
     58 |  00000058 | LATIN CAPITAL LETTER X
     59 |  00000059 | LATIN CAPITAL LETTER Y
     5A |  0000005A | LATIN CAPITAL LETTER Z
     5B |  0000005B | LEFT SQUARE BRACKET
     5C |  0000005C | REVERSE SOLIDUS
     5D |  0000005D | RIGHT SQUARE BRACKET
     5E |  0000005E | CIRCUMFLEX ACCENT
     5F |  0000005F | LOW LINE
     60 |  00000060 | GRAVE ACCENT
     61 |  00000061 | LATIN SMALL LETTER A
     62 |  00000062 | LATIN SMALL LETTER B
     63 |  00000063 | LATIN SMALL LETTER C
     64 |  00000064 | LATIN SMALL LETTER D
     65 |  00000065 | LATIN SMALL LETTER E
     66 |  00000066 | LATIN SMALL LETTER F
     67 |  00000067 | LATIN SMALL LETTER G
     68 |  00000068 | LATIN SMALL LETTER H
     69 |  00000069 | LATIN SMALL LETTER I
     6A |  0000006A | LATIN SMALL LETTER J
     6B |  0000006B | LATIN SMALL LETTER K
     6C |  0000006C | LATIN SMALL LETTER L
     6D |  0000006D | LATIN SMALL LETTER M
     6E |  0000006E | LATIN SMALL LETTER N
     6F |  0000006F | LATIN SMALL LETTER O
     70 |  00000070 | LATIN SMALL LETTER P
     71 |  00000071 | LATIN SMALL LETTER Q
     72 |  00000072 | LATIN SMALL LETTER R
     73 |  00000073 | LATIN SMALL LETTER S
     74 |  00000074 | LATIN SMALL LETTER T
     75 |  00000075 | LATIN SMALL LETTER U
     76 |  00000076 | LATIN SMALL LETTER V
     77 |  00000077 | LATIN SMALL LETTER W
     78 |  00000078 | LATIN SMALL LETTER X
     79 |  00000079 | LATIN SMALL LETTER Y
     7A |  0000007A | LATIN SMALL LETTER Z
     7B |  0000007B | LEFT CURLY BRACKET
     7C |  0000007C | VERTICAL LINE
     7D |  0000007D | RIGHT CURLY BRACKET
     7E |  0000007E | TILDE
     7F |  0000007F | DELETE (DEL)
     80 |  000000C4 | LATIN CAPITAL LETTER A WITH DIAERESIS
     81 |  000000C5 | LATIN CAPITAL LETTER A WITH RING ABOVE
     82 |  000000C7 | LATIN CAPITAL LETTER C WITH CEDILLA
     83 |  000000C9 | LATIN CAPITAL LETTER E WITH ACUTE
     84 |  000000D1 | LATIN CAPITAL LETTER N WITH TILDE
     85 |  000000D6 | LATIN CAPITAL LETTER O WITH DIAERESIS
     86 |  000000DC | LATIN CAPITAL LETTER U WITH DIAERESIS
     87 |  000000E1 | LATIN SMALL LETTER A WITH ACUTE
     88 |  000000E0 | LATIN SMALL LETTER A WITH GRAVE
     89 |  000000E2 | LATIN SMALL LETTER A WITH CIRCUMFLEX
     8A |  000000E4 | LATIN SMALL LETTER A WITH DIAERESIS
     8B |  000000E3 | LATIN SMALL LETTER A WITH TILDE
     8C |  000000E5 | LATIN SMALL LETTER A WITH RING ABOVE
     8D |  000000E7 | LATIN SMALL LETTER C WITH CEDILLA
     8E |  000000E9 | LATIN SMALL LETTER E WITH ACUTE
     8F |  000000E8 | LATIN SMALL LETTER E WITH GRAVE
     90 |  000000EA | LATIN SMALL LETTER E WITH CIRCUMFLEX
     91 |  000000EB | LATIN SMALL LETTER E WITH DIAERESIS
     92 |  000000ED | LATIN SMALL LETTER I WITH ACUTE
     93 |  000000EC | LATIN SMALL LETTER I WITH GRAVE
     94 |  000000EE | LATIN SMALL LETTER I WITH CIRCUMFLEX
     95 |  000000EF | LATIN SMALL LETTER I WITH DIAERESIS
     96 |  000000F1 | LATIN SMALL LETTER N WITH TILDE
     97 |  000000F3 | LATIN SMALL LETTER O WITH ACUTE
     98 |  000000F2 | LATIN SMALL LETTER O WITH GRAVE
     99 |  000000F4 | LATIN SMALL LETTER O WITH CIRCUMFLEX
     9A |  000000F6 | LATIN SMALL LETTER O WITH DIAERESIS
     9B |  000000F5 | LATIN SMALL LETTER O WITH TILDE
     9C |  000000FA | LATIN SMALL LETTER U WITH ACUTE
     9D |  000000F9 | LATIN SMALL LETTER U WITH GRAVE
     9E |  000000FB | LATIN SMALL LETTER U WITH CIRCUMFLEX
     9F |  000000FC | LATIN SMALL LETTER U WITH DIAERESIS
     A0 |  000000DD | LATIN CAPITAL LETTER Y WITH ACUTE
     A1 |  000000B0 | DEGREE SIGN
     A2 |  000000A2 | CENT SIGN
     A3 |  000000A3 | POUND SIGN
     A4 |  000000A7 | SECTION SIGN
     A5 |  00002022 | BULLET
     A6 |  000000B6 | PILCROW SIGN
     A7 |  000000DF | LATIN SMALL LETTER SHARP S
     A8 |  000000AE | REGISTERED SIGN
     A9 |  000000A9 | COPYRIGHT SIGN
     AA |  00002122 | TRADE MARK SIGN
     AB |  000000B4 | ACUTE ACCENT
     AC |  000000A8 | DIAERESIS
     AD |  00002260 | NOT EQUAL TO
     AE |  000000C6 | LATIN CAPITAL LETTER AE
     AF |  000000D8 | LATIN CAPITAL LETTER O WITH STROKE
     B0 |  0000221E | INFINITY
     B1 |  000000B1 | PLUS-MINUS SIGN
     B2 |  00002264 | LESS-THAN OR EQUAL TO
     B3 |  00002265 | GREATER-THAN OR EQUAL TO
     B4 |  000000A5 | YEN SIGN
     B5 |  000000B5 | MICRO SIGN
     B6 |  00002202 | PARTIAL DIFFERENTIAL
     B7 |  00002211 | N-ARY SUMMATION
     B8 |  0000220F | N-ARY PRODUCT
     B9 |  000003C0 | GREEK SMALL LETTER PI
     BA |  0000222B | INTEGRAL
     BB |  000000AA | FEMININE ORDINAL INDICATOR
     BC |  000000BA | MASCULINE ORDINAL INDICATOR
     BD |  00002126 | OHM SIGN
     BE |  000000E6 | LATIN SMALL LETTER AE
     BF |  000000F8 | LATIN SMALL LETTER O WITH STROKE
     C0 |  000000BF | INVERTED QUESTION MARK
     C1 |  000000A1 | INVERTED EXCLAMATION MARK
     C2 |  000000AC | NOT SIGN
     C3 |  0000221A | SQUARE ROOT
     C4 |  00000192 | LATIN SMALL LETTER F WITH HOOK
     C5 |  00002248 | ALMOST EQUAL TO
     C6 |  00002206 | INCREMENT
     C7 |  000000AB | LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
     C8 |  000000BB | RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
     C9 |  00002026 | HORIZONTAL ELLIPSIS
     CA |  000000A0 | NO-BREAK SPACE
     CB |  000000C0 | LATIN CAPITAL LETTER A WITH GRAVE
     CC |  000000C3 | LATIN CAPITAL LETTER A WITH TILDE
     CD |  000000D5 | LATIN CAPITAL LETTER O WITH TILDE
     CE |  00000152 | LATIN CAPITAL LIGATURE OE
     CF |  00000153 | LATIN SMALL LIGATURE OE
     D0 |  00002013 | EN DASH
     D1 |  00002014 | EM DASH
     D2 |  0000201C | LEFT DOUBLE QUOTATION MARK
     D3 |  0000201D | RIGHT DOUBLE QUOTATION MARK
     D4 |  00002018 | LEFT SINGLE QUOTATION MARK
     D5 |  00002019 | RIGHT SINGLE QUOTATION MARK
     D6 |  000000F7 | DIVISION SIGN
     D7 |  000025CA | LOZENGE
     D8 |  000000FF | LATIN SMALL LETTER Y WITH DIAERESIS
     D9 |  00000178 | LATIN CAPITAL LETTER Y WITH DIAERESIS
     DA |  00002044 | FRACTION SLASH
     DB |  000000A4 | CURRENCY SIGN
     DC |  000000D0 | LATIN CAPITAL LETTER ETH
     DD |  000000F0 | LATIN SMALL LETTER ETH
     DE |  000000DE | LATIN CAPITAL LETTER THORN
     DF |  000000FE | LATIN SMALL LETTER THORN
     E0 |  000000FD | LATIN SMALL LETTER Y WITH ACUTE
     E1 |  000000B7 | MIDDLE DOT
     E2 |  0000201A | SINGLE LOW-9 QUOTATION MARK
     E3 |  0000201E | DOUBLE LOW-9 QUOTATION MARK
     E4 |  00002030 | PER MILLE SIGN
     E5 |  000000C2 | LATIN CAPITAL LETTER A WITH CIRCUMFLEX
     E6 |  000000CA | LATIN CAPITAL LETTER E WITH CIRCUMFLEX
     E7 |  000000C1 | LATIN CAPITAL LETTER A WITH ACUTE
     E8 |  000000CB | LATIN CAPITAL LETTER E WITH DIAERESIS
     E9 |  000000C8 | LATIN CAPITAL LETTER E WITH GRAVE
     EA |  000000CD | LATIN CAPITAL LETTER I WITH ACUTE
     EB |  000000CE | LATIN CAPITAL LETTER I WITH CIRCUMFLEX
     EC |  000000CF | LATIN CAPITAL LETTER I WITH DIAERESIS
     ED |  000000CC | LATIN CAPITAL LETTER I WITH GRAVE
     EE |  000000D3 | LATIN CAPITAL LETTER O WITH ACUTE
     EF |  000000D4 | LATIN CAPITAL LETTER O WITH CIRCUMFLEX
     F1 |  000000D2 | LATIN CAPITAL LETTER O WITH GRAVE
     F2 |  000000DA | LATIN CAPITAL LETTER U WITH ACUTE
     F3 |  000000DB | LATIN CAPITAL LETTER U WITH CIRCUMFLEX
     F4 |  000000D9 | LATIN CAPITAL LETTER U WITH GRAVE
     F5 |  00000131 | LATIN SMALL LETTER DOTLESS I
     F6 |  000002C6 | MODIFIER LETTER CIRCUMFLEX ACCENT
     F7 |  000002DC | SMALL TILDE
     F8 |  000000AF | MACRON
     F9 |  000002D8 | BREVE
     FA |  000002D9 | DOT ABOVE
     FB |  000002DA | RING ABOVE
     FC |  000000B8 | CEDILLA
     FD |  000002DD | DOUBLE ACUTE ACCENT
     FE |  000002DB | OGONEK
     FF |  000002C7 | CARON
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/MACINTOSH.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for MACINTOSH.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::MACINTOSH;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x0004,
     0x0005,
     0x0006,
     0x0007,
     0x0008,
     0x0009,
     0x000a,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x0014,
     0x0015,
     0x0016,
     0x0017,
     0x0018,
     0x0019,
     0x001a,
     0x001b,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0020,
     0x0021,
     0x0022,
     0x0023,
     0x0024,
     0x0025,
     0x0026,
     0x0027,
     0x0028,
     0x0029,
     0x002a,
     0x002b,
     0x002c,
     0x002d,
     0x002e,
     0x002f,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x003a,
     0x003b,
     0x003c,
     0x003d,
     0x003e,
     0x003f,
     0x0040,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x005b,
     0x005c,
     0x005d,
     0x005e,
     0x005f,
     0x0060,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x007b,
     0x007c,
     0x007d,
     0x007e,
     0x007f,
     0x00c4,
     0x00c5,
     0x00c7,
     0x00c9,
     0x00d1,
     0x00d6,
     0x00dc,
     0x00e1,
     0x00e0,
     0x00e2,
     0x00e4,
     0x00e3,
     0x00e5,
     0x00e7,
     0x00e9,
     0x00e8,
     0x00ea,
     0x00eb,
     0x00ed,
     0x00ec,
     0x00ee,
     0x00ef,
     0x00f1,
     0x00f3,
     0x00f2,
     0x00f4,
     0x00f6,
     0x00f5,
     0x00fa,
     0x00f9,
     0x00fb,
     0x00fc,
     0x2020,
     0x00b0,
     0x00a2,
     0x00a3,
     0x00a7,
     0x2022,
     0x00b6,
     0x00df,
     0x00ae,
     0x00a9,
     0x2122,
     0x00b4,
     0x00a8,
     0x2260,
     0x00c6,
     0x00d8,
     0x221e,
     0x00b1,
     0x2264,
     0x2265,
     0x00a5,
     0x00b5,
     0x2202,
     0x2211,
     0x220f,
     0x03c0,
     0x222b,
     0x00aa,
     0x00ba,
     0x03a9,
     0x00e6,
     0x00f8,
     0x00bf,
     0x00a1,
     0x00ac,
     0x221a,
     0x0192,
     0x2248,
     0x0394,
     0x00ab,
     0x00bb,
     0x2026,
     0x00a0,
     0x00c0,
     0x00c3,
     0x00d5,
     0x0152,
     0x0153,
     0x2013,
     0x2014,
     0x201c,
     0x201d,
     0x2018,
     0x2019,
     0x00f7,
     0x25ca,
     0x00ff,
     0x0178,
     0x2044,
     0x20ac,
     0x2039,
     0x203a,
     0xfb01,
     0xfb02,
     0x2021,
     0x00b7,
     0x201a,
     0x201e,
     0x2030,
     0x00c2,
     0x00ca,
     0x00c1,
     0x00cb,
     0x00c8,
     0x00cd,
     0x00ce,
     0x00cf,
     0x00cc,
     0x00d3,
     0x00d4,
     0xe01e,
     0x00d2,
     0x00da,
     0x00db,
     0x00d9,
     0x0131,
     0x02c6,
     0x02dc,
     0x00af,
     0x02d8,
     0x02d9,
     0x02da,
     0x00b8,
     0x02dd,
     0x02db,
     0x02c7,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\x04",
     "\x05",
     "\x06",
     "\x07",
     "\x08",
     "\x09",
     "\x0a",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\x14",
     "\x15",
     "\x16",
     "\x17",
     "\x18",
     "\x19",
     "\x1a",
     "\x1b",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\x20",
     "\x21",
     "\x22",
     "\x23",
     "\x24",
     "\x25",
     "\x26",
     "\x27",
     "\x28",
     "\x29",
     "\x2a",
     "\x2b",
     "\x2c",
     "\x2d",
     "\x2e",
     "\x2f",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\x3a",
     "\x3b",
     "\x3c",
     "\x3d",
     "\x3e",
     "\x3f",
     "\x40",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\x5b",
     "\x5c",
     "\x5d",
     "\x5e",
     "\x5f",
     "\x60",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\x7b",
     "\x7c",
     "\x7d",
     "\x7e",
     "\x7f",
     "\xc3\x84",
     "\xc3\x85",
     "\xc3\x87",
     "\xc3\x89",
     "\xc3\x91",
     "\xc3\x96",
     "\xc3\x9c",
     "\xc3\xa1",
     "\xc3\xa0",
     "\xc3\xa2",
     "\xc3\xa4",
     "\xc3\xa3",
     "\xc3\xa5",
     "\xc3\xa7",
     "\xc3\xa9",
     "\xc3\xa8",
     "\xc3\xaa",
     "\xc3\xab",
     "\xc3\xad",
     "\xc3\xac",
     "\xc3\xae",
     "\xc3\xaf",
     "\xc3\xb1",
     "\xc3\xb3",
     "\xc3\xb2",
     "\xc3\xb4",
     "\xc3\xb6",
     "\xc3\xb5",
     "\xc3\xba",
     "\xc3\xb9",
     "\xc3\xbb",
     "\xc3\xbc",
     "\xe2\x80\xa0",
     "\xc2\xb0",
     "\xc2\xa2",
     "\xc2\xa3",
     "\xc2\xa7",
     "\xe2\x80\xa2",
     "\xc2\xb6",
     "\xc3\x9f",
     "\xc2\xae",
     "\xc2\xa9",
     "\xe2\x84\xa2",
     "\xc2\xb4",
     "\xc2\xa8",
     "\xe2\x89\xa0",
     "\xc3\x86",
     "\xc3\x98",
     "\xe2\x88\x9e",
     "\xc2\xb1",
     "\xe2\x89\xa4",
     "\xe2\x89\xa5",
     "\xc2\xa5",
     "\xc2\xb5",
     "\xe2\x88\x82",
     "\xe2\x88\x91",
     "\xe2\x88\x8f",
     "\xcf\x80",
     "\xe2\x88\xab",
     "\xc2\xaa",
     "\xc2\xba",
     "\xce\xa9",
     "\xc3\xa6",
     "\xc3\xb8",
     "\xc2\xbf",
     "\xc2\xa1",
     "\xc2\xac",
     "\xe2\x88\x9a",
     "\xc6\x92",
     "\xe2\x89\x88",
     "\xce\x94",
     "\xc2\xab",
     "\xc2\xbb",
     "\xe2\x80\xa6",
     "\xc2\xa0",
     "\xc3\x80",
     "\xc3\x83",
     "\xc3\x95",
     "\xc5\x92",
     "\xc5\x93",
     "\xe2\x80\x93",
     "\xe2\x80\x94",
     "\xe2\x80\x9c",
     "\xe2\x80\x9d",
     "\xe2\x80\x98",
     "\xe2\x80\x99",
     "\xc3\xb7",
     "\xe2\x97\x8a",
     "\xc3\xbf",
     "\xc5\xb8",
     "\xe2\x81\x84",
     "\xe2\x82\xac",
     "\xe2\x80\xb9",
     "\xe2\x80\xba",
     "\xef\xac\x81",
     "\xef\xac\x82",
     "\xe2\x80\xa1",
     "\xc2\xb7",
     "\xe2\x80\x9a",
     "\xe2\x80\x9e",
     "\xe2\x80\xb0",
     "\xc3\x82",
     "\xc3\x8a",
     "\xc3\x81",
     "\xc3\x8b",
     "\xc3\x88",
     "\xc3\x8d",
     "\xc3\x8e",
     "\xc3\x8f",
     "\xc3\x8c",
     "\xc3\x93",
     "\xc3\x94",
     "\xee\x80\x9e",
     "\xc3\x92",
     "\xc3\x9a",
     "\xc3\x9b",
     "\xc3\x99",
     "\xc4\xb1",
     "\xcb\x86",
     "\xcb\x9c",
     "\xc2\xaf",
     "\xcb\x98",
     "\xcb\x99",
     "\xcb\x9a",
     "\xc2\xb8",
     "\xcb\x9d",
     "\xcb\x9b",
     "\xcb\x87",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x04",
     0x00000005 => "\x05",
     0x00000006 => "\x06",
     0x00000007 => "\x07",
     0x00000008 => "\x08",
     0x00000009 => "\x09",
     0x0000000a => "\x0a",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x14",
     0x00000015 => "\x15",
     0x00000016 => "\x16",
     0x00000017 => "\x17",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x1a",
     0x0000001b => "\x1b",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x20",
     0x00000021 => "\x21",
     0x00000022 => "\x22",
     0x00000023 => "\x23",
     0x00000024 => "\x24",
     0x00000025 => "\x25",
     0x00000026 => "\x26",
     0x00000027 => "\x27",
     0x00000028 => "\x28",
     0x00000029 => "\x29",
     0x0000002a => "\x2a",
     0x0000002b => "\x2b",
     0x0000002c => "\x2c",
     0x0000002d => "\x2d",
     0x0000002e => "\x2e",
     0x0000002f => "\x2f",
     0x00000030 => "\x30",
     0x00000031 => "\x31",
     0x00000032 => "\x32",
     0x00000033 => "\x33",
     0x00000034 => "\x34",
     0x00000035 => "\x35",
     0x00000036 => "\x36",
     0x00000037 => "\x37",
     0x00000038 => "\x38",
     0x00000039 => "\x39",
     0x0000003a => "\x3a",
     0x0000003b => "\x3b",
     0x0000003c => "\x3c",
     0x0000003d => "\x3d",
     0x0000003e => "\x3e",
     0x0000003f => "\x3f",
     0x00000040 => "\x40",
     0x00000041 => "\x41",
     0x00000042 => "\x42",
     0x00000043 => "\x43",
     0x00000044 => "\x44",
     0x00000045 => "\x45",
     0x00000046 => "\x46",
     0x00000047 => "\x47",
     0x00000048 => "\x48",
     0x00000049 => "\x49",
     0x0000004a => "\x4a",
     0x0000004b => "\x4b",
     0x0000004c => "\x4c",
     0x0000004d => "\x4d",
     0x0000004e => "\x4e",
     0x0000004f => "\x4f",
     0x00000050 => "\x50",
     0x00000051 => "\x51",
     0x00000052 => "\x52",
     0x00000053 => "\x53",
     0x00000054 => "\x54",
     0x00000055 => "\x55",
     0x00000056 => "\x56",
     0x00000057 => "\x57",
     0x00000058 => "\x58",
     0x00000059 => "\x59",
     0x0000005a => "\x5a",
     0x0000005b => "\x5b",
     0x0000005c => "\x5c",
     0x0000005d => "\x5d",
     0x0000005e => "\x5e",
     0x0000005f => "\x5f",
     0x00000060 => "\x60",
     0x00000061 => "\x61",
     0x00000062 => "\x62",
     0x00000063 => "\x63",
     0x00000064 => "\x64",
     0x00000065 => "\x65",
     0x00000066 => "\x66",
     0x00000067 => "\x67",
     0x00000068 => "\x68",
     0x00000069 => "\x69",
     0x0000006a => "\x6a",
     0x0000006b => "\x6b",
     0x0000006c => "\x6c",
     0x0000006d => "\x6d",
     0x0000006e => "\x6e",
     0x0000006f => "\x6f",
     0x00000070 => "\x70",
     0x00000071 => "\x71",
     0x00000072 => "\x72",
     0x00000073 => "\x73",
     0x00000074 => "\x74",
     0x00000075 => "\x75",
     0x00000076 => "\x76",
     0x00000077 => "\x77",
     0x00000078 => "\x78",
     0x00000079 => "\x79",
     0x0000007a => "\x7a",
     0x0000007b => "\x7b",
     0x0000007c => "\x7c",
     0x0000007d => "\x7d",
     0x0000007e => "\x7e",
     0x0000007f => "\x7f",
     0x000000a0 => "\xca",
     0x000000a1 => "\xc1",
     0x000000a2 => "\xa2",
     0x000000a3 => "\xa3",
     0x000000a5 => "\xb4",
     0x000000a7 => "\xa4",
     0x000000a8 => "\xac",
     0x000000a9 => "\xa9",
     0x000000aa => "\xbb",
     0x000000ab => "\xc7",
     0x000000ac => "\xc2",
     0x000000ae => "\xa8",
     0x000000af => "\xf8",
     0x000000b0 => "\xa1",
     0x000000b1 => "\xb1",
     0x000000b4 => "\xab",
     0x000000b5 => "\xb5",
     0x000000b6 => "\xa6",
     0x000000b7 => "\xe1",
     0x000000b8 => "\xfc",
     0x000000ba => "\xbc",
     0x000000bb => "\xc8",
     0x000000bf => "\xc0",
     0x000000c0 => "\xcb",
     0x000000c1 => "\xe7",
     0x000000c2 => "\xe5",
     0x000000c3 => "\xcc",
     0x000000c4 => "\x80",
     0x000000c5 => "\x81",
     0x000000c6 => "\xae",
     0x000000c7 => "\x82",
     0x000000c8 => "\xe9",
     0x000000c9 => "\x83",
     0x000000ca => "\xe6",
     0x000000cb => "\xe8",
     0x000000cc => "\xed",
     0x000000cd => "\xea",
     0x000000ce => "\xeb",
     0x000000cf => "\xec",
     0x000000d1 => "\x84",
     0x000000d2 => "\xf1",
     0x000000d3 => "\xee",
     0x000000d4 => "\xef",
     0x000000d5 => "\xcd",
     0x000000d6 => "\x85",
     0x000000d8 => "\xaf",
     0x000000d9 => "\xf4",
     0x000000da => "\xf2",
     0x000000db => "\xf3",
     0x000000dc => "\x86",
     0x000000df => "\xa7",
     0x000000e0 => "\x88",
     0x000000e1 => "\x87",
     0x000000e2 => "\x89",
     0x000000e3 => "\x8b",
     0x000000e4 => "\x8a",
     0x000000e5 => "\x8c",
     0x000000e6 => "\xbe",
     0x000000e7 => "\x8d",
     0x000000e8 => "\x8f",
     0x000000e9 => "\x8e",
     0x000000ea => "\x90",
     0x000000eb => "\x91",
     0x000000ec => "\x93",
     0x000000ed => "\x92",
     0x000000ee => "\x94",
     0x000000ef => "\x95",
     0x000000f1 => "\x96",
     0x000000f2 => "\x98",
     0x000000f3 => "\x97",
     0x000000f4 => "\x99",
     0x000000f5 => "\x9b",
     0x000000f6 => "\x9a",
     0x000000f7 => "\xd6",
     0x000000f8 => "\xbf",
     0x000000f9 => "\x9d",
     0x000000fa => "\x9c",
     0x000000fb => "\x9e",
     0x000000fc => "\x9f",
     0x000000ff => "\xd8",
     0x00000131 => "\xf5",
     0x00000152 => "\xce",
     0x00000153 => "\xcf",
     0x00000178 => "\xd9",
     0x00000192 => "\xc4",
     0x000002c6 => "\xf6",
     0x000002c7 => "\xff",
     0x000002d8 => "\xf9",
     0x000002d9 => "\xfa",
     0x000002da => "\xfb",
     0x000002db => "\xfe",
     0x000002dc => "\xf7",
     0x000002dd => "\xfd",
     0x00000394 => "\xc6",
     0x000003a9 => "\xbd",
     0x000003c0 => "\xb9",
     0x00002013 => "\xd0",
     0x00002014 => "\xd1",
     0x00002018 => "\xd4",
     0x00002019 => "\xd5",
     0x0000201a => "\xe2",
     0x0000201c => "\xd2",
     0x0000201d => "\xd3",
     0x0000201e => "\xe3",
     0x00002020 => "\xa0",
     0x00002021 => "\xe0",
     0x00002022 => "\xa5",
     0x00002026 => "\xc9",
     0x00002030 => "\xe4",
     0x00002039 => "\xdc",
     0x0000203a => "\xdd",
     0x00002044 => "\xda",
     0x000020ac => "\xdb",
     0x00002122 => "\xaa",
     0x00002202 => "\xb6",
     0x0000220f => "\xb8",
     0x00002211 => "\xb7",
     0x0000221a => "\xc3",
     0x0000221e => "\xb0",
     0x0000222b => "\xba",
     0x00002248 => "\xc5",
     0x00002260 => "\xad",
     0x00002264 => "\xb2",
     0x00002265 => "\xb3",
     0x000025ca => "\xd7",
     0x0000e01e => "\xf0",
     0x0000fb01 => "\xde",
     0x0000fb02 => "\xdf",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::MACINTOSH - Conversion routines for MACINTOSH
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for MACINTOSH.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
   source: The Unicode Standard ver 1.0, ISBN 0-201-56788-1, Oct 1991
  alias MAC
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  00000004 | END OF TRANSMISSION (EOT)
     05 |  00000005 | ENQUIRY (ENQ)
     06 |  00000006 | ACKNOWLEDGE (ACK)
     07 |  00000007 | BELL (BEL)
     08 |  00000008 | BACKSPACE (BS)
     09 |  00000009 | CHARACTER TABULATION (HT)
     0A |  0000000A | LINE FEED (LF)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  00000014 | DEVICE CONTROL FOUR (DC4)
     15 |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     16 |  00000016 | SYNCHRONOUS IDLE (SYN)
     17 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  0000001A | SUBSTITUTE (SUB)
     1B |  0000001B | ESCAPE (ESC)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000020 | SPACE
     21 |  00000021 | EXCLAMATION MARK
     22 |  00000022 | QUOTATION MARK
     23 |  00000023 | NUMBER SIGN
     24 |  00000024 | DOLLAR SIGN
     25 |  00000025 | PERCENT SIGN
     26 |  00000026 | AMPERSAND
     27 |  00000027 | APOSTROPHE
     28 |  00000028 | LEFT PARENTHESIS
     29 |  00000029 | RIGHT PARENTHESIS
     2A |  0000002A | ASTERISK
     2B |  0000002B | PLUS SIGN
     2C |  0000002C | COMMA
     2D |  0000002D | HYPHEN-MINUS
     2E |  0000002E | FULL STOP
     2F |  0000002F | SOLIDUS
     30 |  00000030 | DIGIT ZERO
     31 |  00000031 | DIGIT ONE
     32 |  00000032 | DIGIT TWO
     33 |  00000033 | DIGIT THREE
     34 |  00000034 | DIGIT FOUR
     35 |  00000035 | DIGIT FIVE
     36 |  00000036 | DIGIT SIX
     37 |  00000037 | DIGIT SEVEN
     38 |  00000038 | DIGIT EIGHT
     39 |  00000039 | DIGIT NINE
     3A |  0000003A | COLON
     3B |  0000003B | SEMICOLON
     3C |  0000003C | LESS-THAN SIGN
     3D |  0000003D | EQUALS SIGN
     3E |  0000003E | GREATER-THAN SIGN
     3F |  0000003F | QUESTION MARK
     40 |  00000040 | COMMERCIAL AT
     41 |  00000041 | LATIN CAPITAL LETTER A
     42 |  00000042 | LATIN CAPITAL LETTER B
     43 |  00000043 | LATIN CAPITAL LETTER C
     44 |  00000044 | LATIN CAPITAL LETTER D
     45 |  00000045 | LATIN CAPITAL LETTER E
     46 |  00000046 | LATIN CAPITAL LETTER F
     47 |  00000047 | LATIN CAPITAL LETTER G
     48 |  00000048 | LATIN CAPITAL LETTER H
     49 |  00000049 | LATIN CAPITAL LETTER I
     4A |  0000004A | LATIN CAPITAL LETTER J
     4B |  0000004B | LATIN CAPITAL LETTER K
     4C |  0000004C | LATIN CAPITAL LETTER L
     4D |  0000004D | LATIN CAPITAL LETTER M
     4E |  0000004E | LATIN CAPITAL LETTER N
     4F |  0000004F | LATIN CAPITAL LETTER O
     50 |  00000050 | LATIN CAPITAL LETTER P
     51 |  00000051 | LATIN CAPITAL LETTER Q
     52 |  00000052 | LATIN CAPITAL LETTER R
     53 |  00000053 | LATIN CAPITAL LETTER S
     54 |  00000054 | LATIN CAPITAL LETTER T
     55 |  00000055 | LATIN CAPITAL LETTER U
     56 |  00000056 | LATIN CAPITAL LETTER V
     57 |  00000057 | LATIN CAPITAL LETTER W
     58 |  00000058 | LATIN CAPITAL LETTER X
     59 |  00000059 | LATIN CAPITAL LETTER Y
     5A |  0000005A | LATIN CAPITAL LETTER Z
     5B |  0000005B | LEFT SQUARE BRACKET
     5C |  0000005C | REVERSE SOLIDUS
     5D |  0000005D | RIGHT SQUARE BRACKET
     5E |  0000005E | CIRCUMFLEX ACCENT
     5F |  0000005F | LOW LINE
     60 |  00000060 | GRAVE ACCENT
     61 |  00000061 | LATIN SMALL LETTER A
     62 |  00000062 | LATIN SMALL LETTER B
     63 |  00000063 | LATIN SMALL LETTER C
     64 |  00000064 | LATIN SMALL LETTER D
     65 |  00000065 | LATIN SMALL LETTER E
     66 |  00000066 | LATIN SMALL LETTER F
     67 |  00000067 | LATIN SMALL LETTER G
     68 |  00000068 | LATIN SMALL LETTER H
     69 |  00000069 | LATIN SMALL LETTER I
     6A |  0000006A | LATIN SMALL LETTER J
     6B |  0000006B | LATIN SMALL LETTER K
     6C |  0000006C | LATIN SMALL LETTER L
     6D |  0000006D | LATIN SMALL LETTER M
     6E |  0000006E | LATIN SMALL LETTER N
     6F |  0000006F | LATIN SMALL LETTER O
     70 |  00000070 | LATIN SMALL LETTER P
     71 |  00000071 | LATIN SMALL LETTER Q
     72 |  00000072 | LATIN SMALL LETTER R
     73 |  00000073 | LATIN SMALL LETTER S
     74 |  00000074 | LATIN SMALL LETTER T
     75 |  00000075 | LATIN SMALL LETTER U
     76 |  00000076 | LATIN SMALL LETTER V
     77 |  00000077 | LATIN SMALL LETTER W
     78 |  00000078 | LATIN SMALL LETTER X
     79 |  00000079 | LATIN SMALL LETTER Y
     7A |  0000007A | LATIN SMALL LETTER Z
     7B |  0000007B | LEFT CURLY BRACKET
     7C |  0000007C | VERTICAL LINE
     7D |  0000007D | RIGHT CURLY BRACKET
     7E |  0000007E | TILDE
     7F |  0000007F | DELETE (DEL)
     80 |  000000C4 | LATIN CAPITAL LETTER A WITH DIAERESIS
     81 |  000000C5 | LATIN CAPITAL LETTER A WITH RING ABOVE
     82 |  000000C7 | LATIN CAPITAL LETTER C WITH CEDILLA
     83 |  000000C9 | LATIN CAPITAL LETTER E WITH ACUTE
     84 |  000000D1 | LATIN CAPITAL LETTER N WITH TILDE
     85 |  000000D6 | LATIN CAPITAL LETTER O WITH DIAERESIS
     86 |  000000DC | LATIN CAPITAL LETTER U WITH DIAERESIS
     87 |  000000E1 | LATIN SMALL LETTER A WITH ACUTE
     88 |  000000E0 | LATIN SMALL LETTER A WITH GRAVE
     89 |  000000E2 | LATIN SMALL LETTER A WITH CIRCUMFLEX
     8A |  000000E4 | LATIN SMALL LETTER A WITH DIAERESIS
     8B |  000000E3 | LATIN SMALL LETTER A WITH TILDE
     8C |  000000E5 | LATIN SMALL LETTER A WITH RING ABOVE
     8D |  000000E7 | LATIN SMALL LETTER C WITH CEDILLA
     8E |  000000E9 | LATIN SMALL LETTER E WITH ACUTE
     8F |  000000E8 | LATIN SMALL LETTER E WITH GRAVE
     90 |  000000EA | LATIN SMALL LETTER E WITH CIRCUMFLEX
     91 |  000000EB | LATIN SMALL LETTER E WITH DIAERESIS
     92 |  000000ED | LATIN SMALL LETTER I WITH ACUTE
     93 |  000000EC | LATIN SMALL LETTER I WITH GRAVE
     94 |  000000EE | LATIN SMALL LETTER I WITH CIRCUMFLEX
     95 |  000000EF | LATIN SMALL LETTER I WITH DIAERESIS
     96 |  000000F1 | LATIN SMALL LETTER N WITH TILDE
     97 |  000000F3 | LATIN SMALL LETTER O WITH ACUTE
     98 |  000000F2 | LATIN SMALL LETTER O WITH GRAVE
     99 |  000000F4 | LATIN SMALL LETTER O WITH CIRCUMFLEX
     9A |  000000F6 | LATIN SMALL LETTER O WITH DIAERESIS
     9B |  000000F5 | LATIN SMALL LETTER O WITH TILDE
     9C |  000000FA | LATIN SMALL LETTER U WITH ACUTE
     9D |  000000F9 | LATIN SMALL LETTER U WITH GRAVE
     9E |  000000FB | LATIN SMALL LETTER U WITH CIRCUMFLEX
     9F |  000000FC | LATIN SMALL LETTER U WITH DIAERESIS
     A0 |  00002020 | DAGGER
     A1 |  000000B0 | DEGREE SIGN
     A2 |  000000A2 | CENT SIGN
     A3 |  000000A3 | POUND SIGN
     A4 |  000000A7 | SECTION SIGN
     A5 |  00002022 | BULLET
     A6 |  000000B6 | PILCROW SIGN
     A7 |  000000DF | LATIN SMALL LETTER SHARP S (German)
     A8 |  000000AE | REGISTERED SIGN
     A9 |  000000A9 | COPYRIGHT SIGN
     AA |  00002122 | TRADE MARK SIGN
     AB |  000000B4 | ACUTE ACCENT
     AC |  000000A8 | DIAERESIS
     AD |  00002260 | NOT EQUAL TO
     AE |  000000C6 | LATIN CAPITAL LETTER AE
     AF |  000000D8 | LATIN CAPITAL LETTER O WITH STROKE
     B0 |  0000221E | INFINITY
     B1 |  000000B1 | PLUS-MINUS SIGN
     B2 |  00002264 | LESS-THAN OR EQUAL TO
     B3 |  00002265 | GREATER-THAN OR EQUAL TO
     B4 |  000000A5 | YEN SIGN
     B5 |  000000B5 | MICRO SIGN
     B6 |  00002202 | PARTIAL DIFFERENTIAL
     B7 |  00002211 | N-ARY SUMMATION
     B8 |  0000220F | N-ARY PRODUCT
     B9 |  000003C0 | GREEK SMALL LETTER PI
     BA |  0000222B | INTEGRAL
     BB |  000000AA | FEMININE ORDINAL INDICATOR
     BC |  000000BA | MASCULINE ORDINAL INDICATOR
     BD |  000003A9 | GREEK CAPITAL LETTER OMEGA
     BE |  000000E6 | LATIN SMALL LETTER AE
     BF |  000000F8 | LATIN SMALL LETTER O WITH STROKE
     C0 |  000000BF | INVERTED QUESTION MARK
     C1 |  000000A1 | INVERTED EXCLAMATION MARK
     C2 |  000000AC | NOT SIGN
     C3 |  0000221A | SQUARE ROOT
     C4 |  00000192 | LATIN SMALL LETTER F WITH HOOK
     C5 |  00002248 | ALMOST EQUAL TO
     C6 |  00000394 | GREEK CAPITAL LETTER DELTA
     C7 |  000000AB | LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
     C8 |  000000BB | RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
     C9 |  00002026 | HORIZONTAL ELLIPSIS
     CA |  000000A0 | NO-BREAK SPACE
     CB |  000000C0 | LATIN CAPITAL LETTER A WITH GRAVE
     CC |  000000C3 | LATIN CAPITAL LETTER A WITH TILDE
     CD |  000000D5 | LATIN CAPITAL LETTER O WITH TILDE
     CE |  00000152 | LATIN CAPITAL LIGATURE OE
     CF |  00000153 | LATIN SMALL LIGATURE OE
     D0 |  00002013 | EN DASH
     D1 |  00002014 | EM DASH
     D2 |  0000201C | LEFT DOUBLE QUOTATION MARK
     D3 |  0000201D | RIGHT DOUBLE QUOTATION MARK
     D4 |  00002018 | LEFT SINGLE QUOTATION MARK
     D5 |  00002019 | RIGHT SINGLE QUOTATION MARK
     D6 |  000000F7 | DIVISION SIGN
     D7 |  000025CA | LOZENGE
     D8 |  000000FF | LATIN SMALL LETTER Y WITH DIAERESIS
     D9 |  00000178 | LATIN CAPITAL LETTER Y WITH DIAERESIS
     DA |  00002044 | FRACTION SLASH
     DB |  000020AC | EURO SIGN
     DC |  00002039 | SINGLE LEFT-POINTING ANGLE QUOTATION MARK
     DD |  0000203A | SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
     DE |  0000FB01 | LATIN SMALL LIGATURE FI
     DF |  0000FB02 | LATIN SMALL LIGATURE FL
     E0 |  00002021 | DOUBLE DAGGER
     E1 |  000000B7 | MIDDLE DOT
     E2 |  0000201A | SINGLE LOW-9 QUOTATION MARK
     E3 |  0000201E | DOUBLE LOW-9 QUOTATION MARK
     E4 |  00002030 | PER MILLE SIGN
     E5 |  000000C2 | LATIN CAPITAL LETTER A WITH CIRCUMFLEX
     E6 |  000000CA | LATIN CAPITAL LETTER E WITH CIRCUMFLEX
     E7 |  000000C1 | LATIN CAPITAL LETTER A WITH ACUTE
     E8 |  000000CB | LATIN CAPITAL LETTER E WITH DIAERESIS
     E9 |  000000C8 | LATIN CAPITAL LETTER E WITH GRAVE
     EA |  000000CD | LATIN CAPITAL LETTER I WITH ACUTE
     EB |  000000CE | LATIN CAPITAL LETTER I WITH CIRCUMFLEX
     EC |  000000CF | LATIN CAPITAL LETTER I WITH DIAERESIS
     ED |  000000CC | LATIN CAPITAL LETTER I WITH GRAVE
     EE |  000000D3 | LATIN CAPITAL LETTER O WITH ACUTE
     EF |  000000D4 | LATIN CAPITAL LETTER O WITH CIRCUMFLEX
     F0 |  0000E01E | APPLE LOGO (Macintosh_F0)
     F1 |  000000D2 | LATIN CAPITAL LETTER O WITH GRAVE
     F2 |  000000DA | LATIN CAPITAL LETTER U WITH ACUTE
     F3 |  000000DB | LATIN CAPITAL LETTER U WITH CIRCUMFLEX
     F4 |  000000D9 | LATIN CAPITAL LETTER U WITH GRAVE
     F5 |  00000131 | LATIN SMALL LETTER DOTLESS I
     F6 |  000002C6 | MODIFIER LETTER CIRCUMFLEX ACCENT
     F7 |  000002DC | SMALL TILDE
     F8 |  000000AF | MACRON
     F9 |  000002D8 | BREVE
     FA |  000002D9 | DOT ABOVE (Mandarin Chinese light tone)
     FB |  000002DA | RING ABOVE
     FC |  000000B8 | CEDILLA
     FD |  000002DD | DOUBLE ACUTE ACCENT
     FE |  000002DB | OGONEK
     FF |  000002C7 | CARON (Mandarin Chinese third tone)
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/MACROMANIA.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for MACROMANIA.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::MACROMANIA;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x0004,
     0x0005,
     0x0006,
     0x0007,
     0x0008,
     0x0009,
     0x000a,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x0014,
     0x0015,
     0x0016,
     0x0017,
     0x0018,
     0x0019,
     0x001a,
     0x001b,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0020,
     0x0021,
     0x0022,
     0x0023,
     0x0024,
     0x0025,
     0x0026,
     0x0027,
     0x0028,
     0x0029,
     0x002a,
     0x002b,
     0x002c,
     0x002d,
     0x002e,
     0x002f,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x003a,
     0x003b,
     0x003c,
     0x003d,
     0x003e,
     0x003f,
     0x0040,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x005b,
     0x005c,
     0x005d,
     0x005e,
     0x005f,
     0x0060,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x007b,
     0x007c,
     0x007d,
     0x007e,
     0x007f,
     0x00c4,
     0x00c5,
     0x00c7,
     0x00c9,
     0x00d1,
     0x00d6,
     0x00dc,
     0x00e1,
     0x00e0,
     0x00e2,
     0x00e4,
     0x00e3,
     0x00e5,
     0x00e7,
     0x00e9,
     0x00e8,
     0x00ea,
     0x00eb,
     0x00ed,
     0x00ec,
     0x00ee,
     0x00ef,
     0x00f1,
     0x00f3,
     0x00f2,
     0x00f4,
     0x00f6,
     0x00f5,
     0x00fa,
     0x00f9,
     0x00fb,
     0x00fc,
     0x2020,
     0x00b0,
     0x00a2,
     0x00a3,
     0x00a7,
     0x2022,
     0x00b6,
     0x00df,
     0x00ae,
     0x00a9,
     0x2122,
     0x00b4,
     0x00a8,
     0x2260,
     0x0102,
     0x015e,
     0x221e,
     0x00b1,
     0x2264,
     0x2265,
     0x00a5,
     0x00b5,
     0x2202,
     0x2211,
     0x220f,
     0x03c0,
     0x222b,
     0x00aa,
     0x00ba,
     0x2126,
     0x0103,
     0x015f,
     0x00bf,
     0x00a1,
     0x00ac,
     0x221a,
     0x0192,
     0x2248,
     0x2206,
     0x00ab,
     0x00bb,
     0x2026,
     0x00a0,
     0x00c0,
     0x00c3,
     0x00d5,
     0x0152,
     0x0153,
     0x2013,
     0x2014,
     0x201c,
     0x201d,
     0x2018,
     0x2019,
     0x00f7,
     0x25ca,
     0x00ff,
     0x0178,
     0x2044,
     0x00a4,
     0x2039,
     0x203a,
     0x0162,
     0x0163,
     0x2021,
     0x00b7,
     0x201a,
     0x201e,
     0x2030,
     0x00c2,
     0x00ca,
     0x00c1,
     0x00cb,
     0x00c8,
     0x00cd,
     0x00ce,
     0x00cf,
     0x00cc,
     0x00d3,
     0x00d4,
     0xfffd,
     0x00d2,
     0x00da,
     0x00db,
     0x00d9,
     0x0131,
     0x02c6,
     0x02dc,
     0x00af,
     0x02d8,
     0x02d9,
     0x02da,
     0x00b8,
     0x02dd,
     0x02db,
     0x02c7,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\x04",
     "\x05",
     "\x06",
     "\x07",
     "\x08",
     "\x09",
     "\x0a",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\x14",
     "\x15",
     "\x16",
     "\x17",
     "\x18",
     "\x19",
     "\x1a",
     "\x1b",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\x20",
     "\x21",
     "\x22",
     "\x23",
     "\x24",
     "\x25",
     "\x26",
     "\x27",
     "\x28",
     "\x29",
     "\x2a",
     "\x2b",
     "\x2c",
     "\x2d",
     "\x2e",
     "\x2f",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\x3a",
     "\x3b",
     "\x3c",
     "\x3d",
     "\x3e",
     "\x3f",
     "\x40",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\x5b",
     "\x5c",
     "\x5d",
     "\x5e",
     "\x5f",
     "\x60",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\x7b",
     "\x7c",
     "\x7d",
     "\x7e",
     "\x7f",
     "\xc3\x84",
     "\xc3\x85",
     "\xc3\x87",
     "\xc3\x89",
     "\xc3\x91",
     "\xc3\x96",
     "\xc3\x9c",
     "\xc3\xa1",
     "\xc3\xa0",
     "\xc3\xa2",
     "\xc3\xa4",
     "\xc3\xa3",
     "\xc3\xa5",
     "\xc3\xa7",
     "\xc3\xa9",
     "\xc3\xa8",
     "\xc3\xaa",
     "\xc3\xab",
     "\xc3\xad",
     "\xc3\xac",
     "\xc3\xae",
     "\xc3\xaf",
     "\xc3\xb1",
     "\xc3\xb3",
     "\xc3\xb2",
     "\xc3\xb4",
     "\xc3\xb6",
     "\xc3\xb5",
     "\xc3\xba",
     "\xc3\xb9",
     "\xc3\xbb",
     "\xc3\xbc",
     "\xe2\x80\xa0",
     "\xc2\xb0",
     "\xc2\xa2",
     "\xc2\xa3",
     "\xc2\xa7",
     "\xe2\x80\xa2",
     "\xc2\xb6",
     "\xc3\x9f",
     "\xc2\xae",
     "\xc2\xa9",
     "\xe2\x84\xa2",
     "\xc2\xb4",
     "\xc2\xa8",
     "\xe2\x89\xa0",
     "\xc4\x82",
     "\xc5\x9e",
     "\xe2\x88\x9e",
     "\xc2\xb1",
     "\xe2\x89\xa4",
     "\xe2\x89\xa5",
     "\xc2\xa5",
     "\xc2\xb5",
     "\xe2\x88\x82",
     "\xe2\x88\x91",
     "\xe2\x88\x8f",
     "\xcf\x80",
     "\xe2\x88\xab",
     "\xc2\xaa",
     "\xc2\xba",
     "\xe2\x84\xa6",
     "\xc4\x83",
     "\xc5\x9f",
     "\xc2\xbf",
     "\xc2\xa1",
     "\xc2\xac",
     "\xe2\x88\x9a",
     "\xc6\x92",
     "\xe2\x89\x88",
     "\xe2\x88\x86",
     "\xc2\xab",
     "\xc2\xbb",
     "\xe2\x80\xa6",
     "\xc2\xa0",
     "\xc3\x80",
     "\xc3\x83",
     "\xc3\x95",
     "\xc5\x92",
     "\xc5\x93",
     "\xe2\x80\x93",
     "\xe2\x80\x94",
     "\xe2\x80\x9c",
     "\xe2\x80\x9d",
     "\xe2\x80\x98",
     "\xe2\x80\x99",
     "\xc3\xb7",
     "\xe2\x97\x8a",
     "\xc3\xbf",
     "\xc5\xb8",
     "\xe2\x81\x84",
     "\xc2\xa4",
     "\xe2\x80\xb9",
     "\xe2\x80\xba",
     "\xc5\xa2",
     "\xc5\xa3",
     "\xe2\x80\xa1",
     "\xc2\xb7",
     "\xe2\x80\x9a",
     "\xe2\x80\x9e",
     "\xe2\x80\xb0",
     "\xc3\x82",
     "\xc3\x8a",
     "\xc3\x81",
     "\xc3\x8b",
     "\xc3\x88",
     "\xc3\x8d",
     "\xc3\x8e",
     "\xc3\x8f",
     "\xc3\x8c",
     "\xc3\x93",
     "\xc3\x94",
     "\xef\xbf\xbd",
     "\xc3\x92",
     "\xc3\x9a",
     "\xc3\x9b",
     "\xc3\x99",
     "\xc4\xb1",
     "\xcb\x86",
     "\xcb\x9c",
     "\xc2\xaf",
     "\xcb\x98",
     "\xcb\x99",
     "\xcb\x9a",
     "\xc2\xb8",
     "\xcb\x9d",
     "\xcb\x9b",
     "\xcb\x87",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x04",
     0x00000005 => "\x05",
     0x00000006 => "\x06",
     0x00000007 => "\x07",
     0x00000008 => "\x08",
     0x00000009 => "\x09",
     0x0000000a => "\x0a",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x14",
     0x00000015 => "\x15",
     0x00000016 => "\x16",
     0x00000017 => "\x17",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x1a",
     0x0000001b => "\x1b",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x20",
     0x00000021 => "\x21",
     0x00000022 => "\x22",
     0x00000023 => "\x23",
     0x00000024 => "\x24",
     0x00000025 => "\x25",
     0x00000026 => "\x26",
     0x00000027 => "\x27",
     0x00000028 => "\x28",
     0x00000029 => "\x29",
     0x0000002a => "\x2a",
     0x0000002b => "\x2b",
     0x0000002c => "\x2c",
     0x0000002d => "\x2d",
     0x0000002e => "\x2e",
     0x0000002f => "\x2f",
     0x00000030 => "\x30",
     0x00000031 => "\x31",
     0x00000032 => "\x32",
     0x00000033 => "\x33",
     0x00000034 => "\x34",
     0x00000035 => "\x35",
     0x00000036 => "\x36",
     0x00000037 => "\x37",
     0x00000038 => "\x38",
     0x00000039 => "\x39",
     0x0000003a => "\x3a",
     0x0000003b => "\x3b",
     0x0000003c => "\x3c",
     0x0000003d => "\x3d",
     0x0000003e => "\x3e",
     0x0000003f => "\x3f",
     0x00000040 => "\x40",
     0x00000041 => "\x41",
     0x00000042 => "\x42",
     0x00000043 => "\x43",
     0x00000044 => "\x44",
     0x00000045 => "\x45",
     0x00000046 => "\x46",
     0x00000047 => "\x47",
     0x00000048 => "\x48",
     0x00000049 => "\x49",
     0x0000004a => "\x4a",
     0x0000004b => "\x4b",
     0x0000004c => "\x4c",
     0x0000004d => "\x4d",
     0x0000004e => "\x4e",
     0x0000004f => "\x4f",
     0x00000050 => "\x50",
     0x00000051 => "\x51",
     0x00000052 => "\x52",
     0x00000053 => "\x53",
     0x00000054 => "\x54",
     0x00000055 => "\x55",
     0x00000056 => "\x56",
     0x00000057 => "\x57",
     0x00000058 => "\x58",
     0x00000059 => "\x59",
     0x0000005a => "\x5a",
     0x0000005b => "\x5b",
     0x0000005c => "\x5c",
     0x0000005d => "\x5d",
     0x0000005e => "\x5e",
     0x0000005f => "\x5f",
     0x00000060 => "\x60",
     0x00000061 => "\x61",
     0x00000062 => "\x62",
     0x00000063 => "\x63",
     0x00000064 => "\x64",
     0x00000065 => "\x65",
     0x00000066 => "\x66",
     0x00000067 => "\x67",
     0x00000068 => "\x68",
     0x00000069 => "\x69",
     0x0000006a => "\x6a",
     0x0000006b => "\x6b",
     0x0000006c => "\x6c",
     0x0000006d => "\x6d",
     0x0000006e => "\x6e",
     0x0000006f => "\x6f",
     0x00000070 => "\x70",
     0x00000071 => "\x71",
     0x00000072 => "\x72",
     0x00000073 => "\x73",
     0x00000074 => "\x74",
     0x00000075 => "\x75",
     0x00000076 => "\x76",
     0x00000077 => "\x77",
     0x00000078 => "\x78",
     0x00000079 => "\x79",
     0x0000007a => "\x7a",
     0x0000007b => "\x7b",
     0x0000007c => "\x7c",
     0x0000007d => "\x7d",
     0x0000007e => "\x7e",
     0x0000007f => "\x7f",
     0x000000a0 => "\xca",
     0x000000a1 => "\xc1",
     0x000000a2 => "\xa2",
     0x000000a3 => "\xa3",
     0x000000a4 => "\xdb",
     0x000000a5 => "\xb4",
     0x000000a7 => "\xa4",
     0x000000a8 => "\xac",
     0x000000a9 => "\xa9",
     0x000000aa => "\xbb",
     0x000000ab => "\xc7",
     0x000000ac => "\xc2",
     0x000000ae => "\xa8",
     0x000000af => "\xf8",
     0x000000b0 => "\xa1",
     0x000000b1 => "\xb1",
     0x000000b4 => "\xab",
     0x000000b5 => "\xb5",
     0x000000b6 => "\xa6",
     0x000000b7 => "\xe1",
     0x000000b8 => "\xfc",
     0x000000ba => "\xbc",
     0x000000bb => "\xc8",
     0x000000bf => "\xc0",
     0x000000c0 => "\xcb",
     0x000000c1 => "\xe7",
     0x000000c2 => "\xe5",
     0x000000c3 => "\xcc",
     0x000000c4 => "\x80",
     0x000000c5 => "\x81",
     0x000000c7 => "\x82",
     0x000000c8 => "\xe9",
     0x000000c9 => "\x83",
     0x000000ca => "\xe6",
     0x000000cb => "\xe8",
     0x000000cc => "\xed",
     0x000000cd => "\xea",
     0x000000ce => "\xeb",
     0x000000cf => "\xec",
     0x000000d1 => "\x84",
     0x000000d2 => "\xf1",
     0x000000d3 => "\xee",
     0x000000d4 => "\xef",
     0x000000d5 => "\xcd",
     0x000000d6 => "\x85",
     0x000000d9 => "\xf4",
     0x000000da => "\xf2",
     0x000000db => "\xf3",
     0x000000dc => "\x86",
     0x000000df => "\xa7",
     0x000000e0 => "\x88",
     0x000000e1 => "\x87",
     0x000000e2 => "\x89",
     0x000000e3 => "\x8b",
     0x000000e4 => "\x8a",
     0x000000e5 => "\x8c",
     0x000000e7 => "\x8d",
     0x000000e8 => "\x8f",
     0x000000e9 => "\x8e",
     0x000000ea => "\x90",
     0x000000eb => "\x91",
     0x000000ec => "\x93",
     0x000000ed => "\x92",
     0x000000ee => "\x94",
     0x000000ef => "\x95",
     0x000000f1 => "\x96",
     0x000000f2 => "\x98",
     0x000000f3 => "\x97",
     0x000000f4 => "\x99",
     0x000000f5 => "\x9b",
     0x000000f6 => "\x9a",
     0x000000f7 => "\xd6",
     0x000000f9 => "\x9d",
     0x000000fa => "\x9c",
     0x000000fb => "\x9e",
     0x000000fc => "\x9f",
     0x000000ff => "\xd8",
     0x00000102 => "\xae",
     0x00000103 => "\xbe",
     0x00000131 => "\xf5",
     0x00000152 => "\xce",
     0x00000153 => "\xcf",
     0x0000015e => "\xaf",
     0x0000015f => "\xbf",
     0x00000162 => "\xde",
     0x00000163 => "\xdf",
     0x00000178 => "\xd9",
     0x00000192 => "\xc4",
     0x000002c6 => "\xf6",
     0x000002c7 => "\xff",
     0x000002d8 => "\xf9",
     0x000002d9 => "\xfa",
     0x000002da => "\xfb",
     0x000002db => "\xfe",
     0x000002dc => "\xf7",
     0x000002dd => "\xfd",
     0x000003c0 => "\xb9",
     0x00002013 => "\xd0",
     0x00002014 => "\xd1",
     0x00002018 => "\xd4",
     0x00002019 => "\xd5",
     0x0000201a => "\xe2",
     0x0000201c => "\xd2",
     0x0000201d => "\xd3",
     0x0000201e => "\xe3",
     0x00002020 => "\xa0",
     0x00002021 => "\xe0",
     0x00002022 => "\xa5",
     0x00002026 => "\xc9",
     0x00002030 => "\xe4",
     0x00002039 => "\xdc",
     0x0000203a => "\xdd",
     0x00002044 => "\xda",
     0x00002122 => "\xaa",
     0x00002126 => "\xbd",
     0x00002202 => "\xb6",
     0x00002206 => "\xc6",
     0x0000220f => "\xb8",
     0x00002211 => "\xb7",
     0x0000221a => "\xc3",
     0x0000221e => "\xb0",
     0x0000222b => "\xba",
     0x00002248 => "\xc5",
     0x00002260 => "\xad",
     0x00002264 => "\xb2",
     0x00002265 => "\xb3",
     0x000025ca => "\xd7",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::MACROMANIA - Conversion routines for MACROMANIA
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for MACROMANIA.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
 
  This charmap has been generated automatically from GNU libiconv
  conversions.
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  00000004 | END OF TRANSMISSION (EOT)
     05 |  00000005 | ENQUIRY (ENQ)
     06 |  00000006 | ACKNOWLEDGE (ACK)
     07 |  00000007 | BELL (BEL)
     08 |  00000008 | BACKSPACE (BS)
     09 |  00000009 | CHARACTER TABULATION (HT)
     0A |  0000000A | LINE FEED (LF)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  00000014 | DEVICE CONTROL FOUR (DC4)
     15 |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     16 |  00000016 | SYNCHRONOUS IDLE (SYN)
     17 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  0000001A | SUBSTITUTE (SUB)
     1B |  0000001B | ESCAPE (ESC)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000020 | SPACE
     21 |  00000021 | EXCLAMATION MARK
     22 |  00000022 | QUOTATION MARK
     23 |  00000023 | NUMBER SIGN
     24 |  00000024 | DOLLAR SIGN
     25 |  00000025 | PERCENT SIGN
     26 |  00000026 | AMPERSAND
     27 |  00000027 | APOSTROPHE
     28 |  00000028 | LEFT PARENTHESIS
     29 |  00000029 | RIGHT PARENTHESIS
     2A |  0000002A | ASTERISK
     2B |  0000002B | PLUS SIGN
     2C |  0000002C | COMMA
     2D |  0000002D | HYPHEN-MINUS
     2E |  0000002E | FULL STOP
     2F |  0000002F | SOLIDUS
     30 |  00000030 | DIGIT ZERO
     31 |  00000031 | DIGIT ONE
     32 |  00000032 | DIGIT TWO
     33 |  00000033 | DIGIT THREE
     34 |  00000034 | DIGIT FOUR
     35 |  00000035 | DIGIT FIVE
     36 |  00000036 | DIGIT SIX
     37 |  00000037 | DIGIT SEVEN
     38 |  00000038 | DIGIT EIGHT
     39 |  00000039 | DIGIT NINE
     3A |  0000003A | COLON
     3B |  0000003B | SEMICOLON
     3C |  0000003C | LESS-THAN SIGN
     3D |  0000003D | EQUALS SIGN
     3E |  0000003E | GREATER-THAN SIGN
     3F |  0000003F | QUESTION MARK
     40 |  00000040 | COMMERCIAL AT
     41 |  00000041 | LATIN CAPITAL LETTER A
     42 |  00000042 | LATIN CAPITAL LETTER B
     43 |  00000043 | LATIN CAPITAL LETTER C
     44 |  00000044 | LATIN CAPITAL LETTER D
     45 |  00000045 | LATIN CAPITAL LETTER E
     46 |  00000046 | LATIN CAPITAL LETTER F
     47 |  00000047 | LATIN CAPITAL LETTER G
     48 |  00000048 | LATIN CAPITAL LETTER H
     49 |  00000049 | LATIN CAPITAL LETTER I
     4A |  0000004A | LATIN CAPITAL LETTER J
     4B |  0000004B | LATIN CAPITAL LETTER K
     4C |  0000004C | LATIN CAPITAL LETTER L
     4D |  0000004D | LATIN CAPITAL LETTER M
     4E |  0000004E | LATIN CAPITAL LETTER N
     4F |  0000004F | LATIN CAPITAL LETTER O
     50 |  00000050 | LATIN CAPITAL LETTER P
     51 |  00000051 | LATIN CAPITAL LETTER Q
     52 |  00000052 | LATIN CAPITAL LETTER R
     53 |  00000053 | LATIN CAPITAL LETTER S
     54 |  00000054 | LATIN CAPITAL LETTER T
     55 |  00000055 | LATIN CAPITAL LETTER U
     56 |  00000056 | LATIN CAPITAL LETTER V
     57 |  00000057 | LATIN CAPITAL LETTER W
     58 |  00000058 | LATIN CAPITAL LETTER X
     59 |  00000059 | LATIN CAPITAL LETTER Y
     5A |  0000005A | LATIN CAPITAL LETTER Z
     5B |  0000005B | LEFT SQUARE BRACKET
     5C |  0000005C | REVERSE SOLIDUS
     5D |  0000005D | RIGHT SQUARE BRACKET
     5E |  0000005E | CIRCUMFLEX ACCENT
     5F |  0000005F | LOW LINE
     60 |  00000060 | GRAVE ACCENT
     61 |  00000061 | LATIN SMALL LETTER A
     62 |  00000062 | LATIN SMALL LETTER B
     63 |  00000063 | LATIN SMALL LETTER C
     64 |  00000064 | LATIN SMALL LETTER D
     65 |  00000065 | LATIN SMALL LETTER E
     66 |  00000066 | LATIN SMALL LETTER F
     67 |  00000067 | LATIN SMALL LETTER G
     68 |  00000068 | LATIN SMALL LETTER H
     69 |  00000069 | LATIN SMALL LETTER I
     6A |  0000006A | LATIN SMALL LETTER J
     6B |  0000006B | LATIN SMALL LETTER K
     6C |  0000006C | LATIN SMALL LETTER L
     6D |  0000006D | LATIN SMALL LETTER M
     6E |  0000006E | LATIN SMALL LETTER N
     6F |  0000006F | LATIN SMALL LETTER O
     70 |  00000070 | LATIN SMALL LETTER P
     71 |  00000071 | LATIN SMALL LETTER Q
     72 |  00000072 | LATIN SMALL LETTER R
     73 |  00000073 | LATIN SMALL LETTER S
     74 |  00000074 | LATIN SMALL LETTER T
     75 |  00000075 | LATIN SMALL LETTER U
     76 |  00000076 | LATIN SMALL LETTER V
     77 |  00000077 | LATIN SMALL LETTER W
     78 |  00000078 | LATIN SMALL LETTER X
     79 |  00000079 | LATIN SMALL LETTER Y
     7A |  0000007A | LATIN SMALL LETTER Z
     7B |  0000007B | LEFT CURLY BRACKET
     7C |  0000007C | VERTICAL LINE
     7D |  0000007D | RIGHT CURLY BRACKET
     7E |  0000007E | TILDE
     7F |  0000007F | DELETE (DEL)
     80 |  000000C4 | LATIN CAPITAL LETTER A WITH DIAERESIS
     81 |  000000C5 | LATIN CAPITAL LETTER A WITH RING ABOVE
     82 |  000000C7 | LATIN CAPITAL LETTER C WITH CEDILLA
     83 |  000000C9 | LATIN CAPITAL LETTER E WITH ACUTE
     84 |  000000D1 | LATIN CAPITAL LETTER N WITH TILDE
     85 |  000000D6 | LATIN CAPITAL LETTER O WITH DIAERESIS
     86 |  000000DC | LATIN CAPITAL LETTER U WITH DIAERESIS
     87 |  000000E1 | LATIN SMALL LETTER A WITH ACUTE
     88 |  000000E0 | LATIN SMALL LETTER A WITH GRAVE
     89 |  000000E2 | LATIN SMALL LETTER A WITH CIRCUMFLEX
     8A |  000000E4 | LATIN SMALL LETTER A WITH DIAERESIS
     8B |  000000E3 | LATIN SMALL LETTER A WITH TILDE
     8C |  000000E5 | LATIN SMALL LETTER A WITH RING ABOVE
     8D |  000000E7 | LATIN SMALL LETTER C WITH CEDILLA
     8E |  000000E9 | LATIN SMALL LETTER E WITH ACUTE
     8F |  000000E8 | LATIN SMALL LETTER E WITH GRAVE
     90 |  000000EA | LATIN SMALL LETTER E WITH CIRCUMFLEX
     91 |  000000EB | LATIN SMALL LETTER E WITH DIAERESIS
     92 |  000000ED | LATIN SMALL LETTER I WITH ACUTE
     93 |  000000EC | LATIN SMALL LETTER I WITH GRAVE
     94 |  000000EE | LATIN SMALL LETTER I WITH CIRCUMFLEX
     95 |  000000EF | LATIN SMALL LETTER I WITH DIAERESIS
     96 |  000000F1 | LATIN SMALL LETTER N WITH TILDE
     97 |  000000F3 | LATIN SMALL LETTER O WITH ACUTE
     98 |  000000F2 | LATIN SMALL LETTER O WITH GRAVE
     99 |  000000F4 | LATIN SMALL LETTER O WITH CIRCUMFLEX
     9A |  000000F6 | LATIN SMALL LETTER O WITH DIAERESIS
     9B |  000000F5 | LATIN SMALL LETTER O WITH TILDE
     9C |  000000FA | LATIN SMALL LETTER U WITH ACUTE
     9D |  000000F9 | LATIN SMALL LETTER U WITH GRAVE
     9E |  000000FB | LATIN SMALL LETTER U WITH CIRCUMFLEX
     9F |  000000FC | LATIN SMALL LETTER U WITH DIAERESIS
     A0 |  00002020 | DAGGER
     A1 |  000000B0 | DEGREE SIGN
     A2 |  000000A2 | CENT SIGN
     A3 |  000000A3 | POUND SIGN
     A4 |  000000A7 | SECTION SIGN
     A5 |  00002022 | BULLET
     A6 |  000000B6 | PILCROW SIGN
     A7 |  000000DF | LATIN SMALL LETTER SHARP S
     A8 |  000000AE | REGISTERED SIGN
     A9 |  000000A9 | COPYRIGHT SIGN
     AA |  00002122 | TRADE MARK SIGN
     AB |  000000B4 | ACUTE ACCENT
     AC |  000000A8 | DIAERESIS
     AD |  00002260 | NOT EQUAL TO
     AE |  00000102 | LATIN CAPITAL LETTER A WITH BREVE
     AF |  0000015E | LATIN CAPITAL LETTER S WITH CEDILLA
     B0 |  0000221E | INFINITY
     B1 |  000000B1 | PLUS-MINUS SIGN
     B2 |  00002264 | LESS-THAN OR EQUAL TO
     B3 |  00002265 | GREATER-THAN OR EQUAL TO
     B4 |  000000A5 | YEN SIGN
     B5 |  000000B5 | MICRO SIGN
     B6 |  00002202 | PARTIAL DIFFERENTIAL
     B7 |  00002211 | N-ARY SUMMATION
     B8 |  0000220F | N-ARY PRODUCT
     B9 |  000003C0 | GREEK SMALL LETTER PI
     BA |  0000222B | INTEGRAL
     BB |  000000AA | FEMININE ORDINAL INDICATOR
     BC |  000000BA | MASCULINE ORDINAL INDICATOR
     BD |  00002126 | OHM SIGN
     BE |  00000103 | LATIN SMALL LETTER A WITH BREVE
     BF |  0000015F | LATIN SMALL LETTER S WITH CEDILLA
     C0 |  000000BF | INVERTED QUESTION MARK
     C1 |  000000A1 | INVERTED EXCLAMATION MARK
     C2 |  000000AC | NOT SIGN
     C3 |  0000221A | SQUARE ROOT
     C4 |  00000192 | LATIN SMALL LETTER F WITH HOOK
     C5 |  00002248 | ALMOST EQUAL TO
     C6 |  00002206 | INCREMENT
     C7 |  000000AB | LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
     C8 |  000000BB | RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
     C9 |  00002026 | HORIZONTAL ELLIPSIS
     CA |  000000A0 | NO-BREAK SPACE
     CB |  000000C0 | LATIN CAPITAL LETTER A WITH GRAVE
     CC |  000000C3 | LATIN CAPITAL LETTER A WITH TILDE
     CD |  000000D5 | LATIN CAPITAL LETTER O WITH TILDE
     CE |  00000152 | LATIN CAPITAL LIGATURE OE
     CF |  00000153 | LATIN SMALL LIGATURE OE
     D0 |  00002013 | EN DASH
     D1 |  00002014 | EM DASH
     D2 |  0000201C | LEFT DOUBLE QUOTATION MARK
     D3 |  0000201D | RIGHT DOUBLE QUOTATION MARK
     D4 |  00002018 | LEFT SINGLE QUOTATION MARK
     D5 |  00002019 | RIGHT SINGLE QUOTATION MARK
     D6 |  000000F7 | DIVISION SIGN
     D7 |  000025CA | LOZENGE
     D8 |  000000FF | LATIN SMALL LETTER Y WITH DIAERESIS
     D9 |  00000178 | LATIN CAPITAL LETTER Y WITH DIAERESIS
     DA |  00002044 | FRACTION SLASH
     DB |  000000A4 | CURRENCY SIGN
     DC |  00002039 | SINGLE LEFT-POINTING ANGLE QUOTATION MARK
     DD |  0000203A | SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
     DE |  00000162 | LATIN CAPITAL LETTER T WITH CEDILLA
     DF |  00000163 | LATIN SMALL LETTER T WITH CEDILLA
     E0 |  00002021 | DOUBLE DAGGER
     E1 |  000000B7 | MIDDLE DOT
     E2 |  0000201A | SINGLE LOW-9 QUOTATION MARK
     E3 |  0000201E | DOUBLE LOW-9 QUOTATION MARK
     E4 |  00002030 | PER MILLE SIGN
     E5 |  000000C2 | LATIN CAPITAL LETTER A WITH CIRCUMFLEX
     E6 |  000000CA | LATIN CAPITAL LETTER E WITH CIRCUMFLEX
     E7 |  000000C1 | LATIN CAPITAL LETTER A WITH ACUTE
     E8 |  000000CB | LATIN CAPITAL LETTER E WITH DIAERESIS
     E9 |  000000C8 | LATIN CAPITAL LETTER E WITH GRAVE
     EA |  000000CD | LATIN CAPITAL LETTER I WITH ACUTE
     EB |  000000CE | LATIN CAPITAL LETTER I WITH CIRCUMFLEX
     EC |  000000CF | LATIN CAPITAL LETTER I WITH DIAERESIS
     ED |  000000CC | LATIN CAPITAL LETTER I WITH GRAVE
     EE |  000000D3 | LATIN CAPITAL LETTER O WITH ACUTE
     EF |  000000D4 | LATIN CAPITAL LETTER O WITH CIRCUMFLEX
     F1 |  000000D2 | LATIN CAPITAL LETTER O WITH GRAVE
     F2 |  000000DA | LATIN CAPITAL LETTER U WITH ACUTE
     F3 |  000000DB | LATIN CAPITAL LETTER U WITH CIRCUMFLEX
     F4 |  000000D9 | LATIN CAPITAL LETTER U WITH GRAVE
     F5 |  00000131 | LATIN SMALL LETTER DOTLESS I
     F6 |  000002C6 | MODIFIER LETTER CIRCUMFLEX ACCENT
     F7 |  000002DC | SMALL TILDE
     F8 |  000000AF | MACRON
     F9 |  000002D8 | BREVE
     FA |  000002D9 | DOT ABOVE
     FB |  000002DA | RING ABOVE
     FC |  000000B8 | CEDILLA
     FD |  000002DD | DOUBLE ACUTE ACCENT
     FE |  000002DB | OGONEK
     FF |  000002C7 | CARON
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/MACTHAI.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for MACTHAI.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::MACTHAI;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x0004,
     0x0005,
     0x0006,
     0x0007,
     0x0008,
     0x0009,
     0x000a,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x0014,
     0x0015,
     0x0016,
     0x0017,
     0x0018,
     0x0019,
     0x001a,
     0x001b,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0020,
     0x0021,
     0x0022,
     0x0023,
     0x0024,
     0x0025,
     0x0026,
     0x0027,
     0x0028,
     0x0029,
     0x002a,
     0x002b,
     0x002c,
     0x002d,
     0x002e,
     0x002f,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x003a,
     0x003b,
     0x003c,
     0x003d,
     0x003e,
     0x003f,
     0x0040,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x005b,
     0x005c,
     0x005d,
     0x005e,
     0x005f,
     0x0060,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x007b,
     0x007c,
     0x007d,
     0x007e,
     0x007f,
     0x00ab,
     0x00bb,
     0x2026,
     0xf88c,
     0xf88f,
     0xf892,
     0xf895,
     0xf898,
     0xf88b,
     0xf88e,
     0xf891,
     0xf894,
     0xf897,
     0x201c,
     0x201d,
     0xf899,
     0xfffd,
     0x2022,
     0xf884,
     0xf889,
     0xf885,
     0xf886,
     0xf887,
     0xf888,
     0xf88a,
     0xf88d,
     0xf890,
     0xf893,
     0xf896,
     0x2018,
     0x2019,
     0xfffd,
     0x00a0,
     0x0e01,
     0x0e02,
     0x0e03,
     0x0e04,
     0x0e05,
     0x0e06,
     0x0e07,
     0x0e08,
     0x0e09,
     0x0e0a,
     0x0e0b,
     0x0e0c,
     0x0e0d,
     0x0e0e,
     0x0e0f,
     0x0e10,
     0x0e11,
     0x0e12,
     0x0e13,
     0x0e14,
     0x0e15,
     0x0e16,
     0x0e17,
     0x0e18,
     0x0e19,
     0x0e1a,
     0x0e1b,
     0x0e1c,
     0x0e1d,
     0x0e1e,
     0x0e1f,
     0x0e20,
     0x0e21,
     0x0e22,
     0x0e23,
     0x0e24,
     0x0e25,
     0x0e26,
     0x0e27,
     0x0e28,
     0x0e29,
     0x0e2a,
     0x0e2b,
     0x0e2c,
     0x0e2d,
     0x0e2e,
     0x0e2f,
     0x0e30,
     0x0e31,
     0x0e32,
     0x0e33,
     0x0e34,
     0x0e35,
     0x0e36,
     0x0e37,
     0x0e38,
     0x0e39,
     0x0e3a,
     0xfeff,
     0x200b,
     0x2013,
     0x2014,
     0x0e3f,
     0x0e40,
     0x0e41,
     0x0e42,
     0x0e43,
     0x0e44,
     0x0e45,
     0x0e46,
     0x0e47,
     0x0e48,
     0x0e49,
     0x0e4a,
     0x0e4b,
     0x0e4c,
     0x0e4d,
     0x2122,
     0x0e4f,
     0x0e50,
     0x0e51,
     0x0e52,
     0x0e53,
     0x0e54,
     0x0e55,
     0x0e56,
     0x0e57,
     0x0e58,
     0x0e59,
     0x00ae,
     0x00a9,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\x04",
     "\x05",
     "\x06",
     "\x07",
     "\x08",
     "\x09",
     "\x0a",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\x14",
     "\x15",
     "\x16",
     "\x17",
     "\x18",
     "\x19",
     "\x1a",
     "\x1b",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\x20",
     "\x21",
     "\x22",
     "\x23",
     "\x24",
     "\x25",
     "\x26",
     "\x27",
     "\x28",
     "\x29",
     "\x2a",
     "\x2b",
     "\x2c",
     "\x2d",
     "\x2e",
     "\x2f",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\x3a",
     "\x3b",
     "\x3c",
     "\x3d",
     "\x3e",
     "\x3f",
     "\x40",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\x5b",
     "\x5c",
     "\x5d",
     "\x5e",
     "\x5f",
     "\x60",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\x7b",
     "\x7c",
     "\x7d",
     "\x7e",
     "\x7f",
     "\xc2\xab",
     "\xc2\xbb",
     "\xe2\x80\xa6",
     "\xef\xa2\x8c",
     "\xef\xa2\x8f",
     "\xef\xa2\x92",
     "\xef\xa2\x95",
     "\xef\xa2\x98",
     "\xef\xa2\x8b",
     "\xef\xa2\x8e",
     "\xef\xa2\x91",
     "\xef\xa2\x94",
     "\xef\xa2\x97",
     "\xe2\x80\x9c",
     "\xe2\x80\x9d",
     "\xef\xa2\x99",
     "\xef\xbf\xbd",
     "\xe2\x80\xa2",
     "\xef\xa2\x84",
     "\xef\xa2\x89",
     "\xef\xa2\x85",
     "\xef\xa2\x86",
     "\xef\xa2\x87",
     "\xef\xa2\x88",
     "\xef\xa2\x8a",
     "\xef\xa2\x8d",
     "\xef\xa2\x90",
     "\xef\xa2\x93",
     "\xef\xa2\x96",
     "\xe2\x80\x98",
     "\xe2\x80\x99",
     "\xef\xbf\xbd",
     "\xc2\xa0",
     "\xe0\xb8\x81",
     "\xe0\xb8\x82",
     "\xe0\xb8\x83",
     "\xe0\xb8\x84",
     "\xe0\xb8\x85",
     "\xe0\xb8\x86",
     "\xe0\xb8\x87",
     "\xe0\xb8\x88",
     "\xe0\xb8\x89",
     "\xe0\xb8\x8a",
     "\xe0\xb8\x8b",
     "\xe0\xb8\x8c",
     "\xe0\xb8\x8d",
     "\xe0\xb8\x8e",
     "\xe0\xb8\x8f",
     "\xe0\xb8\x90",
     "\xe0\xb8\x91",
     "\xe0\xb8\x92",
     "\xe0\xb8\x93",
     "\xe0\xb8\x94",
     "\xe0\xb8\x95",
     "\xe0\xb8\x96",
     "\xe0\xb8\x97",
     "\xe0\xb8\x98",
     "\xe0\xb8\x99",
     "\xe0\xb8\x9a",
     "\xe0\xb8\x9b",
     "\xe0\xb8\x9c",
     "\xe0\xb8\x9d",
     "\xe0\xb8\x9e",
     "\xe0\xb8\x9f",
     "\xe0\xb8\xa0",
     "\xe0\xb8\xa1",
     "\xe0\xb8\xa2",
     "\xe0\xb8\xa3",
     "\xe0\xb8\xa4",
     "\xe0\xb8\xa5",
     "\xe0\xb8\xa6",
     "\xe0\xb8\xa7",
     "\xe0\xb8\xa8",
     "\xe0\xb8\xa9",
     "\xe0\xb8\xaa",
     "\xe0\xb8\xab",
     "\xe0\xb8\xac",
     "\xe0\xb8\xad",
     "\xe0\xb8\xae",
     "\xe0\xb8\xaf",
     "\xe0\xb8\xb0",
     "\xe0\xb8\xb1",
     "\xe0\xb8\xb2",
     "\xe0\xb8\xb3",
     "\xe0\xb8\xb4",
     "\xe0\xb8\xb5",
     "\xe0\xb8\xb6",
     "\xe0\xb8\xb7",
     "\xe0\xb8\xb8",
     "\xe0\xb8\xb9",
     "\xe0\xb8\xba",
     "\xef\xbb\xbf",
     "\xe2\x80\x8b",
     "\xe2\x80\x93",
     "\xe2\x80\x94",
     "\xe0\xb8\xbf",
     "\xe0\xb9\x80",
     "\xe0\xb9\x81",
     "\xe0\xb9\x82",
     "\xe0\xb9\x83",
     "\xe0\xb9\x84",
     "\xe0\xb9\x85",
     "\xe0\xb9\x86",
     "\xe0\xb9\x87",
     "\xe0\xb9\x88",
     "\xe0\xb9\x89",
     "\xe0\xb9\x8a",
     "\xe0\xb9\x8b",
     "\xe0\xb9\x8c",
     "\xe0\xb9\x8d",
     "\xe2\x84\xa2",
     "\xe0\xb9\x8f",
     "\xe0\xb9\x90",
     "\xe0\xb9\x91",
     "\xe0\xb9\x92",
     "\xe0\xb9\x93",
     "\xe0\xb9\x94",
     "\xe0\xb9\x95",
     "\xe0\xb9\x96",
     "\xe0\xb9\x97",
     "\xe0\xb9\x98",
     "\xe0\xb9\x99",
     "\xc2\xae",
     "\xc2\xa9",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x04",
     0x00000005 => "\x05",
     0x00000006 => "\x06",
     0x00000007 => "\x07",
     0x00000008 => "\x08",
     0x00000009 => "\x09",
     0x0000000a => "\x0a",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x14",
     0x00000015 => "\x15",
     0x00000016 => "\x16",
     0x00000017 => "\x17",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x1a",
     0x0000001b => "\x1b",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x20",
     0x00000021 => "\x21",
     0x00000022 => "\x22",
     0x00000023 => "\x23",
     0x00000024 => "\x24",
     0x00000025 => "\x25",
     0x00000026 => "\x26",
     0x00000027 => "\x27",
     0x00000028 => "\x28",
     0x00000029 => "\x29",
     0x0000002a => "\x2a",
     0x0000002b => "\x2b",
     0x0000002c => "\x2c",
     0x0000002d => "\x2d",
     0x0000002e => "\x2e",
     0x0000002f => "\x2f",
     0x00000030 => "\x30",
     0x00000031 => "\x31",
     0x00000032 => "\x32",
     0x00000033 => "\x33",
     0x00000034 => "\x34",
     0x00000035 => "\x35",
     0x00000036 => "\x36",
     0x00000037 => "\x37",
     0x00000038 => "\x38",
     0x00000039 => "\x39",
     0x0000003a => "\x3a",
     0x0000003b => "\x3b",
     0x0000003c => "\x3c",
     0x0000003d => "\x3d",
     0x0000003e => "\x3e",
     0x0000003f => "\x3f",
     0x00000040 => "\x40",
     0x00000041 => "\x41",
     0x00000042 => "\x42",
     0x00000043 => "\x43",
     0x00000044 => "\x44",
     0x00000045 => "\x45",
     0x00000046 => "\x46",
     0x00000047 => "\x47",
     0x00000048 => "\x48",
     0x00000049 => "\x49",
     0x0000004a => "\x4a",
     0x0000004b => "\x4b",
     0x0000004c => "\x4c",
     0x0000004d => "\x4d",
     0x0000004e => "\x4e",
     0x0000004f => "\x4f",
     0x00000050 => "\x50",
     0x00000051 => "\x51",
     0x00000052 => "\x52",
     0x00000053 => "\x53",
     0x00000054 => "\x54",
     0x00000055 => "\x55",
     0x00000056 => "\x56",
     0x00000057 => "\x57",
     0x00000058 => "\x58",
     0x00000059 => "\x59",
     0x0000005a => "\x5a",
     0x0000005b => "\x5b",
     0x0000005c => "\x5c",
     0x0000005d => "\x5d",
     0x0000005e => "\x5e",
     0x0000005f => "\x5f",
     0x00000060 => "\x60",
     0x00000061 => "\x61",
     0x00000062 => "\x62",
     0x00000063 => "\x63",
     0x00000064 => "\x64",
     0x00000065 => "\x65",
     0x00000066 => "\x66",
     0x00000067 => "\x67",
     0x00000068 => "\x68",
     0x00000069 => "\x69",
     0x0000006a => "\x6a",
     0x0000006b => "\x6b",
     0x0000006c => "\x6c",
     0x0000006d => "\x6d",
     0x0000006e => "\x6e",
     0x0000006f => "\x6f",
     0x00000070 => "\x70",
     0x00000071 => "\x71",
     0x00000072 => "\x72",
     0x00000073 => "\x73",
     0x00000074 => "\x74",
     0x00000075 => "\x75",
     0x00000076 => "\x76",
     0x00000077 => "\x77",
     0x00000078 => "\x78",
     0x00000079 => "\x79",
     0x0000007a => "\x7a",
     0x0000007b => "\x7b",
     0x0000007c => "\x7c",
     0x0000007d => "\x7d",
     0x0000007e => "\x7e",
     0x0000007f => "\x7f",
     0x000000a0 => "\xa0",
     0x000000a9 => "\xfb",
     0x000000ab => "\x80",
     0x000000ae => "\xfa",
     0x000000bb => "\x81",
     0x00000e01 => "\xa1",
     0x00000e02 => "\xa2",
     0x00000e03 => "\xa3",
     0x00000e04 => "\xa4",
     0x00000e05 => "\xa5",
     0x00000e06 => "\xa6",
     0x00000e07 => "\xa7",
     0x00000e08 => "\xa8",
     0x00000e09 => "\xa9",
     0x00000e0a => "\xaa",
     0x00000e0b => "\xab",
     0x00000e0c => "\xac",
     0x00000e0d => "\xad",
     0x00000e0e => "\xae",
     0x00000e0f => "\xaf",
     0x00000e10 => "\xb0",
     0x00000e11 => "\xb1",
     0x00000e12 => "\xb2",
     0x00000e13 => "\xb3",
     0x00000e14 => "\xb4",
     0x00000e15 => "\xb5",
     0x00000e16 => "\xb6",
     0x00000e17 => "\xb7",
     0x00000e18 => "\xb8",
     0x00000e19 => "\xb9",
     0x00000e1a => "\xba",
     0x00000e1b => "\xbb",
     0x00000e1c => "\xbc",
     0x00000e1d => "\xbd",
     0x00000e1e => "\xbe",
     0x00000e1f => "\xbf",
     0x00000e20 => "\xc0",
     0x00000e21 => "\xc1",
     0x00000e22 => "\xc2",
     0x00000e23 => "\xc3",
     0x00000e24 => "\xc4",
     0x00000e25 => "\xc5",
     0x00000e26 => "\xc6",
     0x00000e27 => "\xc7",
     0x00000e28 => "\xc8",
     0x00000e29 => "\xc9",
     0x00000e2a => "\xca",
     0x00000e2b => "\xcb",
     0x00000e2c => "\xcc",
     0x00000e2d => "\xcd",
     0x00000e2e => "\xce",
     0x00000e2f => "\xcf",
     0x00000e30 => "\xd0",
     0x00000e31 => "\xd1",
     0x00000e32 => "\xd2",
     0x00000e33 => "\xd3",
     0x00000e34 => "\xd4",
     0x00000e35 => "\xd5",
     0x00000e36 => "\xd6",
     0x00000e37 => "\xd7",
     0x00000e38 => "\xd8",
     0x00000e39 => "\xd9",
     0x00000e3a => "\xda",
     0x00000e3f => "\xdf",
     0x00000e40 => "\xe0",
     0x00000e41 => "\xe1",
     0x00000e42 => "\xe2",
     0x00000e43 => "\xe3",
     0x00000e44 => "\xe4",
     0x00000e45 => "\xe5",
     0x00000e46 => "\xe6",
     0x00000e47 => "\xe7",
     0x00000e48 => "\xe8",
     0x00000e49 => "\xe9",
     0x00000e4a => "\xea",
     0x00000e4b => "\xeb",
     0x00000e4c => "\xec",
     0x00000e4d => "\xed",
     0x00000e4f => "\xef",
     0x00000e50 => "\xf0",
     0x00000e51 => "\xf1",
     0x00000e52 => "\xf2",
     0x00000e53 => "\xf3",
     0x00000e54 => "\xf4",
     0x00000e55 => "\xf5",
     0x00000e56 => "\xf6",
     0x00000e57 => "\xf7",
     0x00000e58 => "\xf8",
     0x00000e59 => "\xf9",
     0x0000200b => "\xdc",
     0x00002013 => "\xdd",
     0x00002014 => "\xde",
     0x00002018 => "\x9d",
     0x00002019 => "\x9e",
     0x0000201c => "\x8d",
     0x0000201d => "\x8e",
     0x00002022 => "\x91",
     0x00002026 => "\x82",
     0x00002122 => "\xee",
     0x0000f884 => "\x92",
     0x0000f885 => "\x94",
     0x0000f886 => "\x95",
     0x0000f887 => "\x96",
     0x0000f888 => "\x97",
     0x0000f889 => "\x93",
     0x0000f88a => "\x98",
     0x0000f88b => "\x88",
     0x0000f88c => "\x83",
     0x0000f88d => "\x99",
     0x0000f88e => "\x89",
     0x0000f88f => "\x84",
     0x0000f890 => "\x9a",
     0x0000f891 => "\x8a",
     0x0000f892 => "\x85",
     0x0000f893 => "\x9b",
     0x0000f894 => "\x8b",
     0x0000f895 => "\x86",
     0x0000f896 => "\x9c",
     0x0000f897 => "\x8c",
     0x0000f898 => "\x87",
     0x0000f899 => "\x8f",
     0x0000feff => "\xdb",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::MACTHAI - Conversion routines for MACTHAI
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for MACTHAI.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
 
  This charmap has been generated automatically from GNU libiconv
  conversions.
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  00000004 | END OF TRANSMISSION (EOT)
     05 |  00000005 | ENQUIRY (ENQ)
     06 |  00000006 | ACKNOWLEDGE (ACK)
     07 |  00000007 | BELL (BEL)
     08 |  00000008 | BACKSPACE (BS)
     09 |  00000009 | CHARACTER TABULATION (HT)
     0A |  0000000A | LINE FEED (LF)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  00000014 | DEVICE CONTROL FOUR (DC4)
     15 |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     16 |  00000016 | SYNCHRONOUS IDLE (SYN)
     17 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  0000001A | SUBSTITUTE (SUB)
     1B |  0000001B | ESCAPE (ESC)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000020 | SPACE
     21 |  00000021 | EXCLAMATION MARK
     22 |  00000022 | QUOTATION MARK
     23 |  00000023 | NUMBER SIGN
     24 |  00000024 | DOLLAR SIGN
     25 |  00000025 | PERCENT SIGN
     26 |  00000026 | AMPERSAND
     27 |  00000027 | APOSTROPHE
     28 |  00000028 | LEFT PARENTHESIS
     29 |  00000029 | RIGHT PARENTHESIS
     2A |  0000002A | ASTERISK
     2B |  0000002B | PLUS SIGN
     2C |  0000002C | COMMA
     2D |  0000002D | HYPHEN-MINUS
     2E |  0000002E | FULL STOP
     2F |  0000002F | SOLIDUS
     30 |  00000030 | DIGIT ZERO
     31 |  00000031 | DIGIT ONE
     32 |  00000032 | DIGIT TWO
     33 |  00000033 | DIGIT THREE
     34 |  00000034 | DIGIT FOUR
     35 |  00000035 | DIGIT FIVE
     36 |  00000036 | DIGIT SIX
     37 |  00000037 | DIGIT SEVEN
     38 |  00000038 | DIGIT EIGHT
     39 |  00000039 | DIGIT NINE
     3A |  0000003A | COLON
     3B |  0000003B | SEMICOLON
     3C |  0000003C | LESS-THAN SIGN
     3D |  0000003D | EQUALS SIGN
     3E |  0000003E | GREATER-THAN SIGN
     3F |  0000003F | QUESTION MARK
     40 |  00000040 | COMMERCIAL AT
     41 |  00000041 | LATIN CAPITAL LETTER A
     42 |  00000042 | LATIN CAPITAL LETTER B
     43 |  00000043 | LATIN CAPITAL LETTER C
     44 |  00000044 | LATIN CAPITAL LETTER D
     45 |  00000045 | LATIN CAPITAL LETTER E
     46 |  00000046 | LATIN CAPITAL LETTER F
     47 |  00000047 | LATIN CAPITAL LETTER G
     48 |  00000048 | LATIN CAPITAL LETTER H
     49 |  00000049 | LATIN CAPITAL LETTER I
     4A |  0000004A | LATIN CAPITAL LETTER J
     4B |  0000004B | LATIN CAPITAL LETTER K
     4C |  0000004C | LATIN CAPITAL LETTER L
     4D |  0000004D | LATIN CAPITAL LETTER M
     4E |  0000004E | LATIN CAPITAL LETTER N
     4F |  0000004F | LATIN CAPITAL LETTER O
     50 |  00000050 | LATIN CAPITAL LETTER P
     51 |  00000051 | LATIN CAPITAL LETTER Q
     52 |  00000052 | LATIN CAPITAL LETTER R
     53 |  00000053 | LATIN CAPITAL LETTER S
     54 |  00000054 | LATIN CAPITAL LETTER T
     55 |  00000055 | LATIN CAPITAL LETTER U
     56 |  00000056 | LATIN CAPITAL LETTER V
     57 |  00000057 | LATIN CAPITAL LETTER W
     58 |  00000058 | LATIN CAPITAL LETTER X
     59 |  00000059 | LATIN CAPITAL LETTER Y
     5A |  0000005A | LATIN CAPITAL LETTER Z
     5B |  0000005B | LEFT SQUARE BRACKET
     5C |  0000005C | REVERSE SOLIDUS
     5D |  0000005D | RIGHT SQUARE BRACKET
     5E |  0000005E | CIRCUMFLEX ACCENT
     5F |  0000005F | LOW LINE
     60 |  00000060 | GRAVE ACCENT
     61 |  00000061 | LATIN SMALL LETTER A
     62 |  00000062 | LATIN SMALL LETTER B
     63 |  00000063 | LATIN SMALL LETTER C
     64 |  00000064 | LATIN SMALL LETTER D
     65 |  00000065 | LATIN SMALL LETTER E
     66 |  00000066 | LATIN SMALL LETTER F
     67 |  00000067 | LATIN SMALL LETTER G
     68 |  00000068 | LATIN SMALL LETTER H
     69 |  00000069 | LATIN SMALL LETTER I
     6A |  0000006A | LATIN SMALL LETTER J
     6B |  0000006B | LATIN SMALL LETTER K
     6C |  0000006C | LATIN SMALL LETTER L
     6D |  0000006D | LATIN SMALL LETTER M
     6E |  0000006E | LATIN SMALL LETTER N
     6F |  0000006F | LATIN SMALL LETTER O
     70 |  00000070 | LATIN SMALL LETTER P
     71 |  00000071 | LATIN SMALL LETTER Q
     72 |  00000072 | LATIN SMALL LETTER R
     73 |  00000073 | LATIN SMALL LETTER S
     74 |  00000074 | LATIN SMALL LETTER T
     75 |  00000075 | LATIN SMALL LETTER U
     76 |  00000076 | LATIN SMALL LETTER V
     77 |  00000077 | LATIN SMALL LETTER W
     78 |  00000078 | LATIN SMALL LETTER X
     79 |  00000079 | LATIN SMALL LETTER Y
     7A |  0000007A | LATIN SMALL LETTER Z
     7B |  0000007B | LEFT CURLY BRACKET
     7C |  0000007C | VERTICAL LINE
     7D |  0000007D | RIGHT CURLY BRACKET
     7E |  0000007E | TILDE
     7F |  0000007F | DELETE (DEL)
     80 |  000000AB | LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
     81 |  000000BB | RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
     82 |  00002026 | HORIZONTAL ELLIPSIS
     83 |  0000F88C | E<lt>CJKE<gt>
     84 |  0000F88F | E<lt>CJKE<gt>
     85 |  0000F892 | E<lt>CJKE<gt>
     86 |  0000F895 | E<lt>CJKE<gt>
     87 |  0000F898 | E<lt>CJKE<gt>
     88 |  0000F88B | E<lt>CJKE<gt>
     89 |  0000F88E | E<lt>CJKE<gt>
     8A |  0000F891 | E<lt>CJKE<gt>
     8B |  0000F894 | E<lt>CJKE<gt>
     8C |  0000F897 | E<lt>CJKE<gt>
     8D |  0000201C | LEFT DOUBLE QUOTATION MARK
     8E |  0000201D | RIGHT DOUBLE QUOTATION MARK
     8F |  0000F899 | E<lt>CJKE<gt>
     91 |  00002022 | BULLET
     92 |  0000F884 | E<lt>CJKE<gt>
     93 |  0000F889 | E<lt>CJKE<gt>
     94 |  0000F885 | E<lt>CJKE<gt>
     95 |  0000F886 | E<lt>CJKE<gt>
     96 |  0000F887 | E<lt>CJKE<gt>
     97 |  0000F888 | E<lt>CJKE<gt>
     98 |  0000F88A | E<lt>CJKE<gt>
     99 |  0000F88D | E<lt>CJKE<gt>
     9A |  0000F890 | E<lt>CJKE<gt>
     9B |  0000F893 | E<lt>CJKE<gt>
     9C |  0000F896 | E<lt>CJKE<gt>
     9D |  00002018 | LEFT SINGLE QUOTATION MARK
     9E |  00002019 | RIGHT SINGLE QUOTATION MARK
     A0 |  000000A0 | NO-BREAK SPACE
     A1 |  00000E01 | THAI CHARACTER KO KAI
     A2 |  00000E02 | THAI CHARACTER KHO KHAI
     A3 |  00000E03 | THAI CHARACTER KHO KHUAT
     A4 |  00000E04 | THAI CHARACTER KHO KHWAI
     A5 |  00000E05 | THAI CHARACTER KHO KHON
     A6 |  00000E06 | THAI CHARACTER KHO RAKHANG
     A7 |  00000E07 | THAI CHARACTER NGO NGU
     A8 |  00000E08 | THAI CHARACTER CHO CHAN
     A9 |  00000E09 | THAI CHARACTER CHO CHING
     AA |  00000E0A | THAI CHARACTER CHO CHANG
     AB |  00000E0B | THAI CHARACTER SO SO
     AC |  00000E0C | THAI CHARACTER CHO CHOE
     AD |  00000E0D | THAI CHARACTER YO YING
     AE |  00000E0E | THAI CHARACTER DO CHADA
     AF |  00000E0F | THAI CHARACTER TO PATAK
     B0 |  00000E10 | THAI CHARACTER THO THAN
     B1 |  00000E11 | THAI CHARACTER THO NANGMONTHO
     B2 |  00000E12 | THAI CHARACTER THO PHUTHAO
     B3 |  00000E13 | THAI CHARACTER NO NEN
     B4 |  00000E14 | THAI CHARACTER DO DEK
     B5 |  00000E15 | THAI CHARACTER TO TAO
     B6 |  00000E16 | THAI CHARACTER THO THUNG
     B7 |  00000E17 | THAI CHARACTER THO THAHAN
     B8 |  00000E18 | THAI CHARACTER THO THONG
     B9 |  00000E19 | THAI CHARACTER NO NU
     BA |  00000E1A | THAI CHARACTER BO BAIMAI
     BB |  00000E1B | THAI CHARACTER PO PLA
     BC |  00000E1C | THAI CHARACTER PHO PHUNG
     BD |  00000E1D | THAI CHARACTER FO FA
     BE |  00000E1E | THAI CHARACTER PHO PHAN
     BF |  00000E1F | THAI CHARACTER FO FAN
     C0 |  00000E20 | THAI CHARACTER PHO SAMPHAO
     C1 |  00000E21 | THAI CHARACTER MO MA
     C2 |  00000E22 | THAI CHARACTER YO YAK
     C3 |  00000E23 | THAI CHARACTER RO RUA
     C4 |  00000E24 | THAI CHARACTER RU
     C5 |  00000E25 | THAI CHARACTER LO LING
     C6 |  00000E26 | THAI CHARACTER LU
     C7 |  00000E27 | THAI CHARACTER WO WAEN
     C8 |  00000E28 | THAI CHARACTER SO SALA
     C9 |  00000E29 | THAI CHARACTER SO RUSI
     CA |  00000E2A | THAI CHARACTER SO SUA
     CB |  00000E2B | THAI CHARACTER HO HIP
     CC |  00000E2C | THAI CHARACTER LO CHULA
     CD |  00000E2D | THAI CHARACTER O ANG
     CE |  00000E2E | THAI CHARACTER HO NOKHUK
     CF |  00000E2F | THAI CHARACTER PAIYANNOI
     D0 |  00000E30 | THAI CHARACTER SARA A
     D1 |  00000E31 | THAI CHARACTER MAI HAN-AKAT
     D2 |  00000E32 | THAI CHARACTER SARA AA
     D3 |  00000E33 | THAI CHARACTER SARA AM
     D4 |  00000E34 | THAI CHARACTER SARA I
     D5 |  00000E35 | THAI CHARACTER SARA II
     D6 |  00000E36 | THAI CHARACTER SARA UE
     D7 |  00000E37 | THAI CHARACTER SARA UEE
     D8 |  00000E38 | THAI CHARACTER SARA U
     D9 |  00000E39 | THAI CHARACTER SARA UU
     DA |  00000E3A | THAI CHARACTER PHINTHU
     DB |  0000FEFF | ZERO WIDTH NO-BREAK SPACE
     DC |  0000200B | ZERO WIDTH SPACE
     DD |  00002013 | EN DASH
     DE |  00002014 | EM DASH
     DF |  00000E3F | THAI CURRENCY SYMBOL BAHT
     E0 |  00000E40 | THAI CHARACTER SARA E
     E1 |  00000E41 | THAI CHARACTER SARA AE
     E2 |  00000E42 | THAI CHARACTER SARA O
     E3 |  00000E43 | THAI CHARACTER SARA AI MAIMUAN
     E4 |  00000E44 | THAI CHARACTER SARA AI MAIMALAI
     E5 |  00000E45 | THAI CHARACTER LAKKHANGYAO
     E6 |  00000E46 | THAI CHARACTER MAIYAMOK
     E7 |  00000E47 | THAI CHARACTER MAITAIKHU
     E8 |  00000E48 | THAI CHARACTER MAI EK
     E9 |  00000E49 | THAI CHARACTER MAI THO
     EA |  00000E4A | THAI CHARACTER MAI TRI
     EB |  00000E4B | THAI CHARACTER MAI CHATTAWA
     EC |  00000E4C | THAI CHARACTER THANTHAKHAT
     ED |  00000E4D | THAI CHARACTER NIKHAHIT
     EE |  00002122 | TRADE MARK SIGN
     EF |  00000E4F | THAI CHARACTER FONGMAN
     F0 |  00000E50 | THAI DIGIT ZERO
     F1 |  00000E51 | THAI DIGIT ONE
     F2 |  00000E52 | THAI DIGIT TWO
     F3 |  00000E53 | THAI DIGIT THREE
     F4 |  00000E54 | THAI DIGIT FOUR
     F5 |  00000E55 | THAI DIGIT FIVE
     F6 |  00000E56 | THAI DIGIT SIX
     F7 |  00000E57 | THAI DIGIT SEVEN
     F8 |  00000E58 | THAI DIGIT EIGHT
     F9 |  00000E59 | THAI DIGIT NINE
     FA |  000000AE | REGISTERED SIGN
     FB |  000000A9 | COPYRIGHT SIGN
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/MACTURKISH.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for MACTURKISH.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::MACTURKISH;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x0004,
     0x0005,
     0x0006,
     0x0007,
     0x0008,
     0x0009,
     0x000a,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x0014,
     0x0015,
     0x0016,
     0x0017,
     0x0018,
     0x0019,
     0x001a,
     0x001b,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0020,
     0x0021,
     0x0022,
     0x0023,
     0x0024,
     0x0025,
     0x0026,
     0x0027,
     0x0028,
     0x0029,
     0x002a,
     0x002b,
     0x002c,
     0x002d,
     0x002e,
     0x002f,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x003a,
     0x003b,
     0x003c,
     0x003d,
     0x003e,
     0x003f,
     0x0040,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x005b,
     0x005c,
     0x005d,
     0x005e,
     0x005f,
     0x0060,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x007b,
     0x007c,
     0x007d,
     0x007e,
     0x007f,
     0x00c4,
     0x00c5,
     0x00c7,
     0x00c9,
     0x00d1,
     0x00d6,
     0x00dc,
     0x00e1,
     0x00e0,
     0x00e2,
     0x00e4,
     0x00e3,
     0x00e5,
     0x00e7,
     0x00e9,
     0x00e8,
     0x00ea,
     0x00eb,
     0x00ed,
     0x00ec,
     0x00ee,
     0x00ef,
     0x00f1,
     0x00f3,
     0x00f2,
     0x00f4,
     0x00f6,
     0x00f5,
     0x00fa,
     0x00f9,
     0x00fb,
     0x00fc,
     0x2020,
     0x00b0,
     0x00a2,
     0x00a3,
     0x00a7,
     0x2022,
     0x00b6,
     0x00df,
     0x00ae,
     0x00a9,
     0x2122,
     0x00b4,
     0x00a8,
     0x2260,
     0x00c6,
     0x00d8,
     0x221e,
     0x00b1,
     0x2264,
     0x2265,
     0x00a5,
     0x00b5,
     0x2202,
     0x2211,
     0x220f,
     0x03c0,
     0x222b,
     0x00aa,
     0x00ba,
     0x2126,
     0x00e6,
     0x00f8,
     0x00bf,
     0x00a1,
     0x00ac,
     0x221a,
     0x0192,
     0x2248,
     0x2206,
     0x00ab,
     0x00bb,
     0x2026,
     0x00a0,
     0x00c0,
     0x00c3,
     0x00d5,
     0x0152,
     0x0153,
     0x2013,
     0x2014,
     0x201c,
     0x201d,
     0x2018,
     0x2019,
     0x00f7,
     0x25ca,
     0x00ff,
     0x0178,
     0x011e,
     0x011f,
     0x0130,
     0x0131,
     0x015e,
     0x015f,
     0x2021,
     0x00b7,
     0x201a,
     0x201e,
     0x2030,
     0x00c2,
     0x00ca,
     0x00c1,
     0x00cb,
     0x00c8,
     0x00cd,
     0x00ce,
     0x00cf,
     0x00cc,
     0x00d3,
     0x00d4,
     0xfffd,
     0x00d2,
     0x00da,
     0x00db,
     0x00d9,
     0xfffd,
     0x02c6,
     0x02dc,
     0x00af,
     0x02d8,
     0x02d9,
     0x02da,
     0x00b8,
     0x02dd,
     0x02db,
     0x02c7,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\x04",
     "\x05",
     "\x06",
     "\x07",
     "\x08",
     "\x09",
     "\x0a",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\x14",
     "\x15",
     "\x16",
     "\x17",
     "\x18",
     "\x19",
     "\x1a",
     "\x1b",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\x20",
     "\x21",
     "\x22",
     "\x23",
     "\x24",
     "\x25",
     "\x26",
     "\x27",
     "\x28",
     "\x29",
     "\x2a",
     "\x2b",
     "\x2c",
     "\x2d",
     "\x2e",
     "\x2f",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\x3a",
     "\x3b",
     "\x3c",
     "\x3d",
     "\x3e",
     "\x3f",
     "\x40",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\x5b",
     "\x5c",
     "\x5d",
     "\x5e",
     "\x5f",
     "\x60",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\x7b",
     "\x7c",
     "\x7d",
     "\x7e",
     "\x7f",
     "\xc3\x84",
     "\xc3\x85",
     "\xc3\x87",
     "\xc3\x89",
     "\xc3\x91",
     "\xc3\x96",
     "\xc3\x9c",
     "\xc3\xa1",
     "\xc3\xa0",
     "\xc3\xa2",
     "\xc3\xa4",
     "\xc3\xa3",
     "\xc3\xa5",
     "\xc3\xa7",
     "\xc3\xa9",
     "\xc3\xa8",
     "\xc3\xaa",
     "\xc3\xab",
     "\xc3\xad",
     "\xc3\xac",
     "\xc3\xae",
     "\xc3\xaf",
     "\xc3\xb1",
     "\xc3\xb3",
     "\xc3\xb2",
     "\xc3\xb4",
     "\xc3\xb6",
     "\xc3\xb5",
     "\xc3\xba",
     "\xc3\xb9",
     "\xc3\xbb",
     "\xc3\xbc",
     "\xe2\x80\xa0",
     "\xc2\xb0",
     "\xc2\xa2",
     "\xc2\xa3",
     "\xc2\xa7",
     "\xe2\x80\xa2",
     "\xc2\xb6",
     "\xc3\x9f",
     "\xc2\xae",
     "\xc2\xa9",
     "\xe2\x84\xa2",
     "\xc2\xb4",
     "\xc2\xa8",
     "\xe2\x89\xa0",
     "\xc3\x86",
     "\xc3\x98",
     "\xe2\x88\x9e",
     "\xc2\xb1",
     "\xe2\x89\xa4",
     "\xe2\x89\xa5",
     "\xc2\xa5",
     "\xc2\xb5",
     "\xe2\x88\x82",
     "\xe2\x88\x91",
     "\xe2\x88\x8f",
     "\xcf\x80",
     "\xe2\x88\xab",
     "\xc2\xaa",
     "\xc2\xba",
     "\xe2\x84\xa6",
     "\xc3\xa6",
     "\xc3\xb8",
     "\xc2\xbf",
     "\xc2\xa1",
     "\xc2\xac",
     "\xe2\x88\x9a",
     "\xc6\x92",
     "\xe2\x89\x88",
     "\xe2\x88\x86",
     "\xc2\xab",
     "\xc2\xbb",
     "\xe2\x80\xa6",
     "\xc2\xa0",
     "\xc3\x80",
     "\xc3\x83",
     "\xc3\x95",
     "\xc5\x92",
     "\xc5\x93",
     "\xe2\x80\x93",
     "\xe2\x80\x94",
     "\xe2\x80\x9c",
     "\xe2\x80\x9d",
     "\xe2\x80\x98",
     "\xe2\x80\x99",
     "\xc3\xb7",
     "\xe2\x97\x8a",
     "\xc3\xbf",
     "\xc5\xb8",
     "\xc4\x9e",
     "\xc4\x9f",
     "\xc4\xb0",
     "\xc4\xb1",
     "\xc5\x9e",
     "\xc5\x9f",
     "\xe2\x80\xa1",
     "\xc2\xb7",
     "\xe2\x80\x9a",
     "\xe2\x80\x9e",
     "\xe2\x80\xb0",
     "\xc3\x82",
     "\xc3\x8a",
     "\xc3\x81",
     "\xc3\x8b",
     "\xc3\x88",
     "\xc3\x8d",
     "\xc3\x8e",
     "\xc3\x8f",
     "\xc3\x8c",
     "\xc3\x93",
     "\xc3\x94",
     "\xef\xbf\xbd",
     "\xc3\x92",
     "\xc3\x9a",
     "\xc3\x9b",
     "\xc3\x99",
     "\xef\xbf\xbd",
     "\xcb\x86",
     "\xcb\x9c",
     "\xc2\xaf",
     "\xcb\x98",
     "\xcb\x99",
     "\xcb\x9a",
     "\xc2\xb8",
     "\xcb\x9d",
     "\xcb\x9b",
     "\xcb\x87",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x04",
     0x00000005 => "\x05",
     0x00000006 => "\x06",
     0x00000007 => "\x07",
     0x00000008 => "\x08",
     0x00000009 => "\x09",
     0x0000000a => "\x0a",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x14",
     0x00000015 => "\x15",
     0x00000016 => "\x16",
     0x00000017 => "\x17",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x1a",
     0x0000001b => "\x1b",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x20",
     0x00000021 => "\x21",
     0x00000022 => "\x22",
     0x00000023 => "\x23",
     0x00000024 => "\x24",
     0x00000025 => "\x25",
     0x00000026 => "\x26",
     0x00000027 => "\x27",
     0x00000028 => "\x28",
     0x00000029 => "\x29",
     0x0000002a => "\x2a",
     0x0000002b => "\x2b",
     0x0000002c => "\x2c",
     0x0000002d => "\x2d",
     0x0000002e => "\x2e",
     0x0000002f => "\x2f",
     0x00000030 => "\x30",
     0x00000031 => "\x31",
     0x00000032 => "\x32",
     0x00000033 => "\x33",
     0x00000034 => "\x34",
     0x00000035 => "\x35",
     0x00000036 => "\x36",
     0x00000037 => "\x37",
     0x00000038 => "\x38",
     0x00000039 => "\x39",
     0x0000003a => "\x3a",
     0x0000003b => "\x3b",
     0x0000003c => "\x3c",
     0x0000003d => "\x3d",
     0x0000003e => "\x3e",
     0x0000003f => "\x3f",
     0x00000040 => "\x40",
     0x00000041 => "\x41",
     0x00000042 => "\x42",
     0x00000043 => "\x43",
     0x00000044 => "\x44",
     0x00000045 => "\x45",
     0x00000046 => "\x46",
     0x00000047 => "\x47",
     0x00000048 => "\x48",
     0x00000049 => "\x49",
     0x0000004a => "\x4a",
     0x0000004b => "\x4b",
     0x0000004c => "\x4c",
     0x0000004d => "\x4d",
     0x0000004e => "\x4e",
     0x0000004f => "\x4f",
     0x00000050 => "\x50",
     0x00000051 => "\x51",
     0x00000052 => "\x52",
     0x00000053 => "\x53",
     0x00000054 => "\x54",
     0x00000055 => "\x55",
     0x00000056 => "\x56",
     0x00000057 => "\x57",
     0x00000058 => "\x58",
     0x00000059 => "\x59",
     0x0000005a => "\x5a",
     0x0000005b => "\x5b",
     0x0000005c => "\x5c",
     0x0000005d => "\x5d",
     0x0000005e => "\x5e",
     0x0000005f => "\x5f",
     0x00000060 => "\x60",
     0x00000061 => "\x61",
     0x00000062 => "\x62",
     0x00000063 => "\x63",
     0x00000064 => "\x64",
     0x00000065 => "\x65",
     0x00000066 => "\x66",
     0x00000067 => "\x67",
     0x00000068 => "\x68",
     0x00000069 => "\x69",
     0x0000006a => "\x6a",
     0x0000006b => "\x6b",
     0x0000006c => "\x6c",
     0x0000006d => "\x6d",
     0x0000006e => "\x6e",
     0x0000006f => "\x6f",
     0x00000070 => "\x70",
     0x00000071 => "\x71",
     0x00000072 => "\x72",
     0x00000073 => "\x73",
     0x00000074 => "\x74",
     0x00000075 => "\x75",
     0x00000076 => "\x76",
     0x00000077 => "\x77",
     0x00000078 => "\x78",
     0x00000079 => "\x79",
     0x0000007a => "\x7a",
     0x0000007b => "\x7b",
     0x0000007c => "\x7c",
     0x0000007d => "\x7d",
     0x0000007e => "\x7e",
     0x0000007f => "\x7f",
     0x000000a0 => "\xca",
     0x000000a1 => "\xc1",
     0x000000a2 => "\xa2",
     0x000000a3 => "\xa3",
     0x000000a5 => "\xb4",
     0x000000a7 => "\xa4",
     0x000000a8 => "\xac",
     0x000000a9 => "\xa9",
     0x000000aa => "\xbb",
     0x000000ab => "\xc7",
     0x000000ac => "\xc2",
     0x000000ae => "\xa8",
     0x000000af => "\xf8",
     0x000000b0 => "\xa1",
     0x000000b1 => "\xb1",
     0x000000b4 => "\xab",
     0x000000b5 => "\xb5",
     0x000000b6 => "\xa6",
     0x000000b7 => "\xe1",
     0x000000b8 => "\xfc",
     0x000000ba => "\xbc",
     0x000000bb => "\xc8",
     0x000000bf => "\xc0",
     0x000000c0 => "\xcb",
     0x000000c1 => "\xe7",
     0x000000c2 => "\xe5",
     0x000000c3 => "\xcc",
     0x000000c4 => "\x80",
     0x000000c5 => "\x81",
     0x000000c6 => "\xae",
     0x000000c7 => "\x82",
     0x000000c8 => "\xe9",
     0x000000c9 => "\x83",
     0x000000ca => "\xe6",
     0x000000cb => "\xe8",
     0x000000cc => "\xed",
     0x000000cd => "\xea",
     0x000000ce => "\xeb",
     0x000000cf => "\xec",
     0x000000d1 => "\x84",
     0x000000d2 => "\xf1",
     0x000000d3 => "\xee",
     0x000000d4 => "\xef",
     0x000000d5 => "\xcd",
     0x000000d6 => "\x85",
     0x000000d8 => "\xaf",
     0x000000d9 => "\xf4",
     0x000000da => "\xf2",
     0x000000db => "\xf3",
     0x000000dc => "\x86",
     0x000000df => "\xa7",
     0x000000e0 => "\x88",
     0x000000e1 => "\x87",
     0x000000e2 => "\x89",
     0x000000e3 => "\x8b",
     0x000000e4 => "\x8a",
     0x000000e5 => "\x8c",
     0x000000e6 => "\xbe",
     0x000000e7 => "\x8d",
     0x000000e8 => "\x8f",
     0x000000e9 => "\x8e",
     0x000000ea => "\x90",
     0x000000eb => "\x91",
     0x000000ec => "\x93",
     0x000000ed => "\x92",
     0x000000ee => "\x94",
     0x000000ef => "\x95",
     0x000000f1 => "\x96",
     0x000000f2 => "\x98",
     0x000000f3 => "\x97",
     0x000000f4 => "\x99",
     0x000000f5 => "\x9b",
     0x000000f6 => "\x9a",
     0x000000f7 => "\xd6",
     0x000000f8 => "\xbf",
     0x000000f9 => "\x9d",
     0x000000fa => "\x9c",
     0x000000fb => "\x9e",
     0x000000fc => "\x9f",
     0x000000ff => "\xd8",
     0x0000011e => "\xda",
     0x0000011f => "\xdb",
     0x00000130 => "\xdc",
     0x00000131 => "\xdd",
     0x00000152 => "\xce",
     0x00000153 => "\xcf",
     0x0000015e => "\xde",
     0x0000015f => "\xdf",
     0x00000178 => "\xd9",
     0x00000192 => "\xc4",
     0x000002c6 => "\xf6",
     0x000002c7 => "\xff",
     0x000002d8 => "\xf9",
     0x000002d9 => "\xfa",
     0x000002da => "\xfb",
     0x000002db => "\xfe",
     0x000002dc => "\xf7",
     0x000002dd => "\xfd",
     0x000003c0 => "\xb9",
     0x00002013 => "\xd0",
     0x00002014 => "\xd1",
     0x00002018 => "\xd4",
     0x00002019 => "\xd5",
     0x0000201a => "\xe2",
     0x0000201c => "\xd2",
     0x0000201d => "\xd3",
     0x0000201e => "\xe3",
     0x00002020 => "\xa0",
     0x00002021 => "\xe0",
     0x00002022 => "\xa5",
     0x00002026 => "\xc9",
     0x00002030 => "\xe4",
     0x00002122 => "\xaa",
     0x00002126 => "\xbd",
     0x00002202 => "\xb6",
     0x00002206 => "\xc6",
     0x0000220f => "\xb8",
     0x00002211 => "\xb7",
     0x0000221a => "\xc3",
     0x0000221e => "\xb0",
     0x0000222b => "\xba",
     0x00002248 => "\xc5",
     0x00002260 => "\xad",
     0x00002264 => "\xb2",
     0x00002265 => "\xb3",
     0x000025ca => "\xd7",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::MACTURKISH - Conversion routines for MACTURKISH
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for MACTURKISH.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
 
  This charmap has been generated automatically from GNU libiconv
  conversions.
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  00000004 | END OF TRANSMISSION (EOT)
     05 |  00000005 | ENQUIRY (ENQ)
     06 |  00000006 | ACKNOWLEDGE (ACK)
     07 |  00000007 | BELL (BEL)
     08 |  00000008 | BACKSPACE (BS)
     09 |  00000009 | CHARACTER TABULATION (HT)
     0A |  0000000A | LINE FEED (LF)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  00000014 | DEVICE CONTROL FOUR (DC4)
     15 |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     16 |  00000016 | SYNCHRONOUS IDLE (SYN)
     17 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  0000001A | SUBSTITUTE (SUB)
     1B |  0000001B | ESCAPE (ESC)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000020 | SPACE
     21 |  00000021 | EXCLAMATION MARK
     22 |  00000022 | QUOTATION MARK
     23 |  00000023 | NUMBER SIGN
     24 |  00000024 | DOLLAR SIGN
     25 |  00000025 | PERCENT SIGN
     26 |  00000026 | AMPERSAND
     27 |  00000027 | APOSTROPHE
     28 |  00000028 | LEFT PARENTHESIS
     29 |  00000029 | RIGHT PARENTHESIS
     2A |  0000002A | ASTERISK
     2B |  0000002B | PLUS SIGN
     2C |  0000002C | COMMA
     2D |  0000002D | HYPHEN-MINUS
     2E |  0000002E | FULL STOP
     2F |  0000002F | SOLIDUS
     30 |  00000030 | DIGIT ZERO
     31 |  00000031 | DIGIT ONE
     32 |  00000032 | DIGIT TWO
     33 |  00000033 | DIGIT THREE
     34 |  00000034 | DIGIT FOUR
     35 |  00000035 | DIGIT FIVE
     36 |  00000036 | DIGIT SIX
     37 |  00000037 | DIGIT SEVEN
     38 |  00000038 | DIGIT EIGHT
     39 |  00000039 | DIGIT NINE
     3A |  0000003A | COLON
     3B |  0000003B | SEMICOLON
     3C |  0000003C | LESS-THAN SIGN
     3D |  0000003D | EQUALS SIGN
     3E |  0000003E | GREATER-THAN SIGN
     3F |  0000003F | QUESTION MARK
     40 |  00000040 | COMMERCIAL AT
     41 |  00000041 | LATIN CAPITAL LETTER A
     42 |  00000042 | LATIN CAPITAL LETTER B
     43 |  00000043 | LATIN CAPITAL LETTER C
     44 |  00000044 | LATIN CAPITAL LETTER D
     45 |  00000045 | LATIN CAPITAL LETTER E
     46 |  00000046 | LATIN CAPITAL LETTER F
     47 |  00000047 | LATIN CAPITAL LETTER G
     48 |  00000048 | LATIN CAPITAL LETTER H
     49 |  00000049 | LATIN CAPITAL LETTER I
     4A |  0000004A | LATIN CAPITAL LETTER J
     4B |  0000004B | LATIN CAPITAL LETTER K
     4C |  0000004C | LATIN CAPITAL LETTER L
     4D |  0000004D | LATIN CAPITAL LETTER M
     4E |  0000004E | LATIN CAPITAL LETTER N
     4F |  0000004F | LATIN CAPITAL LETTER O
     50 |  00000050 | LATIN CAPITAL LETTER P
     51 |  00000051 | LATIN CAPITAL LETTER Q
     52 |  00000052 | LATIN CAPITAL LETTER R
     53 |  00000053 | LATIN CAPITAL LETTER S
     54 |  00000054 | LATIN CAPITAL LETTER T
     55 |  00000055 | LATIN CAPITAL LETTER U
     56 |  00000056 | LATIN CAPITAL LETTER V
     57 |  00000057 | LATIN CAPITAL LETTER W
     58 |  00000058 | LATIN CAPITAL LETTER X
     59 |  00000059 | LATIN CAPITAL LETTER Y
     5A |  0000005A | LATIN CAPITAL LETTER Z
     5B |  0000005B | LEFT SQUARE BRACKET
     5C |  0000005C | REVERSE SOLIDUS
     5D |  0000005D | RIGHT SQUARE BRACKET
     5E |  0000005E | CIRCUMFLEX ACCENT
     5F |  0000005F | LOW LINE
     60 |  00000060 | GRAVE ACCENT
     61 |  00000061 | LATIN SMALL LETTER A
     62 |  00000062 | LATIN SMALL LETTER B
     63 |  00000063 | LATIN SMALL LETTER C
     64 |  00000064 | LATIN SMALL LETTER D
     65 |  00000065 | LATIN SMALL LETTER E
     66 |  00000066 | LATIN SMALL LETTER F
     67 |  00000067 | LATIN SMALL LETTER G
     68 |  00000068 | LATIN SMALL LETTER H
     69 |  00000069 | LATIN SMALL LETTER I
     6A |  0000006A | LATIN SMALL LETTER J
     6B |  0000006B | LATIN SMALL LETTER K
     6C |  0000006C | LATIN SMALL LETTER L
     6D |  0000006D | LATIN SMALL LETTER M
     6E |  0000006E | LATIN SMALL LETTER N
     6F |  0000006F | LATIN SMALL LETTER O
     70 |  00000070 | LATIN SMALL LETTER P
     71 |  00000071 | LATIN SMALL LETTER Q
     72 |  00000072 | LATIN SMALL LETTER R
     73 |  00000073 | LATIN SMALL LETTER S
     74 |  00000074 | LATIN SMALL LETTER T
     75 |  00000075 | LATIN SMALL LETTER U
     76 |  00000076 | LATIN SMALL LETTER V
     77 |  00000077 | LATIN SMALL LETTER W
     78 |  00000078 | LATIN SMALL LETTER X
     79 |  00000079 | LATIN SMALL LETTER Y
     7A |  0000007A | LATIN SMALL LETTER Z
     7B |  0000007B | LEFT CURLY BRACKET
     7C |  0000007C | VERTICAL LINE
     7D |  0000007D | RIGHT CURLY BRACKET
     7E |  0000007E | TILDE
     7F |  0000007F | DELETE (DEL)
     80 |  000000C4 | LATIN CAPITAL LETTER A WITH DIAERESIS
     81 |  000000C5 | LATIN CAPITAL LETTER A WITH RING ABOVE
     82 |  000000C7 | LATIN CAPITAL LETTER C WITH CEDILLA
     83 |  000000C9 | LATIN CAPITAL LETTER E WITH ACUTE
     84 |  000000D1 | LATIN CAPITAL LETTER N WITH TILDE
     85 |  000000D6 | LATIN CAPITAL LETTER O WITH DIAERESIS
     86 |  000000DC | LATIN CAPITAL LETTER U WITH DIAERESIS
     87 |  000000E1 | LATIN SMALL LETTER A WITH ACUTE
     88 |  000000E0 | LATIN SMALL LETTER A WITH GRAVE
     89 |  000000E2 | LATIN SMALL LETTER A WITH CIRCUMFLEX
     8A |  000000E4 | LATIN SMALL LETTER A WITH DIAERESIS
     8B |  000000E3 | LATIN SMALL LETTER A WITH TILDE
     8C |  000000E5 | LATIN SMALL LETTER A WITH RING ABOVE
     8D |  000000E7 | LATIN SMALL LETTER C WITH CEDILLA
     8E |  000000E9 | LATIN SMALL LETTER E WITH ACUTE
     8F |  000000E8 | LATIN SMALL LETTER E WITH GRAVE
     90 |  000000EA | LATIN SMALL LETTER E WITH CIRCUMFLEX
     91 |  000000EB | LATIN SMALL LETTER E WITH DIAERESIS
     92 |  000000ED | LATIN SMALL LETTER I WITH ACUTE
     93 |  000000EC | LATIN SMALL LETTER I WITH GRAVE
     94 |  000000EE | LATIN SMALL LETTER I WITH CIRCUMFLEX
     95 |  000000EF | LATIN SMALL LETTER I WITH DIAERESIS
     96 |  000000F1 | LATIN SMALL LETTER N WITH TILDE
     97 |  000000F3 | LATIN SMALL LETTER O WITH ACUTE
     98 |  000000F2 | LATIN SMALL LETTER O WITH GRAVE
     99 |  000000F4 | LATIN SMALL LETTER O WITH CIRCUMFLEX
     9A |  000000F6 | LATIN SMALL LETTER O WITH DIAERESIS
     9B |  000000F5 | LATIN SMALL LETTER O WITH TILDE
     9C |  000000FA | LATIN SMALL LETTER U WITH ACUTE
     9D |  000000F9 | LATIN SMALL LETTER U WITH GRAVE
     9E |  000000FB | LATIN SMALL LETTER U WITH CIRCUMFLEX
     9F |  000000FC | LATIN SMALL LETTER U WITH DIAERESIS
     A0 |  00002020 | DAGGER
     A1 |  000000B0 | DEGREE SIGN
     A2 |  000000A2 | CENT SIGN
     A3 |  000000A3 | POUND SIGN
     A4 |  000000A7 | SECTION SIGN
     A5 |  00002022 | BULLET
     A6 |  000000B6 | PILCROW SIGN
     A7 |  000000DF | LATIN SMALL LETTER SHARP S
     A8 |  000000AE | REGISTERED SIGN
     A9 |  000000A9 | COPYRIGHT SIGN
     AA |  00002122 | TRADE MARK SIGN
     AB |  000000B4 | ACUTE ACCENT
     AC |  000000A8 | DIAERESIS
     AD |  00002260 | NOT EQUAL TO
     AE |  000000C6 | LATIN CAPITAL LETTER AE
     AF |  000000D8 | LATIN CAPITAL LETTER O WITH STROKE
     B0 |  0000221E | INFINITY
     B1 |  000000B1 | PLUS-MINUS SIGN
     B2 |  00002264 | LESS-THAN OR EQUAL TO
     B3 |  00002265 | GREATER-THAN OR EQUAL TO
     B4 |  000000A5 | YEN SIGN
     B5 |  000000B5 | MICRO SIGN
     B6 |  00002202 | PARTIAL DIFFERENTIAL
     B7 |  00002211 | N-ARY SUMMATION
     B8 |  0000220F | N-ARY PRODUCT
     B9 |  000003C0 | GREEK SMALL LETTER PI
     BA |  0000222B | INTEGRAL
     BB |  000000AA | FEMININE ORDINAL INDICATOR
     BC |  000000BA | MASCULINE ORDINAL INDICATOR
     BD |  00002126 | OHM SIGN
     BE |  000000E6 | LATIN SMALL LETTER AE
     BF |  000000F8 | LATIN SMALL LETTER O WITH STROKE
     C0 |  000000BF | INVERTED QUESTION MARK
     C1 |  000000A1 | INVERTED EXCLAMATION MARK
     C2 |  000000AC | NOT SIGN
     C3 |  0000221A | SQUARE ROOT
     C4 |  00000192 | LATIN SMALL LETTER F WITH HOOK
     C5 |  00002248 | ALMOST EQUAL TO
     C6 |  00002206 | INCREMENT
     C7 |  000000AB | LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
     C8 |  000000BB | RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
     C9 |  00002026 | HORIZONTAL ELLIPSIS
     CA |  000000A0 | NO-BREAK SPACE
     CB |  000000C0 | LATIN CAPITAL LETTER A WITH GRAVE
     CC |  000000C3 | LATIN CAPITAL LETTER A WITH TILDE
     CD |  000000D5 | LATIN CAPITAL LETTER O WITH TILDE
     CE |  00000152 | LATIN CAPITAL LIGATURE OE
     CF |  00000153 | LATIN SMALL LIGATURE OE
     D0 |  00002013 | EN DASH
     D1 |  00002014 | EM DASH
     D2 |  0000201C | LEFT DOUBLE QUOTATION MARK
     D3 |  0000201D | RIGHT DOUBLE QUOTATION MARK
     D4 |  00002018 | LEFT SINGLE QUOTATION MARK
     D5 |  00002019 | RIGHT SINGLE QUOTATION MARK
     D6 |  000000F7 | DIVISION SIGN
     D7 |  000025CA | LOZENGE
     D8 |  000000FF | LATIN SMALL LETTER Y WITH DIAERESIS
     D9 |  00000178 | LATIN CAPITAL LETTER Y WITH DIAERESIS
     DA |  0000011E | LATIN CAPITAL LETTER G WITH BREVE
     DB |  0000011F | LATIN SMALL LETTER G WITH BREVE
     DC |  00000130 | LATIN CAPITAL LETTER I WITH DOT ABOVE
     DD |  00000131 | LATIN SMALL LETTER DOTLESS I
     DE |  0000015E | LATIN CAPITAL LETTER S WITH CEDILLA
     DF |  0000015F | LATIN SMALL LETTER S WITH CEDILLA
     E0 |  00002021 | DOUBLE DAGGER
     E1 |  000000B7 | MIDDLE DOT
     E2 |  0000201A | SINGLE LOW-9 QUOTATION MARK
     E3 |  0000201E | DOUBLE LOW-9 QUOTATION MARK
     E4 |  00002030 | PER MILLE SIGN
     E5 |  000000C2 | LATIN CAPITAL LETTER A WITH CIRCUMFLEX
     E6 |  000000CA | LATIN CAPITAL LETTER E WITH CIRCUMFLEX
     E7 |  000000C1 | LATIN CAPITAL LETTER A WITH ACUTE
     E8 |  000000CB | LATIN CAPITAL LETTER E WITH DIAERESIS
     E9 |  000000C8 | LATIN CAPITAL LETTER E WITH GRAVE
     EA |  000000CD | LATIN CAPITAL LETTER I WITH ACUTE
     EB |  000000CE | LATIN CAPITAL LETTER I WITH CIRCUMFLEX
     EC |  000000CF | LATIN CAPITAL LETTER I WITH DIAERESIS
     ED |  000000CC | LATIN CAPITAL LETTER I WITH GRAVE
     EE |  000000D3 | LATIN CAPITAL LETTER O WITH ACUTE
     EF |  000000D4 | LATIN CAPITAL LETTER O WITH CIRCUMFLEX
     F1 |  000000D2 | LATIN CAPITAL LETTER O WITH GRAVE
     F2 |  000000DA | LATIN CAPITAL LETTER U WITH ACUTE
     F3 |  000000DB | LATIN CAPITAL LETTER U WITH CIRCUMFLEX
     F4 |  000000D9 | LATIN CAPITAL LETTER U WITH GRAVE
     F6 |  000002C6 | MODIFIER LETTER CIRCUMFLEX ACCENT
     F7 |  000002DC | SMALL TILDE
     F8 |  000000AF | MACRON
     F9 |  000002D8 | BREVE
     FA |  000002D9 | DOT ABOVE
     FB |  000002DA | RING ABOVE
     FC |  000000B8 | CEDILLA
     FD |  000002DD | DOUBLE ACUTE ACCENT
     FE |  000002DB | OGONEK
     FF |  000002C7 | CARON
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/MACUKRAINE.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for MACUKRAINE.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::MACUKRAINE;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x0004,
     0x0005,
     0x0006,
     0x0007,
     0x0008,
     0x0009,
     0x000a,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x0014,
     0x0015,
     0x0016,
     0x0017,
     0x0018,
     0x0019,
     0x001a,
     0x001b,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0020,
     0x0021,
     0x0022,
     0x0023,
     0x0024,
     0x0025,
     0x0026,
     0x0027,
     0x0028,
     0x0029,
     0x002a,
     0x002b,
     0x002c,
     0x002d,
     0x002e,
     0x002f,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x003a,
     0x003b,
     0x003c,
     0x003d,
     0x003e,
     0x003f,
     0x0040,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x005b,
     0x005c,
     0x005d,
     0x005e,
     0x005f,
     0x0060,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x007b,
     0x007c,
     0x007d,
     0x007e,
     0x007f,
     0x0410,
     0x0411,
     0x0412,
     0x0413,
     0x0414,
     0x0415,
     0x0416,
     0x0417,
     0x0418,
     0x0419,
     0x041a,
     0x041b,
     0x041c,
     0x041d,
     0x041e,
     0x041f,
     0x0420,
     0x0421,
     0x0422,
     0x0423,
     0x0424,
     0x0425,
     0x0426,
     0x0427,
     0x0428,
     0x0429,
     0x042a,
     0x042b,
     0x042c,
     0x042d,
     0x042e,
     0x042f,
     0x2020,
     0x00b0,
     0x0490,
     0x00a3,
     0x00a7,
     0x2022,
     0x00b6,
     0x0406,
     0x00ae,
     0x00a9,
     0x2122,
     0x0402,
     0x0452,
     0x2260,
     0x0403,
     0x0453,
     0x221e,
     0x00b1,
     0x2264,
     0x2265,
     0x0456,
     0x00b5,
     0x0491,
     0x0408,
     0x0404,
     0x0454,
     0x0407,
     0x0457,
     0x0409,
     0x0459,
     0x040a,
     0x045a,
     0x0458,
     0x0405,
     0x00ac,
     0x221a,
     0x0192,
     0x2248,
     0x2206,
     0x00ab,
     0x00bb,
     0x2026,
     0x00a0,
     0x040b,
     0x045b,
     0x040c,
     0x045c,
     0x0455,
     0x2013,
     0x2014,
     0x201c,
     0x201d,
     0x2018,
     0x2019,
     0x00f7,
     0x201e,
     0x040e,
     0x045e,
     0x040f,
     0x045f,
     0x2116,
     0x0401,
     0x0451,
     0x044f,
     0x0430,
     0x0431,
     0x0432,
     0x0433,
     0x0434,
     0x0435,
     0x0436,
     0x0437,
     0x0438,
     0x0439,
     0x043a,
     0x043b,
     0x043c,
     0x043d,
     0x043e,
     0x043f,
     0x0440,
     0x0441,
     0x0442,
     0x0443,
     0x0444,
     0x0445,
     0x0446,
     0x0447,
     0x0448,
     0x0449,
     0x044a,
     0x044b,
     0x044c,
     0x044d,
     0x044e,
     0x00a4,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\x04",
     "\x05",
     "\x06",
     "\x07",
     "\x08",
     "\x09",
     "\x0a",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\x14",
     "\x15",
     "\x16",
     "\x17",
     "\x18",
     "\x19",
     "\x1a",
     "\x1b",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\x20",
     "\x21",
     "\x22",
     "\x23",
     "\x24",
     "\x25",
     "\x26",
     "\x27",
     "\x28",
     "\x29",
     "\x2a",
     "\x2b",
     "\x2c",
     "\x2d",
     "\x2e",
     "\x2f",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\x3a",
     "\x3b",
     "\x3c",
     "\x3d",
     "\x3e",
     "\x3f",
     "\x40",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\x5b",
     "\x5c",
     "\x5d",
     "\x5e",
     "\x5f",
     "\x60",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\x7b",
     "\x7c",
     "\x7d",
     "\x7e",
     "\x7f",
     "\xd0\x90",
     "\xd0\x91",
     "\xd0\x92",
     "\xd0\x93",
     "\xd0\x94",
     "\xd0\x95",
     "\xd0\x96",
     "\xd0\x97",
     "\xd0\x98",
     "\xd0\x99",
     "\xd0\x9a",
     "\xd0\x9b",
     "\xd0\x9c",
     "\xd0\x9d",
     "\xd0\x9e",
     "\xd0\x9f",
     "\xd0\xa0",
     "\xd0\xa1",
     "\xd0\xa2",
     "\xd0\xa3",
     "\xd0\xa4",
     "\xd0\xa5",
     "\xd0\xa6",
     "\xd0\xa7",
     "\xd0\xa8",
     "\xd0\xa9",
     "\xd0\xaa",
     "\xd0\xab",
     "\xd0\xac",
     "\xd0\xad",
     "\xd0\xae",
     "\xd0\xaf",
     "\xe2\x80\xa0",
     "\xc2\xb0",
     "\xd2\x90",
     "\xc2\xa3",
     "\xc2\xa7",
     "\xe2\x80\xa2",
     "\xc2\xb6",
     "\xd0\x86",
     "\xc2\xae",
     "\xc2\xa9",
     "\xe2\x84\xa2",
     "\xd0\x82",
     "\xd1\x92",
     "\xe2\x89\xa0",
     "\xd0\x83",
     "\xd1\x93",
     "\xe2\x88\x9e",
     "\xc2\xb1",
     "\xe2\x89\xa4",
     "\xe2\x89\xa5",
     "\xd1\x96",
     "\xc2\xb5",
     "\xd2\x91",
     "\xd0\x88",
     "\xd0\x84",
     "\xd1\x94",
     "\xd0\x87",
     "\xd1\x97",
     "\xd0\x89",
     "\xd1\x99",
     "\xd0\x8a",
     "\xd1\x9a",
     "\xd1\x98",
     "\xd0\x85",
     "\xc2\xac",
     "\xe2\x88\x9a",
     "\xc6\x92",
     "\xe2\x89\x88",
     "\xe2\x88\x86",
     "\xc2\xab",
     "\xc2\xbb",
     "\xe2\x80\xa6",
     "\xc2\xa0",
     "\xd0\x8b",
     "\xd1\x9b",
     "\xd0\x8c",
     "\xd1\x9c",
     "\xd1\x95",
     "\xe2\x80\x93",
     "\xe2\x80\x94",
     "\xe2\x80\x9c",
     "\xe2\x80\x9d",
     "\xe2\x80\x98",
     "\xe2\x80\x99",
     "\xc3\xb7",
     "\xe2\x80\x9e",
     "\xd0\x8e",
     "\xd1\x9e",
     "\xd0\x8f",
     "\xd1\x9f",
     "\xe2\x84\x96",
     "\xd0\x81",
     "\xd1\x91",
     "\xd1\x8f",
     "\xd0\xb0",
     "\xd0\xb1",
     "\xd0\xb2",
     "\xd0\xb3",
     "\xd0\xb4",
     "\xd0\xb5",
     "\xd0\xb6",
     "\xd0\xb7",
     "\xd0\xb8",
     "\xd0\xb9",
     "\xd0\xba",
     "\xd0\xbb",
     "\xd0\xbc",
     "\xd0\xbd",
     "\xd0\xbe",
     "\xd0\xbf",
     "\xd1\x80",
     "\xd1\x81",
     "\xd1\x82",
     "\xd1\x83",
     "\xd1\x84",
     "\xd1\x85",
     "\xd1\x86",
     "\xd1\x87",
     "\xd1\x88",
     "\xd1\x89",
     "\xd1\x8a",
     "\xd1\x8b",
     "\xd1\x8c",
     "\xd1\x8d",
     "\xd1\x8e",
     "\xc2\xa4",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x04",
     0x00000005 => "\x05",
     0x00000006 => "\x06",
     0x00000007 => "\x07",
     0x00000008 => "\x08",
     0x00000009 => "\x09",
     0x0000000a => "\x0a",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x14",
     0x00000015 => "\x15",
     0x00000016 => "\x16",
     0x00000017 => "\x17",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x1a",
     0x0000001b => "\x1b",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x20",
     0x00000021 => "\x21",
     0x00000022 => "\x22",
     0x00000023 => "\x23",
     0x00000024 => "\x24",
     0x00000025 => "\x25",
     0x00000026 => "\x26",
     0x00000027 => "\x27",
     0x00000028 => "\x28",
     0x00000029 => "\x29",
     0x0000002a => "\x2a",
     0x0000002b => "\x2b",
     0x0000002c => "\x2c",
     0x0000002d => "\x2d",
     0x0000002e => "\x2e",
     0x0000002f => "\x2f",
     0x00000030 => "\x30",
     0x00000031 => "\x31",
     0x00000032 => "\x32",
     0x00000033 => "\x33",
     0x00000034 => "\x34",
     0x00000035 => "\x35",
     0x00000036 => "\x36",
     0x00000037 => "\x37",
     0x00000038 => "\x38",
     0x00000039 => "\x39",
     0x0000003a => "\x3a",
     0x0000003b => "\x3b",
     0x0000003c => "\x3c",
     0x0000003d => "\x3d",
     0x0000003e => "\x3e",
     0x0000003f => "\x3f",
     0x00000040 => "\x40",
     0x00000041 => "\x41",
     0x00000042 => "\x42",
     0x00000043 => "\x43",
     0x00000044 => "\x44",
     0x00000045 => "\x45",
     0x00000046 => "\x46",
     0x00000047 => "\x47",
     0x00000048 => "\x48",
     0x00000049 => "\x49",
     0x0000004a => "\x4a",
     0x0000004b => "\x4b",
     0x0000004c => "\x4c",
     0x0000004d => "\x4d",
     0x0000004e => "\x4e",
     0x0000004f => "\x4f",
     0x00000050 => "\x50",
     0x00000051 => "\x51",
     0x00000052 => "\x52",
     0x00000053 => "\x53",
     0x00000054 => "\x54",
     0x00000055 => "\x55",
     0x00000056 => "\x56",
     0x00000057 => "\x57",
     0x00000058 => "\x58",
     0x00000059 => "\x59",
     0x0000005a => "\x5a",
     0x0000005b => "\x5b",
     0x0000005c => "\x5c",
     0x0000005d => "\x5d",
     0x0000005e => "\x5e",
     0x0000005f => "\x5f",
     0x00000060 => "\x60",
     0x00000061 => "\x61",
     0x00000062 => "\x62",
     0x00000063 => "\x63",
     0x00000064 => "\x64",
     0x00000065 => "\x65",
     0x00000066 => "\x66",
     0x00000067 => "\x67",
     0x00000068 => "\x68",
     0x00000069 => "\x69",
     0x0000006a => "\x6a",
     0x0000006b => "\x6b",
     0x0000006c => "\x6c",
     0x0000006d => "\x6d",
     0x0000006e => "\x6e",
     0x0000006f => "\x6f",
     0x00000070 => "\x70",
     0x00000071 => "\x71",
     0x00000072 => "\x72",
     0x00000073 => "\x73",
     0x00000074 => "\x74",
     0x00000075 => "\x75",
     0x00000076 => "\x76",
     0x00000077 => "\x77",
     0x00000078 => "\x78",
     0x00000079 => "\x79",
     0x0000007a => "\x7a",
     0x0000007b => "\x7b",
     0x0000007c => "\x7c",
     0x0000007d => "\x7d",
     0x0000007e => "\x7e",
     0x0000007f => "\x7f",
     0x000000a0 => "\xca",
     0x000000a3 => "\xa3",
     0x000000a4 => "\xff",
     0x000000a7 => "\xa4",
     0x000000a9 => "\xa9",
     0x000000ab => "\xc7",
     0x000000ac => "\xc2",
     0x000000ae => "\xa8",
     0x000000b0 => "\xa1",
     0x000000b1 => "\xb1",
     0x000000b5 => "\xb5",
     0x000000b6 => "\xa6",
     0x000000bb => "\xc8",
     0x000000f7 => "\xd6",
     0x00000192 => "\xc4",
     0x00000401 => "\xdd",
     0x00000402 => "\xab",
     0x00000403 => "\xae",
     0x00000404 => "\xb8",
     0x00000405 => "\xc1",
     0x00000406 => "\xa7",
     0x00000407 => "\xba",
     0x00000408 => "\xb7",
     0x00000409 => "\xbc",
     0x0000040a => "\xbe",
     0x0000040b => "\xcb",
     0x0000040c => "\xcd",
     0x0000040e => "\xd8",
     0x0000040f => "\xda",
     0x00000410 => "\x80",
     0x00000411 => "\x81",
     0x00000412 => "\x82",
     0x00000413 => "\x83",
     0x00000414 => "\x84",
     0x00000415 => "\x85",
     0x00000416 => "\x86",
     0x00000417 => "\x87",
     0x00000418 => "\x88",
     0x00000419 => "\x89",
     0x0000041a => "\x8a",
     0x0000041b => "\x8b",
     0x0000041c => "\x8c",
     0x0000041d => "\x8d",
     0x0000041e => "\x8e",
     0x0000041f => "\x8f",
     0x00000420 => "\x90",
     0x00000421 => "\x91",
     0x00000422 => "\x92",
     0x00000423 => "\x93",
     0x00000424 => "\x94",
     0x00000425 => "\x95",
     0x00000426 => "\x96",
     0x00000427 => "\x97",
     0x00000428 => "\x98",
     0x00000429 => "\x99",
     0x0000042a => "\x9a",
     0x0000042b => "\x9b",
     0x0000042c => "\x9c",
     0x0000042d => "\x9d",
     0x0000042e => "\x9e",
     0x0000042f => "\x9f",
     0x00000430 => "\xe0",
     0x00000431 => "\xe1",
     0x00000432 => "\xe2",
     0x00000433 => "\xe3",
     0x00000434 => "\xe4",
     0x00000435 => "\xe5",
     0x00000436 => "\xe6",
     0x00000437 => "\xe7",
     0x00000438 => "\xe8",
     0x00000439 => "\xe9",
     0x0000043a => "\xea",
     0x0000043b => "\xeb",
     0x0000043c => "\xec",
     0x0000043d => "\xed",
     0x0000043e => "\xee",
     0x0000043f => "\xef",
     0x00000440 => "\xf0",
     0x00000441 => "\xf1",
     0x00000442 => "\xf2",
     0x00000443 => "\xf3",
     0x00000444 => "\xf4",
     0x00000445 => "\xf5",
     0x00000446 => "\xf6",
     0x00000447 => "\xf7",
     0x00000448 => "\xf8",
     0x00000449 => "\xf9",
     0x0000044a => "\xfa",
     0x0000044b => "\xfb",
     0x0000044c => "\xfc",
     0x0000044d => "\xfd",
     0x0000044e => "\xfe",
     0x0000044f => "\xdf",
     0x00000451 => "\xde",
     0x00000452 => "\xac",
     0x00000453 => "\xaf",
     0x00000454 => "\xb9",
     0x00000455 => "\xcf",
     0x00000456 => "\xb4",
     0x00000457 => "\xbb",
     0x00000458 => "\xc0",
     0x00000459 => "\xbd",
     0x0000045a => "\xbf",
     0x0000045b => "\xcc",
     0x0000045c => "\xce",
     0x0000045e => "\xd9",
     0x0000045f => "\xdb",
     0x00000490 => "\xa2",
     0x00000491 => "\xb6",
     0x00002013 => "\xd0",
     0x00002014 => "\xd1",
     0x00002018 => "\xd4",
     0x00002019 => "\xd5",
     0x0000201c => "\xd2",
     0x0000201d => "\xd3",
     0x0000201e => "\xd7",
     0x00002020 => "\xa0",
     0x00002022 => "\xa5",
     0x00002026 => "\xc9",
     0x00002116 => "\xdc",
     0x00002122 => "\xaa",
     0x00002206 => "\xc6",
     0x0000221a => "\xc3",
     0x0000221e => "\xb0",
     0x00002248 => "\xc5",
     0x00002260 => "\xad",
     0x00002264 => "\xb2",
     0x00002265 => "\xb3",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::MACUKRAINE - Conversion routines for MACUKRAINE
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for MACUKRAINE.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
 
  This charmap has been generated automatically from GNU libiconv
  conversions.
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  00000004 | END OF TRANSMISSION (EOT)
     05 |  00000005 | ENQUIRY (ENQ)
     06 |  00000006 | ACKNOWLEDGE (ACK)
     07 |  00000007 | BELL (BEL)
     08 |  00000008 | BACKSPACE (BS)
     09 |  00000009 | CHARACTER TABULATION (HT)
     0A |  0000000A | LINE FEED (LF)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  00000014 | DEVICE CONTROL FOUR (DC4)
     15 |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     16 |  00000016 | SYNCHRONOUS IDLE (SYN)
     17 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  0000001A | SUBSTITUTE (SUB)
     1B |  0000001B | ESCAPE (ESC)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000020 | SPACE
     21 |  00000021 | EXCLAMATION MARK
     22 |  00000022 | QUOTATION MARK
     23 |  00000023 | NUMBER SIGN
     24 |  00000024 | DOLLAR SIGN
     25 |  00000025 | PERCENT SIGN
     26 |  00000026 | AMPERSAND
     27 |  00000027 | APOSTROPHE
     28 |  00000028 | LEFT PARENTHESIS
     29 |  00000029 | RIGHT PARENTHESIS
     2A |  0000002A | ASTERISK
     2B |  0000002B | PLUS SIGN
     2C |  0000002C | COMMA
     2D |  0000002D | HYPHEN-MINUS
     2E |  0000002E | FULL STOP
     2F |  0000002F | SOLIDUS
     30 |  00000030 | DIGIT ZERO
     31 |  00000031 | DIGIT ONE
     32 |  00000032 | DIGIT TWO
     33 |  00000033 | DIGIT THREE
     34 |  00000034 | DIGIT FOUR
     35 |  00000035 | DIGIT FIVE
     36 |  00000036 | DIGIT SIX
     37 |  00000037 | DIGIT SEVEN
     38 |  00000038 | DIGIT EIGHT
     39 |  00000039 | DIGIT NINE
     3A |  0000003A | COLON
     3B |  0000003B | SEMICOLON
     3C |  0000003C | LESS-THAN SIGN
     3D |  0000003D | EQUALS SIGN
     3E |  0000003E | GREATER-THAN SIGN
     3F |  0000003F | QUESTION MARK
     40 |  00000040 | COMMERCIAL AT
     41 |  00000041 | LATIN CAPITAL LETTER A
     42 |  00000042 | LATIN CAPITAL LETTER B
     43 |  00000043 | LATIN CAPITAL LETTER C
     44 |  00000044 | LATIN CAPITAL LETTER D
     45 |  00000045 | LATIN CAPITAL LETTER E
     46 |  00000046 | LATIN CAPITAL LETTER F
     47 |  00000047 | LATIN CAPITAL LETTER G
     48 |  00000048 | LATIN CAPITAL LETTER H
     49 |  00000049 | LATIN CAPITAL LETTER I
     4A |  0000004A | LATIN CAPITAL LETTER J
     4B |  0000004B | LATIN CAPITAL LETTER K
     4C |  0000004C | LATIN CAPITAL LETTER L
     4D |  0000004D | LATIN CAPITAL LETTER M
     4E |  0000004E | LATIN CAPITAL LETTER N
     4F |  0000004F | LATIN CAPITAL LETTER O
     50 |  00000050 | LATIN CAPITAL LETTER P
     51 |  00000051 | LATIN CAPITAL LETTER Q
     52 |  00000052 | LATIN CAPITAL LETTER R
     53 |  00000053 | LATIN CAPITAL LETTER S
     54 |  00000054 | LATIN CAPITAL LETTER T
     55 |  00000055 | LATIN CAPITAL LETTER U
     56 |  00000056 | LATIN CAPITAL LETTER V
     57 |  00000057 | LATIN CAPITAL LETTER W
     58 |  00000058 | LATIN CAPITAL LETTER X
     59 |  00000059 | LATIN CAPITAL LETTER Y
     5A |  0000005A | LATIN CAPITAL LETTER Z
     5B |  0000005B | LEFT SQUARE BRACKET
     5C |  0000005C | REVERSE SOLIDUS
     5D |  0000005D | RIGHT SQUARE BRACKET
     5E |  0000005E | CIRCUMFLEX ACCENT
     5F |  0000005F | LOW LINE
     60 |  00000060 | GRAVE ACCENT
     61 |  00000061 | LATIN SMALL LETTER A
     62 |  00000062 | LATIN SMALL LETTER B
     63 |  00000063 | LATIN SMALL LETTER C
     64 |  00000064 | LATIN SMALL LETTER D
     65 |  00000065 | LATIN SMALL LETTER E
     66 |  00000066 | LATIN SMALL LETTER F
     67 |  00000067 | LATIN SMALL LETTER G
     68 |  00000068 | LATIN SMALL LETTER H
     69 |  00000069 | LATIN SMALL LETTER I
     6A |  0000006A | LATIN SMALL LETTER J
     6B |  0000006B | LATIN SMALL LETTER K
     6C |  0000006C | LATIN SMALL LETTER L
     6D |  0000006D | LATIN SMALL LETTER M
     6E |  0000006E | LATIN SMALL LETTER N
     6F |  0000006F | LATIN SMALL LETTER O
     70 |  00000070 | LATIN SMALL LETTER P
     71 |  00000071 | LATIN SMALL LETTER Q
     72 |  00000072 | LATIN SMALL LETTER R
     73 |  00000073 | LATIN SMALL LETTER S
     74 |  00000074 | LATIN SMALL LETTER T
     75 |  00000075 | LATIN SMALL LETTER U
     76 |  00000076 | LATIN SMALL LETTER V
     77 |  00000077 | LATIN SMALL LETTER W
     78 |  00000078 | LATIN SMALL LETTER X
     79 |  00000079 | LATIN SMALL LETTER Y
     7A |  0000007A | LATIN SMALL LETTER Z
     7B |  0000007B | LEFT CURLY BRACKET
     7C |  0000007C | VERTICAL LINE
     7D |  0000007D | RIGHT CURLY BRACKET
     7E |  0000007E | TILDE
     7F |  0000007F | DELETE (DEL)
     80 |  00000410 | CYRILLIC CAPITAL LETTER A
     81 |  00000411 | CYRILLIC CAPITAL LETTER BE
     82 |  00000412 | CYRILLIC CAPITAL LETTER VE
     83 |  00000413 | CYRILLIC CAPITAL LETTER GHE
     84 |  00000414 | CYRILLIC CAPITAL LETTER DE
     85 |  00000415 | CYRILLIC CAPITAL LETTER IE
     86 |  00000416 | CYRILLIC CAPITAL LETTER ZHE
     87 |  00000417 | CYRILLIC CAPITAL LETTER ZE
     88 |  00000418 | CYRILLIC CAPITAL LETTER I
     89 |  00000419 | CYRILLIC CAPITAL LETTER SHORT I
     8A |  0000041A | CYRILLIC CAPITAL LETTER KA
     8B |  0000041B | CYRILLIC CAPITAL LETTER EL
     8C |  0000041C | CYRILLIC CAPITAL LETTER EM
     8D |  0000041D | CYRILLIC CAPITAL LETTER EN
     8E |  0000041E | CYRILLIC CAPITAL LETTER O
     8F |  0000041F | CYRILLIC CAPITAL LETTER PE
     90 |  00000420 | CYRILLIC CAPITAL LETTER ER
     91 |  00000421 | CYRILLIC CAPITAL LETTER ES
     92 |  00000422 | CYRILLIC CAPITAL LETTER TE
     93 |  00000423 | CYRILLIC CAPITAL LETTER U
     94 |  00000424 | CYRILLIC CAPITAL LETTER EF
     95 |  00000425 | CYRILLIC CAPITAL LETTER HA
     96 |  00000426 | CYRILLIC CAPITAL LETTER TSE
     97 |  00000427 | CYRILLIC CAPITAL LETTER CHE
     98 |  00000428 | CYRILLIC CAPITAL LETTER SHA
     99 |  00000429 | CYRILLIC CAPITAL LETTER SHCHA
     9A |  0000042A | CYRILLIC CAPITAL LETTER HARD SIGN
     9B |  0000042B | CYRILLIC CAPITAL LETTER YERU
     9C |  0000042C | CYRILLIC CAPITAL LETTER SOFT SIGN
     9D |  0000042D | CYRILLIC CAPITAL LETTER E
     9E |  0000042E | CYRILLIC CAPITAL LETTER YU
     9F |  0000042F | CYRILLIC CAPITAL LETTER YA
     A0 |  00002020 | DAGGER
     A1 |  000000B0 | DEGREE SIGN
     A2 |  00000490 | CYRILLIC CAPITAL LETTER GHE WITH UPTURN
     A3 |  000000A3 | POUND SIGN
     A4 |  000000A7 | SECTION SIGN
     A5 |  00002022 | BULLET
     A6 |  000000B6 | PILCROW SIGN
     A7 |  00000406 | CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I
     A8 |  000000AE | REGISTERED SIGN
     A9 |  000000A9 | COPYRIGHT SIGN
     AA |  00002122 | TRADE MARK SIGN
     AB |  00000402 | CYRILLIC CAPITAL LETTER DJE
     AC |  00000452 | CYRILLIC SMALL LETTER DJE
     AD |  00002260 | NOT EQUAL TO
     AE |  00000403 | CYRILLIC CAPITAL LETTER GJE
     AF |  00000453 | CYRILLIC SMALL LETTER GJE
     B0 |  0000221E | INFINITY
     B1 |  000000B1 | PLUS-MINUS SIGN
     B2 |  00002264 | LESS-THAN OR EQUAL TO
     B3 |  00002265 | GREATER-THAN OR EQUAL TO
     B4 |  00000456 | CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I
     B5 |  000000B5 | MICRO SIGN
     B6 |  00000491 | CYRILLIC SMALL LETTER GHE WITH UPTURN
     B7 |  00000408 | CYRILLIC CAPITAL LETTER JE
     B8 |  00000404 | CYRILLIC CAPITAL LETTER UKRAINIAN IE
     B9 |  00000454 | CYRILLIC SMALL LETTER UKRAINIAN IE
     BA |  00000407 | CYRILLIC CAPITAL LETTER YI
     BB |  00000457 | CYRILLIC SMALL LETTER YI
     BC |  00000409 | CYRILLIC CAPITAL LETTER LJE
     BD |  00000459 | CYRILLIC SMALL LETTER LJE
     BE |  0000040A | CYRILLIC CAPITAL LETTER NJE
     BF |  0000045A | CYRILLIC SMALL LETTER NJE
     C0 |  00000458 | CYRILLIC SMALL LETTER JE
     C1 |  00000405 | CYRILLIC CAPITAL LETTER DZE
     C2 |  000000AC | NOT SIGN
     C3 |  0000221A | SQUARE ROOT
     C4 |  00000192 | LATIN SMALL LETTER F WITH HOOK
     C5 |  00002248 | ALMOST EQUAL TO
     C6 |  00002206 | INCREMENT
     C7 |  000000AB | LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
     C8 |  000000BB | RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
     C9 |  00002026 | HORIZONTAL ELLIPSIS
     CA |  000000A0 | NO-BREAK SPACE
     CB |  0000040B | CYRILLIC CAPITAL LETTER TSHE
     CC |  0000045B | CYRILLIC SMALL LETTER TSHE
     CD |  0000040C | CYRILLIC CAPITAL LETTER KJE
     CE |  0000045C | CYRILLIC SMALL LETTER KJE
     CF |  00000455 | CYRILLIC SMALL LETTER DZE
     D0 |  00002013 | EN DASH
     D1 |  00002014 | EM DASH
     D2 |  0000201C | LEFT DOUBLE QUOTATION MARK
     D3 |  0000201D | RIGHT DOUBLE QUOTATION MARK
     D4 |  00002018 | LEFT SINGLE QUOTATION MARK
     D5 |  00002019 | RIGHT SINGLE QUOTATION MARK
     D6 |  000000F7 | DIVISION SIGN
     D7 |  0000201E | DOUBLE LOW-9 QUOTATION MARK
     D8 |  0000040E | CYRILLIC CAPITAL LETTER SHORT U
     D9 |  0000045E | CYRILLIC SMALL LETTER SHORT U
     DA |  0000040F | CYRILLIC CAPITAL LETTER DZHE
     DB |  0000045F | CYRILLIC SMALL LETTER DZHE
     DC |  00002116 | NUMERO SIGN
     DD |  00000401 | CYRILLIC CAPITAL LETTER IO
     DE |  00000451 | CYRILLIC SMALL LETTER IO
     DF |  0000044F | CYRILLIC SMALL LETTER YA
     E0 |  00000430 | CYRILLIC SMALL LETTER A
     E1 |  00000431 | CYRILLIC SMALL LETTER BE
     E2 |  00000432 | CYRILLIC SMALL LETTER VE
     E3 |  00000433 | CYRILLIC SMALL LETTER GHE
     E4 |  00000434 | CYRILLIC SMALL LETTER DE
     E5 |  00000435 | CYRILLIC SMALL LETTER IE
     E6 |  00000436 | CYRILLIC SMALL LETTER ZHE
     E7 |  00000437 | CYRILLIC SMALL LETTER ZE
     E8 |  00000438 | CYRILLIC SMALL LETTER I
     E9 |  00000439 | CYRILLIC SMALL LETTER SHORT I
     EA |  0000043A | CYRILLIC SMALL LETTER KA
     EB |  0000043B | CYRILLIC SMALL LETTER EL
     EC |  0000043C | CYRILLIC SMALL LETTER EM
     ED |  0000043D | CYRILLIC SMALL LETTER EN
     EE |  0000043E | CYRILLIC SMALL LETTER O
     EF |  0000043F | CYRILLIC SMALL LETTER PE
     F0 |  00000440 | CYRILLIC SMALL LETTER ER
     F1 |  00000441 | CYRILLIC SMALL LETTER ES
     F2 |  00000442 | CYRILLIC SMALL LETTER TE
     F3 |  00000443 | CYRILLIC SMALL LETTER U
     F4 |  00000444 | CYRILLIC SMALL LETTER EF
     F5 |  00000445 | CYRILLIC SMALL LETTER HA
     F6 |  00000446 | CYRILLIC SMALL LETTER TSE
     F7 |  00000447 | CYRILLIC SMALL LETTER CHE
     F8 |  00000448 | CYRILLIC SMALL LETTER SHA
     F9 |  00000449 | CYRILLIC SMALL LETTER SHCHA
     FA |  0000044A | CYRILLIC SMALL LETTER HARD SIGN
     FB |  0000044B | CYRILLIC SMALL LETTER YERU
     FC |  0000044C | CYRILLIC SMALL LETTER SOFT SIGN
     FD |  0000044D | CYRILLIC SMALL LETTER E
     FE |  0000044E | CYRILLIC SMALL LETTER YU
     FF |  000000A4 | CURRENCY SIGN
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/MAC_IS.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for MAC-IS.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::MAC_IS;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x0004,
     0x0005,
     0x0006,
     0x0007,
     0x0008,
     0x0009,
     0x000a,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x0014,
     0x0015,
     0x0016,
     0x0017,
     0x0018,
     0x0019,
     0x001a,
     0x001b,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0020,
     0x0021,
     0x0022,
     0x0023,
     0x0024,
     0x0025,
     0x0026,
     0x0027,
     0x0028,
     0x0029,
     0x002a,
     0x002b,
     0x002c,
     0x002d,
     0x002e,
     0x002f,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x003a,
     0x003b,
     0x003c,
     0x003d,
     0x003e,
     0x003f,
     0x0040,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x005b,
     0x005c,
     0x005d,
     0x005e,
     0x005f,
     0x0060,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x007b,
     0x007c,
     0x007d,
     0x007e,
     0x007f,
     0x00c4,
     0x00c5,
     0x00c7,
     0x00c9,
     0x00d1,
     0x00d6,
     0x00dc,
     0x00e1,
     0x00e0,
     0x00e2,
     0x00e4,
     0x00e3,
     0x00e5,
     0x00e7,
     0x00e9,
     0x00e8,
     0x00ea,
     0x00eb,
     0x00ed,
     0x00ec,
     0x00ee,
     0x00ef,
     0x00f1,
     0x00f3,
     0x00f2,
     0x00f4,
     0x00f6,
     0x00f5,
     0x00fa,
     0x00f9,
     0x00fb,
     0x00fc,
     0x2020,
     0x00b0,
     0x00a2,
     0x00a3,
     0x00a7,
     0x2022,
     0x00b6,
     0x00df,
     0x00ae,
     0x00a9,
     0x2122,
     0x00b4,
     0x00a8,
     0x2260,
     0x00c6,
     0x00d8,
     0x221e,
     0x00b1,
     0x2264,
     0x2265,
     0x00a5,
     0x00b5,
     0x2202,
     0x2211,
     0x220f,
     0x03c0,
     0x222b,
     0x00aa,
     0x00ba,
     0x03a9,
     0x00e6,
     0x00f8,
     0x00bf,
     0x00a1,
     0x00ac,
     0x221a,
     0x0192,
     0x2248,
     0x0394,
     0x00ab,
     0x00bb,
     0x2026,
     0x00a0,
     0x00c0,
     0x00c3,
     0x00d5,
     0x0152,
     0x0153,
     0x2014,
     0x2013,
     0x201c,
     0x201d,
     0x2018,
     0x2019,
     0x00f7,
     0x25c6,
     0x00ff,
     0x0178,
     0x2044,
     0x00a4,
     0x0110,
     0x0111,
     0x00de,
     0x00fe,
     0x2021,
     0x00b7,
     0x201a,
     0x201e,
     0x2030,
     0x00c2,
     0x00ca,
     0x00c1,
     0x00cb,
     0x00c8,
     0x00cd,
     0x00ce,
     0x00cf,
     0x00cc,
     0x00d3,
     0x00d4,
     0xe01e,
     0x00d2,
     0x00da,
     0x00db,
     0x00d9,
     0x0131,
     0xfffd,
     0xfffd,
     0x00af,
     0x02d8,
     0x02d9,
     0x02da,
     0x00b8,
     0x02dd,
     0x02db,
     0x02c7,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\x04",
     "\x05",
     "\x06",
     "\x07",
     "\x08",
     "\x09",
     "\x0a",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\x14",
     "\x15",
     "\x16",
     "\x17",
     "\x18",
     "\x19",
     "\x1a",
     "\x1b",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\x20",
     "\x21",
     "\x22",
     "\x23",
     "\x24",
     "\x25",
     "\x26",
     "\x27",
     "\x28",
     "\x29",
     "\x2a",
     "\x2b",
     "\x2c",
     "\x2d",
     "\x2e",
     "\x2f",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\x3a",
     "\x3b",
     "\x3c",
     "\x3d",
     "\x3e",
     "\x3f",
     "\x40",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\x5b",
     "\x5c",
     "\x5d",
     "\x5e",
     "\x5f",
     "\x60",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\x7b",
     "\x7c",
     "\x7d",
     "\x7e",
     "\x7f",
     "\xc3\x84",
     "\xc3\x85",
     "\xc3\x87",
     "\xc3\x89",
     "\xc3\x91",
     "\xc3\x96",
     "\xc3\x9c",
     "\xc3\xa1",
     "\xc3\xa0",
     "\xc3\xa2",
     "\xc3\xa4",
     "\xc3\xa3",
     "\xc3\xa5",
     "\xc3\xa7",
     "\xc3\xa9",
     "\xc3\xa8",
     "\xc3\xaa",
     "\xc3\xab",
     "\xc3\xad",
     "\xc3\xac",
     "\xc3\xae",
     "\xc3\xaf",
     "\xc3\xb1",
     "\xc3\xb3",
     "\xc3\xb2",
     "\xc3\xb4",
     "\xc3\xb6",
     "\xc3\xb5",
     "\xc3\xba",
     "\xc3\xb9",
     "\xc3\xbb",
     "\xc3\xbc",
     "\xe2\x80\xa0",
     "\xc2\xb0",
     "\xc2\xa2",
     "\xc2\xa3",
     "\xc2\xa7",
     "\xe2\x80\xa2",
     "\xc2\xb6",
     "\xc3\x9f",
     "\xc2\xae",
     "\xc2\xa9",
     "\xe2\x84\xa2",
     "\xc2\xb4",
     "\xc2\xa8",
     "\xe2\x89\xa0",
     "\xc3\x86",
     "\xc3\x98",
     "\xe2\x88\x9e",
     "\xc2\xb1",
     "\xe2\x89\xa4",
     "\xe2\x89\xa5",
     "\xc2\xa5",
     "\xc2\xb5",
     "\xe2\x88\x82",
     "\xe2\x88\x91",
     "\xe2\x88\x8f",
     "\xcf\x80",
     "\xe2\x88\xab",
     "\xc2\xaa",
     "\xc2\xba",
     "\xce\xa9",
     "\xc3\xa6",
     "\xc3\xb8",
     "\xc2\xbf",
     "\xc2\xa1",
     "\xc2\xac",
     "\xe2\x88\x9a",
     "\xc6\x92",
     "\xe2\x89\x88",
     "\xce\x94",
     "\xc2\xab",
     "\xc2\xbb",
     "\xe2\x80\xa6",
     "\xc2\xa0",
     "\xc3\x80",
     "\xc3\x83",
     "\xc3\x95",
     "\xc5\x92",
     "\xc5\x93",
     "\xe2\x80\x94",
     "\xe2\x80\x93",
     "\xe2\x80\x9c",
     "\xe2\x80\x9d",
     "\xe2\x80\x98",
     "\xe2\x80\x99",
     "\xc3\xb7",
     "\xe2\x97\x86",
     "\xc3\xbf",
     "\xc5\xb8",
     "\xe2\x81\x84",
     "\xc2\xa4",
     "\xc4\x90",
     "\xc4\x91",
     "\xc3\x9e",
     "\xc3\xbe",
     "\xe2\x80\xa1",
     "\xc2\xb7",
     "\xe2\x80\x9a",
     "\xe2\x80\x9e",
     "\xe2\x80\xb0",
     "\xc3\x82",
     "\xc3\x8a",
     "\xc3\x81",
     "\xc3\x8b",
     "\xc3\x88",
     "\xc3\x8d",
     "\xc3\x8e",
     "\xc3\x8f",
     "\xc3\x8c",
     "\xc3\x93",
     "\xc3\x94",
     "\xee\x80\x9e",
     "\xc3\x92",
     "\xc3\x9a",
     "\xc3\x9b",
     "\xc3\x99",
     "\xc4\xb1",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc2\xaf",
     "\xcb\x98",
     "\xcb\x99",
     "\xcb\x9a",
     "\xc2\xb8",
     "\xcb\x9d",
     "\xcb\x9b",
     "\xcb\x87",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x04",
     0x00000005 => "\x05",
     0x00000006 => "\x06",
     0x00000007 => "\x07",
     0x00000008 => "\x08",
     0x00000009 => "\x09",
     0x0000000a => "\x0a",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x14",
     0x00000015 => "\x15",
     0x00000016 => "\x16",
     0x00000017 => "\x17",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x1a",
     0x0000001b => "\x1b",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x20",
     0x00000021 => "\x21",
     0x00000022 => "\x22",
     0x00000023 => "\x23",
     0x00000024 => "\x24",
     0x00000025 => "\x25",
     0x00000026 => "\x26",
     0x00000027 => "\x27",
     0x00000028 => "\x28",
     0x00000029 => "\x29",
     0x0000002a => "\x2a",
     0x0000002b => "\x2b",
     0x0000002c => "\x2c",
     0x0000002d => "\x2d",
     0x0000002e => "\x2e",
     0x0000002f => "\x2f",
     0x00000030 => "\x30",
     0x00000031 => "\x31",
     0x00000032 => "\x32",
     0x00000033 => "\x33",
     0x00000034 => "\x34",
     0x00000035 => "\x35",
     0x00000036 => "\x36",
     0x00000037 => "\x37",
     0x00000038 => "\x38",
     0x00000039 => "\x39",
     0x0000003a => "\x3a",
     0x0000003b => "\x3b",
     0x0000003c => "\x3c",
     0x0000003d => "\x3d",
     0x0000003e => "\x3e",
     0x0000003f => "\x3f",
     0x00000040 => "\x40",
     0x00000041 => "\x41",
     0x00000042 => "\x42",
     0x00000043 => "\x43",
     0x00000044 => "\x44",
     0x00000045 => "\x45",
     0x00000046 => "\x46",
     0x00000047 => "\x47",
     0x00000048 => "\x48",
     0x00000049 => "\x49",
     0x0000004a => "\x4a",
     0x0000004b => "\x4b",
     0x0000004c => "\x4c",
     0x0000004d => "\x4d",
     0x0000004e => "\x4e",
     0x0000004f => "\x4f",
     0x00000050 => "\x50",
     0x00000051 => "\x51",
     0x00000052 => "\x52",
     0x00000053 => "\x53",
     0x00000054 => "\x54",
     0x00000055 => "\x55",
     0x00000056 => "\x56",
     0x00000057 => "\x57",
     0x00000058 => "\x58",
     0x00000059 => "\x59",
     0x0000005a => "\x5a",
     0x0000005b => "\x5b",
     0x0000005c => "\x5c",
     0x0000005d => "\x5d",
     0x0000005e => "\x5e",
     0x0000005f => "\x5f",
     0x00000060 => "\x60",
     0x00000061 => "\x61",
     0x00000062 => "\x62",
     0x00000063 => "\x63",
     0x00000064 => "\x64",
     0x00000065 => "\x65",
     0x00000066 => "\x66",
     0x00000067 => "\x67",
     0x00000068 => "\x68",
     0x00000069 => "\x69",
     0x0000006a => "\x6a",
     0x0000006b => "\x6b",
     0x0000006c => "\x6c",
     0x0000006d => "\x6d",
     0x0000006e => "\x6e",
     0x0000006f => "\x6f",
     0x00000070 => "\x70",
     0x00000071 => "\x71",
     0x00000072 => "\x72",
     0x00000073 => "\x73",
     0x00000074 => "\x74",
     0x00000075 => "\x75",
     0x00000076 => "\x76",
     0x00000077 => "\x77",
     0x00000078 => "\x78",
     0x00000079 => "\x79",
     0x0000007a => "\x7a",
     0x0000007b => "\x7b",
     0x0000007c => "\x7c",
     0x0000007d => "\x7d",
     0x0000007e => "\x7e",
     0x0000007f => "\x7f",
     0x000000a0 => "\xca",
     0x000000a1 => "\xc1",
     0x000000a2 => "\xa2",
     0x000000a3 => "\xa3",
     0x000000a4 => "\xdb",
     0x000000a5 => "\xb4",
     0x000000a7 => "\xa4",
     0x000000a8 => "\xac",
     0x000000a9 => "\xa9",
     0x000000aa => "\xbb",
     0x000000ab => "\xc7",
     0x000000ac => "\xc2",
     0x000000ae => "\xa8",
     0x000000af => "\xf8",
     0x000000b0 => "\xa1",
     0x000000b1 => "\xb1",
     0x000000b4 => "\xab",
     0x000000b5 => "\xb5",
     0x000000b6 => "\xa6",
     0x000000b7 => "\xe1",
     0x000000b8 => "\xfc",
     0x000000ba => "\xbc",
     0x000000bb => "\xc8",
     0x000000bf => "\xc0",
     0x000000c0 => "\xcb",
     0x000000c1 => "\xe7",
     0x000000c2 => "\xe5",
     0x000000c3 => "\xcc",
     0x000000c4 => "\x80",
     0x000000c5 => "\x81",
     0x000000c6 => "\xae",
     0x000000c7 => "\x82",
     0x000000c8 => "\xe9",
     0x000000c9 => "\x83",
     0x000000ca => "\xe6",
     0x000000cb => "\xe8",
     0x000000cc => "\xed",
     0x000000cd => "\xea",
     0x000000ce => "\xeb",
     0x000000cf => "\xec",
     0x000000d1 => "\x84",
     0x000000d2 => "\xf1",
     0x000000d3 => "\xee",
     0x000000d4 => "\xef",
     0x000000d5 => "\xcd",
     0x000000d6 => "\x85",
     0x000000d8 => "\xaf",
     0x000000d9 => "\xf4",
     0x000000da => "\xf2",
     0x000000db => "\xf3",
     0x000000dc => "\x86",
     0x000000de => "\xde",
     0x000000df => "\xa7",
     0x000000e0 => "\x88",
     0x000000e1 => "\x87",
     0x000000e2 => "\x89",
     0x000000e3 => "\x8b",
     0x000000e4 => "\x8a",
     0x000000e5 => "\x8c",
     0x000000e6 => "\xbe",
     0x000000e7 => "\x8d",
     0x000000e8 => "\x8f",
     0x000000e9 => "\x8e",
     0x000000ea => "\x90",
     0x000000eb => "\x91",
     0x000000ec => "\x93",
     0x000000ed => "\x92",
     0x000000ee => "\x94",
     0x000000ef => "\x95",
     0x000000f1 => "\x96",
     0x000000f2 => "\x98",
     0x000000f3 => "\x97",
     0x000000f4 => "\x99",
     0x000000f5 => "\x9b",
     0x000000f6 => "\x9a",
     0x000000f7 => "\xd6",
     0x000000f8 => "\xbf",
     0x000000f9 => "\x9d",
     0x000000fa => "\x9c",
     0x000000fb => "\x9e",
     0x000000fc => "\x9f",
     0x000000fe => "\xdf",
     0x000000ff => "\xd8",
     0x00000110 => "\xdc",
     0x00000111 => "\xdd",
     0x00000131 => "\xf5",
     0x00000152 => "\xce",
     0x00000153 => "\xcf",
     0x00000178 => "\xd9",
     0x00000192 => "\xc4",
     0x000002c7 => "\xff",
     0x000002d8 => "\xf9",
     0x000002d9 => "\xfa",
     0x000002da => "\xfb",
     0x000002db => "\xfe",
     0x000002dd => "\xfd",
     0x00000394 => "\xc6",
     0x000003a9 => "\xbd",
     0x000003c0 => "\xb9",
     0x00002013 => "\xd1",
     0x00002014 => "\xd0",
     0x00002018 => "\xd4",
     0x00002019 => "\xd5",
     0x0000201a => "\xe2",
     0x0000201c => "\xd2",
     0x0000201d => "\xd3",
     0x0000201e => "\xe3",
     0x00002020 => "\xa0",
     0x00002021 => "\xe0",
     0x00002022 => "\xa5",
     0x00002026 => "\xc9",
     0x00002030 => "\xe4",
     0x00002044 => "\xda",
     0x00002122 => "\xaa",
     0x00002202 => "\xb6",
     0x0000220f => "\xb8",
     0x00002211 => "\xb7",
     0x0000221a => "\xc3",
     0x0000221e => "\xb0",
     0x0000222b => "\xba",
     0x00002248 => "\xc5",
     0x00002260 => "\xad",
     0x00002264 => "\xb2",
     0x00002265 => "\xb3",
     0x000025c6 => "\xd7",
     0x0000e01e => "\xf0",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::MAC_IS - Conversion routines for MAC-IS
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for MAC-IS.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  00000004 | END OF TRANSMISSION (EOT)
     05 |  00000005 | ENQUIRY (ENQ)
     06 |  00000006 | ACKNOWLEDGE (ACK)
     07 |  00000007 | BELL (BEL)
     08 |  00000008 | BACKSPACE (BS)
     09 |  00000009 | CHARACTER TABULATION (HT)
     0A |  0000000A | LINE FEED (LF)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  00000014 | DEVICE CONTROL FOUR (DC4)
     15 |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     16 |  00000016 | SYNCHRONOUS IDLE (SYN)
     17 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  0000001A | SUBSTITUTE (SUB)
     1B |  0000001B | ESCAPE (ESC)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000020 | SPACE
     21 |  00000021 | EXCLAMATION MARK
     22 |  00000022 | QUOTATION MARK
     23 |  00000023 | NUMBER SIGN
     24 |  00000024 | DOLLAR SIGN
     25 |  00000025 | PERCENT SIGN
     26 |  00000026 | AMPERSAND
     27 |  00000027 | APOSTROPHE
     28 |  00000028 | LEFT PARENTHESIS
     29 |  00000029 | RIGHT PARENTHESIS
     2A |  0000002A | ASTERISK
     2B |  0000002B | PLUS SIGN
     2C |  0000002C | COMMA
     2D |  0000002D | HYPHEN-MINUS
     2E |  0000002E | FULL STOP
     2F |  0000002F | SOLIDUS
     30 |  00000030 | DIGIT ZERO
     31 |  00000031 | DIGIT ONE
     32 |  00000032 | DIGIT TWO
     33 |  00000033 | DIGIT THREE
     34 |  00000034 | DIGIT FOUR
     35 |  00000035 | DIGIT FIVE
     36 |  00000036 | DIGIT SIX
     37 |  00000037 | DIGIT SEVEN
     38 |  00000038 | DIGIT EIGHT
     39 |  00000039 | DIGIT NINE
     3A |  0000003A | COLON
     3B |  0000003B | SEMICOLON
     3C |  0000003C | LESS-THAN SIGN
     3D |  0000003D | EQUALS SIGN
     3E |  0000003E | GREATER-THAN SIGN
     3F |  0000003F | QUESTION MARK
     40 |  00000040 | COMMERCIAL AT
     41 |  00000041 | LATIN CAPITAL LETTER A
     42 |  00000042 | LATIN CAPITAL LETTER B
     43 |  00000043 | LATIN CAPITAL LETTER C
     44 |  00000044 | LATIN CAPITAL LETTER D
     45 |  00000045 | LATIN CAPITAL LETTER E
     46 |  00000046 | LATIN CAPITAL LETTER F
     47 |  00000047 | LATIN CAPITAL LETTER G
     48 |  00000048 | LATIN CAPITAL LETTER H
     49 |  00000049 | LATIN CAPITAL LETTER I
     4A |  0000004A | LATIN CAPITAL LETTER J
     4B |  0000004B | LATIN CAPITAL LETTER K
     4C |  0000004C | LATIN CAPITAL LETTER L
     4D |  0000004D | LATIN CAPITAL LETTER M
     4E |  0000004E | LATIN CAPITAL LETTER N
     4F |  0000004F | LATIN CAPITAL LETTER O
     50 |  00000050 | LATIN CAPITAL LETTER P
     51 |  00000051 | LATIN CAPITAL LETTER Q
     52 |  00000052 | LATIN CAPITAL LETTER R
     53 |  00000053 | LATIN CAPITAL LETTER S
     54 |  00000054 | LATIN CAPITAL LETTER T
     55 |  00000055 | LATIN CAPITAL LETTER U
     56 |  00000056 | LATIN CAPITAL LETTER V
     57 |  00000057 | LATIN CAPITAL LETTER W
     58 |  00000058 | LATIN CAPITAL LETTER X
     59 |  00000059 | LATIN CAPITAL LETTER Y
     5A |  0000005A | LATIN CAPITAL LETTER Z
     5B |  0000005B | LEFT SQUARE BRACKET
     5C |  0000005C | REVERSE SOLIDUS
     5D |  0000005D | RIGHT SQUARE BRACKET
     5E |  0000005E | CIRCUMFLEX ACCENT
     5F |  0000005F | LOW LINE
     60 |  00000060 | GRAVE ACCENT
     61 |  00000061 | LATIN SMALL LETTER A
     62 |  00000062 | LATIN SMALL LETTER B
     63 |  00000063 | LATIN SMALL LETTER C
     64 |  00000064 | LATIN SMALL LETTER D
     65 |  00000065 | LATIN SMALL LETTER E
     66 |  00000066 | LATIN SMALL LETTER F
     67 |  00000067 | LATIN SMALL LETTER G
     68 |  00000068 | LATIN SMALL LETTER H
     69 |  00000069 | LATIN SMALL LETTER I
     6A |  0000006A | LATIN SMALL LETTER J
     6B |  0000006B | LATIN SMALL LETTER K
     6C |  0000006C | LATIN SMALL LETTER L
     6D |  0000006D | LATIN SMALL LETTER M
     6E |  0000006E | LATIN SMALL LETTER N
     6F |  0000006F | LATIN SMALL LETTER O
     70 |  00000070 | LATIN SMALL LETTER P
     71 |  00000071 | LATIN SMALL LETTER Q
     72 |  00000072 | LATIN SMALL LETTER R
     73 |  00000073 | LATIN SMALL LETTER S
     74 |  00000074 | LATIN SMALL LETTER T
     75 |  00000075 | LATIN SMALL LETTER U
     76 |  00000076 | LATIN SMALL LETTER V
     77 |  00000077 | LATIN SMALL LETTER W
     78 |  00000078 | LATIN SMALL LETTER X
     79 |  00000079 | LATIN SMALL LETTER Y
     7A |  0000007A | LATIN SMALL LETTER Z
     7B |  0000007B | LEFT CURLY BRACKET
     7C |  0000007C | VERTICAL LINE
     7D |  0000007D | RIGHT CURLY BRACKET
     7E |  0000007E | TILDE
     7F |  0000007F | DELETE (DEL)
     80 |  000000C4 | LATIN CAPITAL LETTER A WITH DIAERESIS
     81 |  000000C5 | LATIN CAPITAL LETTER A WITH RING ABOVE
     82 |  000000C7 | LATIN CAPITAL LETTER C WITH CEDILLA
     83 |  000000C9 | LATIN CAPITAL LETTER E WITH ACUTE
     84 |  000000D1 | LATIN CAPITAL LETTER N WITH TILDE
     85 |  000000D6 | LATIN CAPITAL LETTER O WITH DIAERESIS
     86 |  000000DC | LATIN CAPITAL LETTER U WITH DIAERESIS
     87 |  000000E1 | LATIN SMALL LETTER A WITH ACUTE
     88 |  000000E0 | LATIN SMALL LETTER A WITH GRAVE
     89 |  000000E2 | LATIN SMALL LETTER A WITH CIRCUMFLEX
     8A |  000000E4 | LATIN SMALL LETTER A WITH DIAERESIS
     8B |  000000E3 | LATIN SMALL LETTER A WITH TILDE
     8C |  000000E5 | LATIN SMALL LETTER A WITH RING ABOVE
     8D |  000000E7 | LATIN SMALL LETTER C WITH CEDILLA
     8E |  000000E9 | LATIN SMALL LETTER E WITH ACUTE
     8F |  000000E8 | LATIN SMALL LETTER E WITH GRAVE
     90 |  000000EA | LATIN SMALL LETTER E WITH CIRCUMFLEX
     91 |  000000EB | LATIN SMALL LETTER E WITH DIAERESIS
     92 |  000000ED | LATIN SMALL LETTER I WITH ACUTE
     93 |  000000EC | LATIN SMALL LETTER I WITH GRAVE
     94 |  000000EE | LATIN SMALL LETTER I WITH CIRCUMFLEX
     95 |  000000EF | LATIN SMALL LETTER I WITH DIAERESIS
     96 |  000000F1 | LATIN SMALL LETTER N WITH TILDE
     97 |  000000F3 | LATIN SMALL LETTER O WITH ACUTE
     98 |  000000F2 | LATIN SMALL LETTER O WITH GRAVE
     99 |  000000F4 | LATIN SMALL LETTER O WITH CIRCUMFLEX
     9A |  000000F6 | LATIN SMALL LETTER O WITH DIAERESIS
     9B |  000000F5 | LATIN SMALL LETTER O WITH TILDE
     9C |  000000FA | LATIN SMALL LETTER U WITH ACUTE
     9D |  000000F9 | LATIN SMALL LETTER U WITH GRAVE
     9E |  000000FB | LATIN SMALL LETTER U WITH CIRCUMFLEX
     9F |  000000FC | LATIN SMALL LETTER U WITH DIAERESIS
     A0 |  00002020 | DAGGER
     A1 |  000000B0 | DEGREE SIGN
     A2 |  000000A2 | CENT SIGN
     A3 |  000000A3 | POUND SIGN
     A4 |  000000A7 | SECTION SIGN
     A5 |  00002022 | BULLET
     A6 |  000000B6 | PILCROW SIGN
     A7 |  000000DF | LATIN SMALL LETTER SHARP S (German)
     A8 |  000000AE | REGISTERED SIGN
     A9 |  000000A9 | COPYRIGHT SIGN
     AA |  00002122 | TRADE MARK SIGN
     AB |  000000B4 | ACUTE ACCENT
     AC |  000000A8 | DIAERESIS
     AD |  00002260 | NOT EQUAL TO
     AE |  000000C6 | LATIN CAPITAL LETTER AE
     AF |  000000D8 | LATIN CAPITAL LETTER O WITH STROKE
     B0 |  0000221E | INFINITY
     B1 |  000000B1 | PLUS-MINUS SIGN
     B2 |  00002264 | LESS-THAN OR EQUAL TO
     B3 |  00002265 | GREATER-THAN OR EQUAL TO
     B4 |  000000A5 | YEN SIGN
     B5 |  000000B5 | MICRO SIGN
     B6 |  00002202 | PARTIAL DIFFERENTIAL
     B7 |  00002211 | N-ARY SUMMATION
     B8 |  0000220F | N-ARY PRODUCT
     B9 |  000003C0 | GREEK SMALL LETTER PI
     BA |  0000222B | INTEGRAL
     BB |  000000AA | FEMININE ORDINAL INDICATOR
     BC |  000000BA | MASCULINE ORDINAL INDICATOR
     BD |  000003A9 | GREEK CAPITAL LETTER OMEGA
     BE |  000000E6 | LATIN SMALL LETTER AE
     BF |  000000F8 | LATIN SMALL LETTER O WITH STROKE
     C0 |  000000BF | INVERTED QUESTION MARK
     C1 |  000000A1 | INVERTED EXCLAMATION MARK
     C2 |  000000AC | NOT SIGN
     C3 |  0000221A | SQUARE ROOT
     C4 |  00000192 | LATIN SMALL LETTER F WITH HOOK
     C5 |  00002248 | ALMOST EQUAL TO
     C6 |  00000394 | GREEK CAPITAL LETTER DELTA
     C7 |  000000AB | LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
     C8 |  000000BB | RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
     C9 |  00002026 | HORIZONTAL ELLIPSIS
     CA |  000000A0 | NO-BREAK SPACE
     CB |  000000C0 | LATIN CAPITAL LETTER A WITH GRAVE
     CC |  000000C3 | LATIN CAPITAL LETTER A WITH TILDE
     CD |  000000D5 | LATIN CAPITAL LETTER O WITH TILDE
     CE |  00000152 | LATIN CAPITAL LIGATURE OE
     CF |  00000153 | LATIN SMALL LIGATURE OE
     D0 |  00002014 | EM DASH
     D1 |  00002013 | EN DASH
     D2 |  0000201C | LEFT DOUBLE QUOTATION MARK
     D3 |  0000201D | RIGHT DOUBLE QUOTATION MARK
     D4 |  00002018 | LEFT SINGLE QUOTATION MARK
     D5 |  00002019 | RIGHT SINGLE QUOTATION MARK
     D6 |  000000F7 | DIVISION SIGN
     D7 |  000025C6 | BLACK DIAMOND
     D8 |  000000FF | LATIN SMALL LETTER Y WITH DIAERESIS
     D9 |  00000178 | LATIN CAPITAL LETTER Y WITH DIAERESIS
     DA |  00002044 | FRACTION SLASH
     DB |  000000A4 | CURRENCY SIGN
     DC |  00000110 | LATIN CAPITAL LETTER D WITH STROKE
     DD |  00000111 | LATIN SMALL LETTER D WITH STROKE
     DE |  000000DE | LATIN CAPITAL LETTER THORN (Icelandic)
     DF |  000000FE | LATIN SMALL LETTER THORN (Icelandic)
     E0 |  00002021 | DOUBLE DAGGER
     E1 |  000000B7 | MIDDLE DOT
     E2 |  0000201A | SINGLE LOW-9 QUOTATION MARK
     E3 |  0000201E | DOUBLE LOW-9 QUOTATION MARK
     E4 |  00002030 | PER MILLE SIGN
     E5 |  000000C2 | LATIN CAPITAL LETTER A WITH CIRCUMFLEX
     E6 |  000000CA | LATIN CAPITAL LETTER E WITH CIRCUMFLEX
     E7 |  000000C1 | LATIN CAPITAL LETTER A WITH ACUTE
     E8 |  000000CB | LATIN CAPITAL LETTER E WITH DIAERESIS
     E9 |  000000C8 | LATIN CAPITAL LETTER E WITH GRAVE
     EA |  000000CD | LATIN CAPITAL LETTER I WITH ACUTE
     EB |  000000CE | LATIN CAPITAL LETTER I WITH CIRCUMFLEX
     EC |  000000CF | LATIN CAPITAL LETTER I WITH DIAERESIS
     ED |  000000CC | LATIN CAPITAL LETTER I WITH GRAVE
     EE |  000000D3 | LATIN CAPITAL LETTER O WITH ACUTE
     EF |  000000D4 | LATIN CAPITAL LETTER O WITH CIRCUMFLEX
     F0 |  0000E01E | APPLE LOGO (Macintosh_F0)
     F1 |  000000D2 | LATIN CAPITAL LETTER O WITH GRAVE
     F2 |  000000DA | LATIN CAPITAL LETTER U WITH ACUTE
     F3 |  000000DB | LATIN CAPITAL LETTER U WITH CIRCUMFLEX
     F4 |  000000D9 | LATIN CAPITAL LETTER U WITH GRAVE
     F5 |  00000131 | LATIN SMALL LETTER DOTLESS I
     F8 |  000000AF | MACRON
     F9 |  000002D8 | BREVE
     FA |  000002D9 | DOT ABOVE (Mandarin Chinese light tone)
     FB |  000002DA | RING ABOVE
     FC |  000000B8 | CEDILLA
     FD |  000002DD | DOUBLE ACUTE ACCENT
     FE |  000002DB | OGONEK
     FF |  000002C7 | CARON (Mandarin Chinese third tone)
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/MAC_SAMI.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for MAC-SAMI.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::MAC_SAMI;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x0004,
     0x0005,
     0x0006,
     0x0007,
     0x0008,
     0x0009,
     0x000a,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x0014,
     0x0015,
     0x0016,
     0x0017,
     0x0018,
     0x0019,
     0x001a,
     0x001b,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0020,
     0x0021,
     0x0022,
     0x0023,
     0x0024,
     0x0025,
     0x0026,
     0x0027,
     0x0028,
     0x0029,
     0x002a,
     0x002b,
     0x002c,
     0x002d,
     0x002e,
     0x002f,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x003a,
     0x003b,
     0x003c,
     0x003d,
     0x003e,
     0x003f,
     0x0040,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x005b,
     0x005c,
     0x005d,
     0x005e,
     0x005f,
     0x0060,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x007b,
     0x007c,
     0x007d,
     0x007e,
     0x007f,
     0x00c4,
     0x00c5,
     0x00c7,
     0x00c9,
     0x00d1,
     0x00d6,
     0x00dc,
     0x00e1,
     0x00e0,
     0x00e2,
     0x00e4,
     0x00e3,
     0x00e5,
     0x00e7,
     0x00e9,
     0x00e8,
     0x00ea,
     0x00eb,
     0x00ed,
     0x00ec,
     0x00ee,
     0x00ef,
     0x00f1,
     0x00f3,
     0x00f2,
     0x00f4,
     0x00f6,
     0x00f5,
     0x00fa,
     0x00f9,
     0x00fb,
     0x00fc,
     0x00dd,
     0x00b0,
     0x010c,
     0x00a3,
     0x00a7,
     0x2022,
     0x00b6,
     0x00df,
     0x00ae,
     0x00a9,
     0x2122,
     0x00b4,
     0x00a8,
     0x2260,
     0x00c6,
     0x00d8,
     0x0110,
     0x014a,
     0x821e,
     0x821f,
     0x0160,
     0x0166,
     0x2202,
     0x017d,
     0x010d,
     0x0111,
     0x014b,
     0x0161,
     0x0167,
     0x017e,
     0x00e6,
     0x00f8,
     0x00bf,
     0x00a1,
     0x00ac,
     0x221a,
     0x0192,
     0x2248,
     0x2206,
     0x00ab,
     0x00bb,
     0x2026,
     0x00a0,
     0x00c0,
     0x00c3,
     0x00d5,
     0x0152,
     0x0153,
     0x2013,
     0x2014,
     0x201c,
     0x201d,
     0x2018,
     0x2019,
     0x00f7,
     0x25ca,
     0x00ff,
     0x0178,
     0x2044,
     0x00a4,
     0x00d0,
     0x00f0,
     0x00de,
     0x00fe,
     0x00fd,
     0x00b7,
     0x201a,
     0x201e,
     0x2030,
     0x00c2,
     0x00ca,
     0x00c1,
     0x00cb,
     0x00c8,
     0x00cd,
     0x00ce,
     0x00cf,
     0x00cc,
     0x00d3,
     0x00d4,
     0xf8ff,
     0x00d2,
     0x00da,
     0x00db,
     0x00d9,
     0x0131,
     0x01b7,
     0x0292,
     0x01ee,
     0x01ef,
     0x01e4,
     0x01e5,
     0x01e6,
     0x01e7,
     0x01e8,
     0x01e9,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\x04",
     "\x05",
     "\x06",
     "\x07",
     "\x08",
     "\x09",
     "\x0a",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\x14",
     "\x15",
     "\x16",
     "\x17",
     "\x18",
     "\x19",
     "\x1a",
     "\x1b",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\x20",
     "\x21",
     "\x22",
     "\x23",
     "\x24",
     "\x25",
     "\x26",
     "\x27",
     "\x28",
     "\x29",
     "\x2a",
     "\x2b",
     "\x2c",
     "\x2d",
     "\x2e",
     "\x2f",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\x3a",
     "\x3b",
     "\x3c",
     "\x3d",
     "\x3e",
     "\x3f",
     "\x40",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\x5b",
     "\x5c",
     "\x5d",
     "\x5e",
     "\x5f",
     "\x60",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\x7b",
     "\x7c",
     "\x7d",
     "\x7e",
     "\x7f",
     "\xc3\x84",
     "\xc3\x85",
     "\xc3\x87",
     "\xc3\x89",
     "\xc3\x91",
     "\xc3\x96",
     "\xc3\x9c",
     "\xc3\xa1",
     "\xc3\xa0",
     "\xc3\xa2",
     "\xc3\xa4",
     "\xc3\xa3",
     "\xc3\xa5",
     "\xc3\xa7",
     "\xc3\xa9",
     "\xc3\xa8",
     "\xc3\xaa",
     "\xc3\xab",
     "\xc3\xad",
     "\xc3\xac",
     "\xc3\xae",
     "\xc3\xaf",
     "\xc3\xb1",
     "\xc3\xb3",
     "\xc3\xb2",
     "\xc3\xb4",
     "\xc3\xb6",
     "\xc3\xb5",
     "\xc3\xba",
     "\xc3\xb9",
     "\xc3\xbb",
     "\xc3\xbc",
     "\xc3\x9d",
     "\xc2\xb0",
     "\xc4\x8c",
     "\xc2\xa3",
     "\xc2\xa7",
     "\xe2\x80\xa2",
     "\xc2\xb6",
     "\xc3\x9f",
     "\xc2\xae",
     "\xc2\xa9",
     "\xe2\x84\xa2",
     "\xc2\xb4",
     "\xc2\xa8",
     "\xe2\x89\xa0",
     "\xc3\x86",
     "\xc3\x98",
     "\xc4\x90",
     "\xc5\x8a",
     "\xe8\x88\x9e",
     "\xe8\x88\x9f",
     "\xc5\xa0",
     "\xc5\xa6",
     "\xe2\x88\x82",
     "\xc5\xbd",
     "\xc4\x8d",
     "\xc4\x91",
     "\xc5\x8b",
     "\xc5\xa1",
     "\xc5\xa7",
     "\xc5\xbe",
     "\xc3\xa6",
     "\xc3\xb8",
     "\xc2\xbf",
     "\xc2\xa1",
     "\xc2\xac",
     "\xe2\x88\x9a",
     "\xc6\x92",
     "\xe2\x89\x88",
     "\xe2\x88\x86",
     "\xc2\xab",
     "\xc2\xbb",
     "\xe2\x80\xa6",
     "\xc2\xa0",
     "\xc3\x80",
     "\xc3\x83",
     "\xc3\x95",
     "\xc5\x92",
     "\xc5\x93",
     "\xe2\x80\x93",
     "\xe2\x80\x94",
     "\xe2\x80\x9c",
     "\xe2\x80\x9d",
     "\xe2\x80\x98",
     "\xe2\x80\x99",
     "\xc3\xb7",
     "\xe2\x97\x8a",
     "\xc3\xbf",
     "\xc5\xb8",
     "\xe2\x81\x84",
     "\xc2\xa4",
     "\xc3\x90",
     "\xc3\xb0",
     "\xc3\x9e",
     "\xc3\xbe",
     "\xc3\xbd",
     "\xc2\xb7",
     "\xe2\x80\x9a",
     "\xe2\x80\x9e",
     "\xe2\x80\xb0",
     "\xc3\x82",
     "\xc3\x8a",
     "\xc3\x81",
     "\xc3\x8b",
     "\xc3\x88",
     "\xc3\x8d",
     "\xc3\x8e",
     "\xc3\x8f",
     "\xc3\x8c",
     "\xc3\x93",
     "\xc3\x94",
     "\xef\xa3\xbf",
     "\xc3\x92",
     "\xc3\x9a",
     "\xc3\x9b",
     "\xc3\x99",
     "\xc4\xb1",
     "\xc6\xb7",
     "\xca\x92",
     "\xc7\xae",
     "\xc7\xaf",
     "\xc7\xa4",
     "\xc7\xa5",
     "\xc7\xa6",
     "\xc7\xa7",
     "\xc7\xa8",
     "\xc7\xa9",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x04",
     0x00000005 => "\x05",
     0x00000006 => "\x06",
     0x00000007 => "\x07",
     0x00000008 => "\x08",
     0x00000009 => "\x09",
     0x0000000a => "\x0a",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x14",
     0x00000015 => "\x15",
     0x00000016 => "\x16",
     0x00000017 => "\x17",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x1a",
     0x0000001b => "\x1b",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x20",
     0x00000021 => "\x21",
     0x00000022 => "\x22",
     0x00000023 => "\x23",
     0x00000024 => "\x24",
     0x00000025 => "\x25",
     0x00000026 => "\x26",
     0x00000027 => "\x27",
     0x00000028 => "\x28",
     0x00000029 => "\x29",
     0x0000002a => "\x2a",
     0x0000002b => "\x2b",
     0x0000002c => "\x2c",
     0x0000002d => "\x2d",
     0x0000002e => "\x2e",
     0x0000002f => "\x2f",
     0x00000030 => "\x30",
     0x00000031 => "\x31",
     0x00000032 => "\x32",
     0x00000033 => "\x33",
     0x00000034 => "\x34",
     0x00000035 => "\x35",
     0x00000036 => "\x36",
     0x00000037 => "\x37",
     0x00000038 => "\x38",
     0x00000039 => "\x39",
     0x0000003a => "\x3a",
     0x0000003b => "\x3b",
     0x0000003c => "\x3c",
     0x0000003d => "\x3d",
     0x0000003e => "\x3e",
     0x0000003f => "\x3f",
     0x00000040 => "\x40",
     0x00000041 => "\x41",
     0x00000042 => "\x42",
     0x00000043 => "\x43",
     0x00000044 => "\x44",
     0x00000045 => "\x45",
     0x00000046 => "\x46",
     0x00000047 => "\x47",
     0x00000048 => "\x48",
     0x00000049 => "\x49",
     0x0000004a => "\x4a",
     0x0000004b => "\x4b",
     0x0000004c => "\x4c",
     0x0000004d => "\x4d",
     0x0000004e => "\x4e",
     0x0000004f => "\x4f",
     0x00000050 => "\x50",
     0x00000051 => "\x51",
     0x00000052 => "\x52",
     0x00000053 => "\x53",
     0x00000054 => "\x54",
     0x00000055 => "\x55",
     0x00000056 => "\x56",
     0x00000057 => "\x57",
     0x00000058 => "\x58",
     0x00000059 => "\x59",
     0x0000005a => "\x5a",
     0x0000005b => "\x5b",
     0x0000005c => "\x5c",
     0x0000005d => "\x5d",
     0x0000005e => "\x5e",
     0x0000005f => "\x5f",
     0x00000060 => "\x60",
     0x00000061 => "\x61",
     0x00000062 => "\x62",
     0x00000063 => "\x63",
     0x00000064 => "\x64",
     0x00000065 => "\x65",
     0x00000066 => "\x66",
     0x00000067 => "\x67",
     0x00000068 => "\x68",
     0x00000069 => "\x69",
     0x0000006a => "\x6a",
     0x0000006b => "\x6b",
     0x0000006c => "\x6c",
     0x0000006d => "\x6d",
     0x0000006e => "\x6e",
     0x0000006f => "\x6f",
     0x00000070 => "\x70",
     0x00000071 => "\x71",
     0x00000072 => "\x72",
     0x00000073 => "\x73",
     0x00000074 => "\x74",
     0x00000075 => "\x75",
     0x00000076 => "\x76",
     0x00000077 => "\x77",
     0x00000078 => "\x78",
     0x00000079 => "\x79",
     0x0000007a => "\x7a",
     0x0000007b => "\x7b",
     0x0000007c => "\x7c",
     0x0000007d => "\x7d",
     0x0000007e => "\x7e",
     0x0000007f => "\x7f",
     0x000000a0 => "\xca",
     0x000000a1 => "\xc1",
     0x000000a3 => "\xa3",
     0x000000a4 => "\xdb",
     0x000000a7 => "\xa4",
     0x000000a8 => "\xac",
     0x000000a9 => "\xa9",
     0x000000ab => "\xc7",
     0x000000ac => "\xc2",
     0x000000ae => "\xa8",
     0x000000b0 => "\xa1",
     0x000000b4 => "\xab",
     0x000000b6 => "\xa6",
     0x000000b7 => "\xe1",
     0x000000bb => "\xc8",
     0x000000bf => "\xc0",
     0x000000c0 => "\xcb",
     0x000000c1 => "\xe7",
     0x000000c2 => "\xe5",
     0x000000c3 => "\xcc",
     0x000000c4 => "\x80",
     0x000000c5 => "\x81",
     0x000000c6 => "\xae",
     0x000000c7 => "\x82",
     0x000000c8 => "\xe9",
     0x000000c9 => "\x83",
     0x000000ca => "\xe6",
     0x000000cb => "\xe8",
     0x000000cc => "\xed",
     0x000000cd => "\xea",
     0x000000ce => "\xeb",
     0x000000cf => "\xec",
     0x000000d0 => "\xdc",
     0x000000d1 => "\x84",
     0x000000d2 => "\xf1",
     0x000000d3 => "\xee",
     0x000000d4 => "\xef",
     0x000000d5 => "\xcd",
     0x000000d6 => "\x85",
     0x000000d8 => "\xaf",
     0x000000d9 => "\xf4",
     0x000000da => "\xf2",
     0x000000db => "\xf3",
     0x000000dc => "\x86",
     0x000000dd => "\xa0",
     0x000000de => "\xde",
     0x000000df => "\xa7",
     0x000000e0 => "\x88",
     0x000000e1 => "\x87",
     0x000000e2 => "\x89",
     0x000000e3 => "\x8b",
     0x000000e4 => "\x8a",
     0x000000e5 => "\x8c",
     0x000000e6 => "\xbe",
     0x000000e7 => "\x8d",
     0x000000e8 => "\x8f",
     0x000000e9 => "\x8e",
     0x000000ea => "\x90",
     0x000000eb => "\x91",
     0x000000ec => "\x93",
     0x000000ed => "\x92",
     0x000000ee => "\x94",
     0x000000ef => "\x95",
     0x000000f0 => "\xdd",
     0x000000f1 => "\x96",
     0x000000f2 => "\x98",
     0x000000f3 => "\x97",
     0x000000f4 => "\x99",
     0x000000f5 => "\x9b",
     0x000000f6 => "\x9a",
     0x000000f7 => "\xd6",
     0x000000f8 => "\xbf",
     0x000000f9 => "\x9d",
     0x000000fa => "\x9c",
     0x000000fb => "\x9e",
     0x000000fc => "\x9f",
     0x000000fd => "\xe0",
     0x000000fe => "\xdf",
     0x000000ff => "\xd8",
     0x0000010c => "\xa2",
     0x0000010d => "\xb8",
     0x00000110 => "\xb0",
     0x00000111 => "\xb9",
     0x00000131 => "\xf5",
     0x0000014a => "\xb1",
     0x0000014b => "\xba",
     0x00000152 => "\xce",
     0x00000153 => "\xcf",
     0x00000160 => "\xb4",
     0x00000161 => "\xbb",
     0x00000166 => "\xb5",
     0x00000167 => "\xbc",
     0x00000178 => "\xd9",
     0x0000017d => "\xb7",
     0x0000017e => "\xbd",
     0x00000192 => "\xc4",
     0x000001b7 => "\xf6",
     0x000001e4 => "\xfa",
     0x000001e5 => "\xfb",
     0x000001e6 => "\xfc",
     0x000001e7 => "\xfd",
     0x000001e8 => "\xfe",
     0x000001e9 => "\xff",
     0x000001ee => "\xf8",
     0x000001ef => "\xf9",
     0x00000292 => "\xf7",
     0x00002013 => "\xd0",
     0x00002014 => "\xd1",
     0x00002018 => "\xd4",
     0x00002019 => "\xd5",
     0x0000201a => "\xe2",
     0x0000201c => "\xd2",
     0x0000201d => "\xd3",
     0x0000201e => "\xe3",
     0x00002022 => "\xa5",
     0x00002026 => "\xc9",
     0x00002030 => "\xe4",
     0x00002044 => "\xda",
     0x00002122 => "\xaa",
     0x00002202 => "\xb6",
     0x00002206 => "\xc6",
     0x0000221a => "\xc3",
     0x00002248 => "\xc5",
     0x00002260 => "\xad",
     0x000025ca => "\xd7",
     0x0000821e => "\xb2",
     0x0000821f => "\xb3",
     0x0000f8ff => "\xf0",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::MAC_SAMI - Conversion routines for MAC-SAMI
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for MAC-SAMI.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  source:  http://www.indigo.ie/egt/standards/se/mac-sami.html
  author:  Regnor Jernsletten E<lt>Regnor.Jernsletten@sami.uit.noE<gt>
  date:    2001-07-31
  comment: Macintosh sami standard.
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL
     01 |  00000001 | START OF HEADING
     02 |  00000002 | START OF TEXT
     03 |  00000003 | END OF TEXT
     04 |  00000004 | END OF TRANSMISSION
     05 |  00000005 | ENQUIRY
     06 |  00000006 | ACKNOWLEDGE
     07 |  00000007 | BELL
     08 |  00000008 | BACKSPACE
     09 |  00000009 | HORIZONTAL TABULATION
     0A |  0000000A | LINE FEED
     0B |  0000000B | VERTICAL TABULATION
     0C |  0000000C | FORM FEED
     0D |  0000000D | CARRIAGE RETURN
     0E |  0000000E | SHIFT OUT
     0F |  0000000F | SHIFT IN
     10 |  00000010 | DATA LINK ESCAPE
     11 |  00000011 | DEVICE CONTROL ONE
     12 |  00000012 | DEVICE CONTROL TWO
     13 |  00000013 | DEVICE CONTROL THREE
     14 |  00000014 | DEVICE CONTROL FOUR
     15 |  00000015 | NEGATIVE ACKNOWLEDGE
     16 |  00000016 | SYNCHRONOUS IDLE
     17 |  00000017 | END OF TRANSMISSION BLOCK
     18 |  00000018 | CANCEL
     19 |  00000019 | END OF MEDIUM
     1A |  0000001A | SUBSTITUTE
     1B |  0000001B | ESCAPE
     1C |  0000001C | FILE SEPARATOR
     1D |  0000001D | GROUP SEPARATOR
     1E |  0000001E | RECORD SEPARATOR
     1F |  0000001F | UNIT SEPARATOR
     20 |  00000020 | SPACE
     21 |  00000021 | EXCLAMATION MARK
     22 |  00000022 | QUOTATION MARK
     23 |  00000023 | NUMBER SIGN
     24 |  00000024 | DOLLAR SIGN
     25 |  00000025 | PERCENT SIGN
     26 |  00000026 | AMPERSAND
     27 |  00000027 | APOSTROPHE
     28 |  00000028 | LEFT PARENTHESIS
     29 |  00000029 | RIGHT PARENTHESIS
     2A |  0000002A | ASTERISK
     2B |  0000002B | PLUS SIGN
     2C |  0000002C | COMMA
     2D |  0000002D | HYPHEN-MINUS
     2E |  0000002E | FULL STOP
     2F |  0000002F | SOLIDUS
     30 |  00000030 | DIGIT ZERO
     31 |  00000031 | DIGIT ONE
     32 |  00000032 | DIGIT TWO
     33 |  00000033 | DIGIT THREE
     34 |  00000034 | DIGIT FOUR
     35 |  00000035 | DIGIT FIVE
     36 |  00000036 | DIGIT SIX
     37 |  00000037 | DIGIT SEVEN
     38 |  00000038 | DIGIT EIGHT
     39 |  00000039 | DIGIT NINE
     3A |  0000003A | COLON
     3B |  0000003B | SEMICOLON
     3C |  0000003C | LESS-THAN SIGN
     3D |  0000003D | EQUALS SIGN
     3E |  0000003E | GREATER-THAN SIGN
     3F |  0000003F | QUESTION MARK
     40 |  00000040 | COMMERCIAL AT
     41 |  00000041 | LATIN CAPITAL LETTER A
     42 |  00000042 | LATIN CAPITAL LETTER B
     43 |  00000043 | LATIN CAPITAL LETTER C
     44 |  00000044 | LATIN CAPITAL LETTER D
     45 |  00000045 | LATIN CAPITAL LETTER E
     46 |  00000046 | LATIN CAPITAL LETTER F
     47 |  00000047 | LATIN CAPITAL LETTER G
     48 |  00000048 | LATIN CAPITAL LETTER H
     49 |  00000049 | LATIN CAPITAL LETTER I
     4A |  0000004A | LATIN CAPITAL LETTER J
     4B |  0000004B | LATIN CAPITAL LETTER K
     4C |  0000004C | LATIN CAPITAL LETTER L
     4D |  0000004D | LATIN CAPITAL LETTER M
     4E |  0000004E | LATIN CAPITAL LETTER N
     4F |  0000004F | LATIN CAPITAL LETTER O
     50 |  00000050 | LATIN CAPITAL LETTER P
     51 |  00000051 | LATIN CAPITAL LETTER Q
     52 |  00000052 | LATIN CAPITAL LETTER R
     53 |  00000053 | LATIN CAPITAL LETTER S
     54 |  00000054 | LATIN CAPITAL LETTER T
     55 |  00000055 | LATIN CAPITAL LETTER U
     56 |  00000056 | LATIN CAPITAL LETTER V
     57 |  00000057 | LATIN CAPITAL LETTER W
     58 |  00000058 | LATIN CAPITAL LETTER X
     59 |  00000059 | LATIN CAPITAL LETTER Y
     5A |  0000005A | LATIN CAPITAL LETTER Z
     5B |  0000005B | LEFT SQUARE BRACKET
     5C |  0000005C | REVERSE SOLIDUS
     5D |  0000005D | RIGHT SQUARE BRACKET
     5E |  0000005E | CIRCUMFLEX ACCENT
     5F |  0000005F | LOW LINE
     60 |  00000060 | GRAVE ACCENT
     61 |  00000061 | LATIN SMALL LETTER A
     62 |  00000062 | LATIN SMALL LETTER B
     63 |  00000063 | LATIN SMALL LETTER C
     64 |  00000064 | LATIN SMALL LETTER D
     65 |  00000065 | LATIN SMALL LETTER E
     66 |  00000066 | LATIN SMALL LETTER F
     67 |  00000067 | LATIN SMALL LETTER G
     68 |  00000068 | LATIN SMALL LETTER H
     69 |  00000069 | LATIN SMALL LETTER I
     6A |  0000006A | LATIN SMALL LETTER J
     6B |  0000006B | LATIN SMALL LETTER K
     6C |  0000006C | LATIN SMALL LETTER L
     6D |  0000006D | LATIN SMALL LETTER M
     6E |  0000006E | LATIN SMALL LETTER N
     6F |  0000006F | LATIN SMALL LETTER O
     70 |  00000070 | LATIN SMALL LETTER P
     71 |  00000071 | LATIN SMALL LETTER Q
     72 |  00000072 | LATIN SMALL LETTER R
     73 |  00000073 | LATIN SMALL LETTER S
     74 |  00000074 | LATIN SMALL LETTER T
     75 |  00000075 | LATIN SMALL LETTER U
     76 |  00000076 | LATIN SMALL LETTER V
     77 |  00000077 | LATIN SMALL LETTER W
     78 |  00000078 | LATIN SMALL LETTER X
     79 |  00000079 | LATIN SMALL LETTER Y
     7A |  0000007A | LATIN SMALL LETTER Z
     7B |  0000007B | LEFT CURLY BRACKET
     7C |  0000007C | VERTICAL LINE
     7D |  0000007D | RIGHT CURLY BRACKET
     7E |  0000007E | TILDE
     7F |  0000007F | DELETE
     80 |  000000C4 | LATIN CAPITAL LETTER A WITH DIAERESIS
     81 |  000000C5 | LATIN CAPITAL LETTER A WITH RING ABOVE
     82 |  000000C7 | LATIN CAPITAL LETTER C WITH CEDILLA
     83 |  000000C9 | LATIN CAPITAL LETTER E WITH ACUTE
     84 |  000000D1 | LATIN CAPITAL LETTER N WITH TILDE
     85 |  000000D6 | LATIN CAPITAL LETTER O WITH DIAERESIS
     86 |  000000DC | LATIN CAPITAL LETTER U WITH DIAERESIS
     87 |  000000E1 | LATIN SMALL LETTER A WITH ACUTE
     88 |  000000E0 | LATIN SMALL LETTER A WITH GRAVE
     89 |  000000E2 | LATIN SMALL LETTER A WITH CIRCUMFLEX
     8A |  000000E4 | LATIN SMALL LETTER A WITH DIAERESIS
     8B |  000000E3 | LATIN SMALL LETTER A WITH TILDE
     8C |  000000E5 | LATIN SMALL LETTER A WITH RING ABOVE
     8D |  000000E7 | LATIN SMALL LETTER C WITH CEDILLA
     8E |  000000E9 | LATIN SMALL LETTER E WITH ACUTE
     8F |  000000E8 | LATIN SMALL LETTER E WITH GRAVE
     90 |  000000EA | LATIN SMALL LETTER E WITH CIRCUMFLEX
     91 |  000000EB | LATIN SMALL LETTER E WITH DIAERESIS
     92 |  000000ED | LATIN SMALL LETTER I WITH ACUTE
     93 |  000000EC | LATIN SMALL LETTER I WITH GRAVE
     94 |  000000EE | LATIN SMALL LETTER I WITH CIRCUMFLEX
     95 |  000000EF | LATIN SMALL LETTER I WITH DIAERESIS
     96 |  000000F1 | LATIN SMALL LETTER N WITH TILDE
     97 |  000000F3 | LATIN SMALL LETTER O WITH ACUTE
     98 |  000000F2 | LATIN SMALL LETTER O WITH GRAVE
     99 |  000000F4 | LATIN SMALL LETTER O WITH CIRCUMFLEX
     9A |  000000F6 | LATIN SMALL LETTER O WITH DIAERESIS
     9B |  000000F5 | LATIN SMALL LETTER O WITH TILDE
     9C |  000000FA | LATIN SMALL LETTER U WITH ACUTE
     9D |  000000F9 | LATIN SMALL LETTER U WITH GRAVE
     9E |  000000FB | LATIN SMALL LETTER U WITH CIRCUMFLEX
     9F |  000000FC | LATIN SMALL LETTER U WITH DIAERESIS
     A0 |  000000DD | LATIN CAPITAL LETTER Y WITH ACUTE
     A1 |  000000B0 | DEGREE SIGN
     A2 |  0000010C | LATIN CAPITAL LETTER C WITH CARON
     A3 |  000000A3 | POUND SIGN
     A4 |  000000A7 | SECTION SIGN
     A5 |  00002022 | BULLET
     A6 |  000000B6 | PILCROW SIGN
     A7 |  000000DF | LATIN SMALL LETTER SHARP S (German)
     A8 |  000000AE | REGISTERED SIGN
     A9 |  000000A9 | COPYRIGHT SIGN
     AA |  00002122 | TRADE MARK SIGN
     AB |  000000B4 | ACUTE ACCENT
     AC |  000000A8 | DIAERESIS
     AD |  00002260 | NOT EQUAL TO
     AE |  000000C6 | LATIN CAPITAL LETTER AE
     AF |  000000D8 | LATIN CAPITAL LETTER O WITH STROKE
     B0 |  00000110 | LATIN CAPITAL LETTER D WITH STROKE
     B1 |  0000014A | LATIN CAPITAL LETTER ENG
     B2 |  0000821E | LATIN CAPITAL LETTER H WITH CARON
     B3 |  0000821F | LATIN SMALL LETTER H WITH CARON
     B4 |  00000160 | LATIN CAPITAL LETTER S WITH CARON
     B5 |  00000166 | LATIN CAPITAL LETTER T WITH STROKE
     B6 |  00002202 | PARTIAL DIFFERENTIAL
     B7 |  0000017D | LATIN CAPITAL LETTER Z WITH CARON
     B8 |  0000010D | LATIN SMALL LETTER C WITH CARON
     B9 |  00000111 | LATIN SMALL LETTER D WITH STROKE
     BA |  0000014B | LATIN SMALL LETTER ENG
     BB |  00000161 | LATIN SMALL LETTER S WITH CARON
     BC |  00000167 | LATIN SMALL LETTER T WITH STROKE
     BD |  0000017E | LATIN SMALL LETTER Z WITH CARON
     BE |  000000E6 | LATIN SMALL LETTER AE
     BF |  000000F8 | LATIN SMALL LETTER O WITH STROKE
     C0 |  000000BF | INVERTED QUESTION MARK
     C1 |  000000A1 | INVERTED EXCLAMATION MARK
     C2 |  000000AC | NOT SIGN
     C3 |  0000221A | SQUARE ROOT
     C4 |  00000192 | LATIN SMALL LETTER F WITH HOOK
     C5 |  00002248 | ALMOST EQUAL TO
     C6 |  00002206 | INCREMENT
     C7 |  000000AB | LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
     C8 |  000000BB | RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
     C9 |  00002026 | HORIZONTAL ELLIPSIS
     CA |  000000A0 | NO-BREAK SPACE
     CB |  000000C0 | LATIN CAPITAL LETTER A WITH GRAVE
     CC |  000000C3 | LATIN CAPITAL LETTER A WITH TILDE
     CD |  000000D5 | LATIN CAPITAL LETTER O WITH TILDE
     CE |  00000152 | LATIN CAPITAL LETTER LIGATURE OE
     CF |  00000153 | LATIN SMALL LETTER LIGATURE OE
     D0 |  00002013 | EN DASH
     D1 |  00002014 | EM DASH
     D2 |  0000201C | LEFT DOUBLE QUOTATION MARK
     D3 |  0000201D | RIGHT DOUBLE QUOTATION MARK
     D4 |  00002018 | LEFT SINGLE QUOTATION MARK
     D5 |  00002019 | RIGHT SINGLE QUOTATION MARK
     D6 |  000000F7 | DIVISION SIGN
     D7 |  000025CA | LOZENGE
     D8 |  000000FF | LATIN SMALL LETTER Y WITH DIAERESIS
     D9 |  00000178 | LATIN CAPITAL LETTER Y WITH DIAERESIS
     DA |  00002044 | FRACTION SLASH
     DB |  000000A4 | CURRENCY SIGN
     DC |  000000D0 | LATIN CAPITAL LETTER ETH
     DD |  000000F0 | LATIN SMALL LETTER ETH
     DE |  000000DE | LATIN CAPITAL LETTER THORN
     DF |  000000FE | LATIN SMALL LETTER THORN
     E0 |  000000FD | LATIN SMALL LETTER Y WITH ACUTE
     E1 |  000000B7 | MIDDLE DOT
     E2 |  0000201A | SINGLE LOW-9 QUOTATION MARK
     E3 |  0000201E | DOUBLE LOW-9 QUOTATION MARK
     E4 |  00002030 | PER MILLE SIGN
     E5 |  000000C2 | LATIN CAPITAL LETTER A WITH CIRCUMFLEX
     E6 |  000000CA | LATIN CAPITAL LETTER E WITH CIRCUMFLEX
     E7 |  000000C1 | LATIN CAPITAL LETTER A WITH ACUTE
     E8 |  000000CB | LATIN CAPITAL LETTER E WITH DIAERESIS
     E9 |  000000C8 | LATIN CAPITAL LETTER E WITH GRAVE
     EA |  000000CD | LATIN CAPITAL LETTER I WITH ACUTE
     EB |  000000CE | LATIN CAPITAL LETTER I WITH CIRCUMFLEX
     EC |  000000CF | LATIN CAPITAL LETTER I WITH DIAERESIS
     ED |  000000CC | LATIN CAPITAL LETTER I WITH GRAVE
     EE |  000000D3 | LATIN CAPITAL LETTER O WITH ACUTE
     EF |  000000D4 | LATIN CAPITAL LETTER O WITH CIRCUMFLEX
     F0 |  0000F8FF | APPLE SIGN
     F1 |  000000D2 | LATIN CAPITAL LETTER O WITH GRAVE
     F2 |  000000DA | LATIN CAPITAL LETTER U WITH ACUTE
     F3 |  000000DB | LATIN CAPITAL LETTER U WITH CIRCUMFLEX
     F4 |  000000D9 | LATIN CAPITAL LETTER U WITH GRAVE
     F5 |  00000131 | LATIN SMALL LETTER DOTLESS I
     F6 |  000001B7 | LATIN CAPITAL LETTER EZH
     F7 |  00000292 | LATIN SMALL LETTER EZH
     F8 |  000001EE | LATIN CAPITAL LETTER EZH WITH CARON
     F9 |  000001EF | LATIN SMALL LETTER EZH WITH CARON
     FA |  000001E4 | LATIN CAPITAL LETTER G WITH STROKE
     FB |  000001E5 | LATIN SMALLL LETTER G WITH STROKE
     FC |  000001E6 | LATIN CAPITAL LETTER G WITH CARON
     FD |  000001E7 | LATIN SMALL LETTER G WITH CARON
     FE |  000001E8 | LATIN CAPITAL LETTER K WITH CARON
     FF |  000001E9 | LATIN SMALL LETTER K WITH CARON
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/MAC_UK.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for MAC-UK.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::MAC_UK;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x0004,
     0x0005,
     0x0006,
     0x0007,
     0x0008,
     0x0009,
     0x000a,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x0014,
     0x0015,
     0x0016,
     0x0017,
     0x0018,
     0x0019,
     0x001a,
     0x001b,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0020,
     0x0021,
     0x0022,
     0x0023,
     0x0024,
     0x0025,
     0x0026,
     0x0027,
     0x0028,
     0x0029,
     0x002a,
     0x002b,
     0x002c,
     0x002d,
     0x002e,
     0x002f,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x003a,
     0x003b,
     0x003c,
     0x003d,
     0x003e,
     0x003f,
     0x0040,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x005b,
     0x005c,
     0x005d,
     0x005e,
     0x005f,
     0x0060,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x007b,
     0x007c,
     0x007d,
     0x007e,
     0x007f,
     0x0410,
     0x0411,
     0x0412,
     0x0413,
     0x0414,
     0x0415,
     0x0416,
     0x0417,
     0x0418,
     0x0419,
     0x041a,
     0x041b,
     0x041c,
     0x041d,
     0x041e,
     0x041f,
     0x0420,
     0x0421,
     0x0422,
     0x0423,
     0x0424,
     0x0425,
     0x0426,
     0x0427,
     0x0428,
     0x0429,
     0x042a,
     0x042b,
     0x042c,
     0x042d,
     0x042e,
     0x042f,
     0x2020,
     0x00b0,
     0x0490,
     0x00a3,
     0x00a7,
     0x2022,
     0x00b6,
     0x0406,
     0x00ae,
     0x00a9,
     0x2122,
     0x0402,
     0x0452,
     0x2260,
     0x0403,
     0x0453,
     0x221e,
     0x00b1,
     0x2264,
     0x2265,
     0x0456,
     0x00b5,
     0x0491,
     0x0408,
     0x0404,
     0x0454,
     0x0407,
     0x0457,
     0x0409,
     0x0459,
     0x040a,
     0x045a,
     0x0458,
     0x0405,
     0x00ac,
     0x221a,
     0x0192,
     0x2248,
     0x2206,
     0x00ab,
     0x00bb,
     0x2026,
     0x00a0,
     0x040b,
     0x045b,
     0x040c,
     0x045c,
     0x0455,
     0x2013,
     0x2014,
     0x201c,
     0x201d,
     0x2018,
     0x2019,
     0x00f7,
     0x201e,
     0x040e,
     0x045e,
     0x040f,
     0x045f,
     0x2116,
     0x0401,
     0x0451,
     0x044f,
     0x0430,
     0x0431,
     0x0432,
     0x0433,
     0x0434,
     0x0435,
     0x0436,
     0x0437,
     0x0438,
     0x0439,
     0x043a,
     0x043b,
     0x043c,
     0x043d,
     0x043e,
     0x043f,
     0x0440,
     0x0441,
     0x0442,
     0x0443,
     0x0444,
     0x0445,
     0x0446,
     0x0447,
     0x0448,
     0x0449,
     0x044a,
     0x044b,
     0x044c,
     0x044d,
     0x044e,
     0x00a4,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\x04",
     "\x05",
     "\x06",
     "\x07",
     "\x08",
     "\x09",
     "\x0a",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\x14",
     "\x15",
     "\x16",
     "\x17",
     "\x18",
     "\x19",
     "\x1a",
     "\x1b",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\x20",
     "\x21",
     "\x22",
     "\x23",
     "\x24",
     "\x25",
     "\x26",
     "\x27",
     "\x28",
     "\x29",
     "\x2a",
     "\x2b",
     "\x2c",
     "\x2d",
     "\x2e",
     "\x2f",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\x3a",
     "\x3b",
     "\x3c",
     "\x3d",
     "\x3e",
     "\x3f",
     "\x40",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\x5b",
     "\x5c",
     "\x5d",
     "\x5e",
     "\x5f",
     "\x60",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\x7b",
     "\x7c",
     "\x7d",
     "\x7e",
     "\x7f",
     "\xd0\x90",
     "\xd0\x91",
     "\xd0\x92",
     "\xd0\x93",
     "\xd0\x94",
     "\xd0\x95",
     "\xd0\x96",
     "\xd0\x97",
     "\xd0\x98",
     "\xd0\x99",
     "\xd0\x9a",
     "\xd0\x9b",
     "\xd0\x9c",
     "\xd0\x9d",
     "\xd0\x9e",
     "\xd0\x9f",
     "\xd0\xa0",
     "\xd0\xa1",
     "\xd0\xa2",
     "\xd0\xa3",
     "\xd0\xa4",
     "\xd0\xa5",
     "\xd0\xa6",
     "\xd0\xa7",
     "\xd0\xa8",
     "\xd0\xa9",
     "\xd0\xaa",
     "\xd0\xab",
     "\xd0\xac",
     "\xd0\xad",
     "\xd0\xae",
     "\xd0\xaf",
     "\xe2\x80\xa0",
     "\xc2\xb0",
     "\xd2\x90",
     "\xc2\xa3",
     "\xc2\xa7",
     "\xe2\x80\xa2",
     "\xc2\xb6",
     "\xd0\x86",
     "\xc2\xae",
     "\xc2\xa9",
     "\xe2\x84\xa2",
     "\xd0\x82",
     "\xd1\x92",
     "\xe2\x89\xa0",
     "\xd0\x83",
     "\xd1\x93",
     "\xe2\x88\x9e",
     "\xc2\xb1",
     "\xe2\x89\xa4",
     "\xe2\x89\xa5",
     "\xd1\x96",
     "\xc2\xb5",
     "\xd2\x91",
     "\xd0\x88",
     "\xd0\x84",
     "\xd1\x94",
     "\xd0\x87",
     "\xd1\x97",
     "\xd0\x89",
     "\xd1\x99",
     "\xd0\x8a",
     "\xd1\x9a",
     "\xd1\x98",
     "\xd0\x85",
     "\xc2\xac",
     "\xe2\x88\x9a",
     "\xc6\x92",
     "\xe2\x89\x88",
     "\xe2\x88\x86",
     "\xc2\xab",
     "\xc2\xbb",
     "\xe2\x80\xa6",
     "\xc2\xa0",
     "\xd0\x8b",
     "\xd1\x9b",
     "\xd0\x8c",
     "\xd1\x9c",
     "\xd1\x95",
     "\xe2\x80\x93",
     "\xe2\x80\x94",
     "\xe2\x80\x9c",
     "\xe2\x80\x9d",
     "\xe2\x80\x98",
     "\xe2\x80\x99",
     "\xc3\xb7",
     "\xe2\x80\x9e",
     "\xd0\x8e",
     "\xd1\x9e",
     "\xd0\x8f",
     "\xd1\x9f",
     "\xe2\x84\x96",
     "\xd0\x81",
     "\xd1\x91",
     "\xd1\x8f",
     "\xd0\xb0",
     "\xd0\xb1",
     "\xd0\xb2",
     "\xd0\xb3",
     "\xd0\xb4",
     "\xd0\xb5",
     "\xd0\xb6",
     "\xd0\xb7",
     "\xd0\xb8",
     "\xd0\xb9",
     "\xd0\xba",
     "\xd0\xbb",
     "\xd0\xbc",
     "\xd0\xbd",
     "\xd0\xbe",
     "\xd0\xbf",
     "\xd1\x80",
     "\xd1\x81",
     "\xd1\x82",
     "\xd1\x83",
     "\xd1\x84",
     "\xd1\x85",
     "\xd1\x86",
     "\xd1\x87",
     "\xd1\x88",
     "\xd1\x89",
     "\xd1\x8a",
     "\xd1\x8b",
     "\xd1\x8c",
     "\xd1\x8d",
     "\xd1\x8e",
     "\xc2\xa4",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x04",
     0x00000005 => "\x05",
     0x00000006 => "\x06",
     0x00000007 => "\x07",
     0x00000008 => "\x08",
     0x00000009 => "\x09",
     0x0000000a => "\x0a",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x14",
     0x00000015 => "\x15",
     0x00000016 => "\x16",
     0x00000017 => "\x17",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x1a",
     0x0000001b => "\x1b",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x20",
     0x00000021 => "\x21",
     0x00000022 => "\x22",
     0x00000023 => "\x23",
     0x00000024 => "\x24",
     0x00000025 => "\x25",
     0x00000026 => "\x26",
     0x00000027 => "\x27",
     0x00000028 => "\x28",
     0x00000029 => "\x29",
     0x0000002a => "\x2a",
     0x0000002b => "\x2b",
     0x0000002c => "\x2c",
     0x0000002d => "\x2d",
     0x0000002e => "\x2e",
     0x0000002f => "\x2f",
     0x00000030 => "\x30",
     0x00000031 => "\x31",
     0x00000032 => "\x32",
     0x00000033 => "\x33",
     0x00000034 => "\x34",
     0x00000035 => "\x35",
     0x00000036 => "\x36",
     0x00000037 => "\x37",
     0x00000038 => "\x38",
     0x00000039 => "\x39",
     0x0000003a => "\x3a",
     0x0000003b => "\x3b",
     0x0000003c => "\x3c",
     0x0000003d => "\x3d",
     0x0000003e => "\x3e",
     0x0000003f => "\x3f",
     0x00000040 => "\x40",
     0x00000041 => "\x41",
     0x00000042 => "\x42",
     0x00000043 => "\x43",
     0x00000044 => "\x44",
     0x00000045 => "\x45",
     0x00000046 => "\x46",
     0x00000047 => "\x47",
     0x00000048 => "\x48",
     0x00000049 => "\x49",
     0x0000004a => "\x4a",
     0x0000004b => "\x4b",
     0x0000004c => "\x4c",
     0x0000004d => "\x4d",
     0x0000004e => "\x4e",
     0x0000004f => "\x4f",
     0x00000050 => "\x50",
     0x00000051 => "\x51",
     0x00000052 => "\x52",
     0x00000053 => "\x53",
     0x00000054 => "\x54",
     0x00000055 => "\x55",
     0x00000056 => "\x56",
     0x00000057 => "\x57",
     0x00000058 => "\x58",
     0x00000059 => "\x59",
     0x0000005a => "\x5a",
     0x0000005b => "\x5b",
     0x0000005c => "\x5c",
     0x0000005d => "\x5d",
     0x0000005e => "\x5e",
     0x0000005f => "\x5f",
     0x00000060 => "\x60",
     0x00000061 => "\x61",
     0x00000062 => "\x62",
     0x00000063 => "\x63",
     0x00000064 => "\x64",
     0x00000065 => "\x65",
     0x00000066 => "\x66",
     0x00000067 => "\x67",
     0x00000068 => "\x68",
     0x00000069 => "\x69",
     0x0000006a => "\x6a",
     0x0000006b => "\x6b",
     0x0000006c => "\x6c",
     0x0000006d => "\x6d",
     0x0000006e => "\x6e",
     0x0000006f => "\x6f",
     0x00000070 => "\x70",
     0x00000071 => "\x71",
     0x00000072 => "\x72",
     0x00000073 => "\x73",
     0x00000074 => "\x74",
     0x00000075 => "\x75",
     0x00000076 => "\x76",
     0x00000077 => "\x77",
     0x00000078 => "\x78",
     0x00000079 => "\x79",
     0x0000007a => "\x7a",
     0x0000007b => "\x7b",
     0x0000007c => "\x7c",
     0x0000007d => "\x7d",
     0x0000007e => "\x7e",
     0x0000007f => "\x7f",
     0x000000a0 => "\xca",
     0x000000a3 => "\xa3",
     0x000000a4 => "\xff",
     0x000000a7 => "\xa4",
     0x000000a9 => "\xa9",
     0x000000ab => "\xc7",
     0x000000ac => "\xc2",
     0x000000ae => "\xa8",
     0x000000b0 => "\xa1",
     0x000000b1 => "\xb1",
     0x000000b5 => "\xb5",
     0x000000b6 => "\xa6",
     0x000000bb => "\xc8",
     0x000000f7 => "\xd6",
     0x00000192 => "\xc4",
     0x00000401 => "\xdd",
     0x00000402 => "\xab",
     0x00000403 => "\xae",
     0x00000404 => "\xb8",
     0x00000405 => "\xc1",
     0x00000406 => "\xa7",
     0x00000407 => "\xba",
     0x00000408 => "\xb7",
     0x00000409 => "\xbc",
     0x0000040a => "\xbe",
     0x0000040b => "\xcb",
     0x0000040c => "\xcd",
     0x0000040e => "\xd8",
     0x0000040f => "\xda",
     0x00000410 => "\x80",
     0x00000411 => "\x81",
     0x00000412 => "\x82",
     0x00000413 => "\x83",
     0x00000414 => "\x84",
     0x00000415 => "\x85",
     0x00000416 => "\x86",
     0x00000417 => "\x87",
     0x00000418 => "\x88",
     0x00000419 => "\x89",
     0x0000041a => "\x8a",
     0x0000041b => "\x8b",
     0x0000041c => "\x8c",
     0x0000041d => "\x8d",
     0x0000041e => "\x8e",
     0x0000041f => "\x8f",
     0x00000420 => "\x90",
     0x00000421 => "\x91",
     0x00000422 => "\x92",
     0x00000423 => "\x93",
     0x00000424 => "\x94",
     0x00000425 => "\x95",
     0x00000426 => "\x96",
     0x00000427 => "\x97",
     0x00000428 => "\x98",
     0x00000429 => "\x99",
     0x0000042a => "\x9a",
     0x0000042b => "\x9b",
     0x0000042c => "\x9c",
     0x0000042d => "\x9d",
     0x0000042e => "\x9e",
     0x0000042f => "\x9f",
     0x00000430 => "\xe0",
     0x00000431 => "\xe1",
     0x00000432 => "\xe2",
     0x00000433 => "\xe3",
     0x00000434 => "\xe4",
     0x00000435 => "\xe5",
     0x00000436 => "\xe6",
     0x00000437 => "\xe7",
     0x00000438 => "\xe8",
     0x00000439 => "\xe9",
     0x0000043a => "\xea",
     0x0000043b => "\xeb",
     0x0000043c => "\xec",
     0x0000043d => "\xed",
     0x0000043e => "\xee",
     0x0000043f => "\xef",
     0x00000440 => "\xf0",
     0x00000441 => "\xf1",
     0x00000442 => "\xf2",
     0x00000443 => "\xf3",
     0x00000444 => "\xf4",
     0x00000445 => "\xf5",
     0x00000446 => "\xf6",
     0x00000447 => "\xf7",
     0x00000448 => "\xf8",
     0x00000449 => "\xf9",
     0x0000044a => "\xfa",
     0x0000044b => "\xfb",
     0x0000044c => "\xfc",
     0x0000044d => "\xfd",
     0x0000044e => "\xfe",
     0x0000044f => "\xdf",
     0x00000451 => "\xde",
     0x00000452 => "\xac",
     0x00000453 => "\xaf",
     0x00000454 => "\xb9",
     0x00000455 => "\xcf",
     0x00000456 => "\xb4",
     0x00000457 => "\xbb",
     0x00000458 => "\xc0",
     0x00000459 => "\xbd",
     0x0000045a => "\xbf",
     0x0000045b => "\xcc",
     0x0000045c => "\xce",
     0x0000045e => "\xd9",
     0x0000045f => "\xdb",
     0x00000490 => "\xa2",
     0x00000491 => "\xb6",
     0x00002013 => "\xd0",
     0x00002014 => "\xd1",
     0x00002018 => "\xd4",
     0x00002019 => "\xd5",
     0x0000201c => "\xd2",
     0x0000201d => "\xd3",
     0x0000201e => "\xd7",
     0x00002020 => "\xa0",
     0x00002022 => "\xa5",
     0x00002026 => "\xc9",
     0x00002116 => "\xdc",
     0x00002122 => "\xaa",
     0x00002206 => "\xc6",
     0x0000221a => "\xc3",
     0x0000221e => "\xb0",
     0x00002248 => "\xc5",
     0x00002260 => "\xad",
     0x00002264 => "\xb2",
     0x00002265 => "\xb3",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::MAC_UK - Conversion routines for MAC-UK
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for MAC-UK.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  automatically generated from the charDB
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL
     01 |  00000001 | START OF HEADING
     02 |  00000002 | START OF TEXT
     03 |  00000003 | END OF TEXT
     04 |  00000004 | END OF TRANSMISSION
     05 |  00000005 | ENQUIRY
     06 |  00000006 | ACKNOWLEDGE
     07 |  00000007 | BELL
     08 |  00000008 | BACKSPACE
     09 |  00000009 | HORIZONTAL TABULATION
     0A |  0000000A | LINE FEED
     0B |  0000000B | VERTICAL TABULATION
     0C |  0000000C | FORM FEED
     0D |  0000000D | CARRIAGE RETURN
     0E |  0000000E | SHIFT OUT
     0F |  0000000F | SHIFT IN
     10 |  00000010 | DATA LINK ESCAPE
     11 |  00000011 | DEVICE CONTROL ONE
     12 |  00000012 | DEVICE CONTROL TWO
     13 |  00000013 | DEVICE CONTROL THREE
     14 |  00000014 | DEVICE CONTROL FOUR
     15 |  00000015 | NEGATIVE ACKNOWLEDGE
     16 |  00000016 | SYNCHRONOUS IDLE
     17 |  00000017 | END OF TRANSMISSION BLOCK
     18 |  00000018 | CANCEL
     19 |  00000019 | END OF MEDIUM
     1A |  0000001A | SUBSTITUTE
     1B |  0000001B | ESCAPE
     1C |  0000001C | FILE SEPARATOR
     1D |  0000001D | GROUP SEPARATOR
     1E |  0000001E | RECORD SEPARATOR
     1F |  0000001F | UNIT SEPARATOR
     20 |  00000020 | SPACE
     21 |  00000021 | EXCLAMATION MARK
     22 |  00000022 | QUOTATION MARK
     23 |  00000023 | NUMBER SIGN
     24 |  00000024 | DOLLAR SIGN
     25 |  00000025 | PERCENT SIGN
     26 |  00000026 | AMPERSAND
     27 |  00000027 | APOSTROPHE
     28 |  00000028 | LEFT PARENTHESIS
     29 |  00000029 | RIGHT PARENTHESIS
     2A |  0000002A | ASTERISK
     2B |  0000002B | PLUS SIGN
     2C |  0000002C | COMMA
     2D |  0000002D | HYPHEN-MINUS
     2E |  0000002E | FULL STOP
     2F |  0000002F | SOLIDUS
     30 |  00000030 | DIGIT ZERO
     31 |  00000031 | DIGIT ONE
     32 |  00000032 | DIGIT TWO
     33 |  00000033 | DIGIT THREE
     34 |  00000034 | DIGIT FOUR
     35 |  00000035 | DIGIT FIVE
     36 |  00000036 | DIGIT SIX
     37 |  00000037 | DIGIT SEVEN
     38 |  00000038 | DIGIT EIGHT
     39 |  00000039 | DIGIT NINE
     3A |  0000003A | COLON
     3B |  0000003B | SEMICOLON
     3C |  0000003C | LESS-THAN SIGN
     3D |  0000003D | EQUALS SIGN
     3E |  0000003E | GREATER-THAN SIGN
     3F |  0000003F | QUESTION MARK
     40 |  00000040 | COMMERCIAL AT
     41 |  00000041 | LATIN CAPITAL LETTER A
     42 |  00000042 | LATIN CAPITAL LETTER B
     43 |  00000043 | LATIN CAPITAL LETTER C
     44 |  00000044 | LATIN CAPITAL LETTER D
     45 |  00000045 | LATIN CAPITAL LETTER E
     46 |  00000046 | LATIN CAPITAL LETTER F
     47 |  00000047 | LATIN CAPITAL LETTER G
     48 |  00000048 | LATIN CAPITAL LETTER H
     49 |  00000049 | LATIN CAPITAL LETTER I
     4A |  0000004A | LATIN CAPITAL LETTER J
     4B |  0000004B | LATIN CAPITAL LETTER K
     4C |  0000004C | LATIN CAPITAL LETTER L
     4D |  0000004D | LATIN CAPITAL LETTER M
     4E |  0000004E | LATIN CAPITAL LETTER N
     4F |  0000004F | LATIN CAPITAL LETTER O
     50 |  00000050 | LATIN CAPITAL LETTER P
     51 |  00000051 | LATIN CAPITAL LETTER Q
     52 |  00000052 | LATIN CAPITAL LETTER R
     53 |  00000053 | LATIN CAPITAL LETTER S
     54 |  00000054 | LATIN CAPITAL LETTER T
     55 |  00000055 | LATIN CAPITAL LETTER U
     56 |  00000056 | LATIN CAPITAL LETTER V
     57 |  00000057 | LATIN CAPITAL LETTER W
     58 |  00000058 | LATIN CAPITAL LETTER X
     59 |  00000059 | LATIN CAPITAL LETTER Y
     5A |  0000005A | LATIN CAPITAL LETTER Z
     5B |  0000005B | LEFT SQUARE BRACKET
     5C |  0000005C | REVERSE SOLIDUS
     5D |  0000005D | RIGHT SQUARE BRACKET
     5E |  0000005E | CIRCUMFLEX ACCENT
     5F |  0000005F | LOW LINE
     60 |  00000060 | GRAVE ACCENT
     61 |  00000061 | LATIN SMALL LETTER A
     62 |  00000062 | LATIN SMALL LETTER B
     63 |  00000063 | LATIN SMALL LETTER C
     64 |  00000064 | LATIN SMALL LETTER D
     65 |  00000065 | LATIN SMALL LETTER E
     66 |  00000066 | LATIN SMALL LETTER F
     67 |  00000067 | LATIN SMALL LETTER G
     68 |  00000068 | LATIN SMALL LETTER H
     69 |  00000069 | LATIN SMALL LETTER I
     6A |  0000006A | LATIN SMALL LETTER J
     6B |  0000006B | LATIN SMALL LETTER K
     6C |  0000006C | LATIN SMALL LETTER L
     6D |  0000006D | LATIN SMALL LETTER M
     6E |  0000006E | LATIN SMALL LETTER N
     6F |  0000006F | LATIN SMALL LETTER O
     70 |  00000070 | LATIN SMALL LETTER P
     71 |  00000071 | LATIN SMALL LETTER Q
     72 |  00000072 | LATIN SMALL LETTER R
     73 |  00000073 | LATIN SMALL LETTER S
     74 |  00000074 | LATIN SMALL LETTER T
     75 |  00000075 | LATIN SMALL LETTER U
     76 |  00000076 | LATIN SMALL LETTER V
     77 |  00000077 | LATIN SMALL LETTER W
     78 |  00000078 | LATIN SMALL LETTER X
     79 |  00000079 | LATIN SMALL LETTER Y
     7A |  0000007A | LATIN SMALL LETTER Z
     7B |  0000007B | LEFT CURLY BRACKET
     7C |  0000007C | VERTICAL LINE
     7D |  0000007D | RIGHT CURLY BRACKET
     7E |  0000007E | TILDE
     7F |  0000007F | DELETE
     80 |  00000410 | CYRILLIC CAPITAL LETTER A
     81 |  00000411 | CYRILLIC CAPITAL LETTER BE
     82 |  00000412 | CYRILLIC CAPITAL LETTER VE
     83 |  00000413 | CYRILLIC CAPITAL LETTER GHE
     84 |  00000414 | CYRILLIC CAPITAL LETTER DE
     85 |  00000415 | CYRILLIC CAPITAL LETTER IE
     86 |  00000416 | CYRILLIC CAPITAL LETTER ZHE
     87 |  00000417 | CYRILLIC CAPITAL LETTER ZE
     88 |  00000418 | CYRILLIC CAPITAL LETTER I
     89 |  00000419 | CYRILLIC CAPITAL LETTER SHORT I
     8A |  0000041A | CYRILLIC CAPITAL LETTER KA
     8B |  0000041B | CYRILLIC CAPITAL LETTER EL
     8C |  0000041C | CYRILLIC CAPITAL LETTER EM
     8D |  0000041D | CYRILLIC CAPITAL LETTER EN
     8E |  0000041E | CYRILLIC CAPITAL LETTER O
     8F |  0000041F | CYRILLIC CAPITAL LETTER PE
     90 |  00000420 | CYRILLIC CAPITAL LETTER ER
     91 |  00000421 | CYRILLIC CAPITAL LETTER ES
     92 |  00000422 | CYRILLIC CAPITAL LETTER TE
     93 |  00000423 | CYRILLIC CAPITAL LETTER U
     94 |  00000424 | CYRILLIC CAPITAL LETTER EF
     95 |  00000425 | CYRILLIC CAPITAL LETTER HA
     96 |  00000426 | CYRILLIC CAPITAL LETTER TSE
     97 |  00000427 | CYRILLIC CAPITAL LETTER CHE
     98 |  00000428 | CYRILLIC CAPITAL LETTER SHA
     99 |  00000429 | CYRILLIC CAPITAL LETTER SHCHA
     9A |  0000042A | CYRILLIC CAPITAL LETTER HARD SIGN
     9B |  0000042B | CYRILLIC CAPITAL LETTER YERU
     9C |  0000042C | CYRILLIC CAPITAL LETTER SOFT SIGN
     9D |  0000042D | CYRILLIC CAPITAL LETTER E
     9E |  0000042E | CYRILLIC CAPITAL LETTER YU
     9F |  0000042F | CYRILLIC CAPITAL LETTER YA
     A0 |  00002020 | DAGGER
     A1 |  000000B0 | DEGREE SIGN
     A2 |  00000490 | CYRILLIC CAPITAL LETTER GHE WITH UPTURN
     A3 |  000000A3 | POUND SIGN
     A4 |  000000A7 | SECTION SIGN
     A5 |  00002022 | BULLET
     A6 |  000000B6 | PILCROW SIGN
     A7 |  00000406 | CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I
     A8 |  000000AE | REGISTERED SIGN
     A9 |  000000A9 | COPYRIGHT SIGN
     AA |  00002122 | TRADE MARK SIGN
     AB |  00000402 | CYRILLIC CAPITAL LETTER DJE
     AC |  00000452 | CYRILLIC SMALL LETTER DJE
     AD |  00002260 | NOT EQUAL TO
     AE |  00000403 | CYRILLIC CAPITAL LETTER GJE
     AF |  00000453 | CYRILLIC SMALL LETTER GJE
     B0 |  0000221E | INFINITY
     B1 |  000000B1 | PLUS-MINUS SIGN
     B2 |  00002264 | LESS-THAN OR EQUAL TO
     B3 |  00002265 | GREATER-THAN OR EQUAL TO
     B4 |  00000456 | CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I
     B5 |  000000B5 | MICRO SIGN
     B6 |  00000491 | CYRILLIC SMALL LETTER GHE WITH UPTURN
     B7 |  00000408 | CYRILLIC CAPITAL LETTER JE
     B8 |  00000404 | CYRILLIC CAPITAL LETTER UKRAINIAN IE
     B9 |  00000454 | CYRILLIC SMALL LETTER UKRAINIAN IE
     BA |  00000407 | CYRILLIC CAPITAL LETTER YI
     BB |  00000457 | CYRILLIC SMALL LETTER YI
     BC |  00000409 | CYRILLIC CAPITAL LETTER LJE
     BD |  00000459 | CYRILLIC SMALL LETTER LJE
     BE |  0000040A | CYRILLIC CAPITAL LETTER NJE
     BF |  0000045A | CYRILLIC SMALL LETTER NJE
     C0 |  00000458 | CYRILLIC SMALL LETTER JE
     C1 |  00000405 | CYRILLIC CAPITAL LETTER DZE
     C2 |  000000AC | NOT SIGN
     C3 |  0000221A | SQUARE ROOT
     C4 |  00000192 | LATIN SMALL LETTER F WITH HOOK
     C5 |  00002248 | ALMOST EQUAL TO
     C6 |  00002206 | INCREMENT
     C7 |  000000AB | LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
     C8 |  000000BB | RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
     C9 |  00002026 | HORIZONTAL ELLIPSIS
     CA |  000000A0 | NO-BREAK SPACE
     CB |  0000040B | CYRILLIC CAPITAL LETTER TSHE
     CC |  0000045B | CYRILLIC SMALL LETTER TSHE
     CD |  0000040C | CYRILLIC CAPITAL LETTER KJE
     CE |  0000045C | CYRILLIC SMALL LETTER KJE
     CF |  00000455 | CYRILLIC SMALL LETTER DZE
     D0 |  00002013 | EN DASH
     D1 |  00002014 | EM DASH
     D2 |  0000201C | LEFT DOUBLE QUOTATION MARK
     D3 |  0000201D | RIGHT DOUBLE QUOTATION MARK
     D4 |  00002018 | LEFT SINGLE QUOTATION MARK
     D5 |  00002019 | RIGHT SINGLE QUOTATION MARK
     D6 |  000000F7 | DIVISION SIGN
     D7 |  0000201E | DOUBLE LOW-9 QUOTATION MARK
     D8 |  0000040E | CYRILLIC CAPITAL LETTER SHORT U
     D9 |  0000045E | CYRILLIC SMALL LETTER SHORT U
     DA |  0000040F | CYRILLIC CAPITAL LETTER DZHE
     DB |  0000045F | CYRILLIC SMALL LETTER DZHE
     DC |  00002116 | NUMERO SIGN
     DD |  00000401 | CYRILLIC CAPITAL LETTER IO
     DE |  00000451 | CYRILLIC SMALL LETTER IO
     DF |  0000044F | CYRILLIC SMALL LETTER YA
     E0 |  00000430 | CYRILLIC SMALL LETTER A
     E1 |  00000431 | CYRILLIC SMALL LETTER BE
     E2 |  00000432 | CYRILLIC SMALL LETTER VE
     E3 |  00000433 | CYRILLIC SMALL LETTER GHE
     E4 |  00000434 | CYRILLIC SMALL LETTER DE
     E5 |  00000435 | CYRILLIC SMALL LETTER IE
     E6 |  00000436 | CYRILLIC SMALL LETTER ZHE
     E7 |  00000437 | CYRILLIC SMALL LETTER ZE
     E8 |  00000438 | CYRILLIC SMALL LETTER I
     E9 |  00000439 | CYRILLIC SMALL LETTER SHORT I
     EA |  0000043A | CYRILLIC SMALL LETTER KA
     EB |  0000043B | CYRILLIC SMALL LETTER EL
     EC |  0000043C | CYRILLIC SMALL LETTER EM
     ED |  0000043D | CYRILLIC SMALL LETTER EN
     EE |  0000043E | CYRILLIC SMALL LETTER O
     EF |  0000043F | CYRILLIC SMALL LETTER PE
     F0 |  00000440 | CYRILLIC SMALL LETTER ER
     F1 |  00000441 | CYRILLIC SMALL LETTER ES
     F2 |  00000442 | CYRILLIC SMALL LETTER TE
     F3 |  00000443 | CYRILLIC SMALL LETTER U
     F4 |  00000444 | CYRILLIC SMALL LETTER EF
     F5 |  00000445 | CYRILLIC SMALL LETTER HA
     F6 |  00000446 | CYRILLIC SMALL LETTER TSE
     F7 |  00000447 | CYRILLIC SMALL LETTER CHE
     F8 |  00000448 | CYRILLIC SMALL LETTER SHA
     F9 |  00000449 | CYRILLIC SMALL LETTER SHCHA
     FA |  0000044A | CYRILLIC SMALL LETTER HARD SIGN
     FB |  0000044B | CYRILLIC SMALL LETTER YERU
     FC |  0000044C | CYRILLIC SMALL LETTER SOFT SIGN
     FD |  0000044D | CYRILLIC SMALL LETTER E
     FE |  0000044E | CYRILLIC SMALL LETTER YU
     FF |  000000A4 | CURRENCY SIGN
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/NATS_DANO.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for NATS-DANO.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::NATS_DANO;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x0004,
     0x0005,
     0x0006,
     0x0007,
     0x0008,
     0x0009,
     0x000a,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x0014,
     0x0015,
     0x0016,
     0x0017,
     0x0018,
     0x0019,
     0x001a,
     0x001b,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0020,
     0x0021,
     0x00ab,
     0x00bb,
     0x0024,
     0x0025,
     0x0026,
     0x0027,
     0x0028,
     0x0029,
     0x002a,
     0x002b,
     0x002c,
     0x002d,
     0x002e,
     0x002f,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x003a,
     0x003b,
     0x003c,
     0x003d,
     0x003e,
     0x003f,
     0xe018,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x00c6,
     0x00d8,
     0x00c5,
     0x25a0,
     0x005f,
     0xe019,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x00e6,
     0x00f8,
     0x00e5,
     0x2013,
     0x007f,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\x04",
     "\x05",
     "\x06",
     "\x07",
     "\x08",
     "\x09",
     "\x0a",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\x14",
     "\x15",
     "\x16",
     "\x17",
     "\x18",
     "\x19",
     "\x1a",
     "\x1b",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\x20",
     "\x21",
     "\xc2\xab",
     "\xc2\xbb",
     "\x24",
     "\x25",
     "\x26",
     "\x27",
     "\x28",
     "\x29",
     "\x2a",
     "\x2b",
     "\x2c",
     "\x2d",
     "\x2e",
     "\x2f",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\x3a",
     "\x3b",
     "\x3c",
     "\x3d",
     "\x3e",
     "\x3f",
     "\xee\x80\x98",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\xc3\x86",
     "\xc3\x98",
     "\xc3\x85",
     "\xe2\x96\xa0",
     "\x5f",
     "\xee\x80\x99",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\xc3\xa6",
     "\xc3\xb8",
     "\xc3\xa5",
     "\xe2\x80\x93",
     "\x7f",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x04",
     0x00000005 => "\x05",
     0x00000006 => "\x06",
     0x00000007 => "\x07",
     0x00000008 => "\x08",
     0x00000009 => "\x09",
     0x0000000a => "\x0a",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x14",
     0x00000015 => "\x15",
     0x00000016 => "\x16",
     0x00000017 => "\x17",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x1a",
     0x0000001b => "\x1b",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x20",
     0x00000021 => "\x21",
     0x00000024 => "\x24",
     0x00000025 => "\x25",
     0x00000026 => "\x26",
     0x00000027 => "\x27",
     0x00000028 => "\x28",
     0x00000029 => "\x29",
     0x0000002a => "\x2a",
     0x0000002b => "\x2b",
     0x0000002c => "\x2c",
     0x0000002d => "\x2d",
     0x0000002e => "\x2e",
     0x0000002f => "\x2f",
     0x00000030 => "\x30",
     0x00000031 => "\x31",
     0x00000032 => "\x32",
     0x00000033 => "\x33",
     0x00000034 => "\x34",
     0x00000035 => "\x35",
     0x00000036 => "\x36",
     0x00000037 => "\x37",
     0x00000038 => "\x38",
     0x00000039 => "\x39",
     0x0000003a => "\x3a",
     0x0000003b => "\x3b",
     0x0000003c => "\x3c",
     0x0000003d => "\x3d",
     0x0000003e => "\x3e",
     0x0000003f => "\x3f",
     0x00000041 => "\x41",
     0x00000042 => "\x42",
     0x00000043 => "\x43",
     0x00000044 => "\x44",
     0x00000045 => "\x45",
     0x00000046 => "\x46",
     0x00000047 => "\x47",
     0x00000048 => "\x48",
     0x00000049 => "\x49",
     0x0000004a => "\x4a",
     0x0000004b => "\x4b",
     0x0000004c => "\x4c",
     0x0000004d => "\x4d",
     0x0000004e => "\x4e",
     0x0000004f => "\x4f",
     0x00000050 => "\x50",
     0x00000051 => "\x51",
     0x00000052 => "\x52",
     0x00000053 => "\x53",
     0x00000054 => "\x54",
     0x00000055 => "\x55",
     0x00000056 => "\x56",
     0x00000057 => "\x57",
     0x00000058 => "\x58",
     0x00000059 => "\x59",
     0x0000005a => "\x5a",
     0x0000005f => "\x5f",
     0x00000061 => "\x61",
     0x00000062 => "\x62",
     0x00000063 => "\x63",
     0x00000064 => "\x64",
     0x00000065 => "\x65",
     0x00000066 => "\x66",
     0x00000067 => "\x67",
     0x00000068 => "\x68",
     0x00000069 => "\x69",
     0x0000006a => "\x6a",
     0x0000006b => "\x6b",
     0x0000006c => "\x6c",
     0x0000006d => "\x6d",
     0x0000006e => "\x6e",
     0x0000006f => "\x6f",
     0x00000070 => "\x70",
     0x00000071 => "\x71",
     0x00000072 => "\x72",
     0x00000073 => "\x73",
     0x00000074 => "\x74",
     0x00000075 => "\x75",
     0x00000076 => "\x76",
     0x00000077 => "\x77",
     0x00000078 => "\x78",
     0x00000079 => "\x79",
     0x0000007a => "\x7a",
     0x0000007f => "\x7f",
     0x000000ab => "\x22",
     0x000000bb => "\x23",
     0x000000c5 => "\x5d",
     0x000000c6 => "\x5b",
     0x000000d8 => "\x5c",
     0x000000e5 => "\x7d",
     0x000000e6 => "\x7b",
     0x000000f8 => "\x7c",
     0x00002013 => "\x7e",
     0x000025a0 => "\x5e",
     0x0000e018 => "\x40",
     0x0000e019 => "\x60",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::NATS_DANO - Conversion routines for NATS_DANO
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for NATS-DANO.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
   source: ECMA registry
  alias ISO-IR-9-1
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  00000004 | END OF TRANSMISSION (EOT)
     05 |  00000005 | ENQUIRY (ENQ)
     06 |  00000006 | ACKNOWLEDGE (ACK)
     07 |  00000007 | BELL (BEL)
     08 |  00000008 | BACKSPACE (BS)
     09 |  00000009 | CHARACTER TABULATION (HT)
     0A |  0000000A | LINE FEED (LF)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  00000014 | DEVICE CONTROL FOUR (DC4)
     15 |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     16 |  00000016 | SYNCHRONOUS IDLE (SYN)
     17 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  0000001A | SUBSTITUTE (SUB)
     1B |  0000001B | ESCAPE (ESC)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000020 | SPACE
     21 |  00000021 | EXCLAMATION MARK
     22 |  000000AB | LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
     23 |  000000BB | RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
     24 |  00000024 | DOLLAR SIGN
     25 |  00000025 | PERCENT SIGN
     26 |  00000026 | AMPERSAND
     27 |  00000027 | APOSTROPHE
     28 |  00000028 | LEFT PARENTHESIS
     29 |  00000029 | RIGHT PARENTHESIS
     2A |  0000002A | ASTERISK
     2B |  0000002B | PLUS SIGN
     2C |  0000002C | COMMA
     2D |  0000002D | HYPHEN-MINUS
     2E |  0000002E | FULL STOP
     2F |  0000002F | SOLIDUS
     30 |  00000030 | DIGIT ZERO
     31 |  00000031 | DIGIT ONE
     32 |  00000032 | DIGIT TWO
     33 |  00000033 | DIGIT THREE
     34 |  00000034 | DIGIT FOUR
     35 |  00000035 | DIGIT FIVE
     36 |  00000036 | DIGIT SIX
     37 |  00000037 | DIGIT SEVEN
     38 |  00000038 | DIGIT EIGHT
     39 |  00000039 | DIGIT NINE
     3A |  0000003A | COLON
     3B |  0000003B | SEMICOLON
     3C |  0000003C | LESS-THAN SIGN
     3D |  0000003D | EQUALS SIGN
     3E |  0000003E | GREATER-THAN SIGN
     3F |  0000003F | QUESTION MARK
     40 |  0000E018 | Unit space A E<lt>ISO-IR-8-1_40E<gt>
     41 |  00000041 | LATIN CAPITAL LETTER A
     42 |  00000042 | LATIN CAPITAL LETTER B
     43 |  00000043 | LATIN CAPITAL LETTER C
     44 |  00000044 | LATIN CAPITAL LETTER D
     45 |  00000045 | LATIN CAPITAL LETTER E
     46 |  00000046 | LATIN CAPITAL LETTER F
     47 |  00000047 | LATIN CAPITAL LETTER G
     48 |  00000048 | LATIN CAPITAL LETTER H
     49 |  00000049 | LATIN CAPITAL LETTER I
     4A |  0000004A | LATIN CAPITAL LETTER J
     4B |  0000004B | LATIN CAPITAL LETTER K
     4C |  0000004C | LATIN CAPITAL LETTER L
     4D |  0000004D | LATIN CAPITAL LETTER M
     4E |  0000004E | LATIN CAPITAL LETTER N
     4F |  0000004F | LATIN CAPITAL LETTER O
     50 |  00000050 | LATIN CAPITAL LETTER P
     51 |  00000051 | LATIN CAPITAL LETTER Q
     52 |  00000052 | LATIN CAPITAL LETTER R
     53 |  00000053 | LATIN CAPITAL LETTER S
     54 |  00000054 | LATIN CAPITAL LETTER T
     55 |  00000055 | LATIN CAPITAL LETTER U
     56 |  00000056 | LATIN CAPITAL LETTER V
     57 |  00000057 | LATIN CAPITAL LETTER W
     58 |  00000058 | LATIN CAPITAL LETTER X
     59 |  00000059 | LATIN CAPITAL LETTER Y
     5A |  0000005A | LATIN CAPITAL LETTER Z
     5B |  000000C6 | LATIN CAPITAL LETTER AE
     5C |  000000D8 | LATIN CAPITAL LETTER O WITH STROKE
     5D |  000000C5 | LATIN CAPITAL LETTER A WITH RING ABOVE
     5E |  000025A0 | BLACK SQUARE
     5F |  0000005F | LOW LINE
     60 |  0000E019 | Unit space B E<lt>ISO-IR-8-1_60E<gt>
     61 |  00000061 | LATIN SMALL LETTER A
     62 |  00000062 | LATIN SMALL LETTER B
     63 |  00000063 | LATIN SMALL LETTER C
     64 |  00000064 | LATIN SMALL LETTER D
     65 |  00000065 | LATIN SMALL LETTER E
     66 |  00000066 | LATIN SMALL LETTER F
     67 |  00000067 | LATIN SMALL LETTER G
     68 |  00000068 | LATIN SMALL LETTER H
     69 |  00000069 | LATIN SMALL LETTER I
     6A |  0000006A | LATIN SMALL LETTER J
     6B |  0000006B | LATIN SMALL LETTER K
     6C |  0000006C | LATIN SMALL LETTER L
     6D |  0000006D | LATIN SMALL LETTER M
     6E |  0000006E | LATIN SMALL LETTER N
     6F |  0000006F | LATIN SMALL LETTER O
     70 |  00000070 | LATIN SMALL LETTER P
     71 |  00000071 | LATIN SMALL LETTER Q
     72 |  00000072 | LATIN SMALL LETTER R
     73 |  00000073 | LATIN SMALL LETTER S
     74 |  00000074 | LATIN SMALL LETTER T
     75 |  00000075 | LATIN SMALL LETTER U
     76 |  00000076 | LATIN SMALL LETTER V
     77 |  00000077 | LATIN SMALL LETTER W
     78 |  00000078 | LATIN SMALL LETTER X
     79 |  00000079 | LATIN SMALL LETTER Y
     7A |  0000007A | LATIN SMALL LETTER Z
     7B |  000000E6 | LATIN SMALL LETTER AE
     7C |  000000F8 | LATIN SMALL LETTER O WITH STROKE
     7D |  000000E5 | LATIN SMALL LETTER A WITH RING ABOVE
     7E |  00002013 | EN DASH
     7F |  0000007F | DELETE (DEL)
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/NATS_SEFI.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for NATS-SEFI.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::NATS_SEFI;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x0004,
     0x0005,
     0x0006,
     0x0007,
     0x0008,
     0x0009,
     0x000a,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x0014,
     0x0015,
     0x0016,
     0x0017,
     0x0018,
     0x0019,
     0x001a,
     0x001b,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0020,
     0x0021,
     0x0022,
     0x0023,
     0x0024,
     0x0025,
     0x0026,
     0x0027,
     0x0028,
     0x0029,
     0x002a,
     0x002b,
     0x002c,
     0x002d,
     0x002e,
     0x002f,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x003a,
     0x003b,
     0x003c,
     0x003d,
     0x003e,
     0x003f,
     0xe018,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x00c4,
     0x00d6,
     0x00c5,
     0x25a0,
     0x005f,
     0xe019,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x00e4,
     0x00f6,
     0x00e5,
     0x2013,
     0x007f,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\x04",
     "\x05",
     "\x06",
     "\x07",
     "\x08",
     "\x09",
     "\x0a",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\x14",
     "\x15",
     "\x16",
     "\x17",
     "\x18",
     "\x19",
     "\x1a",
     "\x1b",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\x20",
     "\x21",
     "\x22",
     "\x23",
     "\x24",
     "\x25",
     "\x26",
     "\x27",
     "\x28",
     "\x29",
     "\x2a",
     "\x2b",
     "\x2c",
     "\x2d",
     "\x2e",
     "\x2f",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\x3a",
     "\x3b",
     "\x3c",
     "\x3d",
     "\x3e",
     "\x3f",
     "\xee\x80\x98",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\xc3\x84",
     "\xc3\x96",
     "\xc3\x85",
     "\xe2\x96\xa0",
     "\x5f",
     "\xee\x80\x99",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\xc3\xa4",
     "\xc3\xb6",
     "\xc3\xa5",
     "\xe2\x80\x93",
     "\x7f",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x04",
     0x00000005 => "\x05",
     0x00000006 => "\x06",
     0x00000007 => "\x07",
     0x00000008 => "\x08",
     0x00000009 => "\x09",
     0x0000000a => "\x0a",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x14",
     0x00000015 => "\x15",
     0x00000016 => "\x16",
     0x00000017 => "\x17",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x1a",
     0x0000001b => "\x1b",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x20",
     0x00000021 => "\x21",
     0x00000022 => "\x22",
     0x00000023 => "\x23",
     0x00000024 => "\x24",
     0x00000025 => "\x25",
     0x00000026 => "\x26",
     0x00000027 => "\x27",
     0x00000028 => "\x28",
     0x00000029 => "\x29",
     0x0000002a => "\x2a",
     0x0000002b => "\x2b",
     0x0000002c => "\x2c",
     0x0000002d => "\x2d",
     0x0000002e => "\x2e",
     0x0000002f => "\x2f",
     0x00000030 => "\x30",
     0x00000031 => "\x31",
     0x00000032 => "\x32",
     0x00000033 => "\x33",
     0x00000034 => "\x34",
     0x00000035 => "\x35",
     0x00000036 => "\x36",
     0x00000037 => "\x37",
     0x00000038 => "\x38",
     0x00000039 => "\x39",
     0x0000003a => "\x3a",
     0x0000003b => "\x3b",
     0x0000003c => "\x3c",
     0x0000003d => "\x3d",
     0x0000003e => "\x3e",
     0x0000003f => "\x3f",
     0x00000041 => "\x41",
     0x00000042 => "\x42",
     0x00000043 => "\x43",
     0x00000044 => "\x44",
     0x00000045 => "\x45",
     0x00000046 => "\x46",
     0x00000047 => "\x47",
     0x00000048 => "\x48",
     0x00000049 => "\x49",
     0x0000004a => "\x4a",
     0x0000004b => "\x4b",
     0x0000004c => "\x4c",
     0x0000004d => "\x4d",
     0x0000004e => "\x4e",
     0x0000004f => "\x4f",
     0x00000050 => "\x50",
     0x00000051 => "\x51",
     0x00000052 => "\x52",
     0x00000053 => "\x53",
     0x00000054 => "\x54",
     0x00000055 => "\x55",
     0x00000056 => "\x56",
     0x00000057 => "\x57",
     0x00000058 => "\x58",
     0x00000059 => "\x59",
     0x0000005a => "\x5a",
     0x0000005f => "\x5f",
     0x00000061 => "\x61",
     0x00000062 => "\x62",
     0x00000063 => "\x63",
     0x00000064 => "\x64",
     0x00000065 => "\x65",
     0x00000066 => "\x66",
     0x00000067 => "\x67",
     0x00000068 => "\x68",
     0x00000069 => "\x69",
     0x0000006a => "\x6a",
     0x0000006b => "\x6b",
     0x0000006c => "\x6c",
     0x0000006d => "\x6d",
     0x0000006e => "\x6e",
     0x0000006f => "\x6f",
     0x00000070 => "\x70",
     0x00000071 => "\x71",
     0x00000072 => "\x72",
     0x00000073 => "\x73",
     0x00000074 => "\x74",
     0x00000075 => "\x75",
     0x00000076 => "\x76",
     0x00000077 => "\x77",
     0x00000078 => "\x78",
     0x00000079 => "\x79",
     0x0000007a => "\x7a",
     0x0000007f => "\x7f",
     0x000000c4 => "\x5b",
     0x000000c5 => "\x5d",
     0x000000d6 => "\x5c",
     0x000000e4 => "\x7b",
     0x000000e5 => "\x7d",
     0x000000f6 => "\x7c",
     0x00002013 => "\x7e",
     0x000025a0 => "\x5e",
     0x0000e018 => "\x40",
     0x0000e019 => "\x60",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::NATS_SEFI - Conversion routines for NATS_SEFI
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for NATS-SEFI.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
   source: ECMA registry
  alias ISO-IR-8-1
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  00000004 | END OF TRANSMISSION (EOT)
     05 |  00000005 | ENQUIRY (ENQ)
     06 |  00000006 | ACKNOWLEDGE (ACK)
     07 |  00000007 | BELL (BEL)
     08 |  00000008 | BACKSPACE (BS)
     09 |  00000009 | CHARACTER TABULATION (HT)
     0A |  0000000A | LINE FEED (LF)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  00000014 | DEVICE CONTROL FOUR (DC4)
     15 |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     16 |  00000016 | SYNCHRONOUS IDLE (SYN)
     17 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  0000001A | SUBSTITUTE (SUB)
     1B |  0000001B | ESCAPE (ESC)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000020 | SPACE
     21 |  00000021 | EXCLAMATION MARK
     22 |  00000022 | QUOTATION MARK
     23 |  00000023 | NUMBER SIGN
     24 |  00000024 | DOLLAR SIGN
     25 |  00000025 | PERCENT SIGN
     26 |  00000026 | AMPERSAND
     27 |  00000027 | APOSTROPHE
     28 |  00000028 | LEFT PARENTHESIS
     29 |  00000029 | RIGHT PARENTHESIS
     2A |  0000002A | ASTERISK
     2B |  0000002B | PLUS SIGN
     2C |  0000002C | COMMA
     2D |  0000002D | HYPHEN-MINUS
     2E |  0000002E | FULL STOP
     2F |  0000002F | SOLIDUS
     30 |  00000030 | DIGIT ZERO
     31 |  00000031 | DIGIT ONE
     32 |  00000032 | DIGIT TWO
     33 |  00000033 | DIGIT THREE
     34 |  00000034 | DIGIT FOUR
     35 |  00000035 | DIGIT FIVE
     36 |  00000036 | DIGIT SIX
     37 |  00000037 | DIGIT SEVEN
     38 |  00000038 | DIGIT EIGHT
     39 |  00000039 | DIGIT NINE
     3A |  0000003A | COLON
     3B |  0000003B | SEMICOLON
     3C |  0000003C | LESS-THAN SIGN
     3D |  0000003D | EQUALS SIGN
     3E |  0000003E | GREATER-THAN SIGN
     3F |  0000003F | QUESTION MARK
     40 |  0000E018 | Unit space A E<lt>ISO-IR-8-1_40E<gt>
     41 |  00000041 | LATIN CAPITAL LETTER A
     42 |  00000042 | LATIN CAPITAL LETTER B
     43 |  00000043 | LATIN CAPITAL LETTER C
     44 |  00000044 | LATIN CAPITAL LETTER D
     45 |  00000045 | LATIN CAPITAL LETTER E
     46 |  00000046 | LATIN CAPITAL LETTER F
     47 |  00000047 | LATIN CAPITAL LETTER G
     48 |  00000048 | LATIN CAPITAL LETTER H
     49 |  00000049 | LATIN CAPITAL LETTER I
     4A |  0000004A | LATIN CAPITAL LETTER J
     4B |  0000004B | LATIN CAPITAL LETTER K
     4C |  0000004C | LATIN CAPITAL LETTER L
     4D |  0000004D | LATIN CAPITAL LETTER M
     4E |  0000004E | LATIN CAPITAL LETTER N
     4F |  0000004F | LATIN CAPITAL LETTER O
     50 |  00000050 | LATIN CAPITAL LETTER P
     51 |  00000051 | LATIN CAPITAL LETTER Q
     52 |  00000052 | LATIN CAPITAL LETTER R
     53 |  00000053 | LATIN CAPITAL LETTER S
     54 |  00000054 | LATIN CAPITAL LETTER T
     55 |  00000055 | LATIN CAPITAL LETTER U
     56 |  00000056 | LATIN CAPITAL LETTER V
     57 |  00000057 | LATIN CAPITAL LETTER W
     58 |  00000058 | LATIN CAPITAL LETTER X
     59 |  00000059 | LATIN CAPITAL LETTER Y
     5A |  0000005A | LATIN CAPITAL LETTER Z
     5B |  000000C4 | LATIN CAPITAL LETTER A WITH DIAERESIS
     5C |  000000D6 | LATIN CAPITAL LETTER O WITH DIAERESIS
     5D |  000000C5 | LATIN CAPITAL LETTER A WITH RING ABOVE
     5E |  000025A0 | BLACK SQUARE
     5F |  0000005F | LOW LINE
     60 |  0000E019 | Unit space B E<lt>ISO-IR-8-1_60E<gt>
     61 |  00000061 | LATIN SMALL LETTER A
     62 |  00000062 | LATIN SMALL LETTER B
     63 |  00000063 | LATIN SMALL LETTER C
     64 |  00000064 | LATIN SMALL LETTER D
     65 |  00000065 | LATIN SMALL LETTER E
     66 |  00000066 | LATIN SMALL LETTER F
     67 |  00000067 | LATIN SMALL LETTER G
     68 |  00000068 | LATIN SMALL LETTER H
     69 |  00000069 | LATIN SMALL LETTER I
     6A |  0000006A | LATIN SMALL LETTER J
     6B |  0000006B | LATIN SMALL LETTER K
     6C |  0000006C | LATIN SMALL LETTER L
     6D |  0000006D | LATIN SMALL LETTER M
     6E |  0000006E | LATIN SMALL LETTER N
     6F |  0000006F | LATIN SMALL LETTER O
     70 |  00000070 | LATIN SMALL LETTER P
     71 |  00000071 | LATIN SMALL LETTER Q
     72 |  00000072 | LATIN SMALL LETTER R
     73 |  00000073 | LATIN SMALL LETTER S
     74 |  00000074 | LATIN SMALL LETTER T
     75 |  00000075 | LATIN SMALL LETTER U
     76 |  00000076 | LATIN SMALL LETTER V
     77 |  00000077 | LATIN SMALL LETTER W
     78 |  00000078 | LATIN SMALL LETTER X
     79 |  00000079 | LATIN SMALL LETTER Y
     7A |  0000007A | LATIN SMALL LETTER Z
     7B |  000000E4 | LATIN SMALL LETTER A WITH DIAERESIS
     7C |  000000F6 | LATIN SMALL LETTER O WITH DIAERESIS
     7D |  000000E5 | LATIN SMALL LETTER A WITH RING ABOVE
     7E |  00002013 | EN DASH
     7F |  0000007F | DELETE (DEL)
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/NEXTSTEP.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for NEXTSTEP.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::NEXTSTEP;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x0004,
     0x0005,
     0x0006,
     0x0007,
     0x0008,
     0x0009,
     0x000a,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x0014,
     0x0015,
     0x0016,
     0x0017,
     0x0018,
     0x0019,
     0x001a,
     0x001b,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0020,
     0x0021,
     0x0022,
     0x0023,
     0x0024,
     0x0025,
     0x0026,
     0x0027,
     0x0028,
     0x0029,
     0x002a,
     0x002b,
     0x002c,
     0x002d,
     0x002e,
     0x002f,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x003a,
     0x003b,
     0x003c,
     0x003d,
     0x003e,
     0x003f,
     0x0040,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x005b,
     0x005c,
     0x005d,
     0x005e,
     0x005f,
     0x0060,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x007b,
     0x007c,
     0x007d,
     0x007e,
     0x007f,
     0x00a0,
     0x00c0,
     0x00c1,
     0x00c2,
     0x00c3,
     0x00c4,
     0x00c5,
     0x00c7,
     0x00c8,
     0x00c9,
     0x00ca,
     0x00cb,
     0x00cc,
     0x00cd,
     0x00ce,
     0x00cf,
     0x00d0,
     0x00d1,
     0x00d2,
     0x00d3,
     0x00d4,
     0x00d5,
     0x00d6,
     0x00d9,
     0x00da,
     0x00db,
     0x00dc,
     0x00dd,
     0x00de,
     0x00b5,
     0x00d7,
     0x00f7,
     0x00a9,
     0x00a1,
     0x00a2,
     0x00a3,
     0x2044,
     0x00a5,
     0x0192,
     0x00a7,
     0x00a4,
     0x2019,
     0x201c,
     0x00ab,
     0x2039,
     0x203a,
     0xfb01,
     0xfb02,
     0x00ae,
     0x2013,
     0x2020,
     0x2021,
     0x00b7,
     0x00a6,
     0x00b6,
     0x2022,
     0x201a,
     0x201e,
     0x201d,
     0x00bb,
     0x2026,
     0x2030,
     0x00ac,
     0x00bf,
     0x00b9,
     0x02cb,
     0x00b4,
     0x02c6,
     0x02dc,
     0x00af,
     0x02d8,
     0x02d9,
     0x00a8,
     0x00b2,
     0x02da,
     0x00b8,
     0x00b3,
     0x02dd,
     0x02db,
     0x02c7,
     0x2014,
     0x00b1,
     0x00bc,
     0x00bd,
     0x00be,
     0x00e0,
     0x00e1,
     0x00e2,
     0x00e3,
     0x00e4,
     0x00e5,
     0x00e7,
     0x00e8,
     0x00e9,
     0x00ea,
     0x00eb,
     0x00ec,
     0x00c6,
     0x00ed,
     0x00aa,
     0x00ee,
     0x00ef,
     0x00f0,
     0x00f1,
     0x0141,
     0x00d8,
     0x0152,
     0x00ba,
     0x00f2,
     0x00f3,
     0x00f4,
     0x00f5,
     0x00f6,
     0x00e6,
     0x00f9,
     0x00fa,
     0x00fb,
     0x0131,
     0x00fc,
     0x00fd,
     0x0142,
     0x00f8,
     0x0153,
     0x00df,
     0x00fe,
     0x00ff,
     0xfffd,
     0xfffd,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\x04",
     "\x05",
     "\x06",
     "\x07",
     "\x08",
     "\x09",
     "\x0a",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\x14",
     "\x15",
     "\x16",
     "\x17",
     "\x18",
     "\x19",
     "\x1a",
     "\x1b",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\x20",
     "\x21",
     "\x22",
     "\x23",
     "\x24",
     "\x25",
     "\x26",
     "\x27",
     "\x28",
     "\x29",
     "\x2a",
     "\x2b",
     "\x2c",
     "\x2d",
     "\x2e",
     "\x2f",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\x3a",
     "\x3b",
     "\x3c",
     "\x3d",
     "\x3e",
     "\x3f",
     "\x40",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\x5b",
     "\x5c",
     "\x5d",
     "\x5e",
     "\x5f",
     "\x60",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\x7b",
     "\x7c",
     "\x7d",
     "\x7e",
     "\x7f",
     "\xc2\xa0",
     "\xc3\x80",
     "\xc3\x81",
     "\xc3\x82",
     "\xc3\x83",
     "\xc3\x84",
     "\xc3\x85",
     "\xc3\x87",
     "\xc3\x88",
     "\xc3\x89",
     "\xc3\x8a",
     "\xc3\x8b",
     "\xc3\x8c",
     "\xc3\x8d",
     "\xc3\x8e",
     "\xc3\x8f",
     "\xc3\x90",
     "\xc3\x91",
     "\xc3\x92",
     "\xc3\x93",
     "\xc3\x94",
     "\xc3\x95",
     "\xc3\x96",
     "\xc3\x99",
     "\xc3\x9a",
     "\xc3\x9b",
     "\xc3\x9c",
     "\xc3\x9d",
     "\xc3\x9e",
     "\xc2\xb5",
     "\xc3\x97",
     "\xc3\xb7",
     "\xc2\xa9",
     "\xc2\xa1",
     "\xc2\xa2",
     "\xc2\xa3",
     "\xe2\x81\x84",
     "\xc2\xa5",
     "\xc6\x92",
     "\xc2\xa7",
     "\xc2\xa4",
     "\xe2\x80\x99",
     "\xe2\x80\x9c",
     "\xc2\xab",
     "\xe2\x80\xb9",
     "\xe2\x80\xba",
     "\xef\xac\x81",
     "\xef\xac\x82",
     "\xc2\xae",
     "\xe2\x80\x93",
     "\xe2\x80\xa0",
     "\xe2\x80\xa1",
     "\xc2\xb7",
     "\xc2\xa6",
     "\xc2\xb6",
     "\xe2\x80\xa2",
     "\xe2\x80\x9a",
     "\xe2\x80\x9e",
     "\xe2\x80\x9d",
     "\xc2\xbb",
     "\xe2\x80\xa6",
     "\xe2\x80\xb0",
     "\xc2\xac",
     "\xc2\xbf",
     "\xc2\xb9",
     "\xcb\x8b",
     "\xc2\xb4",
     "\xcb\x86",
     "\xcb\x9c",
     "\xc2\xaf",
     "\xcb\x98",
     "\xcb\x99",
     "\xc2\xa8",
     "\xc2\xb2",
     "\xcb\x9a",
     "\xc2\xb8",
     "\xc2\xb3",
     "\xcb\x9d",
     "\xcb\x9b",
     "\xcb\x87",
     "\xe2\x80\x94",
     "\xc2\xb1",
     "\xc2\xbc",
     "\xc2\xbd",
     "\xc2\xbe",
     "\xc3\xa0",
     "\xc3\xa1",
     "\xc3\xa2",
     "\xc3\xa3",
     "\xc3\xa4",
     "\xc3\xa5",
     "\xc3\xa7",
     "\xc3\xa8",
     "\xc3\xa9",
     "\xc3\xaa",
     "\xc3\xab",
     "\xc3\xac",
     "\xc3\x86",
     "\xc3\xad",
     "\xc2\xaa",
     "\xc3\xae",
     "\xc3\xaf",
     "\xc3\xb0",
     "\xc3\xb1",
     "\xc5\x81",
     "\xc3\x98",
     "\xc5\x92",
     "\xc2\xba",
     "\xc3\xb2",
     "\xc3\xb3",
     "\xc3\xb4",
     "\xc3\xb5",
     "\xc3\xb6",
     "\xc3\xa6",
     "\xc3\xb9",
     "\xc3\xba",
     "\xc3\xbb",
     "\xc4\xb1",
     "\xc3\xbc",
     "\xc3\xbd",
     "\xc5\x82",
     "\xc3\xb8",
     "\xc5\x93",
     "\xc3\x9f",
     "\xc3\xbe",
     "\xc3\xbf",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x04",
     0x00000005 => "\x05",
     0x00000006 => "\x06",
     0x00000007 => "\x07",
     0x00000008 => "\x08",
     0x00000009 => "\x09",
     0x0000000a => "\x0a",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x14",
     0x00000015 => "\x15",
     0x00000016 => "\x16",
     0x00000017 => "\x17",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x1a",
     0x0000001b => "\x1b",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x20",
     0x00000021 => "\x21",
     0x00000022 => "\x22",
     0x00000023 => "\x23",
     0x00000024 => "\x24",
     0x00000025 => "\x25",
     0x00000026 => "\x26",
     0x00000027 => "\x27",
     0x00000028 => "\x28",
     0x00000029 => "\x29",
     0x0000002a => "\x2a",
     0x0000002b => "\x2b",
     0x0000002c => "\x2c",
     0x0000002d => "\x2d",
     0x0000002e => "\x2e",
     0x0000002f => "\x2f",
     0x00000030 => "\x30",
     0x00000031 => "\x31",
     0x00000032 => "\x32",
     0x00000033 => "\x33",
     0x00000034 => "\x34",
     0x00000035 => "\x35",
     0x00000036 => "\x36",
     0x00000037 => "\x37",
     0x00000038 => "\x38",
     0x00000039 => "\x39",
     0x0000003a => "\x3a",
     0x0000003b => "\x3b",
     0x0000003c => "\x3c",
     0x0000003d => "\x3d",
     0x0000003e => "\x3e",
     0x0000003f => "\x3f",
     0x00000040 => "\x40",
     0x00000041 => "\x41",
     0x00000042 => "\x42",
     0x00000043 => "\x43",
     0x00000044 => "\x44",
     0x00000045 => "\x45",
     0x00000046 => "\x46",
     0x00000047 => "\x47",
     0x00000048 => "\x48",
     0x00000049 => "\x49",
     0x0000004a => "\x4a",
     0x0000004b => "\x4b",
     0x0000004c => "\x4c",
     0x0000004d => "\x4d",
     0x0000004e => "\x4e",
     0x0000004f => "\x4f",
     0x00000050 => "\x50",
     0x00000051 => "\x51",
     0x00000052 => "\x52",
     0x00000053 => "\x53",
     0x00000054 => "\x54",
     0x00000055 => "\x55",
     0x00000056 => "\x56",
     0x00000057 => "\x57",
     0x00000058 => "\x58",
     0x00000059 => "\x59",
     0x0000005a => "\x5a",
     0x0000005b => "\x5b",
     0x0000005c => "\x5c",
     0x0000005d => "\x5d",
     0x0000005e => "\x5e",
     0x0000005f => "\x5f",
     0x00000060 => "\x60",
     0x00000061 => "\x61",
     0x00000062 => "\x62",
     0x00000063 => "\x63",
     0x00000064 => "\x64",
     0x00000065 => "\x65",
     0x00000066 => "\x66",
     0x00000067 => "\x67",
     0x00000068 => "\x68",
     0x00000069 => "\x69",
     0x0000006a => "\x6a",
     0x0000006b => "\x6b",
     0x0000006c => "\x6c",
     0x0000006d => "\x6d",
     0x0000006e => "\x6e",
     0x0000006f => "\x6f",
     0x00000070 => "\x70",
     0x00000071 => "\x71",
     0x00000072 => "\x72",
     0x00000073 => "\x73",
     0x00000074 => "\x74",
     0x00000075 => "\x75",
     0x00000076 => "\x76",
     0x00000077 => "\x77",
     0x00000078 => "\x78",
     0x00000079 => "\x79",
     0x0000007a => "\x7a",
     0x0000007b => "\x7b",
     0x0000007c => "\x7c",
     0x0000007d => "\x7d",
     0x0000007e => "\x7e",
     0x0000007f => "\x7f",
     0x000000a0 => "\x80",
     0x000000a1 => "\xa1",
     0x000000a2 => "\xa2",
     0x000000a3 => "\xa3",
     0x000000a4 => "\xa8",
     0x000000a5 => "\xa5",
     0x000000a6 => "\xb5",
     0x000000a7 => "\xa7",
     0x000000a8 => "\xc8",
     0x000000a9 => "\xa0",
     0x000000aa => "\xe3",
     0x000000ab => "\xab",
     0x000000ac => "\xbe",
     0x000000ae => "\xb0",
     0x000000af => "\xc5",
     0x000000b1 => "\xd1",
     0x000000b2 => "\xc9",
     0x000000b3 => "\xcc",
     0x000000b4 => "\xc2",
     0x000000b5 => "\x9d",
     0x000000b6 => "\xb6",
     0x000000b7 => "\xb4",
     0x000000b8 => "\xcb",
     0x000000b9 => "\xc0",
     0x000000ba => "\xeb",
     0x000000bb => "\xbb",
     0x000000bc => "\xd2",
     0x000000bd => "\xd3",
     0x000000be => "\xd4",
     0x000000bf => "\xbf",
     0x000000c0 => "\x81",
     0x000000c1 => "\x82",
     0x000000c2 => "\x83",
     0x000000c3 => "\x84",
     0x000000c4 => "\x85",
     0x000000c5 => "\x86",
     0x000000c6 => "\xe1",
     0x000000c7 => "\x87",
     0x000000c8 => "\x88",
     0x000000c9 => "\x89",
     0x000000ca => "\x8a",
     0x000000cb => "\x8b",
     0x000000cc => "\x8c",
     0x000000cd => "\x8d",
     0x000000ce => "\x8e",
     0x000000cf => "\x8f",
     0x000000d0 => "\x90",
     0x000000d1 => "\x91",
     0x000000d2 => "\x92",
     0x000000d3 => "\x93",
     0x000000d4 => "\x94",
     0x000000d5 => "\x95",
     0x000000d6 => "\x96",
     0x000000d7 => "\x9e",
     0x000000d8 => "\xe9",
     0x000000d9 => "\x97",
     0x000000da => "\x98",
     0x000000db => "\x99",
     0x000000dc => "\x9a",
     0x000000dd => "\x9b",
     0x000000de => "\x9c",
     0x000000df => "\xfb",
     0x000000e0 => "\xd5",
     0x000000e1 => "\xd6",
     0x000000e2 => "\xd7",
     0x000000e3 => "\xd8",
     0x000000e4 => "\xd9",
     0x000000e5 => "\xda",
     0x000000e6 => "\xf1",
     0x000000e7 => "\xdb",
     0x000000e8 => "\xdc",
     0x000000e9 => "\xdd",
     0x000000ea => "\xde",
     0x000000eb => "\xdf",
     0x000000ec => "\xe0",
     0x000000ed => "\xe2",
     0x000000ee => "\xe4",
     0x000000ef => "\xe5",
     0x000000f0 => "\xe6",
     0x000000f1 => "\xe7",
     0x000000f2 => "\xec",
     0x000000f3 => "\xed",
     0x000000f4 => "\xee",
     0x000000f5 => "\xef",
     0x000000f6 => "\xf0",
     0x000000f7 => "\x9f",
     0x000000f8 => "\xf9",
     0x000000f9 => "\xf2",
     0x000000fa => "\xf3",
     0x000000fb => "\xf4",
     0x000000fc => "\xf6",
     0x000000fd => "\xf7",
     0x000000fe => "\xfc",
     0x000000ff => "\xfd",
     0x00000131 => "\xf5",
     0x00000141 => "\xe8",
     0x00000142 => "\xf8",
     0x00000152 => "\xea",
     0x00000153 => "\xfa",
     0x00000192 => "\xa6",
     0x000002c6 => "\xc3",
     0x000002c7 => "\xcf",
     0x000002cb => "\xc1",
     0x000002d8 => "\xc6",
     0x000002d9 => "\xc7",
     0x000002da => "\xca",
     0x000002db => "\xce",
     0x000002dc => "\xc4",
     0x000002dd => "\xcd",
     0x00002013 => "\xb1",
     0x00002014 => "\xd0",
     0x00002019 => "\xa9",
     0x0000201a => "\xb8",
     0x0000201c => "\xaa",
     0x0000201d => "\xba",
     0x0000201e => "\xb9",
     0x00002020 => "\xb2",
     0x00002021 => "\xb3",
     0x00002022 => "\xb7",
     0x00002026 => "\xbc",
     0x00002030 => "\xbd",
     0x00002039 => "\xac",
     0x0000203a => "\xad",
     0x00002044 => "\xa4",
     0x0000fb01 => "\xae",
     0x0000fb02 => "\xaf",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::NEXTSTEP - Conversion routines for NEXTSTEP
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for NEXTSTEP.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
 
  This charmap has been generated automatically from GNU libiconv
  conversions.
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  00000004 | END OF TRANSMISSION (EOT)
     05 |  00000005 | ENQUIRY (ENQ)
     06 |  00000006 | ACKNOWLEDGE (ACK)
     07 |  00000007 | BELL (BEL)
     08 |  00000008 | BACKSPACE (BS)
     09 |  00000009 | CHARACTER TABULATION (HT)
     0A |  0000000A | LINE FEED (LF)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  00000014 | DEVICE CONTROL FOUR (DC4)
     15 |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     16 |  00000016 | SYNCHRONOUS IDLE (SYN)
     17 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  0000001A | SUBSTITUTE (SUB)
     1B |  0000001B | ESCAPE (ESC)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000020 | SPACE
     21 |  00000021 | EXCLAMATION MARK
     22 |  00000022 | QUOTATION MARK
     23 |  00000023 | NUMBER SIGN
     24 |  00000024 | DOLLAR SIGN
     25 |  00000025 | PERCENT SIGN
     26 |  00000026 | AMPERSAND
     27 |  00000027 | APOSTROPHE
     28 |  00000028 | LEFT PARENTHESIS
     29 |  00000029 | RIGHT PARENTHESIS
     2A |  0000002A | ASTERISK
     2B |  0000002B | PLUS SIGN
     2C |  0000002C | COMMA
     2D |  0000002D | HYPHEN-MINUS
     2E |  0000002E | FULL STOP
     2F |  0000002F | SOLIDUS
     30 |  00000030 | DIGIT ZERO
     31 |  00000031 | DIGIT ONE
     32 |  00000032 | DIGIT TWO
     33 |  00000033 | DIGIT THREE
     34 |  00000034 | DIGIT FOUR
     35 |  00000035 | DIGIT FIVE
     36 |  00000036 | DIGIT SIX
     37 |  00000037 | DIGIT SEVEN
     38 |  00000038 | DIGIT EIGHT
     39 |  00000039 | DIGIT NINE
     3A |  0000003A | COLON
     3B |  0000003B | SEMICOLON
     3C |  0000003C | LESS-THAN SIGN
     3D |  0000003D | EQUALS SIGN
     3E |  0000003E | GREATER-THAN SIGN
     3F |  0000003F | QUESTION MARK
     40 |  00000040 | COMMERCIAL AT
     41 |  00000041 | LATIN CAPITAL LETTER A
     42 |  00000042 | LATIN CAPITAL LETTER B
     43 |  00000043 | LATIN CAPITAL LETTER C
     44 |  00000044 | LATIN CAPITAL LETTER D
     45 |  00000045 | LATIN CAPITAL LETTER E
     46 |  00000046 | LATIN CAPITAL LETTER F
     47 |  00000047 | LATIN CAPITAL LETTER G
     48 |  00000048 | LATIN CAPITAL LETTER H
     49 |  00000049 | LATIN CAPITAL LETTER I
     4A |  0000004A | LATIN CAPITAL LETTER J
     4B |  0000004B | LATIN CAPITAL LETTER K
     4C |  0000004C | LATIN CAPITAL LETTER L
     4D |  0000004D | LATIN CAPITAL LETTER M
     4E |  0000004E | LATIN CAPITAL LETTER N
     4F |  0000004F | LATIN CAPITAL LETTER O
     50 |  00000050 | LATIN CAPITAL LETTER P
     51 |  00000051 | LATIN CAPITAL LETTER Q
     52 |  00000052 | LATIN CAPITAL LETTER R
     53 |  00000053 | LATIN CAPITAL LETTER S
     54 |  00000054 | LATIN CAPITAL LETTER T
     55 |  00000055 | LATIN CAPITAL LETTER U
     56 |  00000056 | LATIN CAPITAL LETTER V
     57 |  00000057 | LATIN CAPITAL LETTER W
     58 |  00000058 | LATIN CAPITAL LETTER X
     59 |  00000059 | LATIN CAPITAL LETTER Y
     5A |  0000005A | LATIN CAPITAL LETTER Z
     5B |  0000005B | LEFT SQUARE BRACKET
     5C |  0000005C | REVERSE SOLIDUS
     5D |  0000005D | RIGHT SQUARE BRACKET
     5E |  0000005E | CIRCUMFLEX ACCENT
     5F |  0000005F | LOW LINE
     60 |  00000060 | GRAVE ACCENT
     61 |  00000061 | LATIN SMALL LETTER A
     62 |  00000062 | LATIN SMALL LETTER B
     63 |  00000063 | LATIN SMALL LETTER C
     64 |  00000064 | LATIN SMALL LETTER D
     65 |  00000065 | LATIN SMALL LETTER E
     66 |  00000066 | LATIN SMALL LETTER F
     67 |  00000067 | LATIN SMALL LETTER G
     68 |  00000068 | LATIN SMALL LETTER H
     69 |  00000069 | LATIN SMALL LETTER I
     6A |  0000006A | LATIN SMALL LETTER J
     6B |  0000006B | LATIN SMALL LETTER K
     6C |  0000006C | LATIN SMALL LETTER L
     6D |  0000006D | LATIN SMALL LETTER M
     6E |  0000006E | LATIN SMALL LETTER N
     6F |  0000006F | LATIN SMALL LETTER O
     70 |  00000070 | LATIN SMALL LETTER P
     71 |  00000071 | LATIN SMALL LETTER Q
     72 |  00000072 | LATIN SMALL LETTER R
     73 |  00000073 | LATIN SMALL LETTER S
     74 |  00000074 | LATIN SMALL LETTER T
     75 |  00000075 | LATIN SMALL LETTER U
     76 |  00000076 | LATIN SMALL LETTER V
     77 |  00000077 | LATIN SMALL LETTER W
     78 |  00000078 | LATIN SMALL LETTER X
     79 |  00000079 | LATIN SMALL LETTER Y
     7A |  0000007A | LATIN SMALL LETTER Z
     7B |  0000007B | LEFT CURLY BRACKET
     7C |  0000007C | VERTICAL LINE
     7D |  0000007D | RIGHT CURLY BRACKET
     7E |  0000007E | TILDE
     7F |  0000007F | DELETE (DEL)
     80 |  000000A0 | NO-BREAK SPACE
     81 |  000000C0 | LATIN CAPITAL LETTER A WITH GRAVE
     82 |  000000C1 | LATIN CAPITAL LETTER A WITH ACUTE
     83 |  000000C2 | LATIN CAPITAL LETTER A WITH CIRCUMFLEX
     84 |  000000C3 | LATIN CAPITAL LETTER A WITH TILDE
     85 |  000000C4 | LATIN CAPITAL LETTER A WITH DIAERESIS
     86 |  000000C5 | LATIN CAPITAL LETTER A WITH RING ABOVE
     87 |  000000C7 | LATIN CAPITAL LETTER C WITH CEDILLA
     88 |  000000C8 | LATIN CAPITAL LETTER E WITH GRAVE
     89 |  000000C9 | LATIN CAPITAL LETTER E WITH ACUTE
     8A |  000000CA | LATIN CAPITAL LETTER E WITH CIRCUMFLEX
     8B |  000000CB | LATIN CAPITAL LETTER E WITH DIAERESIS
     8C |  000000CC | LATIN CAPITAL LETTER I WITH GRAVE
     8D |  000000CD | LATIN CAPITAL LETTER I WITH ACUTE
     8E |  000000CE | LATIN CAPITAL LETTER I WITH CIRCUMFLEX
     8F |  000000CF | LATIN CAPITAL LETTER I WITH DIAERESIS
     90 |  000000D0 | LATIN CAPITAL LETTER ETH
     91 |  000000D1 | LATIN CAPITAL LETTER N WITH TILDE
     92 |  000000D2 | LATIN CAPITAL LETTER O WITH GRAVE
     93 |  000000D3 | LATIN CAPITAL LETTER O WITH ACUTE
     94 |  000000D4 | LATIN CAPITAL LETTER O WITH CIRCUMFLEX
     95 |  000000D5 | LATIN CAPITAL LETTER O WITH TILDE
     96 |  000000D6 | LATIN CAPITAL LETTER O WITH DIAERESIS
     97 |  000000D9 | LATIN CAPITAL LETTER U WITH GRAVE
     98 |  000000DA | LATIN CAPITAL LETTER U WITH ACUTE
     99 |  000000DB | LATIN CAPITAL LETTER U WITH CIRCUMFLEX
     9A |  000000DC | LATIN CAPITAL LETTER U WITH DIAERESIS
     9B |  000000DD | LATIN CAPITAL LETTER Y WITH ACUTE
     9C |  000000DE | LATIN CAPITAL LETTER THORN
     9D |  000000B5 | MICRO SIGN
     9E |  000000D7 | MULTIPLICATION SIGN
     9F |  000000F7 | DIVISION SIGN
     A0 |  000000A9 | COPYRIGHT SIGN
     A1 |  000000A1 | INVERTED EXCLAMATION MARK
     A2 |  000000A2 | CENT SIGN
     A3 |  000000A3 | POUND SIGN
     A4 |  00002044 | FRACTION SLASH
     A5 |  000000A5 | YEN SIGN
     A6 |  00000192 | LATIN SMALL LETTER F WITH HOOK
     A7 |  000000A7 | SECTION SIGN
     A8 |  000000A4 | CURRENCY SIGN
     A9 |  00002019 | RIGHT SINGLE QUOTATION MARK
     AA |  0000201C | LEFT DOUBLE QUOTATION MARK
     AB |  000000AB | LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
     AC |  00002039 | SINGLE LEFT-POINTING ANGLE QUOTATION MARK
     AD |  0000203A | SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
     AE |  0000FB01 | LATIN SMALL LIGATURE FI
     AF |  0000FB02 | LATIN SMALL LIGATURE FL
     B0 |  000000AE | REGISTERED SIGN
     B1 |  00002013 | EN DASH
     B2 |  00002020 | DAGGER
     B3 |  00002021 | DOUBLE DAGGER
     B4 |  000000B7 | MIDDLE DOT
     B5 |  000000A6 | BROKEN BAR
     B6 |  000000B6 | PILCROW SIGN
     B7 |  00002022 | BULLET
     B8 |  0000201A | SINGLE LOW-9 QUOTATION MARK
     B9 |  0000201E | DOUBLE LOW-9 QUOTATION MARK
     BA |  0000201D | RIGHT DOUBLE QUOTATION MARK
     BB |  000000BB | RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
     BC |  00002026 | HORIZONTAL ELLIPSIS
     BD |  00002030 | PER MILLE SIGN
     BE |  000000AC | NOT SIGN
     BF |  000000BF | INVERTED QUESTION MARK
     C0 |  000000B9 | SUPERSCRIPT ONE
     C1 |  000002CB | MODIFIER LETTER GRAVE ACCENT
     C2 |  000000B4 | ACUTE ACCENT
     C3 |  000002C6 | MODIFIER LETTER CIRCUMFLEX ACCENT
     C4 |  000002DC | SMALL TILDE
     C5 |  000000AF | MACRON
     C6 |  000002D8 | BREVE
     C7 |  000002D9 | DOT ABOVE
     C8 |  000000A8 | DIAERESIS
     C9 |  000000B2 | SUPERSCRIPT TWO
     CA |  000002DA | RING ABOVE
     CB |  000000B8 | CEDILLA
     CC |  000000B3 | SUPERSCRIPT THREE
     CD |  000002DD | DOUBLE ACUTE ACCENT
     CE |  000002DB | OGONEK
     CF |  000002C7 | CARON
     D0 |  00002014 | EM DASH
     D1 |  000000B1 | PLUS-MINUS SIGN
     D2 |  000000BC | VULGAR FRACTION ONE QUARTER
     D3 |  000000BD | VULGAR FRACTION ONE HALF
     D4 |  000000BE | VULGAR FRACTION THREE QUARTERS
     D5 |  000000E0 | LATIN SMALL LETTER A WITH GRAVE
     D6 |  000000E1 | LATIN SMALL LETTER A WITH ACUTE
     D7 |  000000E2 | LATIN SMALL LETTER A WITH CIRCUMFLEX
     D8 |  000000E3 | LATIN SMALL LETTER A WITH TILDE
     D9 |  000000E4 | LATIN SMALL LETTER A WITH DIAERESIS
     DA |  000000E5 | LATIN SMALL LETTER A WITH RING ABOVE
     DB |  000000E7 | LATIN SMALL LETTER C WITH CEDILLA
     DC |  000000E8 | LATIN SMALL LETTER E WITH GRAVE
     DD |  000000E9 | LATIN SMALL LETTER E WITH ACUTE
     DE |  000000EA | LATIN SMALL LETTER E WITH CIRCUMFLEX
     DF |  000000EB | LATIN SMALL LETTER E WITH DIAERESIS
     E0 |  000000EC | LATIN SMALL LETTER I WITH GRAVE
     E1 |  000000C6 | LATIN CAPITAL LETTER AE
     E2 |  000000ED | LATIN SMALL LETTER I WITH ACUTE
     E3 |  000000AA | FEMININE ORDINAL INDICATOR
     E4 |  000000EE | LATIN SMALL LETTER I WITH CIRCUMFLEX
     E5 |  000000EF | LATIN SMALL LETTER I WITH DIAERESIS
     E6 |  000000F0 | LATIN SMALL LETTER ETH
     E7 |  000000F1 | LATIN SMALL LETTER N WITH TILDE
     E8 |  00000141 | LATIN CAPITAL LETTER L WITH STROKE
     E9 |  000000D8 | LATIN CAPITAL LETTER O WITH STROKE
     EA |  00000152 | LATIN CAPITAL LIGATURE OE
     EB |  000000BA | MASCULINE ORDINAL INDICATOR
     EC |  000000F2 | LATIN SMALL LETTER O WITH GRAVE
     ED |  000000F3 | LATIN SMALL LETTER O WITH ACUTE
     EE |  000000F4 | LATIN SMALL LETTER O WITH CIRCUMFLEX
     EF |  000000F5 | LATIN SMALL LETTER O WITH TILDE
     F0 |  000000F6 | LATIN SMALL LETTER O WITH DIAERESIS
     F1 |  000000E6 | LATIN SMALL LETTER AE
     F2 |  000000F9 | LATIN SMALL LETTER U WITH GRAVE
     F3 |  000000FA | LATIN SMALL LETTER U WITH ACUTE
     F4 |  000000FB | LATIN SMALL LETTER U WITH CIRCUMFLEX
     F5 |  00000131 | LATIN SMALL LETTER DOTLESS I
     F6 |  000000FC | LATIN SMALL LETTER U WITH DIAERESIS
     F7 |  000000FD | LATIN SMALL LETTER Y WITH ACUTE
     F8 |  00000142 | LATIN SMALL LETTER L WITH STROKE
     F9 |  000000F8 | LATIN SMALL LETTER O WITH STROKE
     FA |  00000153 | LATIN SMALL LIGATURE OE
     FB |  000000DF | LATIN SMALL LETTER SHARP S
     FC |  000000FE | LATIN SMALL LETTER THORN
     FD |  000000FF | LATIN SMALL LETTER Y WITH DIAERESIS
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/SAMI_WS2.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for WIN-SAMI-2.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::SAMI_WS2;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x0004,
     0x0005,
     0x0006,
     0x0007,
     0x0008,
     0x0009,
     0x000a,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x0014,
     0x0015,
     0x0016,
     0x0017,
     0x0018,
     0x0019,
     0x001a,
     0x001b,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0020,
     0x0021,
     0x0022,
     0x0023,
     0x0024,
     0x0025,
     0x0026,
     0x0027,
     0x0028,
     0x0029,
     0x002a,
     0x002b,
     0x002c,
     0x002d,
     0x002e,
     0x002f,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x003a,
     0x003b,
     0x003c,
     0x003d,
     0x003e,
     0x003f,
     0x0040,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x005b,
     0x005c,
     0x005d,
     0x005e,
     0x005f,
     0x0060,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x007b,
     0x007c,
     0x007d,
     0x007e,
     0x007f,
     0x20ac,
     0xfffd,
     0x010c,
     0x0192,
     0x010d,
     0x01b7,
     0x0292,
     0x01ee,
     0x01ef,
     0x0110,
     0x0160,
     0x2039,
     0x0152,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x2018,
     0x2019,
     0x201c,
     0x201d,
     0x2022,
     0x2013,
     0x2014,
     0x0111,
     0x01e6,
     0x0161,
     0x203a,
     0x0153,
     0xfffd,
     0xfffd,
     0x0178,
     0x00a0,
     0x01e7,
     0x01e4,
     0x00a3,
     0x00a4,
     0x01e5,
     0x00a6,
     0x00a7,
     0x00a8,
     0x00a9,
     0x021e,
     0x00ab,
     0x00ac,
     0x00ad,
     0x00ae,
     0x021f,
     0x00b0,
     0x00b1,
     0x01e8,
     0x01e9,
     0x00b4,
     0x00b5,
     0x00b6,
     0x00b7,
     0x014a,
     0x014b,
     0x0166,
     0x00bb,
     0x0167,
     0x00bd,
     0x017d,
     0x017e,
     0x00c0,
     0x00c1,
     0x00c2,
     0x00c3,
     0x00c4,
     0x00c5,
     0x00c6,
     0x00c7,
     0x00c8,
     0x00c9,
     0x00ca,
     0x00cb,
     0x00cc,
     0x00cd,
     0x00ce,
     0x00cf,
     0x00d0,
     0x00d1,
     0x00d2,
     0x00d3,
     0x00d4,
     0x00d5,
     0x00d6,
     0x00d7,
     0x00d8,
     0x00d9,
     0x00da,
     0x00db,
     0x00dc,
     0x00dd,
     0x00de,
     0x00df,
     0x00e0,
     0x00e1,
     0x00e2,
     0x00e3,
     0x00e4,
     0x00e5,
     0x00e6,
     0x00e7,
     0x00e8,
     0x00e9,
     0x00ea,
     0x00eb,
     0x00ec,
     0x00ed,
     0x00ee,
     0x00ef,
     0x00f0,
     0x00f1,
     0x00f2,
     0x00f3,
     0x00f4,
     0x00f5,
     0x00f6,
     0x00f7,
     0x00f8,
     0x00f9,
     0x00fa,
     0x00fb,
     0x00fc,
     0x00fd,
     0x00fe,
     0x00ff,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\x04",
     "\x05",
     "\x06",
     "\x07",
     "\x08",
     "\x09",
     "\x0a",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\x14",
     "\x15",
     "\x16",
     "\x17",
     "\x18",
     "\x19",
     "\x1a",
     "\x1b",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\x20",
     "\x21",
     "\x22",
     "\x23",
     "\x24",
     "\x25",
     "\x26",
     "\x27",
     "\x28",
     "\x29",
     "\x2a",
     "\x2b",
     "\x2c",
     "\x2d",
     "\x2e",
     "\x2f",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\x3a",
     "\x3b",
     "\x3c",
     "\x3d",
     "\x3e",
     "\x3f",
     "\x40",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\x5b",
     "\x5c",
     "\x5d",
     "\x5e",
     "\x5f",
     "\x60",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\x7b",
     "\x7c",
     "\x7d",
     "\x7e",
     "\x7f",
     "\xe2\x82\xac",
     "\xef\xbf\xbd",
     "\xc4\x8c",
     "\xc6\x92",
     "\xc4\x8d",
     "\xc6\xb7",
     "\xca\x92",
     "\xc7\xae",
     "\xc7\xaf",
     "\xc4\x90",
     "\xc5\xa0",
     "\xe2\x80\xb9",
     "\xc5\x92",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xe2\x80\x98",
     "\xe2\x80\x99",
     "\xe2\x80\x9c",
     "\xe2\x80\x9d",
     "\xe2\x80\xa2",
     "\xe2\x80\x93",
     "\xe2\x80\x94",
     "\xc4\x91",
     "\xc7\xa6",
     "\xc5\xa1",
     "\xe2\x80\xba",
     "\xc5\x93",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xc5\xb8",
     "\xc2\xa0",
     "\xc7\xa7",
     "\xc7\xa4",
     "\xc2\xa3",
     "\xc2\xa4",
     "\xc7\xa5",
     "\xc2\xa6",
     "\xc2\xa7",
     "\xc2\xa8",
     "\xc2\xa9",
     "\xc8\x9e",
     "\xc2\xab",
     "\xc2\xac",
     "\xc2\xad",
     "\xc2\xae",
     "\xc8\x9f",
     "\xc2\xb0",
     "\xc2\xb1",
     "\xc7\xa8",
     "\xc7\xa9",
     "\xc2\xb4",
     "\xc2\xb5",
     "\xc2\xb6",
     "\xc2\xb7",
     "\xc5\x8a",
     "\xc5\x8b",
     "\xc5\xa6",
     "\xc2\xbb",
     "\xc5\xa7",
     "\xc2\xbd",
     "\xc5\xbd",
     "\xc5\xbe",
     "\xc3\x80",
     "\xc3\x81",
     "\xc3\x82",
     "\xc3\x83",
     "\xc3\x84",
     "\xc3\x85",
     "\xc3\x86",
     "\xc3\x87",
     "\xc3\x88",
     "\xc3\x89",
     "\xc3\x8a",
     "\xc3\x8b",
     "\xc3\x8c",
     "\xc3\x8d",
     "\xc3\x8e",
     "\xc3\x8f",
     "\xc3\x90",
     "\xc3\x91",
     "\xc3\x92",
     "\xc3\x93",
     "\xc3\x94",
     "\xc3\x95",
     "\xc3\x96",
     "\xc3\x97",
     "\xc3\x98",
     "\xc3\x99",
     "\xc3\x9a",
     "\xc3\x9b",
     "\xc3\x9c",
     "\xc3\x9d",
     "\xc3\x9e",
     "\xc3\x9f",
     "\xc3\xa0",
     "\xc3\xa1",
     "\xc3\xa2",
     "\xc3\xa3",
     "\xc3\xa4",
     "\xc3\xa5",
     "\xc3\xa6",
     "\xc3\xa7",
     "\xc3\xa8",
     "\xc3\xa9",
     "\xc3\xaa",
     "\xc3\xab",
     "\xc3\xac",
     "\xc3\xad",
     "\xc3\xae",
     "\xc3\xaf",
     "\xc3\xb0",
     "\xc3\xb1",
     "\xc3\xb2",
     "\xc3\xb3",
     "\xc3\xb4",
     "\xc3\xb5",
     "\xc3\xb6",
     "\xc3\xb7",
     "\xc3\xb8",
     "\xc3\xb9",
     "\xc3\xba",
     "\xc3\xbb",
     "\xc3\xbc",
     "\xc3\xbd",
     "\xc3\xbe",
     "\xc3\xbf",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x04",
     0x00000005 => "\x05",
     0x00000006 => "\x06",
     0x00000007 => "\x07",
     0x00000008 => "\x08",
     0x00000009 => "\x09",
     0x0000000a => "\x0a",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x14",
     0x00000015 => "\x15",
     0x00000016 => "\x16",
     0x00000017 => "\x17",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x1a",
     0x0000001b => "\x1b",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x20",
     0x00000021 => "\x21",
     0x00000022 => "\x22",
     0x00000023 => "\x23",
     0x00000024 => "\x24",
     0x00000025 => "\x25",
     0x00000026 => "\x26",
     0x00000027 => "\x27",
     0x00000028 => "\x28",
     0x00000029 => "\x29",
     0x0000002a => "\x2a",
     0x0000002b => "\x2b",
     0x0000002c => "\x2c",
     0x0000002d => "\x2d",
     0x0000002e => "\x2e",
     0x0000002f => "\x2f",
     0x00000030 => "\x30",
     0x00000031 => "\x31",
     0x00000032 => "\x32",
     0x00000033 => "\x33",
     0x00000034 => "\x34",
     0x00000035 => "\x35",
     0x00000036 => "\x36",
     0x00000037 => "\x37",
     0x00000038 => "\x38",
     0x00000039 => "\x39",
     0x0000003a => "\x3a",
     0x0000003b => "\x3b",
     0x0000003c => "\x3c",
     0x0000003d => "\x3d",
     0x0000003e => "\x3e",
     0x0000003f => "\x3f",
     0x00000040 => "\x40",
     0x00000041 => "\x41",
     0x00000042 => "\x42",
     0x00000043 => "\x43",
     0x00000044 => "\x44",
     0x00000045 => "\x45",
     0x00000046 => "\x46",
     0x00000047 => "\x47",
     0x00000048 => "\x48",
     0x00000049 => "\x49",
     0x0000004a => "\x4a",
     0x0000004b => "\x4b",
     0x0000004c => "\x4c",
     0x0000004d => "\x4d",
     0x0000004e => "\x4e",
     0x0000004f => "\x4f",
     0x00000050 => "\x50",
     0x00000051 => "\x51",
     0x00000052 => "\x52",
     0x00000053 => "\x53",
     0x00000054 => "\x54",
     0x00000055 => "\x55",
     0x00000056 => "\x56",
     0x00000057 => "\x57",
     0x00000058 => "\x58",
     0x00000059 => "\x59",
     0x0000005a => "\x5a",
     0x0000005b => "\x5b",
     0x0000005c => "\x5c",
     0x0000005d => "\x5d",
     0x0000005e => "\x5e",
     0x0000005f => "\x5f",
     0x00000060 => "\x60",
     0x00000061 => "\x61",
     0x00000062 => "\x62",
     0x00000063 => "\x63",
     0x00000064 => "\x64",
     0x00000065 => "\x65",
     0x00000066 => "\x66",
     0x00000067 => "\x67",
     0x00000068 => "\x68",
     0x00000069 => "\x69",
     0x0000006a => "\x6a",
     0x0000006b => "\x6b",
     0x0000006c => "\x6c",
     0x0000006d => "\x6d",
     0x0000006e => "\x6e",
     0x0000006f => "\x6f",
     0x00000070 => "\x70",
     0x00000071 => "\x71",
     0x00000072 => "\x72",
     0x00000073 => "\x73",
     0x00000074 => "\x74",
     0x00000075 => "\x75",
     0x00000076 => "\x76",
     0x00000077 => "\x77",
     0x00000078 => "\x78",
     0x00000079 => "\x79",
     0x0000007a => "\x7a",
     0x0000007b => "\x7b",
     0x0000007c => "\x7c",
     0x0000007d => "\x7d",
     0x0000007e => "\x7e",
     0x0000007f => "\x7f",
     0x000000a0 => "\xa0",
     0x000000a3 => "\xa3",
     0x000000a4 => "\xa4",
     0x000000a6 => "\xa6",
     0x000000a7 => "\xa7",
     0x000000a8 => "\xa8",
     0x000000a9 => "\xa9",
     0x000000ab => "\xab",
     0x000000ac => "\xac",
     0x000000ad => "\xad",
     0x000000ae => "\xae",
     0x000000b0 => "\xb0",
     0x000000b1 => "\xb1",
     0x000000b4 => "\xb4",
     0x000000b5 => "\xb5",
     0x000000b6 => "\xb6",
     0x000000b7 => "\xb7",
     0x000000bb => "\xbb",
     0x000000bd => "\xbd",
     0x000000c0 => "\xc0",
     0x000000c1 => "\xc1",
     0x000000c2 => "\xc2",
     0x000000c3 => "\xc3",
     0x000000c4 => "\xc4",
     0x000000c5 => "\xc5",
     0x000000c6 => "\xc6",
     0x000000c7 => "\xc7",
     0x000000c8 => "\xc8",
     0x000000c9 => "\xc9",
     0x000000ca => "\xca",
     0x000000cb => "\xcb",
     0x000000cc => "\xcc",
     0x000000cd => "\xcd",
     0x000000ce => "\xce",
     0x000000cf => "\xcf",
     0x000000d0 => "\xd0",
     0x000000d1 => "\xd1",
     0x000000d2 => "\xd2",
     0x000000d3 => "\xd3",
     0x000000d4 => "\xd4",
     0x000000d5 => "\xd5",
     0x000000d6 => "\xd6",
     0x000000d7 => "\xd7",
     0x000000d8 => "\xd8",
     0x000000d9 => "\xd9",
     0x000000da => "\xda",
     0x000000db => "\xdb",
     0x000000dc => "\xdc",
     0x000000dd => "\xdd",
     0x000000de => "\xde",
     0x000000df => "\xdf",
     0x000000e0 => "\xe0",
     0x000000e1 => "\xe1",
     0x000000e2 => "\xe2",
     0x000000e3 => "\xe3",
     0x000000e4 => "\xe4",
     0x000000e5 => "\xe5",
     0x000000e6 => "\xe6",
     0x000000e7 => "\xe7",
     0x000000e8 => "\xe8",
     0x000000e9 => "\xe9",
     0x000000ea => "\xea",
     0x000000eb => "\xeb",
     0x000000ec => "\xec",
     0x000000ed => "\xed",
     0x000000ee => "\xee",
     0x000000ef => "\xef",
     0x000000f0 => "\xf0",
     0x000000f1 => "\xf1",
     0x000000f2 => "\xf2",
     0x000000f3 => "\xf3",
     0x000000f4 => "\xf4",
     0x000000f5 => "\xf5",
     0x000000f6 => "\xf6",
     0x000000f7 => "\xf7",
     0x000000f8 => "\xf8",
     0x000000f9 => "\xf9",
     0x000000fa => "\xfa",
     0x000000fb => "\xfb",
     0x000000fc => "\xfc",
     0x000000fd => "\xfd",
     0x000000fe => "\xfe",
     0x000000ff => "\xff",
     0x0000010c => "\x82",
     0x0000010d => "\x84",
     0x00000110 => "\x89",
     0x00000111 => "\x98",
     0x0000014a => "\xb8",
     0x0000014b => "\xb9",
     0x00000152 => "\x8c",
     0x00000153 => "\x9c",
     0x00000160 => "\x8a",
     0x00000161 => "\x9a",
     0x00000166 => "\xba",
     0x00000167 => "\xbc",
     0x00000178 => "\x9f",
     0x0000017d => "\xbe",
     0x0000017e => "\xbf",
     0x00000192 => "\x83",
     0x000001b7 => "\x85",
     0x000001e4 => "\xa2",
     0x000001e5 => "\xa5",
     0x000001e6 => "\x99",
     0x000001e7 => "\xa1",
     0x000001e8 => "\xb2",
     0x000001e9 => "\xb3",
     0x000001ee => "\x87",
     0x000001ef => "\x88",
     0x0000021e => "\xaa",
     0x0000021f => "\xaf",
     0x00000292 => "\x86",
     0x00002013 => "\x96",
     0x00002014 => "\x97",
     0x00002018 => "\x91",
     0x00002019 => "\x92",
     0x0000201c => "\x93",
     0x0000201d => "\x94",
     0x00002022 => "\x95",
     0x00002039 => "\x8b",
     0x0000203a => "\x9b",
     0x000020ac => "\x80",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::SAMI_WS2 - Conversion routines for SAMI_WS2
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for WIN-SAMI-2.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  source: E<lt>URL:http://www2.isl.uit.no/trond/ws2t.htmlE<gt> and
          E<lt>URL:http://www.unicode.org/unicode/alloc/Pipeline.htmlE<gt>
  author: Petter Reinholdtsen E<lt>pere@td.org.uit.noE<gt>
  date:   1999-01-20
  based on info from Trond Trosterud E<lt>Trond.Trosterud@hum.uit.noE<gt>.
  This charmap is based on MS CP1252, not ISO 8859/1.
  alias WS2
  alias WINDOWS-SAMI2
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  00000004 | END OF TRANSMISSION (EOT)
     05 |  00000005 | ENQUIRY (ENQ)
     06 |  00000006 | ACKNOWLEDGE (ACK)
     07 |  00000007 | BELL (BEL)
     08 |  00000008 | BACKSPACE (BS)
     09 |  00000009 | CHARACTER TABULATION (HT)
     0A |  0000000A | LINE FEED (LF)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  00000014 | DEVICE CONTROL FOUR (DC4)
     15 |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     16 |  00000016 | SYNCHRONOUS IDLE (SYN)
     17 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  0000001A | SUBSTITUTE (SUB)
     1B |  0000001B | ESCAPE (ESC)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000020 | SPACE
     21 |  00000021 | EXCLAMATION MARK
     22 |  00000022 | QUOTATION MARK
     23 |  00000023 | NUMBER SIGN
     24 |  00000024 | DOLLAR SIGN
     25 |  00000025 | PERCENT SIGN
     26 |  00000026 | AMPERSAND
     27 |  00000027 | APOSTROPHE
     28 |  00000028 | LEFT PARENTHESIS
     29 |  00000029 | RIGHT PARENTHESIS
     2A |  0000002A | ASTERISK
     2B |  0000002B | PLUS SIGN
     2C |  0000002C | COMMA
     2D |  0000002D | HYPHEN-MINUS
     2E |  0000002E | FULL STOP
     2F |  0000002F | SOLIDUS
     30 |  00000030 | DIGIT ZERO
     31 |  00000031 | DIGIT ONE
     32 |  00000032 | DIGIT TWO
     33 |  00000033 | DIGIT THREE
     34 |  00000034 | DIGIT FOUR
     35 |  00000035 | DIGIT FIVE
     36 |  00000036 | DIGIT SIX
     37 |  00000037 | DIGIT SEVEN
     38 |  00000038 | DIGIT EIGHT
     39 |  00000039 | DIGIT NINE
     3A |  0000003A | COLON
     3B |  0000003B | SEMICOLON
     3C |  0000003C | LESS-THAN SIGN
     3D |  0000003D | EQUALS SIGN
     3E |  0000003E | GREATER-THAN SIGN
     3F |  0000003F | QUESTION MARK
     40 |  00000040 | COMMERCIAL AT
     41 |  00000041 | LATIN CAPITAL LETTER A
     42 |  00000042 | LATIN CAPITAL LETTER B
     43 |  00000043 | LATIN CAPITAL LETTER C
     44 |  00000044 | LATIN CAPITAL LETTER D
     45 |  00000045 | LATIN CAPITAL LETTER E
     46 |  00000046 | LATIN CAPITAL LETTER F
     47 |  00000047 | LATIN CAPITAL LETTER G
     48 |  00000048 | LATIN CAPITAL LETTER H
     49 |  00000049 | LATIN CAPITAL LETTER I
     4A |  0000004A | LATIN CAPITAL LETTER J
     4B |  0000004B | LATIN CAPITAL LETTER K
     4C |  0000004C | LATIN CAPITAL LETTER L
     4D |  0000004D | LATIN CAPITAL LETTER M
     4E |  0000004E | LATIN CAPITAL LETTER N
     4F |  0000004F | LATIN CAPITAL LETTER O
     50 |  00000050 | LATIN CAPITAL LETTER P
     51 |  00000051 | LATIN CAPITAL LETTER Q
     52 |  00000052 | LATIN CAPITAL LETTER R
     53 |  00000053 | LATIN CAPITAL LETTER S
     54 |  00000054 | LATIN CAPITAL LETTER T
     55 |  00000055 | LATIN CAPITAL LETTER U
     56 |  00000056 | LATIN CAPITAL LETTER V
     57 |  00000057 | LATIN CAPITAL LETTER W
     58 |  00000058 | LATIN CAPITAL LETTER X
     59 |  00000059 | LATIN CAPITAL LETTER Y
     5A |  0000005A | LATIN CAPITAL LETTER Z
     5B |  0000005B | LEFT SQUARE BRACKET
     5C |  0000005C | REVERSE SOLIDUS
     5D |  0000005D | RIGHT SQUARE BRACKET
     5E |  0000005E | CIRCUMFLEX ACCENT
     5F |  0000005F | LOW LINE
     60 |  00000060 | GRAVE ACCENT
     61 |  00000061 | LATIN SMALL LETTER A
     62 |  00000062 | LATIN SMALL LETTER B
     63 |  00000063 | LATIN SMALL LETTER C
     64 |  00000064 | LATIN SMALL LETTER D
     65 |  00000065 | LATIN SMALL LETTER E
     66 |  00000066 | LATIN SMALL LETTER F
     67 |  00000067 | LATIN SMALL LETTER G
     68 |  00000068 | LATIN SMALL LETTER H
     69 |  00000069 | LATIN SMALL LETTER I
     6A |  0000006A | LATIN SMALL LETTER J
     6B |  0000006B | LATIN SMALL LETTER K
     6C |  0000006C | LATIN SMALL LETTER L
     6D |  0000006D | LATIN SMALL LETTER M
     6E |  0000006E | LATIN SMALL LETTER N
     6F |  0000006F | LATIN SMALL LETTER O
     70 |  00000070 | LATIN SMALL LETTER P
     71 |  00000071 | LATIN SMALL LETTER Q
     72 |  00000072 | LATIN SMALL LETTER R
     73 |  00000073 | LATIN SMALL LETTER S
     74 |  00000074 | LATIN SMALL LETTER T
     75 |  00000075 | LATIN SMALL LETTER U
     76 |  00000076 | LATIN SMALL LETTER V
     77 |  00000077 | LATIN SMALL LETTER W
     78 |  00000078 | LATIN SMALL LETTER X
     79 |  00000079 | LATIN SMALL LETTER Y
     7A |  0000007A | LATIN SMALL LETTER Z
     7B |  0000007B | LEFT CURLY BRACKET
     7C |  0000007C | VERTICAL LINE
     7D |  0000007D | RIGHT CURLY BRACKET
     7E |  0000007E | TILDE
     7F |  0000007F | DELETE (DEL)
     80 |  000020AC | EURO SIGN
     82 |  0000010C | LATIN CAPITAL LETTER C WITH CARON
     83 |  00000192 | LATIN SMALL LETTER F WITH HOOK
     84 |  0000010D | LATIN SMALL LETTER C WITH CARON
     85 |  000001B7 | LATIN CAPITAL LETTER EZH
     86 |  00000292 | LATIN SMALL LETTER EZH
     87 |  000001EE | LATIN CAPITAL LETTER EZH WITH CARON
     88 |  000001EF | LATIN SMALL LETTER EZH WITH CARON
     89 |  00000110 | LATIN CAPITAL LETTER D WITH STROKE
     8A |  00000160 | LATIN CAPITAL LETTER S WITH CARON
     8B |  00002039 | SINGLE LEFT-POINTING ANGLE QUOTATION MARK
     8C |  00000152 | LATIN CAPITAL LIGATURE OE
     91 |  00002018 | LEFT SINGLE QUOTATION MARK
     92 |  00002019 | RIGHT SINGLE QUOTATION MARK
     93 |  0000201C | LEFT DOUBLE QUOTATION MARK
     94 |  0000201D | RIGHT DOUBLE QUOTATION MARK
     95 |  00002022 | BULLET
     96 |  00002013 | EN DASH
     97 |  00002014 | EM DASH
     98 |  00000111 | LATIN SMALL LETTER D WITH STROKE
     99 |  000001E6 | LATIN CAPITAL LETTER G WITH CARON
     9A |  00000161 | LATIN SMALL LETTER S WITH CARON
     9B |  0000203A | SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
     9C |  00000153 | LATIN SMALL LIGATURE OE
     9F |  00000178 | LATIN CAPITAL LETTER Y WITH DIAERESIS
     A0 |  000000A0 | NO-BREAK SPACE
     A1 |  000001E7 | LATIN SMALL LETTER G WITH CARON
     A2 |  000001E4 | LATIN CAPITAL LETTER G WITH STROKE
     A3 |  000000A3 | POUND SIGN
     A4 |  000000A4 | CURRENCY SIGN
     A5 |  000001E5 | LATIN SMALL LETTER G WITH STROKE
     A6 |  000000A6 | BROKEN BAR
     A7 |  000000A7 | SECTION SIGN
     A8 |  000000A8 | DIAERESIS
     A9 |  000000A9 | COPYRIGHT SIGN
     AA |  0000021E | LATIN CAPITAL LETTER H WITH CARON
     AB |  000000AB | LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
     AC |  000000AC | NOT SIGN
     AD |  000000AD | SOFT HYPHEN
     AE |  000000AE | REGISTERED SIGN
     AF |  0000021F | LATIN SMALL LETTER H WITH CARON
     B0 |  000000B0 | DEGREE SIGN
     B1 |  000000B1 | PLUS-MINUS SIGN
     B2 |  000001E8 | LATIN CAPITAL LETTER K WITH CARON
     B3 |  000001E9 | LATIN SMALL LETTER K WITH CARON
     B4 |  000000B4 | ACUTE ACCENT
     B5 |  000000B5 | MICRO SIGN
     B6 |  000000B6 | PILCROW SIGN
     B7 |  000000B7 | MIDDLE DOT
     B8 |  0000014A | LATIN CAPITAL LETTER ENG (Sami)
     B9 |  0000014B | LATIN SMALL LETTER ENG (Sami)
     BA |  00000166 | LATIN CAPITAL LETTER T WITH STROKE
     BB |  000000BB | RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
     BC |  00000167 | LATIN SMALL LETTER T WITH STROKE
     BD |  000000BD | VULGAR FRACTION ONE HALF
     BE |  0000017D | LATIN CAPITAL LETTER Z WITH CARON
     BF |  0000017E | LATIN SMALL LETTER Z WITH CARON
     C0 |  000000C0 | LATIN CAPITAL LETTER A WITH GRAVE
     C1 |  000000C1 | LATIN CAPITAL LETTER A WITH ACUTE
     C2 |  000000C2 | LATIN CAPITAL LETTER A WITH CIRCUMFLEX
     C3 |  000000C3 | LATIN CAPITAL LETTER A WITH TILDE
     C4 |  000000C4 | LATIN CAPITAL LETTER A WITH DIAERESIS
     C5 |  000000C5 | LATIN CAPITAL LETTER A WITH RING ABOVE
     C6 |  000000C6 | LATIN CAPITAL LETTER AE
     C7 |  000000C7 | LATIN CAPITAL LETTER C WITH CEDILLA
     C8 |  000000C8 | LATIN CAPITAL LETTER E WITH GRAVE
     C9 |  000000C9 | LATIN CAPITAL LETTER E WITH ACUTE
     CA |  000000CA | LATIN CAPITAL LETTER E WITH CIRCUMFLEX
     CB |  000000CB | LATIN CAPITAL LETTER E WITH DIAERESIS
     CC |  000000CC | LATIN CAPITAL LETTER I WITH GRAVE
     CD |  000000CD | LATIN CAPITAL LETTER I WITH ACUTE
     CE |  000000CE | LATIN CAPITAL LETTER I WITH CIRCUMFLEX
     CF |  000000CF | LATIN CAPITAL LETTER I WITH DIAERESIS
     D0 |  000000D0 | LATIN CAPITAL LETTER ETH (Icelandic)
     D1 |  000000D1 | LATIN CAPITAL LETTER N WITH TILDE
     D2 |  000000D2 | LATIN CAPITAL LETTER O WITH GRAVE
     D3 |  000000D3 | LATIN CAPITAL LETTER O WITH ACUTE
     D4 |  000000D4 | LATIN CAPITAL LETTER O WITH CIRCUMFLEX
     D5 |  000000D5 | LATIN CAPITAL LETTER O WITH TILDE
     D6 |  000000D6 | LATIN CAPITAL LETTER O WITH DIAERESIS
     D7 |  000000D7 | MULTIPLICATION SIGN
     D8 |  000000D8 | LATIN CAPITAL LETTER O WITH STROKE
     D9 |  000000D9 | LATIN CAPITAL LETTER U WITH GRAVE
     DA |  000000DA | LATIN CAPITAL LETTER U WITH ACUTE
     DB |  000000DB | LATIN CAPITAL LETTER U WITH CIRCUMFLEX
     DC |  000000DC | LATIN CAPITAL LETTER U WITH DIAERESIS
     DD |  000000DD | LATIN CAPITAL LETTER Y WITH ACUTE
     DE |  000000DE | LATIN CAPITAL LETTER THORN (Icelandic)
     DF |  000000DF | LATIN SMALL LETTER SHARP S (German)
     E0 |  000000E0 | LATIN SMALL LETTER A WITH GRAVE
     E1 |  000000E1 | LATIN SMALL LETTER A WITH ACUTE
     E2 |  000000E2 | LATIN SMALL LETTER A WITH CIRCUMFLEX
     E3 |  000000E3 | LATIN SMALL LETTER A WITH TILDE
     E4 |  000000E4 | LATIN SMALL LETTER A WITH DIAERESIS
     E5 |  000000E5 | LATIN SMALL LETTER A WITH RING ABOVE
     E6 |  000000E6 | LATIN SMALL LETTER AE
     E7 |  000000E7 | LATIN SMALL LETTER C WITH CEDILLA
     E8 |  000000E8 | LATIN SMALL LETTER E WITH GRAVE
     E9 |  000000E9 | LATIN SMALL LETTER E WITH ACUTE
     EA |  000000EA | LATIN SMALL LETTER E WITH CIRCUMFLEX
     EB |  000000EB | LATIN SMALL LETTER E WITH DIAERESIS
     EC |  000000EC | LATIN SMALL LETTER I WITH GRAVE
     ED |  000000ED | LATIN SMALL LETTER I WITH ACUTE
     EE |  000000EE | LATIN SMALL LETTER I WITH CIRCUMFLEX
     EF |  000000EF | LATIN SMALL LETTER I WITH DIAERESIS
     F0 |  000000F0 | LATIN SMALL LETTER ETH (Icelandic)
     F1 |  000000F1 | LATIN SMALL LETTER N WITH TILDE
     F2 |  000000F2 | LATIN SMALL LETTER O WITH GRAVE
     F3 |  000000F3 | LATIN SMALL LETTER O WITH ACUTE
     F4 |  000000F4 | LATIN SMALL LETTER O WITH CIRCUMFLEX
     F5 |  000000F5 | LATIN SMALL LETTER O WITH TILDE
     F6 |  000000F6 | LATIN SMALL LETTER O WITH DIAERESIS
     F7 |  000000F7 | DIVISION SIGN
     F8 |  000000F8 | LATIN SMALL LETTER O WITH STROKE
     F9 |  000000F9 | LATIN SMALL LETTER U WITH GRAVE
     FA |  000000FA | LATIN SMALL LETTER U WITH ACUTE
     FB |  000000FB | LATIN SMALL LETTER U WITH CIRCUMFLEX
     FC |  000000FC | LATIN SMALL LETTER U WITH DIAERESIS
     FD |  000000FD | LATIN SMALL LETTER Y WITH ACUTE
     FE |  000000FE | LATIN SMALL LETTER THORN (Icelandic)
     FF |  000000FF | LATIN SMALL LETTER Y WITH DIAERESIS
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/TIS_620.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for TIS-620.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::TIS_620;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x0002,
     0x0003,
     0x0004,
     0x0005,
     0x0006,
     0x0007,
     0x0008,
     0x0009,
     0x000a,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x0014,
     0x0015,
     0x0016,
     0x0017,
     0x0018,
     0x0019,
     0x001a,
     0x001b,
     0x001c,
     0x001d,
     0x001e,
     0x001f,
     0x0020,
     0x0021,
     0x0022,
     0x0023,
     0x0024,
     0x0025,
     0x0026,
     0x0027,
     0x0028,
     0x0029,
     0x002a,
     0x002b,
     0x002c,
     0x002d,
     0x002e,
     0x002f,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x003a,
     0x003b,
     0x003c,
     0x003d,
     0x003e,
     0x003f,
     0x0040,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x005b,
     0x005c,
     0x005d,
     0x005e,
     0x005f,
     0x0060,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x007b,
     0x007c,
     0x007d,
     0x007e,
     0x007f,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x0e01,
     0x0e02,
     0x0e03,
     0x0e04,
     0x0e05,
     0x0e06,
     0x0e07,
     0x0e08,
     0x0e09,
     0x0e0a,
     0x0e0b,
     0x0e0c,
     0x0e0d,
     0x0e0e,
     0x0e0f,
     0x0e10,
     0x0e11,
     0x0e12,
     0x0e13,
     0x0e14,
     0x0e15,
     0x0e16,
     0x0e17,
     0x0e18,
     0x0e19,
     0x0e1a,
     0x0e1b,
     0x0e1c,
     0x0e1d,
     0x0e1e,
     0x0e1f,
     0x0e20,
     0x0e21,
     0x0e22,
     0x0e23,
     0x0e24,
     0x0e25,
     0x0e26,
     0x0e27,
     0x0e28,
     0x0e29,
     0x0e2a,
     0x0e2b,
     0x0e2c,
     0x0e2d,
     0x0e2e,
     0x0e2f,
     0x0e30,
     0x0e31,
     0x0e32,
     0x0e33,
     0x0e34,
     0x0e35,
     0x0e36,
     0x0e37,
     0x0e38,
     0x0e39,
     0x0e3a,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
     0x0e3f,
     0x0e40,
     0x0e41,
     0x0e42,
     0x0e43,
     0x0e44,
     0x0e45,
     0x0e46,
     0x0e47,
     0x0e48,
     0x0e49,
     0x0e4a,
     0x0e4b,
     0x0e4c,
     0x0e4d,
     0x0e4e,
     0x0e4f,
     0x0e50,
     0x0e51,
     0x0e52,
     0x0e53,
     0x0e54,
     0x0e55,
     0x0e56,
     0x0e57,
     0x0e58,
     0x0e59,
     0x0e5a,
     0x0e5b,
     0xfffd,
     0xfffd,
     0xfffd,
     0xfffd,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\x02",
     "\x03",
     "\x04",
     "\x05",
     "\x06",
     "\x07",
     "\x08",
     "\x09",
     "\x0a",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\x14",
     "\x15",
     "\x16",
     "\x17",
     "\x18",
     "\x19",
     "\x1a",
     "\x1b",
     "\x1c",
     "\x1d",
     "\x1e",
     "\x1f",
     "\x20",
     "\x21",
     "\x22",
     "\x23",
     "\x24",
     "\x25",
     "\x26",
     "\x27",
     "\x28",
     "\x29",
     "\x2a",
     "\x2b",
     "\x2c",
     "\x2d",
     "\x2e",
     "\x2f",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\x3a",
     "\x3b",
     "\x3c",
     "\x3d",
     "\x3e",
     "\x3f",
     "\x40",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\x5b",
     "\x5c",
     "\x5d",
     "\x5e",
     "\x5f",
     "\x60",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\x7b",
     "\x7c",
     "\x7d",
     "\x7e",
     "\x7f",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xe0\xb8\x81",
     "\xe0\xb8\x82",
     "\xe0\xb8\x83",
     "\xe0\xb8\x84",
     "\xe0\xb8\x85",
     "\xe0\xb8\x86",
     "\xe0\xb8\x87",
     "\xe0\xb8\x88",
     "\xe0\xb8\x89",
     "\xe0\xb8\x8a",
     "\xe0\xb8\x8b",
     "\xe0\xb8\x8c",
     "\xe0\xb8\x8d",
     "\xe0\xb8\x8e",
     "\xe0\xb8\x8f",
     "\xe0\xb8\x90",
     "\xe0\xb8\x91",
     "\xe0\xb8\x92",
     "\xe0\xb8\x93",
     "\xe0\xb8\x94",
     "\xe0\xb8\x95",
     "\xe0\xb8\x96",
     "\xe0\xb8\x97",
     "\xe0\xb8\x98",
     "\xe0\xb8\x99",
     "\xe0\xb8\x9a",
     "\xe0\xb8\x9b",
     "\xe0\xb8\x9c",
     "\xe0\xb8\x9d",
     "\xe0\xb8\x9e",
     "\xe0\xb8\x9f",
     "\xe0\xb8\xa0",
     "\xe0\xb8\xa1",
     "\xe0\xb8\xa2",
     "\xe0\xb8\xa3",
     "\xe0\xb8\xa4",
     "\xe0\xb8\xa5",
     "\xe0\xb8\xa6",
     "\xe0\xb8\xa7",
     "\xe0\xb8\xa8",
     "\xe0\xb8\xa9",
     "\xe0\xb8\xaa",
     "\xe0\xb8\xab",
     "\xe0\xb8\xac",
     "\xe0\xb8\xad",
     "\xe0\xb8\xae",
     "\xe0\xb8\xaf",
     "\xe0\xb8\xb0",
     "\xe0\xb8\xb1",
     "\xe0\xb8\xb2",
     "\xe0\xb8\xb3",
     "\xe0\xb8\xb4",
     "\xe0\xb8\xb5",
     "\xe0\xb8\xb6",
     "\xe0\xb8\xb7",
     "\xe0\xb8\xb8",
     "\xe0\xb8\xb9",
     "\xe0\xb8\xba",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xe0\xb8\xbf",
     "\xe0\xb9\x80",
     "\xe0\xb9\x81",
     "\xe0\xb9\x82",
     "\xe0\xb9\x83",
     "\xe0\xb9\x84",
     "\xe0\xb9\x85",
     "\xe0\xb9\x86",
     "\xe0\xb9\x87",
     "\xe0\xb9\x88",
     "\xe0\xb9\x89",
     "\xe0\xb9\x8a",
     "\xe0\xb9\x8b",
     "\xe0\xb9\x8c",
     "\xe0\xb9\x8d",
     "\xe0\xb9\x8e",
     "\xe0\xb9\x8f",
     "\xe0\xb9\x90",
     "\xe0\xb9\x91",
     "\xe0\xb9\x92",
     "\xe0\xb9\x93",
     "\xe0\xb9\x94",
     "\xe0\xb9\x95",
     "\xe0\xb9\x96",
     "\xe0\xb9\x97",
     "\xe0\xb9\x98",
     "\xe0\xb9\x99",
     "\xe0\xb9\x9a",
     "\xe0\xb9\x9b",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
     "\xef\xbf\xbd",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000002 => "\x02",
     0x00000003 => "\x03",
     0x00000004 => "\x04",
     0x00000005 => "\x05",
     0x00000006 => "\x06",
     0x00000007 => "\x07",
     0x00000008 => "\x08",
     0x00000009 => "\x09",
     0x0000000a => "\x0a",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000014 => "\x14",
     0x00000015 => "\x15",
     0x00000016 => "\x16",
     0x00000017 => "\x17",
     0x00000018 => "\x18",
     0x00000019 => "\x19",
     0x0000001a => "\x1a",
     0x0000001b => "\x1b",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001e => "\x1e",
     0x0000001f => "\x1f",
     0x00000020 => "\x20",
     0x00000021 => "\x21",
     0x00000022 => "\x22",
     0x00000023 => "\x23",
     0x00000024 => "\x24",
     0x00000025 => "\x25",
     0x00000026 => "\x26",
     0x00000027 => "\x27",
     0x00000028 => "\x28",
     0x00000029 => "\x29",
     0x0000002a => "\x2a",
     0x0000002b => "\x2b",
     0x0000002c => "\x2c",
     0x0000002d => "\x2d",
     0x0000002e => "\x2e",
     0x0000002f => "\x2f",
     0x00000030 => "\x30",
     0x00000031 => "\x31",
     0x00000032 => "\x32",
     0x00000033 => "\x33",
     0x00000034 => "\x34",
     0x00000035 => "\x35",
     0x00000036 => "\x36",
     0x00000037 => "\x37",
     0x00000038 => "\x38",
     0x00000039 => "\x39",
     0x0000003a => "\x3a",
     0x0000003b => "\x3b",
     0x0000003c => "\x3c",
     0x0000003d => "\x3d",
     0x0000003e => "\x3e",
     0x0000003f => "\x3f",
     0x00000040 => "\x40",
     0x00000041 => "\x41",
     0x00000042 => "\x42",
     0x00000043 => "\x43",
     0x00000044 => "\x44",
     0x00000045 => "\x45",
     0x00000046 => "\x46",
     0x00000047 => "\x47",
     0x00000048 => "\x48",
     0x00000049 => "\x49",
     0x0000004a => "\x4a",
     0x0000004b => "\x4b",
     0x0000004c => "\x4c",
     0x0000004d => "\x4d",
     0x0000004e => "\x4e",
     0x0000004f => "\x4f",
     0x00000050 => "\x50",
     0x00000051 => "\x51",
     0x00000052 => "\x52",
     0x00000053 => "\x53",
     0x00000054 => "\x54",
     0x00000055 => "\x55",
     0x00000056 => "\x56",
     0x00000057 => "\x57",
     0x00000058 => "\x58",
     0x00000059 => "\x59",
     0x0000005a => "\x5a",
     0x0000005b => "\x5b",
     0x0000005c => "\x5c",
     0x0000005d => "\x5d",
     0x0000005e => "\x5e",
     0x0000005f => "\x5f",
     0x00000060 => "\x60",
     0x00000061 => "\x61",
     0x00000062 => "\x62",
     0x00000063 => "\x63",
     0x00000064 => "\x64",
     0x00000065 => "\x65",
     0x00000066 => "\x66",
     0x00000067 => "\x67",
     0x00000068 => "\x68",
     0x00000069 => "\x69",
     0x0000006a => "\x6a",
     0x0000006b => "\x6b",
     0x0000006c => "\x6c",
     0x0000006d => "\x6d",
     0x0000006e => "\x6e",
     0x0000006f => "\x6f",
     0x00000070 => "\x70",
     0x00000071 => "\x71",
     0x00000072 => "\x72",
     0x00000073 => "\x73",
     0x00000074 => "\x74",
     0x00000075 => "\x75",
     0x00000076 => "\x76",
     0x00000077 => "\x77",
     0x00000078 => "\x78",
     0x00000079 => "\x79",
     0x0000007a => "\x7a",
     0x0000007b => "\x7b",
     0x0000007c => "\x7c",
     0x0000007d => "\x7d",
     0x0000007e => "\x7e",
     0x0000007f => "\x7f",
     0x00000e01 => "\xa1",
     0x00000e02 => "\xa2",
     0x00000e03 => "\xa3",
     0x00000e04 => "\xa4",
     0x00000e05 => "\xa5",
     0x00000e06 => "\xa6",
     0x00000e07 => "\xa7",
     0x00000e08 => "\xa8",
     0x00000e09 => "\xa9",
     0x00000e0a => "\xaa",
     0x00000e0b => "\xab",
     0x00000e0c => "\xac",
     0x00000e0d => "\xad",
     0x00000e0e => "\xae",
     0x00000e0f => "\xaf",
     0x00000e10 => "\xb0",
     0x00000e11 => "\xb1",
     0x00000e12 => "\xb2",
     0x00000e13 => "\xb3",
     0x00000e14 => "\xb4",
     0x00000e15 => "\xb5",
     0x00000e16 => "\xb6",
     0x00000e17 => "\xb7",
     0x00000e18 => "\xb8",
     0x00000e19 => "\xb9",
     0x00000e1a => "\xba",
     0x00000e1b => "\xbb",
     0x00000e1c => "\xbc",
     0x00000e1d => "\xbd",
     0x00000e1e => "\xbe",
     0x00000e1f => "\xbf",
     0x00000e20 => "\xc0",
     0x00000e21 => "\xc1",
     0x00000e22 => "\xc2",
     0x00000e23 => "\xc3",
     0x00000e24 => "\xc4",
     0x00000e25 => "\xc5",
     0x00000e26 => "\xc6",
     0x00000e27 => "\xc7",
     0x00000e28 => "\xc8",
     0x00000e29 => "\xc9",
     0x00000e2a => "\xca",
     0x00000e2b => "\xcb",
     0x00000e2c => "\xcc",
     0x00000e2d => "\xcd",
     0x00000e2e => "\xce",
     0x00000e2f => "\xcf",
     0x00000e30 => "\xd0",
     0x00000e31 => "\xd1",
     0x00000e32 => "\xd2",
     0x00000e33 => "\xd3",
     0x00000e34 => "\xd4",
     0x00000e35 => "\xd5",
     0x00000e36 => "\xd6",
     0x00000e37 => "\xd7",
     0x00000e38 => "\xd8",
     0x00000e39 => "\xd9",
     0x00000e3a => "\xda",
     0x00000e3f => "\xdf",
     0x00000e40 => "\xe0",
     0x00000e41 => "\xe1",
     0x00000e42 => "\xe2",
     0x00000e43 => "\xe3",
     0x00000e44 => "\xe4",
     0x00000e45 => "\xe5",
     0x00000e46 => "\xe6",
     0x00000e47 => "\xe7",
     0x00000e48 => "\xe8",
     0x00000e49 => "\xe9",
     0x00000e4a => "\xea",
     0x00000e4b => "\xeb",
     0x00000e4c => "\xec",
     0x00000e4d => "\xed",
     0x00000e4e => "\xee",
     0x00000e4f => "\xef",
     0x00000e50 => "\xf0",
     0x00000e51 => "\xf1",
     0x00000e52 => "\xf2",
     0x00000e53 => "\xf3",
     0x00000e54 => "\xf4",
     0x00000e55 => "\xf5",
     0x00000e56 => "\xf6",
     0x00000e57 => "\xf7",
     0x00000e58 => "\xf8",
     0x00000e59 => "\xf9",
     0x00000e5a => "\xfa",
     0x00000e5b => "\xfb",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::TIS_620 - Conversion routines for TIS-620
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for TIS-620.
 
 =head1 COMMENTS
 
 The following comments have been extracted from the original charmap:
 
  version: 1.0
   sources: Thai Industrial Standards Institute, ECMA registry, IANA
  alias TIS620
  alias TIS620-0
  alias TIS620.2529-1
  alias TIS620.2533-0
  alias ISO-IR-166
 
 Please note that aliases listed above are not necessarily valid!
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  00000004 | END OF TRANSMISSION (EOT)
     05 |  00000005 | ENQUIRY (ENQ)
     06 |  00000006 | ACKNOWLEDGE (ACK)
     07 |  00000007 | BELL (BEL)
     08 |  00000008 | BACKSPACE (BS)
     09 |  00000009 | CHARACTER TABULATION (HT)
     0A |  0000000A | LINE FEED (LF)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  00000014 | DEVICE CONTROL FOUR (DC4)
     15 |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     16 |  00000016 | SYNCHRONOUS IDLE (SYN)
     17 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  0000001A | SUBSTITUTE (SUB)
     1B |  0000001B | ESCAPE (ESC)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000020 | SPACE
     21 |  00000021 | EXCLAMATION MARK
     22 |  00000022 | QUOTATION MARK
     23 |  00000023 | NUMBER SIGN
     24 |  00000024 | DOLLAR SIGN
     25 |  00000025 | PERCENT SIGN
     26 |  00000026 | AMPERSAND
     27 |  00000027 | APOSTROPHE
     28 |  00000028 | LEFT PARENTHESIS
     29 |  00000029 | RIGHT PARENTHESIS
     2A |  0000002A | ASTERISK
     2B |  0000002B | PLUS SIGN
     2C |  0000002C | COMMA
     2D |  0000002D | HYPHEN-MINUS
     2E |  0000002E | FULL STOP
     2F |  0000002F | SOLIDUS
     30 |  00000030 | DIGIT ZERO
     31 |  00000031 | DIGIT ONE
     32 |  00000032 | DIGIT TWO
     33 |  00000033 | DIGIT THREE
     34 |  00000034 | DIGIT FOUR
     35 |  00000035 | DIGIT FIVE
     36 |  00000036 | DIGIT SIX
     37 |  00000037 | DIGIT SEVEN
     38 |  00000038 | DIGIT EIGHT
     39 |  00000039 | DIGIT NINE
     3A |  0000003A | COLON
     3B |  0000003B | SEMICOLON
     3C |  0000003C | LESS-THAN SIGN
     3D |  0000003D | EQUALS SIGN
     3E |  0000003E | GREATER-THAN SIGN
     3F |  0000003F | QUESTION MARK
     40 |  00000040 | COMMERCIAL AT
     41 |  00000041 | LATIN CAPITAL LETTER A
     42 |  00000042 | LATIN CAPITAL LETTER B
     43 |  00000043 | LATIN CAPITAL LETTER C
     44 |  00000044 | LATIN CAPITAL LETTER D
     45 |  00000045 | LATIN CAPITAL LETTER E
     46 |  00000046 | LATIN CAPITAL LETTER F
     47 |  00000047 | LATIN CAPITAL LETTER G
     48 |  00000048 | LATIN CAPITAL LETTER H
     49 |  00000049 | LATIN CAPITAL LETTER I
     4A |  0000004A | LATIN CAPITAL LETTER J
     4B |  0000004B | LATIN CAPITAL LETTER K
     4C |  0000004C | LATIN CAPITAL LETTER L
     4D |  0000004D | LATIN CAPITAL LETTER M
     4E |  0000004E | LATIN CAPITAL LETTER N
     4F |  0000004F | LATIN CAPITAL LETTER O
     50 |  00000050 | LATIN CAPITAL LETTER P
     51 |  00000051 | LATIN CAPITAL LETTER Q
     52 |  00000052 | LATIN CAPITAL LETTER R
     53 |  00000053 | LATIN CAPITAL LETTER S
     54 |  00000054 | LATIN CAPITAL LETTER T
     55 |  00000055 | LATIN CAPITAL LETTER U
     56 |  00000056 | LATIN CAPITAL LETTER V
     57 |  00000057 | LATIN CAPITAL LETTER W
     58 |  00000058 | LATIN CAPITAL LETTER X
     59 |  00000059 | LATIN CAPITAL LETTER Y
     5A |  0000005A | LATIN CAPITAL LETTER Z
     5B |  0000005B | LEFT SQUARE BRACKET
     5C |  0000005C | REVERSE SOLIDUS
     5D |  0000005D | RIGHT SQUARE BRACKET
     5E |  0000005E | CIRCUMFLEX ACCENT
     5F |  0000005F | LOW LINE
     60 |  00000060 | GRAVE ACCENT
     61 |  00000061 | LATIN SMALL LETTER A
     62 |  00000062 | LATIN SMALL LETTER B
     63 |  00000063 | LATIN SMALL LETTER C
     64 |  00000064 | LATIN SMALL LETTER D
     65 |  00000065 | LATIN SMALL LETTER E
     66 |  00000066 | LATIN SMALL LETTER F
     67 |  00000067 | LATIN SMALL LETTER G
     68 |  00000068 | LATIN SMALL LETTER H
     69 |  00000069 | LATIN SMALL LETTER I
     6A |  0000006A | LATIN SMALL LETTER J
     6B |  0000006B | LATIN SMALL LETTER K
     6C |  0000006C | LATIN SMALL LETTER L
     6D |  0000006D | LATIN SMALL LETTER M
     6E |  0000006E | LATIN SMALL LETTER N
     6F |  0000006F | LATIN SMALL LETTER O
     70 |  00000070 | LATIN SMALL LETTER P
     71 |  00000071 | LATIN SMALL LETTER Q
     72 |  00000072 | LATIN SMALL LETTER R
     73 |  00000073 | LATIN SMALL LETTER S
     74 |  00000074 | LATIN SMALL LETTER T
     75 |  00000075 | LATIN SMALL LETTER U
     76 |  00000076 | LATIN SMALL LETTER V
     77 |  00000077 | LATIN SMALL LETTER W
     78 |  00000078 | LATIN SMALL LETTER X
     79 |  00000079 | LATIN SMALL LETTER Y
     7A |  0000007A | LATIN SMALL LETTER Z
     7B |  0000007B | LEFT CURLY BRACKET
     7C |  0000007C | VERTICAL LINE
     7D |  0000007D | RIGHT CURLY BRACKET
     7E |  0000007E | TILDE
     7F |  0000007F | DELETE (DEL)
     A1 |  00000E01 | THAI CHARACTER KO KAI
     A2 |  00000E02 | THAI CHARACTER KHO KHAI
     A3 |  00000E03 | THAI CHARACTER KHO KHUAT
     A4 |  00000E04 | THAI CHARACTER KHO KHWAI
     A5 |  00000E05 | THAI CHARACTER KHO KHON
     A6 |  00000E06 | THAI CHARACTER KHO RAKHANG
     A7 |  00000E07 | THAI CHARACTER NGO NGU
     A8 |  00000E08 | THAI CHARACTER CHO CHAN
     A9 |  00000E09 | THAI CHARACTER CHO CHING
     AA |  00000E0A | THAI CHARACTER CHO CHANG
     AB |  00000E0B | THAI CHARACTER SO SO
     AC |  00000E0C | THAI CHARACTER CHO CHOE
     AD |  00000E0D | THAI CHARACTER YO YING
     AE |  00000E0E | THAI CHARACTER DO CHADA
     AF |  00000E0F | THAI CHARACTER TO PATAK
     B0 |  00000E10 | THAI CHARACTER THO THAN
     B1 |  00000E11 | THAI CHARACTER THO NANGMONTHO
     B2 |  00000E12 | THAI CHARACTER THO PHUTHAO
     B3 |  00000E13 | THAI CHARACTER NO NEN
     B4 |  00000E14 | THAI CHARACTER DO DEK
     B5 |  00000E15 | THAI CHARACTER TO TAO
     B6 |  00000E16 | THAI CHARACTER THO THUNG
     B7 |  00000E17 | THAI CHARACTER THO THAHAN
     B8 |  00000E18 | THAI CHARACTER THO THONG
     B9 |  00000E19 | THAI CHARACTER NO NU
     BA |  00000E1A | THAI CHARACTER BO BAIMAI
     BB |  00000E1B | THAI CHARACTER PO PLA
     BC |  00000E1C | THAI CHARACTER PHO PHUNG
     BD |  00000E1D | THAI CHARACTER FO FA
     BE |  00000E1E | THAI CHARACTER PHO PHAN
     BF |  00000E1F | THAI CHARACTER FO FAN
     C0 |  00000E20 | THAI CHARACTER PHO SAMPHAO
     C1 |  00000E21 | THAI CHARACTER MO MA
     C2 |  00000E22 | THAI CHARACTER YO YAK
     C3 |  00000E23 | THAI CHARACTER RO RUA
     C4 |  00000E24 | THAI CHARACTER RU
     C5 |  00000E25 | THAI CHARACTER LO LING
     C6 |  00000E26 | THAI CHARACTER LU
     C7 |  00000E27 | THAI CHARACTER WO WAEN
     C8 |  00000E28 | THAI CHARACTER SO SALA
     C9 |  00000E29 | THAI CHARACTER SO RUSI
     CA |  00000E2A | THAI CHARACTER SO SUA
     CB |  00000E2B | THAI CHARACTER HO HIP
     CC |  00000E2C | THAI CHARACTER LO CHULA
     CD |  00000E2D | THAI CHARACTER O ANG
     CE |  00000E2E | THAI CHARACTER HO NOKHUK
     CF |  00000E2F | THAI CHARACTER PAIYANNOI
     D0 |  00000E30 | THAI CHARACTER SARA A
     D1 |  00000E31 | THAI CHARACTER MAI HAN-AKAT
     D2 |  00000E32 | THAI CHARACTER SARA AA
     D3 |  00000E33 | THAI CHARACTER SARA AM
     D4 |  00000E34 | THAI CHARACTER SARA I
     D5 |  00000E35 | THAI CHARACTER SARA II
     D6 |  00000E36 | THAI CHARACTER SARA UE
     D7 |  00000E37 | THAI CHARACTER SARA UEE
     D8 |  00000E38 | THAI CHARACTER SARA U
     D9 |  00000E39 | THAI CHARACTER SARA UU
     DA |  00000E3A | THAI CHARACTER PHINTHU
     DF |  00000E3F | THAI CHARACTER SYMBOL BAHT
     E0 |  00000E40 | THAI CHARACTER SARA E
     E1 |  00000E41 | THAI CHARACTER SARA AE
     E2 |  00000E42 | THAI CHARACTER SARA O
     E3 |  00000E43 | THAI CHARACTER SARA AI MAIMUAN
     E4 |  00000E44 | THAI CHARACTER SARA AI MAIMALAI
     E5 |  00000E45 | THAI CHARACTER LAKKHANGYAO
     E6 |  00000E46 | THAI CHARACTER MAIYAMOK
     E7 |  00000E47 | THAI CHARACTER MAITAIKHU
     E8 |  00000E48 | THAI CHARACTER MAI EK
     E9 |  00000E49 | THAI CHARACTER MAI THO
     EA |  00000E4A | THAI CHARACTER MAI TRI
     EB |  00000E4B | THAI CHARACTER MAI CHATTAWA
     EC |  00000E4C | THAI CHARACTER THANTHAKHAT
     ED |  00000E4D | THAI CHARACTER NIKHAHIT
     EE |  00000E4E | THAI CHARACTER YAMAKKAN
     EF |  00000E4F | THAI CHARACTER FONGMAN
     F0 |  00000E50 | THAI DIGIT ZERO
     F1 |  00000E51 | THAI DIGIT ONE
     F2 |  00000E52 | THAI DIGIT TWO
     F3 |  00000E53 | THAI DIGIT THREE
     F4 |  00000E54 | THAI DIGIT FOUR
     F5 |  00000E55 | THAI DIGIT FIVE
     F6 |  00000E56 | THAI DIGIT SIX
     F7 |  00000E57 | THAI DIGIT SEVEN
     F8 |  00000E58 | THAI DIGIT EIGHT
     F9 |  00000E59 | THAI DIGIT NINE
     FA |  00000E5A | THAI CHARACTER ANGKHANKHU
     FB |  00000E5B | THAI CHARACTER KHOMUT
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/US_ASCII.pm ###
 #! /bin/false
 
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for US-ASCII.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::US_ASCII;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		# FIXME: Maybe the lookup is cheaper than the call to chr().
 		$_[1] = join '', 
 		    map $_ > 0x7f ? '?' : chr $_,
 			    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8') {
 		# FIXME: Maybe the lookup is cheaper than the call to chr().
 		$_[1] = join '', 
 		    map $_ > 0x7f ? "\xef\xbf\xbd" : chr $_, unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map { $_ > 0x7f ? 0xfffd : $_ } unpack 'C*', $_[1] ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::US_ASCII - Conversion routines for US-ASCII
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module contains the conversion tables and routines for US-ASCII.
 
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00000002 | START OF TEXT (STX)
     03 |  00000003 | END OF TEXT (ETX)
     04 |  00000004 | END OF TRANSMISSION (EOT)
     05 |  00000005 | ENQUIRY (ENQ)
     06 |  00000006 | ACKNOWLEDGE (ACK)
     07 |  00000007 | BELL (BEL)
     08 |  00000008 | BACKSPACE (BS)
     09 |  00000009 | CHARACTER TABULATION (HT)
     0A |  0000000A | LINE FEED (LF)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  00000014 | DEVICE CONTROL FOUR (DC4)
     15 |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     16 |  00000016 | SYNCHRONOUS IDLE (SYN)
     17 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     18 |  00000018 | CANCEL (CAN)
     19 |  00000019 | END OF MEDIUM (EM)
     1A |  0000001A | SUBSTITUTE (SUB)
     1B |  0000001B | ESCAPE (ESC)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  0000001E | RECORD SEPARATOR (IS2)
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000020 | SPACE
     21 |  00000021 | EXCLAMATION MARK
     22 |  00000022 | QUOTATION MARK
     23 |  00000023 | NUMBER SIGN
     24 |  00000024 | DOLLAR SIGN
     25 |  00000025 | PERCENT SIGN
     26 |  00000026 | AMPERSAND
     27 |  00000027 | APOSTROPHE
     28 |  00000028 | LEFT PARENTHESIS
     29 |  00000029 | RIGHT PARENTHESIS
     2A |  0000002A | ASTERISK
     2B |  0000002B | PLUS SIGN
     2C |  0000002C | COMMA
     2D |  0000002D | HYPHEN-MINUS
     2E |  0000002E | FULL STOP
     2F |  0000002F | SOLIDUS
     30 |  00000030 | DIGIT ZERO
     31 |  00000031 | DIGIT ONE
     32 |  00000032 | DIGIT TWO
     33 |  00000033 | DIGIT THREE
     34 |  00000034 | DIGIT FOUR
     35 |  00000035 | DIGIT FIVE
     36 |  00000036 | DIGIT SIX
     37 |  00000037 | DIGIT SEVEN
     38 |  00000038 | DIGIT EIGHT
     39 |  00000039 | DIGIT NINE
     3A |  0000003A | COLON
     3B |  0000003B | SEMICOLON
     3C |  0000003C | LESS-THAN SIGN
     3D |  0000003D | EQUALS SIGN
     3E |  0000003E | GREATER-THAN SIGN
     3F |  0000003F | QUESTION MARK
     40 |  00000040 | COMMERCIAL AT
     41 |  00000041 | LATIN CAPITAL LETTER A
     42 |  00000042 | LATIN CAPITAL LETTER B
     43 |  00000043 | LATIN CAPITAL LETTER C
     44 |  00000044 | LATIN CAPITAL LETTER D
     45 |  00000045 | LATIN CAPITAL LETTER E
     46 |  00000046 | LATIN CAPITAL LETTER F
     47 |  00000047 | LATIN CAPITAL LETTER G
     48 |  00000048 | LATIN CAPITAL LETTER H
     49 |  00000049 | LATIN CAPITAL LETTER I
     4A |  0000004A | LATIN CAPITAL LETTER J
     4B |  0000004B | LATIN CAPITAL LETTER K
     4C |  0000004C | LATIN CAPITAL LETTER L
     4D |  0000004D | LATIN CAPITAL LETTER M
     4E |  0000004E | LATIN CAPITAL LETTER N
     4F |  0000004F | LATIN CAPITAL LETTER O
     50 |  00000050 | LATIN CAPITAL LETTER P
     51 |  00000051 | LATIN CAPITAL LETTER Q
     52 |  00000052 | LATIN CAPITAL LETTER R
     53 |  00000053 | LATIN CAPITAL LETTER S
     54 |  00000054 | LATIN CAPITAL LETTER T
     55 |  00000055 | LATIN CAPITAL LETTER U
     56 |  00000056 | LATIN CAPITAL LETTER V
     57 |  00000057 | LATIN CAPITAL LETTER W
     58 |  00000058 | LATIN CAPITAL LETTER X
     59 |  00000059 | LATIN CAPITAL LETTER Y
     5A |  0000005A | LATIN CAPITAL LETTER Z
     5B |  0000005B | LEFT SQUARE BRACKET
     5C |  0000005C | REVERSE SOLIDUS
     5D |  0000005D | RIGHT SQUARE BRACKET
     5E |  0000005E | CIRCUMFLEX ACCENT
     5F |  0000005F | LOW LINE
     60 |  00000060 | GRAVE ACCENT
     61 |  00000061 | LATIN SMALL LETTER A
     62 |  00000062 | LATIN SMALL LETTER B
     63 |  00000063 | LATIN SMALL LETTER C
     64 |  00000064 | LATIN SMALL LETTER D
     65 |  00000065 | LATIN SMALL LETTER E
     66 |  00000066 | LATIN SMALL LETTER F
     67 |  00000067 | LATIN SMALL LETTER G
     68 |  00000068 | LATIN SMALL LETTER H
     69 |  00000069 | LATIN SMALL LETTER I
     6A |  0000006A | LATIN SMALL LETTER J
     6B |  0000006B | LATIN SMALL LETTER K
     6C |  0000006C | LATIN SMALL LETTER L
     6D |  0000006D | LATIN SMALL LETTER M
     6E |  0000006E | LATIN SMALL LETTER N
     6F |  0000006F | LATIN SMALL LETTER O
     70 |  00000070 | LATIN SMALL LETTER P
     71 |  00000071 | LATIN SMALL LETTER Q
     72 |  00000072 | LATIN SMALL LETTER R
     73 |  00000073 | LATIN SMALL LETTER S
     74 |  00000074 | LATIN SMALL LETTER T
     75 |  00000075 | LATIN SMALL LETTER U
     76 |  00000076 | LATIN SMALL LETTER V
     77 |  00000077 | LATIN SMALL LETTER W
     78 |  00000078 | LATIN SMALL LETTER X
     79 |  00000079 | LATIN SMALL LETTER Y
     7A |  0000007A | LATIN SMALL LETTER Z
     7B |  0000007B | LEFT CURLY BRACKET
     7C |  0000007C | VERTICAL LINE
     7D |  0000007D | RIGHT CURLY BRACKET
     7E |  0000007E | TILDE
     7F |  0000007F | DELETE (DEL)
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/UTF_8.pm ###
 #! /bin/false
 
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for UTF-8 (perl < 5.8.0).
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::UTF_8;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 	return $_[0]->_fromInternal ($_[1]);
     } else {
 	return $_[0]->_toInternal ($_[1]);
     }
 }
 
 # This routine assumes that the internal representation is always sane
 # and contains valid codes only.
 sub _fromInternal
 {
     $_[1] = join '', map {
 	if ($_ <= 0x7f) {
 	    chr $_;
 	} elsif ($_ <= 0x7ff) {
 	    pack ("C2", 
 		  (0xc0 | (($_ >> 6) & 0x1f)),
 		  (0x80 | ($_ & 0x3f)));
 	} elsif ($_ <= 0xffff) {
 	    pack ("C3", 
 		  (0xe0 | (($_ >> 12) & 0xf)),
 		  (0x80 | (($_ >> 6) & 0x3f)),
 		  (0x80 | ($_ & 0x3f)));
 	} elsif ($_ <= 0x1fffff) {
 	    pack ("C4", 
 		  (0xf0 | (($_ >> 18) & 0x7)),
 		  (0x80 | (($_ >> 12) & 0x3f)),
 		  (0x80 | (($_ >> 6) & 0x3f)),
 		  (0x80 | ($_ & 0x3f)));
 	} elsif ($_ <= 0x3ffffff) {
 	    pack ("C5", 
 		  (0xf0 | (($_ >> 24) & 0x3)),
 		  (0x80 | (($_ >> 18) & 0x3f)),
 		  (0x80 | (($_ >> 12) & 0x3f)),
 		  (0x80 | (($_ >> 6) & 0x3f)),
 		  (0x80 | ($_ & 0x3f)));
 	} else {
 	    pack ("C6", 
 		  (0xf0 | (($_ >> 30) & 0x3)),
 		  (0x80 | (($_ >> 24) & 0x1)),
 		  (0x80 | (($_ >> 18) & 0x3f)),
 		  (0x80 | (($_ >> 12) & 0x3f)),
 		  (0x80 | (($_ >> 6) & 0x3f)),
 		  (0x80 | ($_ & 0x3f)));
 	}
     } @{$_[1]};
     return 1;
 }
 
 # Decode UTF-8 into integers.  We do not bother to care about possibly
 # configured replacement characters here and simply fall back to 0xfffd.
 # Rationale: the internal format is never output directly and the other
 # encoders will handle the replacement character correctly.
 sub _toInternal
 {
     if ($] >= 5.006) {
 	$_[1] = [ unpack "U*", $_[1] ];
 	return 1;
     }
 
     # Sigh, we have to decode ourselves.  FIXME: Should be optimized.
     # The routine is awfully slow.
     # It also does not necessarily detect illegal multi-byte sequences.
 
     my @chars = ();
     my @bytes = unpack "C*", $_[1];
 
     BYTE: while (@bytes) {
 	my $byte = shift @bytes;
         if ($byte < 0x80) {
             push @chars, $byte;
         } elsif ($byte < 0xc0 || $byte > 0xfd) {
             push @chars, 0xfffd;
         } else {
             my $num_bytes;
             my $char;
             if ($byte < 0xe0) {
                 $char = $byte & 0x1f;
                 $num_bytes = 1;
             } elsif ($byte < 0xf0) {
                 $char = $byte & 0xf;
                 $num_bytes = 2;
             } elsif ($byte < 0xf8) {
                 $char = $byte & 0x7;
                 $num_bytes = 3;
             } elsif ($byte < 0xfc) {
                 $char = $byte & 0x3;
                 $num_bytes = 4;
             } else {
                 $char = $byte & 0x1;
                 $num_bytes = 5;
             }
             for (my $i = 0; $i < $num_bytes; ++$i) {
                 my $next = shift @bytes;
                 if (!defined $next || $next < 0x80 || $next > 0xbf) {
                     push @chars, 0xfffd;
                     next BYTE;
                 } else {
                     $char <<= 6;
                     $char |= $next & 0x3f;
                 }
             }
             push @chars, $char;
         }
     }
     
     $_[1] = \@chars;
     
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::UTF_8 - Conversion routines for UTF-8
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This modules contains the conversion tables for UTF-8.  It is capable of
 converting from UTF-8 to the internal format of libintl-perl and vice
 versa.   It is only suitable for Perl versions E<lt>= 5.8.0.  However,
 you do not have to bother about version checking, Locale::Recode(3)
 will do that for you.
 
 
 =head1 CHARACTER TABLE
 
 See http://www.unicode.org/.
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/VISCII.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Conversion routines for VISCII.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::VISCII;
 
 use strict;
 
 require Locale::RecodeData;
 use base qw(Locale::RecodeData);
 
 my @to_ucs4 = (
     0x0000,
     0x0001,
     0x1eb2,
     0x0003,
     0x0004,
     0x1eb4,
     0x1eaa,
     0x0007,
     0x0008,
     0x0009,
     0x000a,
     0x000b,
     0x000c,
     0x000d,
     0x000e,
     0x000f,
     0x0010,
     0x0011,
     0x0012,
     0x0013,
     0x1ef6,
     0x0015,
     0x0016,
     0x0017,
     0x0018,
     0x1ef8,
     0x001a,
     0x001b,
     0x001c,
     0x001d,
     0x1ef4,
     0x001f,
     0x0020,
     0x0021,
     0x0022,
     0x0023,
     0x0024,
     0x0025,
     0x0026,
     0x0027,
     0x0028,
     0x0029,
     0x002a,
     0x002b,
     0x002c,
     0x002d,
     0x002e,
     0x002f,
     0x0030,
     0x0031,
     0x0032,
     0x0033,
     0x0034,
     0x0035,
     0x0036,
     0x0037,
     0x0038,
     0x0039,
     0x003a,
     0x003b,
     0x003c,
     0x003d,
     0x003e,
     0x003f,
     0x0040,
     0x0041,
     0x0042,
     0x0043,
     0x0044,
     0x0045,
     0x0046,
     0x0047,
     0x0048,
     0x0049,
     0x004a,
     0x004b,
     0x004c,
     0x004d,
     0x004e,
     0x004f,
     0x0050,
     0x0051,
     0x0052,
     0x0053,
     0x0054,
     0x0055,
     0x0056,
     0x0057,
     0x0058,
     0x0059,
     0x005a,
     0x005b,
     0x005c,
     0x005d,
     0x005e,
     0x005f,
     0x0060,
     0x0061,
     0x0062,
     0x0063,
     0x0064,
     0x0065,
     0x0066,
     0x0067,
     0x0068,
     0x0069,
     0x006a,
     0x006b,
     0x006c,
     0x006d,
     0x006e,
     0x006f,
     0x0070,
     0x0071,
     0x0072,
     0x0073,
     0x0074,
     0x0075,
     0x0076,
     0x0077,
     0x0078,
     0x0079,
     0x007a,
     0x007b,
     0x007c,
     0x007d,
     0x007e,
     0x007f,
     0x1ea0,
     0x1eae,
     0x1eb0,
     0x1eb6,
     0x1ea4,
     0x1ea6,
     0x1ea8,
     0x1eac,
     0x1ebc,
     0x1eb8,
     0x1ebe,
     0x1ec0,
     0x1ec2,
     0x1ec4,
     0x1ec6,
     0x1ed0,
     0x1ed2,
     0x1ed4,
     0x1ed6,
     0x1ed8,
     0x1ee2,
     0x1eda,
     0x1edc,
     0x1ede,
     0x1eca,
     0x1ece,
     0x1ecc,
     0x1ec8,
     0x1ee6,
     0x0168,
     0x1ee4,
     0x1ef2,
     0x00d5,
     0x1eaf,
     0x1eb1,
     0x1eb7,
     0x1ea5,
     0x1ea7,
     0x1ea9,
     0x1ead,
     0x1ebd,
     0x1eb9,
     0x1ebf,
     0x1ec1,
     0x1ec3,
     0x1ec5,
     0x1ec7,
     0x1ed1,
     0x1ed3,
     0x1ed5,
     0x1ed7,
     0x1ee0,
     0x01a0,
     0x1ed9,
     0x1edd,
     0x1edf,
     0x1ecb,
     0x1ef0,
     0x1ee8,
     0x1eea,
     0x1eec,
     0x01a1,
     0x1edb,
     0x01af,
     0x00c0,
     0x00c1,
     0x00c2,
     0x00c3,
     0x1ea2,
     0x0102,
     0x1eb3,
     0x1eb5,
     0x00c8,
     0x00c9,
     0x00ca,
     0x1eba,
     0x00cc,
     0x00cd,
     0x0128,
     0x1ef3,
     0x0110,
     0x1ee9,
     0x00d2,
     0x00d3,
     0x00d4,
     0x1ea1,
     0x1ef7,
     0x1eeb,
     0x1eed,
     0x00d9,
     0x00da,
     0x1ef9,
     0x1ef5,
     0x00dd,
     0x1ee1,
     0x01b0,
     0x00e0,
     0x00e1,
     0x00e2,
     0x00e3,
     0x1ea3,
     0x0103,
     0x1eef,
     0x1eab,
     0x00e8,
     0x00e9,
     0x00ea,
     0x1ebb,
     0x00ec,
     0x00ed,
     0x0129,
     0x1ec9,
     0x0111,
     0x1ef1,
     0x00f2,
     0x00f3,
     0x00f4,
     0x00f5,
     0x1ecf,
     0x1ecd,
     0x1ee5,
     0x00f9,
     0x00fa,
     0x0169,
     0x1ee7,
     0x00fd,
     0x1ee3,
     0x1eee,
 );
 
 my @to_utf8 = (
     "\x00",
     "\x01",
     "\xe1\xba\xb2",
     "\x03",
     "\x04",
     "\xe1\xba\xb4",
     "\xe1\xba\xaa",
     "\x07",
     "\x08",
     "\x09",
     "\x0a",
     "\x0b",
     "\x0c",
     "\x0d",
     "\x0e",
     "\x0f",
     "\x10",
     "\x11",
     "\x12",
     "\x13",
     "\xe1\xbb\xb6",
     "\x15",
     "\x16",
     "\x17",
     "\x18",
     "\xe1\xbb\xb8",
     "\x1a",
     "\x1b",
     "\x1c",
     "\x1d",
     "\xe1\xbb\xb4",
     "\x1f",
     "\x20",
     "\x21",
     "\x22",
     "\x23",
     "\x24",
     "\x25",
     "\x26",
     "\x27",
     "\x28",
     "\x29",
     "\x2a",
     "\x2b",
     "\x2c",
     "\x2d",
     "\x2e",
     "\x2f",
     "\x30",
     "\x31",
     "\x32",
     "\x33",
     "\x34",
     "\x35",
     "\x36",
     "\x37",
     "\x38",
     "\x39",
     "\x3a",
     "\x3b",
     "\x3c",
     "\x3d",
     "\x3e",
     "\x3f",
     "\x40",
     "\x41",
     "\x42",
     "\x43",
     "\x44",
     "\x45",
     "\x46",
     "\x47",
     "\x48",
     "\x49",
     "\x4a",
     "\x4b",
     "\x4c",
     "\x4d",
     "\x4e",
     "\x4f",
     "\x50",
     "\x51",
     "\x52",
     "\x53",
     "\x54",
     "\x55",
     "\x56",
     "\x57",
     "\x58",
     "\x59",
     "\x5a",
     "\x5b",
     "\x5c",
     "\x5d",
     "\x5e",
     "\x5f",
     "\x60",
     "\x61",
     "\x62",
     "\x63",
     "\x64",
     "\x65",
     "\x66",
     "\x67",
     "\x68",
     "\x69",
     "\x6a",
     "\x6b",
     "\x6c",
     "\x6d",
     "\x6e",
     "\x6f",
     "\x70",
     "\x71",
     "\x72",
     "\x73",
     "\x74",
     "\x75",
     "\x76",
     "\x77",
     "\x78",
     "\x79",
     "\x7a",
     "\x7b",
     "\x7c",
     "\x7d",
     "\x7e",
     "\x7f",
     "\xe1\xba\xa0",
     "\xe1\xba\xae",
     "\xe1\xba\xb0",
     "\xe1\xba\xb6",
     "\xe1\xba\xa4",
     "\xe1\xba\xa6",
     "\xe1\xba\xa8",
     "\xe1\xba\xac",
     "\xe1\xba\xbc",
     "\xe1\xba\xb8",
     "\xe1\xba\xbe",
     "\xe1\xbb\x80",
     "\xe1\xbb\x82",
     "\xe1\xbb\x84",
     "\xe1\xbb\x86",
     "\xe1\xbb\x90",
     "\xe1\xbb\x92",
     "\xe1\xbb\x94",
     "\xe1\xbb\x96",
     "\xe1\xbb\x98",
     "\xe1\xbb\xa2",
     "\xe1\xbb\x9a",
     "\xe1\xbb\x9c",
     "\xe1\xbb\x9e",
     "\xe1\xbb\x8a",
     "\xe1\xbb\x8e",
     "\xe1\xbb\x8c",
     "\xe1\xbb\x88",
     "\xe1\xbb\xa6",
     "\xc5\xa8",
     "\xe1\xbb\xa4",
     "\xe1\xbb\xb2",
     "\xc3\x95",
     "\xe1\xba\xaf",
     "\xe1\xba\xb1",
     "\xe1\xba\xb7",
     "\xe1\xba\xa5",
     "\xe1\xba\xa7",
     "\xe1\xba\xa9",
     "\xe1\xba\xad",
     "\xe1\xba\xbd",
     "\xe1\xba\xb9",
     "\xe1\xba\xbf",
     "\xe1\xbb\x81",
     "\xe1\xbb\x83",
     "\xe1\xbb\x85",
     "\xe1\xbb\x87",
     "\xe1\xbb\x91",
     "\xe1\xbb\x93",
     "\xe1\xbb\x95",
     "\xe1\xbb\x97",
     "\xe1\xbb\xa0",
     "\xc6\xa0",
     "\xe1\xbb\x99",
     "\xe1\xbb\x9d",
     "\xe1\xbb\x9f",
     "\xe1\xbb\x8b",
     "\xe1\xbb\xb0",
     "\xe1\xbb\xa8",
     "\xe1\xbb\xaa",
     "\xe1\xbb\xac",
     "\xc6\xa1",
     "\xe1\xbb\x9b",
     "\xc6\xaf",
     "\xc3\x80",
     "\xc3\x81",
     "\xc3\x82",
     "\xc3\x83",
     "\xe1\xba\xa2",
     "\xc4\x82",
     "\xe1\xba\xb3",
     "\xe1\xba\xb5",
     "\xc3\x88",
     "\xc3\x89",
     "\xc3\x8a",
     "\xe1\xba\xba",
     "\xc3\x8c",
     "\xc3\x8d",
     "\xc4\xa8",
     "\xe1\xbb\xb3",
     "\xc4\x90",
     "\xe1\xbb\xa9",
     "\xc3\x92",
     "\xc3\x93",
     "\xc3\x94",
     "\xe1\xba\xa1",
     "\xe1\xbb\xb7",
     "\xe1\xbb\xab",
     "\xe1\xbb\xad",
     "\xc3\x99",
     "\xc3\x9a",
     "\xe1\xbb\xb9",
     "\xe1\xbb\xb5",
     "\xc3\x9d",
     "\xe1\xbb\xa1",
     "\xc6\xb0",
     "\xc3\xa0",
     "\xc3\xa1",
     "\xc3\xa2",
     "\xc3\xa3",
     "\xe1\xba\xa3",
     "\xc4\x83",
     "\xe1\xbb\xaf",
     "\xe1\xba\xab",
     "\xc3\xa8",
     "\xc3\xa9",
     "\xc3\xaa",
     "\xe1\xba\xbb",
     "\xc3\xac",
     "\xc3\xad",
     "\xc4\xa9",
     "\xe1\xbb\x89",
     "\xc4\x91",
     "\xe1\xbb\xb1",
     "\xc3\xb2",
     "\xc3\xb3",
     "\xc3\xb4",
     "\xc3\xb5",
     "\xe1\xbb\x8f",
     "\xe1\xbb\x8d",
     "\xe1\xbb\xa5",
     "\xc3\xb9",
     "\xc3\xba",
     "\xc5\xa9",
     "\xe1\xbb\xa7",
     "\xc3\xbd",
     "\xe1\xbb\xa3",
     "\xe1\xbb\xae",
 );
 
 my %from_ucs4 = (
     0x00000000 => "\x00",
     0x00000001 => "\x01",
     0x00000003 => "\x03",
     0x00000004 => "\x04",
     0x00000007 => "\x07",
     0x00000008 => "\x08",
     0x00000009 => "\x09",
     0x0000000a => "\x0a",
     0x0000000b => "\x0b",
     0x0000000c => "\x0c",
     0x0000000d => "\x0d",
     0x0000000e => "\x0e",
     0x0000000f => "\x0f",
     0x00000010 => "\x10",
     0x00000011 => "\x11",
     0x00000012 => "\x12",
     0x00000013 => "\x13",
     0x00000015 => "\x15",
     0x00000016 => "\x16",
     0x00000017 => "\x17",
     0x00000018 => "\x18",
     0x0000001a => "\x1a",
     0x0000001b => "\x1b",
     0x0000001c => "\x1c",
     0x0000001d => "\x1d",
     0x0000001f => "\x1f",
     0x00000020 => "\x20",
     0x00000021 => "\x21",
     0x00000022 => "\x22",
     0x00000023 => "\x23",
     0x00000024 => "\x24",
     0x00000025 => "\x25",
     0x00000026 => "\x26",
     0x00000027 => "\x27",
     0x00000028 => "\x28",
     0x00000029 => "\x29",
     0x0000002a => "\x2a",
     0x0000002b => "\x2b",
     0x0000002c => "\x2c",
     0x0000002d => "\x2d",
     0x0000002e => "\x2e",
     0x0000002f => "\x2f",
     0x00000030 => "\x30",
     0x00000031 => "\x31",
     0x00000032 => "\x32",
     0x00000033 => "\x33",
     0x00000034 => "\x34",
     0x00000035 => "\x35",
     0x00000036 => "\x36",
     0x00000037 => "\x37",
     0x00000038 => "\x38",
     0x00000039 => "\x39",
     0x0000003a => "\x3a",
     0x0000003b => "\x3b",
     0x0000003c => "\x3c",
     0x0000003d => "\x3d",
     0x0000003e => "\x3e",
     0x0000003f => "\x3f",
     0x00000040 => "\x40",
     0x00000041 => "\x41",
     0x00000042 => "\x42",
     0x00000043 => "\x43",
     0x00000044 => "\x44",
     0x00000045 => "\x45",
     0x00000046 => "\x46",
     0x00000047 => "\x47",
     0x00000048 => "\x48",
     0x00000049 => "\x49",
     0x0000004a => "\x4a",
     0x0000004b => "\x4b",
     0x0000004c => "\x4c",
     0x0000004d => "\x4d",
     0x0000004e => "\x4e",
     0x0000004f => "\x4f",
     0x00000050 => "\x50",
     0x00000051 => "\x51",
     0x00000052 => "\x52",
     0x00000053 => "\x53",
     0x00000054 => "\x54",
     0x00000055 => "\x55",
     0x00000056 => "\x56",
     0x00000057 => "\x57",
     0x00000058 => "\x58",
     0x00000059 => "\x59",
     0x0000005a => "\x5a",
     0x0000005b => "\x5b",
     0x0000005c => "\x5c",
     0x0000005d => "\x5d",
     0x0000005e => "\x5e",
     0x0000005f => "\x5f",
     0x00000060 => "\x60",
     0x00000061 => "\x61",
     0x00000062 => "\x62",
     0x00000063 => "\x63",
     0x00000064 => "\x64",
     0x00000065 => "\x65",
     0x00000066 => "\x66",
     0x00000067 => "\x67",
     0x00000068 => "\x68",
     0x00000069 => "\x69",
     0x0000006a => "\x6a",
     0x0000006b => "\x6b",
     0x0000006c => "\x6c",
     0x0000006d => "\x6d",
     0x0000006e => "\x6e",
     0x0000006f => "\x6f",
     0x00000070 => "\x70",
     0x00000071 => "\x71",
     0x00000072 => "\x72",
     0x00000073 => "\x73",
     0x00000074 => "\x74",
     0x00000075 => "\x75",
     0x00000076 => "\x76",
     0x00000077 => "\x77",
     0x00000078 => "\x78",
     0x00000079 => "\x79",
     0x0000007a => "\x7a",
     0x0000007b => "\x7b",
     0x0000007c => "\x7c",
     0x0000007d => "\x7d",
     0x0000007e => "\x7e",
     0x0000007f => "\x7f",
     0x000000c0 => "\xc0",
     0x000000c1 => "\xc1",
     0x000000c2 => "\xc2",
     0x000000c3 => "\xc3",
     0x000000c8 => "\xc8",
     0x000000c9 => "\xc9",
     0x000000ca => "\xca",
     0x000000cc => "\xcc",
     0x000000cd => "\xcd",
     0x000000d2 => "\xd2",
     0x000000d3 => "\xd3",
     0x000000d4 => "\xd4",
     0x000000d5 => "\xa0",
     0x000000d9 => "\xd9",
     0x000000da => "\xda",
     0x000000dd => "\xdd",
     0x000000e0 => "\xe0",
     0x000000e1 => "\xe1",
     0x000000e2 => "\xe2",
     0x000000e3 => "\xe3",
     0x000000e8 => "\xe8",
     0x000000e9 => "\xe9",
     0x000000ea => "\xea",
     0x000000ec => "\xec",
     0x000000ed => "\xed",
     0x000000f2 => "\xf2",
     0x000000f3 => "\xf3",
     0x000000f4 => "\xf4",
     0x000000f5 => "\xf5",
     0x000000f9 => "\xf9",
     0x000000fa => "\xfa",
     0x000000fd => "\xfd",
     0x00000102 => "\xc5",
     0x00000103 => "\xe5",
     0x00000110 => "\xd0",
     0x00000111 => "\xf0",
     0x00000128 => "\xce",
     0x00000129 => "\xee",
     0x00000168 => "\x9d",
     0x00000169 => "\xfb",
     0x000001a0 => "\xb4",
     0x000001a1 => "\xbd",
     0x000001af => "\xbf",
     0x000001b0 => "\xdf",
     0x00001ea0 => "\x80",
     0x00001ea1 => "\xd5",
     0x00001ea2 => "\xc4",
     0x00001ea3 => "\xe4",
     0x00001ea4 => "\x84",
     0x00001ea5 => "\xa4",
     0x00001ea6 => "\x85",
     0x00001ea7 => "\xa5",
     0x00001ea8 => "\x86",
     0x00001ea9 => "\xa6",
     0x00001eaa => "\x06",
     0x00001eab => "\xe7",
     0x00001eac => "\x87",
     0x00001ead => "\xa7",
     0x00001eae => "\x81",
     0x00001eaf => "\xa1",
     0x00001eb0 => "\x82",
     0x00001eb1 => "\xa2",
     0x00001eb2 => "\x02",
     0x00001eb3 => "\xc6",
     0x00001eb4 => "\x05",
     0x00001eb5 => "\xc7",
     0x00001eb6 => "\x83",
     0x00001eb7 => "\xa3",
     0x00001eb8 => "\x89",
     0x00001eb9 => "\xa9",
     0x00001eba => "\xcb",
     0x00001ebb => "\xeb",
     0x00001ebc => "\x88",
     0x00001ebd => "\xa8",
     0x00001ebe => "\x8a",
     0x00001ebf => "\xaa",
     0x00001ec0 => "\x8b",
     0x00001ec1 => "\xab",
     0x00001ec2 => "\x8c",
     0x00001ec3 => "\xac",
     0x00001ec4 => "\x8d",
     0x00001ec5 => "\xad",
     0x00001ec6 => "\x8e",
     0x00001ec7 => "\xae",
     0x00001ec8 => "\x9b",
     0x00001ec9 => "\xef",
     0x00001eca => "\x98",
     0x00001ecb => "\xb8",
     0x00001ecc => "\x9a",
     0x00001ecd => "\xf7",
     0x00001ece => "\x99",
     0x00001ecf => "\xf6",
     0x00001ed0 => "\x8f",
     0x00001ed1 => "\xaf",
     0x00001ed2 => "\x90",
     0x00001ed3 => "\xb0",
     0x00001ed4 => "\x91",
     0x00001ed5 => "\xb1",
     0x00001ed6 => "\x92",
     0x00001ed7 => "\xb2",
     0x00001ed8 => "\x93",
     0x00001ed9 => "\xb5",
     0x00001eda => "\x95",
     0x00001edb => "\xbe",
     0x00001edc => "\x96",
     0x00001edd => "\xb6",
     0x00001ede => "\x97",
     0x00001edf => "\xb7",
     0x00001ee0 => "\xb3",
     0x00001ee1 => "\xde",
     0x00001ee2 => "\x94",
     0x00001ee3 => "\xfe",
     0x00001ee4 => "\x9e",
     0x00001ee5 => "\xf8",
     0x00001ee6 => "\x9c",
     0x00001ee7 => "\xfc",
     0x00001ee8 => "\xba",
     0x00001ee9 => "\xd1",
     0x00001eea => "\xbb",
     0x00001eeb => "\xd7",
     0x00001eec => "\xbc",
     0x00001eed => "\xd8",
     0x00001eee => "\xff",
     0x00001eef => "\xe6",
     0x00001ef0 => "\xb9",
     0x00001ef1 => "\xf1",
     0x00001ef2 => "\x9f",
     0x00001ef3 => "\xcf",
     0x00001ef4 => "\x1e",
     0x00001ef5 => "\xdc",
     0x00001ef6 => "\x14",
     0x00001ef7 => "\xd6",
     0x00001ef8 => "\x19",
     0x00001ef9 => "\xdb",
 );
 
 sub _recode
 {
     if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = join '',
 	        map $from_ucs4{$_} 
                 || (defined $from_ucs4{$_} ? $from_ucs4{$_} : "\x3f"),
 		    @{$_[1]};
     } elsif ($_[0]->{_to} eq 'UTF-8',) {
 		$_[1] = join '', map $to_utf8[$_], unpack 'C*', $_[1];
     } else {
 		$_[1] = [ map 
 				  $to_ucs4[$_],
 				  unpack 'C*', $_[1] 
 				  ];
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::VISCII - Conversion routines for VISCII
 
 =head1 SYNOPSIS
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module is generated and contains the conversion tables and
 routines for VISCII.
 =head1 CHARACTER TABLE
 
 The following table is sorted in the same order as the original charmap.
 All character codes are in hexadecimal.  Please read 'ISO-10646' as
 'ISO-10646-UCS4'.
 
  Local | ISO-10646 | Description
 -------+-----------+-------------------------------------------------
     00 |  00000000 | NULL (NUL)
     01 |  00000001 | START OF HEADING (SOH)
     02 |  00001EB2 | LATIN CAPITAL LETTER A WITH BREVE AND HOOK ABOVE
     03 |  00000003 | END OF TEXT (ETX)
     04 |  00000004 | END OF TRANSMISSION (EOT)
     05 |  00001EB4 | LATIN CAPITAL LETTER A WITH BREVE AND TILDE
     06 |  00001EAA | LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND TILDE
     07 |  00000007 | BELL (BEL)
     08 |  00000008 | BACKSPACE (BS)
     09 |  00000009 | CHARACTER TABULATION (HT)
     0A |  0000000A | LINE FEED (LF)
     0B |  0000000B | LINE TABULATION (VT)
     0C |  0000000C | FORM FEED (FF)
     0D |  0000000D | CARRIAGE RETURN (CR)
     0E |  0000000E | SHIFT OUT (SO)
     0F |  0000000F | SHIFT IN (SI)
     10 |  00000010 | DATALINK ESCAPE (DLE)
     11 |  00000011 | DEVICE CONTROL ONE (DC1)
     12 |  00000012 | DEVICE CONTROL TWO (DC2)
     13 |  00000013 | DEVICE CONTROL THREE (DC3)
     14 |  00001EF6 | LATIN CAPITAL LETTER Y WITH HOOK ABOVE
     15 |  00000015 | NEGATIVE ACKNOWLEDGE (NAK)
     16 |  00000016 | SYNCHRONOUS IDLE (SYN)
     17 |  00000017 | END OF TRANSMISSION BLOCK (ETB)
     18 |  00000018 | CANCEL (CAN)
     19 |  00001EF8 | LATIN CAPITAL LETTER Y WITH TILDE
     1A |  0000001A | SUBSTITUTE (SUB)
     1B |  0000001B | ESCAPE (ESC)
     1C |  0000001C | FILE SEPARATOR (IS4)
     1D |  0000001D | GROUP SEPARATOR (IS3)
     1E |  00001EF4 | LATIN CAPITAL LETTER Y WITH DOT BELOW
     1F |  0000001F | UNIT SEPARATOR (IS1)
     20 |  00000020 | SPACE
     21 |  00000021 | EXCLAMATION MARK
     22 |  00000022 | QUOTATION MARK
     23 |  00000023 | NUMBER SIGN
     24 |  00000024 | DOLLAR SIGN
     25 |  00000025 | PERCENT SIGN
     26 |  00000026 | AMPERSAND
     27 |  00000027 | APOSTROPHE
     28 |  00000028 | LEFT PARENTHESIS
     29 |  00000029 | RIGHT PARENTHESIS
     2A |  0000002A | ASTERISK
     2B |  0000002B | PLUS SIGN
     2C |  0000002C | COMMA
     2D |  0000002D | HYPHEN-MINUS
     2E |  0000002E | FULL STOP
     2F |  0000002F | SOLIDUS
     30 |  00000030 | DIGIT ZERO
     31 |  00000031 | DIGIT ONE
     32 |  00000032 | DIGIT TWO
     33 |  00000033 | DIGIT THREE
     34 |  00000034 | DIGIT FOUR
     35 |  00000035 | DIGIT FIVE
     36 |  00000036 | DIGIT SIX
     37 |  00000037 | DIGIT SEVEN
     38 |  00000038 | DIGIT EIGHT
     39 |  00000039 | DIGIT NINE
     3A |  0000003A | COLON
     3B |  0000003B | SEMICOLON
     3C |  0000003C | LESS-THAN SIGN
     3D |  0000003D | EQUALS SIGN
     3E |  0000003E | GREATER-THAN SIGN
     3F |  0000003F | QUESTION MARK
     40 |  00000040 | COMMERCIAL AT
     41 |  00000041 | LATIN CAPITAL LETTER A
     42 |  00000042 | LATIN CAPITAL LETTER B
     43 |  00000043 | LATIN CAPITAL LETTER C
     44 |  00000044 | LATIN CAPITAL LETTER D
     45 |  00000045 | LATIN CAPITAL LETTER E
     46 |  00000046 | LATIN CAPITAL LETTER F
     47 |  00000047 | LATIN CAPITAL LETTER G
     48 |  00000048 | LATIN CAPITAL LETTER H
     49 |  00000049 | LATIN CAPITAL LETTER I
     4A |  0000004A | LATIN CAPITAL LETTER J
     4B |  0000004B | LATIN CAPITAL LETTER K
     4C |  0000004C | LATIN CAPITAL LETTER L
     4D |  0000004D | LATIN CAPITAL LETTER M
     4E |  0000004E | LATIN CAPITAL LETTER N
     4F |  0000004F | LATIN CAPITAL LETTER O
     50 |  00000050 | LATIN CAPITAL LETTER P
     51 |  00000051 | LATIN CAPITAL LETTER Q
     52 |  00000052 | LATIN CAPITAL LETTER R
     53 |  00000053 | LATIN CAPITAL LETTER S
     54 |  00000054 | LATIN CAPITAL LETTER T
     55 |  00000055 | LATIN CAPITAL LETTER U
     56 |  00000056 | LATIN CAPITAL LETTER V
     57 |  00000057 | LATIN CAPITAL LETTER W
     58 |  00000058 | LATIN CAPITAL LETTER X
     59 |  00000059 | LATIN CAPITAL LETTER Y
     5A |  0000005A | LATIN CAPITAL LETTER Z
     5B |  0000005B | LEFT SQUARE BRACKET
     5C |  0000005C | REVERSE SOLIDUS
     5D |  0000005D | RIGHT SQUARE BRACKET
     5E |  0000005E | CIRCUMFLEX ACCENT
     5F |  0000005F | LOW LINE
     60 |  00000060 | GRAVE ACCENT
     61 |  00000061 | LATIN SMALL LETTER A
     62 |  00000062 | LATIN SMALL LETTER B
     63 |  00000063 | LATIN SMALL LETTER C
     64 |  00000064 | LATIN SMALL LETTER D
     65 |  00000065 | LATIN SMALL LETTER E
     66 |  00000066 | LATIN SMALL LETTER F
     67 |  00000067 | LATIN SMALL LETTER G
     68 |  00000068 | LATIN SMALL LETTER H
     69 |  00000069 | LATIN SMALL LETTER I
     6A |  0000006A | LATIN SMALL LETTER J
     6B |  0000006B | LATIN SMALL LETTER K
     6C |  0000006C | LATIN SMALL LETTER L
     6D |  0000006D | LATIN SMALL LETTER M
     6E |  0000006E | LATIN SMALL LETTER N
     6F |  0000006F | LATIN SMALL LETTER O
     70 |  00000070 | LATIN SMALL LETTER P
     71 |  00000071 | LATIN SMALL LETTER Q
     72 |  00000072 | LATIN SMALL LETTER R
     73 |  00000073 | LATIN SMALL LETTER S
     74 |  00000074 | LATIN SMALL LETTER T
     75 |  00000075 | LATIN SMALL LETTER U
     76 |  00000076 | LATIN SMALL LETTER V
     77 |  00000077 | LATIN SMALL LETTER W
     78 |  00000078 | LATIN SMALL LETTER X
     79 |  00000079 | LATIN SMALL LETTER Y
     7A |  0000007A | LATIN SMALL LETTER Z
     7B |  0000007B | LEFT CURLY BRACKET
     7C |  0000007C | VERTICAL LINE
     7D |  0000007D | RIGHT CURLY BRACKET
     7E |  0000007E | TILDE
     7F |  0000007F | DELETE (DEL)
     80 |  00001EA0 | LATIN CAPITAL LETTER A WITH DOT BELOW
     81 |  00001EAE | LATIN CAPITAL LETTER A WITH BREVE AND ACUTE
     82 |  00001EB0 | LATIN CAPITAL LETTER A WITH BREVE AND GRAVE
     83 |  00001EB6 | LATIN CAPITAL LETTER A WITH BREVE AND DOT BELOW
     84 |  00001EA4 | LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND ACUTE
     85 |  00001EA6 | LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND GRAVE
     86 |  00001EA8 | LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE
     87 |  00001EAC | LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND DOT BELOW
     88 |  00001EBC | LATIN CAPITAL LETTER E WITH TILDE
     89 |  00001EB8 | LATIN CAPITAL LETTER E WITH DOT BELOW
     8A |  00001EBE | LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND ACUTE
     8B |  00001EC0 | LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND GRAVE
     8C |  00001EC2 | LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE
     8D |  00001EC4 | LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND TILDE
     8E |  00001EC6 | LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND DOT BELOW
     8F |  00001ED0 | LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND ACUTE
     90 |  00001ED2 | LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND GRAVE
     91 |  00001ED4 | LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE
     92 |  00001ED6 | LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND TILDE
     93 |  00001ED8 | LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND DOT BELOW
     94 |  00001EE2 | LATIN CAPITAL LETTER O WITH HORN AND DOT BELOW
     95 |  00001EDA | LATIN CAPITAL LETTER O WITH HORN AND ACUTE
     96 |  00001EDC | LATIN CAPITAL LETTER O WITH HORN AND GRAVE
     97 |  00001EDE | LATIN CAPITAL LETTER O WITH HORN AND HOOK ABOVE
     98 |  00001ECA | LATIN CAPITAL LETTER I WITH DOT BELOW
     99 |  00001ECE | LATIN CAPITAL LETTER O WITH HOOK ABOVE
     9A |  00001ECC | LATIN CAPITAL LETTER O WITH DOT BELOW
     9B |  00001EC8 | LATIN CAPITAL LETTER I WITH HOOK ABOVE
     9C |  00001EE6 | LATIN CAPITAL LETTER U WITH HOOK ABOVE
     9D |  00000168 | LATIN CAPITAL LETTER U WITH TILDE
     9E |  00001EE4 | LATIN CAPITAL LETTER U WITH DOT BELOW
     9F |  00001EF2 | LATIN CAPITAL LETTER Y WITH GRAVE
     A0 |  000000D5 | LATIN CAPITAL LETTER O WITH TILDE
     A1 |  00001EAF | LATIN SMALL LETTER A WITH BREVE AND ACUTE
     A2 |  00001EB1 | LATIN SMALL LETTER A WITH BREVE AND GRAVE
     A3 |  00001EB7 | LATIN SMALL LETTER A WITH BREVE AND DOT BELOW
     A4 |  00001EA5 | LATIN SMALL LETTER A WITH CIRCUMFLEX AND ACUTE
     A5 |  00001EA7 | LATIN SMALL LETTER A WITH CIRCUMFLEX AND GRAVE
     A6 |  00001EA9 | LATIN SMALL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE
     A7 |  00001EAD | LATIN SMALL LETTER A WITH CIRCUMFLEX AND DOT BELOW
     A8 |  00001EBD | LATIN SMALL LETTER E WITH TILDE
     A9 |  00001EB9 | LATIN SMALL LETTER E WITH DOT BELOW
     AA |  00001EBF | LATIN SMALL LETTER E WITH CIRCUMFLEX AND ACUTE
     AB |  00001EC1 | LATIN SMALL LETTER E WITH CIRCUMFLEX AND GRAVE
     AC |  00001EC3 | LATIN SMALL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE
     AD |  00001EC5 | LATIN SMALL LETTER E WITH CIRCUMFLEX AND TILDE
     AE |  00001EC7 | LATIN SMALL LETTER E WITH CIRCUMFLEX AND DOT BELOW
     AF |  00001ED1 | LATIN SMALL LETTER O WITH CIRCUMFLEX AND ACUTE
     B0 |  00001ED3 | LATIN SMALL LETTER O WITH CIRCUMFLEX AND GRAVE
     B1 |  00001ED5 | LATIN SMALL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE
     B2 |  00001ED7 | LATIN SMALL LETTER O WITH CIRCUMFLEX AND TILDE
     B3 |  00001EE0 | LATIN CAPITAL LETTER O WITH HORN AND TILDE
     B4 |  000001A0 | LATIN CAPITAL LETTER O WITH HORN
     B5 |  00001ED9 | LATIN SMALL LETTER O WITH CIRCUMFLEX AND DOT BELOW
     B6 |  00001EDD | LATIN SMALL LETTER O WITH HORN AND GRAVE
     B7 |  00001EDF | LATIN SMALL LETTER O WITH HORN AND HOOK ABOVE
     B8 |  00001ECB | LATIN SMALL LETTER I WITH DOT BELOW
     B9 |  00001EF0 | LATIN CAPITAL LETTER U WITH HORN AND DOT BELOW
     BA |  00001EE8 | LATIN CAPITAL LETTER U WITH HORN AND ACUTE
     BB |  00001EEA | LATIN CAPITAL LETTER U WITH HORN AND GRAVE
     BC |  00001EEC | LATIN CAPITAL LETTER U WITH HORN AND HOOK ABOVE
     BD |  000001A1 | LATIN SMALL LETTER O WITH HORN
     BE |  00001EDB | LATIN SMALL LETTER O WITH HORN AND ACUTE
     BF |  000001AF | LATIN CAPITAL LETTER U WITH HORN
     C0 |  000000C0 | LATIN CAPITAL LETTER A WITH GRAVE
     C1 |  000000C1 | LATIN CAPITAL LETTER A WITH ACUTE
     C2 |  000000C2 | LATIN CAPITAL LETTER A WITH CIRCUMFLEX
     C3 |  000000C3 | LATIN CAPITAL LETTER A WITH TILDE
     C4 |  00001EA2 | LATIN CAPITAL LETTER A WITH HOOK ABOVE
     C5 |  00000102 | LATIN CAPITAL LETTER A WITH BREVE
     C6 |  00001EB3 | LATIN SMALL LETTER A WITH BREVE AND HOOK ABOVE
     C7 |  00001EB5 | LATIN SMALL LETTER A WITH BREVE AND TILDE
     C8 |  000000C8 | LATIN CAPITAL LETTER E WITH GRAVE
     C9 |  000000C9 | LATIN CAPITAL LETTER E WITH ACUTE
     CA |  000000CA | LATIN CAPITAL LETTER E WITH CIRCUMFLEX
     CB |  00001EBA | LATIN CAPITAL LETTER E WITH HOOK ABOVE
     CC |  000000CC | LATIN CAPITAL LETTER I WITH GRAVE
     CD |  000000CD | LATIN CAPITAL LETTER I WITH ACUTE
     CE |  00000128 | LATIN CAPITAL LETTER I WITH TILDE
     CF |  00001EF3 | LATIN SMALL LETTER Y WITH GRAVE
     D0 |  00000110 | LATIN CAPITAL LETTER D WITH STROKE
     D1 |  00001EE9 | LATIN SMALL LETTER U WITH HORN AND ACUTE
     D2 |  000000D2 | LATIN CAPITAL LETTER O WITH GRAVE
     D3 |  000000D3 | LATIN CAPITAL LETTER O WITH ACUTE
     D4 |  000000D4 | LATIN CAPITAL LETTER O WITH CIRCUMFLEX
     D5 |  00001EA1 | LATIN SMALL LETTER A WITH DOT BELOW
     D6 |  00001EF7 | LATIN SMALL LETTER Y WITH HOOK ABOVE
     D7 |  00001EEB | LATIN SMALL LETTER U WITH HORN AND GRAVE
     D8 |  00001EED | LATIN SMALL LETTER U WITH HORN AND HOOK ABOVE
     D9 |  000000D9 | LATIN CAPITAL LETTER U WITH GRAVE
     DA |  000000DA | LATIN CAPITAL LETTER U WITH ACUTE
     DB |  00001EF9 | LATIN SMALL LETTER Y WITH TILDE
     DC |  00001EF5 | LATIN SMALL LETTER Y WITH DOT BELOW
     DD |  000000DD | LATIN CAPITAL LETTER Y WITH ACUTE
     DE |  00001EE1 | LATIN SMALL LETTER O WITH HORN AND TILDE
     DF |  000001B0 | LATIN SMALL LETTER U WITH HORN
     E0 |  000000E0 | LATIN SMALL LETTER A WITH GRAVE
     E1 |  000000E1 | LATIN SMALL LETTER A WITH ACUTE
     E2 |  000000E2 | LATIN SMALL LETTER A WITH CIRCUMFLEX
     E3 |  000000E3 | LATIN SMALL LETTER A WITH TILDE
     E4 |  00001EA3 | LATIN SMALL LETTER A WITH HOOK ABOVE
     E5 |  00000103 | LATIN SMALL LETTER A WITH BREVE
     E6 |  00001EEF | LATIN SMALL LETTER U WITH HORN AND TILDE
     E7 |  00001EAB | LATIN SMALL LETTER A WITH CIRCUMFLEX AND TILDE
     E8 |  000000E8 | LATIN SMALL LETTER E WITH GRAVE
     E9 |  000000E9 | LATIN SMALL LETTER E WITH ACUTE
     EA |  000000EA | LATIN SMALL LETTER E WITH CIRCUMFLEX
     EB |  00001EBB | LATIN SMALL LETTER E WITH HOOK ABOVE
     EC |  000000EC | LATIN SMALL LETTER I WITH GRAVE
     ED |  000000ED | LATIN SMALL LETTER I WITH ACUTE
     EE |  00000129 | LATIN SMALL LETTER I WITH TILDE
     EF |  00001EC9 | LATIN SMALL LETTER I WITH HOOK ABOVE
     F0 |  00000111 | LATIN SMALL LETTER D WITH STROKE
     F1 |  00001EF1 | LATIN SMALL LETTER U WITH HORN AND DOT BELOW
     F2 |  000000F2 | LATIN SMALL LETTER O WITH GRAVE
     F3 |  000000F3 | LATIN SMALL LETTER O WITH ACUTE
     F4 |  000000F4 | LATIN SMALL LETTER O WITH CIRCUMFLEX
     F5 |  000000F5 | LATIN SMALL LETTER O WITH TILDE
     F6 |  00001ECF | LATIN SMALL LETTER O WITH HOOK ABOVE
     F7 |  00001ECD | LATIN SMALL LETTER O WITH DOT BELOW
     F8 |  00001EE5 | LATIN SMALL LETTER U WITH DOT BELOW
     F9 |  000000F9 | LATIN SMALL LETTER U WITH GRAVE
     FA |  000000FA | LATIN SMALL LETTER U WITH ACUTE
     FB |  00000169 | LATIN SMALL LETTER U WITH TILDE
     FC |  00001EE7 | LATIN SMALL LETTER U WITH HOOK ABOVE
     FD |  000000FD | LATIN SMALL LETTER Y WITH ACUTE
     FE |  00001EE3 | LATIN SMALL LETTER O WITH HORN AND DOT BELOW
     FF |  00001EEE | LATIN CAPITAL LETTER U WITH HORN AND TILDE
 
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::RecodeData(3), Locale::Recode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/RecodeData/_Encode.pm ###
 #! /bin/false
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Interface to Encode.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::RecodeData::_Encode;
 
 use strict;
 use integer;
 
 use Encode;
 
 require Locale::RecodeData;
 use base qw (Locale::RecodeData);
 
 sub _recode
 {
 	use bytes;
 
 	my $retval;
 	
 	if ($_[0]->{_from} eq 'INTERNAL') {
 		$_[1] = pack "N*", @{$_[1]};
 		$retval = Encode::from_to ($_[1], 'UTF-32BE', $_[0]->{_to});
 	} elsif ($_[0]->{_to} eq 'INTERNAL') {
 		$retval = Encode::from_to ($_[1], $_[0]->{_from}, 'UTF-32BE');
 		return unless defined $retval;
 		$_[1] = [ unpack "N*", $_[1] ];
 	} else {
 		$retval = Encode::from_to ($_[1], $_[0]->{_from}, $_[0]->{_to});
 	}
 	
 	return unless defined $retval;
 	return 1;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::RecodeData::_Encode - Internal wrapper around Encode 
 
 =head1 SYNOPSIS
 
 use Locale::RecodeData::_Encode;
 
 This module is internal to libintl.  Do not use directly!
 
 =head1 DESCRIPTION
 
 This module converts text with the help of Encode(3).  It is 
 tried first for conversions if libintl-perl detects the presence
 of Encode.
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::Recode(3), Encode(3), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/TextDomain.pm ###
 #! /bin/false
 
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # High-level interface to Perl i18n.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package __TiedTextDomain;
 
 use strict;
 
 sub TIEHASH
 {
     my ($class, $function) = @_;
     bless {
         __function => $function,
     }, $class;
 }
 
 sub FETCH
 {
     my ($self, $msg) = @_;
     
     &{$self->{__function}} ($msg);
 }
 
 sub FIRSTKEY
 {
     my $self = shift;
     my $reset_iterator = keys %$self;
     return scalar each %$self;
 }
 
 sub NEXTKEY
 {
     my $self = shift;
     return scalar each %$self;
 }
 
 sub CLEAR {}
 sub STORE {}
 sub DELETE {}
 
 1;
 
 package Locale::TextDomain;
 
 use strict;
 
 use Locale::Messages qw (textdomain bindtextdomain dgettext dngettext dpgettext dnpgettext);
 use Cwd qw (abs_path);
 
 use vars qw ($VERSION);
 
 $VERSION = '1.24';
 
 require Exporter;
 
 use vars qw (@ISA @EXPORT %__ $__);
 
 @ISA = ('Exporter');
 @EXPORT = qw (__ __x __n __nx __xn __p __px __np __npx $__ %__ 
               N__ N__n N__p N__np);
 
 my %textdomains = ();
 my %bound_dirs = ();
 my @default_dirs = ();
 
 sub __ ($);
 	
 sub __find_domain ($);
 sub __expand ($%);
 sub __tied_gettext ($$);
 
 BEGIN {
     # Tie the hash to gettext().
     tie %__, '__TiedTextDomain', \&__tied_gettext;
     $__ = \%__;
 
 	# Add default search directories, but only if they exist.
 	for my $dir (qw (/usr/share/locale /usr/local/share/locale)) {
         if (-d $dir) {
             @default_dirs = ($dir);
             last;
         }
     }
 }
 
 # Normal gettext.
 sub __ ($)
 {
     my $msgid = shift;
 	
     my $package = caller;
     
     my $textdomain = $textdomains{$package};
     
     __find_domain $textdomain if 
 		defined $textdomain && defined $bound_dirs{$textdomain};
     
     return dgettext $textdomain => $msgid;
 }
 
 # Called from tied hash.
 sub __tied_gettext ($$)
 {
     my ($msgid) = @_;
     
     my ($package) = caller (1);
     
     my $textdomain = $textdomains{$package};
     unless (defined $textdomain) {
 		my ($maybe_package, $filename, $line) = caller (2);
 		if (exists $textdomains{$maybe_package}) {
 			warn <<EOF;
 Probable use of \$__ or \%__ where __() should be used at $filename:$line.
 EOF
 		}
 	}
     __find_domain $textdomain if
 		defined $textdomain && defined $bound_dirs{$textdomain};
     
     return dgettext $textdomain => $msgid;
 }
 
 # With interpolation.
 sub __x ($@)
 {
     my ($msgid, %vars) = @_;
     
     my $package = caller;
     
     my $textdomain = $textdomains{$package};
     
     __find_domain $textdomain if
 		defined $textdomain && defined $bound_dirs{$textdomain};
     
     return __expand ((dgettext $textdomain => $msgid), %vars);
 }
 
 # Plural.
 sub __n ($$$)
 {
     my ($msgid, $msgid_plural, $count) = @_;
     
     my $package = caller;
     
     my $textdomain = $textdomains{$package};
     
     __find_domain $textdomain if
 		defined $textdomain && defined $bound_dirs{$textdomain};
     
     return dngettext $textdomain, $msgid, $msgid_plural, $count;
 }
 
 # Plural with interpolation.
 sub __nx ($$$@)
 {
     my ($msgid, $msgid_plural, $count, %args) = @_;
     
     my $package = caller;
     
     my $textdomain = $textdomains{$package};
     
     __find_domain $textdomain if
 		defined $textdomain && defined $bound_dirs{$textdomain};
     
     return __expand ((dngettext $textdomain, $msgid, $msgid_plural, $count),
 					 %args);
 }
 
 # Plural with interpolation.
 sub __xn ($$$@)
 {
     my ($msgid, $msgid_plural, $count, %args) = @_;
     
     my $package = caller;
     
     my $textdomain = $textdomains{$package};
     
     __find_domain $textdomain if
 		defined $textdomain && defined $bound_dirs{$textdomain};
     
     return __expand ((dngettext $textdomain, $msgid, $msgid_plural, $count),
 					 %args);
 }
 
 # Context. (p is for particular or special)
 sub __p ($$)
 {
     my $msgctxt = shift;
     my $msgid = shift;
 	
     my $package = caller;
     
     my $textdomain = $textdomains{$package};
     
     __find_domain $textdomain if 
 		defined $textdomain && defined $bound_dirs{$textdomain};
     
     return dpgettext $textdomain => $msgctxt, $msgid;
 }
 
 # With interpolation.
 sub __px ($$@)
 {
     my ($msgctxt, $msgid, %vars) = @_;
     
     my $package = caller;
     
     my $textdomain = $textdomains{$package};
     
     __find_domain $textdomain if
 		defined $textdomain && defined $bound_dirs{$textdomain};
     
     return __expand ((dpgettext $textdomain => $msgctxt, $msgid), %vars);
 }
 
 # Context + Plural.
 sub __np ($$$$)
 {
     my ($msgctxt, $msgid, $msgid_plural, $count) = @_;
     
     my $package = caller;
     
     my $textdomain = $textdomains{$package};
     
     __find_domain $textdomain if
 		defined $textdomain && defined $bound_dirs{$textdomain};
     
     return dnpgettext $textdomain, $msgctxt, $msgid, $msgid_plural, $count;
 }
 
 # Plural with interpolation.
 sub __npx ($$$$@)
 {
     my ($msgctxt, $msgid, $msgid_plural, $count, %args) = @_;
     
     my $package = caller;
     
     my $textdomain = $textdomains{$package};
     
     __find_domain $textdomain if
 		defined $textdomain && defined $bound_dirs{$textdomain};
     
     return __expand ((dnpgettext $textdomain, $msgctxt, $msgid, $msgid_plural, $count),
 					 %args);
 }
 
 # Dummy functions for string marking.
 sub N__($)
 {
     return shift;
 }
 
 sub N__n($$$)
 {
     return @_;
 }
 
 sub N__p($$) {
     return @_;
 }
 
 sub N__np($$$$) {
     return @_;
 }
 
 sub import
 {
     my ($self, $textdomain, @search_dirs) = @_;
     
     # Check our caller.
     my $package = caller;
     return if exists $textdomains{$package};
     
     # Was a textdomain specified?
 	$textdomain = textdomain unless defined $textdomain && length $textdomain;
     
     # Remember the textdomain of that package.
     $textdomains{$package} = $textdomain;
     
     # Remember that we still have to bind that textdomain to
     # a directory.
     unless (exists $bound_dirs{$textdomain}) {
 		unless (@search_dirs) {
 			@search_dirs = ((map $_ . '/LocaleData', @INC), @default_dirs)
 				unless @search_dirs;
 			if (my $share = eval {
 				require File::ShareDir;
 				File::ShareDir::dist_dir ($textdomain);
 			}) {
 				unshift @search_dirs, 
                         map { "$share/$_" }
                         qw (locale LocaleData);
             }
 		}
 		$bound_dirs{$textdomain} = [grep { -d $_ } @search_dirs];
     }
 	
     Locale::TextDomain->export_to_level (1, $package, @EXPORT);
     
     return;
 }
 
 # Private functions.
 sub __find_domain ($)
 {
 	my $domain = shift;
 	
 	my $try_dirs = $bound_dirs{$domain};
 	
 	if (defined $try_dirs) {
 		my $found_dir = '';
 		
 		TRYDIR: foreach my $dir (map { abs_path $_ } grep { -d $_ } @$try_dirs) {
 			# Is there a message catalog?  We have to search recursively
 			# for it.  Since globbing is reported to be buggy under
 			# MS-DOS, we roll our own version.
 			local *DIR;
 			if (opendir DIR, $dir) {
 				my @files = map { "$dir/$_/LC_MESSAGES/$domain.mo" } 
 					grep { ! /^\.\.?$/ } readdir DIR;
 
 				foreach my $file (@files) {
 					if (-f $file || -l $file) {
 						# If we find a non-readable file on our way,
 						# we access has been disabled on purpose.
 						# Therefore no -r check here.
 						$found_dir = $dir;
 						last TRYDIR;
 					}
 				}
 			}
 		}
 		
 		# If there was no success, this will fall back to the default search
 		# directories.
 		bindtextdomain $domain => $found_dir;
     }
     
     # The search has completed.
     undef $bound_dirs{$domain};
     
     return 1;
 }
 
 sub __expand ($%)
 {
     my ($translation, %args) = @_;
     
     my $re = join '|', map { quotemeta $_ } keys %args;
     $translation =~ s/\{($re)\}/defined $args{$1} ? $args{$1} : "{$1}"/ge;
     
     return $translation;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::TextDomain - Perl Interface to Uniforum Message Translation
 
 =head1 SYNOPSIS
 
  use Locale::TextDomain ('my-package', @locale_dirs);
  
  use Locale::TextDomain qw (my-package);
  
  my $translated = __"Hello World!\n";
  
  my $alt = $__{"Hello World!\n"};
  
  my $alt2 = $__->{"Hello World!\n"};
 
  my @list = (N__"Hello",
              N__"World");
  
  printf (__n ("one file read", 
               "%d files read", 
               $num_files),
          $num_files);
 
  print __nx ("one file read", "{num} files read", $num_files,
              num => $num_files);
 
  my $translated_context = __p ("Verb, to view", "View");
 
  printf (__np ("Files read from filesystems",
                "one file read", 
                "%d files read", 
                $num_files),
          $num_files);
 
  print __npx ("Files read from filesystems",
               "one file read", 
               "{num} files read", 
               $num_files,
               num => $num_files);
 
 
 =head1 DESCRIPTION
 
 The module Locale::TextDomain(3pm) provides a high-level interface
 to Perl message translation.
 
 =head2 Textdomains
 
 When you request a translation for a given string, the system used
 in libintl-perl follows a standard strategy to find a suitable message
 catalog containing the translation: Unless you explicitely define
 a name for the message catalog, libintl-perl will assume that your
 catalog is called 'messages' (unless you have changed the default
 value to something else via Locale::Messages(3pm), method textdomain()).
 
 You might think that his default strategy leaves room for optimization
 and you are right.  It would be a lot smarter if multiple software
 packages, all with their individual message catalogs, could be installed
 on one system, and it should also be possible that third-party
 components of your software (like Perl modules) can load their
 message catalogs, too, without interfering with yours.
 
 The solution is clear, you have to assign a unique name to your message
 database, and you have to specify that name at run-time.  That unique
 name is the so-called I<textdomain> of your software package.  The name is
 actually arbitrary but you should follow these best-practice guidelines
 to ensure maximum interoperability:
 
 =over 8
 
 =item File System Safety
 
 In practice, textdomains get mapped into file names, and you should
 therefore make sure that the textdomain you choose is a valid filename
 on every system that will run your software.
 
 =item Case-sensitivity
 
 Textdomains are always case-sensitive (i. e. 'Package' and 'PACKAGE'
 are not the same).  However, since the message catalogs will be stored
 on file systems, that may or may not distinguish case when looking
 up file names, you should avoid potential conflicts here.
 
 =item Textdomain Should Match CPAN Name
 
 If your software is listed as a module on CPAN, you should simply 
 choose the name on CPAN as your textdomain.  The textdomain for 
 libintl-perl is hence 'libintl-perl'.  But please replace all 
 periods ('.') in your package name with an underscore because ...
 
 =item Internet Domain Names as a Fallback
 
 ... if your software is I<not> a module listed on CPAN, as a last 
 resort you should use the Java(tm) package scheme, i. e. choose
 an internet domain that you are owner of (or ask the owner of an
 internet domain) and concatenate your preferred textdomain with the
 reversed internet domain.  Example: Your company runs the web-site
 'www.foobar.org' and is the owner of the domain 'foobar.org'.  The
 textdomain for your company's software 'barfoos' should hence be
 'org.foobar.barfoos'.
 
 =back
 
 If your software is likely to be installed in different versions on
 the same system, it is probably a good idea to append some version
 information to your textdomain.
 
 Other systems are less strict with the naming scheme for textdomains
 but the phenomena known as Perl is actually a plethora of small,
 specialized modules and it is probably wisest to postulate some
 namespace model in order to avoid chaos.
 
 =head2 Binding textdomains to directories
 
 Once the system knows the I<textdomain> of the message that you 
 want to get translated into the user's language, it still has to
 find the correct message catalog.  By default, libintl-perl will
 look up the string in the translation database found in the 
 directories F</usr/share/locale> and F</usr/local/share/locale>
 (in that order).
 
 It is neither guaranteed that these directories exist on the target
 machine, nor can you be sure that the installation routine has write 
 access to these locations.  You can therefore instruct libintl-perl 
 to search other directories prior to the default directories.  Specifying 
 a differnt search directory is called I<binding> a textdomain to a 
 directory.
 
 Beginning with version 1.20, B<Locale::TextDomain> extends the default 
 strategy by a Perl-specific approach.  If L<File::ShareDir> is installed, it 
 will look in the subdirectories named F<locale> and F<LocaleData> (in that 
 order) in the directory returned by C<File::ShareDir::dist_dir ($textdomain)>
 (if L<File::ShareDir> is installed),
 and check for a database containing the message for your textdomain there.
 This allows you to install your database in the Perl-specific shared directory
 using L<Module::Install>'s C<install_share> directive or the Dist::Zilla
 L<ShareDir plugin|Dist::Zilla::Plugin::ShareDir>.
 
 If L<File::ShareDir> is not availabe, or if Locale::TextDomain fails to find
 the translation files in the L<File::ShareDir> directory, it will next look in
 every directory found in the standard include path C<@INC>, and check for a
 database containing the message for your textdomain there. Example: If the
 path F</usr/lib/perl/5.8.0/site_perl> is in your C<@INC>, you can install your
 translation files in F</usr/lib/perl/5.8.0/site_perl/LocaleData>, and they
 will be found at run-time.
 
 =head1 USAGE
 
 It is crucial to remember that you use Locale::TextDomain(3) as
 specified in the section L</SYNOPSIS>, that means you have to 
 B<use> it, not B<require> it.  The module behaves quite differently 
 compared to other modules.
 
 The most significant difference is the meaning of the list passed
 as an argument to the use() function.  It actually works like this:
 
     use Locale::TextDomain (TEXTDOMAIN, DIRECTORY, ...)
 
 The first argument (the first string passed to use()) is the textdomain
 of your package, optionally followed by a list of directories to search
 I<instead> of the Perl-specific directories (see above: F</LocaleData>
 appended to a F<File::ShareDir> directory and every path in C<@INC>).
 
 If you are the author of a package 'barfoos', you will probably put
 the line
 
     use Locale::TextDomain 'barfoos';
 
 resp. for non-CPAN modules
 
     use Locale::TextDomain 'org.foobar.barfoos';
 
 in every module of your package that contains translatable strings. If
 your module has been installed properly, including the message catalogs,
 it will then be able to retrieve these translations at run-time.
 
 If you have not installed the translation database in a directory
 F<LocaleData> in the L<File::ShareDir> directory or the standard include
 path C<@INC> (or in the system directories F</usr/share/locale> resp.
 F</usr/local/share/locale>), you have to explicitely specify a search
 path by giving the names of directories (as strings!) as additional
 arguments to use():
 
     use Locale::TextDomain qw (barfoos ./dir1 ./dir2);
 
 Alternatively you can call the function bindtextdomain() with suitable
 arguments (see the entry for bindtextdomain() in 
 L<Locale::Messages/FUNCTIONS>).  If you do so, you should pass 
 C<undef> as an additional argument in order to avoid unnecessary
 lookups:
 
     use Locale::TextDomain ('barfoos', undef);
 
 You see that the arguments given to use() have nothing to do with
 what is imported into your namespace, but they are rather arguments
 to textdomain(), resp. bindtextdomain().  Does that mean that 
 B<Locale::TextDomain> exports nothing into your namespace? Umh, not
 exactly ... in fact it imports I<all> functions listed below into
 your namespace, and hence you should not define conflicting functions
 (and variables) yourself.
 
 So, why has Locale::TextDomain to be different from other modules?
 If you have ever written software in C and prepared it for 
 internationalization (i18n), you will probably have defined some
 preprocessor macros like:
 
     #define _(String) dgettext ("my-textdomain", String)
     #define N_(String) String
 
 You only have to define that once in C, and the textdomain for your
 package is automatically inserted into all gettext functions.  In 
 Perl there is no such mechanism (at least it is not portable,
 option -P) and using the gettext functions could become quite
 cumbersome without some extra fiddling:
 
     print dgettext ("my-textdomain", "Hello world!\n");
 
 This is no fun.  In C it would merely be a
 
     printf (_("Hello world!\n"));
 
 Perl has to be more concise and shorter than C ... see the next
 section for how you can use B<Locale::TextDomain> to end up in Perl 
 with a mere
 
     print __"Hello World!\n";
 
 =head1 EXPORTED FUNCTIONS
 
 All functions have quite funny names on purpose.  In fact the 
 purpose for that is quite clear: They should be short, operator-like,
 and they should not yell for conflicts with existing functions in
 I<your> namespace.  You will understand it, when you internationalize
 your first Perl program or module.  Preparing it is more like marking
 strings as being translatable than inserting function calls.  Here
 we go:
 
 =over 4
 
 =item B<__ MSGID>
 
 B<NOTE:> This is a I<double> underscore!
 
 The basic and most-used function.  It is a short-cut for a call
 to gettext() resp. dgettext(), and simply returns the translation for
 B<MSGID>.  If your old code reads like this:
 
     print "permission denied";
     
 You will now write:
 
     print __"permission denied";
 
 That's all, the string will be output in the user's preferred language,
 provided that you have installed a translation for it.
 
 Of course you can also use parentheses:
 
     print __("permission denied");
 
 Or even:
 
     print (__("permission denied"));
 
 In my eyes, the first version without parentheses looks best.
 
 =item B<__x MSGID, ID1 =E<gt> VAL1, ID2 =E<gt> VAL2, ...>
 
 One of the nicest features in Perl is its capability to interpolate
 variables into strings:
 
     print "This is the $color $thing.\n";
 
 This nice feature might con you into thinking that you could now
 write
 
     print __"This is the $color $thing.\n";
 
 Alas, that would be nice, but it is not possible.  Remember that the
 function __() serves both as an operator for translating strings 
 I<and> as a mark for translatable strings.  If the above string would
 get extracted from your Perl code, the un-interpolated form would
 end up in the message catalog because when parsing your code it
 is unpredictable what values the variables C<$thing> and C<$color>
 will have at run-time (this fact is most probably one of the reasons
 you have written your program for).
 
 However, at run-time, Perl will have interpolated the values already
 I<before> __() (resp. the underlying gettext() function) has seen the
 original string.  Consequently something like "This is the red car.\n"
 will be looked up in the message catalog, it will not be found (because
 only "This is the $color $thing.\n" is included in the database), 
 and the original, untranslated string will be returned.
 Honestly, because this is almost always an error, the xgettext(1)
 program will bail out with a fatal error when it comes across that
 string in your code.
 
 There are two workarounds for that:
 
     printf __"This is the %s %s.\n", $color, $thing;
 
 But that has several disadvantages: Your translator will only
 see the isolated string, and without the surrounding code it
 is almost impossible to interpret it correctly.  Of course, GNU
 emacs and other software capable of editing PO translation files
 will allow you to examine the context in the source code, but it
 is more likely that your translator will look for a less challenging
 translation project when she frequently comes across such messages.
 
 And even if she does understand the underlying programming, what
 if she has to reorder the color and the thing like in French:
 
     msgid "This is the red car.\n";
     msgstr "Cela est la voiture rouge.\n"
 
 Zut alors! While it is possible to reorder the arguments to printf()
 and friends, it requires a syntax that is is nothing that you want to 
 learn.
 
 So what? The Perl backend to GNU gettext has defined an alternative
 format for interpolatable strings:
 
     "This is the {color} {thing}.\n";
 
 Instead of Perl variables you use place-holders (legal Perl variables
 are also legal place-holders) in curly braces, and then you call
 
     print __x ("This is the {color} {thing}.\n", 
                thing => $thang,
                color => $color);
 
 The function __x() will take the additional hash and replace all
 occurencies of the hash keys in curly braces with the corresponding
 values.  Simple, readable, understandable to translators, what else
 would you want?  And if the translator forgets, misspells or otherwise
 messes up some "variables", the msgfmt(1) program, that is used to
 compile the textual translation file into its binary representation
 will even choke on these errors and refuse to compile the translation.
 
 =item B<__n MSGID, MSGID_PLURAL, COUNT>
 
 Whew! That looks complicated ... It is best explained with an example.
 We'll have another look at your vintage code:
 
     if ($files_deleted > 1) {
         print "All files have been deleted.\n";
     } else {
         print "One file has been deleted.\n";
     }
 
 Your intent is clear, you wanted to avoid the cumbersome
 "1 files deleted".  This is okay for English, but other languages
 have more than one plural form.  For example in Russian it makes
 a difference whether you want to say 1 file, 3 files or 6 files.
 You will use three different forms of the noun 'file' in each
 case.  [Note: Yep, very smart you are, the Russian word for 'file'
 is in fact the English word, and it is an invariable noun, but if you
 know that, you will also understand the rest despite this little
 simplification ...].
 
 That is the reason for the existance of the function ngettext(),
 that __n() is a short-cut for: 
 
     print __n"One file has been deleted.\n", 
              "All files have been deleted.\n",
              $files_deleted;
 
 Alternatively:
 
     print __n ("One file has been deleted.\n",
                "All files have been deleted.\n",
                $files_deleted);
 
 The effect is always the same: libintl-perl will find out which
 plural form to pick for your user's language, and the output string
 will always look okay.
 
 =item B<__nx MSGID, MSGID_PLURAL, COUNT, VAR1 =E<gt> VAL1, VAR2 =E<gt> VAL2, ...>
 
 Bringing it all together:
 
     print __nx ("One file has been deleted.\n",
                 "{count} files have been deleted.\n",
                 $num_files,
                 count => $num_files);
 
 The function __nx() picks the correct plural form (also for English!)
 I<and> it is capable of interpolating variables into strings.
 
 Have a close look at the order of arguments: The first argument is the
 string in the singular, the second one is the plural string. The third
 one is an integer indicating the number of items.  This third argument
 is I<only> used to pick the correct translation.  The optionally 
 following arguments make up the hash used for interpolation.  In the
 beginning it is often a little confusing that the variable holding the
 number of items will usually be repeated somewhere in the interpolation
 hash.
 
 =item B<__xn MSGID, MSGID_PLURAL, COUNT, VAR1 =E<gt> VAL1, VAR2 =E<gt> VAL2, ...>
 
 Does exactly the same thing as __nx().  In fact it is a common typo
 promoted to a feature.
 
 =item B<__p MSGCTXT, MSGID>
 
 This is much like __. The "p" stands for "particular", and the MSGCTXT 
 is used to provide context to the translator. This may be neccessary
 when your string is short, and could stand for multiple things. For example:
 
     print __p"Verb, to view", "View";
     print __p"Noun, a view", "View";
 
 The above may be "View" entries in a menu, where View->Source and File->View 
 are different forms of "View", and likely need to be translated differently.
 
 A typical usage are GUI programs.  Imagine a program with a main
 menu and the notorious "Open" entry in the "File" menu.  Now imagine,
 there is another menu entry Preferences->Advanced->Policy where you have 
 a choice between the alternatives "Open" and "Closed".  In English, "Open"
 is the adequate text at both places.  In other languages, it is very
 likely that you need two different translations.  Therefore, you would
 now write:
 
     __p"File|", "Open";
     __p"Preferences|Advanced|Policy", "Open";
 
 In English, or if no translation can be found, the second argument
 (MSGID) is returned.
 
 This function was introduced in libintl-perl 1.17.
 
 =item B<__px MSGCTXT, MSGID, VAR1 =E<gt> VAL1, VAR2 =E<gt> VAL2, ...>
 
 Like __p(), but supports variable substitution in the string, like __x().
 
     print __px("Verb, to view", "View {file}", file => $filename);
 
 See __p() and __x() for more details.
 
 This function was introduced in libintl-perl 1.17.
 
 =item B<__np MSGCTXT, MSGID, MSGID_PLURAL, COUNT>
 
 This adds context to plural calls. It should not be needed very often,
 if at all, due to the __nx() function. The type of variable substitution
 used in other gettext libraries (using sprintf-like sybols, like %s or %1)
 sometimes required context. For a (bad) example of this:
 
     printf (__np("[count] files have been deleted",
                 "One file has been deleted.\n",
                 "%s files have been deleted.\n",
                 $num_files),
             $num_files);
 
 NOTE: The above usage is discouraged. Just use the __nx() call, which 
 provides inline context via the key names.
 
 This function was introduced in libintl-perl 1.17.
 
 =item B<__npx MSGCTXT, MSGID, MSGID_PLURAL, COUNT, VAR1 =E<gt> VAL1, VAR2 =E<gt> VAL2, ...>
 
 This is provided for comleteness. It adds the variable interpolation
 into the string to the previous method, __np().
 
 It's usage would be like so:
 
     print __npx ("Files being permenantly removed",
                  "One file has been deleted.\n",
                  "{count} files have been deleted.\n",
                  $num_files,
                  count => $num_files);
 
 I cannot think of any situations requiring this, but we can easily 
 support it, so here it is.
 
 This function was introduced in libintl-perl 1.17.
 
 =item B<N__ (ARG1, ARG2, ...)>
 
 A no-op function that simply echoes its arguments to the caller.  Take
 the following piece of Perl:
 
     my @options = (
         "Open",
         "Save",
         "Save As",
     );
 
     ...
 
     my $option = $options[1];
 
 Now say that you want to have this translatable.  You could sometimes
 simply do:
 
     my @options = (
         __"Open",
         __"Save",
         __"Save As",
     );
 
     ...
 
     my $option = $options[1];
 
 But often times this will not be what you want, for example when you
 also need the unmodified original string.  Sometimes it may not even
 work, for example, when the preferred user language is not yet
 determined at the time that the list is initialized.
 
 In these cases you would write:
 
     my @options = (
         N__"Open",
         N__"Save",
         N__"Save As",
     );
 
     ...
 
     my $option = __($options[1]);
     # or: my $option = dgettext ('my-domain', $options[1]);
 
 Now all the strings in C<@options> will be left alone, since N__()
 returns its arguments (one ore more) unmodified.  Nevertheless, the
 string extractor will be able to recognize the strings as being 
 translatable.  And you can still get the translation later by passing
 the variable instead of the string to one of the above translation
 functions.
 
 =item B<N__n (MSGID, MSGID_PLURAL, COUNT)>
 
 Does exactly the same as N__().  You will use this form if you have 
 to mark the strings as having plural forms.
 
 =item B<N__p (MSGCTXT, MSGID)>
 
 Marks B<MSGID> as N__() does, but in the context B<MSGCTXT>.
 
 =item B<N__np (MSGCTXT, MSGID, MSGID_PLURAL, COUNT)>
 
 Marks B<MSGID> as N__n() does, but in the context B<MSGCTXT>.
 =back
 
 =head1 EXPORTED VARIABLES
 
 The module exports several variables into your namespace:
 
 =over 4
 
 =item B<%__>
 
 A tied hash.  Its keys are your original messages, the values are
 their translations:
 
     my $title = "<h1>$__{'My Homepage'}</h1>";
 
 This is much better for your translation team than
 
     my $title = __"<h1>My Homepage</h1>";
 
 In the second case the HTML code will make it into the translation
 database and your translators have to be aware of HTML syntax when
 translating strings.
 
 B<Warning:> Do I<not> use this hash outside of double-quoted strings!
 The code in the tied hash object relies on the correct working of
 the function caller() (see "perldoc -f caller"), and this function
 will report incorrect results if the tied hash value is the argument
 to a function from another package, for example:
 
   my $result = Other::Package::do_it ($__{'Some string'});
 
 The tied hash code will see "Other::Package" as the calling package,
 instead of your own package.  Consequently it will look up the message
 in the wrong text domain.  There is no workaround for this bug.
 Therefore:
 
 Never use the tied hash interpolated strings!
 
 =item B<$__>
 
 A reference to C<%__>, in case you prefer:
 
      my $title = "<h1>$__->{'My Homepage'}</h1>";
 
 =back
 
 =head1 PERFORMANCE
 
 Message translation can be a time-consuming task.  Take this little
 example:
 
     1: use Locale::TextDomain ('my-domain');
     2: use POSIX (:locale_h);
     3: 
     4: setlocale (LC_ALL, '');
     5: print __"Hello world!\n";
 
 This will usually be quite fast, but in pathological cases it may
 run for several seconds.  A worst-case scenario would be a
 Chinese user at a terminal that understands the codeset Big5-HKSCS.
 Your translator for Chinese has however chosen to encode the translations
 in the codeset EUC-TW.
 
 What will happen at run-time?  First, the library will search and load a
 (maybe large) message catalog for your textdomain 'my-domain'.  Then
 it will look up the translation for "Hello world!\n", it will find that
 it is encoded in EUC-TW.  Since that differs from the output codeset
 Big5-HKSCS, it will first load a conversion table containing several
 ten-thousands of codepoints for EUC-TW, then it does the same with
 the smaller, but still very large conversion table for Big5-HKSCS,
 it will convert the translation on the fly from EUC-TW into Big5-HKSCS,
 and finally it will return the converted translation.
 
 A worst-case scenario but realistic.  And for these five lines of codes,
 there is not much you can do to make it any faster.  You should understand,
 however, I<when> the different steps will take place, so that you can
 arrange your code for it.
 
 You have learned in the section L</DESCRIPTION> that line 1 is 
 responsible for locating your message database.  However, the
 use() will do nothing more than remembering your settings.  It will
 not search any directories, it will not load any catalogs or 
 conversion tables.
 
 Somewhere in your code you will always have a call to 
 POSIX::setlocale(), and the performance of this call may be time-consuming,
 depending on the architecture of your system.  On some systems, this
 will consume very little time, on others it will only consume a
 considerable amount of time for the first call, and on others it may
 always be time-consuming.  Since you cannot know, how setlocale() is
 implemented on the target system, you should reduce the calls to
 setlocale() to a minimum.
 
 Line 5 requests the translation for your string.  Only now, the library
 will actually load the message catalog, and only now will it load
 eventually needed conversion tables.  And from now on, all this information
 will be cached in memory.  This strategy is used throughout libintl-perl,
 and you may describe it as 'load-on-first-access'.  Getting the next
 translation will consume very little resources.
 
 However, although the translation retrieval is somewhat obfuscated
 by an operator-like function call, it is still a function call, and in
 fact it even involves a chain of function calls.  Consequently, the
 following example is probably bad practice:
 
     foreach (1 .. 100_000) {
         print __"Hello world!\n";
     }
 
 This example introduces a lot of overhead into your program.  Better
 do this:
 
     my $string = __"Hello world!\n";
     foreach (1 .. 100_000) {
         print $string;
     }
 
 The translation will never change, there is no need to retrieve it
 over and over again.  Although libintl-perl will of course cache
 the translation read from the file system, you can still avoid the
 overhead for the function calls.
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::Messages(3pm), Locale::gettext_pp(3pm), perl(1),
 gettext(1), gettext(3)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/TextDomain/UTF8.pm ###
 package Locale::TextDomain::UTF8;
 
 use 5.010001;
 use strict;
 use warnings;
 
 our $VERSION = '0.01'; # VERSION
 
 use Encode             ();
 use Locale::Messages   ();
 
 $ENV{OUTPUT_CHARSET} = 'UTF-8';
 sub import {
     my ($class, $textdomain, @search_dirs) = @_;
 
     my $pkg = caller;
 
     eval qq[package $pkg; use Locale::TextDomain \$textdomain, \@search_dirs;];
     die $@ if $@;
     Locale::Messages::bind_textdomain_filter(
         $textdomain, \&Encode::decode_utf8);
 }
 
 1;
 # ABSTRACT: Shortcut to use Locale::TextDomain and decoding to UTF8
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Locale::TextDomain::UTF8 - Shortcut to use Locale::TextDomain and decoding to UTF8
 
 =head1 VERSION
 
 version 0.01
 
 =head1 SYNOPSIS
 
 Instead of:
 
  use Locale::TextDomain 'Some-TextDomain';
 
 you now say:
 
  use Locale::TextDomain::UTF8 'Some-TextDomain';
 
 =head1 DESCRIPTION
 
  use Locale::TextDomain::UTF8 'Some-TextDomain'
 
 is equivalent to:
 
  use Locale::TextDomain 'Some-TextDomain';
  use Locale::Messages qw(bind_textdomain_filter);
  use Encode;
  BEGIN {
      $ENV{OUTPUT_CHARSET} = 'UTF-8';
      bind_textdomain_filter 'Some-TextDomain' => \&Encode::decode_utf8;
  }
 
 it's just more convenient, especially if you have to do it for each textdomain.
 
 Why would you want this? To ensure that strings returned by the C<__()>, et al
 functions are UTF8-encoded Perl strings. For example, if you want to pass the
 strings to L<Unicode::GCString>. For more details, see the Perl Advent article
 mentioned in the SEE ALSO section.
 
 =head1 SEE ALSO
 
 L<Locale::TextDomain>
 
 L<Locale::Messages>
 
 L<http://www.perladvent.org/2013/2013-12-09.html>
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Locale-TextDomain-UTF8>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Locale-TextDomain-UTF8>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Locale-TextDomain-UTF8>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 Steven Haryanto <stevenharyanto@gmail.com>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2013 by Steven Haryanto.
 
 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
### Locale/Util.pm ###
 #! /bin/false
 
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Portable methods for locale handling.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::Util;
 
 use strict;
 
 use constant DEBUG => 0;
 
 use base qw (Exporter);
 
 use vars qw (@EXPORT_OK);
 
 @EXPORT_OK = qw (parse_http_accept_language
 				 parse_http_accept_charset
 				 set_locale set_locale_cache get_locale_cache
 				 web_set_locale);
 
 # The following list maps languages to a rough guess of the country that
 # is most likely to be meant if no locale info for the country alone is
 # found.  I have assembled the list to the best of my knowledge, preferring
 # the country that has the language as its official language, and in doubt
 # listing the country that has the most speakers of that language.  Corrections
 # are welcome.
 use constant LANG2COUNTRY => {
     aa => 'ET', # Afar => Ethiopia
     ab => 'AB', # Abkhazian => Georgia
     # ae => '??', # Avestan => ??, Iran?
     af => 'za',  # Afrikaans => South Africa
     am => 'ET', # Amharic => Ethiopia
     ar => 'EG', # Arabic => Egypt
     as => 'IN', # Assamese => India
     ay => 'BO', # Aymara => Bolivia
     az => 'AZ', # Azerbaijani => Azerbaijan
     ba => 'RU', # Bashkir => Russia
     be => 'BY', # Belarusian => Belarus
     bg => 'BG', # Bulgarian => Bulgaria
     bh => 'IN', # Bihari => India
     bi => 'VU', # Bislama => Vanuatu
     bn => 'BD', # Bengali => Bangladesh
     bo => 'CN', # Tibetan => China
     br => 'FR', # Breton => France
     bs => 'BA', # Bosnian => Bosnia and Herzegovina
     ca => 'ES', # Catalan => Spain
     ce => 'RU', # Chechen => Russia
     ch => '??', # Chamorro => Guam (or mp?)
     co => 'FR', # Corsican => France
     cs => 'CZ', # Czech => Czech Republic
     cu => 'BG', # Church Slavic => Bulgaria
     cv => 'RU', # Chuvash => Russia
     cy => 'GB', # Welsh => United Kingdom
     da => 'DK', # Danish => Denmark
     de => 'DE', # German => Germany
     dz => 'BT', # Dzongkha => Bhutan
     el => 'GR', # Greek => Greece
     en => 'US', # English => United States
     es => 'ES', # Actually Mexico and the US have more Spanish speakers
                 # than Spain.  But it can be assumed that they either add
                 # the country to their browser settings or will not care
                 # to much.
     et => 'EE', # Estonian => Estonia
     fa => 'IR', # Iran, Islamic Republic of
     fi => 'FI', # Finnish => Finland
     fj => 'FJ', # Fijian => Fiji
     fo => 'FO', # Faeroese => Faroe Islands
     fr => 'FR', # French => France
     fy => 'FY', # Frisian => Netherlands
     ga => 'IE', # Irish => Ireland
     gd => 'GB', # Gaelic (Scots) => United Kingdom
     gl => 'ES', # Gallegan => Spain
     gn => 'PY', # Guarani => Paraguay
     gu => 'IN', # Gujarati => IN
     gv => 'GB', # Manx => United Kingdom
     ha => 'NE', # Hausa => Niger (ng?)
     he => 'IL', # Hebrew => Israel
     hi => 'IN', # Hindi => India
     ho => 'PG', # Hiri Motu => Papua New Guinea
     hr => 'HR', # Croatian
     hu => 'HU', # Hungarian => Hungary
     hy => 'AM', # Armenian => Armenia
     hz => 'NA', # Herero => Namibia
     # ia => '??', # Interlingua (aka "latino sine flexione") => ??
     id => 'ID', # Indonesian => Indonesia
     # ie => '??', # Interlingue => ???
     ik => 'US', # Inupiaq => United States
     is => 'IS', # Icelandic => Iceland
     it => 'IT', # Italian => Italy
     iu => 'CA', # Inuktitut => Canada
     iw => 'IL', # Hebrew => Israel
     ja => 'JP', # Japanese => Japan
     jw => 'ID', # Javanese => Indonesia
     ka => 'GE', # Georgian => Georgia
     ki => 'KE', # Kikuyu => Kenya
     kj => 'AO', # Kuanyama => Angola (na?)
     kk => 'KZ', # Kazakh => Kazakhstan
     kl => 'GL', # Kalaallisut => Greenland
     km => 'KH', # Khmer => Cambodia
     kn => 'IN', # Kannada => India
     ko => 'KR', # Korean => Korea, Republic of (more speakers than North Korea)
     ks => 'IN', # Kashmiri => India
     ku => 'TR', # Kurdish => Turkey
     kv => 'RU', # Komi => Russia
     kw => 'GB', # Cornish => United Kingdom
     ky => 'KG', # Kirghyz => Kyrgyzstan
     la => 'VA', # Latin => Holy See (Vatican City State)
     lb => 'LU', # Letzeburgesch => Luxembourg
     ln => 'CG', # Lingala => Republic of the Congo (cd?)
     lo => 'LA', # Lao => Lao People's Democratic Republic
     lt => 'LT', # Lithuanian => Lithuania
     lv => 'LV', # Latvian => Latvia
     mg => 'MG', # Malagasy => Madagascar
     mh => 'MH', # Marshall => Marshall Islands
     mi => 'NZ', # Maori => New Zealand
     mk => 'MK', # Macedonian => Macedonia, the Former Yugoslav Republic of
     ml => 'IN', # Malayalam => India
     mn => 'MN', # Mongolian => Mongolia
     mr => 'IN', # Marathi => India
     ms => 'MY', # Malay => Malaysia (FIXME: not really sure ...)
     mt => 'MT', # Maltese => Malta
     my => 'MM', # Burmese => Myanmar
     na => 'NR', # Nauru => Nauru
     nb => 'NO', # Norwegian Bokmål => Norway
     nd => 'ZA', # Ndebele, North => South Africa
     ne => 'NP', # Nepali => Nepal
     ng => 'NA', # Ndonga => Namibia
     nl => 'NL', # Dutch => Netherlands
     nn => 'NO', # Norwegian Nynorsk => Norway
     no => 'NO', # Norwegian => Norway
     nr => 'ZA', # Ndebele, South => South Africa
     nv => 'US', # Navajo => United States
     ny => 'MW', # Chichewa; Nyanja => Malawi
     oc => 'FR', # Occitan (post 1500) => France
     om => 'ET', # Oromo => Ethiopia
     or => 'IN', # Oriya => India
     os => 'RU', # Ossetian; Ossetic => Russia (FIXME: Or Georgia?)
     pa => 'IN', # Panjabi => India
     pi => 'IN', # Pali => India (FIXME: Or Thailand, Sri Lanka, Myanmar,
                 # Cambodia)
     pl => 'PL', # Polish => Poland
     ps => 'PK', # Pushto => Pakistan
     pt => 'PT', # Portuguese => Portugal (following our rules this should
                 # actually be Brazil but that would be to unrealistic,
                 # people from Brazil set their locale to pt_BR).
     qu => 'PE', # Quechua => Peru
     rm => 'CH', # Rhaeto-Romance => Switzerland
     rn => 'RW', # Rundi => Rwanda
     ro => 'RO', # Romanian => Romania
     ru => 'RU', # Russian => Russia
     rw => 'RW', # Kinyarwanda => Rwanda
     sa => 'IN', # Sanskrit => India
     sc => 'IT', # Sardinian => Italy
     sd => 'IN', # Sindhi => India
     se => 'SE', # Sami => Sweden (Totally unsure here.  The Sami languages 
 	            # are also spoken in Norway, Finland and Russia, but the 
                 # largest part of the area seems to be in Sweden. 
     sg => '??', # Sango => Central African Republic
     si => 'LK', # Sinhalese => Sri Lanka
     sk => 'SK', # Slovakian => Slovakia
     sl => 'SI', # Slovenian => Slovenia
     sm => 'WS', # Samoan => Samoa
     sh => 'ZW', # Shona => Zimbabwe (FIXME: Rather Mozambique?)
     so => 'SO', # Somali => Somalia
     sq => 'AL', # Albanian => Albania
     sr => 'YU', # Serbian => Yugoslavia
     ss => '??', # Swati => Swaziland (za?)
     st => 'LS', # Sotho => Lesotho
     su => 'IN', # Sundanese => Indonesia
     sv => 'SE', # Swedish => Sweden
     sw => 'TZ', # Suaheli => Tanzania, United Republic of
     ta => 'LK', # Tamil => Sri Lanka
     te => 'IN', # Telugu => India
     tg => 'TJ', # Tajik => Tajikistan
     th => 'TH', # Thai => Thailand
     ti => 'ER', # Tigrinya => Eritrea
     tk => 'TM', # Turkmen => Turkmenistan
     tl => 'PH', # Tagalog => Philippines
     tn => 'BW', # Tswana => Botswana
     to => 'TO', # Tonga => Tonga
     tr => 'TR', # Turkish => Turkish
     tt => 'RU', # Tatar => Russia
     tw => 'GH', # Twi => Ghana
     ug => 'CN', # Uighur => China
     uk => 'UA', # Ukrainian => Ukraine
     ur => 'PK', # Urdu => Pakistan
     uz => 'UZ', # Uzbek => Uzbekistan
     vi => 'VN', # Vietnamese => Vietnam
     # vo => '??', # Volapuk => Nowhere
     wo => 'SN', # Wolof => Senegal
     xh => 'ZA', # Xhosa => South Africa
     yi => 'IL', # Yiddish => Israel (FIXME: Rather United States?)
     yo => 'NG', # Yoruba => Nigeria
     za => 'CN', # Zhuang => China
     zh => 'CN', # Chinese => China
     zu => 'ZA', # Zulu => South Africa
 };
 
 use constant WIN32LANGUAGE => {
     aa => "Afar",
     ab => "Abkhazian",
     ae => "Avestan",
     af => "Afrikaans",
     am => "Amharic",
     ar => "Arabic",
     as => "Assamese",
     ay => "Aymara",
     az => "Azerbaijani",
     ba => "Bashkir",
     be => "Belarusian",
     bg => "Bulgarian",
     bh => "Bihari",
     bi => "Bislama",
     bn => "Bengali",
     bo => "Tibetan",
     br => "Breton",
     bs => "Bosnian",
     ca => "Catalan",
     ce => "Chechen",
     ch => "Chamorro",
     co => "Corsican",
     cs => "Czech",
     cu => "Church Slavic",
     cv => "Chuvash",
     cy => "Welsh",
     da => "Danish",
     de => "German",
     dz => "Dzongkha",
     el => "Greek",
     en => "English",
     eo => "Esperanto",
     es => "Spanish",
     et => "Estonian",
     eu => "Basque",
     fa => "Persian",
     fi => "Finnish",
     fj => "Fijian",
     fo => "Faeroese",
     fr => "French",
     fy => "Frisian",
     ga => "Irish",
     gd => "Gaelic (Scots)",
     gl => "Gallegan",
     gn => "Guarani",
     gu => "Gujarati",
     gv => "Manx",
     ha => "Hausa",
     he => "Hebrew",
     hi => "Hindi",
     ho => "Hiri Motu",
     hr => "Croatian",
     hu => "Hungarian",
     hy => "Armenian",
     hz => "Herero",
     ia => "Interlingua",
     id => "Indonesian",
     ie => "Interlingue",
     ik => "Inupiaq",
     is => "Icelandic",
     it => "Italian",
     iu => "Inuktitut",
     ja => "Japanese",
     jw => "Javanese",
     ka => "Georgian",
     ki => "Kikuyu",
     kj => "Kuanyama",
     kk => "Kazakh",
     kl => "Kalaallisut",
     km => "Khmer",
     kn => "Kannada",
     ko => "Korean",
     ks => "Kashmiri",
     ku => "Kurdish",
     kv => "Komi",
     kw => "Cornish",
     ky => "Kirghiz",
     la => "Latin",
     lb => "Letzeburgesch",
     ln => "Lingala",
     lo => "Lao",
     lt => "Lithuanian",
     lv => "Latvian",
     mg => "Malagasy",
     mh => "Marshall",
     mi => "Maori",
     # Sorry, lads, but that is what M$ calls your language ...
     mk => "FYRO Macedonian",
     ml => "Malayalam",
     mn => "Mongolian",
     mo => "Moldavian",
     mr => "Marathi",
     ms => "Malay",
     mt => "Maltese",
     my => "Burmese",
     na => "Nauru",
     nb => "Norwegian (Bokmål)",
     nd => "Ndebele, North",
     ne => "Nepali",
     ng => "Ndonga",
     nl => "Dutch",
     nn => "Norwegian-Nynorsk",
     no => "Norwegian-Nynorsk",
     nr => "Ndebele, South",
     nv => "Navajo",
     ny => "Chichewa",
     oc => "Occitan (post 1500)",
     om => "Oromo",
     or => "Oriya",
     os => "Ossetian",
     pa => "Panjabi",
     pi => "Pali",
     pl => "Polish",
     ps => "Pushto",
     pt => "Portuguese",
     qu => "Quechua",
     rm => "Rhaeto-Romance",
     rn => "Rundi",
     ro => "Romanian",
     ru => "Russian",
     rw => "Kinyarwanda",
     sa => "Sanskrit",
     sc => "Sardinian",
     sd => "Sindhi",
     se => "Sami",
     sg => "Sango",
     si => "Sinhalese",
     sk => "Slovak",
     sl => "Slovenian",
     sm => "Samoan",
     sn => "Shona",
     so => "Somali",
     sq => "Albanian",
     sr => "Serbian",
     ss => "Swati",
     st => "Sotho",
     su => "Sundanese",
     sv => "Swedish",
     sw => "Swahili",
     ta => "Tamil",
     te => "Telugu",
     tg => "Tajik",
     th => "Thai",
     ti => "Tigrinya",
     tk => "Turkmen",
     tl => "Tagalog",
     tn => "Tswana",
     to => "Tonga",
     tr => "Turkish",
     ts => "Tsonga",
     tt => "Tatar",
     tw => "Twi",
     ug => "Uighur",
     uk => "Ukrainian",
     ur => "Urdu",
     uz => "Uzbek",
     vi => "Vietnamese",
     vo => "Volapuk",
     wo => "Wolof",
     xh => "Xhosa",
     yi => "Yiddish",
     yo => "Yoruba",
     za => "Zhuang",
     zh => "Chinese",
     zu => "Zulu",
 };
 
 use constant WIN32COUNTRY => {
     ad => "Andorra",
     ae => "United Arab Emirates",
     af => "Afghanistan",
     ag => "Antigua and Barbuda",
     ai => "Anguilla",
     al => "Albania",
     am => "Armenia",
     an => "Netherlands Antilles",
     ao => "Angola",
     aq => "Antarctica",
     ar => "Argentina",
     as => "American Samoa",
     at => "Austria",
     au => "Australia",
     aw => "Aruba",
     ax => "Aland Islands",
     az => "Azerbaijan",
     ba => "Bosnia and Herzegovina",
     bb => "Barbados",
     bd => "Bangladesh",
     be => "Belgium",
     bf => "Burkina Faso",
     bg => "Bulgaria",
     bh => "Bahrain",
     bi => "Burundi",
     bj => "Benin",
     bm => "Bermuda",
     bn => "Brunei Darussalam",
     bo => "Bolivia",
     br => "Brazil",
     bs => "Bahamas",
     bt => "Bhutan",
     bv => "Bouvet Island",
     bw => "Botswana",
     by => "Belarus",
     bz => "Belize",
     ca => "Canada",
     cc => "Cocos (Keeling) Islands",
     cd => "Congo, The Democratic Republic of the",
     cf => "Central African Republic",
     cg => "Congo",
     ch => "Switzerland",
     ci => "Cote D'Ivoire",
     ck => "Cook Islands",
     cl => "Chile",
     cm => "Cameroon",
     cn => "China",
     co => "Colombia",
     cr => "Costa Rica",
     cs => "Serbia and Montenegro",
     cu => "Cuba",
     cv => "Cape Verde",
     cx => "Christmas Island",
     cy => "Cyprus",
     cz => "Czech Republic",
     de => "Germany",
     dj => "Djibouti",
     dk => "Denmark",
     dm => "Dominica",
     do => "Dominican Republic",
     dz => "Algeria",
     ec => "Ecuador",
     ee => "Estonia",
     eg => "Egypt",
     eh => "Western Sahara",
     er => "Eritrea",
     es => "Spain",
     et => "Ethiopia",
     fi => "Finland",
     fj => "Fiji",
     fk => "Falkland Islands (Malvinas)",
     fm => "Micronesia, Federated States of",
     fo => "Faroe Islands",
     fr => "France",
     fx => "France, Metropolitan",
     ga => "Gabon",
     gb => "United Kingdom",
     gd => "Grenada",
     ge => "Georgia",
     gf => "French Guiana",
     gh => "Ghana",
     gi => "Gibraltar",
     gl => "Greenland",
     gm => "Gambia",
     gn => "Guinea",
     gp => "Guadeloupe",
     gq => "Equatorial Guinea",
     gr => "Greece",
     gs => "South Georgia and the South Sandwich Islands",
     gt => "Guatemala",
     gu => "Guam",
     gw => "Guinea-Bissau",
     gy => "Guyana",
     hk => "Hong Kong",
     hm => "Heard Island and McDonald Islands",
     hn => "Honduras",
     hr => "Croatia",
     ht => "Haiti",
     hu => "Hungary",
     id => "Indonesia",
     ie => "Ireland",
     il => "Israel",
     in => "India",
     io => "British Indian Ocean Territory",
     iq => "Iraq",
     ir => "Iran",
     is => "Iceland",
     it => "Italy",
     jm => "Jamaica",
     jo => "Jordan",
     jp => "Japan",
     ke => "Kenya",
     kg => "Kyrgyzstan",
     kh => "Cambodia",
     ki => "Kiribati",
     km => "Comoros",
     kn => "Saint Kitts and Nevis",
     kp => "North-Korea",
     kr => "Korea",
     kw => "Kuwait",
     ky => "Cayman Islands",
     kz => "Kazakhstan",
     la => "Laos",
     lb => "Lebanon",
     lc => "Saint Lucia",
     li => "Liechtenstein",
     lk => "Sri Lanka",
     lr => "Liberia",
     ls => "Lesotho",
     lt => "Lithuania",
     lu => "Luxembourg",
     lv => "Latvia",
     ly => "Libyan",
     ma => "Morocco",
     mc => "Monaco",
     md => "Moldova",
     mg => "Madagascar",
     mh => "Marshall Islands",
     mk => "Former Yugoslav Republic of Macedonia",
     ml => "Mali",
     mm => "Myanmar",
     mn => "Mongolia",
     mo => "Macao",
     mp => "Northern Mariana Islands",
     mq => "Martinique",
     mr => "Mauritania",
     ms => "Montserrat",
     mt => "Malta",
     mu => "Mauritius",
     mv => "Maldives",
     mw => "Malawi",
     mx => "Mexico",
     my => "Malaysia",
     mz => "Mozambique",
     na => "Namibia",
     nc => "New Caledonia",
     ne => "Niger",
     nf => "Norfolk Island",
     ng => "Nigeria",
     ni => "Nicaragua",
     nl => "Netherlands",
     no => "Norway",
     np => "Nepal",
     nr => "Nauru",
     nu => "Niue",
     nz => "New Zealand",
     om => "Oman",
     pa => "Panama",
     pe => "Peru",
     pf => "French Polynesia",
     pg => "Papua New Guinea",
     ph => "Philippines",
     pk => "Pakistan",
     pl => "Poland",
     pm => "Saint Pierre and Miquelon",
     pn => "Pitcairn",
     pr => "Puerto Rico",
     ps => "Palestinian Territory, Occupied",
     pt => "Portugal",
     pw => "Palau",
     py => "Paraguay",
     qa => "Qatar",
     re => "Reunion",
     ro => "Romania",
     ru => "Russian Federation",
     rw => "Rwanda",
     sa => "Saudi Arabia",
     sb => "Solomon Islands",
     sc => "Seychelles",
     sd => "Sudan",
     se => "Sweden",
     sg => "Singapore",
     sh => "Saint Helena",
     si => "Slovenia",
     sj => "Svalbard and Jan Mayen",
     sk => "Slovakia",
     sl => "Sierra Leone",
     sm => "San Marino",
     sn => "Senegal",
     so => "Somalia",
     sr => "Suriname",
     st => "Sao Tome and Principe",
     sv => "El Salvador",
     sy => "Syrian Arab Republic",
     sz => "Swaziland",
     tc => "Turks and Caicos Islands",
     td => "Chad",
     tf => "French Southern Territories",
     tg => "Togo",
     th => "Thailand",
     tj => "Tajikistan",
     tk => "Tokelau",
     tl => "Timor-Leste",
     tm => "Turkmenistan",
     tn => "Tunisia",
     to => "Tonga",
     tr => "Turkey",
     tt => "Trinidad and Tobago",
     tv => "Tuvalu",
     tw => "Taiwan, Province of China",
     tz => "Tanzania, United Republic of",
     ua => "Ukraine",
     ug => "Uganda",
     um => "United States Minor Outlying Islands",
     us => "United States",
     uy => "Uruguay",
     uz => "Uzbekistan",
     va => "Holy See (Vatican City State)",
     vc => "Saint Vincent and the Grenadines",
     ve => "Venezuela",
     vg => "Virgin Islands, British",
     vi => "Virgin Islands, U.S.",
     vn => "Vietnam",
     vu => "Vanuatu",
     wf => "Wallis and Futuna",
     ws => "Samoa",
     ye => "Yemen",
     yt => "Mayotte",
     za => "South Africa",
     zm => "Zambia",
     zw => "Zimbabwe",
 };
 
 my $locale_cache;
 
 sub parse_http_accept_language {
 	my ($string) = @_;
 
 	my @tokens = split / *, */, $string;
 	
 	my %retval;
 	foreach my $token (@tokens) {
 		my $quality = 1;
 		# This RE is more forgiving than the standard.  It accepts
 		# values greater than 1.0 and with more fractional digits
 		# than 3.
 		if ($token =~ s/ *; *q *= *([0-9]+(?:\.([0-9]+))?)$//) {
 			$quality = $1;
 		}
 		$retval{$token} = $quality;
 	}
 
 	# RFC 2616 only allows 1-8 characters for language and country
 	# but we are more forgiving.
 	return grep { 
 		/^[A-Za-z]+(?:-[A-Za-z]+)?$/
 		} map {
 			$_ = 'C' if $_ eq '*'; $_
 		}	sort { 
 			$retval{$b} <=> $retval{$a} 
 		} keys %retval;
 }
 
 sub parse_http_accept_charset {
 	my ($string) = @_;
 
 	my @tokens = split / *, */, $string;
 	
 	my %retval;
 	foreach my $token (@tokens) {
 		my $quality = 1;
 		# This RE is more forgiving than the standard.  It accepts
 		# values greater than 1.0 and with more fractional digits
 		# than 3.
 		if ($token =~ s/ *; *q *= *([0-9]+(?:\.([0-9]+))?)$//) {
 			$quality = $1;
 		}
 		$retval{$token} = $quality;
 	}
 
 	return grep { 
 		# This is really allowed in character set names ...
 		/^[-!\#\$\%\&\'\+\.0-9A-Z_\`a-z\|\~]+$/
 		} map {
 			$_ = undef if $_ eq '*'; $_
 		}	sort { 
 			$retval{$b} <=> $retval{$a} 
 		} keys %retval;
 }
 
 sub set_locale {
 	my ($category, $language, $country, $charset) = @_;
 	
 	require POSIX;
 
     $country = '' unless defined $country;
     $charset = '' unless defined $charset;
     
 	my $set_locale;
 	# Look up the cache first.
     if (my $retval = $locale_cache->{$language}->{$country}->{$charset}) {
     	my ($locale, $country) = @$retval;
 	POSIX::setlocale ($category, $locale);
         return @$retval;
     }
 
 	# Initialize the cache with the undefined value so that we can do
 	# error returns without setting it.
 	$locale_cache->{$language}->{$country}->{$charset} = undef;
 
 	my $windows = ($^O !~ /darwin/i && $^O =~ /win/i) ? 1 : 0;
 	if ($windows) {
 		return &__set_locale_windows;
 	}
 	
 	my $set_language;
 	my $set_country;
 
 	# First we try to only use the language.
 	my @languages = ($language);
 	my @lc_languages = map { lc $_ } @languages;
 	my @uc_languages = map { uc $_ } @languages;
 	my %seen = ();
 
 	foreach my $language (@languages, @lc_languages, @uc_languages) {
 		next if $seen{$language}++;
 		warn "Trying lingua only setlocale '$language'.\n" if DEBUG;
 		my $result = POSIX::setlocale ($category, $language);
 		if ($result) {
 			$set_locale = $set_language = $result if $result;
 			last;
 		}
 	}
 
 	# Now try it with the country appended.
 	my @countries = length $country ? ($country) : ();
 	my @uc_countries = map { uc $_ } @countries;
 	my @lc_countries = map { uc $_ } @countries;
 	push @countries, @uc_countries, @lc_countries;
  
  LINGUA: foreach my $language (@languages, @lc_languages, @uc_languages) {
 		my $count = 0;
 		my @guessed_countries = (LANG2COUNTRY->{lc $language},
 								 lc LANG2COUNTRY->{lc $language},
 								 uc LANG2COUNTRY->{lc $language});
 		foreach my $c (@countries, @guessed_countries) {
 			++$count;
 			next unless defined $c && length $c;
 			my $try = $language . '_' . $c;
 			next if $seen{$try}++;
 			warn "Trying setlocale '$try'.\n" if DEBUG;
 			my $result = POSIX::setlocale ($category, $try);
 			if ($result) {
 				$set_locale = $result;
 				if ($count >= @countries) {
 					$set_country = $c; 
 				} else {
 					$set_country = $country;
 				}
 
 				last LINGUA;
 			}
 		}
 	}
 	
 	unless (length $charset) {
 		return unless defined $set_locale && length $set_locale;
 		
 		$locale_cache->{$language}->{$country}->{$charset} = 
 			[$set_locale, $set_country];
 		return wantarray ? ($set_locale, $set_country) : $set_locale;
 	}
 	
 	my @charsets = ($charset);
 	my $cleaned = $charset;
 	push @charsets, $cleaned if $cleaned =~ s/-//g;
 	my @lc_charsets = map { lc $charset } @charsets;
 	my @uc_charsets = map { uc $charset } @charsets;
 	push @charsets, @lc_charsets, @uc_charsets;
 	
 	%seen = ();
  LINGUA2: foreach my $language (@languages, 
 								@lc_languages, @uc_languages) {
 	     my @guessed_countries = (LANG2COUNTRY->{lc $language},
 								 lc LANG2COUNTRY->{lc $language},
 								 uc LANG2COUNTRY->{lc $language});
 	     my $count = 0;
 		 foreach my $c (@countries, @guessed_countries) {
 			 ++$count;
 			 $c = '' unless defined $c && length $c;
 			 my $country_try = $language;
 			 $country_try .= (length $c) ? "_$c" : '';
 			 
 			 foreach my $ch (@charsets, @lc_charsets, @uc_charsets) {
 				 my $try = $country_try . '.' . $ch;
 				 next if $seen{$try}++;
 				 warn "Trying setlocale '$try'.\n" if DEBUG;
 				 
 				 my $result = POSIX::setlocale ($category, $try);
 				 if ($result) {
 					 $set_locale = $result;
 					 if ($count >= @countries) {
 						 $set_country = $c; 
 					 } else {
 						 $set_country = $country;
 					 }
 					 
 					 last LINGUA2;
 				 }
 			 }
 		 } 
 	 }
 
 	return unless defined $set_locale && length $set_locale;
 
 	$locale_cache->{$language}->{$country}->{$charset} = 
 		[$set_locale, $set_country];
 
 	return wantarray ? ($set_locale, $set_country) : $set_locale;
 }
 
 sub __set_locale_windows {
 	my ($category, $language, $country, $charset) = @_;
 
     my $set_locale;
 
     $country = '' unless defined $country;
     $charset = '' unless defined $charset;
     	
 	# First we try to only use the language.
 	my $long_language = WIN32LANGUAGE->{lc $language};
 	my @languages = ($long_language, $language);
 	my %seen = ();
 	foreach my $language (@languages) {
 		next if $seen{$language}++;
 		warn "Trying lingua only setlocale '$language'.\n" if DEBUG;
 		my $result = POSIX::setlocale ($category, $language);
 		if ($result) {
 			$set_locale = $result if $result;
 			last;
 		}
 	}
 	
 	# Now try it with the country appended.
 	my $set_country;
 	if (length $country) {
         COMBI: foreach my $language (@languages) {
             # We do not need a fallback country here, because the "system" already
             # provides the information.
 	        my @short_countries = ($country);
 		    my @countries = map { 
 			    WIN32COUNTRY->{lc $_} 
 			    } grep { length $_ } @short_countries;
 		    foreach my $c (@countries) {
 			    next unless defined $c && length $c;
 			    my $try = $language . '_' . $c;
 			    next if $seen{$try}++;
 			    warn "Trying setlocale '$try'.\n" if DEBUG;
 			    my $result = POSIX::setlocale ($category, $try);
 			    if ($result) {
 				    $set_locale = $result;
 					$set_country = $c;
 				    last COMBI;
 			    }
 		    }
 	    }
 	}
 
 	return unless defined $set_locale && length $set_locale;
 
     # Apparently, there is no point in setting a charset.  Even the new
     # MS-DOS versions like 2000 or XP still have the concept of more or
     # less fixed codepages.  Switching to UTF-8 does not work.
 	$locale_cache->{$language}->{$country}->{$charset} = 
 		[$set_locale, $set_country];
 	return wantarray ? ($set_locale, $set_country) : $set_locale;
 }
 
 sub get_locale_cache {
 	$locale_cache;
 }
 
 sub set_locale_cache {
 	if (ref $_[0] && 'HASH' eq ref $_[0]) {
 		$locale_cache = $_[0];
     } else {
 		my %locale_cache = @_;
 		$locale_cache = \%locale_cache;
 	}
 }
 
 sub web_set_locale {
 	my ($accept_language, $accept_charset, $category, $available) = @_;
 
 	my %available;
 	if ($available) {
 		foreach (@$available) {
 			my $locale = $_;
 			$locale =~ s/[_\@\.].*//;
 			$available{lc $locale} = 1;
 		}
 	}
 
 	my @languages;
 	if (ref $accept_language && 'ARRAY' eq ref $accept_language) {
 		@languages = @$accept_language;
 	} else {
 		@languages = parse_http_accept_language $accept_language;
 	}
 
 	if ($available) {
 		my @all = @languages;
 		@languages = ();
 		foreach my $locale (@all) {
 			my $language = lc $locale;
 			$language =~ s/[_\@\.].*//;
 			push @languages, $locale if $available{$language};
 		}
 	}
 
 	my @charsets;
 	if (defined $accept_charset) {
 		if (ref $accept_charset && 'ARRAY' eq ref $accept_charset) {
 			@charsets = @$accept_charset;
 		} else {
 			@charsets = parse_http_accept_charset $accept_charset;
 		}
 	}
 
 	unless (defined $category) {
 		require POSIX;
 		$category = POSIX::LC_ALL();
 	}
 
 	my ($set_locale, $set_language, $set_country, $set_charset);
 	foreach my $lang (@languages) {
 		my ($language, $country) = split /-/, $lang, 2;
 
 		my ($locale, $country_used) = 
 			set_locale ($category, $language, $country, $charsets[0]);
 		
 		if (defined $locale) {
 			# If a country was specified, we have to check whether it
 			# was actually selected.
 			if (defined $country) {
 				if (!defined $country
 					|| ($country ne $country_used)) {
 					$set_language = $language;
 					$set_locale = $locale;
 					$set_country = $country_used;
 					$set_charset = $charsets[0];
 				}
 			}
 
 			if (wantarray) {
 				return $locale, $lang, $country_used, $charsets[0];
 			} else {
 				return $locale;
 			}
 		}
 	}
 	
 	if (defined $set_locale) {
 		if (wantarray) {
 			return $set_locale, $set_language, $set_country, $set_charset;
 		} else {
 			return $set_locale;
 		}
 	}
 
 	return;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::Util - Portable l10n and i10n functions
 
 =head1 SYNOPSIS
 
   use Locale::Util;
 
   my @linguas = parse_http_accept_language $ENV{HTTP_ACCEPT_LANGUAGE};
 
   my @charsets = parse_http_accept_charset $ENV{HTTP_ACCEPT_CHARSET};
 
   # Trie to set the locale to Brasilian Portuguese in UTF-8.
   my $set_locale = set_locale LC_ALL, 'pt', 'BR', 'utf-8';
 
   set_locale_cache $last_cache;
   
   my $cache = get_locale_cache;
 
   web_set_locale ($ENV{HTTP_ACCEPT_LANGUAGE}, $ENV_ACCEPT_CHARSET);
 
   web_set_locale (['fr-BE', 'fr', 'it'], ['cp1252', 'utf-8']);
 
 =head1 DESCRIPTION
 
 This module provides portable functions dealing with localization
 (l10n) and internationalization(i10n).  It doesn't export anything
 by default, you have to specify each function you need in the import
 list, or use the fully qualified name.
 
 The functions here have a focus on web development, although they 
 are general enough to have them in the Locale:: namespace.
 
 This module is considered alpha code.  The interface is not stable.
 Please contact the author if you want to use it in production code.
 
 This module was introduced in libintl-perl 1.17.
 
 =head1 FUNCTIONS
 
 =over 4
 
 =item B<parse_http_accept_language STRING>
 
 Parses a string as passed in the HTTP header "Accept-Language".
 It returns a list of tokens sorted by the quality value, see RFC 2616 
 for details.
 
 Example:
 
   parse_http_accept ("fr-fr, fr; q=0.7, de; q=0.3");
 
 This means: Give me French for France with a quality value of 1.0
 (the maximum).  Otherwise I will take any other French version 
 (quality 0.7), German has a quality of 0.3 for me.
 
 The function will return a list of tokens in the order of their quality
 values, in this case "fr-fr", "fr" and "de".
 
 The function is more forgiving than RFC 2616.  It accepts quality
 values greater than 1.0 and with more than 3 decimal places.  It
 also accepts languages and country names with more than 8 characters.
 The language "*" is translated into "C".
 
 =item B<parse_http_accept_charset STRING>
 
 Parses a string as passed in the HTTP header "Accept-Charset".
 It returns a list of tokens sorted by the quality value, see RFC 2616 
 for details.
 
 The special character set "*" (means all character sets) will be
 translated to the undefined value.
 
 =item B<set_locale CATEGORY, LANGUAGE[, COUNTRY, CHARSET]>
 
 Tries to set the user locale by means of POSIX::setlocale().  The latter
 function has the disadvantage, that its second argument (the locale
 description string) is completely non-standard and system-dependent.
 This function tries its best at guessing the system's notion of a locale
 dientifier, with the arguments supplied:
 
 =over 8
 
 =item B<CATEGORY>
 
 An integer argument for a valid locale category.  These are the
 LC_* constants (LC_ALL, LC_CTIME, LC_COLLATE, ...) defined in both
 Locale::Messages(3pm) and POSIX(3pm).
 
 =item B<LANGUAGE>
 
 A 2-letter language identifier as per ISO 639.  Case doesn't matter,
 but an unchanged version (ie. not lower-cased) of the language you
 provided will always be tried to.
 
 =item B<COUNTRY>
 
 A 2-letter language identifier as per ISO 639.  Case doesn't matter,
 but an unchanged version (ie. not lower-cased) of the language you
 provided will always be tried to.
 
 This parameter is optional.  If it is not defined, the function will
 try to guess an appropriate country, otherwise leave it to the 
 operating system.
 
 =item B<CHARSET>
 
 A valid charset name.  Valid means valid!  The charset "utf8" is not
 valid (it is "utf-8").  Charset names that are accepted by the
 guessing algorithms in Encode(3pm) are also not necessarily valid.
 
 If the parameter is undefined, it is ignored.  It is always ignored
 under Windows.
 
 =back
 
 The function tries to approach the desired locale in loops, refining
 it on every success.  It will first try to set the language (for 
 any country), then try to select the correct language, and finally
 try to select the correct charset.
 
 The return value is false in case of failure, or the return value
 of the underlying POSIX::setlocale() call in case of success.
 
 In array context, the function returns the country name 
 that was passed in the successful
 call to POSIX::setlocale().  If this string is equal to the country
 name you passed as an argument, you can be reasonably sure that
 the settings for this country are really used.  If it is not
 equal, the function has taken a guess at the country (it has a list
 of "default" countries for each language).  It seems that under
 Windows, POSIX::setlocale() also succeeds, if you pass a country
 name that is actually not supported.  Therefore, the information
 is not completely reliable.
 
 Please note that this function is intended for server processes 
 (especially web applications) that need to switch in a portable
 way to a certain locale.  It is B<not> the recommended way to set 
 the program locale for a regular application.  In a regular application
 you should do the following:
 
     use POSIX qw (setlocale LC_ALL);
     setlocale LC_ALL, '';
 
 The empty string as the second argument means, that the system
 should switch to the user's default locale.
 
 =item B<get_locale_cache>
 
 The function set_locale() is potentially expansive, especially when
 it fails, because it can try a lot of different combinations, and 
 the system may have to load a lot of locale definitions from its
 internal database.
 
 In order to speed up things, results are internally cached in a 
 hash, keys are the languages, subkeys countries, subsubkeys the
 charsets.  You can get a reference to this hash with get_locale_cache().
 
 The function cannot fail.
 
 =item B<set_locale_cache HASH>
 
 Sets the internal cache.  You can either pass a hash or a hash reference.
 The function will use this as its cache, discarding its old cache.
 This allows you to keep the hash persistent.
 
 The function cannot fail.
 
 =item B<web_set_locale (ACCEPT_LANGUAGE, ACCEPT_CHARSET, CATEGORY,
                         AVAILABLE)>
 
 Try to change the locale to the settings described by ACCEPT_LANGUAGE
 and ACCEPT_CHARSET.  For each argument you can either pass a string
 as in the corresponding http header, or a reference to an array
 of language resp. charset identifiers.
 
 Currently only the first charset passed is used as an argument.
 You are strongly encouraged to pass a hard-coded value here, so
 that you have control about your output.
 
 The argument B<CATEGORY> specifies the category (one of the LC_*
 constants as defined in Locale::Messages(3pm) or in POSIX(3pm)).
 The category defaults to LC_ALL.
 
 You can pass an optional reference to a list of locales in 
 XPG4 format that are available in your application.  This is
 useful if you know which languages are supported by your application.
 In fact, only the language part of the values in the list are
 considered (for example for "en_US", only "en" is used).  The
 country or other parts are ignored.
 
 The function returns the return value of the underlying set_locale()
 call, or false on failure.
 
 The function returns false on failure.  On success it returns the 
 return value of the underlying set_locale() call.  This value can
 be used directly in subsequent calls to POSIX::setlocale().  In 
 array context, it additionally returns the identifiers for the language, 
 the country, and the charset actually used.
 
 =back
 
 =head1 BUGS
 
 The function set_locale() probably fails to guess the correct locale
 identifier on a lot of systems.  If you have found such a case,
 please submit it as a bug report.
 
 The bug tracking system for this packags is at
 http://rt.cpan.org/NoAuth/Bugs.html?libintl-perl
 
 Please note that this module is considered alpha code, and the interface
 is not stable.  Please contact the author, if you want to use it in
 production code.
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 POSIX(3pm), perl(1)
 
 =cut
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 cperl-indent-level: 4
 cperl-continued-statement-offset: 2
 tab-width: 4
 End:
 =cut
### Locale/gettext_dumb.pm ###
 #! /bin/false
 
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Pure Perl implementation of Uniforum message translation.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::gettext_dumb;
 
 use Locale::gettext_pp;
 
 use vars qw (%EXPORT_TAGS @EXPORT_OK @ISA $VERSION);
 
 %EXPORT_TAGS = (locale_h => [ qw (gettext
                                   dgettext
                                   dcgettext
                                   ngettext
                                   dngettext
                                   dcngettext
                                   pgettext
                                   dpgettext
                                   dcpgettext
                                   npgettext
                                   dnpgettext
                                   dcnpgettext
                                   textdomain
                                   bindtextdomain
                                   bind_textdomain_codeset
                                   )],
                 libintl_h => [ qw (LC_CTYPE
                                    LC_NUMERIC
                                    LC_TIME
                                    LC_COLLATE
                                    LC_MONETARY
                                    LC_MESSAGES
                                    LC_ALL)],
                 );
 
 @EXPORT_OK = qw (gettext
                  dgettext
                  dcgettext
                  ngettext
                  dngettext
                  dcngettext
                  pgettext
                  dpgettext
                  dcpgettext
                  npgettext
                  dnpgettext
                  dcnpgettext
                  textdomain
                  bindtextdomain
                  bind_textdomain_codeset
                  nl_putenv
                  setlocale
                  LC_CTYPE
                  LC_NUMERIC
                  LC_TIME
                  LC_COLLATE
                  LC_MONETARY
                  LC_MESSAGES
                  LC_ALL);
                  
 @ISA = qw (Exporter);
 
 *Locale::gettext_dumb::textdomain = \&Locale::gettext_pp::textdomain;
 *Locale::gettext_dumb::bindtextdomain = \&Locale::gettext_pp::bindtextdomain;
 *Locale::gettext_dumb::bind_textdomain_codeset = 
     \&Locale::gettext_pp::bind_textdomain_codeset;
 
 *Locale::gettext_dumb::nl_putenv = \&Locale::gettext_pp::nl_putenv;
 
 *Locale::gettext_dumb::LC_CTYPE = \&Locale::gettext_pp::LC_CTYPE;
 *Locale::gettext_dumb::LC_NUMERIC = \&Locale::gettext_pp::LC_NUMERIC;
 *Locale::gettext_dumb::LC_TIME= \&Locale::gettext_pp::LC_TIME;
 *Locale::gettext_dumb::LC_COLLATE = \&Locale::gettext_pp::LC_COLLATE;
 *Locale::gettext_dumb::LC_MONETARY = \&Locale::gettext_pp::LC_MONETARY;
 *Locale::gettext_dumb::LC_MESSAGES = \&Locale::gettext_pp::LC_MESSAGES;
 *Locale::gettext_dumb::LC_ALL = \&Locale::gettext_pp::LC_ALL;
 
 
 sub gettext ($) {
     my ($msgid) = @_;
 
     return dcnpgettext ('', undef, $msgid, undef, undef, undef);
 }
 
 sub dgettext ($$) {
     my ($domainname, $msgid) = @_;
 
     return dcnpgettext ($domainname, undef, $msgid, undef, undef, undef);
 }
 
 sub dcgettext ($$$) {
     my ($domainname, $msgid, $category) = @_;
 
     return dcnpgettext ($domainname, undef, $msgid, undef, undef, undef);
 }
 
 sub ngettext ($$$) {
     my ($msgid, $msgid_plural, $n) = @_;
 
     return dcnpgettext ('', undef, $msgid, $msgid_plural, $n, undef);
 }
 
 sub dngettext ($$$$) {
     my ($domainname, $msgid, $msgid_plural, $n) = @_;
 
     return dcnpgettext ($domainname, undef, $msgid, $msgid_plural, $n, undef);
 }
 
 sub dcngettext ($$$$$) {
     my ($domainname, $msgid, $msgid_plural, $n, $category) = @_;
 
     return dcnpgettext ($domainname, undef, $msgid, $msgid_plural, $n, , 
                         $category);
 }
 
 sub pgettext ($$) {
     my ($msgctxt, $msgid) = @_;
 
     return dcnpgettext ('', $msgctxt, $msgid, undef, undef, undef);
 }
 
 sub dpgettext ($$$) {
     my ($domainname, $msgctxt, $msgid) = @_;
 
     return dcnpgettext ($domainname, $msgctxt, $msgid, undef, undef, undef);
 }
 
 sub dcpgettext($$$$) {
     my ($domainname, $msgctxt, $msgid, $category) = @_;
 
     return dcnpgettext ($domainname, $msgctxt, $msgid, undef, undef, undef);
 }
 
 sub npgettext ($$$$) {
     my ($msgctxt, $msgid, $msgid_plural, $n) = @_;
 
     return dcnpgettext ('', $msgctxt, $msgid, $msgid_plural, $n, undef);
 }
 
 sub dnpgettext ($$$$$) {
     my ($domainname, $msgctxt, $msgid, $msgid_plural, $n) = @_;
 
     return dcnpgettext ($domainname, $msgctxt, $msgid, $msgid_plural, $n, undef);
 }
 
 sub dcnpgettext ($$$$$$) {
     my ($domainname, $msgctxt, $msgid, $msgid_plural, $n, $category) = @_;
 
     my $locale;
 
     if (exists $ENV{LANGUAGE} && length $ENV{LANGUAGE}) {
         $locale = $ENV{LANGUAGE};
         $locale =~ s/:.*//s;
     } elsif (exists $ENV{LC_ALL} && length $ENV{LC_ALL}) {
         $locale = $ENV{LC_ALL};
     } elsif (exists $ENV{LANG} && length $ENV{LANG}) {
         $locale = $ENV{LANG};
     } elsif (exists $ENV{LC_MESSAGES} && length $ENV{LC_MESSAGES}) {
         $locale = $ENV{LC_MESSAGES};
     } else {
         $locale = 'C';
     }
     
     return Locale::gettext_pp::_dcnpgettext_impl ($domainname, $msgctxt,
                                                   $msgid, $msgid_plural, $n,
                                                   $category, $locale);
 }
 
 sub setlocale($;$) {
 	&POSIX::setlocale;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::gettext_dumb - Locale unaware Implementation of Uniforum Message Translation
 
 =head1 SYNOPSIS
 
  use Locale::gettext_dumb (:locale_h :libintl_h);
 
  # Normally, you will not want to include this module directly but this way:
  use Locale::Messages;
  
  my $selected = Locale::Messages->select_package ('gettext_dumb');
 
  gettext $msgid;
  dgettext $domainname, $msgid;
  dcgettext $domainname, $msgid, LC_MESSAGES;
  ngettext $msgid, $msgid_plural, $count;
  dngettext $domainname, $msgid, $msgid_plural, $count;
  dcngettext $domainname, $msgid, $msgid_plural, $count, LC_MESSAGES;
  pgettext $msgctxt, $msgid;
  dpgettext $domainname, $msgctxt, $msgid;
  dcpgettext $domainname, $msgctxt, $msgid, LC_MESSAGES;
  npgettext $msgctxt, $msgid, $msgid_plural, $count;
  dnpgettext $domainname, $msgctxt, $msgid, $msgid_plural, $count;
  dcnpgettext $domainname, $msgctxt, $msgid, $msgid_plural, $count, LC_MESSAGES;
  textdomain $domainname;
  bindtextdomain $domainname, $directory;
  bind_textdomain_codeset $domainname, $encoding;
  my $category = LC_CTYPE;
  my $category = LC_NUMERIC;
  my $category = LC_TIME;
  my $category = LC_COLLATE;
  my $category = LC_MONETARY;
  my $category = LC_MESSAGES;
  my $category = LC_ALL;
 
 =head1 DESCRIPTION
 
 B<IMPORTANT!> This module is experimental.  It may not work as described!
 
 The module B<Locale::gettext_dumb> does exactly the same as 
 Locale::gettext_xs(3pm) or Locale::gettext_pp(3pm).
 
 While both other modules use POSIX::setlocale() to determine the currently
 selected locale, this backend only checks the environment variables
 LANGUAGE, LANG, LC_ALL, LC_MESSAGES (in that order), when it tries to locate
 a message catalog (a .mo file).
 
 This class was introduced in libintl-perl 1.22.
 
 =head1 USAGE
 
 This module should not be used for desktop software or scripts run locally.
 Why? If you use a message catalog for example in Danish in UTF-8 (da_DA.UTF8)
 but the  system locale is set to Russian with KOI8-R (ru_RU.KOI8-R) you
 may produce invalid output, either invalid multi-byte sequences or invalid
 text, depending on how you look at it.
 
 That will happen, when you mix output from B<Locale::gettext_pp> with
 locale-dependent output from the operating system like the contents of
 the variable "$!", date and time formatting functions (localtime(),
 gmtime(), POSIX::strftime() etc.), number formatting with printf() and
 friends, and so on.
 
 A typical usage scenario looks like this:
 
 You have a server application (for example a web application) that is supposed
 to display a fixed set of messages in many languages.  If you want to do this
 with Locale::gettext_xs(3pm) or Locale::gettext_pp(3pm), you have to install
 the locale data for all of those languages.  Otherwise, translating the
 messages will not work.
 
 With Locale::gettext_dumb(3pm) you can relax these requirements, and display
 messages for all languages that you have mo files for.
 
 On the other hand, you will soon reach limits with this approach.  Almost
 any application requires more than bare translation of messages for
 localisation.  You want to formatted dates and times, you want to display
 numbers in the correct formatting for the selected languages, and you may
 want to display system error messages ("$!").
 
 In practice, Locale::gettext_dumb(3pm) is still useful in these scenarios.
 Your users will have to live with the fact that the presented output is
 in different languages resp. for different locales, when "their" locale
 is not installed on your system.
 
 More dangerous is mixing output in different character sets but that can
 be easily avoided.  Simply make sure that B<Locale::gettext_dump> uses 
 UTF-8 (for example by setting the environment variable OUTPUT_CHARSET or
 by calling bind_textdomain_codeset()) and make sure that the system locale
 also uses UTF-8, for example "en_US.UTF8".  If that fails, switch to a
 locale that uses a subset of UTF-8.  In practice that will be US-ASCII, the
 character set used by the default locale "C" resp. "POSIX".
 
 Your application will then to a certain extent mix output for different
 localisations resp. languages.  But this is completely under your control.
 
 =head1 EXAMPLE
 
 See above! Normally you should not use this module! However, let us assume
 you have read the warnings.  In a web application you would do something
 like this:
 
     use Locale::TextDomain qw (com.example.yourapp);
     use Locale::Messages qw (nl_putenv LC_ALL bindtextdomain
                              bind_textdomain_codeset);
     use Locale::Util qw (web_set_locale);
     use POSIX qw (setlocale);
     
     # First try to switch to the locale requested by the user.  If you
     # know it you can try to pass it to setlocale like this:
     #
     #   my $hardcoded_locale = 'fr_FR.UTF-8';
     #   my $success = POSIX::setlocale (LC_ALL, $hardcoded_locale);
     #
     # However, we try to let libintl-perl do a better job for us:
     my $success = web_set_locale $ENV{HTTP_ACCEPT_LANGUAGE},
                                  $ENV{HTTP_ACCEPT_CHARSET};
     # Note: If your application forces the use of UTF-8 for its output
     # you should pass 'UTF-8' as the second argument to web_set_locale
     # instead of $ENV{HTTP_ACCEPT_CHARSET}.
     
     if (!$success) {
         # Did not work.  Switch to the dumb interface of
         # Locale::Messages.
         Locale::Messages->select_package ('gettext_dumb');
         
         # And try to switch to a default locale:
         if (!setlocale (LC_ALL, 'en_US.UTF-8')) {
             # Still no luck.  Enforce at least US-ASCII:
             setlocale (LC_ALL, 'C');
         }
         bind_textdomain_codeset 'com.example.yourapp', 'utf-8';
     }
     
 If your application forces the usage of UTF-8 you should ignore the environment
 variable 
     
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::TextDomain(3pm), Locale::Messages(3pm), Encode(3pm),
 perllocale(3pm), POSIX(3pm), perl(1), gettext(1), gettext(3)
 
 =cut
 
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 tab-width: 4
 End:
### Locale/gettext_pp.pm ###
 #! /bin/false
 
 # vim: set autoindent shiftwidth=4 tabstop=4:
 
 # Pure Perl implementation of Uniforum message translation.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::gettext_pp;
 
 use strict;
 
 require 5.004;
 
 use vars qw ($__gettext_pp_default_dir 
     		 $__gettext_pp_textdomain
     		 $__gettext_pp_domain_bindings
     		 $__gettext_pp_domain_codeset_bindings
     		 $__gettext_pp_domains
     		 $__gettext_pp_recoders
     		 $__gettext_pp_unavailable_dirs
     		 $__gettext_pp_domain_cache
     		 $__gettext_pp_alias_cache
     		 $__gettext_pp_context_glue);
 
 use locale;
 use File::Spec;
 
 BEGIN {
     $__gettext_pp_textdomain = 'messages';
     $__gettext_pp_domain_bindings = {};
     $__gettext_pp_domain_codeset_bindings = {};
     $__gettext_pp_domains = {};
     $__gettext_pp_recoders = {};
     $__gettext_pp_unavailable_dirs = {};
     $__gettext_pp_domain_cache = {};
     $__gettext_pp_alias_cache = {};
     # The separator between msgctxt and msgid in a .mo file.  */
     $__gettext_pp_context_glue = "\004";
     
     $__gettext_pp_default_dir = '';
     
     for my $dir (qw (/usr/share/locale /usr/local/share/locale)) {
     	if (-d $dir) {
     		$__gettext_pp_default_dir = $dir;
     		last;
     	}
     }
 }
 
 BEGIN {
     	require POSIX;
     	require Exporter;
     	use IO::Handle;
     	require Locale::Recode;
 
     	local $@;
     	my ($has_messages, $five_ok);
     	
     	$has_messages = eval '&POSIX::LC_MESSAGES';
 
     	unless (defined $has_messages && length $has_messages) {
     			$five_ok = ! grep {my $x = eval "&POSIX::$_" || 0; $x eq '5';}
     							qw (LC_CTYPE
     							   LC_NUMERIC
     							   LC_TIME
     							   LC_COLLATE
     							   LC_MONETARY
     							   LC_ALL);
     		if ($five_ok) {
     			$five_ok = POSIX::setlocale (5, '');
     		}
     	}
     	
     	if (defined $has_messages && length $has_messages) {
 eval <<'EOF';
 sub LC_MESSAGES()
 {
     local $!; # Do not clobber errno!
     
     return &POSIX::LC_MESSAGES;
 }
 EOF
     	} elsif ($five_ok) {
 eval <<'EOF';
 sub LC_MESSAGES()
 {
     local $!; # Do not clobber errno!
 
     # Hack: POSIX.pm deems LC_MESSAGES an invalid macro until
     # Perl 5.8.0.  However, on LC_MESSAGES should be 5 ...
     return 5;
 }
 EOF
     	} else {
 eval <<'EOF';
 sub LC_MESSAGES()
 {
     local $!; # Do not clobber errno!
 
     # This fallback value is widely used,
     # when LC_MESSAGES is not available.
     return 1729;
 }
 EOF
     	}
 }
 
 use vars qw (%EXPORT_TAGS @EXPORT_OK @ISA $VERSION);
 
 %EXPORT_TAGS = (locale_h => [ qw (
     							  gettext
     							  dgettext
     							  dcgettext
     							  ngettext
     							  dngettext
     							  dcngettext
     							  pgettext
     							  dpgettext
     							  dcpgettext
     							  npgettext
     							  dnpgettext
     							  dcnpgettext
     							  textdomain
     							  bindtextdomain
     							  bind_textdomain_codeset
     							  )
     						  ],
     			libintl_h => [ qw (LC_CTYPE
     							   LC_NUMERIC
     							   LC_TIME
     							   LC_COLLATE
     							   LC_MONETARY
     							   LC_MESSAGES
     							   LC_ALL)
     						   ],
     			);
 
 @EXPORT_OK = qw (gettext
     			 dgettext
     			 dcgettext
     			 ngettext
     			 dngettext
     			 dcngettext
     			 pgettext
     			 dpgettext
     			 dcpgettext
     			 npgettext
     			 dnpgettext
     			 dcnpgettext
     			 textdomain
     			 bindtextdomain
     			 bind_textdomain_codeset
                  nl_putenv
                  setlocale
     			 LC_CTYPE
     			 LC_NUMERIC
     			 LC_TIME
     			 LC_COLLATE
     			 LC_MONETARY
     			 LC_MESSAGES
     			 LC_ALL);
 @ISA = qw (Exporter);
 
 my $has_nl_langinfo;
 
 sub __load_catalog;
 sub __load_domain;
 sub __locale_category;
 sub __untaint_plural_header;
 sub __compile_plural_function;
 
 sub LC_NUMERIC()
 {
     &POSIX::LC_NUMERIC;
 }
 
 sub LC_CTYPE()
 {
     &POSIX::LC_CTYPE;
 }
 
 sub LC_TIME()
 {
     &POSIX::LC_TIME;
 }
 
 sub LC_COLLATE()
 {
     &POSIX::LC_COLLATE;
 }
 
 sub LC_MONETARY()
 {
     &POSIX::LC_MONETARY;
 }
 
 sub LC_ALL()
 {
     &POSIX::LC_ALL;
 }
 
 sub textdomain(;$)
 {
     my $new_domain = shift;
     
     $__gettext_pp_textdomain = $new_domain if defined $new_domain && 
     	length $new_domain;
     
     return $__gettext_pp_textdomain;
 }
 
 sub bindtextdomain($;$)
 {
     my ($domain, $directory) = @_;
 
     my $retval;	
     if (defined $domain && length $domain) {
     	if (defined $directory && length $directory) {
     		$retval = $__gettext_pp_domain_bindings->{$domain} 
     			= $directory;
     	} elsif (exists $__gettext_pp_domain_bindings->{$domain}) {
     		$retval = $__gettext_pp_domain_bindings->{$domain};
     	} else {
     		$retval = $__gettext_pp_default_dir;
     	}
     	$retval = '/usr/share/locale' unless defined $retval && 
     		length $retval;
     	return $retval;
     } else {
     	return;
     }
 }
 
 sub bind_textdomain_codeset($;$)
 {
     my ($domain, $codeset) = @_;
     
     if (defined $domain && length $domain) {
     	if (defined $codeset && length $codeset) {
     		return $__gettext_pp_domain_codeset_bindings->{$domain} = $codeset;
     	} elsif (exists $__gettext_pp_domain_codeset_bindings->{$domain}) {
     		return $__gettext_pp_domain_codeset_bindings->{$domain};
     	}
     }
     
     return;
 }
 
 sub gettext($)
 {
     my ($msgid) = @_;
 
     return dcnpgettext ('', undef, $msgid, undef, undef, undef);
 }
 
 sub dgettext($$)
 {
     my ($domainname, $msgid) = @_;
 
     return dcnpgettext ($domainname, undef, $msgid, undef, undef, undef);
 }
 
 sub dcgettext($$$)
 {
     my ($domainname, $msgid, $category) = @_;
 
     return dcnpgettext ($domainname, undef, $msgid, undef, undef, undef);
 }
 
 sub ngettext($$$)
 {
     my ($msgid, $msgid_plural, $n) = @_;
 
     return dcnpgettext ('', undef, $msgid, $msgid_plural, $n, undef);
 }
 
 sub dngettext($$$$)
 {
     my ($domainname, $msgid, $msgid_plural, $n) = @_;
 
     return dcnpgettext ($domainname, undef, $msgid, $msgid_plural, $n, undef);
 }
 
 sub dcngettext($$$$$)
 {
     my ($domainname, $msgid, $msgid_plural, $n, $category) = @_;
 
     return dcnpgettext ($domainname, undef, $msgid, $msgid_plural, $n, , $category);
 }
 
 
 sub pgettext($$)
 {
     my ($msgctxt, $msgid) = @_;
 
     return dcnpgettext ('', $msgctxt, $msgid, undef, undef, undef);
 }
 
 sub dpgettext($$$)
 {
     my ($domainname, $msgctxt, $msgid) = @_;
 
     return dcnpgettext ($domainname, $msgctxt, $msgid, undef, undef, undef);
 }
 
 sub dcpgettext($$$$)
 {
     my ($domainname, $msgctxt, $msgid, $category) = @_;
 
     return dcnpgettext ($domainname, $msgctxt, $msgid, undef, undef, undef);
 }
 
 sub npgettext($$$$)
 {
     my ($msgctxt, $msgid, $msgid_plural, $n) = @_;
 
     return dcnpgettext ('', $msgctxt, $msgid, $msgid_plural, $n, undef);
 }
 
 sub dnpgettext($$$$$)
 {
     my ($domainname, $msgctxt, $msgid, $msgid_plural, $n) = @_;
 
     return dcnpgettext ($domainname, $msgctxt, $msgid, $msgid_plural, $n, undef);
 }
 
 # This is the actual implementation of dncpgettext.  It is also used by the
 # corresponding function in Locale::gettext_dumb.
 sub _dcnpgettext_impl {
     my ($domainname, $msgctxt, $msgid, $msgid_plural, $n, $category,
         $locale) = @_;
 
     return unless defined $msgid;
 
     my $plural = defined $msgid_plural;
     my $msg_ctxt_id = defined $msgctxt ? join($__gettext_pp_context_glue, ($msgctxt, $msgid)) : $msgid;
     
     local $!; # Do not clobber errno!
     
     # This is also done in __load_domain but we need a proper value.
     $domainname = $__gettext_pp_textdomain
     	unless defined $domainname && length $domainname;
     
     # Category is always LC_MESSAGES (other categories are ignored).
     my $category_name = 'LC_MESSAGES';
     $category = LC_MESSAGES;
 
     my $domains = __load_domain ($domainname, $category, $category_name,
                                  $locale);
     
     my @trans = ();
     my $domain;
     my $found;
     foreach my $this_domain (@$domains) {
     	if ($this_domain && defined $this_domain->{messages}->{$msg_ctxt_id}) {
     		@trans = @{$this_domain->{messages}->{$msg_ctxt_id}};
     		shift @trans;
     		$domain = $this_domain;
     		$found = 1;
     		last;
     	}
     }
     @trans = ($msgid, $msgid_plural) unless @trans;
     
     my $trans = $trans[0];
     if ($plural) {
     	if ($domain) {
     		my $nplurals = 0;
     		($nplurals, $plural) = &{$domain->{plural_func}} ($n);
     		$plural = 0 unless defined $plural;
     		$nplurals = 0 unless defined $nplurals;
     		$plural = 0 if $nplurals <= $plural;
     	} else {
     		$plural = $n != 1 || 0;
     	}
     	
     	$trans = $trans[$plural] if defined $trans[$plural];
     }
     
     if ($found && defined $domain->{po_header}->{charset}) {
     	my $input_codeset = $domain->{po_header}->{charset};
     	# Convert into output charset.
     	my $output_codeset = $__gettext_pp_domain_codeset_bindings->{$domainname};
 
     	$output_codeset = $ENV{OUTPUT_CHARSET} unless defined $output_codeset;
     	$output_codeset = __get_codeset ($category, $category_name,
     									 $domain->{locale_id})
     		unless defined $output_codeset;
     	
     	unless (defined $output_codeset) {
     		# Still no point.
     		my $lc_ctype = __locale_category (POSIX::LC_CTYPE(), 
     									   'LC_CTYPE');
     		$output_codeset = $1
     			if $lc_ctype =~ /^[a-z]{2}(?:_[A-Z]{2})?\.([^@]+)/;
     	}
 
     	# No point. :-(
     	$output_codeset = $domain->{po_header}->{charset}
     		unless defined $output_codeset;
     
     	if (exists $__gettext_pp_domain_cache->{$output_codeset}) {
     		$output_codeset = $__gettext_pp_domain_cache->{$output_codeset};
     	} else {
     		$output_codeset = 'utf-8' if lc $output_codeset eq 'utf8';
     		$output_codeset = 
     			$__gettext_pp_domain_cache->{$output_codeset} =
     			Locale::Recode->resolveAlias ($output_codeset);
     	}
     	
     	if (defined $output_codeset &&
     		$output_codeset ne $domain->{po_header}->{charset}) {
     		# We have to convert.
     		my $recoder;
     		
     		if (exists 
     			$__gettext_pp_recoders->{$input_codeset}->{$output_codeset}) {
     			$recoder = $__gettext_pp_recoders->{$input_codeset}->{$output_codeset};
     		} else {
     			$recoder = 
     				$__gettext_pp_recoders->{$input_codeset}->{$output_codeset} =
     				Locale::Recode->new (from => $input_codeset,
     									 to => $output_codeset,
     									 );
     		}
     		
     		$recoder->recode ($trans);
     	}
     }
     
     return $trans;
 }
 
 sub dcnpgettext ($$$$$$) {
     return &_dcnpgettext_impl;
 }
 
 sub nl_putenv ($)
 {
     my ($envspec) = @_;
     return unless defined $envspec;
     return unless length $envspec;
     return if substr ($envspec, 0, 1) eq '=';
     
     my ($var, $value) = split /=/, $envspec, 2;
 
     # In Perl we *could* set empty environment variables even under
     # MS-DOS, but for compatibility reasons, we implement the
     # brain-damaged behavior of the Microsoft putenv().
     if ($^O eq 'MSWin32') {
         $value = '' unless defined $value;
         if (length $value) {
             $ENV{$var} = $value;
         } else {
             delete $ENV{$var};
         }
     } else {
         if (defined $value) {
             $ENV{$var} = $value;
         } else {
             delete $ENV{$var};
         }
     }
 
     return 1;
 }
 
 sub setlocale($;$) {
 	require POSIX;
 	&POSIX::setlocale;
 }
 
 sub __load_domain
 {
     my ($domainname, $category, $category_name, $locale) = @_;
 
         # If no locale was selected for the requested locale category,
         # l10n is disabled completely.  This matches the behavior of GNU
         # gettext.
         if ($category != LC_MESSAGES) {
             # Not supported.
             return [];
         }
         
         if (!defined $locale && $category != 1729) {
                 $locale = POSIX::setlocale ($category);
                 if (!defined $locale || 'C' eq $locale || 'POSIX' eq $locale) {
                         return [];
                 }
         }
     
     $domainname = $__gettext_pp_textdomain
     	unless defined $domainname && length $domainname;
 
     my $dir = bindtextdomain ($domainname, '');
     $dir = $__gettext_pp_default_dir unless defined $dir && length $dir;
     return [] unless defined $dir && length $dir;
 
     my @locales;
     my $cache_key;
 
     if (defined $ENV{LANGUAGE} && length $ENV{LANGUAGE}) {
     	@locales = split /:/, $ENV{LANGUAGE};
     	$cache_key = $ENV{LANGUAGE};
     } elsif (!defined $locale) {
             # The system does not have LC_MESSAGES.  Guess the value.
     	@locales = $cache_key = __locale_category ($category, 
     	                                           $category_name);
     } else {
             @locales = $cache_key = $locale;
     }
 
     # Have we looked that one up already?
     my $domains = $__gettext_pp_domain_cache->{$dir}->{$cache_key}->{$category_name}->{$domainname};
     return $domains if defined $domains;
     return [] unless @locales;
     
     my @dirs = ($dir);
     my @tries = (@locales);
     my %locale_lookup = map { $_ => $_ } @tries;
 
     foreach my $locale (@locales) {
     	if ($locale =~ /^([a-z][a-z])
     		(?:(_[A-Z][A-Z])?
     		 (\.[-_A-Za-z0-9]+)?
     		 )?
     		(\@[-_A-Za-z0-9]+)?$/x) {
     		
     		if (defined $3) {
     			defined $2 ?
     				push @tries, $1 . $2 . $3 : push @tries, $1 . $3;
     		}
     		if (defined $2) {
     			push @tries, $1 . $2;
     			$locale_lookup{$1 . $2} = $locale;
     		}
     		if (defined $1) {
     			push @tries, $1 if defined $1;
     			$locale_lookup{$1} = $locale;
     		}
     	}
     }
     	push @dirs, $__gettext_pp_default_dir
     	if $__gettext_pp_default_dir && $dir ne $__gettext_pp_default_dir;
     
     my %seen = ();
     foreach my $basedir (@dirs) {
     	foreach my $try (@tries) {
     		my $fulldir = "$basedir/$try/$category_name";
     		
     		next if $seen{$fulldir}++;
 
     		# If the cache for unavailable directories is removed,
     		# the three lines below should be replaced by:
     		# 'next unless -d $fulldir;'
     		next if $__gettext_pp_unavailable_dirs->{$fulldir};
     		++$__gettext_pp_unavailable_dirs->{$fulldir} and next
     				unless -d $fulldir;
                         my $filename = File::Spec->catfile ($fulldir, 
                                                             "$domainname.mo");
     		my $domain = __load_catalog ($filename, $try);
     		next unless $domain;
     			
     		$domain->{locale_id} = $locale_lookup{$try};
     		push @$domains, $domain;
     	}
     }
     $__gettext_pp_domain_cache->{$dir}
                               ->{$cache_key}
                               ->{$category_name}
                               ->{$domainname} = $domains;
 
     $domains = [] unless defined $domains;
     
     return $domains;
 }
 
 sub __load_catalog
 {
     my ($filename, $locale) = @_;
     
     # Alternatively we could check the filename for evil characters ...
     # (Important for CGIs).
     return unless -f $filename && -r $filename;
     
     local $/;
     local *HANDLE;
     
     open HANDLE, "<$filename"
     	or return;
     binmode HANDLE;
     my $raw = <HANDLE>;
     close HANDLE;
     
     # Corrupted?
     return if ! defined $raw || length $raw < 28;
     
     my $filesize = length $raw;
     
     # Read the magic number in order to determine the byte order.
     my $domain = {};
     my $unpack = 'N';
     $domain->{potter} = unpack $unpack, substr $raw, 0, 4;
     
     if ($domain->{potter} == 0xde120495) {
     	$unpack = 'V';
     } elsif ($domain->{potter} != 0x950412de) {
     	return;
     }
     my $domain_unpack = $unpack x 6;
     
     my ($revision, $num_strings, $msgids_off, $msgstrs_off,
     	$hash_size, $hash_off) = 
     		unpack (($unpack x 6), substr $raw, 4, 24);
     
     return unless $revision == 0; # Invalid revision number.
     
     $domain->{revision} = $revision;
     $domain->{num_strings} = $num_strings;
     $domain->{msgids_off} = $msgids_off;
     $domain->{msgstrs_off} = $msgstrs_off;
     $domain->{hash_size} = $hash_size;
     $domain->{hash_off} = $hash_off;
     
     return if $msgids_off + 4 * $num_strings > $filesize;
     return if $msgstrs_off + 4 * $num_strings > $filesize;
     
     my @orig_tab = unpack (($unpack x (2 * $num_strings)), 
     					   substr $raw, $msgids_off, 8 * $num_strings);
     my @trans_tab = unpack (($unpack x (2 * $num_strings)), 
     						substr $raw, $msgstrs_off, 8 * $num_strings);
     
     my $messages = {};
     
     for (my $count = 0; $count < 2 * $num_strings; $count += 2) {
     	my $orig_length = $orig_tab[$count];
     	my $orig_offset = $orig_tab[$count + 1];
     	my $trans_length = $trans_tab[$count];
     	my $trans_offset = $trans_tab[$count + 1];
     	
     	return if $orig_offset + $orig_length > $filesize;
     	return if $trans_offset + $trans_length > $filesize;
     	
     	my @origs = split /\000/, substr $raw, $orig_offset, $orig_length;
     	my @trans = split /\000/, substr $raw, $trans_offset, $trans_length;
     	
     	# The singular is the key, the plural plus all translations is the
     	# value.
     	my $msgid = $origs[0];
     	$msgid = '' unless defined $msgid && length $msgid;
     	my $msgstr = [ $origs[1], @trans ];
     	$messages->{$msgid} = $msgstr;
     }
     
     $domain->{messages} = $messages;
     
     # Try to find po header information.
     my $po_header = {};
     my $null_entry = $messages->{''}->[1];
     if ($null_entry) {
     	my @lines = split /\n/, $null_entry;
     	foreach my $line (@lines) {
     		my ($key, $value) = split /:/, $line, 2;
     		$key =~ s/-/_/g;
     		$po_header->{lc $key} = $value;
     	}
     }
     $domain->{po_header} = $po_header;
     
     if (exists $domain->{po_header}->{content_type}) {
     	my $content_type = $domain->{po_header}->{content_type};
     	if ($content_type =~ s/.*=//) {
     		$domain->{po_header}->{charset} = $content_type;
     	}
     }
     
     my $code = $domain->{po_header}->{plural_forms} || '';
     
     # Whitespace, locale-independent.
     my $s = '[ \t\r\n\013\014]';
 
     # Untaint the plural header.
     # Keep line breaks as is (Perl 5_005 compatibility).
     $code = $domain->{po_header}->{plural_forms} 
         = __untaint_plural_header $code;
 
     $domain->{plural_func} = __compile_plural_function $code;
 
     unless (defined $domain->{po_header}->{charset} 
             && length $domain->{po_header}->{charset} 
             && $locale =~ /^(?:[a-z][a-z])
                             (?:(?:_[A-Z][A-Z])?
                              (\.[-_A-Za-z0-9]+)?
                             )?
                             (?:\@[-_A-Za-z0-9]+)?$/x) {
         $domain->{po_header}->{charset} = $1;
     }
                                 
     if (defined $domain->{po_header}->{charset}) {
         $domain->{po_header}->{charset} = 
             Locale::Recode->resolveAlias ($domain->{po_header}->{charset});
     }
     
     return $domain;
 }
 
 sub __locale_category
 {
     my ($category, $category_name) = @_;
     
     local $@;
     my $value = eval {POSIX::setlocale ($category)};
     
     # We support only XPG syntax, i. e.
     # language[_territory[.codeset]][@modifier].
     undef $value unless (defined $value && 
     					 length $value &&
     					 $value =~ /^[a-z][a-z]
     					 (?:_[A-Z][A-Z]
     					  (?:\.[-_A-Za-z0-9]+)?
     					  )?
     					 (?:\@[-_A-Za-z0-9]+)?$/x);
 
     unless ($value) {
     	$value = $ENV{LC_ALL};
     	$value = $ENV{$category_name} unless defined $value && length $value;
     	$value = $ENV{LANG} unless defined $value && length $value;
     	return 'C' unless defined $value && length $value;
     }
     
     return $value if $value ne 'C' && $value ne 'POSIX';
 }
 
 sub __get_codeset
 {
     my ($category, $category_name, $locale_id) = @_;
 
     local $@;
     unless (defined $has_nl_langinfo) {
     	eval {
     		require I18N::Langinfo;
     	};
     	$has_nl_langinfo = !$@;
     }
 
     if ($has_nl_langinfo) {
     	# Try to set the locale via the specified id.
     	my $saved_locale = eval { POSIX::setlocale (LC_ALL) };
     	my $had_lc_all = exists $ENV{LC_ALL};
     	my $saved_lc_all = $ENV{LC_ALL} if $had_lc_all;
 
     	# Now try to set the locale via the environment.  There is no
     	# point in calling the langinfo routines if this fails.
     	$ENV{LC_ALL} = $locale_id;
     	my $codeset;
     	my $lc_all = eval { POSIX::setlocale (LC_ALL, $locale_id); };
     	$codeset = I18N::Langinfo::langinfo (I18N::Langinfo::CODESET())
     		if defined $lc_all;
 
         # Restore environment.
     	if ($saved_locale) {
     		eval { POSIX::setlocale (LC_ALL, $saved_locale); }
     	}
     	if ($had_lc_all) {
             $ENV{LC_ALL} = $saved_lc_all if $had_lc_all;
     	} else {
     	    delete $ENV{LC_ALL};
     	}
     	return $codeset;
     }
 
     return;
 }
     
 sub __untaint_plural_header {
     my ($code) = @_;
 
     # Whitespace, locale-independent.
     my $s = '[ \t\r\n\013\014]';
 
     if ($code =~ m{^($s*
     				 nplurals$s*=$s*[0-9]+
     				 $s*;$s*
     				 plural$s*=$s*(?:$s|[-\?\|\&=!<>+*/\%:;a-zA-Z0-9_\(\)])+
     				 )}xms) {
     	return $1;
     }
 
     return '';    
 }
 
 sub __compile_plural_function {
     my ($code) = @_;
 
     # The leading and trailing space is necessary to be able to match
     # against word boundaries.
     my $plural_func;
     
     if (length $code) {
     	my $code = ' ' . $code . ' ';
     	$code =~ 
     		s/(?<=[^_a-zA-Z0-9])[_a-z][_A-Za-z0-9]*(?=[^_a-zA-Z0-9])/\$$&/gs;
     	
     	$code = "sub { my \$n = shift || 0; 
     			   my (\$plural, \$nplurals); 
     			   $code; 
     			   return (\$nplurals, \$plural ? \$plural : 0); }";
     	
     	# Now try to evaluate the code.	 There is no need to run the code in
     	# a Safe compartment.  The above substitutions should have destroyed
     	# all evil code.  Corrections are welcome!
         #warn $code;
     	$plural_func = eval $code;
         #warn $@ if $@;
     	undef $plural_func if $@;
     }
         
     # Default is Germanic plural (which is incorrect for French).
     $plural_func = eval "sub { (2, 1 != shift || 0) }" unless $plural_func;
 
     return $plural_func;    
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Locale::gettext_pp - Pure Perl Implementation of Uniforum Message Translation
 
 =head1 SYNOPSIS
 
  use Locale::gettext_pp (:locale_h :libintl_h);
 
  gettext $msgid;
  dgettext $domainname, $msgid;
  dcgettext $domainname, $msgid, LC_MESSAGES;
  ngettext $msgid, $msgid_plural, $count;
  dngettext $domainname, $msgid, $msgid_plural, $count;
  dcngettext $domainname, $msgid, $msgid_plural, $count, LC_MESSAGES;
  pgettext $msgctxt, $msgid;
  dpgettext $domainname, $msgctxt, $msgid;
  dcpgettext $domainname, $msgctxt, $msgid, LC_MESSAGES;
  npgettext $msgctxt, $msgid, $msgid_plural, $count;
  dnpgettext $domainname, $msgctxt, $msgid, $msgid_plural, $count;
  dcnpgettext $domainname, $msgctxt, $msgid, $msgid_plural, $count, LC_MESSAGES;
  textdomain $domainname;
  bindtextdomain $domainname, $directory;
  bind_textdomain_codeset $domainname, $encoding;
  my $category = LC_CTYPE;
  my $category = LC_NUMERIC;
  my $category = LC_TIME;
  my $category = LC_COLLATE;
  my $category = LC_MONETARY;
  my $category = LC_MESSAGES;
  my $category = LC_ALL;
 
 =head1 DESCRIPTION
 
 The module B<Locale::gettext_pp> is the low-level interface to 
 message translation according to the Uniforum approach that is
 for example used in GNU gettext and Sun's Solaris.
 
 Normally you should not use this module directly, but the high
 level interface Locale::TextDomain(3) that provides a much simpler
 interface.    This description is therefore deliberately kept
 brief.    Please refer to the GNU gettext documentation available at
 L<http://www.gnu.org/manual/gettext/> for in-depth and background 
 information on the topic.
 
 =head1 FUNCTIONS
 
 The module exports by default nothing.    Every function has to be
 imported explicitely or via an export tag (L<"EXPORT TAGS">).
 
 =over 4
 
 =item B<gettext MSGID>
 
 See L<Locale::Messages/FUNCTIONS>.
 
 =item B<dgettext TEXTDOMAIN, MSGID>
 
 See L<Locale::Messages/FUNCTIONS>.
 
 =item B<dcgettext TEXTDOMAIN, MSGID, CATEGORY>
 
 See L<Locale::Messages/FUNCTIONS>.
 
 =item B<ngettext MSGID, MSGID_PLURAL, COUNT>
 
 See L<Locale::Messages/FUNCTIONS>.
 
 =item B<dngettext TEXTDOMAIN, MSGID, MSGID_PLURAL, COUNT>
 
 See L<Locale::Messages/FUNCTIONS>.
 
 =item B<dcngettext TEXTDOMAIN, MSGID, MSGID_PLURAL, COUNT, CATEGORY>
 
 See L<Locale::Messages/FUNCTIONS>.
 
 =item B<pgettext MSGCTXT, MSGID>
 
 See L<Locale::Messages/FUNCTIONS>.
 
 =item B<dpgettext TEXTDOMAIN, MSGCTXT, MSGID>
 
 See L<Locale::Messages/FUNCTIONS>.
 
 =item B<dcpgettext TEXTDOMAIN, MSGCTXT, MSGID, CATEGORY>
 
 See L<Locale::Messages/FUNCTIONS>.
 
 =item B<npgettext MSGCTXT, MSGID, MSGID_PLURAL, COUNT>
 
 See L<Locale::Messages/FUNCTIONS>.
 
 =item B<dnpgettext TEXTDOMAIN, MSGCTXT, MSGID, MSGID_PLURAL, COUNT>
 
 See L<Locale::Messages/FUNCTIONS>.
 
 =item B<dcnpgettext TEXTDOMAIN, MSGCTXT, MSGID, MSGID_PLURAL, COUNT, CATEGORY>
 
 See L<Locale::Messages/FUNCTIONS>.
 
 =item B<textdomain TEXTDOMAIN>
 
 See L<Locale::Messages/FUNCTIONS>.
 
 =item B<bindtextdomain TEXTDOMAIN, DIRECTORY>
 
 See L<Locale::Messages/FUNCTIONS>.
 
 =item B<bind_textdomain_codeset TEXTDOMAIN, ENCODING>
 
 =item B<nl_putenv ENVSPEC>
 
 See L<Locale::Messages/FUNCTIONS>.
 
 =item B<setlocale>
 
 See L<Locale::Messages/FUNCTIONS>.
 
 =back
 
 =head1 CONSTANTS
 
 You can (maybe) get the same constants from POSIX(3); see there for
 a detailed description
 
 =over 4
 
 =item B<LC_CTYPE>
 
 =item B<LC_NUMERIC>
 
 =item B<LC_TIME>
 
 =item B<LC_COLLATE>
 
 =item B<LC_MONETARY>
 
 =item B<LC_MESSAGES>
 
 =item B<LC_ALL>
 
 See L<Locale::Messages/CONSTANTS> for more information.
 
 =back
 
 =head1 EXPORT TAGS
 
 This module does not export anything unless explicitely requested.
 You can import groups of functions via two tags:
 
 =over 4
 
 =item B<use Locale::gettext_pp (':locale_h')>
 
 Imports the functions that are normally defined in the C include
 file F<locale.h>:
 
 =over 8
 
 =item B<gettext()>
 
 =item B<dgettext()>
 
 =item B<dcgettext()>
 
 =item B<ngettext()>
 
 =item B<dngettext()>
 
 =item B<dcngettext()>
 
 =item B<pgettext()>
 
 Introduced with libintl-perl 1.17.
 
 =item B<dpgettext()>
 
 Introduced with libintl-perl 1.17.
 
 =item B<dcpgettext()>
 
 Introduced with libintl-perl 1.17.
 
 =item B<npgettext()>
 
 Introduced with libintl-perl 1.17.
 
 =item B<dnpgettext()>
 
 Introduced with libintl-perl 1.17.
 
 =item B<dcnpgettext()>
 
 Introduced with libintl-perl 1.17.
 
 =item B<textdomain()>
 
 =item B<bindtextdomain()>
 
 =item B<bind_textdomain_codeset()>
 
 =back
 
 =item B<use Locale::gettext_pp (':libintl_h')>
 
 Imports the locale category constants:
 
 =over 8
 
 =item B<LC_CTYPE>
 
 =item B<LC_NUMERIC>
 
 =item B<LC_TIME>
 
 =item B<LC_COLLATE>
 
 =item B<LC_MONETARY>
 
 =item B<LC_MESSAGES>
 
 =item B<LC_ALL>
 
 =back
 
 =back
 
 =head1 AUTHOR
 
 Copyright (C) 2002-2015, Guido Flohr E<lt>guido.flohr@cantanea.comE<gt>, all
 rights reserved.  See the source code for details.
 
 =head1 SEE ALSO
 
 Locale::TextDomain(3pm), Locale::Messages(3pm), Encode(3pm),
 perllocale(3pm), POSIX(3pm), perl(1), gettext(1), gettext(3)
 
 =cut
 
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 tab-width: 4
 End:
 
 =cut
### Locale/gettext_xs.pm ###
 #! /bin/false
 
 # vim: tabstop=4
 
 # Pure Perl implementation of Uniforum message translation.
 # Copyright (C) 2002-2015 Guido Flohr <guido.flohr@cantanea.com>,
 # all rights reserved.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 
 # 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 the
 # GNU General Public License for more details.
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package Locale::gettext_xs;
 
 require DynaLoader;
 require Exporter;
 
 use vars qw (%EXPORT_TAGS @EXPORT_OK @ISA);
 
 %EXPORT_TAGS = (locale_h => [ qw (
 								  gettext
 								  dgettext
 								  dcgettext
 								  ngettext
 								  dngettext
 								  dcngettext
 								  pgettext
 								  dpgettext
 								  dcpgettext
 								  npgettext
 								  dnpgettext
 								  dcnpgettext
 								  textdomain
 								  bindtextdomain
 								  bind_textdomain_codeset
 								  )
 							  ],
 				libintl_h => [ qw (LC_CTYPE
 								   LC_NUMERIC
 								   LC_TIME
 								   LC_COLLATE
 								   LC_MONETARY
 								   LC_MESSAGES
 								   LC_ALL)
 							   ],
 				);
 
 @EXPORT_OK = qw (gettext
 				 dgettext
 				 dcgettext
 				 ngettext
 				 dngettext
 				 dcngettext
                  pgettext
                  dpgettext
                  dcpgettext
                  npgettext
                  dnpgettext
                  dcnpgettext
 				 textdomain
 				 bindtextdomain
 				 bind_textdomain_codeset
 				 nl_putenv
                  setlocale
 				 LC_CTYPE
 				 LC_NUMERIC
 				 LC_TIME
 				 LC_COLLATE
 				 LC_MONETARY
 				 LC_MESSAGES
 				 LC_ALL);
 @ISA = qw (Exporter DynaLoader);
 
 bootstrap Locale::gettext_xs;
 
 require File::Spec;
 
 # Reimplement pgettext functions
 sub pgettext ($$) {
 	my ($msgctxt, $msgid) = @_;
 
 	my $msg_ctxt_id = join("\004", $msgctxt, $msgid);
 	return Locale::gettext_xs::_pgettext_aux
 		("", $msg_ctxt_id, $msgid, Locale::gettext_xs::LC_MESSAGES());
 }
 sub dpgettext ($$$) {
 	my ($domain, $msgctxt, $msgid) = @_;
 
 	my $msg_ctxt_id = join("\004", $msgctxt, $msgid);
 	return Locale::gettext_xs::_pgettext_aux
 		($domain, $msg_ctxt_id, $msgid, Locale::gettext_xs::LC_MESSAGES());
 }
 sub dcpgettext ($$$$) {
 	my ($domain, $msgctxt, $msgid, $category) = @_;
 
 	my $msg_ctxt_id = join("\004", $msgctxt, $msgid);
 	return Locale::gettext_xs::_pgettext_aux
 		($domain, $msg_ctxt_id, $msgid, $category);
 }
 
 # Reimplement npgettext functions
 sub npgettext ($$$$) {
 	my ($msgctxt, $msgid1, $msgid2, $n) = @_;
 
 	my $msg_ctxt_id = join("\004", $msgctxt, $msgid1);
 	return Locale::gettext_xs::_npgettext_aux
 		("", $msg_ctxt_id, $msgid1, $msgid2, $n, Locale::gettext_xs::LC_MESSAGES());
 }
 sub dnpgettext ($$$$$) {
 	my ($domain, $msgctxt, $msgid1, $msgid2, $n) = @_;
 
 	my $msg_ctxt_id = join("\004", $msgctxt, $msgid1);
 	return Locale::gettext_xs::_npgettext_aux
 		($domain, $msg_ctxt_id, $msgid1, $msgid2, $n, Locale::gettext_xs::LC_MESSAGES());
 }
 sub dcnpgettext ($$$$$$) {
 	my ($domain, $msgctxt, $msgid1, $msgid2, $n, $category) = @_;
 
 	my $msg_ctxt_id = join("\004", $msgctxt, $msgid1);
 	return Locale::gettext_xs::_npgettext_aux
 		($domain, $msg_ctxt_id, $msgid1, $msgid2, $n, $category);
 }
 
 # Wrapper function that converts Perl paths to OS paths.
 sub bindtextdomain ($;$) {
 	my ($domain, $directory) = @_;
 
 	if (defined $domain && length $domain && 
 		defined $directory && length $directory) {
 		return Locale::gettext_xs::_bindtextdomain 
 			($domain, File::Spec->catdir ($directory));
 	} else {
 		return &Locale::gettext_xs::_bindtextdomain;
 	}
 }
 
 # In the XS version, making the prototype optional, does not work.
 sub textdomain (;$) {
 	my $domain = shift;
 
 	if (defined $domain) {
 		return Locale::gettext_xs::_textdomain ($domain);
 	} else {
 		return Locale::gettext_xs::_textdomain ("");
 	}
 }
 
 sub nl_putenv ($) {
     my ($envspec) = @_;
     
     return unless defined $envspec;
     return unless length $envspec;
     return if substr ($envspec, 0, 1) eq '=';
     
     my ($var, $value) = split /=/, $envspec, 2;
     
     if ($^O eq 'MSWin32') {
         $value = '' unless defined $value;
         return unless Locale::gettext_xs::_nl_putenv ("$var=$value") == 0;
         if (length $value) {
             $ENV{$var} = $value;
         } else {
             delete $ENV{$var};
         }
     } else {
         if (defined $value) {
             $ENV{$var} = $value;
         } else {
             delete $ENV{$var};
         }
     }
 
     return 1;
 }
 
 1;
 
 __END__
 
 Local Variables:
 mode: perl
 perl-indent-level: 4
 perl-continued-statement-offset: 4
 perl-continued-brace-offset: 0
 perl-brace-offset: -4
 perl-brace-imaginary-offset: 0
 perl-label-offset: -4
 tab-width: 4
 End:
 
### Log/Any.pm ###
 use 5.008001;
 use strict;
 use warnings;
 
 package Log::Any;
 
 # ABSTRACT: Bringing loggers and listeners together
 our $VERSION = '1.032';
 
 use Log::Any::Manager;
 use Log::Any::Adapter::Util qw(
   require_dynamic
   detection_aliases
   detection_methods
   log_level_aliases
   logging_aliases
   logging_and_detection_methods
   logging_methods
 );
 
 # This is overridden in Log::Any::Test
 our $OverrideDefaultAdapterClass;
 our $OverrideDefaultProxyClass;
 
 # singleton and accessor
 {
     my $manager = Log::Any::Manager->new();
     sub _manager { return $manager }
 }
 
 sub import {
     my $class  = shift;
     my $caller = caller();
 
     my @export_params = ( $caller, @_ );
     $class->_export_to_caller(@export_params);
 }
 
 sub _export_to_caller {
     my $class  = shift;
     my $caller = shift;
 
     # Parse parameters passed to 'use Log::Any'
     my $saw_log_param;
     my @params;
     while ( my $param = shift @_ ) {
         if ( $param eq '$log' ) {
             $saw_log_param = 1;    # defer until later
             next;                  # singular
         }
         else {
             push @params, $param, shift @_;    # pairwise
         }
     }
 
     unless ( @params % 2 == 0 ) {
         require Carp;
         Carp::croak("Argument list not balanced: @params");
     }
 
     # get logger if one was requested
     if ($saw_log_param) {
         no strict 'refs';
         my $proxy = $class->get_logger( category => $caller, @params );
         my $varname = "$caller\::log";
         *$varname = \$proxy;
     }
 }
 
 sub get_logger {
     my ( $class, %params ) = @_;
     no warnings 'once';
 
     my $proxy_class = $class->_get_proxy_class( delete $params{proxy_class} );
     my $category =
       defined $params{category} ? delete $params{'category'} : caller;
 
     if ( my $default = delete $params{'default_adapter'} ) {
         $class->_manager->set_default( $category, $default );
     }
 
     my $adapter = $class->_manager->get_adapter( $category );
 
     require_dynamic($proxy_class);
     return $proxy_class->new(
         %params, adapter => $adapter, category => $category,
     );
 }
 
 sub _get_proxy_class {
     my ( $self, $proxy_name ) = @_;
     return $Log::Any::OverrideDefaultProxyClass
       if $Log::Any::OverrideDefaultProxyClass;
     return "Log::Any::Proxy" unless $proxy_name;
     my $proxy_class = (
           substr( $proxy_name, 0, 1 ) eq '+'
         ? substr( $proxy_name, 1 )
         : "Log::Any::Proxy::$proxy_name"
     );
     return $proxy_class;
 }
 
 # For backward compatibility
 sub set_adapter {
     my $class = shift;
     Log::Any->_manager->set(@_);
 }
 
 1;
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Log::Any - Bringing loggers and listeners together
 
 =head1 VERSION
 
 version 1.032
 
 =head1 SYNOPSIS
 
 In a CPAN or other module:
 
     package Foo;
     use Log::Any qw($log);
 
     # log a string
     $log->error("an error occurred");
 
     # log a string and data using a formatting filter
     $log->debugf("arguments are: %s", \@_);
 
 In a Moo/Moose-based module:
 
     package Foo;
     use Moo;
 
     has log => (
         is => 'ro',
         isa => 'Log::Any::Proxy',
         default => sub { Log::Any->get_logger },
     );
 
 In your application:
 
     use Foo;
     use Log::Any::Adapter;
 
     # Send all logs to Log::Log4perl
     Log::Any::Adapter->set('Log4perl');
 
     # Send all logs to Log::Dispatch
     my $log = Log::Dispatch->new(outputs => [[ ... ]]);
     Log::Any::Adapter->set( 'Dispatch', dispatcher => $log );
 
     # See Log::Any::Adapter documentation for more options
 
 =head1 DESCRIPTION
 
 C<Log::Any> provides a standard log production API for modules.
 L<Log::Any::Adapter> allows applications to choose the mechanism for log
 consumption, whether screen, file or another logging mechanism like
 L<Log::Dispatch> or L<Log::Log4perl>.
 
 Many modules have something interesting to say. Unfortunately there is no
 standard way for them to say it - some output to STDERR, others to C<warn>,
 others to custom file logs. And there is no standard way to get a module to
 start talking - sometimes you must call a uniquely named method, other times
 set a package variable.
 
 This being Perl, there are many logging mechanisms available on CPAN.  Each has
 their pros and cons. Unfortunately, the existence of so many mechanisms makes
 it difficult for a CPAN author to commit his/her users to one of them. This may
 be why many CPAN modules invent their own logging or choose not to log at all.
 
 To untangle this situation, we must separate the two parts of a logging API.
 The first, I<log production>, includes methods to output logs (like
 C<$log-E<gt>debug>) and methods to inspect whether a log level is activated
 (like C<$log-E<gt>is_debug>). This is generally all that CPAN modules care
 about. The second, I<log consumption>, includes a way to configure where
 logging goes (a file, the screen, etc.) and the code to send it there. This
 choice generally belongs to the application.
 
 A CPAN module uses C<Log::Any> to get a log producer object.  An application,
 in turn, may choose one or more logging mechanisms via L<Log::Any::Adapter>, or
 none at all.
 
 C<Log::Any> has a very tiny footprint and no dependencies beyond Perl 5.8.1,
 which makes it appropriate for even small CPAN modules to use. It defaults to
 'null' logging activity, so a module can safely log without worrying about
 whether the application has chosen (or will ever choose) a logging mechanism.
 
 See L<http://www.openswartz.com/2007/09/06/standard-logging-api/> for the
 original post proposing this module.
 
 =head1 LOG LEVELS
 
 C<Log::Any> supports the following log levels and aliases, which is meant to be
 inclusive of the major logging packages:
 
      trace
      debug
      info (inform)
      notice
      warning (warn)
      error (err)
      critical (crit, fatal)
      alert
      emergency
 
 Levels are translated as appropriate to the underlying logging mechanism. For
 example, log4perl only has six levels, so we translate 'notice' to 'info' and
 the top three levels to 'fatal'.  See the documentation of an adapter class
 for specifics.
 
 =head1 CATEGORIES
 
 Every logger has a category, generally the name of the class that asked for the
 logger. Some logging mechanisms, like log4perl, can direct logs to different
 places depending on category.
 
 =head1 PRODUCING LOGS (FOR MODULES)
 
 =head2 Getting a logger
 
 The most convenient way to get a logger in your module is:
 
     use Log::Any qw($log);
 
 This creates a package variable I<$log> and assigns it to the logger for the
 current package. It is equivalent to
 
     our $log = Log::Any->get_logger;
 
 In general, to get a logger for a specified category:
 
     my $log = Log::Any->get_logger(category => $category)
 
 If no category is specified, the calling package is used.
 
 A logger object is an instance of L<Log::Any::Proxy>, which passes
 on messages to the L<Log::Any::Adapter> handling its category.
 
 =head2 Logging
 
 To log a message, pass a single string to any of the log levels or aliases. e.g.
 
     $log->error("this is an error");
     $log->warn("this is a warning");
     $log->warning("this is also a warning");
 
 You should B<not> include a newline in your message; that is the responsibility
 of the logging mechanism, which may or may not want the newline.
 
 There are also versions of each of these methods with an additional "f" suffix
 (C<infof>, C<errorf>, C<debugf>, etc.) that format a list of arguments.  The
 specific formatting mechanism and meaning of the arguments is controlled by the
 L<Log::Any::Proxy> object.
 
     $log->errorf("an error occurred: %s", $@);
     $log->debugf("called with %d params: %s", $param_count, \@params);
 
 By default it renders like C<sprintf>, with the following additional features:
 
 =over
 
 =item *
 
 Any complex references (like C<\@params> above) are automatically converted to
 single-line strings with C<Data::Dumper>.
 
 =item *
 
 Any undefined values are automatically converted to the string "<undef>".
 
 =back
 
 =head2 Log level detection
 
 To detect whether a log level is on, use "is_" followed by any of the log
 levels or aliases. e.g.
 
     if ($log->is_info()) { ... }
     $log->debug("arguments are: " . Dumper(\@_))
         if $log->is_debug();
 
 This is important for efficiency, as you can avoid the work of putting together
 the logging message (in the above case, stringifying C<@_>) if the log level is
 not active.
 
 The formatting methods (C<infof>, C<errorf>, etc.) check the log level for you.
 
 Some logging mechanisms don't support detection of log levels. In these cases
 the detection methods will always return 1.
 
 In contrast, the default logging mechanism - Null - will return 0 for all
 detection methods.
 
 =head2 Setting an alternate default logger
 
 To choose something other than Null as the default, pass it as a parameter when
 loading C<Log::Any>
 
     use Log::Any '$log', default_adapter => 'Stderr';
 
 The name of the default class follows the same rules as used by L<Log::Any::Adapter>.
 
 =head2 Configuring the proxy
 
 Any parameter passed on the import line or via the C<get_logger> method
 are passed on the the L<Log::Any::Proxy> constructor.
 
     use Log::Any '$log', filter => \&myfilter;
 
 =head2 Testing
 
 L<Log::Any::Test> provides a mechanism to test code that uses C<Log::Any>.
 
 =head1 CONSUMING LOGS (FOR APPLICATIONS)
 
 Log::Any provides modules with a L<Log::Any::Proxy> object, which is the log
 producer.  To consume its output and direct it where you want (a file, the
 screen, syslog, etc.), you use L<Log::Any::Adapter> along with a
 destination-specific subclass.
 
 For example, to send output to a file via L<Log::Any::Adapter::File>, your
 application could do this:
 
     use Log::Any::Adapter ('File', '/path/to/file.log');
 
 See the L<Log::Any::Adapter> documentation for more details.
 
 =head1 Q & A
 
 =over
 
 =item Isn't Log::Any just yet another logging mechanism?
 
 No. C<Log::Any> does not include code that knows how to log to a particular
 place (file, screen, etc.) It can only forward logging requests to another
 logging mechanism.
 
 =item Why don't you just pick the best logging mechanism, and use and promote it?
 
 Each of the logging mechanisms have their pros and cons, particularly in terms
 of how they are configured. For example, log4perl offers a great deal of power
 and flexibility but uses a global and potentially heavy configuration, whereas
 C<Log::Dispatch> is extremely configuration-light but doesn't handle
 categories. There is also the unnamed future logger that may have advantages
 over either of these two, and all the custom in-house loggers people have
 created and cannot (for whatever reason) stop using.
 
 =item Is it safe for my critical module to depend on Log::Any?
 
 Our intent is to keep C<Log::Any> minimal, and change it only when absolutely
 necessary. Most of the "innovation", if any, is expected to occur in
 C<Log::Any::Adapter>, which your module should not have to depend on (unless it
 wants to direct logs somewhere specific). C<Log::Any> has no non-core dependencies.
 
 =item Why doesn't Log::Any use I<insert modern Perl technique>?
 
 To encourage CPAN module authors to adopt and use C<Log::Any>, we aim to have
 as few dependencies and chances of breakage as possible. Thus, no C<Moose> or
 other niceties.
 
 =back
 
 =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/Log-Any/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/Log-Any>
 
   git clone https://github.com/dagolden/Log-Any.git
 
 =head1 AUTHORS
 
 =over 4
 
 =item *
 
 Jonathan Swartz <swartz@pobox.com>
 
 =item *
 
 David Golden <dagolden@cpan.org>
 
 =back
 
 =head1 CONTRIBUTORS
 
 =for stopwords Maxim Vuets Stephen Thirlwall
 
 =over 4
 
 =item *
 
 Maxim Vuets <maxim.vuets@booking.com>
 
 =item *
 
 Stephen Thirlwall <sdt@dr.com>
 
 =back
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2014 by Jonathan Swartz 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
### Log/Any/Adapter.pm ###
 use 5.008001;
 use strict;
 use warnings;
 
 package Log::Any::Adapter;
 
 # ABSTRACT: Tell Log::Any where to send its logs
 our $VERSION = '1.032';
 
 use Log::Any;
 
 sub import {
     my $pkg = shift;
     Log::Any->_manager->set(@_) if (@_);
 }
 
 sub set {
     my $pkg = shift;
     Log::Any->_manager->set(@_)
 }
 
 sub remove {
     my $pkg = shift;
     Log::Any->_manager->remove(@_)
 }
 
 1;
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Log::Any::Adapter - Tell Log::Any where to send its logs
 
 =head1 VERSION
 
 version 1.032
 
 =head1 SYNOPSIS
 
     # Log to a file, or stdout, or stderr for all categories
     #
     use Log::Any::Adapter ('File', '/path/to/file.log');
     use Log::Any::Adapter ('Stdout');
     use Log::Any::Adapter ('Stderr');
 
     # Use Log::Log4perl for all categories
     #
     Log::Log4perl::init('/etc/log4perl.conf');
     Log::Any::Adapter->set('Log4perl');
 
     # Use Log::Dispatch for Foo::Baz
     #
     use Log::Dispatch;
     my $log = Log::Dispatch->new(outputs => [[ ... ]]);
     Log::Any::Adapter->set( { category => 'Foo::Baz' },
         'Dispatch', dispatcher => $log );
 
     # Use Log::Dispatch::Config for Foo::Baz and its subcategories
     #
     use Log::Dispatch::Config;
     Log::Dispatch::Config->configure('/path/to/log.conf');
     Log::Any::Adapter->set(
         { category => qr/^Foo::Baz/ },
         'Dispatch', dispatcher => Log::Dispatch::Config->instance() );
 
     # Use your own adapter for all categories
     #
     Log::Any::Adapter->set('+My::Log::Any::Adapter', ...);
 
 =head1 DESCRIPTION
 
 Log::Any::Adapter connects log producers and log consumers.  Its methods
 instantiate a logging adapter (a subclass of L<Log::Any::Adapter::Base>)
 and route log messages from one or more categories to it.
 
 =head1 ADAPTERS
 
 In order to use a logging mechanism with C<Log::Any>, there needs to be an
 adapter class for it. Typically this is named Log::Any::Adapter::I<something>.
 
 =head2 Adapters in this distribution
 
 Three basic adapters come with this distribution -- L<Log::Any::Adapter::File>,
 L<Log::Any::Adapter::Stdout> and L<Log::Any::Adapter::Stderr>:
 
     use Log::Any::Adapter ('File', '/path/to/file.log');
     use Log::Any::Adapter ('Stdout');
     use Log::Any::Adapter ('Stderr');
 
     # or
 
     use Log::Any::Adapter;
     Log::Any::Adapter->set('File', '/path/to/file.log');
     Log::Any::Adapter->set('Stdout');
     Log::Any::Adapter->set('Stderr');
 
 All of them simply output the message and newline to the specified destination;
 a datestamp prefix is added in the C<File> case. For anything more complex
 you'll want to use a more robust adapter from CPAN.
 
 =head2 Adapters on CPAN
 
 A sampling of adapters available on CPAN as of this writing:
 
 =over
 
 =item *
 
 L<Log::Any::Adapter::Log4perl|Log::Any::Adapter::Log4perl>
 
 =item *
 
 L<Log::Any::Adapter::Dispatch|Log::Any::Adapter::Dispatch>
 
 =item *
 
 L<Log::Any::Adapter::FileHandle|Log::Any::Adapter::FileHandle>
 
 =item *
 
 L<Log::Any::Adapter::Syslog|Log::Any::Adapter::Syslog>
 
 =back
 
 You may find other adapters on CPAN by searching for "Log::Any::Adapter", or
 create your own adapter. See
 L<Log::Any::Adapter::Development|Log::Any::Adapter::Development> for more
 information on the latter.
 
 =head1 SETTING AND REMOVING ADAPTERS
 
 =over
 
 =item Log::Any::Adapter->set ([options, ]adapter_name, adapter_params...)
 
 This method sets the adapter to use for all log categories, or for a particular
 set of categories.
 
 I<adapter_name> is the name of an adapter. It is automatically prepended with
 "Log::Any::Adapter::". If instead you want to pass the full name of an adapter,
 prefix it with a "+". e.g.
 
     # Use My::Adapter class
     Log::Any::Adapter->set('+My::Adapter', arg => $value);
 
 I<adapter_params> are passed along to the adapter constructor. See the
 documentation for the individual adapter classes for more information.
 
 An optional hash of I<options> may be passed as the first argument. Options
 are:
 
 =over
 
 =item category
 
 A string containing a category name, or a regex (created with C<qr//>) matching
 multiple categories.  If not specified, all categories will be routed to the
 adapter.
 
 =item lexically
 
 A reference to a lexical variable. When the variable goes out of scope, the
 adapter setting will be removed. e.g.
 
     {
         Log::Any::Adapter->set({lexically => \my $lex}, ...);
 
         # in effect here
         ...
     }
     # no longer in effect here
 
 =back
 
 C<set> returns an entry object, which can be passed to C<remove>.
 
 =item use Log::Any::Adapter (...)
 
 If you pass arguments to C<use Log::Any::Adapter>, it calls C<<
 Log::Any::Adapter->set >> with those arguments.
 
 =item Log::Any::Adapter->remove (entry)
 
 Remove an I<entry> previously returned by C<set>.
 
 =back
 
 =head1 MULTIPLE ADAPTER SETTINGS
 
 C<Log::Any> maintains a stack of entries created via C<set>.
 
 When you get a logger for a particular category, C<Log::Any> will work its way
 down the stack and use the first matching entry.
 
 Whenever the stack changes, any C<Log::Any> loggers that have previously been
 created will automatically adjust to the new stack. For example:
 
     my $log = Log::Any->get_logger();
     $log->error("aiggh!");   # this goes nowhere
     ...
     {
         Log::Any::Adapter->set({ lexically => \my $lex }, 'Log4perl');
         $log->error("aiggh!");   # this goes to log4perl
         ...
     }
     $log->error("aiggh!");   # this goes nowhere again
 
 =head1 SEE ALSO
 
 L<Log::Any|Log::Any>
 
 =head1 AUTHORS
 
 =over 4
 
 =item *
 
 Jonathan Swartz <swartz@pobox.com>
 
 =item *
 
 David Golden <dagolden@cpan.org>
 
 =back
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2014 by Jonathan Swartz 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
### Log/Any/Adapter/Base.pm ###
 use 5.008001;
 use strict;
 use warnings;
 
 package Log::Any::Adapter::Base;
 
 our $VERSION = '1.032';
 
 # we import these in case any legacy adapter uses them as class methods
 use Log::Any::Adapter::Util qw/make_method dump_one_line/;
 
 sub new {
     my $class = shift;
     my $self  = {@_};
     bless $self, $class;
     $self->init(@_);
     return $self;
 }
 
 sub init { }
 
 # Create stub logging methods
 for my $method ( Log::Any::Adapter::Util::logging_and_detection_methods() ) {
     no strict 'refs';
     *$method = sub {
         my $class = ref( $_[0] ) || $_[0];
         die "$class does not implement $method";
     };
 }
 
 # This methods installs a method that delegates to an object attribute
 sub delegate_method_to_slot {
     my ( $class, $slot, $method, $adapter_method ) = @_;
 
     make_method( $method,
         sub { my $self = shift; return $self->{$slot}->$adapter_method(@_) },
         $class );
 }
 
 1;
### Log/Any/Adapter/File.pm ###
 use 5.008001;
 use strict;
 use warnings;
 
 package Log::Any::Adapter::File;
 
 # ABSTRACT: Simple adapter for logging to files
 our $VERSION = '1.032';
 
 use Config;
 use Fcntl qw/:flock/;
 use IO::File;
 use Log::Any::Adapter::Util ();
 
 use base qw/Log::Any::Adapter::Base/;
 
 my $HAS_FLOCK = $Config{d_flock} || $Config{d_fcntl_can_lock} || $Config{d_lockf};
 
 my $trace_level = Log::Any::Adapter::Util::numeric_level('trace');
 sub new {
     my ( $class, $file, @args ) = @_;
     return $class->SUPER::new( file => $file, log_level => $trace_level, @args );
 }
 
 sub init {
     my $self = shift;
     if ( exists $self->{log_level} ) {
         $self->{log_level} = Log::Any::Adapter::Util::numeric_level( $self->{log_level} )
             unless $self->{log_level} =~ /^\d+$/;
     }
     else {
         $self->{log_level} = $trace_level;
     }
     my $file = $self->{file};
     open( $self->{fh}, ">>", $file )
       or die "cannot open '$file' for append: $!";
     $self->{fh}->autoflush(1);
 }
 
 foreach my $method ( Log::Any::Adapter::Util::logging_methods() ) {
     no strict 'refs';
     my $method_level = Log::Any::Adapter::Util::numeric_level( $method );
     *{$method} = sub {
         my ( $self, $text ) = @_;
         return if $method_level > $self->{log_level};
         my $msg = sprintf( "[%s] %s\n", scalar(localtime), $text );
         flock($self->{fh}, LOCK_EX) if $HAS_FLOCK;
         $self->{fh}->print($msg);
         flock($self->{fh}, LOCK_UN) if $HAS_FLOCK;
       }
 }
 
 foreach my $method ( Log::Any::Adapter::Util::detection_methods() ) {
     no strict 'refs';
     my $base = substr($method,3);
     my $method_level = Log::Any::Adapter::Util::numeric_level( $base );
     *{$method} = sub {
         return !!(  $method_level <= $_[0]->{log_level} );
     };
 }
 
 1;
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Log::Any::Adapter::File - Simple adapter for logging to files
 
 =head1 VERSION
 
 version 1.032
 
 =head1 SYNOPSIS
 
     use Log::Any::Adapter ('File', '/path/to/file.log');
 
     # or
 
     use Log::Any::Adapter;
     ...
     Log::Any::Adapter->set('File', '/path/to/file.log');
 
     # with minimum level 'warn'
 
     use Log::Any::Adapter (
         'File', '/path/to/file.log', log_level => 'warn',
     );
 
 =head1 DESCRIPTION
 
 This simple built-in L<Log::Any|Log::Any> adapter logs each message to the
 specified file, with a datestamp prefix and newline appended. The file is
 opened for append with autoflush on.  If C<flock> is available, the handle
 will be locked when writing.
 
 The C<log_level> attribute may be set to define a minimum level to log.
 
 Category is ignored.
 
 =head1 SEE ALSO
 
 L<Log::Any|Log::Any>, L<Log::Any::Adapter|Log::Any::Adapter>
 
 =head1 AUTHORS
 
 =over 4
 
 =item *
 
 Jonathan Swartz <swartz@pobox.com>
 
 =item *
 
 David Golden <dagolden@cpan.org>
 
 =back
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2014 by Jonathan Swartz 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
### Log/Any/Adapter/Log4perl.pm ###
 use strict;
 use warnings;
 
 package Log::Any::Adapter::Log4perl;
 # ABSTRACT: Log::Any adapter for Log::Log4perl
 
 use Log::Log4perl 1.32; # bug-free wrapper_register available
 use Log::Any::Adapter::Util 1.03 qw(make_method);
 use base qw(Log::Any::Adapter::Base);
 
 our $VERSION = '0.08';
 
 # Ensure %F, %C, etc. skip Log::Any related packages
 Log::Log4perl->wrapper_register(__PACKAGE__);
 Log::Log4perl->wrapper_register("Log::Any::Proxy");
 
 sub init {
     my ($self) = @_;
 
     $self->{logger} = Log::Log4perl->get_logger( $self->{category} );
 }
 
 foreach my $method ( Log::Any->logging_and_detection_methods() ) {
     my $log4perl_method = $method;
 
     # Map log levels down to log4perl levels where necessary
     #
     for ($log4perl_method) {
         s/notice/info/;
         s/warning/warn/;
         s/critical|alert|emergency/fatal/;
     }
 
     make_method(
         $method,
         sub {
             my $self = shift;
             return $self->{logger}->$log4perl_method(@_);
         }
     );
 }
 
 1;
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Log::Any::Adapter::Log4perl - Log::Any adapter for Log::Log4perl
 
 =head1 VERSION
 
 version 0.08
 
 =head1 SYNOPSIS
 
     use Log::Log4perl;
     Log::Log4perl::init('/etc/log4perl.conf');
 
     Log::Any::Adapter->set('Log::Log4perl');
 
 =head1 DESCRIPTION
 
 This Log::Any adapter uses L<Log::Log4perl|Log::Log4perl> for logging. log4perl
 must be initialized before calling I<set>. There are no parameters.
 
 =for Pod::Coverage init
 
 =head1 LOG LEVEL TRANSLATION
 
 Log levels are translated from Log::Any to Log4perl as follows:
 
     notice -> info
     warning -> warn
     critical -> fatal
     alert -> fatal
     emergency -> fatal
 
 =head1 SEE ALSO
 
 =over 4
 
 =item *
 
 L<Log::Any>
 
 =item *
 
 L<Log::Any::Adapter>
 
 =item *
 
 L<Log::Log4perl>
 
 =back
 
 =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/Log-Any-Adapter-Log4perl/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/Log-Any-Adapter-Log4perl>
 
   git clone https://github.com/dagolden/Log-Any-Adapter-Log4perl.git
 
 =head1 AUTHORS
 
 =over 4
 
 =item *
 
 Jonathan Swartz <swartz@pobox.com>
 
 =item *
 
 David Golden <dagolden@cpan.org>
 
 =back
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by Jonathan Swartz.
 
 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
### Log/Any/Adapter/Null.pm ###
 use 5.008001;
 use strict;
 use warnings;
 
 package Log::Any::Adapter::Null;
 
 # ABSTRACT: Discards all log messages
 our $VERSION = '1.032';
 
 use base qw/Log::Any::Adapter::Base/;
 
 use Log::Any::Adapter::Util ();
 
 # All methods are no-ops and return false
 
 foreach my $method (Log::Any::Adapter::Util::logging_and_detection_methods()) {
     no strict 'refs';
     *{$method} = sub { return '' }; # false
 }
 
 1;
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Log::Any::Adapter::Null - Discards all log messages
 
 =head1 VERSION
 
 version 1.032
 
 =head1 SYNOPSIS
 
     Log::Any::Adapter->set('Null');
 
 =head1 DESCRIPTION
 
 This Log::Any adapter discards all log messages and returns false for all
 detection methods (e.g. is_debug). This is the default adapter when Log::Any is
 loaded.
 
 =head1 SEE ALSO
 
 L<Log::Any|Log::Any>, L<Log::Any::Adapter|Log::Any::Adapter>
 
 =head1 AUTHORS
 
 =over 4
 
 =item *
 
 Jonathan Swartz <swartz@pobox.com>
 
 =item *
 
 David Golden <dagolden@cpan.org>
 
 =back
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2014 by Jonathan Swartz 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
### Log/Any/Adapter/Screen.pm ###
 package Log::Any::Adapter::Screen;
 
 our $DATE = '2015-06-19'; # DATE
 our $VERSION = '0.09'; # VERSION
 
 use 5.010001;
 use strict;
 use warnings;
 
 use Log::Any;
 use Log::Any::Adapter::Util qw(make_method);
 use base qw(Log::Any::Adapter::Base);
 use Term::ANSIColor;
 use Time::HiRes qw(time);
 
 my $Time0 = time();
 
 my @logging_methods = Log::Any->logging_methods;
 our %logging_levels;
 for my $i (0..@logging_methods-1) {
     $logging_levels{$logging_methods[$i]} = $i;
 }
 # some common typos
 $logging_levels{warn} = $logging_levels{warning};
 
 sub _default_level {
     return $ENV{LOG_LEVEL}
         if $ENV{LOG_LEVEL} && $logging_levels{$ENV{LOG_LEVEL}};
     return 'trace' if $ENV{TRACE};
     return 'debug' if $ENV{DEBUG};
     return 'info'  if $ENV{VERBOSE};
     return 'error' if $ENV{QUIET};
     'warning';
 }
 
 sub init {
     my ($self) = @_;
     $self->{stderr}    //= 1;
     $self->{use_color} //= (-t STDOUT);
     $self->{colors}    //= {
         trace     => 'yellow',
         debug     => '',
         info      => 'green',
         notice    => 'green',
         warning   => 'bold blue',
         error     => 'magenta',
         critical  => 'red',
         alert     => 'red',
         emergency => 'red',
     };
     $self->{min_level} //= _default_level();
     $self->{formatter} //= sub {
         my ($self, $msg) = @_;
         my $env = $ENV{LOG_PREFIX} // '';
         if ($env eq 'elapsed') {
             my $time = time();
             $msg = sprintf("[%9.3fms] %s", ($time - $Time0)*1000, $msg);
         }
         $msg;
     };
     $self->{_fh} = $self->{stderr} ? \*STDERR : \*STDOUT;
 }
 
 sub hook_before_log {
     return;
     #my ($self, $msg) = @_;
 }
 
 sub hook_after_log {
     my ($self, $msg) = @_;
     print { $self->{_fh} } "\n" unless $msg =~ /\n\z/;
 }
 
 for my $method (Log::Any->logging_methods()) {
     make_method(
         $method,
         sub {
             my ($self, $msg) = @_;
 
             return if $logging_levels{$method} <
                 $logging_levels{$self->{min_level}};
 
             $self->hook_before_log($msg);
 
             if ($self->{formatter}) {
                 $msg = $self->{formatter}->($self, $msg);
             }
 
             if ($self->{use_color} && $self->{colors}{$method}) {
                 $msg = Term::ANSIColor::colored($msg, $self->{colors}{$method});
             }
 
             print { $self->{_fh} } $msg;
 
             $self->hook_after_log($msg);
         }
     );
 }
 
 for my $method (Log::Any->detection_methods()) {
     my $level = $method; $level =~ s/^is_//;
     make_method(
         $method,
         sub {
             my $self = shift;
             $logging_levels{$level} >= $logging_levels{$self->{min_level}};
         }
     );
 }
 
 1;
 # ABSTRACT: Send logs to screen, with colors and some other features
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Log::Any::Adapter::Screen - Send logs to screen, with colors and some other features
 
 =head1 VERSION
 
 This document describes version 0.09 of Log::Any::Adapter::Screen (from Perl distribution Log-Any-Adapter-Screen), released on 2015-06-19.
 
 =head1 SYNOPSIS
 
  use Log::Any::Adapter;
  Log::Any::Adapter->set('Screen',
      # min_level => 'debug', # default is 'warning'
      # colors    => { trace => 'bold yellow on_gray', ... }, # customize colors
      # use_color => 1, # force color even when not interactive
      # stderr    => 0, # print to STDOUT instead of the default STDERR
      # formatter => sub { "LOG: $_[1]" }, # default none
  );
 
 =head1 DESCRIPTION
 
 This Log::Any adapter prints log messages to screen (STDERR/STDOUT). The
 messages are colored according to level (unless coloring is turned off). It has
 a few other features: allow passing formatter, allow setting level from some
 environment variables, add prefix/timestamps.
 
 Parameters:
 
 =over 4
 
 =item * min_level => STRING
 
 Set logging level. Default is warning. If LOG_LEVEL environment variable is set,
 it will be used instead. If TRACE environment variable is set to true, level
 will be set to 'trace'. If DEBUG environment variable is set to true, level will
 be set to 'debug'. If VERBOSE environment variable is set to true, level will be
 set to 'info'.If QUIET environment variable is set to true, level will be set to
 'error'.
 
 =item * use_color => BOOL
 
 Whether to use color or not. Default is true only when running interactively (-t
 STDOUT returns true).
 
 =item * colors => HASH
 
 Customize colors. Hash keys are the logging methods, hash values are colors
 supported by L<Term::ANSIColor>.
 
 The default colors are:
 
  method/level                 color
  ------------                 -----
  trace                        yellow
  debug                        (none, terminal default)
  info, notice                 green
  warning                      bold blue
  error                        magenta
  critical, alert, emergency   red
 
 =item * stderr => BOOL
 
 Whether to print to STDERR, default is true. If set to 0, will print to STDOUT
 instead.
 
 =item * formatter => CODEREF
 
 Allow formatting message. If defined, message will be passed before being
 colorized. Coderef will be passed:
 
  ($self, $message)
 
 and is expected to return the formatted message.
 
 The default formatter can optionally prefix the message with extra stuffs,
 depending on the content of LOG_PREFIX environment variable, such as: elapsed
 time (e.g. C<< [0.023ms] >>) if LOG_PREFIX is C<elapsed>.
 
 NOTE: Log::Any 1.00+ now has a proxy object which allows
 formatting/customization of message before it is sent to adapter(s), so
 formatting does not have to be done on a per-adapter basis. As an alternative to
 this attribute, you can also consider using the proxy object or the (upcoming?)
 global proxy object.
 
 =back
 
 =for Pod::Coverage ^(init|hook_.+)$
 
 =head1 ENVIRONMENT
 
 LOG_LEVEL, QUIET, VERBOSE, DEBUG, TRACE. These environment variables can set the
 default for C<min_level>. See documentation about C<min_level> for more details.
 
 LOG_PREFIX. The default formatter groks these variables. See documentation about
 C<formatter> about more details.
 
 =head1 SEE ALSO
 
 Originally inspired by L<Log::Log4perl::Appender::ScreenColoredLevel>. The old
 name for this adapter is Log::Any::Adapter::ScreenColoredLevel but at some point
 I figure using a shorter name is better for my fingers.
 
 L<Log::Any>
 
 L<Log::Log4perl::Appender::ScreenColoredLevel>
 
 L<Term::ANSIColor>
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Log-Any-Adapter-Screen>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Log-Any-Adapter-ScreenColoredLevel>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Log-Any-Adapter-Screen>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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
### Log/Any/Adapter/Stderr.pm ###
 use 5.008001;
 use strict;
 use warnings;
 
 package Log::Any::Adapter::Stderr;
 
 # ABSTRACT: Simple adapter for logging to STDERR
 our $VERSION = '1.032';
 
 use Log::Any::Adapter::Util ();
 
 use base qw/Log::Any::Adapter::Base/;
 
 my $trace_level = Log::Any::Adapter::Util::numeric_level('trace');
 
 sub init {
     my ($self) = @_;
     if ( exists $self->{log_level} ) {
         $self->{log_level} =
           Log::Any::Adapter::Util::numeric_level( $self->{log_level} )
           unless $self->{log_level} =~ /^\d+$/;
     }
     else {
         $self->{log_level} = $trace_level;
     }
 }
 
 foreach my $method ( Log::Any::Adapter::Util::logging_methods() ) {
     no strict 'refs';
     my $method_level = Log::Any::Adapter::Util::numeric_level($method);
     *{$method} = sub {
         my ( $self, $text ) = @_;
         return if $method_level > $self->{log_level};
         print STDERR "$text\n";
     };
 }
 
 foreach my $method ( Log::Any::Adapter::Util::detection_methods() ) {
     no strict 'refs';
     my $base = substr( $method, 3 );
     my $method_level = Log::Any::Adapter::Util::numeric_level($base);
     *{$method} = sub {
         return !!( $method_level <= $_[0]->{log_level} );
     };
 }
 
 1;
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Log::Any::Adapter::Stderr - Simple adapter for logging to STDERR
 
 =head1 VERSION
 
 version 1.032
 
 =head1 SYNOPSIS
 
     use Log::Any::Adapter ('Stderr');
 
     # or
 
     use Log::Any::Adapter;
     ...
     Log::Any::Adapter->set('Stderr');
 
     # with minimum level 'warn'
 
     use Log::Any::Adapter ('Stderr', log_level => 'warn' );
 
 =head1 DESCRIPTION
 
 This simple built-in L<Log::Any|Log::Any> adapter logs each message to STDERR
 with a newline appended. Category is ignored.
 
 The C<log_level> attribute may be set to define a minimum level to log.
 
 =head1 SEE ALSO
 
 L<Log::Any|Log::Any>, L<Log::Any::Adapter|Log::Any::Adapter>
 
 =head1 AUTHORS
 
 =over 4
 
 =item *
 
 Jonathan Swartz <swartz@pobox.com>
 
 =item *
 
 David Golden <dagolden@cpan.org>
 
 =back
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2014 by Jonathan Swartz 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
### Log/Any/Adapter/Stdout.pm ###
 use 5.008001;
 use strict;
 use warnings;
 
 package Log::Any::Adapter::Stdout;
 
 # ABSTRACT: Simple adapter for logging to STDOUT
 our $VERSION = '1.032';
 
 use Log::Any::Adapter::Util ();
 
 use base qw/Log::Any::Adapter::Base/;
 
 my $trace_level = Log::Any::Adapter::Util::numeric_level('trace');
 
 sub init {
     my ($self) = @_;
     if ( exists $self->{log_level} ) {
         $self->{log_level} =
           Log::Any::Adapter::Util::numeric_level( $self->{log_level} )
           unless $self->{log_level} =~ /^\d+$/;
     }
     else {
         $self->{log_level} = $trace_level;
     }
 }
 
 foreach my $method ( Log::Any::Adapter::Util::logging_methods() ) {
     no strict 'refs';
     my $method_level = Log::Any::Adapter::Util::numeric_level($method);
     *{$method} = sub {
         my ( $self, $text ) = @_;
         return if $method_level > $self->{log_level};
         print STDOUT "$text\n";
     };
 }
 
 foreach my $method ( Log::Any::Adapter::Util::detection_methods() ) {
     no strict 'refs';
     my $base = substr( $method, 3 );
     my $method_level = Log::Any::Adapter::Util::numeric_level($base);
     *{$method} = sub {
         return !!( $method_level <= $_[0]->{log_level} );
     };
 }
 
 1;
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Log::Any::Adapter::Stdout - Simple adapter for logging to STDOUT
 
 =head1 VERSION
 
 version 1.032
 
 =head1 SYNOPSIS
 
     use Log::Any::Adapter ('Stdout');
 
     # or
 
     use Log::Any::Adapter;
     ...
     Log::Any::Adapter->set('Stdout');
 
     # with minimum level 'warn'
 
     use Log::Any::Adapter ('Stdout', log_level => 'warn' );
 
 =head1 DESCRIPTION
 
 This simple built-in L<Log::Any|Log::Any> adapter logs each message to STDOUT
 with a newline appended. Category is ignored.
 
 The C<log_level> attribute may be set to define a minimum level to log.
 
 =head1 SEE ALSO
 
 L<Log::Any|Log::Any>, L<Log::Any::Adapter|Log::Any::Adapter>
 
 =head1 AUTHORS
 
 =over 4
 
 =item *
 
 Jonathan Swartz <swartz@pobox.com>
 
 =item *
 
 David Golden <dagolden@cpan.org>
 
 =back
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2014 by Jonathan Swartz 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
### Log/Any/Adapter/Test.pm ###
 use 5.008001;
 use strict;
 use warnings;
 
 package Log::Any::Adapter::Test;
 
 our $VERSION = '1.032';
 
 use Log::Any::Adapter::Util qw/dump_one_line/;
 use Test::Builder;
 
 use base qw/Log::Any::Adapter::Base/;
 
 my $tb = Test::Builder->new();
 my @msgs;
 
 # Ignore arguments for the original adapter if we're overriding, but recover
 # category from argument list; this depends on category => $category being put
 # at the end of the list in Log::Any::Manager. If not overriding, allow
 # arguments as usual.
 
 sub new {
     my $class = shift;
     if ( defined $Log::Any::OverrideDefaultAdapterClass
         && $Log::Any::OverrideDefaultAdapterClass eq __PACKAGE__ )
     {
         my $category = pop @_;
         return $class->SUPER::new( category => $category );
     }
     else {
         return $class->SUPER::new(@_);
     }
 }
 
 # All detection methods return true
 #
 foreach my $method ( Log::Any::Adapter::Util::detection_methods() ) {
     no strict 'refs';
     *{$method} = sub { 1 };
 }
 
 # All logging methods push onto msgs array
 #
 foreach my $method ( Log::Any::Adapter::Util::logging_methods() ) {
     no strict 'refs';
     *{$method} = sub {
         my ( $self, $msg ) = @_;
         push(
             @msgs,
             {
                 message  => $msg,
                 level    => $method,
                 category => $self->{category}
             }
         );
     };
 }
 
 # Testing methods below
 #
 
 sub msgs {
     my $self = shift;
 
     return \@msgs;
 }
 
 sub clear {
     my ($self) = @_;
 
     @msgs = ();
 }
 
 sub contains_ok {
     my ( $self, $regex, $test_name ) = @_;
 
     $test_name ||= "log contains '$regex'";
     my $found =
       _first_index( sub { $_->{message} =~ /$regex/ }, @{ $self->msgs } );
     if ( $found != -1 ) {
         splice( @{ $self->msgs }, $found, 1 );
         $tb->ok( 1, $test_name );
     }
     else {
         $tb->ok( 0, $test_name );
         $tb->diag( "could not find message matching $regex; log contains: "
               . $self->dump_one_line( $self->msgs ) );
     }
 }
 
 sub category_contains_ok {
     my ( $self, $category, $regex, $test_name ) = @_;
 
     $test_name ||= "log for $category contains '$regex'";
     my $found =
       _first_index(
         sub { $_->{category} eq $category && $_->{message} =~ /$regex/ },
         @{ $self->msgs } );
     if ( $found != -1 ) {
         splice( @{ $self->msgs }, $found, 1 );
         $tb->ok( 1, $test_name );
     }
     else {
         $tb->ok( 0, $test_name );
         $tb->diag(
             "could not find $category message matching $regex; log contains: "
               . $self->dump_one_line( $self->msgs ) );
     }
 }
 
 sub does_not_contain_ok {
     my ( $self, $regex, $test_name ) = @_;
 
     $test_name ||= "log does not contain '$regex'";
     my $found =
       _first_index( sub { $_->{message} =~ /$regex/ }, @{ $self->msgs } );
     if ( $found != -1 ) {
         $tb->ok( 0, $test_name );
         $tb->diag( "found message matching $regex: " . $self->msgs->[$found] );
     }
     else {
         $tb->ok( 1, $test_name );
     }
 }
 
 sub category_does_not_contain_ok {
     my ( $self, $category, $regex, $test_name ) = @_;
 
     $test_name ||= "log for $category contains '$regex'";
     my $found =
       _first_index(
         sub { $_->{category} eq $category && $_->{message} =~ /$regex/ },
         @{ $self->msgs } );
     if ( $found != -1 ) {
         $tb->ok( 0, $test_name );
         $tb->diag( "found $category message matching $regex: "
               . $self->msgs->[$found] );
     }
     else {
         $tb->ok( 1, $test_name );
     }
 }
 
 sub empty_ok {
     my ( $self, $test_name ) = @_;
 
     $test_name ||= "log is empty";
     if ( !@{ $self->msgs } ) {
         $tb->ok( 1, $test_name );
     }
     else {
         $tb->ok( 0, $test_name );
         $tb->diag( "log is not empty; contains "
               . $self->dump_one_line( $self->msgs ) );
         $self->clear();
     }
 }
 
 sub contains_only_ok {
     my ( $self, $regex, $test_name ) = @_;
 
     $test_name ||= "log contains only '$regex'";
     my $count = scalar( @{ $self->msgs } );
     if ( $count == 1 ) {
         local $Test::Builder::Level = $Test::Builder::Level + 1;
         $self->contains_ok( $regex, $test_name );
     }
     else {
         $tb->ok( 0, $test_name );
         $tb->diag( "log contains $count messages: "
               . $self->dump_one_line( $self->msgs ) );
     }
 }
 
 sub _first_index {
     my $f = shift;
     for my $i ( 0 .. $#_ ) {
         local *_ = \$_[$i];
         return $i if $f->();
     }
     return -1;
 }
 
 1;
### Log/Any/Adapter/Util.pm ###
 use 5.008001;
 use strict;
 use warnings;
 
 package Log::Any::Adapter::Util;
 
 # ABSTRACT: Common utility functions for Log::Any
 our $VERSION = '1.032';
 
 use Data::Dumper;
 use base qw(Exporter);
 
 my %LOG_LEVELS;
 BEGIN {
     %LOG_LEVELS = (
         EMERGENCY => 0,
         ALERT     => 1,
         CRITICAL  => 2,
         ERROR     => 3,
         WARNING   => 4,
         NOTICE    => 5,
         INFO      => 6,
         DEBUG     => 7,
         TRACE     => 8,
     );
 }
 
 use constant \%LOG_LEVELS;
 
 our @EXPORT_OK = qw(
   cmp_deeply
   detection_aliases
   detection_methods
   dump_one_line
   log_level_aliases
   logging_aliases
   logging_and_detection_methods
   logging_methods
   make_method
   numeric_level
   read_file
   require_dynamic
 );
 
 push @EXPORT_OK, keys %LOG_LEVELS;
 
 our %EXPORT_TAGS = ( 'levels' => [ keys %LOG_LEVELS ] );
 
 my ( %LOG_LEVEL_ALIASES, @logging_methods, @logging_aliases, @detection_methods,
     @detection_aliases, @logging_and_detection_methods );
 
 BEGIN {
     %LOG_LEVEL_ALIASES = (
         inform => 'info',
         warn   => 'warning',
         err    => 'error',
         crit   => 'critical',
         fatal  => 'critical'
     );
     @logging_methods =
       qw(trace debug info notice warning error critical alert emergency);
     @logging_aliases               = keys(%LOG_LEVEL_ALIASES);
     @detection_methods             = map { "is_$_" } @logging_methods;
     @detection_aliases             = map { "is_$_" } @logging_aliases;
     @logging_and_detection_methods = ( @logging_methods, @detection_methods );
 }
 
 #pod =func logging_methods
 #pod
 #pod Returns a list of all logging method. E.g. "trace", "info", etc.
 #pod
 #pod =cut
 
 sub logging_methods               { @logging_methods }
 
 #pod =func detection_methods
 #pod
 #pod Returns a list of detection methods.  E.g. "is_trace", "is_info", etc.
 #pod
 #pod =cut
 
 sub detection_methods             { @detection_methods }
 
 #pod =func logging_and_detection_methods
 #pod
 #pod Returns a list of logging and detection methods (but not aliases).
 #pod
 #pod =cut
 
 sub logging_and_detection_methods { @logging_and_detection_methods }
 
 #pod =func log_level_aliases
 #pod
 #pod Returns key/value pairs mapping aliases to "official" names.  E.g. "err" maps
 #pod to "error".
 #pod
 #pod =cut
 
 sub log_level_aliases             { %LOG_LEVEL_ALIASES }
 
 #pod =func logging_aliases
 #pod
 #pod Returns a list of logging alias names.  These are the keys from
 #pod L</log_level_aliases>.
 #pod
 #pod =cut
 
 sub logging_aliases               { @logging_aliases }
 
 #pod =func detection_aliases
 #pod
 #pod Returns a list of detection aliases.  E.g. "is_err", "is_fatal", etc.
 #pod
 #pod =cut
 
 sub detection_aliases             { @detection_aliases }
 
 #pod =func numeric_level
 #pod
 #pod Given a level name (or alias), returns the numeric value described above under
 #pod log level constants.  E.g. "err" would return 3.
 #pod
 #pod =cut
 
 sub numeric_level {
     my ($level) = @_;
     my $canonical =
       exists $LOG_LEVEL_ALIASES{$level} ? $LOG_LEVEL_ALIASES{$level} : $level;
     return $LOG_LEVELS{ uc($canonical) };
 }
 
 #pod =func dump_one_line
 #pod
 #pod Given a reference, returns a one-line L<Data::Dumper> dump with keys sorted.
 #pod
 #pod =cut
 
 sub dump_one_line {
     my ($value) = @_;
 
     return Data::Dumper->new( [$value] )->Indent(0)->Sortkeys(1)->Quotekeys(0)
       ->Terse(1)->Dump();
 }
 
 #pod =func make_method
 #pod
 #pod Given a method name, a code reference and a package name, installs the code
 #pod reference as a method in the package.
 #pod
 #pod =cut
 
 sub make_method {
     my ( $method, $code, $pkg ) = @_;
 
     $pkg ||= caller();
     no strict 'refs';
     *{ $pkg . "::$method" } = $code;
 }
 
 #pod =func require_dynamic (DEPRECATED)
 #pod
 #pod Given a class name, attempts to load it via require unless the class
 #pod already has a constructor available.  Throws an error on failure. Used
 #pod internally and may become private in the future.
 #pod
 #pod =cut
 
 sub require_dynamic {
     my ($class) = @_;
 
     return 1 if $class->can('new'); # duck-type that class is loaded
 
     unless ( defined( eval "require $class; 1" ) )
     {    ## no critic (ProhibitStringyEval)
         die $@;
     }
 }
 
 #pod =func read_file (DEPRECATED)
 #pod
 #pod Slurp a file.  Does *not* apply any layers.  Used for testing and may
 #pod become private in the future.
 #pod
 #pod =cut
 
 sub read_file {
     my ($file) = @_;
 
     local $/ = undef;
     open( my $fh, '<', $file )
       or die "cannot open '$file': $!";
     my $contents = <$fh>;
     return $contents;
 }
 
 #pod =func cmp_deeply (DEPRECATED)
 #pod
 #pod Compares L<dump_one_line> results for two references.  Also takes a test
 #pod label as a third argument.  Used for testing and may become private in the
 #pod future.
 #pod
 #pod =cut
 
 sub cmp_deeply {
     my ( $ref1, $ref2, $name ) = @_;
 
     my $tb = Test::Builder->new();
     $tb->is_eq( dump_one_line($ref1), dump_one_line($ref2), $name );
 }
 
 # 0.XX version loaded Log::Any and some adapters relied on this happening
 # behind the scenes.  Since Log::Any now uses this module, we load Log::Any
 # via require after compilation to mitigate circularity.
 require Log::Any;
 
 1;
 
 
 # vim: ts=4 sts=4 sw=4 et tw=75:
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Log::Any::Adapter::Util - Common utility functions for Log::Any
 
 =head1 VERSION
 
 version 1.032
 
 =head1 DESCRIPTION
 
 This module has utility functions to help develop L<Log::Any::Adapter>
 subclasses or L<Log::Any::Proxy> formatters/filters.  It also has some
 functions used in internal testing.
 
 =head1 USAGE
 
 Nothing is exported by default.
 
 =head2 Log level constants
 
 If the C<:levels> tag is included in the import list, the following numeric
 constants will be imported:
 
     EMERGENCY => 0
     ALERT     => 1
     CRITICAL  => 2
     ERROR     => 3
     WARNING   => 4
     NOTICE    => 5
     INFO      => 6
     DEBUG     => 7
     TRACE     => 8
 
 =head1 FUNCTIONS
 
 =head2 logging_methods
 
 Returns a list of all logging method. E.g. "trace", "info", etc.
 
 =head2 detection_methods
 
 Returns a list of detection methods.  E.g. "is_trace", "is_info", etc.
 
 =head2 logging_and_detection_methods
 
 Returns a list of logging and detection methods (but not aliases).
 
 =head2 log_level_aliases
 
 Returns key/value pairs mapping aliases to "official" names.  E.g. "err" maps
 to "error".
 
 =head2 logging_aliases
 
 Returns a list of logging alias names.  These are the keys from
 L</log_level_aliases>.
 
 =head2 detection_aliases
 
 Returns a list of detection aliases.  E.g. "is_err", "is_fatal", etc.
 
 =head2 numeric_level
 
 Given a level name (or alias), returns the numeric value described above under
 log level constants.  E.g. "err" would return 3.
 
 =head2 dump_one_line
 
 Given a reference, returns a one-line L<Data::Dumper> dump with keys sorted.
 
 =head2 make_method
 
 Given a method name, a code reference and a package name, installs the code
 reference as a method in the package.
 
 =head2 require_dynamic (DEPRECATED)
 
 Given a class name, attempts to load it via require unless the class
 already has a constructor available.  Throws an error on failure. Used
 internally and may become private in the future.
 
 =head2 read_file (DEPRECATED)
 
 Slurp a file.  Does *not* apply any layers.  Used for testing and may
 become private in the future.
 
 =head2 cmp_deeply (DEPRECATED)
 
 Compares L<dump_one_line> results for two references.  Also takes a test
 label as a third argument.  Used for testing and may become private in the
 future.
 
 =head1 AUTHORS
 
 =over 4
 
 =item *
 
 Jonathan Swartz <swartz@pobox.com>
 
 =item *
 
 David Golden <dagolden@cpan.org>
 
 =back
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2014 by Jonathan Swartz 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
### Log/Any/App.pm ###
 package Log::Any::App;
 
 our $DATE = '2015-10-06'; # DATE
 our $VERSION = '0.51'; # VERSION
 
 # i need this to run on centos 5.x. otherwise all my other servers are debian
 # 5.x and 6.x+ (perl 5.010).
 use 5.008000;
 use strict;
 use warnings;
 
 use File::Path qw(make_path);
 use File::Spec;
 use Log::Any::IfLOG;
 use Log::Any::Adapter;
 
 
 use vars qw($dbg_ctx);
 
 our %PATTERN_STYLES = (
     plain             => '%m',
     plain_nl          => '%m%n',
     script_short      => '[%r] %m%n',
     script_long       => '[%d] %m%n',
     daemon            => '[pid %P] [%d] %m%n',
     syslog            => '[pid %p] %m',
 );
 for (keys %PATTERN_STYLES) {
     $PATTERN_STYLES{"cat_$_"} = "[cat %c]$PATTERN_STYLES{$_}";
     $PATTERN_STYLES{"loc_$_"} = "[loc %l]$PATTERN_STYLES{$_}";
 }
 
 my $init_args;
 our $init_called;
 my $is_daemon;
 
 # poor man's version of 5.10's //
 sub _ifdef {
     my $def = pop @_;
     for (@_) {
         return $_ if defined($_);
     }
     $def;
 }
 
 # j=as json (except the last default)
 sub _ifdefj {
     require JSON;
 
     my $def = pop @_;
     for (@_) {
         return JSON::decode_json($_) if defined($_);
     }
     $def;
 }
 
 sub init {
     return if $init_called++;
 
     $is_daemon = undef;
 
     my ($args, $caller) = @_;
     $caller ||= caller();
 
     my $spec = _parse_opts($args, $caller);
     if ($spec->{log} && $spec->{init}) {
         _init_log4perl($spec);
         if ($ENV{LOG_ENV}) {
            my $log_main = Log::Any->get_logger(category => 'main');
            $log_main->tracef("Environment variables: %s", \%ENV);
        }
     }
     $spec;
 }
 
 sub _gen_appender_config {
     my ($ospec, $apd_name, $filter) = @_;
 
     my $name = $ospec->{name};
     my $class;
     my $params = {};
     if ($name =~ /^dir/i) {
         $class = "Log::Dispatch::Dir";
         $params->{dirname}   = $ospec->{path};
         $params->{filename_pattern} = $ospec->{filename_pattern};
         $params->{max_size}  = $ospec->{max_size} if $ospec->{max_size};
         $params->{max_files} = $ospec->{histories}+1 if $ospec->{histories};
         $params->{max_age}   = $ospec->{max_age} if $ospec->{max_age};
     } elsif ($name =~ /^file/i) {
         $class = "Log::Dispatch::FileWriteRotate";
         my ($dir, $prefix) = $ospec->{path} =~ m!(.+)/(.+)!;
         $dir ||= "."; $prefix ||= $ospec->{path};
         $params->{dir}         = $dir;
         $params->{prefix}      = $prefix;
         $params->{suffix}      = $ospec->{suffix};
         $params->{size}        = $ospec->{max_size};
         $params->{period}      = $ospec->{period};
         $params->{histories}   = $ospec->{histories};
         $params->{buffer_size} = $ospec->{buffer_size};
     } elsif ($name =~ /^screen/i) {
         $class = "Log::Log4perl::Appender::" .
             ($ospec->{color} ? "ScreenColoredLevels" : "Screen");
         $params->{stderr}  = $ospec->{stderr} ? 1:0;
         $params->{"color.WARN"} = "bold blue"; # blue on black is so unreadable
     } elsif ($name =~ /^syslog/i) {
         $class = "Log::Dispatch::Syslog";
         $params->{mode}     = 'append';
         $params->{ident}    = $ospec->{ident};
         $params->{facility} = $ospec->{facility};
     } elsif ($name =~ /^unixsock/i) {
         $class = "Log::Log4perl::Appender::Socket::UNIX";
         $params->{Socket} = $ospec->{path};
     } elsif ($name =~ /^array/i) {
         $class = "Log::Dispatch::ArrayWithLimits";
         $params->{array}     = $ospec->{array};
         $params->{max_elems} = $ospec->{max_elems};
     } else {
         die "BUG: Unknown appender type: $name";
     }
 
     join(
         "",
         "log4perl.appender.$apd_name = $class\n",
         (map { "log4perl.appender.$apd_name.$_ = $params->{$_}\n" }
              grep {defined $params->{$_}} keys %$params),
         "log4perl.appender.$apd_name.layout = PatternLayout\n",
         "log4perl.appender.$apd_name.layout.ConversionPattern = $ospec->{pattern}\n",
         ($filter ? "log4perl.appender.$apd_name.Filter = $filter\n" : ""),
     );
 }
 
 sub _lit {
     require Data::Dump;
     Data::Dump::dump(shift);
 }
 
 sub _gen_l4p_config {
     my ($spec) = @_;
 
     my @otypes = qw(file dir screen syslog unixsock array);
 
     # we use a custom perl code to implement filter_* specs.
     my @fccode;
     push @fccode, 'my %p = @_';
     push @fccode, 'my $str';
     for my $ospec (map { @{ $spec->{$_} } } @otypes) {
         if (defined $ospec->{filter_text}) {
             push @fccode, '$str = '._lit($ospec->{filter_text});
             push @fccode, 'return 0 if $p{name} eq '._lit($ospec->{name}).
                 ' && index($_, $str) == -1';
         }
         if (defined $ospec->{filter_no_text}) {
             push @fccode, '$str = '._lit($ospec->{filter_no_text});
             push @fccode, 'return 0 if $p{name} eq '._lit($ospec->{name}).
                 ' && index($_, $str) > -1';
         }
         if (defined $ospec->{filter_citext}) {
             push @fccode, '$str = '._lit($ospec->{filter_citext});
             push @fccode, 'return 0 if $p{name} eq '._lit($ospec->{name}).
                 ' && !/\Q$str/io';
         }
         if (defined $ospec->{filter_no_citext}) {
             push @fccode, '$str = '._lit($ospec->{filter_no_citext});
             push @fccode, 'return 0 if $p{name} eq '._lit($ospec->{name}).
                 ' && /\Q$str/io';
         }
         if (defined $ospec->{filter_re}) {
             push @fccode, '$str = '._lit($ospec->{filter_re});
             push @fccode, 'return 0 if $p{name} eq '._lit($ospec->{name}).
                 ' && $_ !~ ' . (ref($ospec->{filter_re}) eq 'Regexp' ? '$str' : 'qr/$str/o');
         }
         if (defined $ospec->{filter_no_re}) {
             push @fccode, '$str = '._lit($ospec->{filter_no_re});
             push @fccode, 'return 0 if $p{name} eq '._lit($ospec->{name}).
                 ' && $_ =~ ' . (ref($ospec->{filter_re}) eq 'Regexp' ? '$str' : 'qr/$str/o');
         }
     }
     push @fccode, "1";
     my $fccode = join "; ", @fccode;
 
     my $filters_str = join(
         "",
         "log4perl.filter.FilterCustom = sub { $fccode }\n",
         "\n",
         "log4perl.filter.FilterOFF0 = Log::Log4perl::Filter::LevelRange\n",
         "log4perl.filter.FilterOFF0.LevelMin = TRACE\n",
         "log4perl.filter.FilterOFF0.LevelMax = FATAL\n",
         "log4perl.filter.FilterOFF0.AcceptOnMatch = false\n",
         "\n",
         "log4perl.filter.FilterOFF = Log::Log4perl::Filter::Boolean\n",
         "log4perl.filter.FilterOFF.logic = FilterOFF0 && FilterCustom\n",
         map {join(
             "",
             "log4perl.filter.Filter${_}0 = Log::Log4perl::Filter::LevelRange\n",
             "log4perl.filter.Filter${_}0.LevelMin = $_\n",
             "log4perl.filter.Filter${_}0.LevelMax = FATAL\n",
             "log4perl.filter.Filter${_}0.AcceptOnMatch = true\n",
             "\n",
             "log4perl.filter.Filter$_ = Log::Log4perl::Filter::Boolean\n",
             "log4perl.filter.Filter$_.logic = Filter${_}0 && FilterCustom\n",
             "\n",
         )} qw(FATAL ERROR WARN INFO DEBUG), # TRACE
     );
 
     my %levels; # key = output name; value = { cat => level, ... }
     my %cats;   # list of categories
     my %ospecs; # key = oname; this is just a shortcut to get ospec
 
     # 1. list all levels for each category and output
     for my $ospec (map { @{ $spec->{$_} } } @otypes) {
         my $oname = $ospec->{name};
         $ospecs{$oname} = $ospec;
         $levels{$oname} = {};
         my %seen_cats;
         if ($ospec->{category_level}) {
             while (my ($cat0, $level) = each %{ $ospec->{category_level} }) {
                 my @cat = _extract_category($ospec, $cat0);
                 for my $cat (@cat) {
                     next if $seen_cats{$cat}++;
                     $cats{$cat}++;
                     $levels{$oname}{$cat} = $level;
                 }
             }
         }
         if ($spec->{category_level}) {
             while (my ($cat0, $level) = each %{ $spec->{category_level} }) {
                 my @cat = _extract_category($ospec, $cat0);
                 for my $cat (@cat) {
                     next if $seen_cats{$cat}++;
                     $cats{$cat}++;
                     $levels{$oname}{$cat} = $level;
                 }
             }
         }
         my @cat = _extract_category($ospec);
         for my $cat (@cat) {
             next if $seen_cats{$cat}++;
             $cats{$cat}++;
             $levels{$oname}{$cat} = $ospec->{level};
         }
     }
     #print Dumper \%levels; exit;
 
     my $find_olevel = sub {
         my ($oname, $cat) = @_;
         my $olevel = $levels{$oname}{''};
         my @c = split /\./, $cat;
         for (my $i=0; $i<@c; $i++) {
             my $c = join(".", @c[0..$i]);
             if ($levels{$oname}{$c}) {
                 $olevel = $levels{$oname}{$c};
             }
         }
         $olevel;
     };
 
     # 2. determine level for each category (which is the minimum level of all
     # appenders for that category)
     my %cat_configs; # key = cat, value = [catlevel, apdname, ...]
     my $add_str = '';
     my $apd_str = '';
     for my $cat0 (sort {$a cmp $b} keys %cats) {
         $add_str .= "log4perl.additivity.$cat0 = 0\n" unless $cat0 eq '';
         my @cats = ($cat0);
         # since we don't use additivity, we need to add supercategories ourselves
         while ($cat0 =~ s/\.[^.]+$//) { push @cats, $cat0 }
         for my $cat (@cats) {
             my $cat_level;
             for my $oname (keys %levels) {
                 my $olevel = $find_olevel->($oname, $cat);
                 next unless $olevel;
                 $cat_level = _ifdef($cat_level, $olevel);
                 $cat_level = _min_level($cat_level, $olevel);
             }
             $cat_configs{$cat} = [uc($cat_level)];
             #next if $cat_level eq 'off';
         }
     }
     #print Dumper \%cat_configs; exit;
 
     # 3. add appenders for each category
     my %generated_appenders; # key = apdname, just a memory hash
     for my $cat (keys %cat_configs) {
         my $cat_level = $cat_configs{$cat}[0];
         for my $oname (keys %levels) {
             my $ospec = $ospecs{$oname};
             my $olevel = $find_olevel->($oname, $cat);
             #print "D:oname=$oname, cat=$cat, olevel=$olevel, cat_level=$cat_level\n";
             my $apd_name;
             my $filter;
             if ($olevel ne $cat_level &&
                     _min_level($olevel, $cat_level) eq $cat_level) {
                 # we need to filter the appender, since the category level is
                 # lower than the output level
                 $apd_name = $oname . "_" . uc($olevel);
                 $filter = "Filter".uc($olevel);
             } else {
                 $apd_name = $oname;
                 $filter = "FilterCustom";
             }
             unless ($generated_appenders{$apd_name}++) {
                 $apd_str .= _gen_appender_config($ospec, $apd_name, $filter).
                     "\n";
             }
             push @{ $cat_configs{$cat} }, $apd_name;
         }
     }
     #print Dumper \%cat_configs; exit;
 
     # 4. write out log4perl category line
     my $cat_str = '';
     for my $cat (sort {$a cmp $b} keys %cat_configs) {
         my $l = $cat eq '' ? '' : ".$cat";
         $cat_str .= "log4perl.logger$l = ".join(", ", @{ $cat_configs{$cat} })."\n";
     }
 
     join(
         "",
         "# filters\n", $filters_str,
         "# categories\n", $cat_str, $add_str, "\n",
         "# appenders\n", $apd_str,
     );
 }
 
 sub _init_log4perl {
     require Log::Log4perl;
 
     my ($spec) = @_;
 
     # create intermediate directories for dir
     for (@{ $spec->{dir} }) {
         my $dir = _dirname($_->{path});
         make_path($dir) if length($dir) && !(-d $dir);
     }
 
     # create intermediate directories for file
     for (@{ $spec->{file} }) {
         my $dir = _dirname($_->{path});
         make_path($dir) if length($dir) && !(-d $dir);
     }
 
     my $config_str = _gen_l4p_config($spec);
     if ($spec->{dump}) {
         require Data::Dump;
         print "Log::Any::App configuration:\n",
             Data::Dump::dump($spec);
         print "Log4perl configuration: <<EOC\n", $config_str, "EOC\n";
     }
 
     Log::Log4perl->init(\$config_str);
     Log::Any::Adapter->set('Log4perl');
 }
 
 sub _basename {
     my $path = shift;
     my ($vol, $dir, $file) = File::Spec->splitpath($path);
     $file;
 }
 
 sub _dirname {
     my $path = shift;
     my ($vol, $dir, $file) = File::Spec->splitpath($path);
     $dir;
 }
 
 # we separate args and opts, because we need to export logger early
 # (BEGIN), but configure logger in INIT (to be able to detect
 # existence of other modules).
 
 sub _parse_args {
     my ($args, $caller) = @_;
     $args = _ifdef($args, []); # if we don't import(), we never get args
 
     my $i = 0;
     while ($i < @$args) {
         my $arg = $args->[$i];
         do { $i+=2; next } if $arg =~ /^-(\w+)$/;
         if ($arg eq '$log') {
             _export_logger($caller);
         } else {
             die "Unknown arg '$arg', valid arg is '\$log' or -OPTS";
         }
         $i++;
     }
 }
 
 sub _parse_opts {
     require File::HomeDir;
 
     my ($args, $caller) = @_;
     $args = _ifdef($args, []); # if we don't import(), we never get args
     _debug("parse_opts: args = [".join(", ", @$args)."]");
 
     my $i = 0;
     my %opts;
     while ($i < @$args) {
         my $arg = $args->[$i];
         do { $i++; next } unless $arg =~ /^-(\w+)$/;
         my $opt = $1;
         die "Missing argument for option $opt" unless $i++ < @$args-1;
         $arg = $args->[$i];
         $opts{$opt} = $arg;
         $i++;
     }
 
     my $spec = {};
 
     $spec->{log} = _ifdef($ENV{LOG}, 1);
     if (defined $opts{log}) {
         $spec->{log} = $opts{log};
         delete $opts{log};
     }
     # exit as early as possible if we are not doing any logging
     goto END_PARSE_OPTS unless $spec->{log};
 
     $spec->{name} = _basename($0);
     if (defined $opts{name}) {
         $spec->{name} = $opts{name};
         delete $opts{name};
     }
 
     $spec->{level_flag_paths} = [File::HomeDir->my_home, "/etc"];
     if (defined $opts{level_flag_paths}) {
         $spec->{level_flag_paths} = $opts{level_flag_paths};
         delete $opts{level_flag_paths};
     }
 
     $spec->{level} = _set_level("", "", $spec);
     if (!$spec->{level} && defined($opts{level})) {
         $spec->{level} = _check_level($opts{level}, "-level");
         _debug("Set general level to $spec->{level} (from -level)");
     } elsif (!$spec->{level}) {
         $spec->{level} = "warn";
         _debug("Set general level to $spec->{level} (default)");
     }
     delete $opts{level};
 
     $spec->{category_alias} = _ifdefj($ENV{LOG_CATEGORY_ALIAS}, {});
     if (defined $opts{category_alias}) {
         die "category_alias must be a hashref"
             unless ref($opts{category_alias}) eq 'HASH';
         $spec->{category_alias} = $opts{category_alias};
         delete $opts{category_alias};
     }
 
     if (defined $opts{category_level}) {
         die "category_level must be a hashref"
             unless ref($opts{category_level}) eq 'HASH';
         $spec->{category_level} = {};
         for (keys %{ $opts{category_level} }) {
             $spec->{category_level}{$_} =
                 _check_level($opts{category_level}{$_}, "-category_level{$_}");
         }
         delete $opts{category_level};
     }
 
     $spec->{init} = 1;
     if (defined $opts{init}) {
         $spec->{init} = $opts{init};
         delete $opts{init};
     }
 
     $spec->{daemon} = 0;
     if (defined $opts{daemon}) {
         $spec->{daemon} = $opts{daemon};
         _debug("setting is_daemon=$opts{daemon} (from daemon option)");
         $is_daemon = $opts{daemon};
         delete $opts{daemon};
     }
 
     $spec->{dump} = $ENV{LOGANYAPP_DEBUG};
     if (defined $opts{dump}) {
         $spec->{dump} = 1;
         delete $opts{dump};
     }
 
     $spec->{filter_text} = $ENV{LOG_FILTER_TEXT};
     if (defined $opts{filter_text}) {
         $spec->{filter_text} = $opts{filter_text};
         delete $opts{filter_text};
     }
     $spec->{filter_no_text} = $ENV{LOG_FILTER_NO_TEXT};
     if (defined $opts{filter_no_text}) {
         $spec->{filter_no_text} = $opts{filter_no_text};
         delete $opts{filter_no_text};
     }
     $spec->{filter_citext} = $ENV{LOG_FILTER_CITEXT};
     if (defined $opts{filter_citext}) {
         $spec->{filter_citext} = $opts{filter_citext};
         delete $opts{filter_citext};
     }
     $spec->{filter_no_citext} = $ENV{LOG_FILTER_NO_CITEXT};
     if (defined $opts{filter_no_citext}) {
         $spec->{filter_no_citext} = $opts{filter_no_citext};
         delete $opts{filter_no_citext};
     }
     $spec->{filter_re} = $ENV{LOG_FILTER_RE};
     if (defined $opts{filter_re}) {
         $spec->{filter_re} = $opts{filter_re};
         delete $opts{filter_re};
     }
     $spec->{filter_no_re} = $ENV{LOG_FILTER_NO_RE};
     if (defined $opts{filter_no_re}) {
         $spec->{filter_no_re} = $opts{filter_no_re};
         delete $opts{filter_no_re};
     }
 
     $spec->{file} = [];
     _parse_opt_file($spec, _ifdef($opts{file}, ($0 ne '-e' ? 1:0)));
     delete $opts{file};
 
     $spec->{dir} = [];
     _parse_opt_dir($spec, _ifdef($opts{dir}, 0));
     delete $opts{dir};
 
     $spec->{screen} = [];
     _parse_opt_screen($spec, _ifdef($opts{screen}, !_is_daemon()));
     delete $opts{screen};
 
     $spec->{syslog} = [];
     _parse_opt_syslog($spec, _ifdef($opts{syslog}, _is_daemon()));
     delete $opts{syslog};
 
     $spec->{unixsock} = [];
     _parse_opt_unixsock($spec, _ifdef($opts{unixsock}, 0));
     delete $opts{unixsock};
 
     $spec->{array} = [];
     _parse_opt_array($spec, _ifdef($opts{array}, 0));
     delete $opts{array};
 
     if (keys %opts) {
         die "Unknown option(s) ".join(", ", keys %opts)." Known opts are: ".
             "log, name, level, category_level, category_alias, dump, init, ".
                 "filter_{,no_}{text,citext,re}, file, dir, screen, syslog, ".
                     "unixsock, array";
     }
 
   END_PARSE_OPTS:
     #use Data::Dump; dd $spec;
     $spec;
 }
 
 sub _is_daemon {
     if (defined $is_daemon) { return $is_daemon }
     if (defined $main::IS_DAEMON) {
         $is_daemon = $main::IS_DAEMON;
         _debug("Setting is_daemon=$main::IS_DAEMON (from \$main::IS_DAEMON)");
         return $main::IS_DAEMON;
     }
 
     for (
         "App/Daemon.pm",
         "Daemon/Easy.pm",
         "Daemon/Daemonize.pm",
         "Daemon/Generic.pm",
         "Daemonise.pm",
         "Daemon/Simple.pm",
         "HTTP/Daemon.pm",
         "IO/Socket/INET/Daemon.pm",
         #"Mojo/Server/Daemon.pm", # simply loading Mojo::UserAgent will load this too
         "MooseX/Daemonize.pm",
         "Net/Daemon.pm",
         "Net/Server.pm",
         "Proc/Daemon.pm",
         "Proc/PID/File.pm",
         "Win32/Daemon/Simple.pm") {
         if ($INC{$_}) {
             _debug("setting is_daemon=1 (from existence of module $_)");
             $is_daemon = 1;
             return 1;
         }
     }
     _debug("setting is_daemon=0 (no indication that we are a daemon)");
     $is_daemon = 0;
     0;
 }
 
 sub _parse_opt_OUTPUT {
     my (%args) = @_;
     my $kind = $args{kind};
     my $default_sub = $args{default_sub};
     my $postprocess = $args{postprocess};
     my $spec = $args{spec};
     my $arg = $args{arg};
 
     return unless $arg;
 
     if (!ref($arg) || ref($arg) eq 'HASH') {
         my $name = uc($kind).(@{ $spec->{$kind} }+0);
         local $dbg_ctx = $name;
         push @{ $spec->{$kind} }, $default_sub->($spec);
         $spec->{$kind}[-1]{name} = $name;
         if (!ref($arg)) {
             # leave every output parameter as is
         } else {
             for my $k (keys %$arg) {
                 for ($spec->{$kind}[-1]) {
                     exists($_->{$k}) or die "Invalid $kind argument: $k, please".
                         " only specify one of: " . join(", ", sort keys %$_);
                     $_->{$k} = $k eq 'level' ?
                         _check_level($arg->{$k}, "-$kind") : $arg->{$k};
                     _debug("Set level of $kind to $_->{$k} (spec)")
                         if $k eq 'level';
                 }
             }
         }
         $spec->{$kind}[-1]{main_spec} = $spec;
         _set_pattern($spec->{$kind}[-1], $kind);
         $postprocess->(spec => $spec, ospec => $spec->{$kind}[-1])
             if $postprocess;
     } elsif (ref($arg) eq 'ARRAY') {
         for (@$arg) {
             _parse_opt_OUTPUT(%args, arg => $_);
         }
     } else {
         die "Invalid argument for -$kind, ".
             "must be a boolean or hashref or arrayref";
     }
 }
 
 sub _set_pattern_style {
     my ($x) = @_;
     ($ENV{LOG_SHOW_LOCATION} ? 'loc_':
          $ENV{LOG_SHOW_CATEGORY} ? 'cat_':'') . $x;
 }
 
 sub _default_file {
     require File::HomeDir;
 
     my ($spec) = @_;
     my $level = _set_level("file", "file", $spec);
     if (!$level) {
         $level = $spec->{level};
         _debug("Set level of file to $level (general level)");
     }
     return {
         level => $level,
         category_level => _ifdefj($ENV{FILE_LOG_CATEGORY_LEVEL},
                                   $ENV{LOG_CATEGORY_LEVEL},
                                   $spec->{category_level}),
         path => $> ? File::Spec->catfile(File::HomeDir->my_home, "$spec->{name}.log") :
             "/var/log/$spec->{name}.log", # XXX and on Windows?
         max_size => undef,
         histories => undef,
         period => undef,
         buffer_size => undef,
         category => '',
         pattern_style => _set_pattern_style('daemon'),
         pattern => undef,
 
         filter_text      => _ifdef($ENV{FILE_LOG_FILTER_TEXT}, $spec->{filter_text}),
         filter_no_text   => _ifdef($ENV{FILE_LOG_FILTER_NO_TEXT}, $spec->{filter_no_text}),
         filter_citext    => _ifdef($ENV{FILE_LOG_FILTER_CITEXT}, $spec->{filter_citext}),
         filter_no_citext => _ifdef($ENV{FILE_LOG_FILTER_NO_CITEXT}, $spec->{filter_no_citext}),
         filter_re        => _ifdef($ENV{FILE_LOG_FILTER_RE}, $spec->{filter_re}),
         filter_no_re     => _ifdef($ENV{FILE_LOG_FILTER_NO_RE}, $spec->{filter_no_re}),
     };
 }
 
 sub _parse_opt_file {
     my ($spec, $arg) = @_;
 
     if (!ref($arg) && $arg && $arg !~ /^(1|yes|true)$/i) {
         $arg = {path => $arg};
     }
 
     _parse_opt_OUTPUT(
         kind => 'file', default_sub => \&_default_file,
         spec => $spec, arg => $arg,
         postprocess => sub {
             my (%args) = @_;
             my $spec  = $args{spec};
             my $ospec = $args{ospec};
             if ($ospec->{path} =~ m!/$!) {
                 my $p = $ospec->{path};
                 $p .= "$spec->{name}.log";
                 _debug("File path ends with /, assumed to be dir, ".
                            "final path becomes $p");
                 $ospec->{path} = $p;
             }
         },
     );
 }
 
 sub _default_dir {
     require File::HomeDir;
 
     my ($spec) = @_;
     my $level = _set_level("dir", "dir", $spec);
     if (!$level) {
         $level = $spec->{level};
         _debug("Set level of dir to $level (general level)");
     }
     return {
         level => $level,
         category_level => _ifdefj($ENV{DIR_LOG_CATEGORY_LEVEL},
                                    $ENV{LOG_CATEGORY_LEVEL},
                                    $spec->{category_level}),
         path => $> ? File::Spec->catfile(File::HomeDir->my_home, "log", $spec->{name}) :
             "/var/log/$spec->{name}", # XXX and on Windows?
         max_size => undef,
         max_age => undef,
         histories => undef,
         category => '',
         pattern_style => _set_pattern_style('plain'),
         pattern => undef,
         filename_pattern => undef,
 
         filter_text      => _ifdef($ENV{DIR_LOG_FILTER_TEXT}, $spec->{filter_text}),
         filter_no_text   => _ifdef($ENV{DIR_LOG_FILTER_NO_TEXT}, $spec->{filter_no_text}),
         filter_citext    => _ifdef($ENV{DIR_LOG_FILTER_CITEXT}, $spec->{filter_citext}),
         filter_no_citext => _ifdef($ENV{DIR_LOG_FILTER_NO_CITEXT}, $spec->{filter_no_citext}),
         filter_re        => _ifdef($ENV{DIR_LOG_FILTER_RE}, $spec->{filter_re}),
         filter_no_re     => _ifdef($ENV{DIR_LOG_FILTER_NO_RE}, $spec->{filter_no_re}),
     };
 }
 
 sub _parse_opt_dir {
     my ($spec, $arg) = @_;
 
     if (!ref($arg) && $arg && $arg !~ /^(1|yes|true)$/i) {
         $arg = {path => $arg};
     }
 
     _parse_opt_OUTPUT(
         kind => 'dir', default_sub => \&_default_dir,
         spec => $spec, arg => $arg,
     );
 }
 
 sub _default_screen {
     my ($spec) = @_;
     my $level = _set_level("screen", "screen", $spec);
     if (!$level) {
         $level = $spec->{level};
         _debug("Set level of screen to $level (general level)");
     }
     return {
         color => _ifdef($ENV{COLOR}, (-t STDOUT)),
         stderr => 1,
         level => $level,
         category_level => _ifdefj($ENV{SCREEN_LOG_CATEGORY_LEVEL},
                                    $ENV{LOG_CATEGORY_LEVEL},
                                    $spec->{category_level}),
         category => '',
         pattern_style => _set_pattern_style(
             $ENV{LOG_ELAPSED_TIME_IN_SCREEN} ? 'script_short' : 'plain_nl'),
         pattern => undef,
 
         filter_text      => _ifdef($ENV{SCREEN_LOG_FILTER_TEXT}, $spec->{filter_text}),
         filter_no_text   => _ifdef($ENV{SCREEN_FILTER_NO_TEXT}, $spec->{filter_no_text}),
         filter_citext    => _ifdef($ENV{SCREEN_FILTER_CITEXT}, $spec->{filter_citext}),
         filter_no_citext => _ifdef($ENV{SCREEN_FILTER_NO_CITEXT}, $spec->{filter_no_citext}),
         filter_re        => _ifdef($ENV{SCREEN_FILTER_RE}, $spec->{filter_re}),
         filter_no_re     => _ifdef($ENV{SCREEN_FILTER_NO_RE}, $spec->{filter_no_re}),
     };
 }
 
 sub _parse_opt_screen {
     my ($spec, $arg) = @_;
     _parse_opt_OUTPUT(
         kind => 'screen', default_sub => \&_default_screen,
         spec => $spec, arg => $arg,
     );
 }
 
 sub _default_syslog {
     my ($spec) = @_;
     my $level = _set_level("syslog", "syslog", $spec);
     if (!$level) {
         $level = $spec->{level};
         _debug("Set level of syslog to $level (general level)");
     }
     return {
         level => $level,
         category_level => _ifdefj($ENV{SYSLOG_LOG_CATEGORY_LEVEL},
                                    $ENV{LOG_CATEGORY_LEVEL},
                                    $spec->{category_level}),
         ident => $spec->{name},
         facility => 'daemon',
         pattern_style => _set_pattern_style('syslog'),
         pattern => undef,
         category => '',
 
         filter_text      => _ifdef($ENV{SYSLOG_LOG_FILTER_TEXT}, $spec->{filter_text}),
         filter_no_text   => _ifdef($ENV{SYSLOG_FILTER_NO_TEXT}, $spec->{filter_no_text}),
         filter_citext    => _ifdef($ENV{SYSLOG_FILTER_CITEXT}, $spec->{filter_citext}),
         filter_no_citext => _ifdef($ENV{SYSLOG_FILTER_NO_CITEXT}, $spec->{filter_no_citext}),
         filter_re        => _ifdef($ENV{SYSLOG_FILTER_RE}, $spec->{filter_re}),
         filter_no_re     => _ifdef($ENV{SYSLOG_FILTER_NO_RE}, $spec->{filter_no_re}),
     };
 }
 
 sub _parse_opt_syslog {
     my ($spec, $arg) = @_;
     _parse_opt_OUTPUT(
         kind => 'syslog', default_sub => \&_default_syslog,
         spec => $spec, arg => $arg,
     );
 }
 
 sub _default_unixsock {
     require File::HomeDir;
 
     my ($spec) = @_;
     my $level = _set_level("unixsock", "unixsock", $spec);
     if (!$level) {
         $level = $spec->{level};
         _debug("Set level of unixsock to $level (general level)");
     }
     return {
         level => $level,
         category_level => _ifdefj($ENV{UNIXSOCK_LOG_CATEGORY_LEVEL},
                                   $ENV{LOG_CATEGORY_LEVEL},
                                   $spec->{category_level}),
         path => $> ? File::Spec->catfile(File::HomeDir->my_home, "$spec->{name}-log.sock") :
             "/var/run/$spec->{name}-log.sock", # XXX and on Windows?
         category => '',
         pattern_style => _set_pattern_style('daemon'),
         pattern => undef,
 
         filter_text      => _ifdef($ENV{UNIXSOCK_LOG_FILTER_TEXT}, $spec->{filter_text}),
         filter_no_text   => _ifdef($ENV{UNIXSOCK_LOG_FILTER_NO_TEXT}, $spec->{filter_no_text}),
         filter_citext    => _ifdef($ENV{UNIXSOCK_LOG_FILTER_CITEXT}, $spec->{filter_citext}),
         filter_no_citext => _ifdef($ENV{UNIXSOCK_LOG_FILTER_NO_CITEXT}, $spec->{filter_no_citext}),
         filter_re        => _ifdef($ENV{UNIXSOCK_LOG_FILTER_RE}, $spec->{filter_re}),
         filter_no_re     => _ifdef($ENV{UNIXSOCK_LOG_FILTER_NO_RE}, $spec->{filter_no_re}),
     };
 }
 
 sub _parse_opt_unixsock {
     my ($spec, $arg) = @_;
 
     if (!ref($arg) && $arg && $arg !~ /^(1|yes|true)$/i) {
         $arg = {path => $arg};
     }
 
     _parse_opt_OUTPUT(
         kind => 'unixsock', default_sub => \&_default_unixsock,
         spec => $spec, arg => $arg,
         postprocess => sub {
             my (%args) = @_;
             my $spec  = $args{spec};
             my $ospec = $args{ospec};
             if ($ospec->{path} =~ m!/$!) {
                 my $p = $ospec->{path};
                 $p .= "$spec->{name}-log.sock";
                 _debug("Unix socket path ends with /, assumed to be dir, ".
                            "final path becomes $p");
                 $ospec->{path} = $p;
             }
 
             # currently Log::Log4perl::Appender::Socket::UNIX *connects to an
             # existing and listening* Unix socket and prints log to it. we are
             # *not* creating a listening unix socket where clients can connect
             # and see logs. to do that, we'll need a separate thread/process
             # that listens to unix socket and stores (some) log entries and
             # display it to users when they connect and request them.
             #
             #if ($ospec->{create} && !(-e $ospec->{path})) {
             #    _debug("Creating Unix socket $ospec->{path} ...");
             #    require IO::Socket::UNIX::Util;
             #    IO::Socket::UNIX::Util::create_unix_socket(
             #        $ospec->{path});
             #}
         },
     );
 }
 
 sub _default_array {
     my ($spec) = @_;
     my $level = _set_level("array", "array", $spec);
     if (!$level) {
         $level = $spec->{level};
         _debug("Set level of array to $level (general level)");
     }
     return {
         level => $level,
         category_level => _ifdefj($ENV{ARRAY_LOG_CATEGORY_LEVEL},
                                   $ENV{LOG_CATEGORY_LEVEL},
                                   $spec->{category_level}),
         array => [],
         max_elems => undef,
         category => '',
         pattern_style => _set_pattern_style('script_long'),
         pattern => undef,
 
         filter_text      => _ifdef($ENV{ARRAY_LOG_FILTER_TEXT}, $spec->{filter_text}),
         filter_no_text   => _ifdef($ENV{ARRAY_LOG_FILTER_NO_TEXT}, $spec->{filter_no_text}),
         filter_citext    => _ifdef($ENV{ARRAY_LOG_FILTER_CITEXT}, $spec->{filter_citext}),
         filter_no_citext => _ifdef($ENV{ARRAY_LOG_FILTER_NO_CITEXT}, $spec->{filter_no_citext}),
         filter_re        => _ifdef($ENV{ARRAY_LOG_FILTER_RE}, $spec->{filter_re}),
         filter_no_re     => _ifdef($ENV{ARRAY_LOG_FILTER_NO_RE}, $spec->{filter_no_re}),
     };
 }
 
 sub _parse_opt_array {
     my ($spec, $arg) = @_;
 
     _parse_opt_OUTPUT(
         kind => 'array', default_sub => \&_default_array,
         spec => $spec, arg => $arg,
     );
 }
 
 sub _set_pattern {
     my ($s, $name) = @_;
     _debug("Setting $name pattern ...");
     unless (defined($s->{pattern})) {
         die "BUG: neither pattern nor pattern_style is defined ($name)"
             unless defined($s->{pattern_style});
         die "Unknown pattern style for $name `$s->{pattern_style}`, ".
             "use one of: ".join(", ", keys %PATTERN_STYLES)
             unless defined($PATTERN_STYLES{ $s->{pattern_style} });
         $s->{pattern} = $PATTERN_STYLES{ $s->{pattern_style} };
         _debug("Set $name pattern to `$s->{pattern}` ".
                    "(from style `$s->{pattern_style}`)");
     }
 }
 
 sub _extract_category {
     my ($ospec, $c) = @_;
     my $c0 = _ifdef($c, $ospec->{category});
     my @res;
     if (ref($c0) eq 'ARRAY') { @res = @$c0 } else { @res = ($c0) }
     # replace alias with real value
     for (my $i=0; $i<@res; $i++) {
         my $c1 = $res[$i];
         my $a = $ospec->{main_spec}{category_alias}{$c1};
         next unless defined($a);
         if (ref($a) eq 'ARRAY') {
             splice @res, $i, 1, @$a;
             $i += (@$a-1);
         } else {
             $res[$i] = $a;
         }
     }
     for (@res) {
         s/::/./g;
         # $_ = lc; # XXX do we need this?
     }
     @res;
 }
 
 sub _cat2apd {
     my $cat = shift;
     $cat =~ s/[^A-Za-z0-9_]+/_/g;
     $cat;
 }
 
 sub _check_level {
     my ($level, $from) = @_;
     $level =~ /^(off|fatal|error|warn|info|debug|trace)$/i
         or die "Unknown level (from $from): $level";
     lc($1);
 }
 
 sub _set_level {
     my ($prefix, $which, $spec) = @_;
     #use Data::Dump; dd $spec;
     my $p_ = $prefix ? "${prefix}_" : "";
     my $P_ = $prefix ? uc("${prefix}_") : "";
     my $F_ = $prefix ? ucfirst("${prefix}_") : "";
     my $pd = $prefix ? "${prefix}-" : "";
     my $pr = $prefix ? qr/$prefix(_|-)/ : qr//;
     my ($level, $from);
 
     my @label2level =([trace=>"trace"], [debug=>"debug"],
                       [verbose=>"info"], [quiet=>"error"]);
 
     _debug("Setting ", ($which ? "level of $which" : "general level"), " ...");
   SET:
     {
         if ($INC{"App/Options.pm"}) {
             my $key;
             for (qw/log_level loglevel/) {
                 $key = $p_ . $_;
                 _debug("Checking \$App::options{$key}: ", _ifdef($App::options{$key}, "(undef)"));
                 if ($App::options{$key}) {
                     $level = _check_level($App::options{$key}, "\$App::options{$key}");
                     $from = "\$App::options{$key}";
                     last SET;
                 }
             }
             for (@label2level) {
                 $key = $p_ . $_->[0];
                 _debug("Checking \$App::options{$key}: ", _ifdef($App::options{$key}, "(undef)"));
                 if ($App::options{$key}) {
                     $level = $_->[1];
                     $from = "\$App::options{$key}";
                     last SET;
                 }
             }
         }
 
         my $i = 0;
         _debug("Checking \@ARGV ...");
         while ($i < @ARGV) {
             my $arg = $ARGV[$i];
             $from = "cmdline arg $arg";
             if ($arg =~ /^--${pr}log[_-]?level=(.+)/) {
                 _debug("\$ARGV[$i] looks like an option to specify level: $arg");
                 $level = _check_level($1, "ARGV $arg");
                 last SET;
             }
             if ($arg =~ /^--${pr}log[_-]?level$/ and $i < @ARGV-1) {
                 _debug("\$ARGV[$i] and \$ARGV[${\($i+1)}] looks like an option to specify level: $arg ", $ARGV[$i+1]);
                 $level = _check_level($ARGV[$i+1], "ARGV $arg ".$ARGV[$i+1]);
                 last SET;
             }
             for (@label2level) {
                 if ($arg =~ /^--${pr}$_->[0](=(1|yes|true))?$/i) {
                     _debug("\$ARGV[$i] looks like an option to specify level: $arg");
                     $level = $_->[1];
                     last SET;
                 }
             }
             $i++;
         }
 
         for (qw/LOG_LEVEL LOGLEVEL/) {
             my $key = $P_ . $_;
             _debug("Checking environment variable $key: ", _ifdef($ENV{$key}, "(undef)"));
             if ($ENV{$key}) {
                 $level = _check_level($ENV{$key}, "ENV $key");
                 $from = "\$ENV{$key}";
                 last SET;
             }
         }
         for (@label2level) {
             my $key = $P_ . uc($_->[0]);
             _debug("Checking environment variable $key: ", _ifdef($ENV{$key}, "(undef)"));
             if ($ENV{$key}) {
                 $level = $_->[1];
                 $from = "\$ENV{$key}";
                 last SET;
             }
         }
 
         for my $dir (@{$spec->{level_flag_paths}}) {
             for (@label2level) {
                 my $filename = "$dir/$spec->{name}." . $P_ . "log_level";
                 my $exists = -f $filename;
                 my $content;
                 if ($exists) {
                     open my($f), $filename;
                     $content = <$f>;
                     chomp($content) if defined($content);
                     close $f;
                 }
                 _debug("Checking level flag file content $filename: ",
                        (defined($content) ? $content : "(undef)"));
                 if (defined $content) {
                     $level = _check_level($content,
                                           "level flag file $filename");
                     $from = $filename;
                     last SET;
                 }
 
                 $filename = "$dir/$spec->{name}." . $P_ . uc($_->[0]);
                 $exists = -e $filename;
                 _debug("Checking level flag file $filename: ",
                        ($exists ? "EXISTS" : 0));
                 if ($exists) {
                     $level = $_->[1];
                     $from = $filename;
                     last SET;
                 }
             }
         }
 
         no strict 'refs';
         for ("${F_}Log_Level", "${P_}LOG_LEVEL", "${p_}log_level",
              "${F_}LogLevel",  "${P_}LOGLEVEL",  "${p_}loglevel") {
             my $varname = "main::$_";
             _debug("Checking variable \$$varname: ", _ifdef($$varname, "(undef)"));
             if ($$varname) {
                 $from = "\$$varname";
                 $level = _check_level($$varname, "\$$varname");
                 last SET;
             }
         }
         for (@label2level) {
             for my $varname (
                 "main::$F_" . ucfirst($_->[0]),
                 "main::$P_" . uc($_->[0])) {
                 _debug("Checking variable \$$varname: ", _ifdef($$varname, "(undef)"));
                 if ($$varname) {
                     $from = "\$$varname";
                     $level = $_->[1];
                     last SET;
                 }
             }
         }
     }
 
     _debug("Set ", ($which ? "level of $which" : "general level"), " to $level (from $from)") if $level;
     return $level;
 }
 
 # return the lower level (e.g. _min_level("debug", "INFO") -> INFO
 sub _min_level {
     my ($l1, $l2) = @_;
     my %vals = (OFF=>99,
                 FATAL=>6, ERROR=>5, WARN=>4, INFO=>3, DEBUG=>2, TRACE=>1);
     $vals{uc($l1)} > $vals{uc($l2)} ? $l2 : $l1;
 }
 
 sub _export_logger {
     my ($caller) = @_;
     my $log_for_caller = Log::Any->get_logger(category => $caller);
     my $varname = "$caller\::log";
     no strict 'refs';
     *$varname = \$log_for_caller;
 }
 
 sub _debug {
     return unless $ENV{LOGANYAPP_DEBUG};
     print $dbg_ctx, ": " if $dbg_ctx;
     print @_, "\n";
 }
 
 sub import {
     my ($self, @args) = @_;
     my $caller = caller();
     _parse_args(\@args, $caller);
     $init_args = \@args;
 }
 
 {
     no warnings;
     # if we are loaded at run-time, it's too late to run INIT blocks, so user
     # must call init() manually. but sometimes this is what the user wants. so
     # shut up perl warning.
     INIT {
         my $caller = caller();
         init($init_args, $caller);
     }
 }
 
 1;
 # ABSTRACT: An easy way to use Log::Any in applications
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Log::Any::App - An easy way to use Log::Any in applications
 
 =head1 VERSION
 
 This document describes version 0.51 of Log::Any::App (from Perl distribution Log-Any-App), released on 2015-10-06.
 
 =head1 SYNOPSIS
 
 Most of the time you only need to do this:
 
  # in your script.pl
  use Log::Any::App '$log';
  $log->warn("blah ...");
  if ($log->is_debug) { ... }
 
  # or, in command line
  % perl -MLog::Any::App -MModuleThatUsesLogAny -e'...'
 
 Here's the default logging that Log::Any::App sets up for you:
 
  Condition                        screen  file               syslog        dir
  --------------------------------+-------+------------------+-------------+---
  -e (one-liners)                  y       -                  -             -
  Scripts running as normal user   y       ~/NAME.log         -             -
  Scripts running as root          y       /var/log/NAME.log  -             -
  Daemons                          -       y                  y             -
 
 You can customize level from outside the script, using environment variables or
 command-line options (won't interfere with command-line processing modules like
 Getopt::Long etc):
 
  % DEBUG=1 script.pl
  % LOG_LEVEL=trace script.pl
  % script.pl --verbose
 
 And to customize other stuffs:
 
  use Log::Any::App '$log',
      -syslog => 1, # turn on syslog logging explicitly
      -screen => 0, # turn off screen logging explicitly
      -file   => {path=>'/foo/bar', max_size=>'10M', histories=>10};
                 # customize file logging
 
 For more customization like categories, per-category level, per-output level,
 multiple outputs, string patterns, etc see L</USING AND EXAMPLES> and init().
 
 =head1 DESCRIPTION
 
 IMPORTANT: Please read L</"ROAD TO 1.0"> on some incompatibilities in the near
 future, before 1.0 is released.
 
 Log::Any::App is a convenient combo for L<Log::Any> and L<Log::Log4perl>
 (although alternative backends beside Log4perl might be considered in the
 future). To use Log::Any::App you need to be sold on the idea of Log::Any first,
 so please do a read up on that first.
 
 The goal of Log::Any::App is to provide developers an easy and concise way to
 add logging to their I<*applications*>. That is, instead of modules; modules
 remain using Log::Any to produce logs. Applications can upgrade to full Log4perl
 later when necessary, although in my experience, they usually don't.
 
 With Log::Any::App, you can replace this code in your application:
 
  use Log::Any '$log';
  use Log::Any::Adapter;
  use Log::Log4perl;
  my $log4perl_config = '
    some
    long
    multiline
    config...';
  Log::Log4perl->init(\$log4perl_config);
  Log::Any::Adapter->set('Log4perl');
 
 with just this:
 
  use Log::Any::App '$log'; # plus some other options when necessary
 
 Most of the time you don't need to configure anything as Log::Any::App will
 construct the most appropriate default Log4perl configuration for your
 application.
 
 =head1 USING AND EXAMPLES
 
 To use Log::Any::App, just do:
 
  use Log::Any::App '$log';
 
 or from the command line:
 
  % perl -MLog::Any::App -MModuleThatUsesLogAny -e ...
 
 This will send logs to screen as well as file (unless -e scripts, which only log
 to screen). Default log file is ~/$SCRIPT_NAME.log, or /var/log/$SCRIPT_NAME.log
 if script is running as root. Default level is 'warn'.
 
 The 'use Log::Any::App' statement can be issued before or after the modules that
 use Log::Any, it doesn't matter. Logging will be initialized in the INIT phase
 by Log::Any::App.
 
 You are not required to import '$log', and don't need to if you do not produce
 logs in your application (only in the modules).
 
 =head2 Changing logging level
 
 Since one of the most commonly tweaked logging setting is level (for example:
 increasing level when debugging problems), Log::Any::App provides several
 mechanisms to change log level, either from the script or from outside the
 script, for your convenience. Below are the mechanisms, ordered from highest
 priority:
 
 =over 4
 
 =item * import argument (inside the script)
 
 =item * command line arguments (outside the script)
 
 =item * environment variables (outside the script)
 
 =item * level flag files (outside the script)
 
 =item * variables in 'main' package (inside the script)
 
 =back
 
 These mechanisms are explained in more details in the documentation for the
 B<init()> function. But below are some examples.
 
 To change level from inside the script:
 
  use Log::Any::App '$log', -level => 'debug';
 
 This is useful if you want a fixed level that cannot be overridden by other
 mechanisms (since setting level using import argument has the highest priority).
 But oftentimes what you want is changing level without modifying the script
 itself. Thereby, just write:
 
  use Log::Any::App '$log';
 
 and then you can use environment variables to change level:
 
  TRACE=1 script.pl;         # setting level to trace
  DEBUG=1 script.pl;         # setting level to debug
  VERBOSE=1 script.pl;       # setting level to info
  QUIET=1 script.pl;         # setting level to error
  LOG_LEVEL=trace script.pl; # setting a specific log level
 
 or command-line options:
 
  script.pl --trace
  script.pl --debug
  script.pl --verbose
  script.pl --quiet
  script.pl --log_level=debug;   # '--log-level debug' will also do
 
 Regarding command-line options: Log::Any::App won't consume the command-line
 options from @ARGV and thus won't interfere with command-line processing modules
 like L<Getopt::Long> or L<App::Options>. If you use a command-line processing
 module and plan to use command-line options to set level, you might want to
 define these level options, or your command-line processing module will complain
 about unknown options.
 
 =head2 Changing default level
 
 The default log level is 'warn'. To change the default level, you can use 'main'
 package variables (since they have the lowest priority):
 
  use Log::Any::App '$log';
  BEGIN { our $Log_Level = 'info' } # be more verbose by default
 
 Then you will still be able to use level flag files or environment variables or
 command-line options to override this setting.
 
 =head2 Changing per-output level
 
 Logging level can also be specified on a per-output level. For example, if you
 want your script to be chatty on the screen but still logs to file at the
 default 'warn' level:
 
  SCREEN_VERBOSE=1 script.pl
  SCREEN_DEBUG=1 script.pl
  SCREEN_TRACE=1 script.pl
  SCREEN_LOG_LEVEL=info script.pl
 
  script.pl --screen_verbose
  script.pl --screen-debug
  script.pl --screen-trace=1
  script.pl --screen-log-level=info
 
 Similarly, to set only file level, use FILE_VERBOSE, FILE_LOG_LEVEL,
 --file-trace, and so on.
 
 =head2 Setting default per-output level
 
 As with setting default level, you can also set default level on a per-output
 basis:
 
  use Log::Any::App '$log';
  BEGIN {
      our $Screen_Log_Level = 'off';
      our $File_Quiet = 1; # setting file level to 'error'
      # and so on
  }
 
 If a per-output level is not specified, it will default to the general log level.
 
 =head2 Enabling/disabling output
 
 To disable a certain output, you can do this:
 
  use Log::Any::App '$log', -file => 0;
 
 or:
 
  use Log::Any::App '$log', -screen => {level=>'off'};
 
 and this won't allow the output to be re-enabled from outside the script. However
 if you do this:
 
  use Log::Any::App;
  BEGIN { our $Screen_Log_Level = 'off' }
 
 then by default screen logging is turned off but you will be able to override
 the screen log level using level flag files or environment variables or
 command-line options (SCREEN_DEBUG, --screen-verbose, and so on).
 
 =head2 Changing log level of cron scripts
 
 Environment variables and command-line options allow changing log level without
 modifying the script. But for scripts specified in crontab, they still require
 changing crontab entries, e.g.:
 
  # turn on debugging
  */5 * * * * DEBUG=1 foo
 
  # be silent
  */5 * * * * bar --quiet
 
 Another mechanism, level flag file, is useful in this case. By doing:
 
  $ echo debug > ~/foo.log_level
  # touch /etc/bar.QUIET
 
 you can also change log levels without modifying your crontab.
 
 =head2 Changing log file name/location
 
 By default Log::Any::App will log to file to ~/$NAME.log (or /var/log/$NAME.log
 if script is running as root), where $NAME is taken from the basename of $0. But
 this can be changed using:
 
  use Log::Any::App '$log', -name => 'myprog';
 
 Or, using custom path:
 
  use Log::Any::App '$log', -file => '/path/to/file';
 
 =head2 Changing other output parameters
 
 Each output argument can accept a hashref to specify various options. For
 example:
 
  use Log::Any::App '$log',
      -screen => {color=>0},   # never use color
      -file   => {path=>'/var/log/foo',
                  max_size=>'10M',
                  histories=>10,
                 },
 
 For all the available options of each output, see the init() function.
 
 =head2 Logging to syslog
 
 Logging to syslog is enabled by default if your script looks like or declare
 that it is a daemon, e.g.:
 
  use Net::Daemon; # this indicate your program is a daemon
  use Log::Any::App; # syslog logging will be turned on by default
 
  use Log::Any::App -daemon => 1; # script declares that it is a daemon
 
  # idem
  package main;
  our $IS_DAEMON = 1;
 
 But if you are certain you don't want syslog logging:
 
  use Log::Any::App -syslog => 0;
 
 =head2 Logging to directory
 
 This is done using L<Log::Dispatch::Dir> where each log message is logged to a
 different file in a specified directory. By default logging to dir is not turned
 on, to turn it on:
 
  use Log::Any::App '$log', -dir => 1;
 
 For all the available options of directory output, see the init() function.
 
 =head2 Multiple outputs
 
 Each output argument can accept an arrayref to specify more than one output. For
 example below is a code to log to three files:
 
  use Log::Any::App '$log',
      -file => [1, # default, to ~/$NAME.log or /var/log/$NAME.log
                "/var/log/log1",
                {path=>"/var/log/debug_foo", category=>'Foo', level=>'debug'}];
 
 =head2 Changing level of certain module(s)
 
 Suppose you want to shut up logs from modules Foo, Bar::Baz, and Qux (and their
 submodules as well, e.g. Foo::Alpha, Bar::Baz::Beta::Gamma) because they are too
 noisy:
 
  use Log::Any::App '$log',
      -category_level => { Foo => 'off', 'Bar::Baz' => 'off', Qux => 'off' };
 
 or (same thing):
 
  use Log::Any::App '$log',
      -category_alias => { -noisy => [qw/Foo Bar::Baz Qux/] },
      -category_level => { -noisy => 'off' };
 
 You can even specify this on a per-output basis. Suppose you only want to shut
 up the noisy modules on the screen, but not on the file:
 
  use Log::Any::App '$log',
     -category_alias => { -noisy => [qw/Foo Bar::Baz Qux/] },
     -screen => { category_level => { -noisy => 'off' } };
 
 Or perhaps, you want to shut up the noisy modules everywhere, except on the
 screen:
 
  use Log::Any::App '$log',
      -category_alias => { -noisy => [qw/Foo Bar::Baz Qux/] },
      -category_level => { -noisy => 'off' },
      -syslog => 1,                        # uses general -category_level
      -file   => "/var/log/foo",           # uses general -category_level
      -screen => { category_level => {} }; # overrides general -category_level
 
 You can also do this from the outside the script using environment variable,
 which is more flexible. Encode data structure using JSON:
 
  % LOG_SHOW_CATEGORY=1 \
    LOG_CATEGORY_ALIAS='{"-noisy":["Foo","Bar::Baz","Quz"]}' \
    LOG_CATEGORY_LEVEL='{"-noisy":"off"}' script.pl ...
 
 =head2 Only displaying log from certain module(s)
 
 Use a combination of LOG_LEVEL and LOG_CATEGORY_LEVEL. For example:
 
  % LOG_LEVEL=off LOG_CATEGORY_LEVEL='{"Foo.Bar":"trace", "Baz":"info"}' \
    script.pl ...
 
 =head2 Displaying category name
 
  % LOG_SHOW_CATEGORY=1 script.pl ...
 
 Now instead of:
 
  [25] Starting baz ritual ...
 
 now log messages will be prefixed with category:
 
  [cat Foo.Bar][25] Starting baz ritual ...
 
 =head2 Displaying location name
 
  % LOG_SHOW_LOCATION=1 script.pl ...
 
 Now log messages will be prefixed with location (function/file/line number)
 information:
 
  [loc Foo::Bar lib/Foo/Bar.pm (12)][25] Starting baz ritual ...
 
 =head2 Preventing logging level to be changed from outside the script
 
 Sometimes, for security/audit reasons, you don't want to allow script caller to
 change logging level. As explained previously, you can use the 'level' import
 argument (the highest priority of level-setting):
 
  use Log::Any::App '$log', -level => 'debug'; # always use debug level
 
 TODO: Allow something like 'debug+' to allow other mechanisms to *increase* the
 level but not decrease it. Or 'debug-' to allow other mechanisms to decrease
 level but not increase it. And finally 'debug,trace' to specify allowable levels
 (is this necessary?)
 
 =head2 Debugging
 
 To see the Log4perl configuration that is generated by Log::Any::App and how it
 came to be, set environment LOGANYAPP_DEBUG to true.
 
 =head1 FUNCTIONS
 
 None is exported.
 
 =head2 init(\@args)
 
 This is the actual function that implements the setup and configuration of
 logging. You normally need not call this function explicitly (but see below), it
 will be called once in an INIT block. In fact, when you do:
 
  use Log::Any::App 'a', 'b', 'c';
 
 it is actually passed as:
 
  init(['a', 'b', 'c']);
 
 You will need to call init() manually if you require Log::Any::App at runtime,
 in which case it is too late to run INIT block. If you want to run Log::Any::App
 in runtime phase, do this:
 
  require Log::Any::App;
  Log::Any::App::init(['a', 'b', 'c']);
 
 Arguments to init can be one or more of:
 
 =over 4
 
 =item -log => BOOL
 
 Whether to do log at all. Default is from LOG environment variable, or 1. This
 option is only to allow users to disable Log::Any::App (thus speeding up startup
 by avoiding loading Log4perl, etc) by passing LOG=1 environment when running
 programs. However, if you explicitly set this option to 1, Log::Any::App cannot
 be disabled this way.
 
 =item -init => BOOL
 
 Whether to call Log::Log4perl->init() after setting up the Log4perl
 configuration. Default is true. You can set this to false, and you can
 initialize Log4perl yourself (but then there's not much point in using this
 module, right?)
 
 =item -name => STRING
 
 Change the program name. Default is taken from $0.
 
 =item -level_flag_paths => ARRAY OF STRING
 
 Edit level flag file locations. The default is [$homedir, "/etc"].
 
 =item -daemon => BOOL
 
 Declare that script is a daemon. Default is no. Aside from this, to declare that
 your script is a daemon you can also set $main::IS_DAEMON to true.
 
 =item -category_alias => {ALIAS=>CATEGORY, ...}
 
 Create category aliases so the ALIAS can be used in place of real categories in
 each output's category specification. For example, instead of doing this:
 
  init(
      -file   => [category=>[qw/Foo Bar Baz/], ...],
      -screen => [category=>[qw/Foo Bar Baz/]],
  );
 
 you can do this instead:
 
  init(
      -category_alias => {-fbb => [qw/Foo Bar Baz/]},
      -file   => [category=>'-fbb', ...],
      -screen => [category=>'-fbb', ...],
  );
 
 You can also specify this from the environment variable LOG_CATEGORY_ALIAS using
 JSON encoding, e.g.
 
  LOG_CATEGORY_ALIAS='{"-fbb":["Foo","Bar","Baz"]}'
 
 =item -category_level => {CATEGORY=>LEVEL, ...}
 
 Specify per-category level. Categories not mentioned on this will use the
 general level (-level). This can be used to increase or decrease logging on
 certain categories/modules.
 
 You can also specify this from the environment variable LOG_CATEGORY_LEVEL using
 JSON encoding, e.g.
 
  LOG_CATEGORY_LEVEL='{"-fbb":"off"}'
 
 =item -level => 'trace'|'debug'|'info'|'warn'|'error'|'fatal'|'off'
 
 Specify log level for all outputs. Each output can override this value. The
 default log level is determined as follow:
 
 B<Search in command-line options>. If L<App::Options> is present, these keys are
 checked in B<%App::options>: B<log_level>, B<trace> (if true then level is
 C<trace>), B<debug> (if true then level is C<debug>), B<verbose> (if true then
 level is C<info>), B<quiet> (if true then level is C<error>).
 
 Otherwise, it will try to scrape @ARGV for the presence of B<--log-level>,
 B<--trace>, B<--debug>, B<--verbose>, or B<--quiet> (this usually works because
 Log::Any::App does this in the INIT phase, before you call L<Getopt::Long>'s
 GetOptions() or the like).
 
 B<Search in environment variables>. Otherwise, it will look for environment
 variables: B<LOG_LEVEL>, B<QUIET>. B<VERBOSE>, B<DEBUG>, B<TRACE>.
 
 B<Search in level flag files>. Otherwise, it will look for existence of files
 with one of these names C<$NAME.QUIET>, C<$NAME.VERBOSE>, C<$NAME.TRACE>,
 C<$NAME.DEBUG>, or content of C<$NAME.log_level> in ~ or /etc.
 
 B<Search in main package variables>. Otherwise, it will try to search for
 package variables in the C<main> namespace with names like C<$Log_Level> or
 C<$LOG_LEVEL> or C<$log_level>, C<$Quiet> or C<$QUIET> or C<$quiet>, C<$Verbose>
 or C<$VERBOSE> or C<$verbose>, C<$Trace> or C<$TRACE> or C<$trace>, C<$Debug> or
 C<$DEBUG> or C<$debug>.
 
 If everything fails, it defaults to 'warn'.
 
 =item -filter_text => STR
 
 Only show log lines matching STR. Default from C<LOG_FILTER_TEXT> environment.
 
 =item -filter_no_text => STR
 
 Only show log lines not matching STR. Default from C<LOG_FILTER_NO_TEXT>
 environment.
 
 =item -filter_citext => STR
 
 Only show log lines matching STR (case insensitive). Default from
 C<LOG_FILTER_CITEXT> environment.
 
 =item -filter_no_citext => STR
 
 Only show log lines not matching STR (case insensitive). Default from
 C<LOG_FILTER_NO_CITEXT> environment.
 
 =item -filter_re => RE
 
 Only show log lines matching regex pattern RE. Default from C<LOG_FILTER_RE>
 environment.
 
 =item -filter_no_re => RE
 
 Only show log lines not matching regex pattern RE. Default from
 C<LOG_FILTER_NO_RE> environment.
 
 =item -file => 0 | 1|yes|true | PATH | {opts} | [{opts}, ...]
 
 Specify output to one or more files, using L<Log::Dispatch::FileWriteRotate>.
 
 If the argument is a false boolean value, file logging will be turned off. If
 argument is a true value that matches /^(1|yes|true)$/i, file logging will be
 turned on with default path, etc. If the argument is another scalar value then
 it is assumed to be a path. If the argument is a hashref, then the keys of the
 hashref must be one of: C<level>, C<path>, C<max_size> (maximum size before
 rotating, in bytes, 0 means unlimited or never rotate), C<histories> (number of
 old files to keep, excluding the current file), C<suffix> (will be passed to
 Log::Dispatch::FileWriteRotate's constructor), C<period> (will be passed to
 Log::Dispatch::FileWriteRotate's constructor), C<buffer_size> (will be passed to
 Log::Dispatch::FileWriteRotate's constructor), C<category> (a string of ref to
 array of strings), C<category_level> (a hashref, similar to -category_level),
 C<pattern_style> (see L<"PATTERN STYLES">), C<pattern> (Log4perl pattern),
 C<filter_text>, C<filter_no_text>, C<filter_citext>, C<filter_no_citext>,
 C<filter_re>, C<filter_no_re>.
 
 If the argument is an arrayref, it is assumed to be specifying multiple files,
 with each element of the array as a hashref.
 
 How Log::Any::App determines defaults for file logging:
 
 If program is a one-liner script specified using "perl -e", the default is no
 file logging. Otherwise file logging is turned on.
 
 If the program runs as root, the default path is C</var/log/$NAME.log>, where
 $NAME is taken from B<$0> (or C<-name>). Otherwise the default path is
 ~/$NAME.log. Intermediate directories will be made with L<File::Path>.
 
 If specified C<path> ends with a slash (e.g. "/my/log/"), it is assumed to be a
 directory and the final file path is directory appended with $NAME.log.
 
 Default rotating behaviour is no rotate (max_size = 0).
 
 Default level for file is the same as the global level set by B<-level>. But
 App::options, command line, environment, level flag file, and package variables
 in main are also searched first (for B<FILE_LOG_LEVEL>, B<FILE_TRACE>,
 B<FILE_DEBUG>, B<FILE_VERBOSE>, B<FILE_QUIET>, and the similars).
 
 You can also specify category level from environment FILE_LOG_CATEGORY_LEVEL.
 
 =item -dir => 0 | 1|yes|true | PATH | {opts} | [{opts}, ...]
 
 Log messages using L<Log::Dispatch::Dir>. Each message is logged into separate
 files in the directory. Useful for dumping content (e.g. HTML, network dumps, or
 temporary results).
 
 If the argument is a false boolean value, dir logging will be turned off. If
 argument is a true value that matches /^(1|yes|true)$/i, dir logging will be
 turned on with defaults path, etc. If the argument is another scalar value then
 it is assumed to be a directory path. If the argument is a hashref, then the
 keys of the hashref must be one of: C<level>, C<path>, C<max_size> (maximum
 total size of files before deleting older files, in bytes, 0 means unlimited),
 C<max_age> (maximum age of files to keep, in seconds, undef means unlimited).
 C<histories> (number of old files to keep, excluding the current file),
 C<category>, C<category_level> (a hashref, similar to -category_level),
 C<pattern_style> (see L<"PATTERN STYLES">), C<pattern> (Log4perl pattern),
 C<filename_pattern> (pattern of file name), C<filter_text>, C<filter_no_text>,
 C<filter_citext>, C<filter_no_citext>, C<filter_re>, C<filter_no_re>.
 
 If the argument is an arrayref, it is assumed to be specifying multiple
 directories, with each element of the array as a hashref.
 
 How Log::Any::App determines defaults for dir logging:
 
 Directory logging is by default turned off. You have to explicitly turn it on.
 
 If the program runs as root, the default path is C</var/log/$NAME/>, where $NAME
 is taken from B<$0>. Otherwise the default path is ~/log/$NAME/. Intermediate
 directories will be created with File::Path. Program name can be changed using
 C<-name>.
 
 Default rotating parameters are: histories=1000, max_size=0, max_age=undef.
 
 Default level for dir logging is the same as the global level set by B<-level>.
 But App::options, command line, environment, level flag file, and package
 variables in main are also searched first (for B<DIR_LOG_LEVEL>, B<DIR_TRACE>,
 B<DIR_DEBUG>, B<DIR_VERBOSE>, B<DIR_QUIET>, and the similars).
 
 You can also specify category level from environment DIR_LOG_CATEGORY_LEVEL.
 
 =item -screen => 0 | 1|yes|true | {opts}
 
 Log messages using L<Log::Log4perl::Appender::ScreenColoredLevels>.
 
 If the argument is a false boolean value, screen logging will be turned off. If
 argument is a true value that matches /^(1|yes|true)$/i, screen logging will be
 turned on with default settings. If the argument is a hashref, then the keys of
 the hashref must be one of: C<color> (default is true, set to 0 to turn off
 color), C<stderr> (default is true, set to 0 to log to stdout instead),
 C<level>, C<category>, C<category_level> (a hashref, similar to
 -category_level), C<pattern_style> (see L<"PATTERN STYLE">), C<pattern>
 (Log4perl string pattern), C<filter_text>, C<filter_no_text>, C<filter_citext>,
 C<filter_no_citext>, C<filter_re>, C<filter_no_re>.
 
 How Log::Any::App determines defaults for screen logging:
 
 Screen logging is turned on by default.
 
 Default level for screen logging is the same as the global level set by
 B<-level>. But App::options, command line, environment, level flag file, and
 package variables in main are also searched first (for B<SCREEN_LOG_LEVEL>,
 B<SCREEN_TRACE>, B<SCREEN_DEBUG>, B<SCREEN_VERBOSE>, B<SCREEN_QUIET>, and the
 similars).
 
 Color can also be turned on/off using environment variable COLOR (if B<color>
 argument is not set).
 
 You can also specify category level from environment SCREEN_LOG_CATEGORY_LEVEL.
 
 =item -syslog => 0 | 1|yes|true | {opts}
 
 Log messages using L<Log::Dispatch::Syslog>.
 
 If the argument is a false boolean value, syslog logging will be turned off. If
 argument is a true value that matches /^(1|yes|true)$/i, syslog logging will be
 turned on with default level, ident, etc. If the argument is a hashref, then the
 keys of the hashref must be one of: C<level>, C<ident>, C<facility>,
 C<category>, C<category_level> (a hashref, similar to -category_level),
 C<pattern_style> (see L<"PATTERN STYLES">), C<pattern> (Log4perl pattern),
 C<filter_text>, C<filter_no_text>, C<filter_citext>, C<filter_no_citext>,
 C<filter_re>, C<filter_no_re>.
 
 How Log::Any::App determines defaults for syslog logging:
 
 If a program is a daemon (determined by detecting modules like L<Net::Server> or
 L<Proc::PID::File>, or by checking if -daemon or $main::IS_DAEMON is true) then
 syslog logging is turned on by default and facility is set to C<daemon>,
 otherwise the default is off.
 
 Ident is program's name by default ($0, or C<-name>).
 
 Default level for syslog logging is the same as the global level set by
 B<-level>. But App::options, command line, environment, level flag file, and
 package variables in main are also searched first (for B<SYSLOG_LOG_LEVEL>,
 B<SYSLOG_TRACE>, B<SYSLOG_DEBUG>, B<SYSLOG_VERBOSE>, B<SYSLOG_QUIET>, and the
 similars).
 
 You can also specify category level from environment SYSLOG_LOG_CATEGORY_LEVEL.
 
 =item -unixsock => 0 | 1|yes|true | PATH | {opts} | [{opts}, ...]
 
 Specify output to one or more B<existing, listening, datagram> Unix domain
 sockets, using L<Log::Log4perl::Appender::Socket::UNIX>.
 
 The listening end might be a different process, or the same process using a
 different thread of nonblocking I/O. It usually makes little sense to make the
 same program the listening end. If you want, for example, to let a client
 connects to your program to see logs being produced, you might want to setup an
 in-memory output (C<-array>) and create another thread or non-blocking I/O to
 listen to client requests and show them the content of the array when requested.
 
 If the argument is a false boolean value, Unix domain socket logging will be
 turned off. If argument is a true value that matches /^(1|yes|true)$/i, Unix
 domain socket logging will be turned on with default path, etc. If the argument
 is another scalar value then it is assumed to be a path. If the argument is a
 hashref, then the keys of the hashref must be one of: C<level>, C<path>,
 C<filter_text>, C<filter_no_text>, C<filter_citext>, C<filter_no_citext>,
 C<filter_re>, C<filter_no_re>.
 
 If the argument is an arrayref, it is assumed to be specifying multiple sockets,
 with each element of the array as a hashref.
 
 How Log::Any::App determines defaults for Unix domain socket logging:
 
 By default Unix domain socket logging is off.
 
 If the program runs as root, the default path is C</var/run/$NAME-log.sock>,
 where $NAME is taken from B<$0> (or C<-name>). Otherwise the default path is
 ~/$NAME-log.sock.
 
 If specified C<path> ends with a slash (e.g. "/my/log/"), it is assumed to be a
 directory and the final socket path is directory appended with $NAME-log.sock.
 
 Default level is the same as the global level set by B<-level>. But
 App::options, command line, environment, level flag file, and package variables
 in main are also searched first (for B<UNIXSOCK_LOG_LEVEL>, B<UNIXSOCK_TRACE>,
 B<UNIXSOCK_DEBUG>, B<UNIXSOCK_VERBOSE>, B<UNIXSOCK_QUIET>, and the similars).
 
 You can also specify category level from environment
 UNIXSOCK_LOG_CATEGORY_LEVEL.
 
 =item -array => 0 | {opts} | [{opts}, ...]
 
 Specify output to one or more Perl arrays. Logging will be done using
 L<Log::Dispatch::ArrayWithLimits>. Note that the syntax is:
 
  -array => {array=>$ary}
 
 and not just:
 
  -array => $ary
 
 because that will be interpreted as multiple array outputs:
 
  -array => [{output1}, ...]
 
 If the argument is a false boolean value, array logging will be turned off.
 Otherwise argument must be a hashref or an arrayref (to specify multiple
 outputs). If the argument is a hashref, then the keys of the hashref must be one
 of: C<level>, C<array> (defaults to new anonymous array []), C<filter_text>,
 C<filter_no_text>, C<filter_citext>, C<filter_no_citext>, C<filter_re>,
 C<filter_no_re>. If the argument is an arrayref, it is assumed to be specifying
 multiple sockets, with each element of the array as a hashref.
 
 How Log::Any::App determines defaults for array logging:
 
 By default array logging is off.
 
 Default level is the same as the global level set by B<-level>. But
 App::options, command line, environment, level flag file, and package variables
 in main are also searched first (for B<ARRAY_LOG_LEVEL>, B<ARRAY_TRACE>,
 B<ARRAY_DEBUG>, B<ARRAY_VERBOSE>, B<ARRAY_QUIET>, and the similars).
 
 You can also specify category level from environment ARRAY_LOG_CATEGORY_LEVEL.
 
 =item -dump => BOOL
 
 If set to true then Log::Any::App will dump the generated Log4perl config.
 Useful for debugging the logging.
 
 =back
 
 =head1 PATTERN STYLES
 
 Log::Any::App provides some styles for Log4perl patterns. You can specify
 C<pattern_style> instead of directly specifying C<pattern>. example:
 
  use Log::Any::App -screen => {pattern_style=>"script_long"};
 
  Name           Description                        Example output
  ----           -----------                        --------------
  plain          The message, the whole message,    Message
                 and nothing but the message.
                 Used by dir logging.
 
                 Equivalent to pattern: '%m'
 
  plain_nl       Message plus newline. The default  Message
                 for screen without
                 LOG_ELAPSED_TIME_IN_SCREEN.
 
                 Equivalent to pattern: '%m%n'
 
  script_short   For scripts that run for a short   [234] Message
                 time (a few seconds). Shows just
                 the number of milliseconds. This
                 is the default for screen under
                 LOG_ELAPSED_TIME_IN_SCREEN.
 
                 Equivalent to pattern:
                 '[%r] %m%n'
 
  script_long    Scripts that will run for a        [2010-04-22 18:01:02] Message
                 while (more than a few seconds).
                 Shows date/time.
 
                 Equivalent to pattern:
                 '[%d] %m%n'
 
  daemon         For typical daemons. Shows PID     [pid 1234] [2010-04-22 18:01:02] Message
                 and date/time. This is the
                 default for file logging.
 
                 Equivalent to pattern:
                 '[pid %P] [%d] %m%n'
 
  syslog         Style suitable for syslog          [pid 1234] Message
                 logging.
 
                 Equivalent to pattern:
                 '[pid %p] %m'
 
 For each of the above there are also C<cat_XXX> (e.g. C<cat_script_long>) which
 are the same as XXX but with C<[cat %c]> in front of the pattern. It is used
 mainly to show categories and then filter by categories. You can turn picking
 default pattern style with category using environment variable
 LOG_SHOW_CATEGORY.
 
 And for each of the above there are also C<loc_XXX> (e.g. C<loc_syslog>) which
 are the same as XXX but with C<[loc %l]> in front of the pattern. It is used to
 show calling location (file, function/method, and line number). You can turn
 picking default pattern style with location prefix using environment variable
 LOG_SHOW_LOCATION.
 
 If you have a favorite pattern style, please do share them.
 
 =head1 ENVIRONMENT
 
 Below is summary of environment variables used.
 
 =head2 Turning on/off logging
 
  LOG (bool)
 
 =head2 Setting general level
 
  TRACE (bool)       setting general level to trace
  DEBUG (bool)       setting general level to debug
  VERBOSE (bool)     setting general level to info
  QUIET (bool)       setting general level to error (turn off warnings)
  LOG_LEVEL (str)
 
 =head2 Setting per-output level
 
  FILE_TRACE, FILE_DEBUG, FILE_VERBOSE, FILE_QUIET, FILE_LOG_LEVEL
  SCREEN_TRACE and so on
  DIR_TRACE and so on
  SYSLOG_TRACE and so on
  UNIXSOCK_TRACE and so on
  ARRAY_TRACE and so on
 
 =head2 Setting per-category level
 
  LOG_CATEGORY_LEVEL (hash, json)
  LOG_CATEGORY_ALIAS (hash, json)
 
 =head2 Setting per-output, per-category level
 
  FILE_LOG_CATEGORY_LEVEL
  SCREEN_LOG_CATEGORY_LEVEL
  and so on
 
 =head2 Controlling extra fields to log
 
  LOG_SHOW_LOCATION
  LOG_SHOW_CATEGORY
 
 =head2 Force-enable or disable color
 
  COLOR (bool)
 
 =head2 Turn on Log::Any::App's debugging
 
  LOGANYAPP_DEBUG (bool)
 
 =head2 Turn on showing elapsed time in screen
 
  LOG_ELAPSED_TIME_IN_SCREEN (bool)
 
 Note that elapsed time is currently produced using Log::Log4perl's %r (number of
 milliseconds since the program started, where program started means when
 Log::Log4perl starts counting time).
 
 =head2 Filtering
 
  LOG_FILTER_TEXT (str)
  LOG_FILTER_NO_TEXT (str)
  LOG_FILTER_CITEXT (str)
  LOG_FILTER_NO_CITEXT (str)
  LOG_FILTER_RE (str)
  LOG_FILTER_NO_RE (str)
 
 =head2 Per-output filtering
 
  {FILE,DIR,SCREEN,SYSLOG,UNIXSOCK,ARRAY}_LOG_FILTER_TEXT (str)
  and so on
 
 =head2 Extra things to log
 
 =over
 
 =item * LOG_ENV (bool)
 
 If set to 1, will dump environment variables at the start of program. Useful for
 debugging e.g. CGI or git hook scripts. You might also want to look at
 L<Log::Any::Adapter::Core::Patch::UseDataDump> to make the dump more readable.
 
 Logging will be done under category C<main> and at level C<trace>.
 
 =back
 
 =head1 FAQ
 
 =head2 Why?
 
 I initially wrote Log::Any::App because I'm sick of having to parse command-line
 options to set log level like --verbose, --log-level=debug for every script.
 Also, before using Log::Any I previously used Log4perl directly and modules
 which produce logs using Log4perl cannot be directly use'd in one-liners without
 Log4perl complaining about uninitialized configuration or some such. Thus, I
 like Log::Any's default null adapter and want to settle using Log::Any for any
 kind of logging. Log::Any::App makes it easy to output Log::Any logs in your
 scripts and even one-liners.
 
 =head2 What's the benefit of using Log::Any::App?
 
 You get all the benefits of Log::Any, as what Log::Any::App does is just wrap
 Log::Any and Log4perl with some nice defaults. It provides you with an easy way
 to consume Log::Any logs and customize level/some other options via various
 ways.
 
 =head2 And what's the benefit of using Log::Any?
 
 This is better described in the Log::Any documentation itself, but in short:
 Log::Any frees your module users to use whatever logging framework they want. It
 increases the reusability of your modules.
 
 =head2 Do I need Log::Any::App if I am writing modules?
 
 No, if you write modules just use Log::Any.
 
 =head2 Why use Log4perl?
 
 Log::Any::App uses the Log4perl adapter to display the logs because it is
 mature, flexible, featureful. The other alternative adapter is Log::Dispatch,
 but you can use Log::Dispatch::* output modules in Log4perl and (currently) not
 vice versa.
 
 Other adapters might be considered in the future, for now I'm fairly satisfied
 with Log4perl. It does have a slightly heavy startup cost for my taste, but it
 is still bearable.
 
 =head2 Are you coupling adapter with Log::Any (thus defeating Log::Any's purpose)?
 
 No, producing logs are still done with Log::Any as usual and not tied to
 Log4perl in any way. Your modules, as explained above, only 'use Log::Any' and
 do not depend on Log::Any::App at all.
 
 Should portions of your application code get refactored into modules later, you
 don't need to change the logging part. And if your application becomes more
 complex and Log::Any::App doesn't suffice your custom logging needs anymore, you
 can just replace 'use Log::Any::App' line with something more adequate.
 
 =head2 How do I create extra logger objects?
 
 The usual way as with Log::Any:
 
  my $other_log = Log::Any->get_logger(category => $category);
 
 =head2 My needs are not met by the simple configuration system of Log::Any::App!
 
 You can use the Log4perl adapter directly and write your own Log4perl
 configuration (or even other adapters). Log::Any::App is meant for quick and
 simple logging output needs anyway (but do tell me if your logging output needs
 are reasonably simple and should be supported by Log::Any::App).
 
 =head2 What is array output for?
 
 Logging to a Perl array might be useful for testing/debugging, or (one use-case
 I can think of) for letting users of your program connect to your program
 directly to request viewing the logs being produced (although logging to other
 outputs doesn't preclude this ability). For example, here is a program that uses
 a separate thread to listen to Unix socket for requests to view the (last 100)
 logs. Requires perl built with threads enabled.
 
  use threads;
  use threads::shared;
  BEGIN { our @buf :shared }
  use IO::Socket::UNIX::Util qw(create_unix_stream_socket);
  use Log::Any::App '$log', -array => [{array => 'main::buf', max_elems=>100}];
 
  my $sock = create_unix_stream_socket('/tmp/app-logview.sock');
 
  # thread to listen to unix socket and receive log viewing instruction
  my $thr = threads->create(
     sub {
         local $| = 1;
         while (my $cli = $sock->accept) {
             while (1) {
                 print $cli "> ";
                 my $line = <$cli>;
                 last unless $line;
                 if ($line =~ /\Ar(ead)?\b/i) {
                     print $cli @buf;
                 } else {
                     print $cli "Unknown command\n";
                 }
             }
         }
     });
 
  # main thread, application which produces logs
  $|++;
  while (1) {
      $log->warnf("Log (%d) ...", ++$i);
      sleep 1;
  }
 
 After you run this program, you can connect to it, e.g. from another terminal:
 
  % socat UNIX-CONNECT:/tmp/app-logview.sock -
  > read
  [2014/07/06 23:34:49] Log (1) ...
  [2014/07/06 23:34:50] Log (2) ...
  [2014/07/06 23:34:50] Log (3) ...
  [2014/07/06 23:34:51] Log (4) ...
  [2014/07/06 23:34:51] Log (5) ...
 
 =head1 BUGS/TODOS
 
 Need to provide appropriate defaults for Windows/other OS.
 
 =head1 ROAD TO 1.0
 
 Here are some planned changes/development before 1.0 is reached. There might be
 some incompatibilities, please read this section carefully.
 
 =over 4
 
 =item * Everything is configurable via environment/command-line/option file
 
 As I I<love> specifying log options from environment, I will make I<every>
 init() options configurable from outside the script
 (environment/command-line/control file). Of course, init() arguments still take
 precedence for authors that do not want some/all options to be overridden from
 outside.
 
 =item * Reorganization of command-line/environment names
 
 Aside from the handy and short TRACE (--trace), DEBUG, VERBOSE, QUIET, all the
 other environment names will be put under LOG_ prefix. This means FILE_LOG_LEVEL
 will be changed to LOG_FILE_LEVEL, and so on. SCREEN_VERBOSE will be changed to
 VERBOSE_SCREEN.
 
 This is meant to reduce "pollution" of the environment variables namespace.
 
 Log option file (option file for short, previously "flag file") will be searched
 in <PROG>.log_options. Its content is in JSON and will become init() arguments.
 For example:
 
  {"file": 1, "screen":{"level":"trace"}}
 
 or more akin to init() (both will be supported):
 
  ["-file": 1, "-screen":{"level":"trace"}]
 
 =item * Possible reorganization of package variable names
 
 To be more strict and reduce confusion, case variation might not be searched.
 
 =item * Pluggable backend
 
 This is actually the main motivator to reach 1.0 and all these changes. Backends
 will be put in Log::Any::App::Backend::Log4perl, and so on.
 
 =item * Pluggable output
 
 Probably split to Log::Any::App::Output::file, and so on. Each output needs
 its backend support.
 
 =item * App::Options support will probably be dropped
 
 I no longer use App::Options these days, and I don't know of any Log::Any::App
 user who does.
 
 =item * Probably some hooks to allow for more flexibility.
 
 For example, if user wants to parse or detect levels/log file paths/etc from
 some custom logic.
 
 =back
 
 =head1 SEE ALSO
 
 L<Log::Any> and L<Log::Log4perl>
 
 Some alternative logging modules: L<Log::Dispatchouli> (based on
 L<Log::Dispatch>), L<Log::Fast>, L<Log::Log4perl::Tiny>. Really, there are 7,451
 of them (roughly one third of CPAN) at the time of this writing.
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Log-Any-App>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Log-Any-App>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Log-Any-App>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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
### Log/Any/IfLOG.pm ###
 package Log::Any::IfLOG;
 
 our $DATE = '2015-08-17'; # DATE
 our $VERSION = '0.07'; # VERSION
 
 our $DEBUG;
 our $ENABLE_LOG;
 
 my $log_singleton;
 sub __log_singleton {
     if (!$log_singleton) { $log_singleton = Object::Dumb->new }
     $log_singleton;
 }
 
 sub __log_enabled {
     if (defined $ENABLE_LOG) {
         return $ENABLE_LOG;
     } elsif ($INC{'Log/Any.pm'}) {
         # Log::Any has been loaded, so we have absorbed the cost anyway
         return 1;
     } else {
         return
             $ENV{LOG} || $ENV{TRACE} || $ENV{DEBUG} ||
             $ENV{VERBOSE} || $ENV{QUIET} || $ENV{LOG_LEVEL};
     }
 }
 
 sub import {
     my $self = shift;
 
     my $caller = caller();
     if (__log_enabled()) {
         require Log::Any;
         Log::Any->_export_to_caller($caller, @_);
     } else {
         my $saw_log_param = grep { $_ eq '$log' } @_;
         if ($saw_log_param) {
             __log_singleton(); # to init $log_singleton
             *{"$caller\::log"} = \$log_singleton;
         }
     }
 }
 
 sub get_logger {
     if (__log_enabled()) {
         require Log::Any;
         my $class = shift;
         if ($class eq 'Log::Any::IfLOG') {
             Log::Any->get_logger(@_);
         } else {
             Log::Any::get_logger($class, @_);
         }
     } else {
         return __log_singleton();
     }
 }
 
 package
     Object::Dumb;
 sub new { my $o = ""; bless \$o, shift }
 sub AUTOLOAD { 0 }
 
 1;
 # ABSTRACT: Load Log::Any only if "logging is enabled"
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Log::Any::IfLOG - Load Log::Any only if "logging is enabled"
 
 =head1 VERSION
 
 This document describes version 0.07 of Log::Any::IfLOG (from Perl distribution Log-Any-IfLOG), released on 2015-08-17.
 
 =head1 SYNOPSIS
 
  use Log::Any::IfLOG '$log';
 
 =head1 DESCRIPTION
 
 This module is a drop-in replacement/wrapper for L<Log::Any> to be used from
 your modules. This is a quick-hack solution to avoid the cost of loading
 Log::Any under "normal condition". Since Log::Any 1.00, startup overhead
 increases to about 7-10ms on my PC/laptop (from under 1ms for the previous
 version). Because I want to keep startup overhead of CLI apps under 50ms (see
 L<Perinci::CmdLine::Lite>) to keep tab completion from getting a noticeable lag,
 every millisecond counts.
 
 This module will only load L<Log::Any> when "logging is enabled". Otherwise, it
 will just return without loading anything. If C<$log> is requested in import, a
 fake object is returned that responds to methods like C<debug>, C<is_debug> and
 so on but will do nothing when called and just return 0.
 
 To determine "logging is enabled":
 
 =over
 
 =item * Is $ENABLE_LOG defined?
 
 This package variable can be used to force "logging enabled" (if true) or
 "logging disabled" (if false). Normally, you don't need to do this except for
 testing.
 
 =item * Is Log::Any is already loaded (from %INC)?
 
 If Log::Any is already loaded, it means we have taken the overhead hit anyway so
 logging is enabled.
 
 =item * Is one of log-related environment variables true?
 
 If one of L<LOG>, C<TRACE>, or C<DEBUG>, or C<VERBOSE>, or C<QUIET>, or
 C<LOG_LEVEL> is true then logging is enabled. These variables are used by
 L<Perinci::CmdLine>.
 
 Otherwise, logging is disabled.
 
 =back
 
 =for Pod::Coverage ^(.+)$
 
 =head1 ENVIRONMENT
 
 =head2 LOG => bool
 
 =head2 TRACE => bool
 
 =head2 DEBUG => bool
 
 =head2 VERBOSE => bool
 
 =head2 QUIET => bool
 
 =head2 LOG_LEVEL => str
 
 =head1 VARIABLES
 
 =head2 $ENABLE_LOG => bool
 
 This setting can be forced to force loading Log::Any or not.
 
 =head1 SEE ALSO
 
 L<Log::Any>
 
 L<http://github.com/dagolden/Log-Any/issues/24>
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Log-Any-IfLOG>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Log-Any-IfLOG>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Log-Any-IfLOG>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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
### Log/Any/Manager.pm ###
 use 5.008001;
 use strict;
 use warnings;
 
 package Log::Any::Manager;
 
 our $VERSION = '1.032';
 
 sub new {
     my $class = shift;
     my $self  = {
         entries         => [],
         category_cache  => {},
         default_adapter => {},
     };
     bless $self, $class;
 
     return $self;
 }
 
 sub get_adapter {
     my ( $self, $category ) = @_;
 
     # Create a new adapter for this category if it is not already in cache
     #
     my $category_cache = $self->{category_cache};
     if ( !defined( $category_cache->{$category} ) ) {
         my $entry = $self->_choose_entry_for_category($category);
         my $adapter = $self->_new_adapter_for_entry( $entry, $category );
         $category_cache->{$category} = { entry => $entry, adapter => $adapter };
     }
     return $category_cache->{$category}->{adapter};
 }
 
 {
     no warnings 'once';
     *get_logger = \&get_adapter;    # backwards compatibility
 }
 
 sub _choose_entry_for_category {
     my ( $self, $category ) = @_;
 
     foreach my $entry ( @{ $self->{entries} } ) {
         if ( $category =~ $entry->{pattern} ) {
             return $entry;
         }
     }
     # nothing requested so fallback to default
     my $default = $self->{default_adapter}{$category}
         || [ $self->_get_adapter_class("Null"), [] ];
     my ($adapter_class, $adapter_params) = @$default;
     _require_dynamic($adapter_class);
     return {
         adapter_class  => $adapter_class,
         adapter_params => $adapter_params,
     };
 }
 
 sub _new_adapter_for_entry {
     my ( $self, $entry, $category ) = @_;
 
     return $entry->{adapter_class}
       ->new( @{ $entry->{adapter_params} }, category => $category );
 }
 
 sub set_default {
     my ( $self, $category, $adapter_name, @adapter_params ) = @_;
     my $adapter_class = $self->_get_adapter_class($adapter_name);
     $self->{default_adapter}{$category} = [$adapter_class, \@adapter_params];
 }
 
 sub set {
     my $self = shift;
     my $options;
     if ( ref( $_[0] ) eq 'HASH' ) {
         $options = shift(@_);
     }
     my ( $adapter_name, @adapter_params ) = @_;
 
     unless ( defined($adapter_name) && $adapter_name =~ /\S/ ) {
         require Carp;
         Carp::croak("expected adapter name");
     }
 
     my $pattern = $options->{category};
     if ( !defined($pattern) ) {
         $pattern = qr/.*/;
     }
     elsif ( !ref($pattern) ) {
         $pattern = qr/^\Q$pattern\E$/;
     }
 
     my $adapter_class = $self->_get_adapter_class($adapter_name);
     _require_dynamic($adapter_class);
 
     my $entry = $self->_new_entry( $pattern, $adapter_class, \@adapter_params );
     unshift( @{ $self->{entries} }, $entry );
 
     $self->_reselect_matching_adapters($pattern);
 
     if ( my $lex_ref = $options->{lexically} ) {
         $$lex_ref = Log::Any::Manager::_Guard->new(
             sub { $self->remove($entry) unless _in_global_destruction() } );
     }
 
     return $entry;
 }
 
 sub remove {
     my ( $self, $entry ) = @_;
 
     my $pattern = $entry->{pattern};
     $self->{entries} = [ grep { $_ ne $entry } @{ $self->{entries} } ];
     $self->_reselect_matching_adapters($pattern);
 }
 
 sub _new_entry {
     my ( $self, $pattern, $adapter_class, $adapter_params ) = @_;
 
     return {
         pattern        => $pattern,
         adapter_class  => $adapter_class,
         adapter_params => $adapter_params,
     };
 }
 
 sub _reselect_matching_adapters {
     my ( $self, $pattern ) = @_;
 
     return if _in_global_destruction();
 
     # Reselect adapter for each category matching $pattern
     #
     while ( my ( $category, $category_info ) =
         each( %{ $self->{category_cache} } ) )
     {
         my $new_entry = $self->_choose_entry_for_category($category);
         if ( $new_entry ne $category_info->{entry} ) {
             my $new_adapter =
               $self->_new_adapter_for_entry( $new_entry, $category );
             %{ $category_info->{adapter} } = %$new_adapter;
             bless( $category_info->{adapter}, ref($new_adapter) );
             $category_info->{entry} = $new_entry;
         }
     }
 }
 
 sub _get_adapter_class {
     my ( $self, $adapter_name ) = @_;
     return $Log::Any::OverrideDefaultAdapterClass if $Log::Any::OverrideDefaultAdapterClass;
     $adapter_name =~ s/^Log:://;    # Log::Dispatch -> Dispatch, etc.
     my $adapter_class = (
           substr( $adapter_name, 0, 1 ) eq '+'
         ? substr( $adapter_name, 1 )
         : "Log::Any::Adapter::$adapter_name"
     );
     return $adapter_class;
 }
 
 # This is adapted from the pure perl parts of Devel::GlobalDestruction
 if ( defined ${^GLOBAL_PHASE} ) {
     eval 'sub _in_global_destruction () { ${^GLOBAL_PHASE} eq q[DESTRUCT] }; 1' ## no critic
       or die $@;
 }
 else {
     require B;
     my $started = !B::main_start()->isa(q[B::NULL]);
     unless ($started) {
         eval '0 && $started; CHECK { $started = 1 }; 1' ## no critic
           or die $@;
     }
     eval ## no critic
       '0 && $started; sub _in_global_destruction () { $started && B::main_start()->isa(q[B::NULL]) }; 1'
       or die $@;
 }
 
 # XXX not DRY and not a great way to do this, but oh, well.
 sub _require_dynamic {
     my ($class) = @_;
 
     return 1 if $class->can('new'); # duck-type that class is loaded
 
     unless ( defined( eval "require $class; 1" ) )
     {    ## no critic (ProhibitStringyEval)
         die $@;
     }
 }
 
 package    # hide from PAUSE
   Log::Any::Manager::_Guard;
 
 sub new { bless $_[1], $_[0] }
 
 sub DESTROY { $_[0]->() }
 
 1;
### Log/Any/Proxy.pm ###
 use 5.008001;
 use strict;
 use warnings;
 
 package Log::Any::Proxy;
 
 # ABSTRACT: Log::Any generator proxy object
 our $VERSION = '1.032';
 
 use Log::Any::Adapter::Util ();
 
 sub _default_formatter {
     my ( $cat, $lvl, $format, @params ) = @_;
     my @new_params =
       map { !defined($_) ? '<undef>' : ref($_) ? _dump_one_line($_) : $_ }
       @params;
     return sprintf( $format, @new_params );
 }
 
 sub _dump_one_line {
     my ($value) = @_;
 
     return Data::Dumper->new( [$value] )->Indent(0)->Sortkeys(1)->Quotekeys(0)
       ->Terse(1)->Useqq(1)->Dump();
 }
 
 sub new {
     my $class = shift;
     my $self = { formatter => \&_default_formatter, @_ };
     unless ( $self->{adapter} ) {
         require Carp;
         Carp::croak("$class requires an 'adapter' parameter");
     }
     unless ( $self->{category} ) {
         require Carp;
         Carp::croak("$class requires an 'category' parameter")
     }
     bless $self, $class;
     $self->init(@_);
     return $self;
 }
 
 sub init { }
 
 for my $attr (qw/adapter filter formatter prefix/) {
     no strict 'refs';
     *{$attr} = sub { return $_[0]->{$attr} };
 }
 
 my %aliases = Log::Any::Adapter::Util::log_level_aliases();
 
 # Set up methods/aliases and detection methods/aliases
 foreach my $name ( Log::Any::Adapter::Util::logging_methods(), keys(%aliases) )
 {
     my $realname    = $aliases{$name} || $name;
     my $namef       = $name . "f";
     my $is_name     = "is_$name";
     my $is_realname = "is_$realname";
     my $numeric     = Log::Any::Adapter::Util::numeric_level($realname);
     no strict 'refs';
     *{$is_name} = sub {
         my ($self) = @_;
         return $self->{adapter}->$is_realname;
     };
     *{$name} = sub {
         my ( $self, @parts ) = @_;
         my $message = join(" ", grep { defined($_) && length($_) } @parts );
         return unless length $message;
         $message = $self->{filter}->( $self->{category}, $numeric, $message )
           if defined $self->{filter};
         return unless defined $message and length $message;
         $message = "$self->{prefix}$message"
           if defined $self->{prefix} && length $self->{prefix};
         return $self->{adapter}->$realname($message);
     };
     *{$namef} = sub {
         my ( $self, @args ) = @_;
         return unless $self->{adapter}->$is_realname;
         my $message =
           $self->{formatter}->( $self->{category}, $numeric, @args );
         return unless defined $message and length $message;
         return $self->$name($message);
     };
 }
 
 1;
 
 
 # vim: ts=4 sts=4 sw=4 et tw=75:
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Log::Any::Proxy - Log::Any generator proxy object
 
 =head1 VERSION
 
 version 1.032
 
 =head1 SYNOPSIS
 
     # prefix log messages
     use Log::Any '$log', prefix => 'MyApp: ';
 
     # transform log messages
     use Log::Any '$log', filter => \&myfilter;
 
     # format with String::Flogger instead of the default
     use String::Flogger;
     use Log::Any '$log', formatter => sub {
         my ($cat, $lvl, @args) = @_;
         String::Flogger::flog( @args );
     };
 
 =head1 DESCRIPTION
 
 Log::Any::Proxy objects are what modules use to produce log messages.  They
 construct messages and pass them along to a configured adapter.
 
 =head1 USAGE
 
 =head2 Simple logging
 
 Your library can do simple logging using logging methods corresponding to
 the log levels (or aliases):
 
 =over 4
 
 =item *
 
 trace
 
 =item *
 
 debug
 
 =item *
 
 info (inform)
 
 =item *
 
 notice
 
 =item *
 
 warning (warn)
 
 =item *
 
 error (err)
 
 =item *
 
 critical (crit, fatal)
 
 =item *
 
 alert
 
 =item *
 
 emergency
 
 =back
 
 Pass a string to be logged.  Do not include a newline.
 
     $log->info("Got some new for you.");
 
 The log string will be tranformed via the C<filter> attribute (if any) and
 the C<prefix> (if any) will be prepended.
 
 B<NOTE>: While you are encouraged to pass a single string to be logged, if
 multiple arguments are passed, they are concatenated with a space character
 into a single string before processing.  This ensures consistency across
 adapters, some of which may support multiple arguments to their logging
 functions (and which concatenate in different ways) and some of which do
 not.
 
 =head2 Advanced logging
 
 Your library can do advanced logging using logging methods corresponding to
 the log levels (or aliases), but with an "f" appended:
 
 =over 4
 
 =item *
 
 tracef
 
 =item *
 
 debugf
 
 =item *
 
 infof (informf)
 
 =item *
 
 noticef
 
 =item *
 
 warningf (warnf)
 
 =item *
 
 errorf (errf)
 
 =item *
 
 criticalf (critf, fatalf)
 
 =item *
 
 alertf
 
 =item *
 
 emergencyf
 
 =back
 
 When these methods are called, the adapter is first checked to see if it is
 logging at that level.  If not, the method returns without logging.
 
 Next, arguments are transformed to a message string via the C<formatter>
 attribute.  The default acts like C<sprintf> with some helpful formatting.
 
 Finally, the message string is logged via the simple logging functions, which
 can transform or prefix as described above.
 
 =head1 ATTRIBUTES
 
 =head2 adapter
 
 A L<Log::Any::Adapter> object to receive any messages logged.  This is
 generated by L<Log::Any> and can not be overridden.
 
 =head2 category
 
 The category name of the proxy.  If not provided, L<Log::Any> will set it
 equal to the calling when the proxy is constructed.
 
 =head2 filter
 
 A code reference to transform messages before passing them to a
 Log::Any::Adapter.  It gets three arguments: a category, a numeric level
 and a string.  It should return a string to be logged.
 
     sub {
         my ($cat, $lvl, $msg) = @_;
         return "[$lvl] $msg";
     }
 
 If the return value is undef or the empty string, no message will be
 logged.  Otherwise, the return value is passed to the logging adapter.
 
 Numeric levels range from 0 (emergency) to 8 (trace).  Constant functions
 for these levels are available from L<Log::Any::Adapter::Util>.
 
 =head2 formatter
 
 A code reference to format messages given to the C<*f> methods (C<tracef>,
 C<debugf>, C<infof>, etc..)
 
 It get three or more arguments: a category, a numeric level and the list
 of arguments passsed to the C<*f> method.  It should return a string to
 be logged.
 
     sub {
         my ($cat, $lvl, $format, @args) = @_;
         return sprintf($format, @args);
     }
 
 The default formatter acts like C<sprintf>, except that undef arguments are
 changed to C<< <undef> >> and any references or objects are dumped via
 L<Data::Dumper> (but without newlines).
 
 Numeric levels range from 0 (emergency) to 8 (trace).  Constant functions
 for these levels are available from L<Log::Any::Adapter::Util>.
 
 =head2 prefix
 
 If defined, this string will be prepended to all messages.  It will not
 include a trailing space, so add that yourself if you want.  This is less
 flexible/powerful than L</filter>, but avoids an extra function call.
 
 =head1 AUTHORS
 
 =over 4
 
 =item *
 
 Jonathan Swartz <swartz@pobox.com>
 
 =item *
 
 David Golden <dagolden@cpan.org>
 
 =back
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2014 by Jonathan Swartz 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
### Log/Any/Proxy/Test.pm ###
 use 5.008001;
 use strict;
 use warnings;
 
 package Log::Any::Proxy::Test;
 
 our $VERSION = '1.032';
 
 use base qw/Log::Any::Proxy/;
 
 my @test_methods = qw(
   msgs
   clear
   contains_ok
   category_contains_ok
   does_not_contain_ok
   category_does_not_contain_ok
   empty_ok
   contains_only_ok
 );
 
 foreach my $name (@test_methods) {
     no strict 'refs';
     *{$name} = sub {
         my $self = shift;
         $self->{adapter}->$name(@_);
     };
 }
 
 1;
### Log/Any/Test.pm ###
 use 5.008001;
 use strict;
 use warnings;
 
 package Log::Any::Test;
 
 # ABSTRACT: Test what you're logging with Log::Any
 our $VERSION = '1.032';
 
 no warnings 'once';
 $Log::Any::OverrideDefaultAdapterClass = 'Log::Any::Adapter::Test';
 $Log::Any::OverrideDefaultProxyClass   = 'Log::Any::Proxy::Test';
 
 1;
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Log::Any::Test - Test what you're logging with Log::Any
 
 =head1 VERSION
 
 version 1.032
 
 =head1 SYNOPSIS
 
     use Test::More;
     use Log::Any::Test;    # should appear before 'use Log::Any'!
     use Log::Any qw($log);
 
     # ...
     # call something that logs using Log::Any
     # ...
 
     # now test to make sure you logged the right things
 
     $log->contains_ok(qr/good log message/, "good message was logged");
     $log->does_not_contain_ok(qr/unexpected log message/, "unexpected message was not logged");
     $log->empty_ok("no more logs");
 
     # or
 
     my $msgs = $log->msgs;
     cmp_deeply($msgs, [{message => 'msg1', level => 'debug'}, ...]);
 
 =head1 DESCRIPTION
 
 C<Log::Any::Test> is a simple module that allows you to test what has been
 logged with Log::Any. Most of its API and implementation have been taken from
 L<Log::Any::Dispatch|Log::Any::Dispatch>.
 
 Using C<Log::Any::Test> sends all subsequent Log::Any log messages to a single
 global in-memory buffer.  It should be used before L<Log::Any|Log::Any>.
 
 =head1 METHODS
 
 The test_name is optional in the *_ok methods; a reasonable default will be
 provided.
 
 =over
 
 =item msgs ()
 
 Returns the current contents of the global log buffer as an array reference,
 where each element is a hash containing a I<category>, I<level>, and I<message>
 key.  e.g.
 
   {
     category => 'Foo',
     level => 'error',
     message => 'this is an error'
   },
   {
     category => 'Bar::Baz',
     level => 'debug',
     message => 'this is a debug'
   }
 
 =item contains_ok ($regex[, $test_name])
 
 Tests that a message in the log buffer matches I<$regex>. On success, the
 message is I<removed> from the log buffer (but any other matches are left
 untouched).
 
 =item does_not_contain_ok ($regex[, $test_name])
 
 Tests that no message in the log buffer matches I<$regex>.
 
 =item category_contains_ok ($category, $regex[, $test_name])
 
 Tests that a message in the log buffer from a specific category matches
 I<$regex>. On success, the message is I<removed> from the log buffer (but any
 other matches are left untouched).
 
 =item category_does_not_contain_ok ($category, $regex[, $test_name])
 
 Tests that no message from a specific category in the log buffer matches
 I<$regex>.
 
 =item empty_ok ([$test_name])
 
 Tests that there is no log buffer left. On failure, the log buffer is cleared
 to limit further cascading failures.
 
 =item contains_only_ok ($regex[, $test_name])
 
 Tests that there is a single message in the log buffer and it matches
 I<$regex>. On success, the message is removed.
 
 =item clear ()
 
 Clears the log buffer.
 
 =back
 
 =head1 SEE ALSO
 
 L<Log::Any|Log::Any>, L<Test::Log::Dispatch|Test::Log::Dispatch>
 
 =head1 AUTHORS
 
 =over 4
 
 =item *
 
 Jonathan Swartz <swartz@pobox.com>
 
 =item *
 
 David Golden <dagolden@cpan.org>
 
 =back
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2014 by Jonathan Swartz 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
### Log/Dispatch.pm ###
 package Log::Dispatch;
 
 use 5.006;
 
 use strict;
 use warnings;
 
 our $VERSION = '2.51';
 
 use base qw( Log::Dispatch::Base );
 
 use Module::Runtime qw( use_package_optimistically );
 use Params::Validate 1.03 qw(validate_with ARRAYREF CODEREF);
 use Carp ();
 
 our %LEVELS;
 
 BEGIN {
     my %level_map = (
         (
             map { $_ => $_ }
                 qw(
                 debug
                 info
                 notice
                 warning
                 error
                 critical
                 alert
                 emergency
                 )
         ),
         warn  => 'warning',
         err   => 'error',
         crit  => 'critical',
         emerg => 'emergency',
     );
 
     foreach my $l ( keys %level_map ) {
         my $sub = sub {
             my $self = shift;
             $self->log(
                 level => $level_map{$l},
                 message => @_ > 1 ? "@_" : $_[0],
             );
         };
 
         $LEVELS{$l} = 1;
 
         no strict 'refs';
         *{$l} = $sub;
     }
 }
 
 sub new {
     my $proto = shift;
     my $class = ref $proto || $proto;
 
     my %p = validate_with(
         params => \@_,
         spec   => {
             outputs => { type => ARRAYREF, optional => 1 },
             callbacks => { type => ARRAYREF | CODEREF, optional => 1 }
         },
         allow_extra => 1,    # for backward compatibility
     );
 
     my $self = bless {}, $class;
 
     my @cb = $self->_get_callbacks(%p);
     $self->{callbacks} = \@cb if @cb;
 
     if ( my $outputs = $p{outputs} ) {
         if ( ref $outputs->[1] eq 'HASH' ) {
 
             # 2.23 API
             # outputs => [
             #   File => { min_level => 'debug', filename => 'logfile' },
             #   Screen => { min_level => 'warning' }
             # ]
             while ( my ( $class, $params ) = splice @$outputs, 0, 2 ) {
                 $self->_add_output( $class, %$params );
             }
         }
         else {
 
             # 2.24+ syntax
             # outputs => [
             #   [ 'File',   min_level => 'debug', filename => 'logfile' ],
             #   [ 'Screen', min_level => 'warning' ]
             # ]
             foreach my $arr (@$outputs) {
                 die "expected arrayref, not '$arr'"
                     unless ref $arr eq 'ARRAY';
                 $self->_add_output(@$arr);
             }
         }
     }
 
     return $self;
 }
 
 sub clone {
     my $self = shift;
 
     my %clone = (
         callbacks => [ @{ $self->{callbacks} || [] } ],
         outputs   => { %{ $self->{outputs}   || {} } },
     );
 
     return bless \%clone, ref $self;
 }
 
 sub _add_output {
     my $self  = shift;
     my $class = shift;
 
     my $full_class
         = substr( $class, 0, 1 ) eq '+'
         ? substr( $class, 1 )
         : "Log::Dispatch::$class";
 
     use_package_optimistically($full_class);
 
     $self->add( $full_class->new(@_) );
 }
 
 sub add {
     my $self   = shift;
     my $object = shift;
 
     # Once 5.6 is more established start using the warnings module.
     if ( exists $self->{outputs}{ $object->name } && $^W ) {
         Carp::carp(
             "Log::Dispatch::* object ", $object->name,
             " already exists."
         );
     }
 
     $self->{outputs}{ $object->name } = $object;
 }
 
 sub remove {
     my $self = shift;
     my $name = shift;
 
     return delete $self->{outputs}{$name};
 }
 
 sub outputs {
     my $self = shift;
 
     return values %{ $self->{outputs} };
 }
 
 sub callbacks {
     my $self = shift;
 
     return @{ $self->{callbacks} };
 }
 
 sub log {
     my $self = shift;
     my %p    = @_;
 
     return unless $self->would_log( $p{level} );
 
     $self->_log_to_outputs( $self->_prepare_message(%p) );
 }
 
 sub _prepare_message {
     my $self = shift;
     my %p    = @_;
 
     $p{message} = $p{message}->()
         if ref $p{message} eq 'CODE';
 
     $p{message} = $self->_apply_callbacks(%p)
         if $self->{callbacks};
 
     return %p;
 }
 
 sub _log_to_outputs {
     my $self = shift;
     my %p    = @_;
 
     foreach ( keys %{ $self->{outputs} } ) {
         $p{name} = $_;
         $self->_log_to(%p);
     }
 }
 
 sub log_and_die {
     my $self = shift;
 
     my %p = $self->_prepare_message(@_);
 
     $self->_log_to_outputs(%p) if $self->would_log( $p{level} );
 
     $self->_die_with_message(%p);
 }
 
 sub log_and_croak {
     my $self = shift;
 
     $self->log_and_die( @_, carp_level => 3 );
 }
 
 sub _die_with_message {
     my $self = shift;
     my %p    = @_;
 
     my $msg = $p{message};
 
     local $Carp::CarpLevel = ( $Carp::CarpLevel || 0 ) + $p{carp_level}
         if exists $p{carp_level};
 
     Carp::croak($msg);
 }
 
 sub log_to {
     my $self = shift;
     my %p    = @_;
 
     $p{message} = $self->_apply_callbacks(%p)
         if $self->{callbacks};
 
     $self->_log_to(%p);
 }
 
 sub _log_to {
     my $self = shift;
     my %p    = @_;
     my $name = $p{name};
 
     if ( exists $self->{outputs}{$name} ) {
         $self->{outputs}{$name}->log(@_);
     }
     elsif ($^W) {
         Carp::carp(
             "Log::Dispatch::* object named '$name' not in dispatcher\n");
     }
 }
 
 sub output {
     my $self = shift;
     my $name = shift;
 
     return unless exists $self->{outputs}{$name};
 
     return $self->{outputs}{$name};
 }
 
 sub level_is_valid {
     shift;
     my $level = shift
         or Carp::croak('Logging level was not provided');
 
     return $LEVELS{$level};
 }
 
 sub would_log {
     my $self  = shift;
     my $level = shift;
 
     return 0 unless $self->level_is_valid($level);
 
     foreach ( values %{ $self->{outputs} } ) {
         return 1 if $_->_should_log($level);
     }
 
     return 0;
 }
 
 sub is_debug     { $_[0]->would_log('debug') }
 sub is_info      { $_[0]->would_log('info') }
 sub is_notice    { $_[0]->would_log('notice') }
 sub is_warning   { $_[0]->would_log('warning') }
 sub is_warn      { $_[0]->would_log('warn') }
 sub is_error     { $_[0]->would_log('error') }
 sub is_err       { $_[0]->would_log('err') }
 sub is_critical  { $_[0]->would_log('critical') }
 sub is_crit      { $_[0]->would_log('crit') }
 sub is_alert     { $_[0]->would_log('alert') }
 sub is_emerg     { $_[0]->would_log('emerg') }
 sub is_emergency { $_[0]->would_log('emergency') }
 
 1;
 
 # ABSTRACT: Dispatches messages to one or more outputs
 
 __END__
 
 =pod
 
 =head1 NAME
 
 Log::Dispatch - Dispatches messages to one or more outputs
 
 =head1 VERSION
 
 version 2.51
 
 =head1 SYNOPSIS
 
   use Log::Dispatch;
 
   # Simple API
   #
   my $log = Log::Dispatch->new(
       outputs => [
           [ 'File',   min_level => 'debug', filename => 'logfile' ],
           [ 'Screen', min_level => 'warning' ],
       ],
   );
 
   $log->info('Blah, blah');
 
   # More verbose API
   #
   my $log = Log::Dispatch->new();
   $log->add(
       Log::Dispatch::File->new(
           name      => 'file1',
           min_level => 'debug',
           filename  => 'logfile'
       )
   );
   $log->add(
       Log::Dispatch::Screen->new(
           name      => 'screen',
           min_level => 'warning',
       )
   );
 
   $log->log( level => 'info', message => 'Blah, blah' );
 
   my $sub = sub { my %p = @_; return reverse $p{message}; };
   my $reversing_dispatcher = Log::Dispatch->new( callbacks => $sub );
 
 =head1 DESCRIPTION
 
 This module manages a set of Log::Dispatch::* output objects that can be
 logged to via a unified interface.
 
 The idea is that you create a Log::Dispatch object and then add various
 logging objects to it (such as a file logger or screen logger). Then you
 call the C<log> method of the dispatch object, which passes the message to
 each of the objects, which in turn decide whether or not to accept the
 message and what to do with it.
 
 This makes it possible to call single method and send a message to a
 log file, via email, to the screen, and anywhere else, all with very
 little code needed on your part, once the dispatching object has been
 created.
 
 =encoding UTF-8
 
 =head1 METHODS
 
 This class provides the following methods:
 
 =head2 Log::Dispatch->new(...)
 
 This method takes the following parameters:
 
 =over 4
 
 =item * outputs( [ [ class, params, ... ], [ class, params, ... ], ... ] )
 
 This parameter is a reference to a list of lists. Each inner list consists of
 a class name and a set of constructor params. The class is automatically
 prefixed with 'Log::Dispatch::' unless it begins with '+', in which case the
 string following '+' is taken to be a full classname. e.g.
 
     outputs => [ [ 'File',          min_level => 'debug', filename => 'logfile' ],
                  [ '+My::Dispatch', min_level => 'info' ] ]
 
 For each inner list, a new output object is created and added to the
 dispatcher (via the C<add()> method).
 
 See L<OUTPUT CLASSES> for the parameters that can be used when creating an
 output object.
 
 =item * callbacks( \& or [ \&, \&, ... ] )
 
 This parameter may be a single subroutine reference or an array
 reference of subroutine references. These callbacks will be called in
 the order they are given and passed a hash containing the following keys:
 
  ( message => $log_message, level => $log_level )
 
 In addition, any key/value pairs passed to a logging method will be
 passed onto your callback.
 
 The callbacks are expected to modify the message and then return a
 single scalar containing that modified message. These callbacks will
 be called when either the C<log> or C<log_to> methods are called and
 will only be applied to a given message once. If they do not return
 the message then you will get no output. Make sure to return the
 message!
 
 =back
 
 =head2 $dispatch->clone()
 
 This returns a I<shallow> clone of the original object. The underlying output
 objects and callbacks are shared between the two objects. However any changes
 made to the outputs or callbacks that the object contains are not shared.
 
 =head2 $dispatch->log( level => $, message => $ or \& )
 
 Sends the message (at the appropriate level) to all the
 output objects that the dispatcher contains (by calling the
 C<log_to> method repeatedly).
 
 This method also accepts a subroutine reference as the message
 argument. This reference will be called only if there is an output
 that will accept a message of the specified level.
 
 =head2 $dispatch->debug (message), info (message), ...
 
 You may call any valid log level (including valid abbreviations) as a method
 with a single argument that is the message to be logged. This is converted
 into a call to the C<log> method with the appropriate level.
 
 For example:
 
  $log->alert('Strange data in incoming request');
 
 translates to:
 
  $log->log( level => 'alert', message => 'Strange data in incoming request' );
 
 If you pass an array to these methods, it will be stringified as is:
 
  my @array = ('Something', 'bad', 'is', 'here');
  $log->alert(@array);
 
  # is equivalent to
 
  $log->alert("@array");
 
 You can also pass a subroutine reference, just like passing one to the
 C<log()> method.
 
 =head2 $dispatch->log_and_die( level => $, message => $ or \& )
 
 Has the same behavior as calling C<log()> but calls
 C<_die_with_message()> at the end.
 
 =head2 $dispatch->log_and_croak( level => $, message => $ or \& )
 
 This method adjusts the C<$Carp::CarpLevel> scalar so that the croak
 comes from the context in which it is called.
 
 You can throw exception objects by subclassing this method.
 
 If the C<carp_level> parameter is present its value will be added to
 the current value of C<$Carp::CarpLevel>.
 
 =head2 $dispatch->log_to( name => $, level => $, message => $ )
 
 Sends the message only to the named object. Note: this will not properly
 handle a subroutine reference as the message.
 
 =head2 $dispatch->add_callback( $code )
 
 Adds a callback (like those given during construction). It is added to the end
 of the list of callbacks. Note that this can also be called on individual
 output objects.
 
 =head2 $dispatch->callbacks()
 
 Returns a list of the callbacks in a given output.
 
 =head2 $dispatch->level_is_valid( $string )
 
 Returns true or false to indicate whether or not the given string is a
 valid log level. Can be called as either a class or object method.
 
 =head2 $dispatch->would_log( $string )
 
 Given a log level, returns true or false to indicate whether or not
 anything would be logged for that log level.
 
 =head2 $dispatch->is_C<$level>
 
 There are methods for every log level: C<is_debug()>, C<is_warning()>, etc.
 
 This returns true if the logger will log a message at the given level.
 
 =head2 $dispatch->add( Log::Dispatch::* OBJECT )
 
 Adds a new L<output object|OUTPUT CLASSES> to the dispatcher. If an object
 of the same name already exists, then that object is replaced, with
 a warning if C<$^W> is true.
 
 =head2 $dispatch->remove($)
 
 Removes the object that matches the name given to the remove method.
 The return value is the object being removed or undef if no object
 matched this.
 
 =head2 $dispatch->outputs()
 
 Returns a list of output objects.
 
 =head2 $dispatch->output( $name )
 
 Returns the output object of the given name. Returns undef or an empty
 list, depending on context, if the given output does not exist.
 
 =head2 $dispatch->_die_with_message( message => $, carp_level => $ )
 
 This method is used by C<log_and_die> and will either die() or croak()
 depending on the value of C<message>: if it's a reference or it ends
 with a new line then a plain die will be used, otherwise it will
 croak.
 
 =head1 OUTPUT CLASSES
 
 An output class - e.g. L<Log::Dispatch::File> or
 L<Log::Dispatch::Screen> - implements a particular way
 of dispatching logs. Many output classes come with this distribution,
 and others are available separately on CPAN.
 
 The following common parameters can be used when creating an output class.
 All are optional. Most output classes will have additional parameters beyond
 these, see their documentation for details.
 
 =over 4
 
 =item * name ($)
 
 A name for the object (not the filename!). This is useful if you want to
 refer to the object later, e.g. to log specifically to it or remove it.
 
 By default a unique name will be generated. You should not depend on the
 form of generated names, as they may change.
 
 =item * min_level ($)
 
 The minimum L<logging level|LOG LEVELS> this object will accept. Required.
 
 =item * max_level ($)
 
 The maximum L<logging level|LOG LEVELS> this object will accept. By default
 the maximum is the highest possible level (which means functionally that the
 object has no maximum).
 
 =item * callbacks( \& or [ \&, \&, ... ] )
 
 This parameter may be a single subroutine reference or an array
 reference of subroutine references. These callbacks will be called in
 the order they are given and passed a hash containing the following keys:
 
  ( message => $log_message, level => $log_level )
 
 The callbacks are expected to modify the message and then return a
 single scalar containing that modified message. These callbacks will
 be called when either the C<log> or C<log_to> methods are called and
 will only be applied to a given message once. If they do not return
 the message then you will get no output. Make sure to return the
 message!
 
 =item * newline (0|1)
 
 If true, a callback will be added to the end of the callbacks list that adds
 a newline to the end of each message. Default is false, but some
 output classes may decide to make the default true.
 
 =back
 
 =head1 LOG LEVELS
 
 The log levels that Log::Dispatch uses are taken directly from the
 syslog man pages (except that I expanded them to full words). Valid
 levels are:
 
 =over 4
 
 =item debug
 
 =item info
 
 =item notice
 
 =item warning
 
 =item error
 
 =item critical
 
 =item alert
 
 =item emergency
 
 =back
 
 Alternately, the numbers 0 through 7 may be used (debug is 0 and emergency is
 7). The syslog standard of 'err', 'crit', and 'emerg' is also acceptable. We
 also allow 'warn' as a synonym for 'warning'.
 
 =head1 SUBCLASSING
 
 This module was designed to be easy to subclass. If you want to handle
 messaging in a way not implemented in this package, you should be able to add
 this with minimal effort. It is generally as simple as subclassing
 Log::Dispatch::Output and overriding the C<new> and C<log_message>
 methods. See the L<Log::Dispatch::Output> docs for more details.
 
 If you would like to create your own subclass for sending email then
 it is even simpler. Simply subclass L<Log::Dispatch::Email> and
 override the C<send_email> method. See the L<Log::Dispatch::Email>
 docs for more details.
 
 The logging levels that Log::Dispatch uses are borrowed from the standard
 UNIX syslog levels, except that where syslog uses partial words ("err")
 Log::Dispatch also allows the use of the full word as well ("error").
 
 =head1 RELATED MODULES
 
 =head2 Log::Dispatch::DBI
 
 Written by Tatsuhiko Miyagawa. Log output to a database table.
 
 =head2 Log::Dispatch::FileRotate
 
 Written by Mark Pfeiffer. Rotates log files periodically as part of
 its usage.
 
 =head2 Log::Dispatch::File::Stamped
 
 Written by Eric Cholet. Stamps log files with date and time
 information.
 
 =head2 Log::Dispatch::Jabber
 
 Written by Aaron Straup Cope. Logs messages via Jabber.
 
 =head2 Log::Dispatch::Tk
 
 Written by Dominique Dumont. Logs messages to a Tk window.
 
 =head2 Log::Dispatch::Win32EventLog
 
 Written by Arthur Bergman. Logs messages to the Windows event log.
 
 =head2 Log::Log4perl
 
 An implementation of Java's log4j API in Perl. Log messages can be limited by
 fine-grained controls, and if they end up being logged, both native Log4perl
 and Log::Dispatch appenders can be used to perform the actual logging
 job. Created by Mike Schilli and Kevin Goess.
 
 =head2 Log::Dispatch::Config
 
 Written by Tatsuhiko Miyagawa. Allows configuration of logging via a
 text file similar (or so I'm told) to how it is done with log4j.
 Simpler than Log::Log4perl.
 
 =head2 Log::Agent
 
 A very different API for doing many of the same things that
 Log::Dispatch does. Originally written by Raphael Manfredi.
 
 =head1 SUPPORT
 
 Please submit bugs and patches to the CPAN RT system at
 http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Log%3A%3ADispatch
 or via email at bug-log-dispatch@rt.cpan.org.
 
 Support questions can be sent to me at my email address, shown below.
 
 =head1 DONATIONS
 
 If you'd like to thank me for the work I've done on this module,
 please consider making a "donation" to me via PayPal. I spend a lot of
 free time creating free software, and would appreciate any support
 you'd care to offer.
 
 Please note that B<I am not suggesting that you must do this> in order
 for me to continue working on this particular software. I will
 continue to do so, inasmuch as I have in the past, for as long as it
 interests me.
 
 Similarly, a donation made in this way will probably not make me work
 on this software much more, unless I get so many donations that I can
 consider working on free software full time, which seems unlikely at
 best.
 
 To donate, log into PayPal and send money to autarch@urth.org or use
 the button on this page:
 L<http://www.urth.org/~autarch/fs-donation.html>
 
 =head1 SEE ALSO
 
 L<Log::Dispatch::ApacheLog>, L<Log::Dispatch::Email>,
 L<Log::Dispatch::Email::MailSend>, L<Log::Dispatch::Email::MailSender>,
 L<Log::Dispatch::Email::MailSendmail>, L<Log::Dispatch::Email::MIMELite>,
 L<Log::Dispatch::File>, L<Log::Dispatch::File::Locked>,
 L<Log::Dispatch::Handle>, L<Log::Dispatch::Output>, L<Log::Dispatch::Screen>,
 L<Log::Dispatch::Syslog>
 
 =head1 AUTHOR
 
 Dave Rolsky <autarch@urth.org>
 
 =head1 CONTRIBUTORS
 
 =for stopwords Karen Etheridge Olaf Alders Olivier Mengué Rohan Carly Ross Attrill swartz@jonathan-swartzs-macbook-4.local swartz@pobox.com Whitney Jackson
 
 =over 4
 
 =item *
 
 Karen Etheridge <ether@cpan.org>
 
 =item *
 
 Olaf Alders <olaf@wundersolutions.com>
 
 =item *
 
 Olivier Mengué <dolmen@cpan.org>
 
 =item *
 
 Rohan Carly <se456@rohan.id.au>
 
 =item *
 
 Ross Attrill <ross.attrill@gmail.com>
 
 =item *
 
 swartz@jonathan-swartzs-macbook-4.local <swartz@jonathan-swartzs-macbook-4.local>
 
 =item *
 
 swartz@pobox.com <swartz@pobox.com>
 
 =item *
 
 Whitney Jackson <whitney.jackson@baml.com>
 
 =back
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is Copyright (c) 2015 by Dave Rolsky.
 
 This is free software, licensed under:
 
   The Artistic License 2.0 (GPL Compatible)
 
 =cut
### Log/Dispatch/ApacheLog.pm ###
 package Log::Dispatch::ApacheLog;
 
 use strict;
 use warnings;
 
 our $VERSION = '2.51';
 
 use Log::Dispatch::Output;
 
 use base qw( Log::Dispatch::Output );
 
 use Params::Validate qw(validate);
 Params::Validate::validation_options( allow_extra => 1 );
 
 BEGIN {
     if ( $ENV{MOD_PERL} && $ENV{MOD_PERL} =~ /2\./ ) {
         require Apache2::Log;
     }
     else {
         require Apache::Log;
     }
 }
 
 sub new {
     my $proto = shift;
     my $class = ref $proto || $proto;
 
     my %p = validate( @_, { apache => { can => 'log' } } );
 
     my $self = bless {}, $class;
 
     $self->_basic_init(%p);
     $self->{apache_log} = $p{apache}->log;
 
     return $self;
 }
 
 {
     my %methods = (
         emergency => 'emerg',
         critical  => 'crit',
         warning   => 'warn',
     );
 
     sub log_message {
         my $self = shift;
         my %p    = @_;
 
         my $level = $self->_level_as_name( $p{level} );
 
         my $method = $methods{$level} || $level;
 
         $self->{apache_log}->$method( $p{message} );
     }
 }
 
 1;
 
 # ABSTRACT: Object for logging to Apache::Log objects
 
 __END__
 
 =pod
 
 =head1 NAME
 
 Log::Dispatch::ApacheLog - Object for logging to Apache::Log objects
 
 =head1 VERSION
 
 version 2.51
 
 =head1 SYNOPSIS
 
   use Log::Dispatch;
 
   my $log = Log::Dispatch->new(
       outputs => [
           [ 'ApacheLog', apache => $r ],
       ],
   );
 
   $log->emerg('Kaboom');
 
 =head1 DESCRIPTION
 
 This module allows you to pass messages to Apache's log object,
 represented by the L<Apache::Log> class.
 
 =head1 CONSTRUCTOR
 
 The constructor takes the following parameters in addition to the standard
 parameters documented in L<Log::Dispatch::Output>:
 
 =over 4
 
 =item * apache ($)
 
 An object of either the L<Apache> or L<Apache::Server> classes. Required.
 
 =back
 
 =head1 AUTHOR
 
 Dave Rolsky <autarch@urth.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is Copyright (c) 2015 by Dave Rolsky.
 
 This is free software, licensed under:
 
   The Artistic License 2.0 (GPL Compatible)
 
 =cut
### Log/Dispatch/ArrayWithLimits.pm ###
 package Log::Dispatch::ArrayWithLimits;
 
 use 5.010001;
 use warnings;
 use strict;
 
 use parent qw(Log::Dispatch::Output);
 
 our $DATE = '2015-01-03'; # DATE
 our $VERSION = '0.04'; # VERSION
 
 sub new {
     my ($class, %args) = @_;
     my $self = {};
     $self->{array} = $args{array} // [];
     if (!ref($self->{array})) {
         no strict 'refs';
         say "$self->{array}";
         $self->{array} = \@{"$self->{array}"};
     }
     $self->{max_elems} = $args{max_elems} // undef;
     bless $self, $class;
     $self->_basic_init(%args);
     $self;
 }
 
 sub log_message {
     my $self = shift;
     my %args = @_;
 
     push @{$self->{array}}, $args{message};
 
     if (defined($self->{max_elems}) && @{$self->{array}} > $self->{max_elems}) {
         # splice() is not supported for threads::shared-array, so we use
         # repeated shift
         while (@{$self->{array}} > $self->{max_elems}) {
             shift @{$self->{array}};
         }
     }
 }
 
 1;
 # ABSTRACT: Log to array, with some limits applied
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Log::Dispatch::ArrayWithLimits - Log to array, with some limits applied
 
 =head1 VERSION
 
 This document describes version 0.04 of Log::Dispatch::ArrayWithLimits (from Perl distribution Log-Dispatch-ArrayWithLimits), released on 2015-01-03.
 
 =head1 SYNOPSIS
 
  use Log::Dispatch::ArrayWithLimits;
 
  my $file = Log::Dispatch::ArrayWithLimits(
      min_level     => 'info',
      array         => $ary,    # default: [], you can always refer by name e.g. 'My::array' to refer to @My::array
      max_elems     => 100,     # defaults unlimited
  );
 
  $file->log(level => 'info', message => "Your comment\n");
 
 =head1 DESCRIPTION
 
 This module functions similarly to L<Log::Dispatch::Array>, with a few
 differences:
 
 =over
 
 =item * only the messages (strings) are stored
 
 =item * allow specifying array variable name (e.g. "My::array" instead of \@My:array)
 
 This makes it possible to use in L<Log::Log4perl> configuration, which is a text
 file.
 
 =item * can apply some limits
 
 Currently only max_elems (the maximum number of elements in the array) is
 available. Future limits will be added.
 
 =back
 
 Logging to an in-process array can be useful when debugging/testing, or when you
 want to let users of your program connect to your program to request viewing the
 ogs being produced.
 
 =head1 METHODS
 
 =head2 new(%args)
 
 Constructor. This method takes a hash of parameters. The following options are
 valid: C<min_level> and C<max_level> (see L<Log::Dispatch> documentation);
 C<array> (a reference to an array, or if value is string, will be taken as name
 of array variable; this is so this module can be used/configured e.g. by
 L<Log::Log4perl> because configuration is specified via a text file),
 C<max_elems>.
 
 =head2 log_message(message => STR)
 
 Send a message to the appropriate output. Generally this shouldn't be called
 directly but should be called through the C<log()> method (in
 LLog::Dispatch::Output>).
 
 =head1 SEE ALSO
 
 L<Log::Dispatch>
 
 L<Log::Dispatch::Array>
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Log-Dispatch-ArrayWithLimits>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Log-Dispatch-ArrayWithLimits>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Log-Dispatch-ArrayWithLimits>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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
### Log/Dispatch/Base.pm ###
 package Log::Dispatch::Base;
 
 use strict;
 use warnings;
 
 our $VERSION = '2.51';
 
 sub _get_callbacks {
     shift;
     my %p = @_;
 
     return unless exists $p{callbacks};
 
     return @{ $p{callbacks} }
         if ref $p{callbacks} eq 'ARRAY';
 
     return $p{callbacks}
         if ref $p{callbacks} eq 'CODE';
 
     return;
 }
 
 sub _apply_callbacks {
     my $self = shift;
     my %p    = @_;
 
     my $msg = delete $p{message};
     foreach my $cb ( @{ $self->{callbacks} } ) {
         $msg = $cb->( message => $msg, %p );
     }
 
     return $msg;
 }
 
 sub add_callback {
     my $self  = shift;
     my $value = shift;
 
     Carp::carp("given value $value is not a valid callback")
         unless ref $value eq 'CODE';
 
     $self->{callbacks} ||= [];
     push @{ $self->{callbacks} }, $value;
 
     return;
 }
 
 1;
 
 # ABSTRACT: Code shared by dispatch and output objects.
 
 __END__
 
 =pod
 
 =head1 NAME
 
 Log::Dispatch::Base - Code shared by dispatch and output objects.
 
 =head1 VERSION
 
 version 2.51
 
 =head1 SYNOPSIS
 
   use Log::Dispatch::Base;
 
   ...
 
   @ISA = qw(Log::Dispatch::Base);
 
 =head1 DESCRIPTION
 
 Unless you are me, you probably don't need to know what this class
 does.
 
 =for Pod::Coverage add_callback
 
 =head1 AUTHOR
 
 Dave Rolsky <autarch@urth.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is Copyright (c) 2015 by Dave Rolsky.
 
 This is free software, licensed under:
 
   The Artistic License 2.0 (GPL Compatible)
 
 =cut
### Log/Dispatch/Code.pm ###
 package Log::Dispatch::Code;
 
 use strict;
 use warnings;
 
 our $VERSION = '2.51';
 
 use Log::Dispatch::Output;
 
 use base qw( Log::Dispatch::Output );
 
 use Params::Validate qw(validate CODEREF);
 Params::Validate::validation_options( allow_extra => 1 );
 
 sub new {
     my $proto = shift;
     my $class = ref $proto || $proto;
 
     my %p = validate( @_, { code => CODEREF } );
 
     my $self = bless {}, $class;
 
     $self->_basic_init(%p);
     $self->{code} = $p{code};
 
     return $self;
 }
 
 sub log_message {
     my $self = shift;
     my %p    = @_;
 
     delete $p{name};
 
     $self->{code}->(%p);
 }
 
 1;
 
 # ABSTRACT: Object for logging to a subroutine reference
 
 __END__
 
 =pod
 
 =head1 NAME
 
 Log::Dispatch::Code - Object for logging to a subroutine reference
 
 =head1 VERSION
 
 version 2.51
 
 =head1 SYNOPSIS
 
   use Log::Dispatch;
 
   my $log = Log::Dispatch->new(
       outputs => [
           [
               'Code',
               min_level => 'emerg',
               code      => \&_log_it,
           ],
       ]
   );
 
   sub _log_it {
       my %p = @_;
 
       warn $p{message};
   }
 
 =head1 DESCRIPTION
 
 This module supplies a simple object for logging to a subroutine reference.
 
 =for Pod::Coverage new log_message
 
 =head1 CONSTRUCTOR
 
 The constructor takes the following parameters in addition to the standard
 parameters documented in L<Log::Dispatch::Output>:
 
 =over 4
 
 =item * code ($)
 
 The subroutine reference.
 
 =back
 
 =head1 HOW IT WORKS
 
 The subroutine you provide will be called with a hash of named arguments. The
 two arguments are:
 
 =over 4
 
 =item * level
 
 The log level of the message. This will be a string like "info" or "error".
 
 =item * message
 
 The message being logged.
 
 =back
 
 =head1 AUTHOR
 
 Dave Rolsky <autarch@urth.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is Copyright (c) 2015 by Dave Rolsky.
 
 This is free software, licensed under:
 
   The Artistic License 2.0 (GPL Compatible)
 
 =cut
### Log/Dispatch/Dir.pm ###
 package Log::Dispatch::Dir;
 
 our $DATE = '2015-10-20'; # DATE
 our $VERSION = '0.13'; # VERSION
 
 use 5.010001;
 use warnings;
 use strict;
 use Log::Dispatch::Output;
 use base qw(Log::Dispatch::Output);
 
 use File::Slurp::Tiny qw(write_file);
 #use File::Stat qw(:stat); # doesn't work in all platforms?
 use Params::Validate qw(validate SCALAR CODEREF);
 use POSIX;
 
 Params::Validate::validation_options( allow_extra => 1 );
 
 sub new {
     my $proto = shift;
     my $class = ref $proto || $proto;
 
     my %p = @_;
 
     my $self = bless {}, $class;
 
     $self->_basic_init(%p);
     $self->_make_handle(%p);
 
     return $self;
 }
 
 sub _make_handle {
     my $self = shift;
 
     my %p = validate(
         @_,
         {
             dirname             => { type => SCALAR },
             permissions         => { type => SCALAR , optional => 1 },
             filename_pattern    => { type => SCALAR , optional => 1 },
             filename_sub        => { type => CODEREF, optional => 1 },
             max_size            => { type => SCALAR , optional => 1 },
             max_files           => { type => SCALAR , optional => 1 },
             max_age             => { type => SCALAR , optional => 1 },
             rotate_probability  => { type => SCALAR , optional => 1 },
         });
 
     $self->{dirname}            = $p{dirname};
     $self->{permissions}        = $p{permissions};
     $self->{filename_pattern}   = $p{filename_pattern} ||
         '%Y-%m-%d-%H%M%S.pid-%{pid}.%{ext}';
     $self->{filename_sub}       = $p{filename_sub};
     $self->{max_size}           = $p{max_size};
     $self->{max_files}          = $p{max_files};
     $self->{max_age}            = $p{max_age};
     $self->{rotate_probability} = ($p{rotate_probability}) || 0.25;
     $self->_open_dir();
 }
 
 sub _open_dir {
     my $self = shift;
 
     unless (-e $self->{dirname}) {
         my $perm = $self->{permissions} // 0755;
         mkdir($self->{dirname}, $perm)
             or die "Cannot create directory `$self->{dirname}: $!";
         $self->{chmodded} = 1;
     }
 
     unless (-d $self->{dirname}) {
         die "$self->{dirname} is not a directory";
     }
 
     if ($self->{permissions} && ! $self->{chmodded}) {
         chmod $self->{permissions}, $self->{dirname}
             or die "Cannot chmod $self->{dirname} to $self->{permissions}: $!";
         $self->{chmodded} = 1;
     }
 }
 
 my $default_ext = "log";
 my $libmagic;
 
 sub _resolve_pattern {
     my ($self, $p) = @_;
     my $pat = $self->{filename_pattern};
     my $now = time;
 
     my @vars = qw(Y y m d H M S z Z %);
     my $strftime = POSIX::strftime(join("|", map {"%$_"} @vars),
                                    localtime($now));
     my %vars;
     my $i = 0;
     for (split /\|/, $strftime) {
         $vars{ $vars[$i] } = $_;
         $i++;
     }
 
     push @vars, "{pid}";
     $vars{"{pid}"} = $$;
 
     push @vars, "{ext}";
     $vars{"{ext}"} = sub {
         my $p = shift;
         unless (defined $libmagic) {
             if (eval { require File::LibMagic; require Media::Type::Simple }) {
                 $libmagic = File::LibMagic->new;
             } else {
                 print "err = $@\n";
                 $libmagic = 0;
             }
         }
         return $default_ext unless $libmagic;
         my $type = $libmagic->checktype_contents($p->{message} // '');
         return $default_ext unless $type;
         $type =~ s/[; ].*//; # only get the mime type
         my $ext = Media::Type::Simple::ext_from_type($type);
         return $ext || $default_ext;
     };
 
     my $res = $pat;
     $res =~ s[%(\{\w+\}|\S)]
              [defined($vars{$1}) ?
                   ( ref($vars{$1}) eq 'CODE' ?
                         $vars{$1}->($p) : $vars{$1} ) :
                             die("Invalid filename_pattern `%$1'")]eg;
     $res;
 }
 
 sub log_message {
     my $self = shift;
     my %p = @_;
 
     my $filename0 = defined($self->{filename_sub}) ?
         $self->{filename_sub}->(%p) :
         $self->_resolve_pattern(\%p);
 
     my $filename = $filename0;
     my $i = 0;
     while (-e "$self->{dirname}/$filename") {
         $i++;
         $filename = "$filename0.$i";
     }
 
     write_file("$self->{dirname}/$filename", $p{message});
     $self->_rotate(\%p) if (rand() < $self->{rotate_probability});
 }
 
 sub _rotate {
     my ($self, $p) = @_;
 
     my $ms = $self->{max_size};
     my $mf = $self->{max_files};
     my $ma = $self->{max_age};
 
     return unless (defined($ms) || defined($mf) || defined($ma));
 
     my @entries;
     my $d = $self->{dirname};
     my $now = time;
     local *DH;
     opendir DH, $self->{dirname};
     while (my $e = readdir DH) {
         ($e) = $e =~ /(.*)/s; # untaint
         next if $e eq '.' || $e eq '..';
         my @st = stat "$d/$e";
         push @entries, {name => $e, age => ($now-$st[10]), size => $st[7]};
     }
     closedir DH;
 
     @entries = sort {$a->{age} <=> $b->{age}} @entries;
 
     # max files
     if (defined($mf) && @entries > $mf) {
         unlink "$d/$_->{name}" for (splice @entries, $mf);
     }
 
     # max age
     if (defined($ma)) {
         my $i = 0;
         for (@entries) {
             if ($_->{age} > $ma) {
                 unlink "$d/$_->{name}" for (splice @entries, $i);
                 last;
             }
             $i++;
         }
     }
 
     # max size
     if (defined($ms)) {
         my $i = 0;
         my $tot_size = 0;
         for (@entries) {
             $tot_size += $_->{size};
             if ($tot_size > $ms) {
                 unlink "$d/$_->{name}" for (splice @entries, $i);
                 last;
             }
             $i++;
         }
     }
 }
 
 1;
 # ABSTRACT: Log messages to separate files in a directory, with rotate options
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Log::Dispatch::Dir - Log messages to separate files in a directory, with rotate options
 
 =head1 VERSION
 
 This document describes version 0.13 of Log::Dispatch::Dir (from Perl distribution Log-Dispatch-Dir), released on 2015-10-20.
 
 =head1 SYNOPSIS
 
     use Log::Dispatch::Dir;
 
     my $dir = Log::Dispatch::Dir->new(
         name => 'dir1',
         min_level => 'info',
         dirname => 'somedir.log',
         filename_pattern => '%Y-%m-%d-%H%M%S.%{ext}',
     );
     $dir->log( level => 'info', message => 'your comment\n" );
 
     # limit total size
     my $dir = Log::Dispatch::Dir->new(
         # ...
         max_size => 10*1024*1024, # 10MB
     );
 
     # limit number of files
     my $dir = Log::Dispatch::Dir->new(
         # ...
         max_files => 1000,
     );
 
     # limit oldest file
     my $dir = Log::Dispatch::Dir->new(
         # ...
         max_age => 10*24*3600, # 10 days
     );
 
 =head1 DESCRIPTION
 
 This module provides a simple object for logging to directories under the
 Log::Dispatch::* system, and automatically rotating them according to different
 constraints. Each message will be logged to a separate file the directory.
 
 Logging to separate files can be useful for example when dumping whole network
 responses (like HTTP::Response content).
 
 =head1 METHODS
 
 =head2 new(%p)
 
 This method takes a hash of parameters. The following options are valid:
 
 =over 4
 
 =item * name ($)
 
 The name of the object (not the dirname!).  Required.
 
 =item * min_level ($)
 
 The minimum logging level this object will accept. See the Log::Dispatch
 documentation on L<Log Levels|Log::Dispatch/"Log Levels"> for more information.
 Required.
 
 =item * max_level ($)
 
 The maximum logging level this obejct will accept. See the Log::Dispatch
 documentation on L<Log Levels|Log::Dispatch/"Log Levels"> for more information.
 This is not required. By default the maximum is the highest possible level
 (which means functionally that the object has no maximum).
 
 =item * dirname ($)
 
 The directory to write to.
 
 =item * permissions ($)
 
 If the directory does not already exist, the permissions that it should be
 created with. Optional. The argument passed must be a valid octal value, such as
 0700 or the constants available from Fcntl, like S_IRUSR|S_IWUSR|S_IXUSR.
 
 See L<perlfunc/chmod> for more on potential traps when passing octal values
 around. Most importantly, remember that if you pass a string that looks like an
 octal value, like this:
 
  my $mode = '0644';
 
 Then the resulting directory will end up with permissions like this:
 
  --w----r-T
 
 which is probably not what you want.
 
 =item * callbacks( \& or [ \&, \&, ... ] )
 
 This parameter may be a single subroutine reference or an array reference of
 subroutine references. These callbacks will be called in the order they are
 given and passed a hash containing the following keys:
 
  ( message => $log_message, level => $log_level )
 
 The callbacks are expected to modify the message and then return a single scalar
 containing that modified message. These callbacks will be called when either the
 C<log> or C<log_to> methods are called and will only be applied to a given
 message once.
 
 =item * filename_pattern ($)
 
 Names to give to each file, expressed in pattern a la strftime()'s. Optional.
 Default is '%Y-%m-%d-%H%M%S.pid-%{pid}.%{ext}'. Time is expressed in local time.
 
 If file of the same name already exists, a suffix ".1", ".2", and so on will be
 appended.
 
 Available pattern:
 
 =over 8
 
 =item %Y - 4-digit year number, e.g. 2009
 
 =item %y - 2-digit year number, e.g. 09 for year 2009
 
 =item %m - 2-digit month, e.g. 04 for April
 
 =item %d - 2-digit day of month, e.g. 28
 
 =item %H - 2-digit hour, e.g. 01
 
 =item %M - 2-digit minute, e.g. 57
 
 =item %S - 2-digit second, e.g. 59
 
 =item %z - the time zone as hour offset from GMT
 
 =item %Z - the time zone or name or abbreviation
 
 =item %{pid} - Process ID
 
 =item %{ext} - Guessed file extension
 
 Try to detect appropriate file extension using L<File::LibMagic>. For example,
 if log message looks like an HTML document, then 'html'. If File::LibMagic is
 not available or type cannot be detected, defaults to 'log'.
 
 =item %% - literal '%' character
 
 =back
 
 =item * filename_sub (\&)
 
 A more generic mechanism for B<filename_pattern>. If B<filename_sub> is given,
 B<filename_pattern> will be ignored. The code will be called with the same
 arguments as log_message() and is expected to return a filename. Will die if
 code returns undef.
 
 =item * max_size ($)
 
 Maximum total size of files, in bytes. After the size is surpassed, oldest files
 (based on ctime) will be deleted. Optional. Default is undefined, which means
 unlimited.
 
 =item * max_files ($)
 
 Maximum number of files. After this number is surpassed, oldest files
 (based on ctime) will be deleted. Optional. Default is undefined, which means
 unlimited.
 
 =item * max_age ($)
 
 Maximum age of files (based on ctime), in seconds. After the age is surpassed,
 files older than this age will be deleted. Optional. Default is undefined, which
 means unlimited.
 
 =item * rotate_probability ($)
 
 A number between 0 and 1 which specifies the probability that rotate()
 will be called after each log_message(). This is a balance between performance
 and rotate size accuracy. 1 means always rotate, 0 means never rotate. Optional.
 Default is 0.25.
 
 =back
 
 =head2 log_message(message => $)
 
 Sends a message to the appropriate output. Generally this shouldn't be called
 directly but should be called through the C<log()> method (in
 Log::Dispatch::Output).
 
 =head1 SEE ALSO
 
 L<Log::Dispatch>
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Log-Dispatch-Dir>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Log-Dispatch-Dir>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Log-Dispatch-Dir>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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
### Log/Dispatch/Email.pm ###
 package Log::Dispatch::Email;
 
 use strict;
 use warnings;
 
 our $VERSION = '2.51';
 
 use Log::Dispatch::Output;
 
 use base qw( Log::Dispatch::Output );
 
 use Devel::GlobalDestruction qw( in_global_destruction );
 use Params::Validate qw(validate SCALAR ARRAYREF BOOLEAN);
 Params::Validate::validation_options( allow_extra => 1 );
 
 # need to untaint this value
 my ($program) = $0 =~ /(.+)/;
 
 sub new {
     my $proto = shift;
     my $class = ref $proto || $proto;
 
     my %p = validate(
         @_, {
             subject => {
                 type    => SCALAR,
                 default => "$program: log email"
             },
             to => { type => SCALAR | ARRAYREF },
             from => {
                 type     => SCALAR,
                 optional => 1
             },
             buffered => {
                 type    => BOOLEAN,
                 default => 1
             },
         }
     );
 
     my $self = bless {}, $class;
 
     $self->_basic_init(%p);
 
     $self->{subject} = $p{subject} || "$0: log email";
     $self->{to} = ref $p{to} ? $p{to} : [ $p{to} ];
     $self->{from} = $p{from};
 
     # Default to buffered for obvious reasons!
     $self->{buffered} = $p{buffered};
 
     $self->{buffer} = [] if $self->{buffered};
 
     return $self;
 }
 
 sub log_message {
     my $self = shift;
     my %p    = @_;
 
     if ( $self->{buffered} ) {
         push @{ $self->{buffer} }, $p{message};
     }
     else {
         $self->send_email(@_);
     }
 }
 
 sub send_email {
     my $self  = shift;
     my $class = ref $self;
 
     die "The send_email method must be overridden in the $class subclass";
 }
 
 sub flush {
     my $self = shift;
 
     if ( $self->{buffered} && @{ $self->{buffer} } ) {
         my $message = join '', @{ $self->{buffer} };
 
         $self->send_email( message => $message );
         $self->{buffer} = [];
     }
 }
 
 sub DESTROY {
     my $self = shift;
 
     if (   in_global_destruction()
         && $self->{buffered}
         && @{ $self->{buffer} } ) {
 
         my $name  = $self->name();
         my $class = ref $self;
         my $message
             = "Log messages for the $name output (a $class object) remain unsent but the program is terminating.\n";
         $message .= "The messages are:\n";
         $message .= "  $_\n" for @{ $self->{buffer} };
     }
     else {
         $self->flush();
     }
 }
 
 1;
 
 # ABSTRACT: Base class for objects that send log messages via email
 
 __END__
 
 =pod
 
 =head1 NAME
 
 Log::Dispatch::Email - Base class for objects that send log messages via email
 
 =head1 VERSION
 
 version 2.51
 
 =head1 SYNOPSIS
 
   package Log::Dispatch::Email::MySender;
 
   use Log::Dispatch::Email;
   use base qw( Log::Dispatch::Email );
 
   sub send_email {
       my $self = shift;
       my %p    = @_;
 
       # Send email somehow. Message is in $p{message}
   }
 
 =head1 DESCRIPTION
 
 This module should be used as a base class to implement
 Log::Dispatch::* objects that send their log messages via email.
 Implementing a subclass simply requires the code shown in the
 L<SYNOPSIS> with a real implementation of the C<send_email()> method.
 
 =for Pod::Coverage new log_message
 
 =head1 CONSTRUCTOR
 
 The constructor takes the following parameters in addition to the standard
 parameters documented in L<Log::Dispatch::Output>:
 
 =over 4
 
 =item * subject ($)
 
 The subject of the email messages which are sent. Defaults to "$0:
 log email"
 
 =item * to ($ or \@)
 
 Either a string or a list reference of strings containing email
 addresses. Required.
 
 =item * from ($)
 
 A string containing an email address. This is optional and may not
 work with all mail sending methods.
 
 =item * buffered (0 or 1)
 
 This determines whether the object sends one email per message it is
 given or whether it stores them up and sends them all at once. The
 default is to buffer messages.
 
 =back
 
 =head1 METHODS
 
 This class provides the following methods:
 
 =head2 $email->send_email(%p)
 
 This is the method that must be subclassed. For now the only
 parameter in the hash is 'message'.
 
 =head2 $email->flush
 
 If the object is buffered, then this method will call the
 C<send_email()> method to send the contents of the buffer and then
 clear the buffer.
 
 =head2 $email->DESTROY
 
 On destruction, the object will call C<flush()> to send any pending
 email.
 
 =head1 AUTHOR
 
 Dave Rolsky <autarch@urth.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is Copyright (c) 2015 by Dave Rolsky.
 
 This is free software, licensed under:
 
   The Artistic License 2.0 (GPL Compatible)
 
 =cut
### Log/Dispatch/Email/MIMELite.pm ###
 package Log::Dispatch::Email::MIMELite;
 
 use strict;
 use warnings;
 
 our $VERSION = '2.51';
 
 use Log::Dispatch::Email;
 
 use base qw( Log::Dispatch::Email );
 
 use MIME::Lite;
 
 sub send_email {
     my $self = shift;
     my %p    = @_;
 
     my %mail = (
         To => ( join ',', @{ $self->{to} } ),
         Subject => $self->{subject},
         Type    => 'TEXT',
         Data    => $p{message},
     );
 
     $mail{From} = $self->{from} if defined $self->{from};
 
     local $?;
     unless ( MIME::Lite->new(%mail)->send ) {
         warn "Error sending mail with MIME::Lite";
     }
 }
 
 1;
 
 # ABSTRACT: Subclass of Log::Dispatch::Email that uses the MIME::Lite module
 
 __END__
 
 =pod
 
 =head1 NAME
 
 Log::Dispatch::Email::MIMELite - Subclass of Log::Dispatch::Email that uses the MIME::Lite module
 
 =head1 VERSION
 
 version 2.51
 
 =head1 SYNOPSIS
 
   use Log::Dispatch;
 
   my $log = Log::Dispatch->new(
       outputs => [
           [
               'Email::MIMELite',
               min_level => 'emerg',
               to        => [qw( foo@example.com bar@example.org )],
               subject   => 'Big error!'
           ]
       ],
   );
 
   $log->emerg("Something bad is happening");
 
 =head1 DESCRIPTION
 
 This is a subclass of L<Log::Dispatch::Email> that implements the
 send_email method using the L<MIME::Lite> module.
 
 =head1 AUTHOR
 
 Dave Rolsky <autarch@urth.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is Copyright (c) 2015 by Dave Rolsky.
 
 This is free software, licensed under:
 
   The Artistic License 2.0 (GPL Compatible)
 
 =cut
### Log/Dispatch/Email/MailSend.pm ###
 package Log::Dispatch::Email::MailSend;
 
 use strict;
 use warnings;
 
 our $VERSION = '2.51';
 
 use Log::Dispatch::Email;
 
 use base qw( Log::Dispatch::Email );
 
 use Mail::Send;
 
 sub send_email {
     my $self = shift;
     my %p    = @_;
 
     my $msg = Mail::Send->new;
 
     $msg->to( join ',', @{ $self->{to} } );
     $msg->subject( $self->{subject} );
 
     # Does this ever work for this module?
     $msg->set( 'From', $self->{from} ) if $self->{from};
 
     local $?;
     eval {
         my $fh = $msg->open
             or die "Cannot open handle to mail program";
 
         $fh->print( $p{message} )
             or die "Cannot print message to mail program handle";
 
         $fh->close
             or die "Cannot close handle to mail program";
     };
 
     warn $@ if $@;
 }
 
 1;
 
 # ABSTRACT: Subclass of Log::Dispatch::Email that uses the Mail::Send module
 
 __END__
 
 =pod
 
 =head1 NAME
 
 Log::Dispatch::Email::MailSend - Subclass of Log::Dispatch::Email that uses the Mail::Send module
 
 =head1 VERSION
 
 version 2.51
 
 =head1 SYNOPSIS
 
   use Log::Dispatch;
 
   my $log = Log::Dispatch->new(
       outputs => [
           [
               'Email::MailSend',
               min_level => 'emerg',
               to        => [qw( foo@example.com bar@example.org )],
               subject   => 'Big error!'
           ]
       ],
   );
 
   $log->emerg("Something bad is happening");
 
 =head1 DESCRIPTION
 
 This is a subclass of L<Log::Dispatch::Email> that implements the send_email
 method using the L<Mail::Send> module.
 
 =head1 CHANGING HOW MAIL IS SENT
 
 Since L<Mail::Send> is a subclass of L<Mail::Mailer>, you can change
 how mail is sent from this module by simply C<use>ing L<Mail::Mailer>
 in your code before mail is sent. For example, to send mail via smtp,
 you could do:
 
   use Mail::Mailer 'smtp', Server => 'foo.example.com';
 
 For more details, see the L<Mail::Mailer> docs.
 
 =head1 AUTHOR
 
 Dave Rolsky <autarch@urth.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is Copyright (c) 2015 by Dave Rolsky.
 
 This is free software, licensed under:
 
   The Artistic License 2.0 (GPL Compatible)
 
 =cut
### Log/Dispatch/Email/MailSender.pm ###
 package Log::Dispatch::Email::MailSender;
 
 # By: Joseph Annino
 # (c) 2002
 # Licensed under the same terms as Perl
 #
 
 use strict;
 use warnings;
 
 our $VERSION = '2.51';
 
 use Log::Dispatch::Email;
 
 use base qw( Log::Dispatch::Email );
 
 use Mail::Sender ();
 
 sub new {
     my $proto = shift;
     my $class = ref $proto || $proto;
 
     my %p = @_;
 
     my $smtp = delete $p{smtp} || 'localhost';
     my $port = delete $p{port} || '25';
 
     my $authid       = delete $p{authid};
     my $authpwd      = delete $p{authpwd};
     my $auth         = delete $p{auth};
     my $tls_required = delete $p{tls_required};
     my $replyto      = delete $p{replyto};
     my $fake_from    = delete $p{fake_from};
 
     my $self = $class->SUPER::new(%p);
 
     $self->{smtp} = $smtp;
     $self->{port} = $port;
 
     $self->{authid}       = $authid;
     $self->{authpwd}      = $authpwd;
     $self->{auth}         = $auth;
     $self->{tls_required} = $tls_required;
 
     $self->{fake_from} = $fake_from;
     $self->{replyto}   = $replyto;
 
     return $self;
 }
 
 sub send_email {
     my $self = shift;
     my %p    = @_;
 
     local $?;
     eval {
         my $sender = Mail::Sender->new(
             {
                 from => $self->{from} || 'LogDispatch@foo.bar',
                 fake_from    => $self->{fake_from},
                 replyto      => $self->{replyto},
                 to           => ( join ',', @{ $self->{to} } ),
                 subject      => $self->{subject},
                 smtp         => $self->{smtp},
                 port         => $self->{port},
                 authid       => $self->{authid},
                 authpwd      => $self->{authpwd},
                 auth         => $self->{auth},
                 tls_required => $self->{tls_required},
 
                 #debug => \*STDERR,
             }
         );
 
         die "Error sending mail ($sender): $Mail::Sender::Error"
             unless ref $sender;
 
         ref $sender->MailMsg( { msg => $p{message} } )
             or die "Error sending mail: $Mail::Sender::Error";
     };
 
     warn $@ if $@;
 }
 
 1;
 
 # ABSTRACT: Subclass of Log::Dispatch::Email that uses the Mail::Sender module
 
 __END__
 
 =pod
 
 =head1 NAME
 
 Log::Dispatch::Email::MailSender - Subclass of Log::Dispatch::Email that uses the Mail::Sender module
 
 =head1 VERSION
 
 version 2.51
 
 =head1 SYNOPSIS
 
   use Log::Dispatch;
 
   my $log = Log::Dispatch->new(
       outputs => [
           [
               'Email::MailSender',
               min_level => 'emerg',
               to        => [qw( foo@example.com bar@example.org )],
               subject   => 'Big error!'
           ]
       ],
   );
 
   $log->emerg("Something bad is happening");
 
 =head1 DESCRIPTION
 
 This is a subclass of L<Log::Dispatch::Email> that implements the send_email
 method using the L<Mail::Sender> module.
 
 =head1 CONSTRUCTOR
 
 The constructor takes the following parameters in addition to the parameters
 documented in L<Log::Dispatch::Output> and L<Log::Dispatch::Email>:
 
 =over 4
 
 =item * smtp ($)
 
 The smtp server to connect to. This defaults to "localhost".
 
 =item * port ($)
 
 The port to use when connecting. This defaults to 25.
 
 =item * auth ($)
 
 Optional. The SMTP authentication protocol to use to login to the server. At
 the time of writing Mail::Sender only supports LOGIN, PLAIN, CRAM-MD5 and
 NTLM.
 
 Some protocols have module dependencies. CRAM-MD5 depends on Digest::HMAC_MD5
 and NTLM on Authen::NTLM.
 
 =item * authid ($)
 
 Optional. The username used to login to the server.
 
 =item * authpwd ($)
 
 Optional. The password used to login to the server.
 
 =item * tls_required ($)
 
 Optional. If you set this option to a true value, Mail::Sender will fail
 whenever it's unable to use TLS.
 
 =item * fake_from ($)
 
 The From address that will be shown in headers. If not specified we use the
 value of from.
 
 =item * replyto ($)
 
 The reply-to address.
 
 =back
 
 =head1 AUTHOR
 
 Dave Rolsky <autarch@urth.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is Copyright (c) 2015 by Dave Rolsky.
 
 This is free software, licensed under:
 
   The Artistic License 2.0 (GPL Compatible)
 
 =cut
### Log/Dispatch/Email/MailSendmail.pm ###
 package Log::Dispatch::Email::MailSendmail;
 
 use strict;
 use warnings;
 
 our $VERSION = '2.51';
 
 use Log::Dispatch::Email;
 
 use base qw( Log::Dispatch::Email );
 
 use Mail::Sendmail ();
 
 sub send_email {
     my $self = shift;
     my %p    = @_;
 
     my %mail = (
         To => ( join ',', @{ $self->{to} } ),
         Subject => $self->{subject},
         Message => $p{message},
 
         # Mail::Sendmail insists on having this parameter.
         From => $self->{from} || 'LogDispatch@foo.bar',
     );
 
     local $?;
     unless ( Mail::Sendmail::sendmail(%mail) ) {
         warn "Error sending mail: $Mail::Sendmail::error";
     }
 }
 
 1;
 
 # ABSTRACT: Subclass of Log::Dispatch::Email that uses the Mail::Sendmail module
 
 __END__
 
 =pod
 
 =head1 NAME
 
 Log::Dispatch::Email::MailSendmail - Subclass of Log::Dispatch::Email that uses the Mail::Sendmail module
 
 =head1 VERSION
 
 version 2.51
 
 =head1 SYNOPSIS
 
   use Log::Dispatch;
 
   my $log = Log::Dispatch->new(
       outputs => [
           [
               'Email::MailSendmail',
               min_level => 'emerg',
               to        => [qw( foo@example.com bar@example.org )],
               subject   => 'Big error!'
           ]
       ],
   );
 
   $log->emerg("Something bad is happening");
 
 =head1 DESCRIPTION
 
 This is a subclass of L<Log::Dispatch::Email> that implements the
 send_email method using the L<Mail::Sendmail> module.
 
 =head1 AUTHOR
 
 Dave Rolsky <autarch@urth.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is Copyright (c) 2015 by Dave Rolsky.
 
 This is free software, licensed under:
 
   The Artistic License 2.0 (GPL Compatible)
 
 =cut
### Log/Dispatch/File.pm ###
 package Log::Dispatch::File;
 
 use strict;
 use warnings;
 
 our $VERSION = '2.51';
 
 use Log::Dispatch::Output;
 
 use base qw( Log::Dispatch::Output );
 
 use Params::Validate qw(validate SCALAR BOOLEAN);
 Params::Validate::validation_options( allow_extra => 1 );
 
 use Scalar::Util qw( openhandle );
 
 # Prevents death later on if IO::File can't export this constant.
 *O_APPEND = \&APPEND unless defined &O_APPEND;
 
 sub APPEND {0}
 
 sub new {
     my $proto = shift;
     my $class = ref $proto || $proto;
 
     my %p = @_;
 
     my $self = bless {}, $class;
 
     $self->_basic_init(%p);
     $self->_make_handle;
 
     return $self;
 }
 
 sub _basic_init {
     my $self = shift;
 
     $self->SUPER::_basic_init(@_);
 
     my %p = validate(
         @_, {
             filename => { type => SCALAR },
             mode => {
                 type    => SCALAR,
                 default => '>'
             },
             binmode => {
                 type    => SCALAR,
                 default => undef
             },
             autoflush => {
                 type    => BOOLEAN,
                 default => 1
             },
             close_after_write => {
                 type    => BOOLEAN,
                 default => 0
             },
             permissions => {
                 type     => SCALAR,
                 optional => 1
             },
             syswrite => {
                 type    => BOOLEAN,
                 default => 0
             },
         }
     );
 
     $self->{filename}    = $p{filename};
     $self->{binmode}     = $p{binmode};
     $self->{autoflush}   = $p{autoflush};
     $self->{close}       = $p{close_after_write};
     $self->{permissions} = $p{permissions};
     $self->{syswrite}    = $p{syswrite};
 
     if ( $self->{close} ) {
         $self->{mode} = '>>';
     }
     elsif (
            exists $p{mode}
         && defined $p{mode}
         && (
             $p{mode} =~ /^(?:>>|append)$/
             || (   $p{mode} =~ /^\d+$/
                 && $p{mode} == O_APPEND() )
         )
         ) {
         $self->{mode} = '>>';
     }
     else {
         $self->{mode} = '>';
     }
 
 }
 
 sub _make_handle {
     my $self = shift;
 
     $self->_open_file() unless $self->{close};
 }
 
 sub _open_file {
     my $self = shift;
 
     open my $fh, $self->{mode}, $self->{filename}
         or die "Cannot write to '$self->{filename}': $!";
 
     if ( $self->{autoflush} ) {
         my $oldfh = select $fh;
         $| = 1;
         select $oldfh;
     }
 
     if ( $self->{permissions}
         && !$self->{chmodded} ) {
         my $current_mode = ( stat $self->{filename} )[2] & 07777;
         if ( $current_mode ne $self->{permissions} ) {
             chmod $self->{permissions}, $self->{filename}
                 or die
                 "Cannot chmod $self->{filename} to $self->{permissions}: $!";
         }
 
         $self->{chmodded} = 1;
     }
 
     if ( $self->{binmode} ) {
         binmode $fh, $self->{binmode};
     }
 
     $self->{fh} = $fh;
 }
 
 sub log_message {
     my $self = shift;
     my %p    = @_;
 
     if ( $self->{close} ) {
         $self->_open_file;
     }
 
     my $fh = $self->{fh};
 
     if ( $self->{syswrite} ) {
         defined syswrite( $fh, $p{message} )
             or die "Cannot write to '$self->{filename}': $!";
     }
     else {
         print $fh $p{message}
             or die "Cannot write to '$self->{filename}': $!";
     }
 
     if ( $self->{close} ) {
         close $fh
             or die "Cannot close '$self->{filename}': $!";
     }
 }
 
 sub DESTROY {
     my $self = shift;
 
     if ( $self->{fh} ) {
         my $fh = $self->{fh};
         close $fh if openhandle($fh);
     }
 }
 
 1;
 
 # ABSTRACT: Object for logging to files
 
 __END__
 
 =pod
 
 =head1 NAME
 
 Log::Dispatch::File - Object for logging to files
 
 =head1 VERSION
 
 version 2.51
 
 =head1 SYNOPSIS
 
   use Log::Dispatch;
 
   my $log = Log::Dispatch->new(
       outputs => [
           [
               'File',
               min_level => 'info',
               filename  => 'Somefile.log',
               mode      => '>>',
               newline   => 1
           ]
       ],
   );
 
   $log->emerg("I've fallen and I can't get up");
 
 =head1 DESCRIPTION
 
 This module provides a simple object for logging to files under the
 Log::Dispatch::* system.
 
 Note that a newline will I<not> be added automatically at the end of a message
 by default. To do that, pass C<< newline => 1 >>.
 
 =for Pod::Coverage new log_message
 
 =head1 CONSTRUCTOR
 
 The constructor takes the following parameters in addition to the standard
 parameters documented in L<Log::Dispatch::Output>:
 
 =over 4
 
 =item * filename ($)
 
 The filename to be opened for writing.
 
 =item * mode ($)
 
 The mode the file should be opened with. Valid options are 'write',
 '>', 'append', '>>', or the relevant constants from Fcntl. The
 default is 'write'.
 
 =item * binmode ($)
 
 A layer name to be passed to binmode, like ":encoding(UTF-8)" or ":raw".
 
 =item * close_after_write ($)
 
 Whether or not the file should be closed after each write. This
 defaults to false.
 
 If this is true, then the mode will always be append, so that the file is not
 re-written for each new message.
 
 =item * autoflush ($)
 
 Whether or not the file should be autoflushed. This defaults to true.
 
 =item * syswrite ($)
 
 Whether or not to perform the write using L<perlfunc/syswrite>(),
 as opposed to L<perlfunc/print>(). This defaults to false.
 The usual caveats and warnings as documented in L<perlfunc/syswrite> apply.
 
 =item * permissions ($)
 
 If the file does not already exist, the permissions that it should
 be created with. Optional. The argument passed must be a valid
 octal value, such as 0600 or the constants available from Fcntl, like
 S_IRUSR|S_IWUSR.
 
 See L<perlfunc/chmod> for more on potential traps when passing octal
 values around. Most importantly, remember that if you pass a string
 that looks like an octal value, like this:
 
  my $mode = '0644';
 
 Then the resulting file will end up with permissions like this:
 
  --w----r-T
 
 which is probably not what you want.
 
 =back
 
 =head1 AUTHOR
 
 Dave Rolsky <autarch@urth.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is Copyright (c) 2015 by Dave Rolsky.
 
 This is free software, licensed under:
 
   The Artistic License 2.0 (GPL Compatible)
 
 =cut
### Log/Dispatch/File/Locked.pm ###
 package Log::Dispatch::File::Locked;
 
 use strict;
 use warnings;
 
 use base qw( Log::Dispatch::File );
 
 our $VERSION = '2.51';
 
 use Fcntl qw(:DEFAULT :flock);
 
 sub _open_file {
     my $self = shift;
 
     $self->SUPER::_open_file();
 
     my $fh = $self->{fh};
 
     flock( $fh, LOCK_EX )
         or die "Cannot lock '$self->{filename}' for writing: $!";
 
     # just in case there was an append while we waited for the lock
     seek( $fh, 0, 2 )
         or die "Cannot seek to end of '$self->{filename}': $!";
 }
 
 1;
 
 # ABSTRACT: Subclass of Log::Dispatch::File to facilitate locking
 
 __END__
 
 =pod
 
 =head1 NAME
 
 Log::Dispatch::File::Locked - Subclass of Log::Dispatch::File to facilitate locking
 
 =head1 VERSION
 
 version 2.51
 
 =head1 SYNOPSIS
 
   use Log::Dispatch;
 
   my $log = Log::Dispatch->new(
       outputs => [
           [
               'File::Locked',
               min_level => 'info',
               filename  => 'Somefile.log',
               mode      => '>>',
               newline   => 1
           ]
       ],
   );
 
   $log->emerg("I've fallen and I can't get up");
 
 =head1 DESCRIPTION
 
 This module acts exactly like L<Log::Dispatch::File> except that it
 obtains an exclusive lock on the file while opening it.
 
 =head1 CAVEATS
 
 B<DANGER!> Use very carefully in multi-process environments. Because the lock
 is obtained at file open time, not at write time, you may experience deadlocks
 in your system.
 
 You can partially work around this by using the C<close_after_write> option,
 which causes the file to be re-opened every time a log message is written.
 
 Alternatively, the C<syswrite> option does atomic writes, which may mean that
 you don't need locking at all.
 
 See  L<Log::Dispatch::File>) for details on these options.
 
 =head1 SEE ALSO
 
 L<perlfunc/flock>
 
 =head1 AUTHOR
 
 Dave Rolsky <autarch@urth.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is Copyright (c) 2015 by Dave Rolsky.
 
 This is free software, licensed under:
 
   The Artistic License 2.0 (GPL Compatible)
 
 =cut
### Log/Dispatch/FileWriteRotate.pm ###
 package Log::Dispatch::FileWriteRotate;
 
 our $DATE = '2015-01-26'; # DATE
 our $VERSION = '0.03'; # VERSION
 
 use 5.010001;
 use warnings;
 use strict;
 
 use File::Write::Rotate;
 use Log::Dispatch::Output;
 use base qw(Log::Dispatch::Output);
 
 sub new {
     my $class = shift;
     my $self = bless {}, $class;
     my %args = @_;
     $self->_basic_init(%args);
     $self->_make_handle(%args);
 
     $self;
 }
 
 sub _make_handle {
     my $self = shift;
     my %args = @_;
 
     for (keys %args) {
         # XXX hook_*
         delete $args{$_} unless /\A(
                                      dir|prefix|suffix|period|size|histories|
                                      binmode|buffer_size|lock_mode|
                                      rotate_probability
                                  )\z/x;
     }
     $self->{_fwr} = File::Write::Rotate->new(%args);
 }
 
 sub log_message {
     my $self = shift;
     my %args = @_;
 
     $self->{_fwr}->write($args{message});
 }
 
 1;
 # ABSTRACT: Log to files that archive/rotate themselves, w/ File::Write::Rotate
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Log::Dispatch::FileWriteRotate - Log to files that archive/rotate themselves, w/ File::Write::Rotate
 
 =head1 VERSION
 
 This document describes version 0.03 of Log::Dispatch::FileWriteRotate (from Perl distribution Log-Dispatch-FileWriteRotate), released on 2015-01-26.
 
 =head1 SYNOPSIS
 
  use Log::Dispatch::FileWriteRotate;
 
  my $file = Log::Dispatch::FileWriteRotate(
      min_level => 'info',
 
      # will be passed to File::Write::Rotate
      dir       => '/var/log',
      prefix    => 'myapp',
      suffix    => '.log',
      period    => 'monthly',
      size      => 25*1024*1024,
      histories => 12,
  );
 
  $file->log(level => 'info', message => "Your comment\n");
 
 =head1 DESCRIPTION
 
 This module functions similarly to L<Log::Dispatch::FileRotate>, but uses
 L<File::Write::Rotate> as backend, thus interoperates more easily with other
 modules which use File::Write::Rotate as backend, e.g.
 L<Tie::Handle::FileWriteRotate> or L<Process::Govern>.
 
 =head1 METHODS
 
 =head2 new(%args)
 
 Constructor. This method takes a hash of parameters. The following options are
 valid: C<min_level> and C<max_level> (see L<Log::Dispatch> documentation);
 C<dir>, C<prefix>, C<suffix>, C<period>, C<size>, and C<histories> (see
 L<File::Write::Rotate>).
 
 =head2 log_message(message => STR)
 
 Send a message to the appropriate output. Generally this shouldn't be called
 directly but should be called through the C<log()> method (in
 LLog::Dispatch::Output>).
 
 =head1 SEE ALSO
 
 L<Log::Dispatch>
 
 L<File::Write::Rotate>
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Log-Dispatch-FileWriteRotate>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Log-Dispatch-FileWriteRotate>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Log-Dispatch-FileWriteRotate>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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
### Log/Dispatch/Handle.pm ###
 package Log::Dispatch::Handle;
 
 use strict;
 use warnings;
 
 our $VERSION = '2.51';
 
 use Log::Dispatch::Output;
 
 use base qw( Log::Dispatch::Output );
 
 use Params::Validate qw(validate SCALAR ARRAYREF BOOLEAN);
 Params::Validate::validation_options( allow_extra => 1 );
 
 sub new {
     my $proto = shift;
     my $class = ref $proto || $proto;
 
     my %p = validate( @_, { handle => { can => 'print' } } );
 
     my $self = bless {}, $class;
 
     $self->_basic_init(%p);
     $self->{handle} = $p{handle};
 
     return $self;
 }
 
 sub log_message {
     my $self = shift;
     my %p    = @_;
 
     $self->{handle}->print( $p{message} )
         or die "Cannot write to handle: $!";
 }
 
 1;
 
 # ABSTRACT: Object for logging to IO::Handle classes
 
 __END__
 
 =pod
 
 =head1 NAME
 
 Log::Dispatch::Handle - Object for logging to IO::Handle classes
 
 =head1 VERSION
 
 version 2.51
 
 =head1 SYNOPSIS
 
   use Log::Dispatch;
 
   my $log = Log::Dispatch->new(
       outputs => [
           [
               'Handle',
               min_level => 'emerg',
               handle    => $io_socket_object,
           ],
       ]
   );
 
   $log->emerg('I am the Lizard King!');
 
 =head1 DESCRIPTION
 
 This module supplies a very simple object for logging to some sort of
 handle object. Basically, anything that implements a C<print()>
 method can be passed the object constructor and it should work.
 
 =for Pod::Coverage new log_message
 
 =head1 CONSTRUCTOR
 
 The constructor takes the following parameters in addition to the standard
 parameters documented in L<Log::Dispatch::Output>:
 
 =over 4
 
 =item * handle ($)
 
 The handle object. This object must implement a C<print()> method.
 
 =back
 
 =head1 AUTHOR
 
 Dave Rolsky <autarch@urth.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is Copyright (c) 2015 by Dave Rolsky.
 
 This is free software, licensed under:
 
   The Artistic License 2.0 (GPL Compatible)
 
 =cut
### Log/Dispatch/Null.pm ###
 package Log::Dispatch::Null;
 
 use strict;
 use warnings;
 
 our $VERSION = '2.51';
 
 use Log::Dispatch::Output;
 
 use base qw( Log::Dispatch::Output );
 
 sub new {
     my $proto = shift;
     my $class = ref $proto || $proto;
 
     my $self = bless {}, $class;
 
     $self->_basic_init(@_);
 
     return $self;
 }
 
 sub log_message { }
 
 1;
 
 # ABSTRACT: Object that accepts messages and does nothing
 
 __END__
 
 =pod
 
 =head1 NAME
 
 Log::Dispatch::Null - Object that accepts messages and does nothing
 
 =head1 VERSION
 
 version 2.51
 
 =head1 SYNOPSIS
 
   use Log::Dispatch;
 
   my $null
       = Log::Dispatch->new( outputs => [ [ 'Null', min_level => 'debug' ] ] );
 
   $null->emerg( "I've fallen and I can't get up" );
 
 =head1 DESCRIPTION
 
 This class provides a null logging object. Messages can be sent to the
 object but it does nothing with them.
 
 =for Pod::Coverage new log_message
 
 =head1 AUTHOR
 
 Dave Rolsky <autarch@urth.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is Copyright (c) 2015 by Dave Rolsky.
 
 This is free software, licensed under:
 
   The Artistic License 2.0 (GPL Compatible)
 
 =cut
### Log/Dispatch/Output.pm ###
 package Log::Dispatch::Output;
 
 use strict;
 use warnings;
 
 our $VERSION = '2.51';
 
 use Log::Dispatch;
 
 use base qw( Log::Dispatch::Base );
 
 use Params::Validate qw(validate SCALAR ARRAYREF CODEREF BOOLEAN);
 Params::Validate::validation_options( allow_extra => 1 );
 
 use Carp ();
 
 my $level_names
     = [qw( debug info notice warning error critical alert emergency )];
 my $ln            = 0;
 my $level_numbers = {
     ( map { $_ => $ln++ } @{$level_names} ),
     warn  => 3,
     err   => 4,
     crit  => 5,
     emerg => 7
 };
 
 sub new {
     my $proto = shift;
     my $class = ref $proto || $proto;
 
     die "The new method must be overridden in the $class subclass";
 }
 
 sub log {
     my $self = shift;
 
     my %p = validate(
         @_, {
             level   => { type => SCALAR },
             message => { type => SCALAR },
         }
     );
 
     return unless $self->_should_log( $p{level} );
 
     $p{message} = $self->_apply_callbacks(%p)
         if $self->{callbacks};
 
     $self->log_message(%p);
 }
 
 sub _basic_init {
     my $self = shift;
 
     my %p = validate(
         @_, {
             name      => { type => SCALAR, optional => 1 },
             min_level => { type => SCALAR, required => 1 },
             max_level => {
                 type     => SCALAR,
                 optional => 1
             },
             callbacks => {
                 type     => ARRAYREF | CODEREF,
                 optional => 1
             },
             newline => { type => BOOLEAN, optional => 1 },
         }
     );
 
     $self->{level_names}   = $level_names;
     $self->{level_numbers} = $level_numbers;
 
     $self->{name} = $p{name} || $self->_unique_name();
 
     $self->{min_level} = $self->_level_as_number( $p{min_level} );
     die "Invalid level specified for min_level"
         unless defined $self->{min_level};
 
     # Either use the parameter supplied or just the highest possible level.
     $self->{max_level} = (
         exists $p{max_level}
         ? $self->_level_as_number( $p{max_level} )
         : $#{ $self->{level_names} }
     );
 
     die "Invalid level specified for max_level"
         unless defined $self->{max_level};
 
     my @cb = $self->_get_callbacks(%p);
     $self->{callbacks} = \@cb if @cb;
 
     if ( $p{newline} ) {
         push @{ $self->{callbacks} }, \&_add_newline_callback;
     }
 }
 
 sub name {
     my $self = shift;
 
     return $self->{name};
 }
 
 sub min_level {
     my $self = shift;
 
     return $self->{level_names}[ $self->{min_level} ];
 }
 
 sub max_level {
     my $self = shift;
 
     return $self->{level_names}[ $self->{max_level} ];
 }
 
 sub accepted_levels {
     my $self = shift;
 
     return @{ $self->{level_names} }
         [ $self->{min_level} .. $self->{max_level} ];
 }
 
 sub _should_log {
     my $self = shift;
 
     my $msg_level = $self->_level_as_number(shift);
     return (   ( $msg_level >= $self->{min_level} )
             && ( $msg_level <= $self->{max_level} ) );
 }
 
 sub _level_as_number {
     my $self  = shift;
     my $level = shift;
 
     unless ( defined $level ) {
         Carp::croak "undefined value provided for log level";
     }
 
     return $level if $level =~ /^\d$/;
 
     unless ( Log::Dispatch->level_is_valid($level) ) {
         Carp::croak "$level is not a valid Log::Dispatch log level";
     }
 
     return $self->{level_numbers}{$level};
 }
 
 sub _level_as_name {
     my $self  = shift;
     my $level = shift;
 
     unless ( defined $level ) {
         Carp::croak "undefined value provided for log level";
     }
 
     return $level unless $level =~ /^\d$/;
 
     return $self->{level_names}[$level];
 }
 
 my $_unique_name_counter = 0;
 
 sub _unique_name {
     my $self = shift;
 
     return '_anon_' . $_unique_name_counter++;
 }
 
 sub _add_newline_callback {
 
     # This weird construct is an optimization since this might be called a lot
     # - see https://github.com/autarch/Log-Dispatch/pull/7
     +{@_}->{message} . "\n";
 }
 
 1;
 
 # ABSTRACT: Base class for all Log::Dispatch::* objects
 
 __END__
 
 =pod
 
 =head1 NAME
 
 Log::Dispatch::Output - Base class for all Log::Dispatch::* objects
 
 =head1 VERSION
 
 version 2.51
 
 =head1 SYNOPSIS
 
   package Log::Dispatch::MySubclass;
 
   use Log::Dispatch::Output;
   use base qw( Log::Dispatch::Output );
 
   sub new {
       my $proto = shift;
       my $class = ref $proto || $proto;
 
       my %p = @_;
 
       my $self = bless {}, $class;
 
       $self->_basic_init(%p);
 
       # Do more if you like
 
       return $self;
   }
 
   sub log_message {
       my $self = shift;
       my %p    = @_;
 
       # Do something with message in $p{message}
   }
 
   1;
 
 =head1 DESCRIPTION
 
 This module is the base class from which all Log::Dispatch::* objects
 should be derived.
 
 =head1 CONSTRUCTOR
 
 The constructor, C<new>, must be overridden in a subclass. See L<Output
 Classes|Log::Dispatch/OUTPUT CLASSES> for a description of the common
 parameters accepted by this constructor.
 
 =head1 METHODS
 
 This class provides the following methods:
 
 =head2 $output->_basic_init(%p)
 
 This should be called from a subclass's constructor. Make sure to
 pass the arguments in @_ to it. It sets the object's name and minimum
 level from the passed parameters  It also sets up two other attributes which
 are used by other Log::Dispatch::Output methods, level_names and level_numbers.
 Subclasses will perform parameter validation in this method, and must also call
 the superclass's method.
 
 =head2 $output->name
 
 Returns the object's name.
 
 =head2 $output->min_level
 
 Returns the object's minimum log level.
 
 =head2 $output->max_level
 
 Returns the object's maximum log level.
 
 =head2 $output->accepted_levels
 
 Returns a list of the object's accepted levels (by name) from minimum
 to maximum.
 
 =head2 $output->log( level => $, message => $ )
 
 Sends a message if the level is greater than or equal to the object's
 minimum level. This method applies any message formatting callbacks
 that the object may have.
 
 =head2 $output->_should_log ($)
 
 This method is called from the C<log()> method with the log level of
 the message to be logged as an argument. It returns a boolean value
 indicating whether or not the message should be logged by this
 particular object. The C<log()> method will not process the message
 if the return value is false.
 
 =head2 $output->_level_as_number ($)
 
 This method will take a log level as a string (or a number) and return
 the number of that log level. If not given an argument, it returns
 the calling object's log level instead. If it cannot determine the
 level then it will croak.
 
 =head2 $output->add_callback( $code )
 
 Adds a callback (like those given during construction). It is added to the end
 of the list of callbacks.
 
 =head1 SUBCLASSING
 
 This class should be used as the base class for all logging objects
 you create that you would like to work under the Log::Dispatch
 architecture. Subclassing is fairly trivial. For most subclasses, if
 you simply copy the code in the SYNOPSIS and then put some
 functionality into the C<log_message> method then you should be all
 set. Please make sure to use the C<_basic_init> method as described above.
 
 The actual logging implementation should be done in a C<log_message>
 method that you write. B<Do not override C<log>!>.
 
 =head1 AUTHOR
 
 Dave Rolsky <autarch@urth.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is Copyright (c) 2015 by Dave Rolsky.
 
 This is free software, licensed under:
 
   The Artistic License 2.0 (GPL Compatible)
 
 =cut
### Log/Dispatch/Screen.pm ###
 package Log::Dispatch::Screen;
 
 use strict;
 use warnings;
 
 our $VERSION = '2.51';
 
 use Log::Dispatch::Output;
 
 use base qw( Log::Dispatch::Output );
 
 use Encode qw( encode );
 use IO::Handle;
 use Params::Validate qw(validate BOOLEAN);
 Params::Validate::validation_options( allow_extra => 1 );
 
 sub new {
     my $proto = shift;
     my $class = ref $proto || $proto;
 
     my %p = validate(
         @_, {
             stderr => {
                 type    => BOOLEAN,
                 default => 1,
             },
             utf8 => {
                 type    => BOOLEAN,
                 default => 0,
             },
         }
     );
 
     my $self = bless \%p, $class;
     $self->_basic_init(%p);
 
     return $self;
 }
 
 sub log_message {
     my $self = shift;
     my %p    = @_;
 
     # This is a bit gross but it's important that we print directly to the
     # STDOUT or STDERR handle for backwards compatibility. Various modules
     # have tests which rely on this, so we can't open a new filehandle to fd 1
     # or 2 and use that.
     my $message
         = $self->{utf8} ? encode( 'UTF-8', $p{message} ) : $p{message};
     if ( $self->{stderr} ) {
         print STDERR $message;
     }
     else {
         print STDOUT $message;
     }
 }
 
 1;
 
 # ABSTRACT: Object for logging to the screen
 
 __END__
 
 =pod
 
 =head1 NAME
 
 Log::Dispatch::Screen - Object for logging to the screen
 
 =head1 VERSION
 
 version 2.51
 
 =head1 SYNOPSIS
 
   use Log::Dispatch;
 
   my $log = Log::Dispatch->new(
       outputs => [
           [
               'Screen',
               min_level => 'debug',
               stderr    => 1,
               newline   => 1
           ]
       ],
   );
 
   $log->alert("I'm searching the city for sci-fi wasabi");
 
 =head1 DESCRIPTION
 
 This module provides an object for logging to the screen (really
 C<STDOUT> or C<STDERR>).
 
 Note that a newline will I<not> be added automatically at the end of a
 message by default. To do that, pass C<< newline => 1 >>.
 
 The handle will be autoflushed, but this module opens it's own handle to fd 1
 or 2 instead of using the global C<STDOUT> or C<STDERR>.
 
 =for Pod::Coverage new log_message
 
 =head1 CONSTRUCTOR
 
 The constructor takes the following parameters in addition to the standard
 parameters documented in L<Log::Dispatch::Output>:
 
 =over 4
 
 =item * stderr (0 or 1)
 
 Indicates whether or not logging information should go to C<STDERR>. If
 false, logging information is printed to C<STDOUT> instead.
 
 This defaults to true.
 
 =item * utf8 (0 or 1)
 
 If this is true, then the output uses C<binmode> to apply the
 C<:encoding(UTF-8)> layer to the relevant handle for output. This will not
 affect C<STDOUT> or C<STDERR> in other parts of your code.
 
 This defaults to false.
 
 =back
 
 =head1 AUTHOR
 
 Dave Rolsky <autarch@urth.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is Copyright (c) 2015 by Dave Rolsky.
 
 This is free software, licensed under:
 
   The Artistic License 2.0 (GPL Compatible)
 
 =cut
### Log/Dispatch/Syslog.pm ###
 package Log::Dispatch::Syslog;
 
 use strict;
 use warnings;
 
 our $VERSION = '2.51';
 
 use Log::Dispatch::Output;
 
 use base qw( Log::Dispatch::Output );
 
 use Params::Validate qw(validate ARRAYREF BOOLEAN HASHREF SCALAR);
 Params::Validate::validation_options( allow_extra => 1 );
 
 use Scalar::Util qw( reftype );
 use Sys::Syslog 0.28 ();
 
 sub new {
     my $proto = shift;
     my $class = ref $proto || $proto;
 
     my %p = @_;
 
     my $self = bless {}, $class;
 
     $self->_basic_init(%p);
     $self->_init(%p);
 
     return $self;
 }
 
 my ($Ident) = $0 =~ /(.+)/;
 
 my $thread_lock;
 my $threads_loaded;
 
 sub _init {
     my $self = shift;
 
     my %p = validate(
         @_, {
             ident => {
                 type    => SCALAR,
                 default => $Ident
             },
             logopt => {
                 type    => SCALAR,
                 default => ''
             },
             facility => {
                 type    => SCALAR,
                 default => 'user'
             },
             socket => {
                 type    => SCALAR | ARRAYREF | HASHREF,
                 default => undef
             },
             lock => {
                 type    => BOOLEAN,
                 default => 0,
             },
         }
     );
 
     $self->{$_} = $p{$_} for qw( ident logopt facility socket lock );
     if ( $self->{lock} ) {
 
         # These need to be loaded with use, not require.
         eval 'use threads; use threads::shared'
             unless $threads_loaded;
         $threads_loaded = 1;
         threads::shared::share( \$thread_lock );
     }
 
     $self->{priorities} = [
         'DEBUG',
         'INFO',
         'NOTICE',
         'WARNING',
         'ERR',
         'CRIT',
         'ALERT',
         'EMERG'
     ];
 }
 
 sub log_message {
     my $self = shift;
     my %p    = @_;
 
     my $pri = $self->_level_as_number( $p{level} );
 
     lock($thread_lock) if $self->{lock};
 
     eval {
         if ( defined $self->{socket} ) {
             Sys::Syslog::setlogsock(
                 ref $self->{socket} && reftype( $self->{socket} ) eq 'ARRAY'
                 ? @{ $self->{socket} }
                 : $self->{socket}
             );
         }
 
         Sys::Syslog::openlog(
             $self->{ident},
             $self->{logopt},
             $self->{facility}
         );
         Sys::Syslog::syslog( $self->{priorities}[$pri], $p{message} );
         Sys::Syslog::closelog;
     };
 
     warn $@ if $@ and $^W;
 }
 
 1;
 
 # ABSTRACT: Object for logging to system log.
 
 __END__
 
 =pod
 
 =head1 NAME
 
 Log::Dispatch::Syslog - Object for logging to system log.
 
 =head1 VERSION
 
 version 2.51
 
 =head1 SYNOPSIS
 
   use Log::Dispatch;
 
   my $log = Log::Dispatch->new(
       outputs => [
           [
               'Syslog',
               min_level => 'info',
               ident     => 'Yadda yadda'
           ]
       ]
   );
 
   $log->emerg("Time to die.");
 
 =head1 DESCRIPTION
 
 This module provides a simple object for sending messages to the
 system log (via UNIX syslog calls).
 
 Note that logging may fail if you try to pass UTF-8 characters in the
 log message. If logging fails and warnings are enabled, the error
 message will be output using Perl's C<warn>.
 
 =for Pod::Coverage new log_message
 
 =head1 CONSTRUCTOR
 
 The constructor takes the following parameters in addition to the standard
 parameters documented in L<Log::Dispatch::Output>:
 
 =over 4
 
 =item * ident ($)
 
 This string will be prepended to all messages in the system log.
 Defaults to $0.
 
 =item * logopt ($)
 
 A string containing the log options (separated by any separator you
 like). See the openlog(3) and Sys::Syslog docs for more details.
 Defaults to ''.
 
 =item * facility ($)
 
 Specifies what type of program is doing the logging to the system log.
 Valid options are 'auth', 'authpriv', 'cron', 'daemon', 'kern',
 'local0' through 'local7', 'mail, 'news', 'syslog', 'user',
 'uucp'. Defaults to 'user'
 
 =item * socket ($, \@, or \%)
 
 Tells what type of socket to use for sending syslog messages. Valid
 options are listed in C<Sys::Syslog>.
 
 If you don't provide this, then we let C<Sys::Syslog> simply pick one
 that works, which is the preferred option, as it makes your code more
 portable.
 
 If you pass an array reference, it is dereferenced and passed to
 C<Sys::Syslog::setlogsock()>.
 
 If you pass a hash reference, it is passed to C<Sys::Syslog::setlogsock()> as
 is.
 
 =item * lock ($)
 
 If this is set to a true value, then the calls to C<setlogsock()>,
 C<openlog()>, C<syslog()>, and C<closelog()> will all be guarded by a
 thread-locked variable.
 
 This is only relevant when running you are using Perl threads in your
 application. Setting this to a true value will cause the L<threads> and
 L<threads::shared> modules to be loaded.
 
 This defaults to false.
 
 =back
 
 =head1 AUTHOR
 
 Dave Rolsky <autarch@urth.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is Copyright (c) 2015 by Dave Rolsky.
 
 This is free software, licensed under:
 
   The Artistic License 2.0 (GPL Compatible)
 
 =cut
### Log/Log4perl.pm ###
 ##################################################
 package Log::Log4perl;
 ##################################################
 
 END { local($?); Log::Log4perl::Logger::cleanup(); }
 
 use 5.006;
 use strict;
 use warnings;
 
 use Log::Log4perl::Util;
 use Log::Log4perl::Logger;
 use Log::Log4perl::Level;
 use Log::Log4perl::Config;
 use Log::Log4perl::Appender;
 
 our $VERSION = '1.46';
 
    # set this to '1' if you're using a wrapper
    # around Log::Log4perl
 our $caller_depth = 0;
 
     #this is a mapping of convenience names to opcode masks used in
     #$ALLOWED_CODE_OPS_IN_CONFIG_FILE below
 our %ALLOWED_CODE_OPS = (
     'safe'        => [ ':browse' ],
     'restrictive' => [ ':default' ],
 );
 
 our %WRAPPERS_REGISTERED = map { $_ => 1 } qw(Log::Log4perl);
 
     #set this to the opcodes which are allowed when
     #$ALLOW_CODE_IN_CONFIG_FILE is set to a true value
     #if undefined, there are no restrictions on code that can be
     #excuted
 our @ALLOWED_CODE_OPS_IN_CONFIG_FILE;
 
     #this hash lists things that should be exported into the Safe
     #compartment.  The keys are the package the symbol should be
     #exported from and the values are array references to the names
     #of the symbols (including the leading type specifier)
 our %VARS_SHARED_WITH_SAFE_COMPARTMENT = (
     main => [ '%ENV' ],
 );
 
     #setting this to a true value will allow Perl code to be executed
     #within the config file.  It works in conjunction with
     #$ALLOWED_CODE_OPS_IN_CONFIG_FILE, which if defined restricts the
     #opcodes which can be executed using the 'Safe' module.
     #setting this to a false value disables code execution in the
     #config file
 our $ALLOW_CODE_IN_CONFIG_FILE = 1;
 
     #arrays in a log message will be joined using this character,
     #see Log::Log4perl::Appender::DBI
 our $JOIN_MSG_ARRAY_CHAR = '';
 
     #version required for XML::DOM, to enable XML Config parsing
     #and XML Config unit tests
 our $DOM_VERSION_REQUIRED = '1.29'; 
 
 our $CHATTY_DESTROY_METHODS = 0;
 
 our $LOGDIE_MESSAGE_ON_STDERR = 1;
 our $LOGEXIT_CODE             = 1;
 our %IMPORT_CALLED;
 
 our $EASY_CLOSURES = {};
 
   # to throw refs as exceptions via logcarp/confess, turn this off
 our $STRINGIFY_DIE_MESSAGE = 1;
 
 use constant _INTERNAL_DEBUG => 0;
 
 ##################################################
 sub import {
 ##################################################
     my($class) = shift;
 
     my $caller_pkg = caller();
 
     return 1 if $IMPORT_CALLED{$caller_pkg}++;
 
     my(%tags) = map { $_ => 1 } @_;
 
         # Lazy man's logger
     if(exists $tags{':easy'}) {
         $tags{':levels'} = 1;
         $tags{':nowarn'} = 1;
         $tags{'get_logger'} = 1;
     }
 
     if(exists $tags{':no_extra_logdie_message'}) {
         $Log::Log4perl::LOGDIE_MESSAGE_ON_STDERR = 0;
         delete $tags{':no_extra_logdie_message'};
     }
 
     if(exists $tags{get_logger}) {
         # Export get_logger into the calling module's 
         no strict qw(refs);
         *{"$caller_pkg\::get_logger"} = *get_logger;
 
         delete $tags{get_logger};
     }
 
     if(exists $tags{':levels'}) {
         # Export log levels ($DEBUG, $INFO etc.) from Log4perl::Level
         for my $key (keys %Log::Log4perl::Level::PRIORITY) {
             my $name  = "$caller_pkg\::$key";
                # Need to split this up in two lines, or CVS will
                # mess it up.
             my $value = $
                         Log::Log4perl::Level::PRIORITY{$key};
             no strict qw(refs);
             *{"$name"} = \$value;
         }
 
         delete $tags{':levels'};
     }
 
         # Lazy man's logger
     if(exists $tags{':easy'}) {
         delete $tags{':easy'};
 
             # Define default logger object in caller's package
         my $logger = get_logger("$caller_pkg");
         
             # Define DEBUG, INFO, etc. routines in caller's package
         for(qw(TRACE DEBUG INFO WARN ERROR FATAL ALWAYS)) {
             my $level   = $_;
             $level = "OFF" if $level eq "ALWAYS";
             my $lclevel = lc($_);
             easy_closure_create($caller_pkg, $_, sub {
                 Log::Log4perl::Logger::init_warn() unless 
                     $Log::Log4perl::Logger::INITIALIZED or
                     $Log::Log4perl::Logger::NON_INIT_WARNED;
                 $logger->{$level}->($logger, @_, $level);
             }, $logger);
         }
 
             # Define LOGCROAK, LOGCLUCK, etc. routines in caller's package
         for(qw(LOGCROAK LOGCLUCK LOGCARP LOGCONFESS)) {
             my $method = "Log::Log4perl::Logger::" . lc($_);
 
             easy_closure_create($caller_pkg, $_, sub {
                 unshift @_, $logger;
                 goto &$method;
             }, $logger);
         }
 
             # Define LOGDIE, LOGWARN
          easy_closure_create($caller_pkg, "LOGDIE", sub {
              Log::Log4perl::Logger::init_warn() unless 
                      $Log::Log4perl::Logger::INITIALIZED or
                      $Log::Log4perl::Logger::NON_INIT_WARNED;
              $logger->{FATAL}->($logger, @_, "FATAL");
              $Log::Log4perl::LOGDIE_MESSAGE_ON_STDERR ?
                  CORE::die(Log::Log4perl::Logger::callerline(join '', @_)) :
                  exit $Log::Log4perl::LOGEXIT_CODE;
          }, $logger);
 
          easy_closure_create($caller_pkg, "LOGEXIT", sub {
             Log::Log4perl::Logger::init_warn() unless 
                     $Log::Log4perl::Logger::INITIALIZED or
                     $Log::Log4perl::Logger::NON_INIT_WARNED;
             $logger->{FATAL}->($logger, @_, "FATAL");
             exit $Log::Log4perl::LOGEXIT_CODE;
          }, $logger);
 
         easy_closure_create($caller_pkg, "LOGWARN", sub {
             Log::Log4perl::Logger::init_warn() unless 
                     $Log::Log4perl::Logger::INITIALIZED or
                     $Log::Log4perl::Logger::NON_INIT_WARNED;
             $logger->{WARN}->($logger, @_, "WARN");
             CORE::warn(Log::Log4perl::Logger::callerline(join '', @_))
                 if $Log::Log4perl::LOGDIE_MESSAGE_ON_STDERR;
         }, $logger);
     }
 
     if(exists $tags{':nowarn'}) {
         $Log::Log4perl::Logger::NON_INIT_WARNED = 1;
         delete $tags{':nowarn'};
     }
 
     if(exists $tags{':nostrict'}) {
         $Log::Log4perl::Logger::NO_STRICT = 1;
         delete $tags{':nostrict'};
     }
 
     if(exists $tags{':resurrect'}) {
         my $FILTER_MODULE = "Filter::Util::Call";
         if(! Log::Log4perl::Util::module_available($FILTER_MODULE)) {
             die "$FILTER_MODULE required with :resurrect" .
                 "(install from CPAN)";
         }
         eval "require $FILTER_MODULE" or die "Cannot pull in $FILTER_MODULE";
         Filter::Util::Call::filter_add(
             sub {
                 my($status);
                 s/^\s*###l4p// if
                     ($status = Filter::Util::Call::filter_read()) > 0;
                 $status;
                 });
         delete $tags{':resurrect'};
     }
 
     if(keys %tags) {
         # We received an Option we couldn't understand.
         die "Unknown Option(s): @{[keys %tags]}";
     }
 }
 
 ##################################################
 sub initialized {
 ##################################################
     return $Log::Log4perl::Logger::INITIALIZED;
 }
 
 ##################################################
 sub new {
 ##################################################
     die "THIS CLASS ISN'T FOR DIRECT USE. " .
         "PLEASE CHECK 'perldoc " . __PACKAGE__ . "'.";
 }
 
 ##################################################
 sub reset { # Mainly for debugging/testing
 ##################################################
     # Delegate this to the logger ...
     return Log::Log4perl::Logger->reset();
 }
 
 ##################################################
 sub init_once { # Call init only if it hasn't been
                 # called yet.
 ##################################################
     init(@_) unless $Log::Log4perl::Logger::INITIALIZED;
 }
 
 ##################################################
 sub init { # Read the config file
 ##################################################
     my($class, @args) = @_;
 
     #woops, they called ::init instead of ->init, let's be forgiving
     if ($class ne __PACKAGE__) {
         unshift(@args, $class);
     }
 
     # Delegate this to the config module
     return Log::Log4perl::Config->init(@args);
 }
 
 ##################################################
 sub init_and_watch { 
 ##################################################
     my($class, @args) = @_;
 
     #woops, they called ::init instead of ->init, let's be forgiving
     if ($class ne __PACKAGE__) {
         unshift(@args, $class);
     }
 
     # Delegate this to the config module
     return Log::Log4perl::Config->init_and_watch(@args);
 }
 
 
 ##################################################
 sub easy_init { # Initialize the root logger with a screen appender
 ##################################################
     my($class, @args) = @_;
 
     # Did somebody call us with Log::Log4perl::easy_init()?
     if(ref($class) or $class =~ /^\d+$/) {
         unshift @args, $class;
     }
 
     # Reset everything first
     Log::Log4perl->reset();
 
     my @loggers = ();
 
     my %default = ( level    => $DEBUG,
                     file     => "STDERR",
                     utf8     => undef,
                     category => "",
                     layout   => "%d %m%n",
                   );
 
     if(!@args) {
         push @loggers, \%default;
     } else {
         for my $arg (@args) {
             if($arg =~ /^\d+$/) {
                 my %logger = (%default, level => $arg);
                 push @loggers, \%logger;
             } elsif(ref($arg) eq "HASH") {
                 my %logger = (%default, %$arg);
                 push @loggers, \%logger;
             }
         }
     }
 
     for my $logger (@loggers) {
 
         my $app;
 
         if($logger->{file} =~ /^stderr$/i) {
             $app = Log::Log4perl::Appender->new(
                 "Log::Log4perl::Appender::Screen",
                 utf8 => $logger->{utf8});
         } elsif($logger->{file} =~ /^stdout$/i) {
             $app = Log::Log4perl::Appender->new(
                 "Log::Log4perl::Appender::Screen",
                 stderr => 0,
                 utf8   => $logger->{utf8});
         } else {
             my $binmode;
             if($logger->{file} =~ s/^(:.*?)>/>/) {
                 $binmode = $1;
             }
             $logger->{file} =~ /^(>)?(>)?/;
             my $mode = ($2 ? "append" : "write");
             $logger->{file} =~ s/.*>+\s*//g;
             $app = Log::Log4perl::Appender->new(
                 "Log::Log4perl::Appender::File",
                 filename => $logger->{file},
                 mode     => $mode,
                 utf8     => $logger->{utf8},
                 binmode  => $binmode,
             );
         }
 
         my $layout = Log::Log4perl::Layout::PatternLayout->new(
                                                         $logger->{layout});
         $app->layout($layout);
 
         my $log = Log::Log4perl->get_logger($logger->{category});
         $log->level($logger->{level});
         $log->add_appender($app);
     }
 
     $Log::Log4perl::Logger::INITIALIZED = 1;
 }
 
 ##################################################
 sub wrapper_register {  
 ##################################################
     my $wrapper = $_[-1];
 
     $WRAPPERS_REGISTERED{ $wrapper } = 1;
 }
 
 ##################################################
 sub get_logger {  # Get an instance (shortcut)
 ##################################################
     # get_logger() can be called in the following ways:
     #
     #   (1) Log::Log4perl::get_logger()     => ()
     #   (2) Log::Log4perl->get_logger()     => ("Log::Log4perl")
     #   (3) Log::Log4perl::get_logger($cat) => ($cat)
     #   
     #   (5) Log::Log4perl->get_logger($cat) => ("Log::Log4perl", $cat)
     #   (6)   L4pSubclass->get_logger($cat) => ("L4pSubclass", $cat)
 
     # Note that (4) L4pSubclass->get_logger() => ("L4pSubclass")
     # is indistinguishable from (3) and therefore can't be allowed.
     # Wrapper classes always have to specify the category explicitly.
 
     my $category;
 
     if(@_ == 0) {
           # 1
         my $level = 0;
         do { $category = scalar caller($level++);
         } while exists $WRAPPERS_REGISTERED{ $category };
 
     } elsif(@_ == 1) {
           # 2, 3
         $category = $_[0];
 
         my $level = 0;
         while(exists $WRAPPERS_REGISTERED{ $category }) { 
             $category = scalar caller($level++);
         }
 
     } else {
           # 5, 6
         $category = $_[1];
     }
 
     # Delegate this to the logger module
     return Log::Log4perl::Logger->get_logger($category);
 }
 
 ###########################################
 sub caller_depth_offset {
 ###########################################
     my( $level ) = @_;
 
     my $category;
 
     { 
         my $category = scalar caller($level + 1);
 
         if(defined $category and
            exists $WRAPPERS_REGISTERED{ $category }) {
             $level++;
             redo;
         }
     }
 
     return $level;
 }
 
 ##################################################
 sub appenders {  # Get a hashref of all defined appender wrappers
 ##################################################
     return \%Log::Log4perl::Logger::APPENDER_BY_NAME;
 }
 
 ##################################################
 sub add_appender { # Add an appender to the system, but don't assign
 	           # it to a logger yet
 ##################################################
     my($class, $appender) = @_;
 
     my $name = $appender->name();
     die "Mandatory parameter 'name' missing in appender" unless defined $name;
 
       # Make it known by name in the Log4perl universe
       # (so that composite appenders can find it)
     Log::Log4perl->appenders()->{ $name } = $appender;
 }
 
 ##################################################
 # Return number of appenders changed
 sub appender_thresholds_adjust {  # Readjust appender thresholds
 ##################################################
         # If someone calls L4p-> and not L4p::
     shift if $_[0] eq __PACKAGE__;
     my($delta, $appenders) = @_;
 	my $retval = 0;
 
     if($delta == 0) {
           # Nothing to do, no delta given.
         return;
     }
 
     if(defined $appenders) {
             # Map names to objects
         $appenders = [map { 
                        die "Unkown appender: '$_'" unless exists
                           $Log::Log4perl::Logger::APPENDER_BY_NAME{
                             $_};
                        $Log::Log4perl::Logger::APPENDER_BY_NAME{
                          $_} 
                       } @$appenders];
     } else {
             # Just hand over all known appenders
         $appenders = [values %{Log::Log4perl::appenders()}] unless 
             defined $appenders;
     }
 
         # Change all appender thresholds;
     foreach my $app (@$appenders) {
         my $old_thres = $app->threshold();
         my $new_thres;
         if($delta > 0) {
             $new_thres = Log::Log4perl::Level::get_higher_level(
                              $old_thres, $delta);
         } else {
             $new_thres = Log::Log4perl::Level::get_lower_level(
                              $old_thres, -$delta);
         }
 
         ++$retval if ($app->threshold($new_thres) == $new_thres);
     }
 	return $retval;
 }
 
 ##################################################
 sub appender_by_name {  # Get a (real) appender by name
 ##################################################
         # If someone calls L4p->appender_by_name and not L4p::appender_by_name
     shift if $_[0] eq __PACKAGE__;
 
     my($name) = @_;
 
     if(defined $name and
        exists $Log::Log4perl::Logger::APPENDER_BY_NAME{
                  $name}) {
         return $Log::Log4perl::Logger::APPENDER_BY_NAME{
                  $name}->{appender};
     } else {
         return undef;
     }
 }
 
 ##################################################
 sub eradicate_appender {  # Remove an appender from the system
 ##################################################
         # If someone calls L4p->... and not L4p::...
     shift if $_[0] eq __PACKAGE__;
     Log::Log4perl::Logger->eradicate_appender(@_);
 }
 
 ##################################################
 sub infiltrate_lwp {  # 
 ##################################################
     no warnings qw(redefine);
 
     my $l4p_wrapper = sub {
         my($prio, @message) = @_;
         local $Log::Log4perl::caller_depth =
               $Log::Log4perl::caller_depth + 2;
         get_logger(scalar caller(1))->log($prio, @message);
     };
 
     *LWP::Debug::trace = sub { 
         $l4p_wrapper->($INFO, @_); 
     };
     *LWP::Debug::conns =
     *LWP::Debug::debug = sub { 
         $l4p_wrapper->($DEBUG, @_); 
     };
 }
 
 ##################################################
 sub easy_closure_create {
 ##################################################
     my($caller_pkg, $entry, $code, $logger) = @_;
 
     no strict 'refs';
 
     print("easy_closure: Setting shortcut $caller_pkg\::$entry ", 
          "(logger=$logger\n") if _INTERNAL_DEBUG;
 
     $EASY_CLOSURES->{ $caller_pkg }->{ $entry } = $logger;
     *{"$caller_pkg\::$entry"} = $code;
 }
 
 ###########################################
 sub easy_closure_cleanup {
 ###########################################
     my($caller_pkg, $entry) = @_;
 
     no warnings 'redefine';
     no strict 'refs';
 
     my $logger = $EASY_CLOSURES->{ $caller_pkg }->{ $entry };
 
     print("easy_closure: Nuking easy shortcut $caller_pkg\::$entry ", 
          "(logger=$logger\n") if _INTERNAL_DEBUG;
 
     *{"$caller_pkg\::$entry"} = sub { };
     delete $EASY_CLOSURES->{ $caller_pkg }->{ $entry };
 }
 
 ##################################################
 sub easy_closure_category_cleanup {
 ##################################################
     my($caller_pkg) = @_;
 
     if(! exists $EASY_CLOSURES->{ $caller_pkg } ) {
         return 1;
     }
 
     for my $entry ( keys %{ $EASY_CLOSURES->{ $caller_pkg } } ) {
         easy_closure_cleanup( $caller_pkg, $entry );
     }
 
     delete $EASY_CLOSURES->{ $caller_pkg };
 }
 
 ###########################################
 sub easy_closure_global_cleanup {
 ###########################################
 
     for my $caller_pkg ( keys %$EASY_CLOSURES ) {
         easy_closure_category_cleanup( $caller_pkg );
     }
 }
 
 ###########################################
 sub easy_closure_logger_remove {
 ###########################################
     my($class, $logger) = @_;
 
     PKG: for my $caller_pkg ( keys %$EASY_CLOSURES ) {
         for my $entry ( keys %{ $EASY_CLOSURES->{ $caller_pkg } } ) {
             if( $logger == $EASY_CLOSURES->{ $caller_pkg }->{ $entry } ) {
                 easy_closure_category_cleanup( $caller_pkg );
                 next PKG;
             }
         }
     }
 }
 
 ##################################################
 sub remove_logger {
 ##################################################
     my ($class, $logger) = @_;
 
     # Any stealth logger convenience function still using it will
     # now become a no-op.
     Log::Log4perl->easy_closure_logger_remove( $logger );
 
     # Remove the logger from the system
     delete $Log::Log4perl::Logger::LOGGERS_BY_NAME->{ $logger->{category} };
 }
 
 1;
 
 __END__
 
 =encoding utf8
 
 =head1 NAME
 
 Log::Log4perl - Log4j implementation for Perl
 
 =head1 SYNOPSIS
         # Easy mode if you like it simple ...
 
     use Log::Log4perl qw(:easy);
     Log::Log4perl->easy_init($ERROR);
 
     DEBUG "This doesn't go anywhere";
     ERROR "This gets logged";
 
         # ... or standard mode for more features:
 
     Log::Log4perl::init('/etc/log4perl.conf');
     
     --or--
     
         # Check config every 10 secs
     Log::Log4perl::init_and_watch('/etc/log4perl.conf',10);
 
     --then--
     
     $logger = Log::Log4perl->get_logger('house.bedrm.desk.topdrwr');
     
     $logger->debug('this is a debug message');
     $logger->info('this is an info message');
     $logger->warn('etc');
     $logger->error('..');
     $logger->fatal('..');
     
     #####/etc/log4perl.conf###############################
     log4perl.logger.house              = WARN,  FileAppndr1
     log4perl.logger.house.bedroom.desk = DEBUG, FileAppndr1
     
     log4perl.appender.FileAppndr1      = Log::Log4perl::Appender::File
     log4perl.appender.FileAppndr1.filename = desk.log 
     log4perl.appender.FileAppndr1.layout   = \
                             Log::Log4perl::Layout::SimpleLayout
     ######################################################
 
 =head1 ABSTRACT
 
 Log::Log4perl provides a powerful logging API for your application
 
 =head1 DESCRIPTION
 
 Log::Log4perl lets you remote-control and fine-tune the logging behaviour
 of your system from the outside. It implements the widely popular 
 (Java-based) Log4j logging package in pure Perl. 
 
 B<For a detailed tutorial on Log::Log4perl usage, please read> 
 
 L<http://www.perl.com/pub/a/2002/09/11/log4perl.html>
 
 Logging beats a debugger if you want to know what's going on 
 in your code during runtime. However, traditional logging packages
 are too static and generate a flood of log messages in your log files
 that won't help you.
 
 C<Log::Log4perl> is different. It allows you to control the number of 
 logging messages generated at three different levels:
 
 =over 4
 
 =item *
 
 At a central location in your system (either in a configuration file or
 in the startup code) you specify I<which components> (classes, functions) 
 of your system should generate logs.
 
 =item *
 
 You specify how detailed the logging of these components should be by
 specifying logging I<levels>.
 
 =item *
 
 You also specify which so-called I<appenders> you want to feed your
 log messages to ("Print it to the screen and also append it to /tmp/my.log")
 and which format ("Write the date first, then the file name and line 
 number, and then the log message") they should be in.
 
 =back
 
 This is a very powerful and flexible mechanism. You can turn on and off
 your logs at any time, specify the level of detail and make that
 dependent on the subsystem that's currently executed. 
 
 Let me give you an example: You might 
 find out that your system has a problem in the 
 C<MySystem::Helpers::ScanDir>
 component. Turning on detailed debugging logs all over the system would
 generate a flood of useless log messages and bog your system down beyond
 recognition. With C<Log::Log4perl>, however, you can tell the system:
 "Continue to log only severe errors to the log file. Open a second
 log file, turn on full debug logs in the C<MySystem::Helpers::ScanDir>
 component and dump all messages originating from there into the new
 log file". And all this is possible by just changing the parameters
 in a configuration file, which your system can re-read even 
 while it's running!
 
 =head1 How to use it
 
 The C<Log::Log4perl> package can be initialized in two ways: Either
 via Perl commands or via a C<log4j>-style configuration file.
 
 =head2 Initialize via a configuration file
 
 This is the easiest way to prepare your system for using
 C<Log::Log4perl>. Use a configuration file like this:
 
     ############################################################
     # A simple root logger with a Log::Log4perl::Appender::File 
     # file appender in Perl.
     ############################################################
     log4perl.rootLogger=ERROR, LOGFILE
     
     log4perl.appender.LOGFILE=Log::Log4perl::Appender::File
     log4perl.appender.LOGFILE.filename=/var/log/myerrs.log
     log4perl.appender.LOGFILE.mode=append
     
     log4perl.appender.LOGFILE.layout=PatternLayout
     log4perl.appender.LOGFILE.layout.ConversionPattern=[%r] %F %L %c - %m%n
 
 These lines define your standard logger that's appending severe
 errors to C</var/log/myerrs.log>, using the format
 
     [millisecs] source-filename line-number class - message newline
 
 Assuming that this configuration file is saved as C<log.conf>, you need to 
 read it in the startup section of your code, using the following
 commands:
 
   use Log::Log4perl;
   Log::Log4perl->init("log.conf");
 
 After that's done I<somewhere> in the code, you can retrieve
 logger objects I<anywhere> in the code. Note that
 there's no need to carry any logger references around with your 
 functions and methods. You can get a logger anytime via a singleton
 mechanism:
 
     package My::MegaPackage;
     use  Log::Log4perl;
 
     sub some_method {
         my($param) = @_;
 
         my $log = Log::Log4perl->get_logger("My::MegaPackage");
 
         $log->debug("Debug message");
         $log->info("Info message");
         $log->error("Error message");
 
         ...
     }
 
 With the configuration file above, C<Log::Log4perl> will write
 "Error message" to the specified log file, but won't do anything for 
 the C<debug()> and C<info()> calls, because the log level has been set
 to C<ERROR> for all components in the first line of 
 configuration file shown above.
 
 Why C<Log::Log4perl-E<gt>get_logger> and
 not C<Log::Log4perl-E<gt>new>? We don't want to create a new
 object every time. Usually in OO-Programming, you create an object
 once and use the reference to it to call its methods. However,
 this requires that you pass around the object to all functions
 and the last thing we want is pollute each and every function/method
 we're using with a handle to the C<Logger>:
 
     sub function {  # Brrrr!!
         my($logger, $some, $other, $parameters) = @_;
     }
 
 Instead, if a function/method wants a reference to the logger, it
 just calls the Logger's static C<get_logger($category)> method to obtain
 a reference to the I<one and only> possible logger object of
 a certain category.
 That's called a I<singleton> if you're a Gamma fan.
 
 How does the logger know
 which messages it is supposed to log and which ones to suppress?
 C<Log::Log4perl> works with inheritance: The config file above didn't 
 specify anything about C<My::MegaPackage>. 
 And yet, we've defined a logger of the category 
 C<My::MegaPackage>.
 In this case, C<Log::Log4perl> will walk up the namespace hierarchy
 (C<My> and then we're at the root) to figure out if a log level is
 defined somewhere. In the case above, the log level at the root
 (root I<always> defines a log level, but not necessarily an appender)
 defines that 
 the log level is supposed to be C<ERROR> -- meaning that I<DEBUG>
 and I<INFO> messages are suppressed. Note that this 'inheritance' is
 unrelated to Perl's class inheritance, it is merely related to the
 logger namespace.
 By the way, if you're ever in doubt about what a logger's category is, 
 use C<$logger-E<gt>category()> to retrieve it.
 
 =head2 Log Levels
 
 There are six predefined log levels: C<FATAL>, C<ERROR>, C<WARN>, C<INFO>,
 C<DEBUG>, and C<TRACE> (in descending priority). Your configured logging level
 has to at least match the priority of the logging message.
 
 If your configured logging level is C<WARN>, then messages logged 
 with C<info()>, C<debug()>, and C<trace()> will be suppressed. 
 C<fatal()>, C<error()> and C<warn()> will make their way through,
 because their priority is higher or equal than the configured setting.
 
 Instead of calling the methods
 
     $logger->trace("...");  # Log a trace message
     $logger->debug("...");  # Log a debug message
     $logger->info("...");   # Log a info message
     $logger->warn("...");   # Log a warn message
     $logger->error("...");  # Log a error message
     $logger->fatal("...");  # Log a fatal message
 
 you could also call the C<log()> method with the appropriate level
 using the constants defined in C<Log::Log4perl::Level>:
 
     use Log::Log4perl::Level;
 
     $logger->log($TRACE, "...");
     $logger->log($DEBUG, "...");
     $logger->log($INFO, "...");
     $logger->log($WARN, "...");
     $logger->log($ERROR, "...");
     $logger->log($FATAL, "...");
 
 This form is rarely used, but it comes in handy if you want to log 
 at different levels depending on an exit code of a function:
 
     $logger->log( $exit_level{ $rc }, "...");
 
 As for needing more logging levels than these predefined ones: It's
 usually best to steer your logging behaviour via the category 
 mechanism instead.
 
 If you need to find out if the currently configured logging
 level would allow a logger's logging statement to go through, use the
 logger's C<is_I<level>()> methods:
 
     $logger->is_trace()    # True if trace messages would go through
     $logger->is_debug()    # True if debug messages would go through
     $logger->is_info()     # True if info messages would go through
     $logger->is_warn()     # True if warn messages would go through
     $logger->is_error()    # True if error messages would go through
     $logger->is_fatal()    # True if fatal messages would go through
 
 Example: C<$logger-E<gt>is_warn()> returns true if the logger's current
 level, as derived from either the logger's category (or, in absence of
 that, one of the logger's parent's level setting) is 
 C<$WARN>, C<$ERROR> or C<$FATAL>.
 
 Also available are a series of more Java-esque functions which return
 the same values. These are of the format C<isI<Level>Enabled()>,
 so C<$logger-E<gt>isDebugEnabled()> is synonymous to 
 C<$logger-E<gt>is_debug()>.
 
 
 These level checking functions
 will come in handy later, when we want to block unnecessary
 expensive parameter construction in case the logging level is too
 low to log the statement anyway, like in:
 
     if($logger->is_error()) {
         $logger->error("Erroneous array: @super_long_array");
     }
 
 If we had just written
 
     $logger->error("Erroneous array: @super_long_array");
 
 then Perl would have interpolated
 C<@super_long_array> into the string via an expensive operation
 only to figure out shortly after that the string can be ignored
 entirely because the configured logging level is lower than C<$ERROR>.
 
 The to-be-logged
 message passed to all of the functions described above can
 consist of an arbitrary number of arguments, which the logging functions
 just chain together to a single string. Therefore
 
     $logger->debug("Hello ", "World", "!");  # and
     $logger->debug("Hello World!");
 
 are identical.
 
 Note that even if one of the methods above returns true, it doesn't 
 necessarily mean that the message will actually get logged. 
 What is_debug() checks is that
 the logger used is configured to let a message of the given priority 
 (DEBUG) through. But after this check, Log4perl will eventually apply custom 
 filters and forward the message to one or more appenders. None of this
 gets checked by is_xxx(), for the simple reason that it's 
 impossible to know what a custom filter does with a message without
 having the actual message or what an appender does to a message without
 actually having it log it.
 
 =head2 Log and die or warn
 
 Often, when you croak / carp / warn / die, you want to log those messages.
 Rather than doing the following:
 
     $logger->fatal($err) && die($err);
 
 you can use the following:
 
     $logger->logdie($err);
 
 And if instead of using
 
     warn($message);
     $logger->warn($message);
 
 to both issue a warning via Perl's warn() mechanism and make sure you have
 the same message in the log file as well, use:
 
     $logger->logwarn($message);
 
 Since there is
 an ERROR level between WARN and FATAL, there are two additional helper
 functions in case you'd like to use ERROR for either warn() or die():
 
     $logger->error_warn();
     $logger->error_die();
 
 Finally, there's the Carp functions that, in addition to logging,
 also pass the stringified message to their companions in the Carp package:
 
     $logger->logcarp();        # warn w/ 1-level stack trace
     $logger->logcluck();       # warn w/ full stack trace
     $logger->logcroak();       # die w/ 1-level stack trace
     $logger->logconfess();     # die w/ full stack trace
 
 =head2 Appenders
 
 If you don't define any appenders, nothing will happen. Appenders will
 be triggered whenever the configured logging level requires a message
 to be logged and not suppressed.
 
 C<Log::Log4perl> doesn't define any appenders by default, not even the root
 logger has one.
 
 C<Log::Log4perl> already comes with a standard set of appenders:
 
     Log::Log4perl::Appender::Screen
     Log::Log4perl::Appender::ScreenColoredLevels
     Log::Log4perl::Appender::File
     Log::Log4perl::Appender::Socket
     Log::Log4perl::Appender::DBI
     Log::Log4perl::Appender::Synchronized
     Log::Log4perl::Appender::RRDs
 
 to log to the screen, to files and to databases. 
 
 On CPAN, you can find additional appenders like
 
     Log::Log4perl::Layout::XMLLayout
 
 by Guido Carls E<lt>gcarls@cpan.orgE<gt>.
 It allows for hooking up Log::Log4perl with the graphical Log Analyzer
 Chainsaw (see 
 L<Log::Log4perl::FAQ/"Can I use Log::Log4perl with log4j's Chainsaw?">).
 
 =head2 Additional Appenders via Log::Dispatch
 
 C<Log::Log4perl> also supports I<Dave Rolskys> excellent C<Log::Dispatch>
 framework which implements a wide variety of different appenders. 
 
 Here's the list of appender modules currently available via C<Log::Dispatch>:
 
        Log::Dispatch::ApacheLog
        Log::Dispatch::DBI (by Tatsuhiko Miyagawa)
        Log::Dispatch::Email,
        Log::Dispatch::Email::MailSend,
        Log::Dispatch::Email::MailSendmail,
        Log::Dispatch::Email::MIMELite
        Log::Dispatch::File
        Log::Dispatch::FileRotate (by Mark Pfeiffer)
        Log::Dispatch::Handle
        Log::Dispatch::Screen
        Log::Dispatch::Syslog
        Log::Dispatch::Tk (by Dominique Dumont)
 
 Please note that in order to use any of these additional appenders, you
 have to fetch Log::Dispatch from CPAN and install it. Also the particular
 appender you're using might require installing the particular module.
 
 For additional information on appenders, please check the
 L<Log::Log4perl::Appender> manual page.
 
 =head2 Appender Example
 
 Now let's assume that we want to log C<info()> or
 higher prioritized messages in the C<Foo::Bar> category
 to both STDOUT and to a log file, say C<test.log>.
 In the initialization section of your system,
 just define two appenders using the readily available
 C<Log::Log4perl::Appender::File> and C<Log::Log4perl::Appender::Screen> 
 modules:
 
   use Log::Log4perl;
 
      # Configuration in a string ...
   my $conf = q(
     log4perl.category.Foo.Bar          = INFO, Logfile, Screen
 
     log4perl.appender.Logfile          = Log::Log4perl::Appender::File
     log4perl.appender.Logfile.filename = test.log
     log4perl.appender.Logfile.layout   = Log::Log4perl::Layout::PatternLayout
     log4perl.appender.Logfile.layout.ConversionPattern = [%r] %F %L %m%n
 
     log4perl.appender.Screen         = Log::Log4perl::Appender::Screen
     log4perl.appender.Screen.stderr  = 0
     log4perl.appender.Screen.layout = Log::Log4perl::Layout::SimpleLayout
   );
 
      # ... passed as a reference to init()
   Log::Log4perl::init( \$conf );
 
 Once the initialization shown above has happened once, typically in
 the startup code of your system, just use the defined logger anywhere in 
 your system:
 
   ##########################
   # ... in some function ...
   ##########################
   my $log = Log::Log4perl::get_logger("Foo::Bar");
 
     # Logs both to STDOUT and to the file test.log
   $log->info("Important Info!");
 
 The C<layout> settings specified in the configuration section define the 
 format in which the
 message is going to be logged by the specified appender. The format shown
 for the file appender is logging not only the message but also the number of
 milliseconds since the program has started (%r), the name of the file
 the call to the logger has happened and the line number there (%F and
 %L), the message itself (%m) and a OS-specific newline character (%n):
 
     [187] ./myscript.pl 27 Important Info!
 
 The
 screen appender above, on the other hand, 
 uses a C<SimpleLayout>, which logs the 
 debug level, a hyphen (-) and the log message:
 
     INFO - Important Info!
 
 For more detailed info on layout formats, see L<Log Layouts>. 
 
 In the configuration sample above, we chose to define a I<category> 
 logger (C<Foo::Bar>).
 This will cause only messages originating from
 this specific category logger to be logged in the defined format
 and locations.
 
 =head2 Logging newlines
 
 There's some controversy between different logging systems as to when and 
 where newlines are supposed to be added to logged messages.
 
 The Log4perl way is that a logging statement I<should not> 
 contain a newline:
 
     $logger->info("Some message");
     $logger->info("Another message");
 
 If this is supposed to end up in a log file like
 
     Some message
     Another message
 
 then an appropriate appender layout like "%m%n" will take care of adding
 a newline at the end of each message to make sure every message is 
 printed on its own line.
 
 Other logging systems, Log::Dispatch in particular, recommend adding the
 newline to the log statement. This doesn't work well, however, if you, say,
 replace your file appender by a database appender, and all of a sudden
 those newlines scattered around the code don't make sense anymore.
 
 Assigning matching layouts to different appenders and leaving newlines
 out of the code solves this problem. If you inherited code that has logging
 statements with newlines and want to make it work with Log4perl, read
 the L<Log::Log4perl::Layout::PatternLayout> documentation on how to 
 accomplish that.
 
 =head2 Configuration files
 
 As shown above, you can define C<Log::Log4perl> loggers both from within
 your Perl code or from configuration files. The latter have the unbeatable
 advantage that you can modify your system's logging behaviour without 
 interfering with the code at all. So even if your code is being run by 
 somebody who's totally oblivious to Perl, they still can adapt the
 module's logging behaviour to their needs.
 
 C<Log::Log4perl> has been designed to understand C<Log4j> configuration
 files -- as used by the original Java implementation. Instead of 
 reiterating the format description in [2], let me just list three
 examples (also derived from [2]), which should also illustrate
 how it works:
 
     log4j.rootLogger=DEBUG, A1
     log4j.appender.A1=org.apache.log4j.ConsoleAppender
     log4j.appender.A1.layout=org.apache.log4j.PatternLayout
     log4j.appender.A1.layout.ConversionPattern=%-4r %-5p %c %x - %m%n
 
 This enables messages of priority C<DEBUG> or higher in the root
 hierarchy and has the system write them to the console. 
 C<ConsoleAppender> is a Java appender, but C<Log::Log4perl> jumps
 through a significant number of hoops internally to map these to their
 corresponding Perl classes, C<Log::Log4perl::Appender::Screen> in this case.
 
 Second example:
 
     log4perl.rootLogger=DEBUG, A1
     log4perl.appender.A1=Log::Log4perl::Appender::Screen
     log4perl.appender.A1.layout=PatternLayout
     log4perl.appender.A1.layout.ConversionPattern=%d %-5p %c - %m%n
     log4perl.logger.com.foo=WARN
 
 This defines two loggers: The root logger and the C<com.foo> logger.
 The root logger is easily triggered by debug-messages, 
 but the C<com.foo> logger makes sure that messages issued within
 the C<Com::Foo> component and below are only forwarded to the appender
 if they're of priority I<warning> or higher. 
 
 Note that the C<com.foo> logger doesn't define an appender. Therefore,
 it will just propagate the message up the hierarchy until the root logger
 picks it up and forwards it to the one and only appender of the root
 category, using the format defined for it.
 
 Third example:
 
     log4j.rootLogger=DEBUG, stdout, R
     log4j.appender.stdout=org.apache.log4j.ConsoleAppender
     log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
     log4j.appender.stdout.layout.ConversionPattern=%5p (%F:%L) - %m%n
     log4j.appender.R=org.apache.log4j.RollingFileAppender
     log4j.appender.R.File=example.log
     log4j.appender.R.layout=org.apache.log4j.PatternLayout
     log4j.appender.R.layout.ConversionPattern=%p %c - %m%n
 
 The root logger defines two appenders here: C<stdout>, which uses 
 C<org.apache.log4j.ConsoleAppender> (ultimately mapped by C<Log::Log4perl>
 to L<Log::Log4perl::Appender::Screen>) to write to the screen. And
 C<R>, a C<org.apache.log4j.RollingFileAppender> 
 (mapped by C<Log::Log4perl> to 
 L<Log::Dispatch::FileRotate> with the C<File> attribute specifying the
 log file.
 
 See L<Log::Log4perl::Config> for more examples and syntax explanations.
 
 =head2 Log Layouts
 
 If the logging engine passes a message to an appender, because it thinks
 it should be logged, the appender doesn't just
 write it out haphazardly. There's ways to tell the appender how to format
 the message and add all sorts of interesting data to it: The date and
 time when the event happened, the file, the line number, the
 debug level of the logger and others.
 
 There's currently two layouts defined in C<Log::Log4perl>: 
 C<Log::Log4perl::Layout::SimpleLayout> and
 C<Log::Log4perl::Layout::PatternLayout>:
 
 =over 4 
 
 =item C<Log::Log4perl::SimpleLayout> 
 
 formats a message in a simple
 way and just prepends it by the debug level and a hyphen:
 C<"$level - $message>, for example C<"FATAL - Can't open password file">.
 
 =item C<Log::Log4perl::Layout::PatternLayout> 
 
 on the other hand is very powerful and 
 allows for a very flexible format in C<printf>-style. The format
 string can contain a number of placeholders which will be
 replaced by the logging engine when it's time to log the message:
 
     %c Category of the logging event.
     %C Fully qualified package (or class) name of the caller
     %d Current date in yyyy/MM/dd hh:mm:ss format
     %F File where the logging event occurred
     %H Hostname (if Sys::Hostname is available)
     %l Fully qualified name of the calling method followed by the
        callers source the file name and line number between 
        parentheses.
     %L Line number within the file where the log statement was issued
     %m The message to be logged
     %m{chomp} The message to be logged, stripped off a trailing newline
     %M Method or function where the logging request was issued
     %n Newline (OS-independent)
     %p Priority of the logging event
     %P pid of the current process
     %r Number of milliseconds elapsed from program start to logging 
        event
     %R Number of milliseconds elapsed from last logging event to
        current logging event 
     %T A stack trace of functions called
     %x The topmost NDC (see below)
     %X{key} The entry 'key' of the MDC (see below)
     %% A literal percent (%) sign
 
 NDC and MDC are explained in L<"Nested Diagnostic Context (NDC)">
 and L<"Mapped Diagnostic Context (MDC)">.
 
 Also, C<%d> can be fine-tuned to display only certain characteristics
 of a date, according to the SimpleDateFormat in the Java World
 (L<http://java.sun.com/j2se/1.3/docs/api/java/text/SimpleDateFormat.html>)
 
 In this way, C<%d{HH:mm}> displays only hours and minutes of the current date,
 while C<%d{yy, EEEE}> displays a two-digit year, followed by a spelled-out
 (like C<Wednesday>). 
 
 Similar options are available for shrinking the displayed category or
 limit file/path components, C<%F{1}> only displays the source file I<name>
 without any path components while C<%F> logs the full path. %c{2} only
 logs the last two components of the current category, C<Foo::Bar::Baz> 
 becomes C<Bar::Baz> and saves space.
 
 If those placeholders aren't enough, then you can define your own right in
 the config file like this:
 
     log4perl.PatternLayout.cspec.U = sub { return "UID $<" }
 
 See L<Log::Log4perl::Layout::PatternLayout> for further details on
 customized specifiers.
 
 Please note that the subroutines you're defining in this way are going
 to be run in the C<main> namespace, so be sure to fully qualify functions
 and variables if they're located in different packages.
 
 SECURITY NOTE: this feature means arbitrary perl code can be embedded in the 
 config file.  In the rare case where the people who have access to your config 
 file are different from the people who write your code and shouldn't have 
 execute rights, you might want to call
 
     Log::Log4perl::Config->allow_code(0);
 
 before you call init(). Alternatively you can supply a restricted set of
 Perl opcodes that can be embedded in the config file as described in
 L<"Restricting what Opcodes can be in a Perl Hook">.
 
 =back
 
 All placeholders are quantifiable, just like in I<printf>. Following this 
 tradition, C<%-20c> will reserve 20 chars for the category and left-justify it.
 
 For more details on logging and how to use the flexible and the simple
 format, check out the original C<log4j> website under
 
 L<SimpleLayout|http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/SimpleLayout.html>
 and
 L<PatternLayout|http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/PatternLayout.html>
 
 =head2 Penalties
 
 Logging comes with a price tag. C<Log::Log4perl> has been optimized
 to allow for maximum performance, both with logging enabled and disabled.
 
 But you need to be aware that there's a small hit every time your code
 encounters a log statement -- no matter if logging is enabled or not. 
 C<Log::Log4perl> has been designed to keep this so low that it will
 be unnoticeable to most applications.
 
 Here's a couple of tricks which help C<Log::Log4perl> to avoid
 unnecessary delays:
 
 You can save serious time if you're logging something like
 
         # Expensive in non-debug mode!
     for (@super_long_array) {
         $logger->debug("Element: $_");
     }
 
 and C<@super_long_array> is fairly big, so looping through it is pretty
 expensive. Only you, the programmer, knows that going through that C<for>
 loop can be skipped entirely if the current logging level for the 
 actual component is higher than C<debug>.
 In this case, use this instead:
 
         # Cheap in non-debug mode!
     if($logger->is_debug()) {
         for (@super_long_array) {
             $logger->debug("Element: $_");
         }
     }
 
 If you're afraid that generating the parameters to the
 logging function is fairly expensive, use closures:
 
         # Passed as subroutine ref
     use Data::Dumper;
     $logger->debug(sub { Dumper($data) } );
 
 This won't unravel C<$data> via Dumper() unless it's actually needed
 because it's logged. 
 
 Also, Log::Log4perl lets you specify arguments
 to logger functions in I<message output filter syntax>:
 
     $logger->debug("Structure: ",
                    { filter => \&Dumper,
                      value  => $someref });
 
 In this way, shortly before Log::Log4perl sending the
 message out to any appenders, it will be searching all arguments for
 hash references and treat them in a special way:
 
 It will invoke the function given as a reference with the C<filter> key
 (C<Data::Dumper::Dumper()>) and pass it the value that came with
 the key named C<value> as an argument.
 The anonymous hash in the call above will be replaced by the return 
 value of the filter function.
 
 =head1 Categories
 
 B<Categories are also called "Loggers" in Log4perl, both refer
 to the same thing and these terms are used interchangeably.>
 C<Log::Log4perl> uses I<categories> to determine if a log statement in
 a component should be executed or suppressed at the current logging level.
 Most of the time, these categories are just the classes the log statements
 are located in:
 
     package Candy::Twix;
 
     sub new { 
         my $logger = Log::Log4perl->get_logger("Candy::Twix");
         $logger->debug("Creating a new Twix bar");
         bless {}, shift;
     }
  
     # ...
 
     package Candy::Snickers;
 
     sub new { 
         my $logger = Log::Log4perl->get_logger("Candy.Snickers");
         $logger->debug("Creating a new Snickers bar");
         bless {}, shift;
     }
 
     # ...
 
     package main;
     Log::Log4perl->init("mylogdefs.conf");
 
         # => "LOG> Creating a new Snickers bar"
     my $first = Candy::Snickers->new();
         # => "LOG> Creating a new Twix bar"
     my $second = Candy::Twix->new();
 
 Note that you can separate your category hierarchy levels
 using either dots like
 in Java (.) or double-colons (::) like in Perl. Both notations
 are equivalent and are handled the same way internally.
 
 However, categories are just there to make
 use of inheritance: if you invoke a logger in a sub-category, 
 it will bubble up the hierarchy and call the appropriate appenders.
 Internally, categories are not related to the class hierarchy of the program
 at all -- they're purely virtual. You can use arbitrary categories --
 for example in the following program, which isn't oo-style, but
 procedural:
 
     sub print_portfolio {
 
         my $log = Log::Log4perl->get_logger("user.portfolio");
         $log->debug("Quotes requested: @_");
 
         for(@_) {
             print "$_: ", get_quote($_), "\n";
         }
     }
 
     sub get_quote {
 
         my $log = Log::Log4perl->get_logger("internet.quotesystem");
         $log->debug("Fetching quote: $_[0]");
 
         return yahoo_quote($_[0]);
     }
 
 The logger in first function, C<print_portfolio>, is assigned the
 (virtual) C<user.portfolio> category. Depending on the C<Log4perl>
 configuration, this will either call a C<user.portfolio> appender,
 a C<user> appender, or an appender assigned to root -- without
 C<user.portfolio> having any relevance to the class system used in 
 the program.
 The logger in the second function adheres to the 
 C<internet.quotesystem> category -- again, maybe because it's bundled 
 with other Internet functions, but not because there would be
 a class of this name somewhere.
 
 However, be careful, don't go overboard: if you're developing a system
 in object-oriented style, using the class hierarchy is usually your best
 choice. Think about the people taking over your code one day: The
 class hierarchy is probably what they know right up front, so it's easy
 for them to tune the logging to their needs.
 
 =head2 Turn off a component
 
 C<Log4perl> doesn't only allow you to selectively switch I<on> a category
 of log messages, you can also use the mechanism to selectively I<disable>
 logging in certain components whereas logging is kept turned on in higher-level
 categories. This mechanism comes in handy if you find that while bumping 
 up the logging level of a high-level (i. e. close to root) category, 
 that one component logs more than it should, 
 
 Here's how it works: 
 
     ############################################################
     # Turn off logging in a lower-level category while keeping
     # it active in higher-level categories.
     ############################################################
     log4perl.rootLogger=DEBUG, LOGFILE
     log4perl.logger.deep.down.the.hierarchy = ERROR, LOGFILE
 
     # ... Define appenders ...
 
 This way, log messages issued from within 
 C<Deep::Down::The::Hierarchy> and below will be
 logged only if they're C<ERROR> or worse, while in all other system components
 even C<DEBUG> messages will be logged.
 
 =head2 Return Values
 
 All logging methods return values indicating if their message
 actually reached one or more appenders. If the message has been
 suppressed because of level constraints, C<undef> is returned.
 
 For example,
 
     my $ret = $logger->info("Message");
 
 will return C<undef> if the system debug level for the current category
 is not C<INFO> or more permissive. 
 If Log::Log4perl
 forwarded the message to one or more appenders, the number of appenders
 is returned.
 
 If appenders decide to veto on the message with an appender threshold,
 the log method's return value will have them excluded. This means that if
 you've got one appender holding an appender threshold and you're 
 logging a message
 which passes the system's log level hurdle but not the appender threshold,
 C<0> will be returned by the log function.
 
 The bottom line is: Logging functions will return a I<true> value if the message
 made it through to one or more appenders and a I<false> value if it didn't.
 This allows for constructs like
 
     $logger->fatal("@_") or print STDERR "@_\n";
 
 which will ensure that the fatal message isn't lost
 if the current level is lower than FATAL or printed twice if 
 the level is acceptable but an appender already points to STDERR.
 
 =head2 Pitfalls with Categories
 
 Be careful with just blindly reusing the system's packages as
 categories. If you do, you'll get into trouble with inherited methods.
 Imagine the following class setup:
 
     use Log::Log4perl;
 
     ###########################################
     package Bar;
     ###########################################
     sub new {
         my($class) = @_;
         my $logger = Log::Log4perl::get_logger(__PACKAGE__);
         $logger->debug("Creating instance");
         bless {}, $class;
     }
     ###########################################
     package Bar::Twix;
     ###########################################
     our @ISA = qw(Bar);
 
     ###########################################
     package main;
     ###########################################
     Log::Log4perl->init(\ qq{
     log4perl.category.Bar.Twix = DEBUG, Screen
     log4perl.appender.Screen = Log::Log4perl::Appender::Screen
     log4perl.appender.Screen.layout = SimpleLayout
     });
 
     my $bar = Bar::Twix->new();
 
 C<Bar::Twix> just inherits everything from C<Bar>, including the constructor
 C<new()>.
 Contrary to what you might be thinking at first, this won't log anything. 
 Reason for this is the C<get_logger()> call in package C<Bar>, which
 will always get a logger of the C<Bar> category, even if we call C<new()> via
 the C<Bar::Twix> package, which will make perl go up the inheritance 
 tree to actually execute C<Bar::new()>. Since we've only defined logging
 behaviour for C<Bar::Twix> in the configuration file, nothing will happen.
 
 This can be fixed by changing the C<get_logger()> method in C<Bar::new()>
 to obtain a logger of the category matching the
 I<actual> class of the object, like in
 
         # ... in Bar::new() ...
     my $logger = Log::Log4perl::get_logger( $class );
 
 In a method other than the constructor, the class name of the actual
 object can be obtained by calling C<ref()> on the object reference, so
 
     package BaseClass;
     use Log::Log4perl qw( get_logger );
 
     sub new { 
         bless {}, shift; 
     }
 
     sub method {
         my( $self ) = @_;
 
         get_logger( ref $self )->debug( "message" );
     }
 
     package SubClass;
     our @ISA = qw(BaseClass);
 
 is the recommended pattern to make sure that 
 
     my $sub = SubClass->new();
     $sub->meth();
 
 starts logging if the C<"SubClass"> category 
 (and not the C<"BaseClass"> category has logging enabled at the DEBUG level.
 
 =head2 Initialize once and only once
 
 It's important to realize that Log::Log4perl gets initialized once and only
 once, typically at the start of a program or system. Calling C<init()>
 more than once will cause it to clobber the existing configuration and
 I<replace> it by the new one.
 
 If you're in a traditional CGI environment, where every request is
 handled by a new process, calling C<init()> every time is fine. In
 persistent environments like C<mod_perl>, however, Log::Log4perl
 should be initialized either at system startup time (Apache offers
 startup handlers for that) or via
 
         # Init or skip if already done
     Log::Log4perl->init_once($conf_file);
 
 C<init_once()> is identical to C<init()>, just with the exception
 that it will leave a potentially existing configuration alone and 
 will only call C<init()> if Log::Log4perl hasn't been initialized yet.
 
 If you're just curious if Log::Log4perl has been initialized yet, the
 check
 
     if(Log::Log4perl->initialized()) {
         # Yes, Log::Log4perl has already been initialized
     } else {
         # No, not initialized yet ...
     }
 
 can be used.
 
 If you're afraid that the components of your system are stepping on 
 each other's toes or if you are thinking that different components should
 initialize Log::Log4perl separately, try to consolidate your system
 to use a centralized Log4perl configuration file and use 
 Log4perl's I<categories> to separate your components.
 
 =head2 Custom Filters
 
 Log4perl allows the use of customized filters in its appenders
 to control the output of messages. These filters might grep for
 certain text chunks in a message, verify that its priority
 matches or exceeds a certain level or that this is the 10th
 time the same message has been submitted -- and come to a log/no log 
 decision based upon these circumstantial facts.
 
 Check out L<Log::Log4perl::Filter> for detailed instructions 
 on how to use them.
 
 =head2 Performance
 
 The performance of Log::Log4perl calls obviously depends on a lot of things.
 But to give you a general idea, here's some rough numbers:
 
 On a Pentium 4 Linux box at 2.4 GHz, you'll get through
 
 =over 4
 
 =item *
 
 500,000 suppressed log statements per second
 
 =item *
 
 30,000 logged messages per second (using an in-memory appender)
 
 =item *
 
 init_and_watch delay mode: 300,000 suppressed, 30,000 logged.
 init_and_watch signal mode: 450,000 suppressed, 30,000 logged.
 
 =back
 
 Numbers depend on the complexity of the Log::Log4perl configuration.
 For a more detailed benchmark test, check the C<docs/benchmark.results.txt> 
 document in the Log::Log4perl distribution.
 
 =head1 Cool Tricks
 
 Here's a collection of useful tricks for the advanced C<Log::Log4perl> user.
 For more, check the FAQ, either in the distribution 
 (L<Log::Log4perl::FAQ>) or on L<http://log4perl.sourceforge.net>.
 
 =head2 Shortcuts
 
 When getting an instance of a logger, instead of saying
 
     use Log::Log4perl;
     my $logger = Log::Log4perl->get_logger();
 
 it's often more convenient to import the C<get_logger> method from 
 C<Log::Log4perl> into the current namespace:
 
     use Log::Log4perl qw(get_logger);
     my $logger = get_logger();
 
 Please note this difference: To obtain the root logger, please use
 C<get_logger("")>, call it without parameters (C<get_logger()>), you'll
 get the logger of a category named after the current package. 
 C<get_logger()> is equivalent to C<get_logger(__PACKAGE__)>.
 
 =head2 Alternative initialization
 
 Instead of having C<init()> read in a configuration file by specifying
 a file name or passing it a reference to an open filehandle
 (C<Log::Log4perl-E<gt>init( \*FILE )>),
 you can 
 also pass in a reference to a string, containing the content of
 the file:
 
     Log::Log4perl->init( \$config_text );
 
 Also, if you've got the C<name=value> pairs of the configuration in
 a hash, you can just as well initialize C<Log::Log4perl> with
 a reference to it:
 
     my %key_value_pairs = (
         "log4perl.rootLogger"       => "ERROR, LOGFILE",
         "log4perl.appender.LOGFILE" => "Log::Log4perl::Appender::File",
         ...
     );
 
     Log::Log4perl->init( \%key_value_pairs );
 
 Or also you can use a URL, see below:
 
 =head2 Using LWP to parse URLs
 
 (This section borrowed from XML::DOM::Parser by T.J. Mather).
 
 The init() function now also supports URLs, e.g. I<http://www.erols.com/enno/xsa.xml>.
 It uses LWP to download the file and then calls parse() on the resulting string.
 By default it will use a L<LWP::UserAgent> that is created as follows:
 
  use LWP::UserAgent;
  $LWP_USER_AGENT = LWP::UserAgent->new;
  $LWP_USER_AGENT->env_proxy;
 
 Note that env_proxy reads proxy settings from environment variables, which is what I need to
 do to get thru our firewall. If you want to use a different LWP::UserAgent, you can 
 set it with
 
     Log::Log4perl::Config::set_LWP_UserAgent($my_agent);
 
 Currently, LWP is used when the filename (passed to parsefile) starts with one of
 the following URL schemes: http, https, ftp, wais, gopher, or file (followed by a colon.)
 
 Don't use this feature with init_and_watch().
 
 =head2 Automatic reloading of changed configuration files
 
 Instead of just statically initializing Log::Log4perl via
 
     Log::Log4perl->init($conf_file);
 
 there's a way to have Log::Log4perl periodically check for changes
 in the configuration and reload it if necessary:
 
     Log::Log4perl->init_and_watch($conf_file, $delay);
 
 In this mode, Log::Log4perl will examine the configuration file 
 C<$conf_file> every C<$delay> seconds for changes via the file's
 last modification timestamp. If the file has been updated, it will
 be reloaded and replace the current Log::Log4perl configuration.
 
 The way this works is that with every logger function called 
 (debug(), is_debug(), etc.), Log::Log4perl will check if the delay 
 interval has expired. If so, it will run a -M file check on the 
 configuration file. If its timestamp has been modified, the current
 configuration will be dumped and new content of the file will be
 loaded.
 
 This convenience comes at a price, though: Calling time() with every
 logging function call, especially the ones that are "suppressed" (!), 
 will slow down these Log4perl calls by about 40%.
 
 To alleviate this performance hit a bit, C<init_and_watch()> 
 can be configured to listen for a Unix signal to reload the 
 configuration instead:
 
     Log::Log4perl->init_and_watch($conf_file, 'HUP');
 
 This will set up a signal handler for SIGHUP and reload the configuration
 if the application receives this signal, e.g. via the C<kill> command:
 
     kill -HUP pid
 
 where C<pid> is the process ID of the application. This will bring you back
 to about 85% of Log::Log4perl's normal execution speed for suppressed
 statements. For details, check out L<"Performance">. For more info
 on the signal handler, look for L<Log::Log4perl::Config::Watch/"SIGNAL MODE">.
 
 If you have a somewhat long delay set between physical config file checks
 or don't want to use the signal associated with the config file watcher,
 you can trigger a configuration reload at the next possible time by
 calling C<Log::Log4perl::Config-E<gt>watcher-E<gt>force_next_check()>.
 
 One thing to watch out for: If the configuration file contains a syntax
 or other fatal error, a running application will stop with C<die> if
 this damaged configuration will be loaded during runtime, triggered
 either by a signal or if the delay period expired and the change is 
 detected. This behaviour might change in the future.
 
 To allow the application to intercept and control a configuration reload
 in init_and_watch mode, a callback can be specified:
 
     Log::Log4perl->init_and_watch($conf_file, 10, { 
             preinit_callback => \&callback });
 
 If Log4perl determines that the configuration needs to be reloaded, it will
 call the C<preinit_callback> function without parameters. If the callback
 returns a true value, Log4perl will proceed and reload the configuration.  If
 the callback returns a false value, Log4perl will keep the old configuration
 and skip reloading it until the next time around.  Inside the callback, an
 application can run all kinds of checks, including accessing the configuration
 file, which is available via
 C<Log::Log4perl::Config-E<gt>watcher()-E<gt>file()>.
 
 =head2 Variable Substitution
 
 To avoid having to retype the same expressions over and over again,
 Log::Log4perl's configuration files support simple variable substitution.
 New variables are defined simply by adding
 
     varname = value
 
 lines to the configuration file before using
 
     ${varname}
 
 afterwards to recall the assigned values. Here's an example:
 
     layout_class   = Log::Log4perl::Layout::PatternLayout
     layout_pattern = %d %F{1} %L> %m %n
     
     log4perl.category.Bar.Twix = WARN, Logfile, Screen
 
     log4perl.appender.Logfile  = Log::Log4perl::Appender::File
     log4perl.appender.Logfile.filename = test.log
     log4perl.appender.Logfile.layout = ${layout_class}
     log4perl.appender.Logfile.layout.ConversionPattern = ${layout_pattern}
 
     log4perl.appender.Screen  = Log::Log4perl::Appender::Screen
     log4perl.appender.Screen.layout = ${layout_class}
     log4perl.appender.Screen.layout.ConversionPattern = ${layout_pattern}
 
 This is a convenient way to define two appenders with the same layout 
 without having to retype the pattern definitions.
 
 Variable substitution via C<${varname}> 
 will first try to find an explicitly defined 
 variable. If that fails, it will check your shell's environment
 for a variable of that name. If that also fails, the program will C<die()>.
 
 =head2 Perl Hooks in the Configuration File
 
 If some of the values used in the Log4perl configuration file 
 need to be dynamically modified by the program, use Perl hooks:
 
     log4perl.appender.File.filename = \
         sub { return getLogfileName(); }
 
 Each value starting with the string C<sub {...> is interpreted as Perl code to
 be executed at the time the application parses the configuration
 via C<Log::Log4perl::init()>. The return value of the subroutine
 is used by Log::Log4perl as the configuration value.
 
 The Perl code is executed in the C<main> package, functions in
 other packages have to be called in fully-qualified notation.
 
 Here's another example, utilizing an environment variable as a
 username for a DBI appender:
 
     log4perl.appender.DB.username = \
         sub { $ENV{DB_USER_NAME } }
 
 However, please note the difference between these code snippets and those
 used for user-defined conversion specifiers as discussed in
 L<Log::Log4perl::Layout::PatternLayout>: 
 While the snippets above are run I<once>
 when C<Log::Log4perl::init()> is called, the conversion specifier
 snippets are executed I<each time> a message is rendered according to
 the PatternLayout.
 
 SECURITY NOTE: this feature means arbitrary perl code can be embedded in the 
 config file.  In the rare case where the people who have access to your config 
 file are different from the people who write your code and shouldn't have 
 execute rights, you might want to set
 
     Log::Log4perl::Config->allow_code(0);
 
 before you call init().  Alternatively you can supply a restricted set of
 Perl opcodes that can be embedded in the config file as described in
 L<"Restricting what Opcodes can be in a Perl Hook">.
 
 =head2 Restricting what Opcodes can be in a Perl Hook
 
 The value you pass to Log::Log4perl::Config->allow_code() determines whether
 the code that is embedded in the config file is eval'd unrestricted, or
 eval'd in a Safe compartment.  By default, a value of '1' is assumed,
 which does a normal 'eval' without any restrictions. A value of '0' 
 however prevents any embedded code from being evaluated.
 
 If you would like fine-grained control over what can and cannot be included
 in embedded code, then please utilize the following methods:
 
  Log::Log4perl::Config->allow_code( $allow );
  Log::Log4perl::Config->allowed_code_ops($op1, $op2, ... );
  Log::Log4perl::Config->vars_shared_with_safe_compartment( [ \%vars | $package, \@vars ] );
  Log::Log4perl::Config->allowed_code_ops_convenience_map( [ \%map | $name, \@mask ] );
 
 Log::Log4perl::Config-E<gt>allowed_code_ops() takes a list of opcode masks
 that are allowed to run in the compartment.  The opcode masks must be
 specified as described in L<Opcode>:
 
  Log::Log4perl::Config->allowed_code_ops(':subprocess');
 
 This example would allow Perl operations like backticks, system, fork, and
 waitpid to be executed in the compartment.  Of course, you probably don't
 want to use this mask -- it would allow exactly what the Safe compartment is
 designed to prevent.
 
 Log::Log4perl::Config-E<gt>vars_shared_with_safe_compartment() 
 takes the symbols which
 should be exported into the Safe compartment before the code is evaluated. 
 The keys of this hash are the package names that the symbols are in, and the
 values are array references to the literal symbol names.  For convenience,
 the default settings export the '%ENV' hash from the 'main' package into the
 compartment:
 
  Log::Log4perl::Config->vars_shared_with_safe_compartment(
    main => [ '%ENV' ],
  );
 
 Log::Log4perl::Config-E<gt>allowed_code_ops_convenience_map() is an accessor
 method to a map of convenience names to opcode masks. At present, the
 following convenience names are defined:
 
  safe        = [ ':browse' ]
  restrictive = [ ':default' ]
 
 For convenience, if Log::Log4perl::Config-E<gt>allow_code() is called with a
 value which is a key of the map previously defined with
 Log::Log4perl::Config-E<gt>allowed_code_ops_convenience_map(), then the
 allowed opcodes are set according to the value defined in the map. If this
 is confusing, consider the following:
 
  use Log::Log4perl;
  
  my $config = <<'END';
   log4perl.logger = INFO, Main
   log4perl.appender.Main = Log::Log4perl::Appender::File
   log4perl.appender.Main.filename = \
       sub { "example" . getpwuid($<) . ".log" }
   log4perl.appender.Main.layout = Log::Log4perl::Layout::SimpleLayout
  END
  
  $Log::Log4perl::Config->allow_code('restrictive');
  Log::Log4perl->init( \$config );       # will fail
  $Log::Log4perl::Config->allow_code('safe');
  Log::Log4perl->init( \$config );       # will succeed
 
 The reason that the first call to -E<gt>init() fails is because the
 'restrictive' name maps to an opcode mask of ':default'.  getpwuid() is not
 part of ':default', so -E<gt>init() fails.  The 'safe' name maps to an opcode
 mask of ':browse', which allows getpwuid() to run, so -E<gt>init() succeeds.
 
 allowed_code_ops_convenience_map() can be invoked in several ways:
 
 =over 4
 
 =item allowed_code_ops_convenience_map()
 
 Returns the entire convenience name map as a hash reference in scalar
 context or a hash in list context.
 
 =item allowed_code_ops_convenience_map( \%map )
 
 Replaces the entire convenience name map with the supplied hash reference.
 
 =item allowed_code_ops_convenience_map( $name )
 
 Returns the opcode mask for the given convenience name, or undef if no such
 name is defined in the map.
 
 =item allowed_code_ops_convenience_map( $name, \@mask )
 
 Adds the given name/mask pair to the convenience name map.  If the name
 already exists in the map, it's value is replaced with the new mask.
 
 =back
 
 as can vars_shared_with_safe_compartment():
 
 =over 4
 
 =item vars_shared_with_safe_compartment()
 
 Return the entire map of packages to variables as a hash reference in scalar
 context or a hash in list context.
 
 =item vars_shared_with_safe_compartment( \%packages )
 
 Replaces the entire map of packages to variables with the supplied hash
 reference.
 
 =item vars_shared_with_safe_compartment( $package )
 
 Returns the arrayref of variables to be shared for a specific package.
 
 =item vars_shared_with_safe_compartment( $package, \@vars )
 
 Adds the given package / varlist pair to the map.  If the package already
 exists in the map, it's value is replaced with the new arrayref of variable
 names.
 
 =back
 
 For more information on opcodes and Safe Compartments, see L<Opcode> and
 L<Safe>.
 
 =head2 Changing the Log Level on a Logger
 
 Log4perl provides some internal functions for quickly adjusting the
 log level from within a running Perl program. 
 
 Now, some people might
 argue that you should adjust your levels from within an external 
 Log4perl configuration file, but Log4perl is everybody's darling.
 
 Typically run-time adjusting of levels is done
 at the beginning, or in response to some external input (like a
 "more logging" runtime command for diagnostics).
 
 You get the log level from a logger object with:
 
     $current_level = $logger->level();
 
 and you may set it with the same method, provided you first
 imported the log level constants, with:
 
     use Log::Log4perl::Level;
 
 Then you can set the level on a logger to one of the constants,
 
     $logger->level($ERROR); # one of DEBUG, INFO, WARN, ERROR, FATAL
 
 To B<increase> the level of logging currently being done, use:
 
     $logger->more_logging($delta);
 
 and to B<decrease> it, use:
 
     $logger->less_logging($delta);
 
 $delta must be a positive integer (for now, we may fix this later ;).
 
 There are also two equivalent functions:
 
     $logger->inc_level($delta);
     $logger->dec_level($delta);
 
 They're included to allow you a choice in readability. Some folks
 will prefer more/less_logging, as they're fairly clear in what they
 do, and allow the programmer not to worry too much about what a Level
 is and whether a higher Level means more or less logging. However,
 other folks who do understand and have lots of code that deals with
 levels will probably prefer the inc_level() and dec_level() methods as
 they want to work with Levels and not worry about whether that means
 more or less logging. :)
 
 That diatribe aside, typically you'll use more_logging() or inc_level()
 as such:
 
     my $v = 0; # default level of verbosity.
     
     GetOptions("v+" => \$v, ...);
 
     if( $v ) {
       $logger->more_logging($v); # inc logging level once for each -v in ARGV
     }
 
 =head2 Custom Log Levels
 
 First off, let me tell you that creating custom levels is heavily
 deprecated by the log4j folks. Indeed, instead of creating additional
 levels on top of the predefined DEBUG, INFO, WARN, ERROR and FATAL, 
 you should use categories to control the amount of logging smartly,
 based on the location of the log-active code in the system.
 
 Nevertheless, 
 Log4perl provides a nice way to create custom levels via the 
 create_custom_level() routine function. However, this must be done
 before the first call to init() or get_logger(). Say you want to create
 a NOTIFY logging level that comes after WARN (and thus before INFO).
 You'd do such as follows:
 
     use Log::Log4perl;
     use Log::Log4perl::Level;
 
     Log::Log4perl::Logger::create_custom_level("NOTIFY", "WARN");
 
 And that's it! create_custom_level() creates the following functions /
 variables for level FOO:
 
     $FOO_INT        # integer to use in L4p::Level::to_level()
     $logger->foo()  # log function to log if level = FOO
     $logger->is_foo()   # true if current level is >= FOO
 
 These levels can also be used in your
 config file, but note that your config file probably won't be
 portable to another log4perl or log4j environment unless you've
 made the appropriate mods there too.
 
 Since Log4perl translates log levels to syslog and Log::Dispatch if 
 their appenders are used, you may add mappings for custom levels as well:
 
   Log::Log4perl::Level::add_priority("NOTIFY", "WARN",
                                      $syslog_equiv, $log_dispatch_level);
 
 For example, if your new custom "NOTIFY" level is supposed to map 
 to syslog level 2 ("LOG_NOTICE") and Log::Dispatch level 2 ("notice"), use:
 
   Log::Log4perl::Logger::create_custom_level("NOTIFY", "WARN", 2, 2);
 
 =head2 System-wide log levels
 
 As a fairly drastic measure to decrease (or increase) the logging level
 all over the system with one single configuration option, use the C<threshold>
 keyword in the Log4perl configuration file:
 
     log4perl.threshold = ERROR
 
 sets the system-wide (or hierarchy-wide according to the log4j documentation)
 to ERROR and therefore deprives every logger in the system of the right 
 to log lower-prio messages.
 
 =head2 Easy Mode
 
 For teaching purposes (especially for [1]), I've put C<:easy> mode into 
 C<Log::Log4perl>, which just initializes a single root logger with a 
 defined priority and a screen appender including some nice standard layout:
 
     ### Initialization Section
     use Log::Log4perl qw(:easy);
     Log::Log4perl->easy_init($ERROR);  # Set priority of root logger to ERROR
 
     ### Application Section
     my $logger = get_logger();
     $logger->fatal("This will get logged.");
     $logger->debug("This won't.");
 
 This will dump something like
 
     2002/08/04 11:43:09 ERROR> script.pl:16 main::function - This will get logged.
 
 to the screen. While this has been proven to work well familiarizing people
 with C<Log::Logperl> slowly, effectively avoiding to clobber them over the 
 head with a 
 plethora of different knobs to fiddle with (categories, appenders, levels, 
 layout), the overall mission of C<Log::Log4perl> is to let people use
 categories right from the start to get used to the concept. So, let's keep
 this one fairly hidden in the man page (congrats on reading this far :).
 
 =head2 Stealth loggers
 
 Sometimes, people are lazy. If you're whipping up a 50-line script and want 
 the comfort of Log::Log4perl without having the burden of carrying a
 separate log4perl.conf file or a 5-liner defining that you want to append
 your log statements to a file, you can use the following features:
 
     use Log::Log4perl qw(:easy);
 
     Log::Log4perl->easy_init( { level   => $DEBUG,
                                 file    => ">>test.log" } );
 
         # Logs to test.log via stealth logger
     DEBUG("Debug this!");
     INFO("Info this!");
     WARN("Warn this!");
     ERROR("Error this!");
 
     some_function();
 
     sub some_function {
             # Same here
         FATAL("Fatal this!");
     }
 
 In C<:easy> mode, C<Log::Log4perl> will instantiate a I<stealth logger>
 and introduce the
 convenience functions C<TRACE>, C<DEBUG()>, C<INFO()>, C<WARN()>, 
 C<ERROR()>, C<FATAL()>, and C<ALWAYS> into the package namespace.
 These functions simply take messages as
 arguments and forward them to the stealth loggers methods (C<debug()>,
 C<info()>, and so on).
 
 If a message should never be blocked, regardless of the log level,
 use the C<ALWAYS> function which corresponds to a log level of C<OFF>:
 
     ALWAYS "This will be printed regardless of the log level";
 
 The C<easy_init> method can be called with a single level value to
 create a STDERR appender and a root logger as in
 
     Log::Log4perl->easy_init($DEBUG);
 
 or, as shown below (and in the example above) 
 with a reference to a hash, specifying values
 for C<level> (the logger's priority), C<file> (the appender's data sink),
 C<category> (the logger's category and C<layout> for the appender's 
 pattern layout specification.
 All key-value pairs are optional, they 
 default to C<$DEBUG> for C<level>, C<STDERR> for C<file>,
 C<""> (root category) for C<category> and 
 C<%d %m%n> for C<layout>:
 
     Log::Log4perl->easy_init( { level    => $DEBUG,
                                 file     => ">test.log",
                                 utf8     => 1,
                                 category => "Bar::Twix",
                                 layout   => '%F{1}-%L-%M: %m%n' } );
 
 The C<file> parameter takes file names preceded by C<"E<gt>">
 (overwrite) and C<"E<gt>E<gt>"> (append) as arguments. This will
 cause C<Log::Log4perl::Appender::File> appenders to be created behind
 the scenes. Also the keywords C<STDOUT> and C<STDERR> (no C<E<gt>> or
 C<E<gt>E<gt>>) are recognized, which will utilize and configure
 C<Log::Log4perl::Appender::Screen> appropriately. The C<utf8> flag,
 if set to a true value, runs a C<binmode> command on the file handle
 to establish a utf8 line discipline on the file, otherwise you'll get a
 'wide character in print' warning message and probably not what you'd
 expect as output.
 
 The stealth loggers can be used in different packages, you just need to make
 sure you're calling the "use" function in every package you're using
 C<Log::Log4perl>'s easy services:
 
     package Bar::Twix;
     use Log::Log4perl qw(:easy);
     sub eat { DEBUG("Twix mjam"); }
 
     package Bar::Mars;
     use Log::Log4perl qw(:easy);
     sub eat { INFO("Mars mjam"); }
 
     package main;
 
     use Log::Log4perl qw(:easy);
 
     Log::Log4perl->easy_init( { level    => $DEBUG,
                                 file     => ">>test.log",
                                 category => "Bar::Twix",
                                 layout   => '%F{1}-%L-%M: %m%n' },
                               { level    => $DEBUG,
                                 file     => "STDOUT",
                                 category => "Bar::Mars",
                                 layout   => '%m%n' },
                             );
     Bar::Twix::eat();
     Bar::Mars::eat();
 
 As shown above, C<easy_init()> will take any number of different logger 
 definitions as hash references.
 
 Also, stealth loggers feature the functions C<LOGWARN()>, C<LOGDIE()>,
 and C<LOGEXIT()>,
 combining a logging request with a subsequent Perl warn() or die() or exit()
 statement. So, for example
 
     if($all_is_lost) {
         LOGDIE("Terrible Problem");
     }
 
 will log the message if the package's logger is at least C<FATAL> but
 C<die()> (including the traditional output to STDERR) in any case afterwards.
 
 See L<"Log and die or warn"> for the similar C<logdie()> and C<logwarn()>
 functions of regular (i.e non-stealth) loggers.
 
 Similarily, C<LOGCARP()>, C<LOGCLUCK()>, C<LOGCROAK()>, and C<LOGCONFESS()>
 are provided in C<:easy> mode, facilitating the use of C<logcarp()>,
 C<logcluck()>, C<logcroak()>, and C<logconfess()> with stealth loggers.
 
 B<When using Log::Log4perl in easy mode, 
 please make sure you understand the implications of 
 L</"Pitfalls with Categories">>.
 
 By the way, these convenience functions perform exactly as fast as the 
 standard Log::Log4perl logger methods, there's I<no> performance penalty
 whatsoever.
 
 =head2 Nested Diagnostic Context (NDC)
 
 If you find that your application could use a global (thread-specific)
 data stack which your loggers throughout the system have easy access to,
 use Nested Diagnostic Contexts (NDCs). Also check out
 L<"Mapped Diagnostic Context (MDC)">, this might turn out to be even more
 useful.
 
 For example, when handling a request of a web client, it's probably 
 useful to have the user's IP address available in all log statements
 within code dealing with this particular request. Instead of passing
 this piece of data around between your application functions, you can just
 use the global (but thread-specific) NDC mechanism. It allows you
 to push data pieces (scalars usually) onto its stack via
 
     Log::Log4perl::NDC->push("San");
     Log::Log4perl::NDC->push("Francisco");
 
 and have your loggers retrieve them again via the "%x" placeholder in
 the PatternLayout. With the stack values above and a PatternLayout format
 like "%x %m%n", the call
 
     $logger->debug("rocks");
 
 will end up as 
 
     San Francisco rocks
 
 in the log appender.
 
 The stack mechanism allows for nested structures.
 Just make sure that at the end of the request, you either decrease the stack
 one by one by calling
 
     Log::Log4perl::NDC->pop();
     Log::Log4perl::NDC->pop();
 
 or clear out the entire NDC stack by calling
 
     Log::Log4perl::NDC->remove();
 
 Even if you should forget to do that, C<Log::Log4perl> won't grow the stack
 indefinitely, but limit it to a maximum, defined in C<Log::Log4perl::NDC>
 (currently 5). A call to C<push()> on a full stack will just replace
 the topmost element by the new value.
 
 Again, the stack is always available via the "%x" placeholder
 in the Log::Log4perl::Layout::PatternLayout class whenever a logger
 fires. It will replace "%x" by the blank-separated list of the
 values on the stack. It does that by just calling
 
     Log::Log4perl::NDC->get();
 
 internally. See details on how this standard log4j feature is implemented
 in L<Log::Log4perl::NDC>.
 
 =head2 Mapped Diagnostic Context (MDC)
 
 Just like the previously discussed NDC stores thread-specific
 information in a stack structure, the MDC implements a hash table
 to store key/value pairs in.
 
 The static method
 
     Log::Log4perl::MDC->put($key, $value);
 
 stores C<$value> under a key C<$key>, with which it can be retrieved later
 (possibly in a totally different part of the system) by calling
 the C<get> method:
 
     my $value = Log::Log4perl::MDC->get($key);
 
 If no value has been stored previously under C<$key>, the C<get> method
 will return C<undef>.
 
 Typically, MDC values are retrieved later on via the C<"%X{...}"> placeholder
 in C<Log::Log4perl::Layout::PatternLayout>. If the C<get()> method
 returns C<undef>, the placeholder will expand to the string C<[undef]>.
 
 An application taking a web request might store the remote host
 like
 
     Log::Log4perl::MDC->put("remote_host", $r->headers("HOST"));
 
 at its beginning and if the appender's layout looks something like
 
     log4perl.appender.Logfile.layout.ConversionPattern = %X{remote_host}: %m%n
 
 then a log statement like
 
    DEBUG("Content delivered");
 
 will log something like
 
    adsl-63.dsl.snf.pacbell.net: Content delivered 
 
 later on in the program.
 
 For details, please check L<Log::Log4perl::MDC>.
 
 =head2 Resurrecting hidden Log4perl Statements
 
 Sometimes scripts need to be deployed in environments without having
 Log::Log4perl installed yet. On the other hand, you don't want to
 live without your Log4perl statements -- they're gonna come in
 handy later.
 
 So, just deploy your script with Log4perl statements commented out with the
 pattern C<###l4p>, like in
 
     ###l4p DEBUG "It works!";
     # ...
     ###l4p INFO "Really!";
 
 If Log::Log4perl is available,
 use the C<:resurrect> tag to have Log4perl resurrect those buried 
 statements before the script starts running:
 
     use Log::Log4perl qw(:resurrect :easy);
 
     ###l4p Log::Log4perl->easy_init($DEBUG);
     ###l4p DEBUG "It works!";
     # ...
     ###l4p INFO "Really!";
 
 This will have a source filter kick in and indeed print
 
     2004/11/18 22:08:46 It works!
     2004/11/18 22:08:46 Really!
 
 In environments lacking Log::Log4perl, just comment out the first line
 and the script will run nevertheless (but of course without logging):
 
     # use Log::Log4perl qw(:resurrect :easy);
 
     ###l4p Log::Log4perl->easy_init($DEBUG);
     ###l4p DEBUG "It works!";
     # ...
     ###l4p INFO "Really!";
 
 because everything's a regular comment now. Alternatively, put the
 magic Log::Log4perl comment resurrection line into your shell's 
 PERL5OPT environment variable, e.g. for bash:
 
     set PERL5OPT=-MLog::Log4perl=:resurrect,:easy
     export PERL5OPT
 
 This will awaken the giant within an otherwise silent script like
 the following:
 
     #!/usr/bin/perl
 
     ###l4p Log::Log4perl->easy_init($DEBUG);
     ###l4p DEBUG "It works!";
 
 As of C<Log::Log4perl> 1.12, you can even force I<all> modules
 loaded by a script to have their hidden Log4perl statements
 resurrected. For this to happen, load C<Log::Log4perl::Resurrector>
 I<before> loading any modules:
 
     use Log::Log4perl qw(:easy);
     use Log::Log4perl::Resurrector;
 
     use Foobar; # All hidden Log4perl statements in here will
                 # be uncommented before Foobar gets loaded.
 
     Log::Log4perl->easy_init($DEBUG);
     ...
 
 Check the C<Log::Log4perl::Resurrector> manpage for more details.
 
 =head2 Access defined appenders
 
 All appenders defined in the configuration file or via Perl code
 can be retrieved by the C<appender_by_name()> class method. This comes
 in handy if you want to manipulate or query appender properties after
 the Log4perl configuration has been loaded via C<init()>.
 
 Note that internally, Log::Log4perl uses the C<Log::Log4perl::Appender> 
 wrapper class to control the real appenders (like 
 C<Log::Log4perl::Appender::File> or C<Log::Dispatch::FileRotate>). 
 The C<Log::Log4perl::Appender> class has an C<appender> attribute,
 pointing to the real appender.
 
 The reason for this is that external appenders like 
 C<Log::Dispatch::FileRotate> don't support all of Log::Log4perl's 
 appender control mechanisms (like appender thresholds).
 
 The previously mentioned method C<appender_by_name()> returns a
 reference to the I<real> appender object. If you want access to the
 wrapper class (e.g. if you want to modify the appender's threshold),
 use the hash C<$Log::Log4perl::Logger::APPENDER_BY_NAME{...}> instead,
 which holds references to all appender wrapper objects.
 
 =head2 Modify appender thresholds
 
 To set an appender's threshold, use its C<threshold()> method:
 
     $app->threshold( $FATAL );
 
 To conveniently adjust I<all> appender thresholds (e.g. because a script
 uses more_logging()), use
 
        # decrease thresholds of all appenders
     Log::Log4perl->appender_thresholds_adjust(-1);
 
 This will decrease the thresholds of all appenders in the system by
 one level, i.e. WARN becomes INFO, INFO becomes DEBUG, etc. To only modify 
 selected ones, use
 
        # decrease thresholds of all appenders
     Log::Log4perl->appender_thresholds_adjust(-1, ['AppName1', ...]);
 
 and pass the names of affected appenders in a ref to an array.
 
 =head1 Advanced configuration within Perl
 
 Initializing Log::Log4perl can certainly also be done from within Perl.
 At last, this is what C<Log::Log4perl::Config> does behind the scenes.
 Log::Log4perl's configuration file parsers are using a publically 
 available API to set up Log::Log4perl's categories, appenders and layouts.
 
 Here's an example on how to configure two appenders with the same layout
 in Perl, without using a configuration file at all:
 
   ########################
   # Initialization section
   ########################
   use Log::Log4perl;
   use Log::Log4perl::Layout;
   use Log::Log4perl::Level;
 
      # Define a category logger
   my $log = Log::Log4perl->get_logger("Foo::Bar");
 
      # Define a layout
   my $layout = Log::Log4perl::Layout::PatternLayout->new("[%r] %F %L %m%n");
 
      # Define a file appender
   my $file_appender = Log::Log4perl::Appender->new(
                           "Log::Log4perl::Appender::File",
                           name      => "filelog",
                           filename  => "/tmp/my.log");
 
      # Define a stdout appender
   my $stdout_appender =  Log::Log4perl::Appender->new(
                           "Log::Log4perl::Appender::Screen",
                           name      => "screenlog",
                           stderr    => 0);
 
      # Have both appenders use the same layout (could be different)
   $stdout_appender->layout($layout);
   $file_appender->layout($layout);
 
   $log->add_appender($stdout_appender);
   $log->add_appender($file_appender);
   $log->level($INFO);
 
 Please note the class of the appender object is passed as a I<string> to
 C<Log::Log4perl::Appender> in the I<first> argument. Behind the scenes,
 C<Log::Log4perl::Appender> will create the necessary
 C<Log::Log4perl::Appender::*> (or C<Log::Dispatch::*>) object and pass
 along the name value pairs we provided to
 C<Log::Log4perl::Appender-E<gt>new()> after the first argument.
 
 The C<name> value is optional and if you don't provide one,
 C<Log::Log4perl::Appender-E<gt>new()> will create a unique one for you.
 The names and values of additional parameters are dependent on the requirements
 of the particular appender class and can be looked up in their
 manual pages.
 
 A side note: In case you're wondering if
 C<Log::Log4perl::Appender-E<gt>new()> will also take care of the
 C<min_level> argument to the C<Log::Dispatch::*> constructors called
 behind the scenes -- yes, it does. This is because we want the
 C<Log::Dispatch> objects to blindly log everything we send them
 (C<debug> is their lowest setting) because I<we> in C<Log::Log4perl>
 want to call the shots and decide on when and what to log.
 
 The call to the appender's I<layout()> method specifies the format (as a
 previously created C<Log::Log4perl::Layout::PatternLayout> object) in which the
 message is being logged in the specified appender. 
 If you don't specify a layout, the logger will fall back to
 C<Log::Log4perl::SimpleLayout>, which logs the debug level, a hyphen (-)
 and the log message.
 
 Layouts are objects, here's how you create them:
 
         # Create a simple layout
     my $simple = Log::Log4perl::SimpleLayout();
 
         # create a flexible layout:
         # ("yyyy/MM/dd hh:mm:ss (file:lineno)> message\n")
     my $pattern = Log::Log4perl::Layout::PatternLayout("%d (%F:%L)> %m%n");
 
 Every appender has exactly one layout assigned to it. You assign
 the layout to the appender using the appender's C<layout()> object:
 
     my $app =  Log::Log4perl::Appender->new(
                   "Log::Log4perl::Appender::Screen",
                   name      => "screenlog",
                   stderr    => 0);
 
         # Assign the previously defined flexible layout
     $app->layout($pattern);
 
         # Add the appender to a previously defined logger
     $logger->add_appender($app);
 
         # ... and you're good to go!
     $logger->debug("Blah");
         # => "2002/07/10 23:55:35 (test.pl:207)> Blah\n"
 
 It's also possible to remove appenders from a logger:
 
     $logger->remove_appender($appender_name);
 
 will remove an appender, specified by name, from a given logger. 
 Please note that this does
 I<not> remove an appender from the system.
 
 To eradicate an appender from the system, 
 you need to call C<Log::Log4perl-E<gt>eradicate_appender($appender_name)>
 which will first remove the appender from every logger in the system
 and then will delete all references Log4perl holds to it.
 
 To remove a logger from the system, use 
 C<Log::Log4perl-E<gt>remove_logger($logger)>. After the remaining 
 reference C<$logger> goes away, the logger will self-destruct. If the
 logger in question is a stealth logger, all of its convenience shortcuts
 (DEBUG, INFO, etc) will turn into no-ops.
 
 =head1 How about Log::Dispatch::Config?
 
 Tatsuhiko Miyagawa's C<Log::Dispatch::Config> is a very clever 
 simplified logger implementation, covering some of the I<log4j>
 functionality. Among the things that 
 C<Log::Log4perl> can but C<Log::Dispatch::Config> can't are:
 
 =over 4
 
 =item *
 
 You can't assign categories to loggers. For small systems that's fine,
 but if you can't turn off and on detailed logging in only a tiny
 subsystem of your environment, you're missing out on a majorly
 useful log4j feature.
 
 =item *
 
 Defining appender thresholds. Important if you want to solve problems like
 "log all messages of level FATAL to STDERR, plus log all DEBUG
 messages in C<Foo::Bar> to a log file". If you don't have appenders
 thresholds, there's no way to prevent cluttering STDERR with DEBUG messages.
 
 =item *
 
 PatternLayout specifications in accordance with the standard
 (e.g. "%d{HH:mm}").
 
 =back
 
 Bottom line: Log::Dispatch::Config is fine for small systems with
 simple logging requirements. However, if you're
 designing a system with lots of subsystems which you need to control
 independently, you'll love the features of C<Log::Log4perl>,
 which is equally easy to use.
 
 =head1 Using Log::Log4perl with wrapper functions and classes
 
 If you don't use C<Log::Log4perl> as described above, 
 but from a wrapper function, the pattern layout will generate wrong data 
 for %F, %C, %L, and the like. Reason for this is that C<Log::Log4perl>'s 
 loggers assume a static caller depth to the application that's using them. 
 
 If you're using
 one (or more) wrapper functions, C<Log::Log4perl> will indicate where
 your logger function called the loggers, not where your application
 called your wrapper:
 
     use Log::Log4perl qw(:easy);
     Log::Log4perl->easy_init({ level => $DEBUG, 
                                layout => "%M %m%n" });
 
     sub mylog {
         my($message) = @_;
 
         DEBUG $message;
     }
 
     sub func {
         mylog "Hello";
     }
 
     func();
 
 prints
 
     main::mylog Hello
 
 but that's probably not what your application expects. Rather, you'd
 want
 
     main::func Hello
 
 because the C<func> function called your logging function.
 
 But don't despair, there's a solution: Just register your wrapper
 package with Log4perl beforehand. If Log4perl then finds that it's being 
 called from a registered wrapper, it will automatically step up to the
 next call frame.
 
     Log::Log4perl->wrapper_register(__PACKAGE__);
 
     sub mylog {
         my($message) = @_;
 
         DEBUG $message;
     }
 
 Alternatively, you can increase the value of the global variable
 C<$Log::Log4perl::caller_depth> (defaults to 0) by one for every
 wrapper that's in between your application and C<Log::Log4perl>,
 then C<Log::Log4perl> will compensate for the difference:
 
     sub mylog {
         my($message) = @_;
 
         local $Log::Log4perl::caller_depth =
               $Log::Log4perl::caller_depth + 1;
         DEBUG $message;
     }
 
 Also, note that if you're writing a subclass of Log4perl, like
 
     package MyL4pWrapper;
     use Log::Log4perl;
     our @ISA = qw(Log::Log4perl);
 
 and you want to call get_logger() in your code, like
 
     use MyL4pWrapper;
 
     sub get_logger {
         my $logger = Log::Log4perl->get_logger();
     }
 
 then the get_logger() call will get a logger for the C<MyL4pWrapper>
 category, not for the package calling the wrapper class as in
 
     package UserPackage;
     my $logger = MyL4pWrapper->get_logger();
 
 To have the above call to get_logger return a logger for the 
 "UserPackage" category, you need to tell Log4perl that "MyL4pWrapper"
 is a Log4perl wrapper class:
 
     use MyL4pWrapper;
     Log::Log4perl->wrapper_register(__PACKAGE__);
 
     sub get_logger {
           # Now gets a logger for the category of the calling package
         my $logger = Log::Log4perl->get_logger();
     }
 
 This feature works both for Log4perl-relaying classes like the wrapper
 described above, and for wrappers that inherit from Log4perl use Log4perl's
 get_logger function via inheritance, alike.
 
 =head1 Access to Internals
 
 The following methods are only of use if you want to peek/poke in
 the internals of Log::Log4perl. Be careful not to disrupt its
 inner workings.
 
 =over 4
 
 =item C<< Log::Log4perl->appenders() >>
 
 To find out which appenders are currently defined (not only
 for a particular logger, but overall), a C<appenders()>
 method is available to return a reference to a hash mapping appender
 names to their Log::Log4perl::Appender object references.
 
 =back
 
 =head1 Dirty Tricks
 
 =over 4
 
 =item infiltrate_lwp()
 
 The famous LWP::UserAgent module isn't Log::Log4perl-enabled. Often, though,
 especially when tracing Web-related problems, it would be helpful to get
 some insight on what's happening inside LWP::UserAgent. Ideally, LWP::UserAgent
 would even play along in the Log::Log4perl framework.
 
 A call to C<Log::Log4perl-E<gt>infiltrate_lwp()> does exactly this. 
 In a very rude way, it pulls the rug from under LWP::UserAgent and transforms
 its C<debug/conn> messages into C<debug()> calls of loggers of the category
 C<"LWP::UserAgent">. Similarily, C<LWP::UserAgent>'s C<trace> messages 
 are turned into C<Log::Log4perl>'s C<info()> method calls. Note that this
 only works for LWP::UserAgent versions E<lt> 5.822, because this (and
 probably later) versions miss debugging functions entirely.
 
 =item Suppressing 'duplicate' LOGDIE messages
 
 If a script with a simple Log4perl configuration uses logdie() to catch
 errors and stop processing, as in 
 
     use Log::Log4perl qw(:easy) ;
     Log::Log4perl->easy_init($DEBUG);
     
     shaky_function() or LOGDIE "It failed!";
 
 there's a cosmetic problem: The message gets printed twice:
 
     2005/07/10 18:37:14 It failed!
     It failed! at ./t line 12
 
 The obvious solution is to use LOGEXIT() instead of LOGDIE(), but there's
 also a special tag for Log4perl that suppresses the second message:
 
     use Log::Log4perl qw(:no_extra_logdie_message);
 
 This causes logdie() and logcroak() to call exit() instead of die(). To
 modify the script exit code in these occasions, set the variable
 C<$Log::Log4perl::LOGEXIT_CODE> to the desired value, the default is 1.
 
 =item Redefine values without causing errors
 
 Log4perl's configuration file parser has a few basic safety mechanisms to 
 make sure configurations are more or less sane. 
 
 One of these safety measures is catching redefined values. For example, if
 you first write
 
     log4perl.category = WARN, Logfile
 
 and then a couple of lines later
 
     log4perl.category = TRACE, Logfile
 
 then you might have unintentionally overwritten the first value and Log4perl
 will die on this with an error (suspicious configurations always throw an
 error). Now, there's a chance that this is intentional, for example when
 you're lumping together several configuration files and actually I<want>
 the first value to overwrite the second. In this case use
 
     use Log::Log4perl qw(:nostrict);
 
 to put Log4perl in a more permissive mode.
 
 =item Prevent croak/confess from stringifying
 
 The logcroak/logconfess functions stringify their arguments before
 they pass them to Carp's croak/confess functions. This can get in the
 way if you want to throw an object or a hashref as an exception, in
 this case use:
 
     $Log::Log4perl::STRINGIFY_DIE_MESSAGE = 0;
 
     eval {
           # throws { foo => "bar" }
           # without stringification
         $logger->logcroak( { foo => "bar" } );
     };
 
 =back
 
 =head1 EXAMPLE
 
 A simple example to cut-and-paste and get started:
 
     use Log::Log4perl qw(get_logger);
     
     my $conf = q(
     log4perl.category.Bar.Twix         = WARN, Logfile
     log4perl.appender.Logfile          = Log::Log4perl::Appender::File
     log4perl.appender.Logfile.filename = test.log
     log4perl.appender.Logfile.layout = \
         Log::Log4perl::Layout::PatternLayout
     log4perl.appender.Logfile.layout.ConversionPattern = %d %F{1} %L> %m %n
     );
     
     Log::Log4perl::init(\$conf);
     
     my $logger = get_logger("Bar::Twix");
     $logger->error("Blah");
 
 This will log something like
 
     2002/09/19 23:48:15 t1 25> Blah 
 
 to the log file C<test.log>, which Log4perl will append to or 
 create it if it doesn't exist already.
 
 =head1 INSTALLATION
 
 If you want to use external appenders provided with C<Log::Dispatch>,
 you need to install C<Log::Dispatch> (2.00 or better) from CPAN,
 which itself depends on C<Attribute-Handlers> and
 C<Params-Validate>. And a lot of other modules, that's the reason
 why we're now shipping Log::Log4perl with its own standard appenders
 and only if you wish to use additional ones, you'll have to go through
 the C<Log::Dispatch> installation process.
 
 Log::Log4perl needs C<Test::More>, C<Test::Harness> and C<File::Spec>, 
 but they already come with fairly recent versions of perl.
 If not, everything's automatically fetched from CPAN if you're using the CPAN 
 shell (CPAN.pm), because they're listed as dependencies.
 
 C<Time::HiRes> (1.20 or better) is required only if you need the
 fine-grained time stamps of the C<%r> parameter in
 C<Log::Log4perl::Layout::PatternLayout>.
 
 Manual installation works as usual with
 
     perl Makefile.PL
     make
     make test
     make install
 
 =head1 DEVELOPMENT
 
 Log::Log4perl is still being actively developed. We will
 always make sure the test suite (approx. 500 cases) will pass, but there 
 might still be bugs. please check L<http://github.com/mschilli/log4perl>
 for the latest release. The api has reached a mature state, we will 
 not change it unless for a good reason.
 
 Bug reports and feedback are always welcome, just email them to our 
 mailing list shown in the AUTHORS section. We're usually addressing
 them immediately.
 
 =head1 REFERENCES
 
 =over 4
 
 =item [1]
 
 Michael Schilli, "Retire your debugger, log smartly with Log::Log4perl!",
 Tutorial on perl.com, 09/2002, 
 L<http://www.perl.com/pub/a/2002/09/11/log4perl.html>
 
 =item [2]
 
 Ceki Gülcü, "Short introduction to log4j",
 L<http://logging.apache.org/log4j/1.2/manual.html>
 
 =item [3]
 
 Vipan Singla, "Don't Use System.out.println! Use Log4j.",
 L<http://www.vipan.com/htdocs/log4jhelp.html>
 
 =item [4]
 
 The Log::Log4perl project home page: L<http://log4perl.com>
 
 =back
 
 =head1 SEE ALSO
 
 L<Log::Log4perl::Config|Log::Log4perl::Config>,
 L<Log::Log4perl::Appender|Log::Log4perl::Appender>,
 L<Log::Log4perl::Layout::PatternLayout|Log::Log4perl::Layout::PatternLayout>,
 L<Log::Log4perl::Layout::SimpleLayout|Log::Log4perl::Layout::SimpleLayout>,
 L<Log::Log4perl::Level|Log::Log4perl::Level>,
 L<Log::Log4perl::JavaMap|Log::Log4perl::JavaMap>
 L<Log::Log4perl::NDC|Log::Log4perl::NDC>,
 
 =head1 AUTHORS
 
 Please contribute patches to the project on Github:
 
     http://github.com/mschilli/log4perl
 
 Send bug reports or requests for enhancements to the authors via our
 
 MAILING LIST (questions, bug reports, suggestions/patches): 
 log4perl-devel@lists.sourceforge.net
 
 Authors (please contact them via the list above, not directly):
 Mike Schilli <m@perlmeister.com>,
 Kevin Goess <cpan@goess.org>
 
 Contributors (in alphabetical order):
 Ateeq Altaf, Cory Bennett, Jens Berthold, Jeremy Bopp, Hutton
 Davidson, Chris R. Donnelly, Matisse Enzer, Hugh Esco, Anthony
 Foiani, James FitzGibbon, Carl Franks, Dennis Gregorovic, Andy
 Grundman, Paul Harrington, Alexander Hartmaier, David Hull, 
 Robert Jacobson, Jason Kohles, Jeff Macdonald, Markus Peter, 
 Brett Rann, Peter Rabbitson, Erik Selberg, Aaron Straup Cope, 
 Lars Thegler, David Viner, Mac Yang.
 
 =head1 LICENSE
 
 Copyright 2002-2013 by Mike Schilli E<lt>m@perlmeister.comE<gt> 
 and Kevin Goess E<lt>cpan@goess.orgE<gt>.
 
 This library is free software; you can redistribute it and/or modify
 it under the same terms as Perl itself. 
 
### Log/Log4perl/Appender.pm ###
 ##################################################
 package Log::Log4perl::Appender;
 ##################################################
 
 use 5.006;
 use strict;
 use warnings;
 
 use Log::Log4perl::Config;
 use Log::Log4perl::Level;
 use Carp;
 
 use constant _INTERNAL_DEBUG => 0;
 
 our $unique_counter = 0;
 
 ##################################################
 sub reset {
 ##################################################
     $unique_counter = 0;
 }
 
 ##################################################
 sub unique_name {
 ##################################################
         # THREADS: Need to lock here to make it thread safe
     $unique_counter++;
     my $unique_name = sprintf("app%03d", $unique_counter);
         # THREADS: Need to unlock here to make it thread safe
     return $unique_name;
 }
 
 ##################################################
 sub new {
 ##################################################
     my($class, $appenderclass, %params) = @_;
 
         # Pull in the specified Log::Log4perl::Appender object
     eval {
 
            # Eval erroneously succeeds on unknown appender classes if
            # the eval string just consists of valid perl code (e.g. an
            # appended ';' in $appenderclass variable). Fail if we see
            # anything in there that can't be class name.
         die "'$appenderclass' not a valid class name " if 
             $appenderclass =~ /[^:\w]/;
 
         # Check if the class/package is already available because
         # something like Class::Prototyped injected it previously.
 
         # Use UNIVERSAL::can to check the appender's new() method
         # [RT 28987]
         if( ! $appenderclass->can('new') ) {
             # Not available yet, try to pull it in.
             # see 'perldoc -f require' for why two evals
             eval "require $appenderclass";
                  #unless ${$appenderclass.'::IS_LOADED'};  #for unit tests, 
                                                           #see 004Config
             die $@ if $@;
         }
     };
 
     $@ and die "ERROR: can't load appenderclass '$appenderclass'\n$@";
 
     $params{name} = unique_name() unless exists $params{name};
 
     # If it's a Log::Dispatch::File appender, default to append 
     # mode (Log::Dispatch::File defaults to 'clobber') -- consensus 9/2002
     # (Log::Log4perl::Appender::File already defaults to 'append')
     if ($appenderclass eq 'Log::Dispatch::File' &&
         ! exists $params{mode}) {
         $params{mode} = 'append';
     }
 
     my $appender = $appenderclass->new(
             # Set min_level to the lowest setting. *we* are 
             # controlling this now, the appender should just
             # log it with no questions asked.
         min_level => 'debug',
             # Set 'name' and other parameters
         map { $_ => $params{$_} } keys %params,
     );
 
     my $self = {
                  appender  => $appender,
                  name      => $params{name},
                  layout    => undef,
                  level     => $ALL,
                  composite => 0,
                };
 
         #whether to collapse arrays, etc.
     $self->{warp_message} = $params{warp_message};
     if($self->{warp_message} and
        my $cref = 
        Log::Log4perl::Config::compile_if_perl($self->{warp_message})) {
         $self->{warp_message} = $cref;
     }
     
     bless $self, $class;
 
     return $self;
 }
 
 ##################################################
 sub composite { # Set/Get the composite flag
 ##################################################
     my ($self, $flag) = @_;
 
     $self->{composite} = $flag if defined $flag;
     return $self->{composite};
 }
 
 ##################################################
 sub threshold { # Set/Get the appender threshold
 ##################################################
     my ($self, $level) = @_;
 
     print "Setting threshold to $level\n" if _INTERNAL_DEBUG;
 
     if(defined $level) {
         # Checking for \d makes for a faster regex(p)
         $self->{level} = ($level =~ /^(\d+)$/) ? $level :
             # Take advantage of &to_priority's error reporting
             Log::Log4perl::Level::to_priority($level);
     }
 
     return $self->{level};
 }
 
 ##################################################
 sub log { 
 ##################################################
 # Relay this call to Log::Log4perl::Appender:* or
 # Log::Dispatch::*
 ##################################################
     my ($self, $p, $category, $level, $cache) = @_;
 
     # Check if the appender has a last-minute veto in form
     # of an "appender threshold"
     if($self->{level} > $
                         Log::Log4perl::Level::PRIORITY{$level}) {
         print "$self->{level} > $level, aborting\n" if _INTERNAL_DEBUG;
         return undef;
     }
 
     # Run against the (yes only one) customized filter (which in turn
     # might call other filters via the Boolean filter) and check if its
     # ok() method approves the message or blocks it.
     if($self->{filter}) {
         if($self->{filter}->ok(%$p,
                                log4p_category => $category,
                                log4p_level    => $level )) {
             print "Filter $self->{filter}->{name} passes\n" if _INTERNAL_DEBUG;
         } else {
             print "Filter $self->{filter}->{name} blocks\n" if _INTERNAL_DEBUG;
             return undef;
         }
     }
 
     unless($self->composite()) {
 
             #not defined, the normal case
         if (! defined $self->{warp_message} ){
                 #join any message elements
             if (ref $p->{message} eq "ARRAY") {
                 for my $i (0..$#{$p->{message}}) {
                     if( !defined $p->{message}->[ $i ] ) {
                         local $Carp::CarpLevel =
                         $Carp::CarpLevel + $Log::Log4perl::caller_depth + 1;
                         carp "Warning: Log message argument #" . 
                              ($i+1) . " undefined";
                     }
                 }
                 $p->{message} = 
                     join($Log::Log4perl::JOIN_MSG_ARRAY_CHAR, 
                          @{$p->{message}} 
                          );
             }
             
             #defined but false, e.g. Appender::DBI
         } elsif (! $self->{warp_message}) {
             ;  #leave the message alone
     
         } elsif (ref($self->{warp_message}) eq "CODE") {
             #defined and a subref
             $p->{message} = 
                 [$self->{warp_message}->(@{$p->{message}})];
         } else {
             #defined and a function name?
             no strict qw(refs);
             $p->{message} = 
                 [$self->{warp_message}->(@{$p->{message}})];
         }
 
         $p->{message} = $self->{layout}->render($p->{message}, 
             $category,
             $level,
             3 + $Log::Log4perl::caller_depth,
         ) if $self->layout();
     }
 
     my $args = [%$p, log4p_category => $category, log4p_level => $level];
 
     if(defined $cache) {
         $$cache = $args;
     } else {
         $self->{appender}->log(@$args);
     }
 
     return 1;
 }
 
 ###########################################
 sub log_cached {
 ###########################################
     my ($self, $cache) = @_;
 
     $self->{appender}->log(@$cache);
 }
 
 ##################################################
 sub name { # Set/Get the name
 ##################################################
     my($self, $name) = @_;
 
         # Somebody wants to *set* the name?
     if($name) {
         $self->{name} = $name;
     }
 
     return $self->{name};
 }
 
 ###########################################
 sub layout { # Set/Get the layout object
              # associated with this appender
 ###########################################
     my($self, $layout) = @_;
 
         # Somebody wants to *set* the layout?
     if($layout) {
         $self->{layout} = $layout;
 
         # somebody wants a layout, but not set yet, so give 'em default
     }elsif (! $self->{layout}) {
         $self->{layout} = Log::Log4perl::Layout::SimpleLayout
                                                 ->new($self->{name});
 
     }
 
     return $self->{layout};
 }
 
 ##################################################
 sub filter { # Set filter
 ##################################################
     my ($self, $filter) = @_;
 
     if($filter) {
         print "Setting filter to $filter->{name}\n" if _INTERNAL_DEBUG;
         $self->{filter} = $filter;
     }
 
     return $self->{filter};
 }
 
 ##################################################
 sub AUTOLOAD { 
 ##################################################
 # Relay everything else to the underlying 
 # Log::Log4perl::Appender::* or Log::Dispatch::*
 #  object
 ##################################################
     my $self = shift;
 
     no strict qw(vars);
 
     $AUTOLOAD =~ s/.*:://;
 
     if(! defined $self->{appender}) {
         die "Can't locate object method $AUTOLOAD() in ", __PACKAGE__;
     }
 
     return $self->{appender}->$AUTOLOAD(@_);
 }
 
 ##################################################
 sub DESTROY {
 ##################################################
     foreach my $key (keys %{$_[0]}) {
         # print "deleting $key\n";
         delete $_[0]->{$key};
     }
 }
 
 1;
 
 __END__
 
 =encoding utf8
 
 =head1 NAME
 
 Log::Log4perl::Appender - Log appender class
 
 =head1 SYNOPSIS
 
   use Log::Log4perl;
 
       # Define a logger
   my $logger = Log::Log4perl->get_logger("abc.def.ghi");
 
       # Define a layout
   my $layout = Log::Log4perl::Layout::PatternLayout->new(
                    "%d (%F:%L)> %m");
 
       # Define an appender
   my $appender = Log::Log4perl::Appender->new(
                    "Log::Log4perl::Appender::Screen",
                    name => 'dumpy');
 
       # Set the appender's layout
   $appender->layout($layout);
   $logger->add_appender($appender);
 
 =head1 DESCRIPTION
 
 This class is a wrapper around the C<Log::Log4perl::Appender>
 appender set. 
 
 It also supports the <Log::Dispatch::*> collections of appenders. The
 module hides the idiosyncrasies of C<Log::Dispatch> (e.g. every
 dispatcher gotta have a name, but there's no accessor to retrieve it)
 from C<Log::Log4perl> and yet re-uses the extremely useful variety of
 dispatchers already created and tested in C<Log::Dispatch>.
 
 =head1 FUNCTIONS
 
 =head2 Log::Log4perl::Appender->new($dispatcher_class_name, ...);
 
 The constructor C<new()> takes the name of the appender
 class to be created as a I<string> (!) argument, optionally followed by 
 a number of appender-specific parameters,
 for example:
 
       # Define an appender
   my $appender = Log::Log4perl::Appender->new(
       "Log::Log4perl::Appender::File"
       filename => 'out.log');
 
 In case of C<Log::Dispatch> appenders,
 if no C<name> parameter is specified, the appender object will create
 a unique one (format C<appNNN>), which can be retrieved later via
 the C<name()> method:
 
   print "The appender's name is ", $appender->name(), "\n";
 
 Other parameters are specific to the appender class being used.
 In the case above, the C<filename> parameter specifies the name of 
 the C<Log::Log4perl::Appender::File> dispatcher used. 
 
 However, if, for instance, 
 you're using a C<Log::Dispatch::Email> dispatcher to send you 
 email, you'll have to specify C<from> and C<to> email addresses.
 Every dispatcher is different.
 Please check the C<Log::Dispatch::*> documentation for the appender used
 for details on specific requirements.
 
 The C<new()> method will just pass these parameters on to a newly created
 C<Log::Dispatch::*> object of the specified type.
 
 When it comes to logging, the C<Log::Log4perl::Appender> will transparently
 relay all messages to the C<Log::Dispatch::*> object it carries 
 in its womb.
 
 =head2 $appender->layout($layout);
 
 The C<layout()> method sets the log layout
 used by the appender to the format specified by the 
 C<Log::Log4perl::Layout::*> object which is passed to it as a reference.
 Currently there's two layouts available:
 
     Log::Log4perl::Layout::SimpleLayout
     Log::Log4perl::Layout::PatternLayout
 
 Please check the L<Log::Log4perl::Layout::SimpleLayout> and 
 L<Log::Log4perl::Layout::PatternLayout> manual pages for details.
 
 =head1 Supported Appenders 
 
 Here's the list of appender modules currently available via C<Log::Dispatch>,
 if not noted otherwise, written by Dave Rolsky:
 
        Log::Dispatch::ApacheLog
        Log::Dispatch::DBI (by Tatsuhiko Miyagawa)
        Log::Dispatch::Email,
        Log::Dispatch::Email::MailSend,
        Log::Dispatch::Email::MailSendmail,
        Log::Dispatch::Email::MIMELite
        Log::Dispatch::File
        Log::Dispatch::FileRotate (by Mark Pfeiffer)
        Log::Dispatch::Handle
        Log::Dispatch::Screen
        Log::Dispatch::Syslog
        Log::Dispatch::Tk (by Dominique Dumont)
 
 C<Log4perl> doesn't care which ones you use, they're all handled in 
 the same way via the C<Log::Log4perl::Appender> interface.
 Please check the well-written manual pages of the 
 C<Log::Dispatch> hierarchy on how to use each one of them.
 
 =head1 Parameters passed on to the appender's log() method
 
 When calling the appender's log()-Funktion, Log::Log4perl will 
 submit a list of key/value pairs. Entries to the following keys are
 guaranteed to be present:
 
 =over 4
 
 =item message
 
 Text of the rendered message
 
 =item log4p_category
 
 Name of the category of the logger that triggered the event.
 
 =item log4p_level
 
 Log::Log4perl level of the event
 
 =back
 
 =head1 Pitfalls
 
 Since the C<Log::Dispatch::File> appender truncates log files by default,
 and most of the time this is I<not> what you want, we've instructed 
 C<Log::Log4perl> to change this behavior by slipping it the 
 C<mode =E<gt> append> parameter behind the scenes. So, effectively
 with C<Log::Log4perl> 0.23, a configuration like
 
     log4perl.category = INFO, FileAppndr
     log4perl.appender.FileAppndr          = Log::Dispatch::File
     log4perl.appender.FileAppndr.filename = test.log
     log4perl.appender.FileAppndr.layout   = Log::Log4perl::Layout::SimpleLayout
 
 will always I<append> to an existing logfile C<test.log> while if you 
 specifically request clobbering like in
 
     log4perl.category = INFO, FileAppndr
     log4perl.appender.FileAppndr          = Log::Dispatch::File
     log4perl.appender.FileAppndr.filename = test.log
     log4perl.appender.FileAppndr.mode     = write
     log4perl.appender.FileAppndr.layout   = Log::Log4perl::Layout::SimpleLayout
 
 it will overwrite an existing log file C<test.log> and start from scratch.
 
 =head1 Appenders Expecting Message Chunks
 
 Instead of simple strings, certain appenders are expecting multiple fields
 as log messages. If a statement like 
 
     $logger->debug($ip, $user, "signed in");
 
 causes an off-the-shelf C<Log::Log4perl::Appender::Screen> 
 appender to fire, the appender will 
 just concatenate the three message chunks passed to it
 in order to form a single string.
 The chunks will be separated by a string defined in 
 C<$Log::Log4perl::JOIN_MSG_ARRAY_CHAR> (defaults to the empty string
 ""). 
 
 However, different appenders might choose to 
 interpret the message above differently: An
 appender like C<Log::Log4perl::Appender::DBI> might take the
 three arguments passed to the logger and put them in three separate
 rows into the DB.
 
 The  C<warp_message> appender option is used to specify the desired 
 behavior.
 If no setting for the appender property
 
     # *** Not defined ***
     # log4perl.appender.SomeApp.warp_message
 
 is defined in the Log4perl configuration file, the
 appender referenced by C<SomeApp> will fall back to the standard behavior
 and join all message chunks together, separating them by
 C<$Log::Log4perl::JOIN_MSG_ARRAY_CHAR>.
 
 If, on the other hand, it is set to a false value, like in
 
     log4perl.appender.SomeApp.layout=NoopLayout
     log4perl.appender.SomeApp.warp_message = 0
 
 then the message chunks are passed unmodified to the appender as an
 array reference. Please note that you need to set the appender's
 layout to C<Log::Log4perl::Layout::NoopLayout> which just leaves 
 the messages chunks alone instead of formatting them or replacing
 conversion specifiers.
 
 B<Please note that the standard appenders in the Log::Dispatch hierarchy
 will choke on a bunch of messages passed to them as an array reference. 
 You can't use C<warp_message = 0> (or the function name syntax
 defined below) on them.
 Only special appenders like Log::Log4perl::Appender::DBI can deal with
 this.>
 
 If (and now we're getting fancy)
 an appender expects message chunks, but we would 
 like to pre-inspect and probably modify them before they're 
 actually passed to the appender's C<log>
 method, an inspection subroutine can be defined with the
 appender's C<warp_message> property:
 
     log4perl.appender.SomeApp.layout=NoopLayout
     log4perl.appender.SomeApp.warp_message = sub { \
                                            $#_ = 2 if @_ > 3; \
                                            return @_; }
 
 The inspection subroutine defined by the C<warp_message> 
 property will receive the list of message chunks, like they were
 passed to the logger and is expected to return a corrected list.
 The example above simply limits the argument list to a maximum of
 three by cutting off excess elements and returning the shortened list.
 
 Also, the warp function can be specified by name like in
 
     log4perl.appender.SomeApp.layout=NoopLayout
     log4perl.appender.SomeApp.warp_message = main::filter_my_message
 
 In this example,
 C<filter_my_message> is a function in the C<main> package, 
 defined like this:
 
     my $COUNTER = 0;
 
     sub filter_my_message {
         my @chunks = @_;
         unshift @chunks, ++$COUNTER;
         return @chunks;
     }
 
 The subroutine above will add an ever increasing counter
 as an additional first field to 
 every message passed to the C<SomeApp> appender -- but not to
 any other appender in the system.
 
 =head2 Composite Appenders
 
 Composite appenders relay their messages to sub-appenders after providing
 some filtering or synchronizing functionality on incoming messages. 
 Examples are 
 Log::Log4perl::Appender::Synchronized,
 Log::Log4perl::Appender::Limit, and
 Log::Log4perl::Appender::Buffer. Check their manual pages for details.
 
 Composite appender objects are regular Log::Log4perl::Appender objects, 
 but they have the composite flag set:
 
     $app->composite(1);
 
 and they define a post_init() method, which sets the appender it relays
 its messages to:
 
     ###########################################
     sub post_init {
     ############################################
         my($self) = @_;
     
         if(! exists $self->{appender}) {
             die "No appender defined for " . __PACKAGE__;
         }
     
         my $appenders = Log::Log4perl->appenders();
         my $appender = Log::Log4perl->appenders()->{$self->{appender}};
     
         if(! defined $appender) {
             die "Appender $self->{appender} not defined (yet) when " .
                 __PACKAGE__ . " needed it";
         }
     
         $self->{app} = $appender;
     }
 
 The reason for this post-processing step is that the relay appender
 might not be defined yet when the composite appender gets defined.
 This can happen if Log4perl is initialized with a configuration file
 (which is the most common way to initialize Log4perl), because
 appenders spring into existence in unpredictable order.
 
 For example, if you define a Synchronized appender like
 
     log4perl.appender.Syncer            = Log::Log4perl::Appender::Synchronized
     log4perl.appender.Syncer.appender   = Logfile
 
 then Log4perl will set the appender's C<appender> attribute to the
 I<name> of the appender to finally relay messages to. After the
 Log4perl configuration file has been processed, Log4perl will remember to 
 call the composite appender's post_init() method, which will grab
 the relay appender instance referred to by the name (Logfile) 
 and set it in its C<app> attribute. This is exactly what the
 code snippet above does.
 
 But if you initialize Log4perl by its API, you need to remember to
 perform these steps. Here's the lineup:
 
     use Log::Log4perl qw(get_logger :levels);
     
     my $fileApp = Log::Log4perl::Appender->new(
     		'Log::Log4perl::Appender::File',
     		name     => 'MyFileApp',
     		filename => 'mylog',
     		mode     => 'append',
     		);
     $fileApp->layout(
     		Log::Log4perl::Layout::PatternLayout::Multiline->new(
     			'%d{yyyy-MM-dd HH:mm:ss} %p [%c] #%P> %m%n')
     		);
       # Make the appender known to the system (without assigning it to
       # any logger
     Log::Log4perl->add_appender( $fileApp );
     
     my $syncApp = Log::Log4perl::Appender->new(
     		'Log::Log4perl::Appender::Synchronized',
     		name       => 'MySyncApp',
     		appender   => 'MyFileApp',
     		key        => 'nem',
     		);
     $syncApp->post_init();
     $syncApp->composite(1);
 
       # The Synchronized appender is now ready, assign it to a logger
       # and start logging.
     get_logger("")->add_appender($syncApp);
 
     get_logger("")->level($DEBUG);
     get_logger("wonk")->debug("waah!");
 
 The composite appender's log() function will typically cache incoming 
 messages until a certain trigger condition is met and then forward a bulk
 of messages to the relay appender.
 
 Caching messages is surprisingly tricky, because you want them to look
 like they came from the code location they were originally issued from
 and not from the location that triggers the flush. Luckily, Log4perl
 offers a cache mechanism for messages, all you need to do is call the
 base class' log() function with an additional reference to a scalar,
 and then save its content to your composite appender's message buffer
 afterwards:
 
     ###########################################
     sub log {
     ###########################################
         my($self, %params) = @_;
 
         # ... some logic to decide whether to cache or flush
 
             # Adjust the caller stack
         local $Log::Log4perl::caller_depth =
               $Log::Log4perl::caller_depth + 2;
 
             # We need to cache.
             # Ask the appender to save a cached message in $cache
         $self->{relay_app}->SUPER::log(\%params,
                              $params{log4p_category},
                              $params{log4p_level}, \my $cache);
 
             # Save it in the appender's message buffer
         push @{ $self->{buffer} }, $cache;
     }
 
 Note that before calling the log() method of the relay appender's base class
 (and thus introducing two additional levels on the call stack), we need to
 adjust the call stack to allow Log4perl to render cspecs like the %M or %L
 correctly.  The cache will then contain a correctly rendered message, according
 to the layout of the target appender.
 
 Later, when the time comes to flush the cached messages, a call to the relay
 appender's base class' log_cached() method with the cached message as 
 an argument will forward the correctly rendered message:
 
     ###########################################
     sub log {
     ###########################################
         my($self, %params) = @_;
 
         # ... some logic to decide whether to cache or flush
 
             # Flush pending messages if we have any
         for my $cache (@{$self->{buffer}}) {
             $self->{relay_app}->SUPER::log_cached($cache);
         }
     }
 
 
 =head1 SEE ALSO
 
 Log::Dispatch
 
 =head1 LICENSE
 
 Copyright 2002-2013 by Mike Schilli E<lt>m@perlmeister.comE<gt> 
 and Kevin Goess E<lt>cpan@goess.orgE<gt>.
 
 This library is free software; you can redistribute it and/or modify
 it under the same terms as Perl itself. 
 
 =head1 AUTHOR
 
 Please contribute patches to the project on Github:
 
     http://github.com/mschilli/log4perl
 
 Send bug reports or requests for enhancements to the authors via our
 
 MAILING LIST (questions, bug reports, suggestions/patches): 
 log4perl-devel@lists.sourceforge.net
 
 Authors (please contact them via the list above, not directly):
 Mike Schilli <m@perlmeister.com>,
 Kevin Goess <cpan@goess.org>
 
 Contributors (in alphabetical order):
 Ateeq Altaf, Cory Bennett, Jens Berthold, Jeremy Bopp, Hutton
 Davidson, Chris R. Donnelly, Matisse Enzer, Hugh Esco, Anthony
 Foiani, James FitzGibbon, Carl Franks, Dennis Gregorovic, Andy
 Grundman, Paul Harrington, Alexander Hartmaier  David Hull, 
 Robert Jacobson, Jason Kohles, Jeff Macdonald, Markus Peter, 
 Brett Rann, Peter Rabbitson, Erik Selberg, Aaron Straup Cope, 
 Lars Thegler, David Viner, Mac Yang.
 
### Log/Log4perl/Appender/Buffer.pm ###
 ######################################################################
 # Buffer.pm -- 2004, Mike Schilli <m@perlmeister.com>
 ######################################################################
 # Composite appender buffering messages until a trigger condition is met.
 ######################################################################
 
 ###########################################
 package Log::Log4perl::Appender::Buffer;
 ###########################################
 
 use strict;
 use warnings;
 
 our @ISA = qw(Log::Log4perl::Appender);
 
 our $CVSVERSION   = '$Revision: 1.2 $';
 our ($VERSION)    = ($CVSVERSION =~ /(\d+\.\d+)/);
 
 ###########################################
 sub new {
 ###########################################
     my($class, %options) = @_;
 
     my $self = {
         appender=> undef,
         buffer  => [],
         options => { 
             max_messages  => undef, 
             trigger       => undef,
             trigger_level => undef,
         },
         level   => 0,
         %options,
     };
 
     if($self->{trigger_level}) {
         $self->{trigger} = level_trigger($self->{trigger_level});
     }
 
         # Pass back the appender to be synchronized as a dependency
         # to the configuration file parser
     push @{$options{l4p_depends_on}}, $self->{appender};
 
         # Run our post_init method in the configurator after
         # all appenders have been defined to make sure the
         # appender we're playing 'dam' for really exists
     push @{$options{l4p_post_config_subs}}, sub { $self->post_init() };
 
     bless $self, $class;
 }
 
 ###########################################
 sub log {
 ###########################################
     my($self, %params) = @_;
 
     local $Log::Log4perl::caller_depth =
         $Log::Log4perl::caller_depth + 2;
 
         # Do we need to discard a message because there's already
         # max_size messages in the buffer?
     if(defined $self->{max_messages} and
        @{$self->{buffer}} == $self->{max_messages}) {
         shift @{$self->{buffer}};
     }
         # Ask the appender to save a cached message in $cache
     $self->{app}->SUPER::log(\%params,
                          $params{log4p_category},
                          $params{log4p_level}, \my $cache);
 
         # Save it in the appender's message buffer, but only if
         # it hasn't been suppressed by an appender threshold
     if( defined $cache ) {
         push @{ $self->{buffer} }, $cache;
     }
 
     $self->flush() if $self->{trigger}->($self, \%params);
 }
 
 ###########################################
 sub flush {
 ###########################################
     my($self) = @_;
 
         # Flush pending messages if we have any
     for my $cache (@{$self->{buffer}}) {
         $self->{app}->SUPER::log_cached($cache);
     }
 
         # Empty buffer
     $self->{buffer} = [];
 }
 
 ###########################################
 sub post_init {
 ###########################################
     my($self) = @_;
 
     if(! exists $self->{appender}) {
        die "No appender defined for " . __PACKAGE__;
     }
 
     my $appenders = Log::Log4perl->appenders();
     my $appender = Log::Log4perl->appenders()->{$self->{appender}};
 
     if(! defined $appender) {
        die "Appender $self->{appender} not defined (yet) when " .
            __PACKAGE__ . " needed it";
     }
 
     $self->{app} = $appender;
 }
 
 ###########################################
 sub level_trigger {
 ###########################################
     my($level) = @_;
 
         # closure holding $level
     return sub {
         my($self, $params) = @_;
 
         return Log::Log4perl::Level::to_priority(
                  $params->{log4p_level}) >= 
                Log::Log4perl::Level::to_priority($level);
     };
 }
     
 ###########################################
 sub DESTROY {
 ###########################################
     my($self) = @_;
 }
 
 1;
 
 __END__
 
 =encoding utf8
 
 =head1 NAME
 
     Log::Log4perl::Appender::Buffer - Buffering Appender
 
 =head1 SYNOPSIS
 
     use Log::Log4perl qw(:easy);
 
     my $conf = qq(
     log4perl.category                  = DEBUG, Buffer
 
         # Regular Screen Appender
     log4perl.appender.Screen           = Log::Log4perl::Appender::Screen
     log4perl.appender.Screen.stdout    = 1
     log4perl.appender.Screen.layout    = PatternLayout
     log4perl.appender.Screen.layout.ConversionPattern = %d %p %c %m %n
 
         # Buffering appender, using the appender above as outlet
     log4perl.appender.Buffer               = Log::Log4perl::Appender::Buffer
     log4perl.appender.Buffer.appender      = Screen
     log4perl.appender.Buffer.trigger_level = ERROR
     );
 
     Log::Log4perl->init(\$conf);
 
     DEBUG("This message gets buffered.");
     INFO("This message gets buffered also.");
 
     # Time passes. Nothing happens. But then ...
 
     print "It's GO time!!!\n";
 
     ERROR("This message triggers a buffer flush.");
 
 =head1 DESCRIPTION
 
 C<Log::Log4perl::Appender::Buffer> takes these arguments:
 
 =over 4
 
 =item C<appender>
 
 Specifies the name of the appender it buffers messages for. The
 appender specified must be defined somewhere in the configuration file,
 not necessarily before the definition of 
 C<Log::Log4perl::Appender::Buffer>.
 
 =item C<max_messages>
 
 Specifies the maximum number of messages the appender will hold in
 its ring buffer. C<max_messages> is optional. By default,
 C<Log::Log4perl::Appender::Buffer> will I<not> limit the number of
 messages buffered. This might be undesirable in long-running processes
 accumulating lots of messages before a flush happens. If
 C<max_messages> is set to a numeric value,
 C<Log::Log4perl::Appender::Buffer> will displace old messages in its
 buffer to make room if the buffer is full.
 
 =item C<trigger_level>
 
 If trigger_level is set to one of Log4perl's levels (see
 Log::Log4perl::Level), a C<trigger> function will be defined internally
 to flush the buffer if a message with a priority of $level or higher
 comes along. This is just a convenience function. Defining
 
     log4perl.appender.Buffer.trigger_level = ERROR
 
 is equivalent to creating a trigger function like
 
     log4perl.appender.Buffer.trigger = sub {   \
         my($self, $params) = @_;               \
         return $params->{log4p_level} >=       \
                $Log::Log4perl::Level::ERROR; }
 
 See the next section for defining generic trigger functions.
 
 =item C<trigger>
 
 C<trigger> holds a reference to a subroutine, which
 C<Log::Log4perl::Appender::Buffer> will call on every incoming message
 with the same parameters as the appender's C<log()> method:
 
         my($self, $params) = @_;
 
 C<$params> references a hash containing
 the message priority (key C<l4p_level>), the
 message category (key C<l4p_category>) and the content of the message
 (key C<message>).
 
 If the subroutine returns 1, it will trigger a flush of buffered messages.
 
 Shortcut 
 
 =back
 
 =head1 DEVELOPMENT NOTES
 
 C<Log::Log4perl::Appender::Buffer> is a I<composite> appender.
 Unlike other appenders, it doesn't log any messages, it just
 passes them on to its attached sub-appender.
 For this reason, it doesn't need a layout (contrary to regular appenders).
 If it defines none, messages are passed on unaltered.
 
 Custom filters are also applied to the composite appender only.
 They are I<not> applied to the sub-appender. Same applies to appender
 thresholds. This behaviour might change in the future.
 
 =head1 LICENSE
 
 Copyright 2002-2013 by Mike Schilli E<lt>m@perlmeister.comE<gt> 
 and Kevin Goess E<lt>cpan@goess.orgE<gt>.
 
 This library is free software; you can redistribute it and/or modify
 it under the same terms as Perl itself. 
 
 =head1 AUTHOR
 
 Please contribute patches to the project on Github:
 
     http://github.com/mschilli/log4perl
 
 Send bug reports or requests for enhancements to the authors via our
 
 MAILING LIST (questions, bug reports, suggestions/patches): 
 log4perl-devel@lists.sourceforge.net
 
 Authors (please contact them via the list above, not directly):
 Mike Schilli <m@perlmeister.com>,
 Kevin Goess <cpan@goess.org>
 
 Contributors (in alphabetical order):
 Ateeq Altaf, Cory Bennett, Jens Berthold, Jeremy Bopp, Hutton
 Davidson, Chris R. Donnelly, Matisse Enzer, Hugh Esco, Anthony
 Foiani, James FitzGibbon, Carl Franks, Dennis Gregorovic, Andy
 Grundman, Paul Harrington, Alexander Hartmaier  David Hull, 
 Robert Jacobson, Jason Kohles, Jeff Macdonald, Markus Peter, 
 Brett Rann, Peter Rabbitson, Erik Selberg, Aaron Straup Cope, 
 Lars Thegler, David Viner, Mac Yang.
 
### Log/Log4perl/Appender/DBI.pm ###
 package Log::Log4perl::Appender::DBI;
 
 our @ISA = qw(Log::Log4perl::Appender);
 
 use Carp;
 
 use strict;
 use DBI;
 
 sub new {
     my($proto, %p) = @_;
     my $class = ref $proto || $proto;
 
     my $self = bless {}, $class;
 
     $self->_init(%p);
 
     my %defaults = (
         reconnect_attempts => 1,
         reconnect_sleep    => 0,
     );
 
     for (keys %defaults) {
         if(exists $p{$_}) {
             $self->{$_} = $p{$_};
         } else {
             $self->{$_} = $defaults{$_};
         }
     }
 
     #e.g.
     #log4j.appender.DBAppndr.params.1 = %p    
     #log4j.appender.DBAppndr.params.2 = %5.5m
     foreach my $pnum (keys %{$p{params}}){
         $self->{bind_value_layouts}{$pnum} = 
                 Log::Log4perl::Layout::PatternLayout->new({
                    ConversionPattern  => {value  => $p{params}->{$pnum}},
                    undef_column_value => undef,
                 });
     }
     #'bind_value_layouts' now contains a PatternLayout
     #for each parameter heading for the Sql engine
 
     $self->{SQL} = $p{sql}; #save for error msg later on
 
     $self->{MAX_COL_SIZE} = $p{max_col_size};
 
     $self->{BUFFERSIZE} = $p{bufferSize} || 1; 
 
     if ($p{usePreparedStmt}) {
         $self->{sth} = $self->create_statement($p{sql});
         $self->{usePreparedStmt} = 1;
     }else{
         $self->{layout} = Log::Log4perl::Layout::PatternLayout->new({
             ConversionPattern  => {value  => $p{sql}},
             undef_column_value => undef,
         });
     }
 
     if ($self->{usePreparedStmt} &&  $self->{bufferSize}){
         warn "Log4perl: you've defined both usePreparedStmt and bufferSize \n".
         "in your appender '$p{name}'--\n".
         "I'm going to ignore bufferSize and just use a prepared stmt\n";
     }
 
     return $self;
 }
 
 
 sub _init {
     my $self = shift;
     my %params = @_;
 
     if ($params{dbh}) {
         $self->{dbh} = $params{dbh};
     } else {
         $self->{connect} = sub {
             DBI->connect(@params{qw(datasource username password)},
                          {PrintError => 0, $params{attrs} ? %{$params{attrs}} : ()})
                             or croak "Log4perl: $DBI::errstr";
         };
         $self->{dbh} = $self->{connect}->();
         $self->{_mine} = 1;
     }
 }
 
 sub create_statement {
     my ($self, $stmt) = @_;
 
     $stmt || croak "Log4perl: sql not set in Log4perl::Appender::DBI";
 
     return $self->{dbh}->prepare($stmt) || croak "Log4perl: DBI->prepare failed $DBI::errstr\n$stmt";
 
 }
 
 
 sub log {
     my $self = shift;
     my %p = @_;
 
     #%p is
     #    { name    => $appender_name,
     #      level   => loglevel
     #      message => $message,
     #      log4p_category => $category,
     #      log4p_level  => $level,);
     #    },
 
         #getting log4j behavior with no specified ConversionPattern
     chomp $p{message} unless ref $p{message}; 
 
         
     my $qmarks = $self->calculate_bind_values(\%p);
 
 
     if ($self->{usePreparedStmt}) {
 
         $self->query_execute($self->{sth}, @$qmarks);
 
     }else{
 
         #first expand any %x's in the statement
         my $stmt = $self->{layout}->render(
                         $p{message},
                         $p{log4p_category},
                         $p{log4p_level},
                         5 + $Log::Log4perl::caller_depth,  
                         );
 
         push @{$self->{BUFFER}}, $stmt, $qmarks;
 
         $self->check_buffer();
     }
 }
 
 sub query_execute {
     my($self, $sth, @qmarks) = @_;
 
     my $errstr = "[no error]";
 
     for my $attempt (0..$self->{reconnect_attempts}) {
         #warn "Exe: @qmarks"; # TODO
         if(! $sth->execute(@qmarks)) {
 
                   # save errstr because ping() would override it [RT 56145]
                 $errstr = $self->{dbh}->errstr();
 
                 # Exe failed -- was it because we lost the DB
                 # connection?
                 if($self->{dbh}->ping()) {
                     # No, the connection is ok, we failed because there's
                     # something wrong with the execute(): Bad SQL or 
                     # missing parameters or some such). Abort.
                     croak "Log4perl: DBI appender error: '$errstr'";
                 }
 
                 if($attempt == $self->{reconnect_attempts}) {
                     croak "Log4perl: DBI appender failed to " .
                           ($self->{reconnect_attempts} == 1 ? "" : "re") .
                           "connect " .
                           "to database after " .
                           "$self->{reconnect_attempts} attempt" .
                           ($self->{reconnect_attempts} == 1 ? "" : "s") .
                           " (last error error was [$errstr]";
                 }
             if(! $self->{dbh}->ping()) {
                 # Ping failed, try to reconnect
                 if($attempt) {
                     #warn "Sleeping"; # TODO
                     sleep($self->{reconnect_sleep}) if $self->{reconnect_sleep};
                 }
 
                 eval {
                     #warn "Reconnecting to DB"; # TODO
                     $self->{dbh} = $self->{connect}->();
                 };
             }
 
             if ($self->{usePreparedStmt}) {
                 $sth = $self->create_statement($self->{SQL});
                 $self->{sth} = $sth if $self->{sth};
             } else {
                 #warn "Pending stmt: $self->{pending_stmt}"; #TODO
                 $sth = $self->create_statement($self->{pending_stmt});
             }
 
             next;
         }
         return 1;
     }
     croak "Log4perl: DBI->execute failed $errstr, \n".
           "on $self->{SQL}\n @qmarks";
 }
 
 sub calculate_bind_values {
     my ($self, $p) = @_;
 
     my @qmarks;
     my $user_ph_idx = 0;
 
     my $i=0;
     
     if ($self->{bind_value_layouts}) {
 
         my $prev_pnum = 0;
         my $max_pnum = 0;
     
         my @pnums = sort {$a <=> $b} keys %{$self->{bind_value_layouts}};
         $max_pnum = $pnums[-1];
         
         #Walk through the integers for each possible bind value.
         #If it doesn't have a layout assigned from the config file
         #then shift it off the array from the $log call
         #This needs to be reworked now that we always get an arrayref? --kg 1/2003
         foreach my $pnum (1..$max_pnum){
             my $msg;
     
                 #we've got a bind_value_layout to fill the spot
             if ($self->{bind_value_layouts}{$pnum}){
                $msg = $self->{bind_value_layouts}{$pnum}->render(
                         $p->{message},
                         $p->{log4p_category},
                         $p->{log4p_level},
                         5 + $Log::Log4perl::caller_depth,  
                     );
 
                #we don't have a bind_value_layout, so get
                #a message bit
             }elsif (ref $p->{message} eq 'ARRAY' && @{$p->{message}}){
                 #$msg = shift @{$p->{message}};
                 $msg = $p->{message}->[$i++];
 
                #here handle cases where we ran out of message bits
                #before we ran out of bind_value_layouts, just keep going
             }elsif (ref $p->{message} eq 'ARRAY'){
                 $msg = undef;
                 $p->{message} = undef;
 
                #here handle cases where we didn't get an arrayref
                #log the message in the first placeholder and nothing in the rest
             }elsif (! ref $p->{message} ){
                 $msg = $p->{message};
                 $p->{message} = undef;
 
             }
 
             if ($self->{MAX_COL_SIZE} &&
                 length($msg) > $self->{MAX_COL_SIZE}){
                 substr($msg, $self->{MAX_COL_SIZE}) = '';
             }
             push @qmarks, $msg;
         }
     }
 
     #handle leftovers
     if (ref $p->{message} eq 'ARRAY' && @{$p->{message}} ) {
         #push @qmarks, @{$p->{message}};
         push @qmarks, @{$p->{message}}[$i..@{$p->{message}}-1];
 
     }
 
     return \@qmarks;
 }
 
 
 sub check_buffer {
     my $self = shift;
 
     return unless ($self->{BUFFER} && ref $self->{BUFFER} eq 'ARRAY');
 
     if (scalar @{$self->{BUFFER}} >= $self->{BUFFERSIZE} * 2) {
 
         my ($sth, $stmt, $prev_stmt);
 
         $prev_stmt = ""; # Init to avoid warning (ms 5/10/03)
 
         while (@{$self->{BUFFER}}) {
             my ($stmt, $qmarks) = splice (@{$self->{BUFFER}},0,2);
 
             $self->{pending_stmt} = $stmt;
 
                 #reuse the sth if the stmt doesn't change
             if ($stmt ne $prev_stmt) {
                 $sth->finish if $sth;
                 $sth = $self->create_statement($stmt);
             }
 
             $self->query_execute($sth, @$qmarks);
 
             $prev_stmt = $stmt;
 
         }
 
         $sth->finish;
 
         my $dbh = $self->{dbh};
 
         if ($dbh && ! $dbh->{AutoCommit}) {
             $dbh->commit;
         }
     }
 }
 
 sub DESTROY {
     my $self = shift;
 
     $self->{BUFFERSIZE} = 1;
 
     $self->check_buffer();
 
     if ($self->{_mine} && $self->{dbh}) {
         $self->{dbh}->disconnect;
     }
 }
 
 
 1;
 
 __END__
 
 =encoding utf8
 
 =head1 NAME
 
 Log::Log4perl::Appender::DBI - implements appending to a DB
 
 =head1 SYNOPSIS
 
     my $config = q{
      log4j.category = WARN, DBAppndr
      log4j.appender.DBAppndr             = Log::Log4perl::Appender::DBI
      log4j.appender.DBAppndr.datasource  = DBI:CSV:f_dir=t/tmp
      log4j.appender.DBAppndr.username    = bobjones
      log4j.appender.DBAppndr.password    = 12345
      log4j.appender.DBAppndr.sql         = \
         insert into log4perltest           \
         (loglevel, custid, category, message, ipaddr) \
         values (?,?,?,?,?)
      log4j.appender.DBAppndr.params.1 = %p    
                                    #2 is custid from the log() call
      log4j.appender.DBAppndr.params.3 = %c
                                    #4 is the message from log()
                                    #5 is ipaddr from log()
 
      log4j.appender.DBAppndr.usePreparedStmt = 1
       #--or--
      log4j.appender.DBAppndr.bufferSize = 2
 
      #just pass through the array of message items in the log statement
      log4j.appender.DBAppndr.layout    = Log::Log4perl::Layout::NoopLayout
      log4j.appender.DBAppndr.warp_message = 0
 
      #driver attributes support
      log4j.appender.DBAppndr.attrs.f_encoding = utf8
     };
 
     $logger->warn( $custid, 'big problem!!', $ip_addr );
 
 =head1 CAVEAT
 
 This is a very young module and there are a lot of variations
 in setups with different databases and connection methods,
 so make sure you test thoroughly!  Any feedback is welcome!
 
 =head1 DESCRIPTION
 
 This is a specialized Log::Dispatch object customized to work with
 log4perl and its abilities, originally based on Log::Dispatch::DBI 
 by Tatsuhiko Miyagawa but with heavy modifications.
 
 It is an attempted compromise between what Log::Dispatch::DBI was 
 doing and what log4j's JDBCAppender does.  Note the log4j docs say
 the JDBCAppender "is very likely to be completely replaced in the future."
 
 The simplest usage is this:
 
     log4j.category = WARN, DBAppndr
     log4j.appender.DBAppndr            = Log::Log4perl::Appender::DBI
     log4j.appender.DBAppndr.datasource = DBI:CSV:f_dir=t/tmp
     log4j.appender.DBAppndr.username   = bobjones
     log4j.appender.DBAppndr.password   = 12345
     log4j.appender.DBAppndr.sql        = \
        INSERT INTO logtbl                \
           (loglevel, message)            \
           VALUES ('%c','%m')
 
     log4j.appender.DBAppndr.layout    = Log::Log4perl::Layout::PatternLayout
 
 
     $logger->fatal('fatal message');
     $logger->warn('warning message');
 
     ===============================
     |FATAL|fatal message          |
     |WARN |warning message        |
     ===============================
 
 
 But the downsides to that usage are:
 
 =over 4
 
 =item * 
 
 You'd better be darn sure there are not quotes in your log message, or your
 insert could have unforeseen consequences!  This is a very insecure way to
 handle database inserts, using place holders and bind values is much better, 
 keep reading. (Note that the log4j docs warn "Be careful of quotes in your 
 messages!") B<*>.
 
 =item *
 
 It's not terribly high-performance, a statement is created and executed
 for each log call.
 
 =item *
 
 The only run-time parameter you get is the %m message, in reality
 you probably want to log specific data in specific table columns.
 
 =back
 
 So let's try using placeholders, and tell the logger to create a
 prepared statement handle at the beginning and just reuse it 
 (just like Log::Dispatch::DBI does)
 
 
     log4j.appender.DBAppndr.sql = \
        INSERT INTO logtbl \
           (custid, loglevel, message) \
           VALUES (?,?,?)
 
     #---------------------------------------------------
     #now the bind values:
                                   #1 is the custid
     log4j.appender.DBAppndr.params.2 = %p    
                                   #3 is the message
     #---------------------------------------------------
 
     log4j.appender.DBAppndr.layout    = Log::Log4perl::Layout::NoopLayout
     log4j.appender.DBAppndr.warp_message = 0
     
     log4j.appender.DBAppndr.usePreparedStmt = 1
     
     
     $logger->warn( 1234, 'warning message' ); 
 
 
 Now see how we're using the '?' placeholders in our statement?  This
 means we don't have to worry about messages that look like 
 
     invalid input: 1234';drop table custid;
 
 fubaring our database!
 
 Normally a list of things in the logging statement gets concatenated into 
 a single string, but setting C<warp_message> to 0 and using the 
 NoopLayout means that in
 
     $logger->warn( 1234, 'warning message', 'bgates' );
 
 the individual list values will still be available for the DBI appender later 
 on.  (If C<warp_message> is not set to 0, the default behavior is to
 join the list elements into a single string.   If PatternLayout or SimpleLayout
 are used, their attempt to C<render()> your layout will result in something 
 like "ARRAY(0x841d8dc)" in your logs.  More information on C<warp_message>
 is in Log::Log4perl::Appender.)
 
 In your insert SQL you can mix up '?' placeholders with conversion specifiers 
 (%c, %p, etc) as you see fit--the logger will match the question marks to 
 params you've defined in the config file and populate the rest with values 
 from your list.  If there are more '?' placeholders than there are values in 
 your message, it will use undef for the rest.  For instance, 
 
 	log4j.appender.DBAppndr.sql =                 \
 	   insert into log4perltest                   \
 	   (loglevel, message, datestr, subpoena_id)\
 	   values (?,?,?,?)
 	log4j.appender.DBAppndr.params.1 = %p
 	log4j.appender.DBAppndr.params.3 = %d
 
 	log4j.appender.DBAppndr.warp_message=0
 
 
 	$logger->info('arrest him!', $subpoena_id);
 
 results in the first '?' placeholder being bound to %p, the second to
 "arrest him!", the third to the date from "%d", and the fourth to your
 $subpoenaid.  If you forget the $subpoena_id and just log
 
 	$logger->info('arrest him!');
 
 then you just get undef in the fourth column.
 
 
 If the logger statement is also being handled by other non-DBI appenders,
 they will just join the list into a string, joined with 
 C<$Log::Log4perl::JOIN_MSG_ARRAY_CHAR> (default is an empty string).
 
 And see the C<usePreparedStmt>?  That creates a statement handle when
 the logger object is created and just reuses it.  That, however, may
 be problematic for long-running processes like webservers, in which case
 you can use this parameter instead
 
     log4j.appender.DBAppndr.bufferSize=2
 
 This copies log4j's JDBCAppender's behavior, it saves up that many
 log statements and writes them all out at once.  If your INSERT
 statement uses only ? placeholders and no %x conversion specifiers
 it should be quite efficient because the logger can re-use the
 same statement handle for the inserts.
 
 If the program ends while the buffer is only partly full, the DESTROY
 block should flush the remaining statements, if the DESTROY block
 runs of course.
 
 * I<As I was writing this, Danko Mannhaupt was coming out with his
 improved log4j JDBCAppender (http://www.mannhaupt.com/danko/projects/)
 which overcomes many of the drawbacks of the original JDBCAppender.>
 
 =head1 DESCRIPTION 2
 
 Or another way to say the same thing:
 
 The idea is that if you're logging to a database table, you probably
 want specific parts of your log information in certain columns.  To this
 end, you pass an list to the log statement, like 
 
     $logger->warn('big problem!!',$userid,$subpoena_nr,$ip_addr);
 
 and the array members drop into the positions defined by the placeholders
 in your SQL statement. You can also define information in the config
 file like
 
     log4j.appender.DBAppndr.params.2 = %p    
 
 in which case those numbered placeholders will be filled in with
 the specified values, and the rest of the placeholders will be
 filled in with the values from your log statement's array.
 
 =head1 MISC PARAMETERS
 
 
 =over 4
 
 =item usePreparedStmt
 
 See above.
 
 =item warp_message
 
 see Log::Log4perl::Appender
 
 =item max_col_size
 
 If you're used to just throwing debugging messages like huge stacktraces
 into your logger, some databases (Sybase's DBD!!) may surprise you 
 by choking on data size limitations.  Normally, the data would
 just be truncated to fit in the column, but Sybases's DBD it turns out
 maxes out at 255 characters.  Use this parameter in such a situation
 to truncate long messages before they get to the INSERT statement.
 
 =back
 
 =head1 CHANGING DBH CONNECTIONS (POOLING)
 
 If you want to get your dbh from some place in particular, like
 maybe a pool, subclass and override _init() and/or create_statement(), 
 for instance 
 
     sub _init {
         ; #no-op, no pooling at this level
     }
     sub create_statement {
         my ($self, $stmt) = @_;
     
         $stmt || croak "Log4perl: sql not set in ".__PACKAGE__;
     
         return My::Connections->getConnection->prepare($stmt) 
             || croak "Log4perl: DBI->prepare failed $DBI::errstr\n$stmt";
     }
 
 
 =head1 LIFE OF CONNECTIONS
 
 If you're using C<log4j.appender.DBAppndr.usePreparedStmt>
 this module creates an sth when it starts and keeps it for the life
 of the program.  For long-running processes (e.g. mod_perl), connections
 might go stale, but if C<Log::Log4perl::Appender::DBI> tries to write
 a message and figures out that the DB connection is no longer working
 (using DBI's ping method), it will reconnect.
 
 The reconnection process can be controlled by two parameters,
 C<reconnect_attempts> and C<reconnect_sleep>. C<reconnect_attempts>
 specifies the number of reconnections attempts the DBI appender 
 performs until it gives up and dies. C<reconnect_sleep> is the
 time between reconnection attempts, measured in seconds.
 C<reconnect_attempts> defaults to 1,  C<reconnect_sleep> to 0.
 
 Alternatively, use C<Apache::DBI> or C<Apache::DBI::Cache> and read
 CHANGING DB CONNECTIONS above.
 
 Note that C<Log::Log4perl::Appender::DBI> holds one connection open
 for every appender, which might be too many.
 
 =head1 SEE ALSO
 
 L<Log::Dispatch::DBI>
 
 L<Log::Log4perl::JavaMap::JDBCAppender>
 
 =head1 LICENSE
 
 Copyright 2002-2013 by Mike Schilli E<lt>m@perlmeister.comE<gt> 
 and Kevin Goess E<lt>cpan@goess.orgE<gt>.
 
 This library is free software; you can redistribute it and/or modify
 it under the same terms as Perl itself. 
 
 =head1 AUTHOR
 
 Please contribute patches to the project on Github:
 
     http://github.com/mschilli/log4perl
 
 Send bug reports or requests for enhancements to the authors via our
 
 MAILING LIST (questions, bug reports, suggestions/patches): 
 log4perl-devel@lists.sourceforge.net
 
 Authors (please contact them via the list above, not directly):
 Mike Schilli <m@perlmeister.com>,
 Kevin Goess <cpan@goess.org>
 
 Contributors (in alphabetical order):
 Ateeq Altaf, Cory Bennett, Jens Berthold, Jeremy Bopp, Hutton
 Davidson, Chris R. Donnelly, Matisse Enzer, Hugh Esco, Anthony
 Foiani, James FitzGibbon, Carl Franks, Dennis Gregorovic, Andy
 Grundman, Paul Harrington, Alexander Hartmaier  David Hull, 
 Robert Jacobson, Jason Kohles, Jeff Macdonald, Markus Peter, 
 Brett Rann, Peter Rabbitson, Erik Selberg, Aaron Straup Cope, 
 Lars Thegler, David Viner, Mac Yang.
 
### Log/Log4perl/Appender/File.pm ###
 ##################################################
 package Log::Log4perl::Appender::File;
 ##################################################
 
 our @ISA = qw(Log::Log4perl::Appender);
 
 use warnings;
 use strict;
 use Log::Log4perl::Config::Watch;
 use Fcntl;
 use File::Path;
 use File::Spec::Functions qw(splitpath);
 use constant _INTERNAL_DEBUG => 0;
 
 ##################################################
 sub new {
 ##################################################
     my($class, @options) = @_;
 
     my $self = {
         name      => "unknown name",
         umask     => undef,
         owner     => undef,
         group     => undef,
         autoflush => 1,
         syswrite  => 0,
         mode      => "append",
         binmode   => undef,
         utf8      => undef,
         recreate  => 0,
         recreate_check_interval => 30,
         recreate_check_signal   => undef,
         recreate_pid_write      => undef,
         create_at_logtime       => 0,
         header_text             => undef,
         mkpath                  => 0,
         mkpath_umask            => 0,
         @options,
     };
 
     if($self->{create_at_logtime}) {
         $self->{recreate}  = 1;
     }
     for my $param ('umask', 'mkpath_umask') {
         if(defined $self->{$param} and $self->{$param} =~ /^0/) {
                 # umask value is a string, meant to be an oct value
             $self->{$param} = oct($self->{$param});
         }
     }
 
     die "Mandatory parameter 'filename' missing" unless
         exists $self->{filename};
 
     bless $self, $class;
 
     if($self->{recreate_pid_write}) {
         print "Creating pid file",
               " $self->{recreate_pid_write}\n" if _INTERNAL_DEBUG;
         open FILE, ">$self->{recreate_pid_write}" or
             die "Cannot open $self->{recreate_pid_write}";
         print FILE "$$\n";
         close FILE;
     }
 
         # This will die() if it fails
     $self->file_open() unless $self->{create_at_logtime};
 
     return $self;
 }
 
 ##################################################
 sub filename {
 ##################################################
     my($self) = @_;
 
     return $self->{filename};
 }
 
 ##################################################
 sub file_open {
 ##################################################
     my($self) = @_;
 
     my $arrows  = ">";
     my $sysmode = (O_CREAT|O_WRONLY);
 
 
     if($self->{mode} eq "append") {
         $arrows   = ">>";
         $sysmode |= O_APPEND;
     } elsif ($self->{mode} eq "pipe") {
         $arrows = "|";
     } else {
         $sysmode |= O_TRUNC;
     }
 
     my $fh = do { local *FH; *FH; };
 
 
     my $didnt_exist = ! -e $self->{filename};
     if($didnt_exist && $self->{mkpath}) {
         my ($volume, $path, $file) = splitpath($self->{filename});
         if($path ne '' && !-e $path) {
             my $old_umask = umask($self->{mkpath_umask}) if defined $self->{mkpath_umask};
             my $options = {};
             foreach my $param (qw(owner group) ) {
                 $options->{$param} = $self->{$param} if defined $self->{$param};
             }
             eval {
                 mkpath($path,$options);
             };
             umask($old_umask) if defined $old_umask;
             die "Can't create path ${path} ($!)" if $@;
         }
     }
 
     my $old_umask = umask($self->{umask}) if defined $self->{umask};
 
     eval {
         if($self->{syswrite}) {
             sysopen $fh, "$self->{filename}", $sysmode or
                 die "Can't sysopen $self->{filename} ($!)";
         } else {
             open $fh, "$arrows$self->{filename}" or
                 die "Can't open $self->{filename} ($!)";
         }
     };
     umask($old_umask) if defined $old_umask;
     die $@ if $@;
 
     if($didnt_exist and
          ( defined $self->{owner} or defined $self->{group} )
       ) {
 
         eval { $self->perms_fix() };
 
         if($@) {
               # Cleanup and re-throw
             unlink $self->{filename};
             die $@;
         }
     }
 
     if($self->{recreate}) {
         $self->{watcher} = Log::Log4perl::Config::Watch->new(
             file           => $self->{filename},
             (defined $self->{recreate_check_interval} ?
               (check_interval => $self->{recreate_check_interval}) : ()),
             (defined $self->{recreate_check_signal} ?
               (signal => $self->{recreate_check_signal}) : ()),
         );
     }
 
     $self->{fh} = $fh;
 
     if ($self->{autoflush} and ! $self->{syswrite}) {
         my $oldfh = select $self->{fh};
         $| = 1;
         select $oldfh;
     }
 
     if (defined $self->{binmode}) {
         binmode $self->{fh}, $self->{binmode};
     }
 
     if (defined $self->{utf8}) {
         binmode $self->{fh}, ":utf8";
     }
 
     if(defined $self->{header_text}) {
         if( $self->{header_text} !~ /\n\Z/ ) {
             $self->{header_text} .= "\n";
         }
         my $fh = $self->{fh};
         print $fh $self->{header_text};
     }
 }
 
 ##################################################
 sub file_close {
 ##################################################
     my($self) = @_;
 
     if(defined $self->{fh}) {
         $self->close_with_care( $self->{ fh } );
     }
 
     undef $self->{fh};
 }
 
 ##################################################
 sub perms_fix {
 ##################################################
     my($self) = @_;
 
     my ($uid_org, $gid_org) = (stat $self->{filename})[4,5];
 
     my ($uid, $gid) = ($uid_org, $gid_org);
 
     if(!defined $uid) {
         die "stat of $self->{filename} failed ($!)";
     }
 
     my $needs_fixing = 0;
 
     if(defined $self->{owner}) {
         $uid = $self->{owner};
         if($self->{owner} !~ /^\d+$/) {
             $uid = (getpwnam($self->{owner}))[2];
             die "Unknown user: $self->{owner}" unless defined $uid;
         }
     }
 
     if(defined $self->{group}) {
         $gid = $self->{group};
         if($self->{group} !~ /^\d+$/) {
             $gid = getgrnam($self->{group});
 
             die "Unknown group: $self->{group}" unless defined $gid;
         }
     }
     if($uid != $uid_org or $gid != $gid_org) {
         chown($uid, $gid, $self->{filename}) or
             die "chown('$uid', '$gid') on '$self->{filename}' failed: $!";
     }
 }
 
 ##################################################
 sub file_switch {
 ##################################################
     my($self, $new_filename) = @_;
 
     print "Switching file from $self->{filename} to $new_filename\n" if
         _INTERNAL_DEBUG;
 
     $self->file_close();
     $self->{filename} = $new_filename;
     $self->file_open();
 }
 
 ##################################################
 sub log {
 ##################################################
     my($self, %params) = @_;
 
     if($self->{recreate}) {
         if($self->{recreate_check_signal}) {
             if(!$self->{watcher} or
                $self->{watcher}->{signal_caught}) {
                 $self->file_switch($self->{filename});
                 $self->{watcher}->{signal_caught} = 0;
             }
         } else {
             if(!$self->{watcher} or
                 $self->{watcher}->file_has_moved()) {
                 $self->file_switch($self->{filename});
             }
         }
     }
 
     my $fh = $self->{fh};
 
     if($self->{syswrite}) {
        defined (syswrite $fh, $params{message}) or
            die "Cannot syswrite to '$self->{filename}': $!";
     } else {
         print $fh $params{message} or
             die "Cannot write to '$self->{filename}': $!";
     }
 }
 
 ##################################################
 sub DESTROY {
 ##################################################
     my($self) = @_;
 
     if ($self->{fh}) {
         my $fh = $self->{fh};
         $self->close_with_care( $fh );
     }
 }
 
 ###########################################
 sub close_with_care {
 ###########################################
     my( $self, $fh ) = @_;
 
     my $prev_rc = $?;
 
     my $rc = close $fh;
 
       # [rt #84723] If a sig handler is reaping the child generated
       # by close() internally before close() gets to it, it'll
       # result in a weird (but benign) error that we don't want to
       # expose to the user.
     if( !$rc ) {
         if( $self->{ mode } eq "pipe" and
             $!{ ECHILD } ) {
             if( $Log::Log4perl::CHATTY_DESTROY_METHODS ) {
                 warn "$$: pipe closed with ECHILD error -- guess that's ok";
             }
             $? = $prev_rc;
         } else {
             warn "Can't close $self->{filename} ($!)";
         }
     }
 
     return $rc;
 }
 
 1;
 
 __END__
 
 =encoding utf8
 
 =head1 NAME
 
 Log::Log4perl::Appender::File - Log to file
 
 =head1 SYNOPSIS
 
     use Log::Log4perl::Appender::File;
 
     my $app = Log::Log4perl::Appender::File->new(
       filename  => 'file.log',
       mode      => 'append',
       autoflush => 1,
       umask     => 0222,
     );
 
     $file->log(message => "Log me\n");
 
 =head1 DESCRIPTION
 
 This is a simple appender for writing to a file.
 
 The C<log()> method takes a single scalar. If a newline character
 should terminate the message, it has to be added explicitly.
 
 Upon destruction of the object, the filehandle to access the
 file is flushed and closed.
 
 If you want to switch over to a different logfile, use the
 C<file_switch($newfile)> method which will first close the old
 file handle and then open a one to the new file specified.
 
 =head2 OPTIONS
 
 =over 4
 
 =item filename
 
 Name of the log file.
 
 =item mode
 
 Messages will be append to the file if C<$mode> is set to the
 string C<"append">. Will clobber the file
 if set to C<"clobber">. If it is C<"pipe">, the file will be understood
 as executable to pipe output to. Default mode is C<"append">.
 
 =item autoflush
 
 C<autoflush>, if set to a true value, triggers flushing the data
 out to the file on every call to C<log()>. C<autoflush> is on by default.
 
 =item syswrite
 
 C<syswrite>, if set to a true value, makes sure that the appender uses
 syswrite() instead of print() to log the message. C<syswrite()> usually
 maps to the operating system's C<write()> function and makes sure that
 no other process writes to the same log file while C<write()> is busy.
 Might safe you from having to use other synchronisation measures like
 semaphores (see: Synchronized appender).
 
 =item umask
 
 Specifies the C<umask> to use when creating the file, determining
 the file's permission settings.
 If set to C<0022> (default), new
 files will be created with C<rw-r--r--> permissions.
 If set to C<0000>, new files will be created with C<rw-rw-rw-> permissions.
 
 =item owner
 
 If set, specifies that the owner of the newly created log file should
 be different from the effective user id of the running process.
 Only makes sense if the process is running as root.
 Both numerical user ids and user names are acceptable.
 Log4perl does not attempt to change the ownership of I<existing> files.
 
 =item group
 
 If set, specifies that the group of the newly created log file should
 be different from the effective group id of the running process.
 Only makes sense if the process is running as root.
 Both numerical group ids and group names are acceptable.
 Log4perl does not attempt to change the group membership of I<existing> files.
 
 =item utf8
 
 If you're printing out Unicode strings, the output filehandle needs
 to be set into C<:utf8> mode:
 
     my $app = Log::Log4perl::Appender::File->new(
       filename  => 'file.log',
       mode      => 'append',
       utf8      => 1,
     );
 
 =item binmode
 
 To manipulate the output filehandle via C<binmode()>, use the
 binmode parameter:
 
     my $app = Log::Log4perl::Appender::File->new(
       filename  => 'file.log',
       mode      => 'append',
       binmode   => ":utf8",
     );
 
 A setting of ":utf8" for C<binmode> is equivalent to specifying
 the C<utf8> option (see above).
 
 =item recreate
 
 Normally, if a file appender logs to a file and the file gets moved to
 a different location (e.g. via C<mv>), the appender's open file handle
 will automatically follow the file to the new location.
 
 This may be undesirable. When using an external logfile rotator,
 for example, the appender should create a new file under the old name
 and start logging into it. If the C<recreate> option is set to a true value,
 C<Log::Log4perl::Appender::File> will do exactly that. It defaults to
 false. Check the C<recreate_check_interval> option for performance
 optimizations with this feature.
 
 =item recreate_check_interval
 
 In C<recreate> mode, the appender has to continuously check if the
 file it is logging to is still in the same location. This check is
 fairly expensive, since it has to call C<stat> on the file name and
 figure out if its inode has changed. Doing this with every call
 to C<log> can be prohibitively expensive. Setting it to a positive
 integer value N will only check the file every N seconds. It defaults to 30.
 
 This obviously means that the appender will continue writing to
 a moved file until the next check occurs, in the worst case
 this will happen C<recreate_check_interval> seconds after the file
 has been moved or deleted. If this is undesirable,
 setting C<recreate_check_interval> to 0 will have the
 appender check the file with I<every> call to C<log()>.
 
 =item recreate_check_signal
 
 In C<recreate> mode, if this option is set to a signal name
 (e.g. "USR1"), the appender will recreate a missing logfile
 when it receives the signal. It uses less resources than constant
 polling. The usual limitation with perl's signal handling apply.
 Check the FAQ for using this option with the log rotating
 utility C<newsyslog>.
 
 =item recreate_pid_write
 
 The popular log rotating utility C<newsyslog> expects a pid file
 in order to send the application a signal when its logs have
 been rotated. This option expects a path to a file where the pid
 of the currently running application gets written to.
 Check the FAQ for using this option with the log rotating
 utility C<newsyslog>.
 
 =item create_at_logtime
 
 The file appender typically creates its logfile in its constructor, i.e.
 at Log4perl C<init()> time. This is desirable for most use cases, because
 it makes sure that file permission problems get detected right away, and
 not after days/weeks/months of operation when the appender suddenly needs
 to log something and fails because of a problem that was obvious at
 startup.
 
 However, there are rare use cases where the file shouldn't be created
 at Log4perl C<init()> time, e.g. if the appender can't be used by the current
 user although it is defined in the configuration file. If you set
 C<create_at_logtime> to a true value, the file appender will try to create
 the file at log time. Note that this setting lets permission problems
 sit undetected until log time, which might be undesirable.
 
 =item header_text
 
 If you want Log4perl to print a header into every newly opened
 (or re-opened) logfile, set C<header_text> to either a string
 or a subroutine returning a string. If the message doesn't have a newline,
 a newline at the end of the header will be provided.
 
 =item mkpath
 
 If this this option is set to true,
 the directory path will be created if it does not exist yet.
 
 =item mkpath_umask
 
 Specifies the C<umask> to use when creating the directory, determining
 the directory's permission settings.
 If set to C<0022> (default), new
 directory will be created with C<rwxr-xr-x> permissions.
 If set to C<0000>, new directory will be created with C<rwxrwxrwx> permissions.
 
 =back
 
 Design and implementation of this module has been greatly inspired by
 Dave Rolsky's C<Log::Dispatch> appender framework.
 
 =head1 LICENSE
 
 Copyright 2002-2013 by Mike Schilli E<lt>m@perlmeister.comE<gt>
 and Kevin Goess E<lt>cpan@goess.orgE<gt>.
 
 This library is free software; you can redistribute it and/or modify
 it under the same terms as Perl itself.
 
 =head1 AUTHOR
 
 Please contribute patches to the project on Github:
 
     http://github.com/mschilli/log4perl
 
 Send bug reports or requests for enhancements to the authors via our
 
 MAILING LIST (questions, bug reports, suggestions/patches):
 log4perl-devel@lists.sourceforge.net
 
 Authors (please contact them via the list above, not directly):
 Mike Schilli <m@perlmeister.com>,
 Kevin Goess <cpan@goess.org>
 
 Contributors (in alphabetical order):
 Ateeq Altaf, Cory Bennett, Jens Berthold, Jeremy Bopp, Hutton
 Davidson, Chris R. Donnelly, Matisse Enzer, Hugh Esco, Anthony
 Foiani, James FitzGibbon, Carl Franks, Dennis Gregorovic, Andy
 Grundman, Paul Harrington, Alexander Hartmaier  David Hull,
 Robert Jacobson, Jason Kohles, Jeff Macdonald, Markus Peter,
 Brett Rann, Peter Rabbitson, Erik Selberg, Aaron Straup Cope,
 Lars Thegler, David Viner, Mac Yang.
 
### Log/Log4perl/Appender/Limit.pm ###
 ######################################################################
 # Limit.pm -- 2003, Mike Schilli <m@perlmeister.com>
 ######################################################################
 # Special composite appender limiting the number of messages relayed
 # to its appender(s).
 ######################################################################
 
 ###########################################
 package Log::Log4perl::Appender::Limit;
 ###########################################
 
 use strict;
 use warnings;
 use Storable;
 
 our @ISA = qw(Log::Log4perl::Appender);
 
 our $CVSVERSION   = '$Revision: 1.7 $';
 our ($VERSION)    = ($CVSVERSION =~ /(\d+\.\d+)/);
 
 ###########################################
 sub new {
 ###########################################
     my($class, %options) = @_;
 
     my $self = {
         max_until_flushed   => undef,
         max_until_discarded => undef,
         appender_method_on_flush 
                             => undef,
         appender            => undef,
         accumulate          => 1,
         persistent          => undef,
         block_period        => 3600,
         buffer              => [],
         %options,
     };
 
         # Pass back the appender to be limited as a dependency
         # to the configuration file parser
     push @{$options{l4p_depends_on}}, $self->{appender};
 
         # Run our post_init method in the configurator after
         # all appenders have been defined to make sure the
         # appenders we're connecting to really exist.
     push @{$options{l4p_post_config_subs}}, sub { $self->post_init() };
 
     bless $self, $class;
 
     if(defined $self->{persistent}) {
         $self->restore();
     }
 
     return $self;
 }
 
 ###########################################
 sub log {
 ###########################################
     my($self, %params) = @_;
     
     local $Log::Log4perl::caller_depth =
         $Log::Log4perl::caller_depth + 2;
 
         # Check if message needs to be discarded
     my $discard = 0;
     if(defined $self->{max_until_discarded} and
        scalar @{$self->{buffer}} >= $self->{max_until_discarded} - 1) {
         $discard = 1;
     }
 
         # Check if we need to flush
     my $flush = 0;
     if(defined $self->{max_until_flushed} and
        scalar @{$self->{buffer}} >= $self->{max_until_flushed} - 1) {
         $flush = 1;
     }
 
     if(!$flush and
        (exists $self->{sent_last} and
         $self->{sent_last} + $self->{block_period} > time()
        )
       ) {
             # Message needs to be blocked for now.
         return if $discard;
 
             # Ask the appender to save a cached message in $cache
         $self->{app}->SUPER::log(\%params,
                              $params{log4p_category},
                              $params{log4p_level}, \my $cache);
 
             # Save message and other parameters
         push @{$self->{buffer}}, $cache if $self->{accumulate};
 
         $self->save() if $self->{persistent};
 
         return;
     }
 
     # Relay all messages we got to the SUPER class, which needs to render the
     # messages according to the appender's layout, first.
 
         # Log pending messages if we have any
     $self->flush();
 
         # Log current message as well
     $self->{app}->SUPER::log(\%params,
                              $params{log4p_category},
                              $params{log4p_level});
 
     $self->{sent_last} = time();
 
         # We need to store the timestamp persistently, if requested
     $self->save() if $self->{persistent};
 }
 
 ###########################################
 sub post_init {
 ###########################################
     my($self) = @_;
 
     if(! exists $self->{appender}) {
        die "No appender defined for " . __PACKAGE__;
     }
 
     my $appenders = Log::Log4perl->appenders();
     my $appender = Log::Log4perl->appenders()->{$self->{appender}};
 
     if(! defined $appender) {
        die "Appender $self->{appender} not defined (yet) when " .
            __PACKAGE__ . " needed it";
     }
 
     $self->{app} = $appender;
 }
 
 ###########################################
 sub save {
 ###########################################
     my($self) = @_;
 
     my $pdata = [$self->{buffer}, $self->{sent_last}];
 
         # Save the buffer if we're in persistent mode
     store $pdata, $self->{persistent} or
         die "Cannot save messages in $self->{persistent} ($!)";
 }
 
 ###########################################
 sub restore {
 ###########################################
     my($self) = @_;
 
     if(-f $self->{persistent}) {
         my $pdata = retrieve $self->{persistent} or
             die "Cannot retrieve messages from $self->{persistent} ($!)";
         ($self->{buffer}, $self->{sent_last}) = @$pdata;
     }
 }
 
 ###########################################
 sub flush {
 ###########################################
     my($self) = @_;
 
         # Log pending messages if we have any
     for(@{$self->{buffer}}) {
         $self->{app}->SUPER::log_cached($_);
     }
 
       # call flush() on the attached appender if so desired.
     if( $self->{appender_method_on_flush} ) {
         no strict 'refs';
         my $method = $self->{appender_method_on_flush};
         $self->{app}->$method();
     }
 
         # Empty buffer
     $self->{buffer} = [];
 }
 
 ###########################################
 sub DESTROY {
 ###########################################
     my($self) = @_;
 
 }
 
 1;
 
 __END__
 
 =encoding utf8
 
 =head1 NAME
 
     Log::Log4perl::Appender::Limit - Limit message delivery via block period
 
 =head1 SYNOPSIS
 
     use Log::Log4perl qw(:easy);
 
     my $conf = qq(
       log4perl.category = WARN, Limiter
     
           # Email appender
       log4perl.appender.Mailer          = Log::Dispatch::Email::MailSend
       log4perl.appender.Mailer.to       = drone\@pageme.com
       log4perl.appender.Mailer.subject  = Something's broken!
       log4perl.appender.Mailer.buffered = 0
       log4perl.appender.Mailer.layout   = PatternLayout
       log4perl.appender.Mailer.layout.ConversionPattern=%d %m %n
 
           # Limiting appender, using the email appender above
       log4perl.appender.Limiter              = Log::Log4perl::Appender::Limit
       log4perl.appender.Limiter.appender     = Mailer
       log4perl.appender.Limiter.block_period = 3600
     );
 
     Log::Log4perl->init(\$conf);
     WARN("This message will be sent immediately.");
     WARN("This message will be delayed by one hour.");
     sleep(3601);
     WARN("This message plus the last one will be sent now, seperately.");
 
 =head1 DESCRIPTION
 
 =over 4
 
 =item C<appender>
 
 Specifies the name of the appender used by the limiter. The
 appender specified must be defined somewhere in the configuration file,
 not necessarily before the definition of 
 C<Log::Log4perl::Appender::Limit>.
 
 =item C<block_period>
 
 Period in seconds between delivery of messages. If messages arrive in between,
 they will be either saved (if C<accumulate> is set to a true value) or
 discarded (if C<accumulate> isn't set).
 
 =item C<persistent>
 
 File name in which C<Log::Log4perl::Appender::Limit> persistently stores 
 delivery times. If omitted, the appender will have no recollection of what
 happened when the program restarts.
 
 =item C<max_until_flushed>
 
 Maximum number of accumulated messages. If exceeded, the appender flushes 
 all messages, regardless if the interval set in C<block_period> 
 has passed or not. Don't mix with C<max_until_discarded>.
 
 =item C<max_until_discarded>
 
 Maximum number of accumulated messages. If exceeded, the appender will
 simply discard additional messages, waiting for C<block_period> to expire
 to flush all accumulated messages. Don't mix with C<max_until_flushed>.
 
 =item C<appender_method_on_flush>
 
 Optional method name to be called on the appender attached to the
 limiter when messages are flushed. For example, to have the sample code 
 in the SYNOPSIS section bundle buffered emails into one, change the 
 mailer's C<buffered> parameter to C<1> and set the limiters 
 C<appender_method_on_flush> value to the string C<"flush">:
 
       log4perl.category = WARN, Limiter
     
           # Email appender
       log4perl.appender.Mailer          = Log::Dispatch::Email::MailSend
       log4perl.appender.Mailer.to       = drone\@pageme.com
       log4perl.appender.Mailer.subject  = Something's broken!
       log4perl.appender.Mailer.buffered = 1
       log4perl.appender.Mailer.layout   = PatternLayout
       log4perl.appender.Mailer.layout.ConversionPattern=%d %m %n
 
           # Limiting appender, using the email appender above
       log4perl.appender.Limiter              = Log::Log4perl::Appender::Limit
       log4perl.appender.Limiter.appender     = Mailer
       log4perl.appender.Limiter.block_period = 3600
       log4perl.appender.Limiter.appender_method_on_flush = flush
 
 This will cause the mailer to buffer messages and wait for C<flush()>
 to send out the whole batch. The limiter will then call the appender's
 C<flush()> method when it's own buffer gets flushed out.
 
 =back
 
 If the appender attached to C<Limit> uses C<PatternLayout> with a timestamp
 specifier, you will notice that the message timestamps are reflecting the
 original log event, not the time of the message rendering in the
 attached appender. Major trickery has been applied to accomplish 
 this (Cough!).
 
 =head1 DEVELOPMENT NOTES
 
 C<Log::Log4perl::Appender::Limit> is a I<composite> appender.
 Unlike other appenders, it doesn't log any messages, it just
 passes them on to its attached sub-appender.
 For this reason, it doesn't need a layout (contrary to regular appenders).
 If it defines none, messages are passed on unaltered.
 
 Custom filters are also applied to the composite appender only.
 They are I<not> applied to the sub-appender. Same applies to appender
 thresholds. This behaviour might change in the future.
 
 =head1 LICENSE
 
 Copyright 2002-2013 by Mike Schilli E<lt>m@perlmeister.comE<gt> 
 and Kevin Goess E<lt>cpan@goess.orgE<gt>.
 
 This library is free software; you can redistribute it and/or modify
 it under the same terms as Perl itself. 
 
 =head1 AUTHOR
 
 Please contribute patches to the project on Github:
 
     http://github.com/mschilli/log4perl
 
 Send bug reports or requests for enhancements to the authors via our
 
 MAILING LIST (questions, bug reports, suggestions/patches): 
 log4perl-devel@lists.sourceforge.net
 
 Authors (please contact them via the list above, not directly):
 Mike Schilli <m@perlmeister.com>,
 Kevin Goess <cpan@goess.org>
 
 Contributors (in alphabetical order):
 Ateeq Altaf, Cory Bennett, Jens Berthold, Jeremy Bopp, Hutton
 Davidson, Chris R. Donnelly, Matisse Enzer, Hugh Esco, Anthony
 Foiani, James FitzGibbon, Carl Franks, Dennis Gregorovic, Andy
 Grundman, Paul Harrington, Alexander Hartmaier  David Hull, 
 Robert Jacobson, Jason Kohles, Jeff Macdonald, Markus Peter, 
 Brett Rann, Peter Rabbitson, Erik Selberg, Aaron Straup Cope, 
 Lars Thegler, David Viner, Mac Yang.
 
### Log/Log4perl/Appender/RRDs.pm ###
 ##################################################
 package Log::Log4perl::Appender::RRDs;
 ##################################################
 our @ISA = qw(Log::Log4perl::Appender);
 
 use warnings;
 use strict;
 use RRDs;
 
 ##################################################
 sub new {
 ##################################################
     my($class, @options) = @_;
 
     my $self = {
         name             => "unknown name",
         dbname           => undef,
         rrdupd_params => [],
         @options,
     };
 
     die "Mandatory parameter 'dbname' missing" unless
         defined $self->{dbname};
 
     bless $self, $class;
 
     return $self;
 }
 
 ##################################################
 sub log {
 ##################################################
     my($self, %params) = @_;
 
     #print "UPDATE: '$self->{dbname}' - '$params{message}'\n";
 
     RRDs::update($self->{dbname}, 
                  @{$params{rrdupd_params}},
                  $params{message}) or
         die "Cannot update rrd $self->{dbname} ",
             "with $params{message} ($!)";
 }
 
 1;
 
 __END__
 
 =encoding utf8
 
 =head1 NAME
 
 Log::Log4perl::Appender::RRDs - Log to a RRDtool Archive
     
 =head1 SYNOPSIS
     
     use Log::Log4perl qw(get_logger);
     use RRDs;
     
     my $DB = "myrrddb.dat";
     
     RRDs::create(
       $DB, "--step=1",
       "DS:myvalue:GAUGE:2:U:U",
       "RRA:MAX:0.5:1:120");
     
     print time(), "\n";
     
     Log::Log4perl->init(\qq{
       log4perl.category = INFO, RRDapp
       log4perl.appender.RRDapp = Log::Log4perl::Appender::RRDs
       log4perl.appender.RRDapp.dbname = $DB
       log4perl.appender.RRDapp.layout = Log::Log4perl::Layout::PatternLayout
       log4perl.appender.RRDapp.layout.ConversionPattern = N:%m
     });
     
     my $logger = get_logger();
     
     for(10, 15, 20, 25) {
         $logger->info($_);
         sleep 1;
     }
    
 =head1 DESCRIPTION
 
 C<Log::Log4perl::Appender::RRDs> appenders facilitate writing data
 to RRDtool round-robin archives via Log4perl. For documentation
 on RRD and its Perl interface C<RRDs> (which comes with the distribution),
 check out L<http://rrdtool.org>.
 
 Messages sent to Log4perl's RRDs appender are expected to be numerical values
 (ints or floats), which then are used to run a C<rrdtool update> command
 on an existing round-robin database. The name of this database needs to
 be set in the appender's C<dbname> configuration parameter.
 
 If there's more parameters you wish to pass to the C<update> method,
 use the C<rrdupd_params> configuration parameter:
 
     log4perl.appender.RRDapp.rrdupd_params = --template=in:out
 
 To read out the round robin database later on, use C<rrdtool fetch>
 or C<rrdtool graph> for graphic displays.
 
 =head1 LICENSE
 
 Copyright 2002-2013 by Mike Schilli E<lt>m@perlmeister.comE<gt> 
 and Kevin Goess E<lt>cpan@goess.orgE<gt>.
 
 This library is free software; you can redistribute it and/or modify
 it under the same terms as Perl itself. 
 
 =head1 AUTHOR
 
 Please contribute patches to the project on Github:
 
     http://github.com/mschilli/log4perl
 
 Send bug reports or requests for enhancements to the authors via our
 
 MAILING LIST (questions, bug reports, suggestions/patches): 
 log4perl-devel@lists.sourceforge.net
 
 Authors (please contact them via the list above, not directly):
 Mike Schilli <m@perlmeister.com>,
 Kevin Goess <cpan@goess.org>
 
 Contributors (in alphabetical order):
 Ateeq Altaf, Cory Bennett, Jens Berthold, Jeremy Bopp, Hutton
 Davidson, Chris R. Donnelly, Matisse Enzer, Hugh Esco, Anthony
 Foiani, James FitzGibbon, Carl Franks, Dennis Gregorovic, Andy
 Grundman, Paul Harrington, Alexander Hartmaier  David Hull, 
 Robert Jacobson, Jason Kohles, Jeff Macdonald, Markus Peter, 
 Brett Rann, Peter Rabbitson, Erik Selberg, Aaron Straup Cope, 
 Lars Thegler, David Viner, Mac Yang.
 
### Log/Log4perl/Appender/Screen.pm ###
 ##################################################
 package Log::Log4perl::Appender::Screen;
 ##################################################
 
 our @ISA = qw(Log::Log4perl::Appender);
 
 use warnings;
 use strict;
 
 ##################################################
 sub new {
 ##################################################
     my($class, @options) = @_;
 
     my $self = {
         name   => "unknown name",
         stderr => 1,
         utf8   => undef,
         @options,
     };
 
     if( $self->{utf8} ) {
         if( $self->{stderr} ) {
             binmode STDERR, ":utf8";
         } else {
             binmode STDOUT, ":utf8";
         }
     }
 
     bless $self, $class;
 }
     
 ##################################################
 sub log {
 ##################################################
     my($self, %params) = @_;
 
     if($self->{stderr}) {
         print STDERR $params{message};
     } else {
         print $params{message};
     }
 }
 
 1;
 
 __END__
 
 =encoding utf8
 
 =head1 NAME
 
 Log::Log4perl::Appender::Screen - Log to STDOUT/STDERR
 
 =head1 SYNOPSIS
 
     use Log::Log4perl::Appender::Screen;
 
     my $app = Log::Log4perl::Appender::Screen->new(
       stderr    => 0,
       utf8      => 1,
     );
 
     $file->log(message => "Log me\n");
 
 =head1 DESCRIPTION
 
 This is a simple appender for writing to STDOUT or STDERR.
 
 The constructor C<new()> take an optional parameter C<stderr>,
 if set to a true value, the appender will log to STDERR. 
 The default setting for C<stderr> is 1, so messages will be logged to 
 STDERR by default.
 
 If C<stderr>
 is set to a false value, it will log to STDOUT (or, more accurately,
 whichever file handle is selected via C<select()>, STDOUT by default). 
 
 Design and implementation of this module has been greatly inspired by
 Dave Rolsky's C<Log::Dispatch> appender framework.
 
 To enable printing wide utf8 characters, set the utf8 option to a true
 value:
 
     my $app = Log::Log4perl::Appender::Screen->new(
       stderr    => 1,
       utf8      => 1,
     );
 
 This will issue the necessary binmode command to the selected output
 channel (stderr/stdout).
 
 =head1 LICENSE
 
 Copyright 2002-2013 by Mike Schilli E<lt>m@perlmeister.comE<gt> 
 and Kevin Goess E<lt>cpan@goess.orgE<gt>.
 
 This library is free software; you can redistribute it and/or modify
 it under the same terms as Perl itself. 
 
 =head1 AUTHOR
 
 Please contribute patches to the project on Github:
 
     http://github.com/mschilli/log4perl
 
 Send bug reports or requests for enhancements to the authors via our
 
 MAILING LIST (questions, bug reports, suggestions/patches): 
 log4perl-devel@lists.sourceforge.net
 
 Authors (please contact them via the list above, not directly):
 Mike Schilli <m@perlmeister.com>,
 Kevin Goess <cpan@goess.org>
 
 Contributors (in alphabetical order):
 Ateeq Altaf, Cory Bennett, Jens Berthold, Jeremy Bopp, Hutton
 Davidson, Chris R. Donnelly, Matisse Enzer, Hugh Esco, Anthony
 Foiani, James FitzGibbon, Carl Franks, Dennis Gregorovic, Andy
 Grundman, Paul Harrington, Alexander Hartmaier  David Hull, 
 Robert Jacobson, Jason Kohles, Jeff Macdonald, Markus Peter, 
 Brett Rann, Peter Rabbitson, Erik Selberg, Aaron Straup Cope, 
 Lars Thegler, David Viner, Mac Yang.
 
### Log/Log4perl/Appender/ScreenColoredLevels.pm ###
 ##################################################
 package Log::Log4perl::Appender::ScreenColoredLevels;
 ##################################################
 use Log::Log4perl::Appender::Screen;
 our @ISA = qw(Log::Log4perl::Appender::Screen);
 
 use warnings;
 use strict;
 
 use Term::ANSIColor qw();
 use Log::Log4perl::Level;
 
 BEGIN {
     $Term::ANSIColor::EACHLINE="\n";
 }
 
 ##################################################
 sub new {
 ##################################################
     my($class, %options) = @_;
 
     my %specific_options = ( color => {} );
 
     for my $option ( keys %specific_options ) {
         $specific_options{ $option } = delete $options{ $option } if
             exists $options{ $option };
     }
 
     my $self = $class->SUPER::new( %options );
     @$self{ keys %specific_options } = values %specific_options;
     bless $self, __PACKAGE__; # rebless
 
       # also accept lower/mixed case levels in config
     for my $level ( keys %{ $self->{color} } ) {
         my $uclevel = uc($level);
         $self->{color}->{$uclevel} = $self->{color}->{$level};
     }
 
     my %default_colors = (
         TRACE   => 'yellow',
         DEBUG   => '',
         INFO    => 'green',
         WARN    => 'blue',
         ERROR   => 'magenta',
         FATAL   => 'red',
     );
     for my $level ( keys %default_colors ) {
         if ( ! exists $self->{ 'color' }->{ $level } ) {
             $self->{ 'color' }->{ $level } = $default_colors{ $level };
         }
     }
 
     bless $self, $class;
 }
     
 ##################################################
 sub log {
 ##################################################
     my($self, %params) = @_;
 
     my $msg = $params{ 'message' };
 
     if ( my $color = $self->{ 'color' }->{ $params{ 'log4p_level' } } ) {
         $msg = Term::ANSIColor::colored( $msg, $color );
     }
     
     if($self->{stderr}) {
         print STDERR $msg;
     } else {
         print $msg;
     }
 }
 
 1;
 
 __END__
 
 =encoding utf8
 
 =head1 NAME
 
 Log::Log4perl::Appender::ScreenColoredLevel - Colorize messages according to level
 
 =head1 SYNOPSIS
 
     use Log::Log4perl qw(:easy);
 
     Log::Log4perl->init(\ <<'EOT');
       log4perl.category = DEBUG, Screen
       log4perl.appender.Screen = \
           Log::Log4perl::Appender::ScreenColoredLevels
       log4perl.appender.Screen.layout = \
           Log::Log4perl::Layout::PatternLayout
       log4perl.appender.Screen.layout.ConversionPattern = \
           %d %F{1} %L> %m %n
     EOT
 
       # Appears black
     DEBUG "Debug Message";
 
       # Appears green
     INFO  "Info Message";
 
       # Appears blue
     WARN  "Warn Message";
 
       # Appears magenta
     ERROR "Error Message";
 
       # Appears red
     FATAL "Fatal Message";
 
 =head1 DESCRIPTION
 
 This appender acts like Log::Log4perl::Appender::Screen, except that
 it colorizes its output, based on the priority of the message sent.
 
 You can configure the colors and attributes used for the different
 levels, by specifying them in your configuration:
 
     log4perl.appender.Screen.color.TRACE=cyan
     log4perl.appender.Screen.color.DEBUG=bold blue
 
 You can also specify nothing, to indicate that level should not have
 coloring applied, which means the text will be whatever the default
 color for your terminal is.  This is the default for debug messages.
 
     log4perl.appender.Screen.color.DEBUG=
 
 You can use any attribute supported by L<Term::ANSIColor> as a configuration
 option.
 
     log4perl.appender.Screen.color.FATAL=\
         bold underline blink red on_white
 
 The commonly used colors and attributes are:
 
 =over 4
 
 =item attributes
 
 BOLD, DARK, UNDERLINE, UNDERSCORE, BLINK
 
 =item colors
 
 BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE
 
 =item background colors
 
 ON_BLACK, ON_RED, ON_GREEN, ON_YELLOW, ON_BLUE, ON_MAGENTA, ON_CYAN, ON_WHITE
 
 =back
 
 See L<Term::ANSIColor> for a complete list, and information on which are
 supported by various common terminal emulators.
 
 The default values for these options are:
 
 =over 4
 
 =item Trace
 
 Yellow
 
 =item Debug
 
 None (whatever the terminal default is)
 
 =item Info
 
 Green
 
 =item Warn
 
 Blue
 
 =item Error
 
 Magenta
 
 =item Fatal
 
 Red
 
 =back
 
 The constructor C<new()> takes an optional parameter C<stderr>,
 if set to a true value, the appender will log to STDERR. If C<stderr>
 is set to a false value, it will log to STDOUT. The default setting
 for C<stderr> is 1, so messages will be logged to STDERR by default.
 The constructor can also take an optional parameter C<color>, whose
 value is a  hashref of color configuration options, any levels that
 are not included in the hashref will be set to their default values.
 
 =head2 Using ScreenColoredLevels on Windows
 
 Note that if you're using this appender on Windows, you need to fetch
 Win32::Console::ANSI from CPAN and add
 
     use Win32::Console::ANSI;
 
 to your script.
 
 =head1 LICENSE
 
 Copyright 2002-2013 by Mike Schilli E<lt>m@perlmeister.comE<gt> 
 and Kevin Goess E<lt>cpan@goess.orgE<gt>.
 
 This library is free software; you can redistribute it and/or modify
 it under the same terms as Perl itself. 
 
 =head1 AUTHOR
 
 Please contribute patches to the project on Github:
 
     http://github.com/mschilli/log4perl
 
 Send bug reports or requests for enhancements to the authors via our
 
 MAILING LIST (questions, bug reports, suggestions/patches): 
 log4perl-devel@lists.sourceforge.net
 
 Authors (please contact them via the list above, not directly):
 Mike Schilli <m@perlmeister.com>,
 Kevin Goess <cpan@goess.org>
 
 Contributors (in alphabetical order):
 Ateeq Altaf, Cory Bennett, Jens Berthold, Jeremy Bopp, Hutton
 Davidson, Chris R. Donnelly, Matisse Enzer, Hugh Esco, Anthony
 Foiani, James FitzGibbon, Carl Franks, Dennis Gregorovic, Andy
 Grundman, Paul Harrington, Alexander Hartmaier  David Hull, 
 Robert Jacobson, Jason Kohles, Jeff Macdonald, Markus Peter, 
 Brett Rann, Peter Rabbitson, Erik Selberg, Aaron Straup Cope, 
 Lars Thegler, David Viner, Mac Yang.
 
### Log/Log4perl/Appender/Socket.pm ###
 ##################################################
 package Log::Log4perl::Appender::Socket;
 ##################################################
 our @ISA = qw(Log::Log4perl::Appender);
 
 use warnings;
 use strict;
 
 use IO::Socket::INET;
 
 ##################################################
 sub new {
 ##################################################
     my($class, @options) = @_;
 
     my $self = {
         name            => "unknown name",
         silent_recovery => 0,
         no_warning      => 0,
         PeerAddr        => "localhost",
         Proto           => 'tcp',
         Timeout         => 5,
         @options,
     };
 
     bless $self, $class;
 
     unless ($self->{defer_connection}){
         unless($self->connect(@options)) {
             if($self->{silent_recovery}) {
                 if( ! $self->{no_warning}) {
                     warn "Connect to $self->{PeerAddr}:$self->{PeerPort} failed: $!";
                 }
                return $self;
             }
             die "Connect to $self->{PeerAddr}:$self->{PeerPort} failed: $!";
         }
 
         $self->{socket}->autoflush(1); 
         #autoflush has been the default behavior since 1997
     }
 
     return $self;
 }
     
 ##################################################
 sub connect {
 ##################################################
     my($self, @options) = @_;
 
     $self->{socket} = IO::Socket::INET->new(@options);
 
     return $self->{socket};
 }
 
 ##################################################
 sub log {
 ##################################################
     my($self, %params) = @_;
 
 
     {
             # If we were never able to establish
             # a connection, try to establish one 
             # here. If it fails, return.
         if(($self->{silent_recovery} or $self->{defer_connection}) and 
            !defined $self->{socket}) {
             if(! $self->connect(%$self)) {
                 return undef;
             }
         }
   
             # Try to send the message across
         eval { $self->{socket}->send($params{message}); 
              };
 
         if($@) {
             warn "Send to " . ref($self) . " failed ($@), retrying once...";
             if($self->connect(%$self)) {
                 redo;
             }
             if($self->{silent_recovery}) {
                 return undef;
             }
             warn "Reconnect to $self->{PeerAddr}:$self->{PeerPort} " .
                  "failed: $!";
             return undef;
         }
     };
 
     return 1;
 }
 
 ##################################################
 sub DESTROY {
 ##################################################
     my($self) = @_;
 
     undef $self->{socket};
 }
 
 1;
 
 __END__
 
 =encoding utf8
 
 =head1 NAME
 
 Log::Log4perl::Appender::Socket - Log to a socket
 
 =head1 SYNOPSIS
 
     use Log::Log4perl::Appender::Socket;
 
     my $appender = Log::Log4perl::Appender::Socket->new(
       PeerAddr => "server.foo.com",
       PeerPort => 1234,
     );
 
     $appender->log(message => "Log me\n");
 
 =head1 DESCRIPTION
 
 This is a simple appender for writing to a socket. It relies on
 L<IO::Socket::INET> and offers all parameters this module offers.
 
 Upon destruction of the object, pending messages will be flushed
 and the socket will be closed.
 
 If the appender cannot contact the server during the initialization
 phase (while running the constructor C<new>), it will C<die()>.
 
 If the appender fails to log a message because the socket's C<send()>
 method fails (most likely because the server went down), it will
 try to reconnect once. If it succeeds, the message will be sent.
 If the reconnect fails, a warning is sent to STDERR and the C<log()>
 method returns, discarding the message.
 
 If the option C<silent_recovery> is given to the constructor and
 set to a true value, the behaviour is different: If the socket connection
 can't be established at initialization time, a single warning is issued.
 Every log attempt will then try to establish the connection and 
 discard the message silently if it fails.
 If you don't even want the warning, set the C<no_warning> option to
 a true value.
 
 Connecting at initialization time may not be the best option when
 running under Apache1 Apache2/prefork, because the parent process creates
 the socket and the connections are shared among the forked children--all
 the children writing to the same socket could intermingle messages.  So instead
 of that, you can use C<defer_connection> which will put off making the
 connection until the first log message is sent.
 
 =head1 EXAMPLE
 
 Write a server quickly using the IO::Socket::INET module:
 
     use IO::Socket::INET;
 
     my $sock = IO::Socket::INET->new(
         Listen    => 5,
         LocalAddr => 'localhost',
         LocalPort => 12345,
         Proto     => 'tcp');
 
     while(my $client = $sock->accept()) {
         print "Client connected\n";
         while(<$client>) {
             print "$_\n";
         }
     }
 
 Start it and then run the following script as a client:
 
     use Log::Log4perl qw(:easy);
 
     my $conf = q{
         log4perl.category                  = WARN, Socket
         log4perl.appender.Socket           = Log::Log4perl::Appender::Socket
         log4perl.appender.Socket.PeerAddr  = localhost
         log4perl.appender.Socket.PeerPort  = 12345
         log4perl.appender.Socket.layout    = SimpleLayout
     };
 
     Log::Log4perl->init(\$conf);
 
     sleep(2);
 
     for(1..10) {
         ERROR("Quack!");
         sleep(5);
     }
 
 =head1 LICENSE
 
 Copyright 2002-2013 by Mike Schilli E<lt>m@perlmeister.comE<gt> 
 and Kevin Goess E<lt>cpan@goess.orgE<gt>.
 
 This library is free software; you can redistribute it and/or modify
 it under the same terms as Perl itself. 
 
 =head1 AUTHOR
 
 Please contribute patches to the project on Github:
 
     http://github.com/mschilli/log4perl
 
 Send bug reports or requests for enhancements to the authors via our
 
 MAILING LIST (questions, bug reports, suggestions/patches): 
 log4perl-devel@lists.sourceforge.net
 
 Authors (please contact them via the list above, not directly):
 Mike Schilli <m@perlmeister.com>,
 Kevin Goess <cpan@goess.org>
 
 Contributors (in alphabetical order):
 Ateeq Altaf, Cory Bennett, Jens Berthold, Jeremy Bopp, Hutton
 Davidson, Chris R. Donnelly, Matisse Enzer, Hugh Esco, Anthony
 Foiani, James FitzGibbon, Carl Franks, Dennis Gregorovic, Andy
 Grundman, Paul Harrington, Alexander Hartmaier  David Hull, 
 Robert Jacobson, Jason Kohles, Jeff Macdonald, Markus Peter, 
 Brett Rann, Peter Rabbitson, Erik Selberg, Aaron Straup Cope, 
 Lars Thegler, David Viner, Mac Yang.
 
### Log/Log4perl/Appender/String.pm ###
 package Log::Log4perl::Appender::String;
 our @ISA = qw(Log::Log4perl::Appender);
 
 ##################################################
 # Log dispatcher writing to a string buffer
 ##################################################
 
 ##################################################
 sub new {
 ##################################################
     my $proto  = shift;
     my $class  = ref $proto || $proto;
     my %params = @_;
 
     my $self = {
         name      => "unknown name",
         string    => "",
         %params,
     };
 
     bless $self, $class;
 }
 
 ##################################################
 sub log {   
 ##################################################
     my $self = shift;
     my %params = @_;
 
     $self->{string} .= $params{message};
 }
 
 ##################################################
 sub string {   
 ##################################################
     my($self, $new) = @_;
 
     if(defined $new) {
         $self->{string} = $new;
     }
 
     return $self->{string};
 }
 
 1;
 
 __END__
 
 =encoding utf8
 
 =head1 NAME
 
 Log::Log4perl::Appender::String - Append to a string
 
 =head1 SYNOPSIS
 
   use Log::Log4perl::Appender::String;
 
   my $appender = Log::Log4perl::Appender::String->new( 
       name      => 'my string appender',
   );
 
       # Append to the string
   $appender->log( 
       message => "I'm searching the city for sci-fi wasabi\n" 
   );
 
       # Retrieve the result
   my $result = $appender->string();
 
       # Reset the buffer to the empty string
   $appender->string("");
 
 =head1 DESCRIPTION
 
 This is a simple appender used internally by C<Log::Log4perl>. It
 appends messages to a scalar instance variable.
 
 =head1 LICENSE
 
 Copyright 2002-2013 by Mike Schilli E<lt>m@perlmeister.comE<gt> 
 and Kevin Goess E<lt>cpan@goess.orgE<gt>.
 
 This library is free software; you can redistribute it and/or modify
 it under the same terms as Perl itself. 
 
 =head1 AUTHOR
 
 Please contribute patches to the project on Github:
 
     http://github.com/mschilli/log4perl
 
 Send bug reports or requests for enhancements to the authors via our
 
 MAILING LIST (questions, bug reports, suggestions/patches): 
 log4perl-devel@lists.sourceforge.net
 
 Authors (please contact them via the list above, not directly):
 Mike Schilli <m@perlmeister.com>,
 Kevin Goess <cpan@goess.org>
 
 Contributors (in alphabetical order):
 Ateeq Altaf, Cory Bennett, Jens Berthold, Jeremy Bopp, Hutton
 Davidson, Chris R. Donnelly, Matisse Enzer, Hugh Esco, Anthony
 Foiani, James FitzGibbon, Carl Franks, Dennis Gregorovic, Andy
 Grundman, Paul Harrington, Alexander Hartmaier  David Hull, 
 Robert Jacobson, Jason Kohles, Jeff Macdonald, Markus Peter, 
 Brett Rann, Peter Rabbitson, Erik Selberg, Aaron Straup Cope, 
 Lars Thegler, David Viner, Mac Yang.
 
### Log/Log4perl/Appender/Synchronized.pm ###
 ######################################################################
 # Synchronized.pm -- 2003, 2007 Mike Schilli <m@perlmeister.com>
 ######################################################################
 # Special appender employing a locking strategy to synchronize
 # access.
 ######################################################################
 
 ###########################################
 package Log::Log4perl::Appender::Synchronized;
 ###########################################
 
 use strict;
 use warnings;
 use Log::Log4perl::Util::Semaphore;
 
 our @ISA = qw(Log::Log4perl::Appender);
 
 our $CVSVERSION   = '$Revision: 1.12 $';
 our ($VERSION)    = ($CVSVERSION =~ /(\d+\.\d+)/);
 
 ###########################################
 sub new {
 ###########################################
     my($class, %options) = @_;
 
     my $self = {
         appender=> undef,
         key     => '_l4p',
         level   => 0,
         %options,
     };
 
     my @values = ();
     for my $param (qw(uid gid mode destroy key)) {
         push @values, $param, $self->{$param} if defined $self->{$param};
     }
 
     $self->{sem} = Log::Log4perl::Util::Semaphore->new(
         @values
     );
 
         # Pass back the appender to be synchronized as a dependency
         # to the configuration file parser
     push @{$options{l4p_depends_on}}, $self->{appender};
 
         # Run our post_init method in the configurator after
         # all appenders have been defined to make sure the
         # appender we're synchronizing really exists
     push @{$options{l4p_post_config_subs}}, sub { $self->post_init() };
 
     bless $self, $class;
 }
 
 ###########################################
 sub log {
 ###########################################
     my($self, %params) = @_;
     
     $self->{sem}->semlock();
 
     # Relay that to the SUPER class which needs to render the
     # message according to the appender's layout, first.
     $Log::Log4perl::caller_depth +=2;
     $self->{app}->SUPER::log(\%params, 
                              $params{log4p_category},
                              $params{log4p_level});
     $Log::Log4perl::caller_depth -=2;
 
     $self->{sem}->semunlock();
 }
 
 ###########################################
 sub post_init {
 ###########################################
     my($self) = @_;
 
     if(! exists $self->{appender}) {
        die "No appender defined for " . __PACKAGE__;
     }
 
     my $appenders = Log::Log4perl->appenders();
     my $appender = Log::Log4perl->appenders()->{$self->{appender}};
 
     if(! defined $appender) {
        die "Appender $self->{appender} not defined (yet) when " .
            __PACKAGE__ . " needed it";
     }
 
     $self->{app} = $appender;
 }
 
 1;
 
 __END__
 
 =encoding utf8
 
 =head1 NAME
 
     Log::Log4perl::Appender::Synchronized - Synchronizing other appenders
 
 =head1 SYNOPSIS
 
     use Log::Log4perl qw(:easy);
 
     my $conf = qq(
     log4perl.category                   = WARN, Syncer
     
         # File appender (unsynchronized)
     log4perl.appender.Logfile           = Log::Log4perl::Appender::File
     log4perl.appender.Logfile.autoflush = 1
     log4perl.appender.Logfile.filename  = test.log
     log4perl.appender.Logfile.mode      = truncate
     log4perl.appender.Logfile.layout    = SimpleLayout
     
         # Synchronizing appender, using the file appender above
     log4perl.appender.Syncer            = Log::Log4perl::Appender::Synchronized
     log4perl.appender.Syncer.appender   = Logfile
 );
 
     Log::Log4perl->init(\$conf);
     WARN("This message is guaranteed to be complete.");
 
 =head1 DESCRIPTION
 
 If multiple processes are using the same C<Log::Log4perl> appender 
 without synchronization, overwrites might happen. A typical scenario
 for this would be a process spawning children, each of which inherits
 the parent's Log::Log4perl configuration.
 
 In most cases, you won't need an external synchronisation tool like
 Log::Log4perl::Appender::Synchronized at all. Log4perl's file appender, 
 Log::Log4perl::Appender::File, for example, provides the C<syswrite>
 mechanism for making sure that even long log lines won't interleave.
 Short log lines won't interleave anyway, because the operating system
 makes sure the line gets written before a task switch occurs.
 
 In cases where you need additional synchronization, however, you can use
 C<Log::Log4perl::Appender::Synchronized> as a gateway between your
 loggers and your appenders. An appender itself, 
 C<Log::Log4perl::Appender::Synchronized> just takes two additional
 arguments:
 
 =over 4
 
 =item C<appender>
 
 Specifies the name of the appender it synchronizes access to. The
 appender specified must be defined somewhere in the configuration file,
 not necessarily before the definition of 
 C<Log::Log4perl::Appender::Synchronized>.
 
 =item C<key>
 
 This optional argument specifies the key for the semaphore that
 C<Log::Log4perl::Appender::Synchronized> uses internally to ensure
 atomic operations. It defaults to C<_l4p>. If you define more than
 one C<Log::Log4perl::Appender::Synchronized> appender, it is 
 important to specify different keys for them, as otherwise every
 new C<Log::Log4perl::Appender::Synchronized> appender will nuke
 previously defined semaphores. The maximum key length is four
 characters, longer keys will be truncated to 4 characters -- 
 C<mylongkey1> and C<mylongkey2> are interpreted to be the same:
 C<mylo> (thanks to David Viner E<lt>dviner@yahoo-inc.comE<gt> for
 pointing this out).
 
 =back
 
 C<Log::Log4perl::Appender::Synchronized> uses Log::Log4perl::Util::Semaphore
 internally to perform locking with semaphores provided by the
 operating system used.
 
 =head2 Performance tips
 
 The C<Log::Log4perl::Appender::Synchronized> serializes access to a
 protected resource globally, slowing down actions otherwise performed in
 parallel.
 
 Unless specified otherwise, all instances of 
 C<Log::Log4perl::Appender::Synchronized> objects in the system will
 use the same global IPC key C<_l4p>.
 
 To control access to different appender instances, it often makes sense
 to define different keys for different synchronizing appenders. In this
 way, Log::Log4perl serializes access to each appender instance separately:
 
     log4perl.category                   = WARN, Syncer1, Syncer2
     
         # File appender 1 (unsynchronized)
     log4perl.appender.Logfile1           = Log::Log4perl::Appender::File
     log4perl.appender.Logfile1.filename  = test1.log
     log4perl.appender.Logfile1.layout    = SimpleLayout
     
         # File appender 2 (unsynchronized)
     log4perl.appender.Logfile2           = Log::Log4perl::Appender::File
     log4perl.appender.Logfile2.filename  = test2.log
     log4perl.appender.Logfile2.layout    = SimpleLayout
     
         # Synchronizing appender, using the file appender above
     log4perl.appender.Syncer1            = Log::Log4perl::Appender::Synchronized
     log4perl.appender.Syncer1.appender   = Logfile1
     log4perl.appender.Syncer1.key        = l4p1
 
         # Synchronizing appender, using the file appender above
     log4perl.appender.Syncer2            = Log::Log4perl::Appender::Synchronized
     log4perl.appender.Syncer2.appender   = Logfile2
     log4perl.appender.Syncer2.key        = l4p2
 
 Without the C<.key = l4p1> and C<.key = l4p2> lines, both Synchronized 
 appenders would be using the default C<_l4p> key, causing unnecessary
 serialization of output written to different files.
 
 =head2 Advanced configuration
 
 To configure the underlying Log::Log4perl::Util::Semaphore module in 
 a different way than with the default settings provided by 
 Log::Log4perl::Appender::Synchronized, use the following parameters:
 
     log4perl.appender.Syncer1.destroy  = 1
     log4perl.appender.Syncer1.mode     = sub { 0775 }
     log4perl.appender.Syncer1.uid      = hugo
     log4perl.appender.Syncer1.gid      = 100
 
 Valid options are 
 C<destroy> (Remove the semaphore on exit), 
 C<mode> (permissions on the semaphore), 
 C<uid> (uid or user name the semaphore is owned by), 
 and
 C<gid> (group id the semaphore is owned by), 
 
 Note that C<mode> is usually given in octal and therefore needs to be
 specified as a perl sub {}, unless you want to calculate what 0755 means
 in decimal.
 
 Changing ownership or group settings for a semaphore will obviously only
 work if the current user ID owns the semaphore already or if the current
 user is C<root>. The C<destroy> option causes the current process to 
 destroy the semaphore on exit. Spawned children of the process won't
 inherit this behavior.
 
 =head2 Semaphore user and group IDs with mod_perl
 
 Setting user and group IDs is especially important when the Synchronized
 appender is used with mod_perl. If Log4perl gets initialized by a startup
 handler, which runs as root, and not as the user who will later use
 the semaphore, the settings for uid, gid, and mode can help establish 
 matching semaphore ownership and access rights.
 
 =head1 DEVELOPMENT NOTES
 
 C<Log::Log4perl::Appender::Synchronized> is a I<composite> appender.
 Unlike other appenders, it doesn't log any messages, it just
 passes them on to its attached sub-appender.
 For this reason, it doesn't need a layout (contrary to regular appenders).
 If it defines none, messages are passed on unaltered.
 
 Custom filters are also applied to the composite appender only.
 They are I<not> applied to the sub-appender. Same applies to appender
 thresholds. This behaviour might change in the future.
 
 =head1 LICENSE
 
 Copyright 2002-2013 by Mike Schilli E<lt>m@perlmeister.comE<gt> 
 and Kevin Goess E<lt>cpan@goess.orgE<gt>.
 
 This library is free software; you can redistribute it and/or modify
 it under the same terms as Perl itself. 
 
 =head1 AUTHOR
 
 Please contribute patches to the project on Github:
 
     http://github.com/mschilli/log4perl
 
 Send bug reports or requests for enhancements to the authors via our
 
 MAILING LIST (questions, bug reports, suggestions/patches): 
 log4perl-devel@lists.sourceforge.net
 
 Authors (please contact them via the list above, not directly):
 Mike Schilli <m@perlmeister.com>,
 Kevin Goess <cpan@goess.org>
 
 Contributors (in alphabetical order):
 Ateeq Altaf, Cory Bennett, Jens Berthold, Jeremy Bopp, Hutton
 Davidson, Chris R. Donnelly, Matisse Enzer, Hugh Esco, Anthony
 Foiani, James FitzGibbon, Carl Franks, Dennis Gregorovic, Andy
 Grundman, Paul Harrington, Alexander Hartmaier  David Hull, 
 Robert Jacobson, Jason Kohles, Jeff Macdonald, Markus Peter, 
 Brett Rann, Peter Rabbitson, Erik Selberg, Aaron Straup Cope, 
 Lars Thegler, David Viner, Mac Yang.
 
### Log/Log4perl/Appender/TestArrayBuffer.pm ###
 ##################################################
 package Log::Log4perl::Appender::TestArrayBuffer;
 ##################################################
 # Like Log::Log4perl::Appender::TestBuffer, just with 
 # array capability.
 # For testing only.
 ##################################################
 
 use base qw( Log::Log4perl::Appender::TestBuffer );
 
 ##################################################
 sub log {   
 ##################################################
     my $self = shift;
     my %params = @_;
 
     $self->{buffer} .= "[$params{level}]: " if $LOG_PRIORITY;
 
     if(ref($params{message}) eq "ARRAY") {
         $self->{buffer} .= "[" . join(',', @{$params{message}}) . "]";
     } else {
         $self->{buffer} .= $params{message};
     }
 }
 
 1;
 
 =encoding utf8
 
 =head1 NAME
 
 Log::Log4perl::Appender::TestArrayBuffer - Subclass of Appender::TestBuffer
 
 =head1 SYNOPSIS
 
   use Log::Log4perl::Appender::TestArrayBuffer;
 
   my $appender = Log::Log4perl::Appender::TestArrayBuffer->new( 
       name      => 'buffer',
   );
 
       # Append to the buffer
   $appender->log( 
       level =  > 'alert', 
       message => ['first', 'second', 'third'],
   );
 
       # Retrieve the result
   my $result = $appender->buffer();
 
       # Reset the buffer to the empty string
   $appender->reset();
 
 =head1 DESCRIPTION
 
 This class is a subclass of Log::Log4perl::Appender::TestBuffer and
 just provides message array refs as an additional feature. 
 
 Just like Log::Log4perl::Appender::TestBuffer, 
 Log::Log4perl::Appender::TestArrayBuffer is used for internal
 Log::Log4perl testing only.
 
 =head1 LICENSE
 
 Copyright 2002-2013 by Mike Schilli E<lt>m@perlmeister.comE<gt> 
 and Kevin Goess E<lt>cpan@goess.orgE<gt>.
 
 This library is free software; you can redistribute it and/or modify
 it under the same terms as Perl itself. 
 
 =head1 AUTHOR
 
 Please contribute patches to the project on Github:
 
     http://github.com/mschilli/log4perl
 
 Send bug reports or requests for enhancements to the authors via our
 
 MAILING LIST (questions, bug reports, suggestions/patches): 
 log4perl-devel@lists.sourceforge.net
 
 Authors (please contact them via the list above, not directly):
 Mike Schilli <m@perlmeister.com>,
 Kevin Goess <cpan@goess.org>
 
 Contributors (in alphabetical order):
 Ateeq Altaf, Cory Bennett, Jens Berthold, Jeremy Bopp, Hutton
 Davidson, Chris R. Donnelly, Matisse Enzer, Hugh Esco, Anthony
 Foiani, James FitzGibbon, Carl Franks, Dennis Gregorovic, Andy
 Grundman, Paul Harrington, Alexander Hartmaier  David Hull, 
 Robert Jacobson, Jason Kohles, Jeff Macdonald, Markus Peter, 
 Brett Rann, Peter Rabbitson, Erik Selberg, Aaron Straup Cope, 
 Lars Thegler, David Viner, Mac Yang.
 
### Log/Log4perl/Appender/TestBuffer.pm ###
 package Log::Log4perl::Appender::TestBuffer;
 our @ISA = qw(Log::Log4perl::Appender);
 
 ##################################################
 # Log dispatcher writing to a string buffer
 # For testing.
 # This is like having a Log::Log4perl::Appender::TestBuffer
 ##################################################
 
 our %POPULATION       = ();
 our $LOG_PRIORITY     = 0;
 our $DESTROY_MESSAGES = "";
 
 ##################################################
 sub new {
 ##################################################
     my $proto  = shift;
     my $class  = ref $proto || $proto;
     my %params = @_;
 
     my $self = {
         name      => "unknown name",
         %params,
     };
 
     bless $self, $class;
 
     $self->{stderr} = exists $params{stderr} ? $params{stderr} : 1;
     $self->{buffer} = "";
 
     $POPULATION{$self->{name}} = $self;
 
     return $self;
 }
 
 ##################################################
 sub log {   
 ##################################################
     my $self = shift;
     my %params = @_;
 
     if( !defined $params{level} ) {
         die "No level defined in log() call of " . __PACKAGE__;
     }
     $self->{buffer} .= "[$params{level}]: " if $LOG_PRIORITY;
     $self->{buffer} .= $params{message};
 }
 
 ###########################################
 sub clear {
 ###########################################
     my($self) = @_;
 
     $self->{buffer} = "";
 }
 
 ##################################################
 sub buffer {   
 ##################################################
     my($self, $new) = @_;
 
     if(defined $new) {
         $self->{buffer} = $new;
     }
 
     return $self->{buffer};
 }
 
 ##################################################
 sub reset {   
 ##################################################
     my($self) = @_;
 
     %POPULATION = ();
     $self->{buffer} = "";
 }
 
 ##################################################
 sub DESTROY {   
 ##################################################
     my($self) = @_;
 
     $DESTROY_MESSAGES .= __PACKAGE__ . " destroyed";
 
     #this delete() along with &reset() above was causing
     #Attempt to free unreferenced scalar at 
     #blib/lib/Log/Log4perl/TestBuffer.pm line 69.
     #delete $POPULATION{$self->name};
 }
 
 ##################################################
 sub by_name {   
 ##################################################
     my($self, $name) = @_;
 
     # Return a TestBuffer by appender name. This is useful if
     # test buffers are created behind our back (e.g. via the
     # Log4perl config file) and later on we want to 
     # retrieve an instance to query its content.
 
     die "No name given"  unless defined $name;
 
     return $POPULATION{$name};
 
 }
 
 1;
 
 __END__
 
 =encoding utf8
 
 =head1 NAME
 
 Log::Log4perl::Appender::TestBuffer - Appender class for testing
 
 =head1 SYNOPSIS
 
   use Log::Log4perl::Appender::TestBuffer;
 
   my $appender = Log::Log4perl::Appender::TestBuffer->new( 
       name      => 'mybuffer',
   );
 
       # Append to the buffer
   $appender->log( 
       level =  > 'alert', 
       message => "I'm searching the city for sci-fi wasabi\n" 
   );
 
       # Retrieve the result
   my $result = $appender->buffer();
 
       # Clear the buffer to the empty string
   $appender->clear();
 
 =head1 DESCRIPTION
 
 This class is used for internal testing of C<Log::Log4perl>. It
 is a C<Log::Dispatch>-style appender, which writes to a buffer 
 in memory, from where actual results can be easily retrieved later
 to compare with expected results.
 
 Every buffer created is stored in an internal global array, and can
 later be referenced by name:
 
     my $app = Log::Log4perl::Appender::TestBuffer->by_name("mybuffer");
 
 retrieves the appender object of a previously created buffer "mybuffer".
 To reset this global array and have it forget all of the previously 
 created testbuffer appenders (external references to those appenders
 nonwithstanding), use
 
     Log::Log4perl::Appender::TestBuffer->reset();
 
 =head1 SEE ALSO
 
 =head1 LICENSE
 
 Copyright 2002-2013 by Mike Schilli E<lt>m@perlmeister.comE<gt> 
 and Kevin Goess E<lt>cpan@goess.orgE<gt>.
 
 This library is free software; you can redistribute it and/or modify
 it under the same terms as Perl itself. 
 
 =head1 AUTHOR
 
 Please contribute patches to the project on Github:
 
     http://github.com/mschilli/log4perl
 
 Send bug reports or requests for enhancements to the authors via our
 
 MAILING LIST (questions, bug reports, suggestions/patches): 
 log4perl-devel@lists.sourceforge.net
 
 Authors (please contact them via the list above, not directly):
 Mike Schilli <m@perlmeister.com>,
 Kevin Goess <cpan@goess.org>
 
 Contributors (in alphabetical order):
 Ateeq Altaf, Cory Bennett, Jens Berthold, Jeremy Bopp, Hutton
 Davidson, Chris R. Donnelly, Matisse Enzer, Hugh Esco, Anthony
 Foiani, James FitzGibbon, Carl Franks, Dennis Gregorovic, Andy
 Grundman, Paul Harrington, Alexander Hartmaier  David Hull, 
 Robert Jacobson, Jason Kohles, Jeff Macdonald, Markus Peter, 
 Brett Rann, Peter Rabbitson, Erik Selberg, Aaron Straup Cope, 
 Lars Thegler, David Viner, Mac Yang.
 
### Log/Log4perl/Appender/TestFileCreeper.pm ###
 ##################################################
 package Log::Log4perl::Appender::TestFileCreeper;
 ##################################################
 # Test appender, intentionally slow. It writes 
 # out one byte at a time to provoke sync errors.
 # Don't use it, unless for testing.
 ##################################################
 
 use warnings;
 use strict;
 
 use Log::Log4perl::Appender::File;
 
 our @ISA = qw(Log::Log4perl::Appender::File);
 
 ##################################################
 sub log {
 ##################################################
     my($self, %params) = @_;
 
     my $fh = $self->{fh};
 
     for (split //, $params{message}) {
         print $fh $_;
         my $oldfh = select $self->{fh}; 
         $| = 1; 
         select $oldfh;
     }
 }
 
 1;
 
 __END__
 
 =encoding utf8
 
 =head1 NAME
 
 Log::Log4perl::Appender::TestFileCreeper - Intentionally slow test appender
 
 =head1 SYNOPSIS
 
     use Log::Log4perl::Appender::TestFileCreeper;
 
     my $app = Log::Log4perl::Appender::TestFileCreeper->new(
       filename  => 'file.log',
       mode      => 'append',
     );
 
     $file->log(message => "Log me\n");
 
 =head1 DESCRIPTION
 
 This is a test appender, and it is intentionally slow. It writes 
 out one byte at a time to provoke sync errors. Don't use it, unless 
 for testing.
 
 =head1 LICENSE
 
 Copyright 2002-2013 by Mike Schilli E<lt>m@perlmeister.comE<gt> 
 and Kevin Goess E<lt>cpan@goess.orgE<gt>.
 
 This library is free software; you can redistribute it and/or modify
 it under the same terms as Perl itself. 
 
 =head1 AUTHOR
 
 Please contribute patches to the project on Github:
 
     http://github.com/mschilli/log4perl
 
 Send bug reports or requests for enhancements to the authors via our
 
 MAILING LIST (questions, bug reports, suggestions/patches): 
 log4perl-devel@lists.sourceforge.net
 
 Authors (please contact them via the list above, not directly):
 Mike Schilli <m@perlmeister.com>,
 Kevin Goess <cpan@goess.org>
 
 Contributors (in alphabetical order):
 Ateeq Altaf, Cory Bennett, Jens Berthold, Jeremy Bopp, Hutton
 Davidson, Chris R. Donnelly, Matisse Enzer, Hugh Esco, Anthony
 Foiani, James FitzGibbon, Carl Franks, Dennis Gregorovic, Andy
 Grundman, Paul Harrington, Alexander Hartmaier  David Hull, 
 Robert Jacobson, Jason Kohles, Jeff Macdonald, Markus Peter, 
 Brett Rann, Peter Rabbitson, Erik Selberg, Aaron Straup Cope, 
 Lars Thegler, David Viner, Mac Yang.
 
### Log/Log4perl/Catalyst.pm ###
 package Log::Log4perl::Catalyst;
 
 use strict;
 use Log::Log4perl qw(:levels);
 use Log::Log4perl::Logger;
 
 our $VERSION                  = $Log::Log4perl::VERSION;
 our $CATALYST_APPENDER_SUFFIX = "catalyst_buffer";
 our $LOG_LEVEL_ADJUSTMENT     = 1;
 
 init();
 
 ##################################################
 sub init {
 ##################################################
 
     my @levels = qw[ trace debug info warn error fatal ];
 
     Log::Log4perl->wrapper_register(__PACKAGE__);
 
     for my $level (@levels) {
         no strict 'refs';
 
         *{$level} = sub {
             my ( $self, @message ) = @_;
 
             local $Log::Log4perl::caller_depth =
                   $Log::Log4perl::caller_depth +
                      $LOG_LEVEL_ADJUSTMENT;
 
             my $logger = Log::Log4perl->get_logger();
             $logger->$level(@message);
             return 1;
         };
 
         *{"is_$level"} = sub {
             my ( $self, @message ) = @_;
 
             local $Log::Log4perl::caller_depth =
                   $Log::Log4perl::caller_depth +
                      $LOG_LEVEL_ADJUSTMENT;
 
             my $logger = Log::Log4perl->get_logger();
             my $func   = "is_" . $level;
             return $logger->$func;
         };
     }
 }
 
 ##################################################
 sub new {
 ##################################################
     my($class, $config, %options) = @_;
 
     my $self = {
         autoflush   => 0,
         abort       => 0,
         watch_delay => 0,
         %options,
     };
 
     if( !Log::Log4perl->initialized() ) {
         if( defined $config ) {
             if( $self->{watch_delay} ) {
                 Log::Log4perl::init_and_watch( $config, $self->{watch_delay} );
             } else {
                 Log::Log4perl::init( $config );
             }
         } else {
              Log::Log4perl->easy_init({
                  level  => $DEBUG,
                  layout => "[%d] [catalyst] [%p] %m%n",
              });
         }
     }
 
       # Unless we have autoflush, Catalyst likes to buffer all messages
       # until it calls flush(). This is somewhat unusual for Log4perl,
       # but we just put an army of buffer appenders in front of all 
       # appenders defined in the system.
 
     if(! $options{autoflush} ) {
         for my $appender (values %Log::Log4perl::Logger::APPENDER_BY_NAME) {
             next if $appender->{name} =~ /_$CATALYST_APPENDER_SUFFIX$/;
 
             # put a buffering appender in front of every appender
             # defined so far
 
             my $buf_app_name = "$appender->{name}_$CATALYST_APPENDER_SUFFIX";
 
             my $buf_app = Log::Log4perl::Appender->new(
                 'Log::Log4perl::Appender::Buffer',
                 name       => $buf_app_name,
                 appender   => $appender->{name},
                 trigger    => sub { 0 },    # only trigger on explicit flush()
             );
 
             Log::Log4perl->add_appender($buf_app);
             $buf_app->post_init();
             $buf_app->composite(1);
 
             # Point all loggers currently connected to the previously defined
             # appenders to the chained buffer appenders instead.
 
             foreach my $logger (
                            values %$Log::Log4perl::Logger::LOGGERS_BY_NAME){
                 if(defined $logger->remove_appender( $appender->{name}, 0, 1)) {
                     $logger->add_appender( $buf_app );
                 }
             }
         }
     }
 
     bless $self, $class;
 
     return $self;
 }
 
 ##################################################
 sub _flush {
 ##################################################
     my ($self) = @_;
 
     for my $appender (values %Log::Log4perl::Logger::APPENDER_BY_NAME) {
         next if $appender->{name} !~ /_$CATALYST_APPENDER_SUFFIX$/;
 
         if ($self->abort) {
             $appender->{appender}{buffer} = [];
         }
         else {
             $appender->flush();
         }
     }
 
     $self->abort(undef);
 }
 
 ##################################################
 sub abort {
 ##################################################
     my $self = shift;
 
     $self->{abort} = $_[0] if @_;
 
     return $self->{abort};
 }
 
 ##################################################
 sub levels {
 ##################################################
       # stub function, until we have something meaningful
     return 0;
 }
 
 ##################################################
 sub enable {
 ##################################################
       # stub function, until we have something meaningful
     return 0;
 }
 
 ##################################################
 sub disable {
 ##################################################
       # stub function, until we have something meaningful
     return 0;
 }
 
 1;
 
 __END__
 
 =encoding utf8
 
 =head1 NAME
 
 Log::Log4perl::Catalyst - Log::Log4perl Catalyst Module
 
 =head1 SYNOPSIS
 
 In your main Catalyst application module:
 
   use Log::Log4perl::Catalyst;
 
     # Either make Log4perl act like the Catalyst default logger:
   __PACKAGE__->log(Log::Log4perl::Catalyst->new());
 
     # or use a Log4perl configuration file, utilizing the full 
     # functionality of Log4perl
   __PACKAGE__->log(Log::Log4perl::Catalyst->new('l4p.conf'));
   
 ... and then sprinkle logging statements all over any code executed
 by Catalyst:
 
     $c->log->debug("This is using log4perl!");
 
 =head1 DESCRIPTION
 
 This module provides Log4perl functions to Catalyst applications. It was
 inspired by Catalyst::Log::Log4perl on CPAN, but has been completely 
 rewritten and uses a different approach to unite Catalyst and Log4perl.
 
 Log4perl provides loggers, usually associated with the current
 package, which can then be remote-controlled by a central
 configuration. This means that if you have a controller function like
 
     package MyApp::Controller::User;
 
     sub add : Chained('base'): PathPart('add'): Args(0) {
         my ( $self, $c ) = @_;
 
         $c->log->info("Adding a user");
         # ...
     }
 
 Level-based control is available via the following methods:
 
    $c->log->debug("Reading configuration");
    $c->log->info("Adding a user");
    $c->log->warn("Can't read configuration ($!)");
    $c->log->error("Can't add user ", $user);
    $c->log->fatal("Database down, aborting request");
 
 But that's not all, Log4perl is much more powerful.
 
 The logging statement can be suppressed or activated based on a Log4perl
 file that looks like
 
       # All MyApp loggers opened up for DEBUG and above
     log4perl.logger.MyApp = DEBUG, Screen
     # ...
 
 or 
 
       # All loggers block messages below INFO
     log4perl.logger=INFO, Screen
     # ...
 
 respectively. See the Log4perl manpage on how to perform fine-grained 
 log-level and location filtering, and how to forward messages not only
 to the screen or to log files, but also to databases, email appenders,
 and much more.
 
 Also, you can change the message layout. For example if you want
 to know where a particular statement was logged, turn on file names and 
 line numbers:
 
     # Log4perl configuration file
     # ...
     log4perl.appender.Screen.layout.ConversionPattern = \
           %F{1}-%L: %p %m%n
 
 Messages will then look like
 
     MyApp.pm-1869: INFO Saving user profile for user "wonko"
 
 Or want to log a request's IP address with every log statement? No problem 
 with Log4perl, just call
 
     Log::Log4perl::MDC->put( "ip", $c->req->address() );
 
 at the beginning of the request cycle and use
 
     # Log4perl configuration file
     # ...
     log4perl.appender.Screen.layout.ConversionPattern = \
           [%d]-%X{ip} %F{1}-%L: %p %m%n
 
 as a Log4perl layout. Messages will look like
 
     [2010/02/22 23:25:55]-123.122.108.10 MyApp.pm-1953: INFO Reading profile for user "wonko"
 
 Again, check the Log4perl manual page, there's a plethora of configuration
 options.
 
 =head1 METHODS
 
 =over 4
 
 =item new($config, [%options])
 
 If called without parameters, new() initializes Log4perl in a way 
 so that messages are logged similarly to Catalyst's default logging
 mechanism. If you provide a configuration, either the name of a configuration
 file or a reference to a scalar string containing the configuration, it
 will call Log4perl with these parameters.
 
 The second (optional) parameter is a list of key/value pairs:
 
   'autoflush'   =>  1   # Log without buffering ('abort' not supported)
   'watch_delay' => 30   # If set, use L<Log::Log4perl>'s init_and_watch
 
 =item _flush()
 
 Flushes the cache.
 
 =item abort($abort)
 
 Clears the logging system's internal buffers without logging anything.
 
 =back
 
 =head2 Using :easy Macros with Catalyst
 
 If you're tired of typing
 
     $c->log->debug("...");
 
 and would prefer to use Log4perl's convenient :easy mode macros like
 
     DEBUG "...";
 
 then just pull those macros in via Log::Log4perl's :easy mode and start
 cranking:
 
     use Log::Log4perl qw(:easy);
 
       # ... use macros later on
     sub base :Chained('/') :PathPart('apples') :CaptureArgs(0) {
         my ( $self, $c ) = @_;
 
         DEBUG "Handling apples";
     }
 
 Note the difference between Log4perl's initialization in Catalyst, which
 uses the Catalyst-specific Log::Log4perl::Catalyst module (top of this
 page), and making use of Log4perl's loggers with the standard 
 Log::Log4perl loggers and macros. While initialization requires Log4perl
 to perform dark magic to conform to Catalyst's different logging strategy,
 obtaining Log4perl's logger objects or calling its macros are unchanged.
 
 Instead of using Catalyst's way of referencing the "context" object $c to 
 obtain logger references via its log() method, you can just as well use 
 Log4perl's get_logger() or macros to access Log4perl's logger singletons. 
 The result is the same.
 
 =head1 LICENSE
 
 Copyright 2002-2013 by Mike Schilli E<lt>m@perlmeister.comE<gt> 
 and Kevin Goess E<lt>cpan@goess.orgE<gt>.
 
 This library is free software; you can redistribute it and/or modify
 it under the same terms as Perl itself. 
 
 =head1 AUTHOR
 
 Please contribute patches to the project on Github:
 
     http://github.com/mschilli/log4perl
 
 Send bug reports or requests for enhancements to the authors via our
 
 MAILING LIST (questions, bug reports, suggestions/patches): 
 log4perl-devel@lists.sourceforge.net
 
 Authors (please contact them via the list above, not directly):
 Mike Schilli <m@perlmeister.com>,
 Kevin Goess <cpan@goess.org>
 
 Contributors (in alphabetical order):
 Ateeq Altaf, Cory Bennett, Jens Berthold, Jeremy Bopp, Hutton
 Davidson, Chris R. Donnelly, Matisse Enzer, Hugh Esco, Anthony
 Foiani, James FitzGibbon, Carl Franks, Dennis Gregorovic, Andy
 Grundman, Paul Harrington, Alexander Hartmaier  David Hull, 
 Robert Jacobson, Jason Kohles, Jeff Macdonald, Markus Peter, 
 Brett Rann, Peter Rabbitson, Erik Selberg, Aaron Straup Cope, 
 Lars Thegler, David Viner, Mac Yang.
 
### Log/Log4perl/Config.pm ###
 ##################################################
 package Log::Log4perl::Config;
 ##################################################
 use 5.006;
 use strict;
 use warnings;
 
 use Log::Log4perl::Logger;
 use Log::Log4perl::Level;
 use Log::Log4perl::Config::PropertyConfigurator;
 use Log::Log4perl::JavaMap;
 use Log::Log4perl::Filter;
 use Log::Log4perl::Filter::Boolean;
 use Log::Log4perl::Config::Watch;
 
 use constant _INTERNAL_DEBUG => 0;
 
 our $CONFIG_FILE_READS       = 0;
 our $CONFIG_INTEGRITY_CHECK  = 1;
 our $CONFIG_INTEGRITY_ERROR  = undef;
 
 our $WATCHER;
 our $DEFAULT_WATCH_DELAY = 60; # seconds
 our $OPTS = {};
 our $OLD_CONFIG;
 our $LOGGERS_DEFINED;
 our $UTF8 = 0;
 
 ###########################################
 sub init {
 ###########################################
     Log::Log4perl::Logger->reset();
 
     undef $WATCHER; # just in case there's a one left over (e.g. test cases)
 
     return _init(@_);
 }
 
 ###########################################
 sub utf8 {
 ###########################################
     my( $class, $flag ) = @_;
 
     $UTF8 = $flag if defined $flag;
 
     return $UTF8;
 }
 
 ###########################################
 sub watcher {
 ###########################################
     return $WATCHER;
 }
 
 ###########################################
 sub init_and_watch {
 ###########################################
     my ($class, $config, $delay, $opts) = @_;
         # delay can be a signal name - in this case we're gonna
         # set up a signal handler.
 
     if(defined $WATCHER) {
         $config = $WATCHER->file();
         if(defined $Log::Log4perl::Config::Watch::SIGNAL_CAUGHT) {
             $delay  = $WATCHER->signal();
         } else {
             $delay  = $WATCHER->check_interval();
         }
     }
 
     print "init_and_watch ($config-$delay). Resetting.\n" if _INTERNAL_DEBUG;
 
     Log::Log4perl::Logger->reset();
 
     defined ($delay) or $delay = $DEFAULT_WATCH_DELAY;  
 
     if (ref $config) {
         die "Log4perl can only watch a file, not a string of " .
             "configuration information";
     }elsif ($config =~ m!^(https?|ftp|wais|gopher|file):!){
         die "Log4perl can only watch a file, not a url like $config";
     }
 
     if($delay =~ /\D/) {
         $WATCHER = Log::Log4perl::Config::Watch->new(
                           file         => $config,
                           signal       => $delay,
                           l4p_internal => 1,
                    );
     } else {
         $WATCHER = Log::Log4perl::Config::Watch->new(
                           file           => $config,
                           check_interval => $delay,
                           l4p_internal   => 1,
                    );
     }
 
     if(defined $opts) {
         die "Parameter $opts needs to be a hash ref" if ref($opts) ne "HASH";
         $OPTS = $opts;
     }
 
     eval { _init($class, $config); };
 
     if($@) {
         die "$@" unless defined $OLD_CONFIG;
             # Call _init with a pre-parsed config to go back to old setting
         _init($class, undef, $OLD_CONFIG);
         warn "Loading new config failed, reverted to old one\n";
     }
 }
 
 ##################################################
 sub _init {
 ##################################################
     my($class, $config, $data) = @_;
 
     my %additivity = ();
 
     $LOGGERS_DEFINED = 0;
 
     print "Calling _init\n" if _INTERNAL_DEBUG;
 
     #keep track so we don't create the same one twice
     my %appenders_created = ();
 
     #some appenders need to run certain subroutines right at the
     #end of the configuration phase, when all settings are in place.
     my @post_config_subs  = ();
 
     # This logic is probably suited to win an obfuscated programming
     # contest. It desperately needs to be rewritten.
     # Basically, it works like this:
     # config_read() reads the entire config file into a hash of hashes:
     #     log4j.logger.foo.bar.baz: WARN, A1
     # gets transformed into
     #     $data->{log4j}->{logger}->{foo}->{bar}->{baz} = "WARN, A1";
     # The code below creates the necessary loggers, sets the appenders
     # and the layouts etc.
     # In order to transform parts of this tree back into identifiers
     # (like "foo.bar.baz"), we're using the leaf_paths functions below.
     # Pretty scary. But it allows the lines of the config file to be
     # in *arbitrary* order.
 
     $data = config_read($config) unless defined $data;
     
     if(_INTERNAL_DEBUG) {
         require Data::Dumper;
         Data::Dumper->import();
         print Data::Dumper::Dumper($data);
     }
 
     my @loggers      = ();
     my %filter_names = ();
 
     my $system_wide_threshold;
 
       # Autocorrect the rootlogger/rootLogger typo
     if(exists $data->{rootlogger} and 
        ! exists $data->{rootLogger}) {
          $data->{rootLogger} = $data->{rootlogger};
     }
 
         # Find all logger definitions in the conf file. Start
         # with root loggers.
     if(exists $data->{rootLogger}) {
         $LOGGERS_DEFINED++;
         push @loggers, ["", $data->{rootLogger}->{value}];
     }
         
         # Check if we've got a system-wide threshold setting
     if(exists $data->{threshold}) {
             # yes, we do.
         $system_wide_threshold = $data->{threshold}->{value};
     }
 
     if (exists $data->{oneMessagePerAppender}){
                     $Log::Log4perl::one_message_per_appender = 
                         $data->{oneMessagePerAppender}->{value};
     }
 
     if(exists $data->{utcDateTimes}) {
         require Log::Log4perl::DateFormat;
         $Log::Log4perl::DateFormat::GMTIME = !!$data->{utcDateTimes}->{value};
     }
 
         # Boolean filters 
     my %boolean_filters = ();
 
         # Continue with lower level loggers. Both 'logger' and 'category'
         # are valid keywords. Also 'additivity' is one, having a logger
         # attached. We'll differentiate between the two further down.
     for my $key (qw(logger category additivity PatternLayout filter)) {
 
         if(exists $data->{$key}) {
 
             for my $path (@{leaf_paths($data->{$key})}) {
 
                 print "Path before: @$path\n" if _INTERNAL_DEBUG;
 
                 my $value = boolean_to_perlish(pop @$path);
 
                 pop @$path; # Drop the 'value' keyword part
 
                 if($key eq "additivity") {
                     # This isn't a logger but an additivity setting.
                     # Save it in a hash under the logger's name for later.
                     $additivity{join('.', @$path)} = $value;
 
                     #a global user-defined conversion specifier (cspec)
                 }elsif ($key eq "PatternLayout"){
                     &add_global_cspec(@$path[-1], $value);
 
                 }elsif ($key eq "filter"){
                     print "Found entry @$path\n" if _INTERNAL_DEBUG;
                     $filter_names{@$path[0]}++;
                 } else {
 
                     if (ref($value) eq "ARRAY") {
                       die "Multiple definitions of logger ".join('.',@$path)." in log4perl config";
                     }
 
                     # This is a regular logger
                     $LOGGERS_DEFINED++;
                     push @loggers, [join('.', @$path), $value];
                 }
             }
         }
     }
 
         # Now go over all filters found by name
     for my $filter_name (keys %filter_names) {
 
         print "Checking filter $filter_name\n" if _INTERNAL_DEBUG;
 
             # The boolean filter needs all other filters already
             # initialized, defer its initialization
         if($data->{filter}->{$filter_name}->{value} eq
            "Log::Log4perl::Filter::Boolean") {
             print "Boolean filter ($filter_name)\n" if _INTERNAL_DEBUG;
             $boolean_filters{$filter_name}++;
             next;
         }
 
         my $type = $data->{filter}->{$filter_name}->{value};
         if(my $code = compile_if_perl($type)) {
             $type = $code;
         }
         
         print "Filter $filter_name is of type $type\n" if _INTERNAL_DEBUG;
 
         my $filter;
 
         if(ref($type) eq "CODE") {
                 # Subroutine - map into generic Log::Log4perl::Filter class
             $filter = Log::Log4perl::Filter->new($filter_name, $type);
         } else {
                 # Filter class
                 die "Filter class '$type' doesn't exist" unless
                      Log::Log4perl::Util::module_available($type);
                 eval "require $type" or die "Require of $type failed ($!)";
 
                 # Invoke with all defined parameter
                 # key/values (except the key 'value' which is the entry 
                 # for the class)
             $filter = $type->new(name => $filter_name,
                 map { $_ => $data->{filter}->{$filter_name}->{$_}->{value} } 
                 grep { $_ ne "value" } 
                 keys %{$data->{filter}->{$filter_name}});
         }
             # Register filter with the global filter registry
         $filter->register();
     }
 
         # Initialize boolean filters (they need the other filters to be
         # initialized to be able to compile their logic)
     for my $name (keys %boolean_filters) {
         my $logic = $data->{filter}->{$name}->{logic}->{value};
         die "No logic defined for boolean filter $name" unless defined $logic;
         my $filter = Log::Log4perl::Filter::Boolean->new(
                          name  => $name, 
                          logic => $logic);
         $filter->register();
     }
 
     for (@loggers) {
         my($name, $value) = @$_;
 
         my $logger = Log::Log4perl::Logger->get_logger($name);
         my ($level, @appnames) = split /\s*,\s*/, $value;
 
         $logger->level(
             Log::Log4perl::Level::to_priority($level),
             'dont_reset_all');
 
         if(exists $additivity{$name}) {
             $logger->additivity($additivity{$name}, 1);
         }
 
         for my $appname (@appnames) {
 
             my $appender = create_appender_instance(
                 $data, $appname, \%appenders_created, \@post_config_subs,
                 $system_wide_threshold);
 
             $logger->add_appender($appender, 'dont_reset_all');
             set_appender_by_name($appname, $appender, \%appenders_created);
         }
     }
 
     #run post_config subs
     for(@post_config_subs) {
         $_->();
     }
 
     #now we're done, set up all the output methods (e.g. ->debug('...'))
     Log::Log4perl::Logger::reset_all_output_methods();
 
     #Run a sanity test on the config not disabled
     if($Log::Log4perl::Config::CONFIG_INTEGRITY_CHECK and
        !config_is_sane()) {
         warn "Log::Log4perl configuration looks suspicious: ",
              "$CONFIG_INTEGRITY_ERROR";
     }
 
         # Successful init(), save config for later
     $OLD_CONFIG = $data;
 
     $Log::Log4perl::Logger::INITIALIZED = 1;
 }
 
 ##################################################
 sub config_is_sane {
 ##################################################
     if(! $LOGGERS_DEFINED) {
         $CONFIG_INTEGRITY_ERROR = "No loggers defined";
         return 0;
     }    
 
     if(scalar keys %Log::Log4perl::Logger::APPENDER_BY_NAME == 0) {
         $CONFIG_INTEGRITY_ERROR = "No appenders defined";
         return 0;
     }
 
     return 1;
 }
 
 ##################################################
 sub create_appender_instance {
 ##################################################
     my($data, $appname, $appenders_created, $post_config_subs,
        $system_wide_threshold) = @_;
 
     my $appenderclass = get_appender_by_name(
             $data, $appname, $appenders_created);
 
     print "appenderclass=$appenderclass\n" if _INTERNAL_DEBUG;
 
     my $appender;
 
     if (ref $appenderclass) {
         $appender = $appenderclass;
     } else {
         die "ERROR: you didn't tell me how to " .
             "implement your appender '$appname'"
                 unless $appenderclass;
 
         if (Log::Log4perl::JavaMap::translate($appenderclass)){
             # It's Java. Try to map
             print "Trying to map Java $appname\n" if _INTERNAL_DEBUG;
             $appender = Log::Log4perl::JavaMap::get($appname, 
                                         $data->{appender}->{$appname});
 
         }else{
             # It's Perl
             my @params = grep { $_ ne "layout" and
                                 $_ ne "value"
                               } keys %{$data->{appender}->{$appname}};
     
             my %param = ();
             foreach my $pname (@params){
                 #this could be simple value like 
                 #{appender}{myAppender}{file}{value} => 'log.txt'
                 #or a structure like
                 #{appender}{myAppender}{login} => 
                 #                         { name => {value => 'bob'},
                 #                           pwd  => {value => 'xxx'},
                 #                         }
                 #in the latter case we send a hashref to the appender
                 if (exists $data->{appender}{$appname}
                                   {$pname}{value}      ) {
                     $param{$pname} = $data->{appender}{$appname}
                                             {$pname}{value};
                 }else{
                     $param{$pname} = {map {$_ => $data->{appender}
                                                         {$appname}
                                                         {$pname}
                                                         {$_}
                                                         {value}} 
                                      keys %{$data->{appender}
                                                    {$appname}
                                                    {$pname}}
                                      };
                 }
     
             }
 
             my $depends_on = [];
     
             $appender = Log::Log4perl::Appender->new(
                 $appenderclass, 
                 name                 => $appname,
                 l4p_post_config_subs => $post_config_subs,
                 l4p_depends_on       => $depends_on,
                 %param,
             ); 
     
             for my $dependency (@$depends_on) {
                 # If this appender indicates that it needs other appenders
                 # to exist (e.g. because it's a composite appender that
                 # relays messages on to its appender-refs) then we're 
                 # creating their instances here. Reason for this is that 
                 # these appenders are not attached to any logger and are
                 # therefore missed by the config parser which goes through
                 # the defined loggers and just creates *their* attached
                 # appenders.
                 $appender->composite(1);
                 next if exists $appenders_created->{$appname};
                 my $app = create_appender_instance($data, $dependency, 
                              $appenders_created,
                              $post_config_subs);
                 # If the appender appended a subroutine to $post_config_subs
                 # (a reference to an array of subroutines)
                 # here, the configuration parser will later execute this
                 # method. This is used by a composite appender which needs
                 # to make sure all of its appender-refs are available when
                 # all configuration settings are done.
 
                 # Smuggle this sub-appender into the hash of known appenders 
                 # without attaching it to any logger directly.
                 $
                 Log::Log4perl::Logger::APPENDER_BY_NAME{$dependency} = $app;
             }
         }
     }
 
     add_layout_by_name($data, $appender, $appname) unless
         $appender->composite();
 
        # Check for appender thresholds
     my $threshold = 
        $data->{appender}->{$appname}->{Threshold}->{value};
 
     if(defined $system_wide_threshold and
        !defined $threshold) {
         $threshold = $system_wide_threshold;
     }
 
     if(defined $threshold) {
             # Need to split into two lines because of CVS
         $appender->threshold($
             Log::Log4perl::Level::PRIORITY{$threshold});
     }
 
         # Check for custom filters attached to the appender
     my $filtername = 
        $data->{appender}->{$appname}->{Filter}->{value};
     if(defined $filtername) {
             # Need to split into two lines because of CVS
         my $filter = Log::Log4perl::Filter::by_name($filtername);
         die "Filter $filtername doesn't exist" unless defined $filter;
         $appender->filter($filter);
     }
 
     if(defined $system_wide_threshold and
        defined $threshold and
        $
         Log::Log4perl::Level::PRIORITY{$system_wide_threshold} > 
        $
          Log::Log4perl::Level::PRIORITY{$threshold}
       ) {
         $appender->threshold($
             Log::Log4perl::Level::PRIORITY{$system_wide_threshold});
     }
 
     if(exists $data->{appender}->{$appname}->{threshold}) {
         die "invalid keyword 'threshold' - perhaps you meant 'Threshold'?";
     }
 
     return $appender;
 }
 
 ###########################################
 sub add_layout_by_name {
 ###########################################
     my($data, $appender, $appender_name) = @_;
 
     my $layout_class = $data->{appender}->{$appender_name}->{layout}->{value};
 
     die "Layout not specified for appender $appender_name" unless $layout_class;
 
     $layout_class =~ s/org.apache.log4j./Log::Log4perl::Layout::/;
 
         # Check if we have this layout class
     if(!Log::Log4perl::Util::module_available($layout_class)) {
         if(Log::Log4perl::Util::module_available(
            "Log::Log4perl::Layout::$layout_class")) {
             # Someone used the layout shortcut, use the fully qualified
             # module name instead.
             $layout_class = "Log::Log4perl::Layout::$layout_class";
         } else {
             die "ERROR: trying to set layout for $appender_name to " .
                 "'$layout_class' failed";
         }
     }
 
     eval "require $layout_class" or 
         die "Require to $layout_class failed ($!)";
 
     $appender->layout($layout_class->new(
         $data->{appender}->{$appender_name}->{layout},
         ));
 }
 
 ###########################################
 sub get_appender_by_name {
 ###########################################
     my($data, $name, $appenders_created) = @_;
 
     if (exists $appenders_created->{$name}) {
         return $appenders_created->{$name};
     } else {
         return $data->{appender}->{$name}->{value};
     }
 }
 
 ###########################################
 sub set_appender_by_name {
 ###########################################
 # keep track of appenders we've already created
 ###########################################
     my($appname, $appender, $appenders_created) = @_;
 
     $appenders_created->{$appname} ||= $appender;
 }
 
 ##################################################
 sub add_global_cspec {
 ##################################################
 # the config file said
 # log4j.PatternLayout.cspec.Z=sub {return $$*2}
 ##################################################
     my ($letter, $perlcode) = @_;
 
     die "error: only single letters allowed in log4j.PatternLayout.cspec.$letter"
         unless ($letter =~ /^[a-zA-Z]$/);
 
     Log::Log4perl::Layout::PatternLayout::add_global_cspec($letter, $perlcode);
 }
 
 my $LWP_USER_AGENT;
 sub set_LWP_UserAgent
 {
     $LWP_USER_AGENT = shift;
 }
 
 
 ###########################################
 sub config_read {
 ###########################################
 # Read the lib4j configuration and store the
 # values into a nested hash structure.
 ###########################################
     my($config) = @_;
 
     die "Configuration not defined" unless defined $config;
 
     my @text;
     my $parser;
 
     $CONFIG_FILE_READS++;  # Count for statistical purposes
 
     my $base_configurator = Log::Log4perl::Config::BaseConfigurator->new(
         utf8 => $UTF8,
     );
 
     my $data = {};
 
     if (ref($config) eq 'HASH') {   # convert the hashref into a list 
                                     # of name/value pairs
         print "Reading config from hash\n" if _INTERNAL_DEBUG;
         @text = ();
         for my $key ( keys %$config ) {
             if( ref( $config->{$key} ) eq "CODE" ) {
                 $config->{$key} = $config->{$key}->();
             }
             push @text, $key . '=' . $config->{$key} . "\n";
         }
     } elsif (ref $config eq 'SCALAR') {
         print "Reading config from scalar\n" if _INTERNAL_DEBUG;
         @text = split(/\n/,$$config);
 
     } elsif (ref $config eq 'GLOB' or 
              ref $config eq 'IO::File') {
             # If we have a file handle, just call the reader
         print "Reading config from file handle\n" if _INTERNAL_DEBUG;
         @text = @{ $base_configurator->file_h_read( $config ) };
 
     } elsif (ref $config) {
             # Caller provided a config parser object, which already
             # knows which file (or DB or whatever) to parse.
         print "Reading config from parser object\n" if _INTERNAL_DEBUG;
         $data = $config->parse();
         return $data;
 
     } elsif ($config =~ m|^ldap://|){
        if(! Log::Log4perl::Util::module_available("Net::LDAP")) {
            die "Log4perl: missing Net::LDAP needed to parse LDAP urls\n$@\n";
        }
 
        require Net::LDAP;
        require Log::Log4perl::Config::LDAPConfigurator;
 
        return Log::Log4perl::Config::LDAPConfigurator->new->parse($config);
 
     } else {
 
         if ($config =~ /^(https?|ftp|wais|gopher|file):/){
             my ($result, $ua);
     
             die "LWP::UserAgent not available" unless
                 Log::Log4perl::Util::module_available("LWP::UserAgent");
 
             require LWP::UserAgent;
             unless (defined $LWP_USER_AGENT) {
                 $LWP_USER_AGENT = LWP::UserAgent->new;
     
                 # Load proxy settings from environment variables, i.e.:
                 # http_proxy, ftp_proxy, no_proxy etc (see LWP::UserAgent)
                 # You need these to go thru firewalls.
                 $LWP_USER_AGENT->env_proxy;
             }
             $ua = $LWP_USER_AGENT;
 
             my $req = new HTTP::Request GET => $config;
             my $res = $ua->request($req);
 
             if ($res->is_success) {
                 @text = split(/\n/, $res->content);
             } else {
                 die "Log4perl couln't get $config, ".
                      $res->message." ";
             }
         } else {
             print "Reading config from file '$config'\n" if _INTERNAL_DEBUG;
             print "Reading ", -s $config, " bytes.\n" if _INTERNAL_DEBUG;
               # Use the BaseConfigurator's file reader to avoid duplicating
               # utf8 handling here.
             $base_configurator->file( $config );
             @text = @{ $base_configurator->text() };
         }
     }
     
     print "Reading $config: [@text]\n" if _INTERNAL_DEBUG;
 
     if(! grep /\S/, @text) {
         return $data;
     }
 
     if ($text[0] =~ /^<\?xml /) {
 
         die "XML::DOM not available" unless
                 Log::Log4perl::Util::module_available("XML::DOM");
 
         require XML::DOM; 
         require Log::Log4perl::Config::DOMConfigurator;
 
         XML::DOM->VERSION($Log::Log4perl::DOM_VERSION_REQUIRED);
         $parser = Log::Log4perl::Config::DOMConfigurator->new();
         $data = $parser->parse(\@text);
     } else {
         $parser = Log::Log4perl::Config::PropertyConfigurator->new();
         $data = $parser->parse(\@text);
     }
 
     $data = $parser->parse_post_process( $data, leaf_paths($data) );
 
     return $data;
 }
 
 ###########################################
 sub unlog4j {
 ###########################################
     my ($string) = @_;
 
     $string =~ s#^org\.apache\.##;
     $string =~ s#^log4j\.##;
     $string =~ s#^l4p\.##;
     $string =~ s#^log4perl\.##i;
 
     $string =~ s#\.#::#g;
 
     return $string;
 }
 
 ############################################################
 sub leaf_paths {
 ############################################################
 # Takes a reference to a hash of hashes structure of 
 # arbitrary depth, walks the tree and returns a reference
 # to an array of all possible leaf paths (each path is an 
 # array again).
 # Example: { a => { b => { c => d }, e => f } } would generate
 #          [ [a, b, c, d], [a, e, f] ]
 ############################################################
     my ($root) = @_;
 
     my @stack  = ();
     my @result = ();
 
     push @stack, [$root, []];  
     
     while(@stack) {
         my $item = pop @stack;
 
         my($node, $path) = @$item;
 
         if(ref($node) eq "HASH") { 
             for(keys %$node) {
                 push @stack, [$node->{$_}, [@$path, $_]];
             }
         } else {
             push @result, [@$path, $node];
         }
     }
     return \@result;
 }
 
 ###########################################
 sub leaf_path_to_hash {
 ###########################################
     my($leaf_path, $data) = @_;
 
     my $ref = \$data;
 
     for my $part ( @$leaf_path[0..$#$leaf_path-1] ) {
         $ref = \$$ref->{ $part };
     }
 
     return $ref;
 }
 
 ###########################################
 sub eval_if_perl {
 ###########################################
     my($value) = @_;
 
     if(my $cref = compile_if_perl($value)) {
         return $cref->();
     }
 
     return $value;
 }
 
 ###########################################
 sub compile_if_perl {
 ###########################################
     my($value) = @_;
 
     if($value =~ /^\s*sub\s*{/ ) {
         my $mask;
         unless( Log::Log4perl::Config->allow_code() ) {
             die "\$Log::Log4perl::Config->allow_code() setting " .
                 "prohibits Perl code in config file";
         }
         if( defined( $mask = Log::Log4perl::Config->allowed_code_ops() ) ) {
             return compile_in_safe_cpt($value, $mask );
         }
         elsif( $mask = Log::Log4perl::Config->allowed_code_ops_convenience_map(
                              Log::Log4perl::Config->allow_code()
                           ) ) {
             return compile_in_safe_cpt($value, $mask );
         }
         elsif( Log::Log4perl::Config->allow_code() == 1 ) {
 
             # eval without restriction
             my $cref = eval "package main; $value" or 
                 die "Can't evaluate '$value' ($@)";
             return $cref;
         }
         else {
             die "Invalid value for \$Log::Log4perl::Config->allow_code(): '".
                 Log::Log4perl::Config->allow_code() . "'";
         }
     }
 
     return undef;
 }
 
 ###########################################
 sub compile_in_safe_cpt {
 ###########################################
     my($value, $allowed_ops) = @_;
 
     # set up a Safe compartment
     require Safe;
     my $safe = Safe->new();
     $safe->permit_only( @{ $allowed_ops } );
  
     # share things with the compartment
     for( keys %{ Log::Log4perl::Config->vars_shared_with_safe_compartment() } ) {
         my $toshare = Log::Log4perl::Config->vars_shared_with_safe_compartment($_);
         $safe->share_from( $_, $toshare )
             or die "Can't share @{ $toshare } with Safe compartment";
     }
     
     # evaluate with restrictions
     my $cref = $safe->reval("package main; $value") or
         die "Can't evaluate '$value' in Safe compartment ($@)";
     return $cref;
     
 }
 
 ###########################################
 sub boolean_to_perlish {
 ###########################################
     my($value) = @_;
 
         # Translate boolean to perlish
     $value = 1 if $value =~ /^true$/i;
     $value = 0 if $value =~ /^false$/i;
 
     return $value;
 }
 
 ###########################################
 sub vars_shared_with_safe_compartment {
 ###########################################
     my($class, @args) = @_;
 
         # Allow both for ...::Config::foo() and ...::Config->foo()
     if(defined $class and $class ne __PACKAGE__) {
         unshift @args, $class;
     }
    
     # handle different invocation styles
     if(@args == 1 && ref $args[0] eq 'HASH' ) {
         # replace entire hash of vars
         %Log::Log4perl::VARS_SHARED_WITH_SAFE_COMPARTMENT = %{$args[0]};
     }
     elsif( @args == 1 ) {
         # return vars for given package
         return $Log::Log4perl::VARS_SHARED_WITH_SAFE_COMPARTMENT{
                $args[0]};
     }
     elsif( @args == 2 ) {
         # add/replace package/var pair
         $Log::Log4perl::VARS_SHARED_WITH_SAFE_COMPARTMENT{
            $args[0]} = $args[1];
     }
 
     return wantarray ? %Log::Log4perl::VARS_SHARED_WITH_SAFE_COMPARTMENT
                      : \%Log::Log4perl::VARS_SHARED_WITH_SAFE_COMPARTMENT;
     
 }
 
 ###########################################
 sub allowed_code_ops {
 ###########################################
     my($class, @args) = @_;
 
         # Allow both for ...::Config::foo() and ...::Config->foo()
     if(defined $class and $class ne __PACKAGE__) {
         unshift @args, $class;
     }
    
     if(@args) {
         @Log::Log4perl::ALLOWED_CODE_OPS_IN_CONFIG_FILE = @args;
     }
     else {
         # give back 'undef' instead of an empty arrayref
         unless( @Log::Log4perl::ALLOWED_CODE_OPS_IN_CONFIG_FILE ) {
             return;
         }
     }
 
     return wantarray ? @Log::Log4perl::ALLOWED_CODE_OPS_IN_CONFIG_FILE
                      : \@Log::Log4perl::ALLOWED_CODE_OPS_IN_CONFIG_FILE;
 }
 
 ###########################################
 sub allowed_code_ops_convenience_map {
 ###########################################
     my($class, @args) = @_;
 
         # Allow both for ...::Config::foo() and ...::Config->foo()
     if(defined $class and $class ne __PACKAGE__) {
         unshift @args, $class;
     }
 
     # handle different invocation styles
     if( @args == 1 && ref $args[0] eq 'HASH' ) {
         # replace entire map
         %Log::Log4perl::ALLOWED_CODE_OPS = %{$args[0]};
     }
     elsif( @args == 1 ) {
         # return single opcode mask
         return $Log::Log4perl::ALLOWED_CODE_OPS{
                    $args[0]};
     }
     elsif( @args == 2 ) {
         # make sure the mask is an array ref
         if( ref $args[1] ne 'ARRAY' ) {
             die "invalid mask (not an array ref) for convenience name '$args[0]'";
         }
         # add name/mask pair
         $Log::Log4perl::ALLOWED_CODE_OPS{
             $args[0]} = $args[1];
     }
 
     return wantarray ? %Log::Log4perl::ALLOWED_CODE_OPS
                      : \%Log::Log4perl::ALLOWED_CODE_OPS
 }
 
 ###########################################
 sub allow_code {
 ###########################################
     my($class, @args) = @_;
 
         # Allow both for ...::Config::foo() and ...::Config->foo()
     if(defined $class and $class ne __PACKAGE__) {
         unshift @args, $class;
     }
    
     if(@args) {
         $Log::Log4perl::ALLOW_CODE_IN_CONFIG_FILE = 
             $args[0];
     }
 
     return $Log::Log4perl::ALLOW_CODE_IN_CONFIG_FILE;
 }
 
 ################################################
 sub var_subst {
 ################################################
     my($varname, $subst_hash) = @_;
 
         # Throw out blanks
     $varname =~ s/\s+//g;
 
     if(exists $subst_hash->{$varname}) {
         print "Replacing variable: '$varname' => '$subst_hash->{$varname}'\n" 
             if _INTERNAL_DEBUG;
         return $subst_hash->{$varname};
 
     } elsif(exists $ENV{$varname}) {
         print "Replacing ENV variable: '$varname' => '$ENV{$varname}'\n" 
             if _INTERNAL_DEBUG;
         return $ENV{$varname};
 
     }
 
     die "Undefined Variable '$varname'";
 }
 
 1;
 
 __END__
 
 =encoding utf8
 
 =head1 NAME
 
 Log::Log4perl::Config - Log4perl configuration file syntax
 
 =head1 DESCRIPTION
 
 In C<Log::Log4perl>, configuration files are used to describe how the
 system's loggers ought to behave. 
 
 The format is the same as the one as used for C<log4j>, just with
 a few perl-specific extensions, like enabling the C<Bar::Twix>
 syntax instead of insisting on the Java-specific C<Bar.Twix>.
 
 Comment lines and blank lines (all whitespace or empty) are ignored.
 
 Comment lines may start with arbitrary whitespace followed by one of:
 
 =over 4
 
 =item # - Common comment delimiter
 
 =item ! - Java .properties file comment delimiter accepted by log4j
 
 =item ; - Common .ini file comment delimiter
 
 =back
 
 Comments at the end of a line are not supported. So if you write
 
     log4perl.appender.A1.filename=error.log #in current dir
 
 you will find your messages in a file called C<error.log #in current dir>.
 
 Also, blanks between syntactical entities are ignored, it doesn't 
 matter if you write
 
     log4perl.logger.Bar.Twix=WARN,Screen
 
 or 
 
     log4perl.logger.Bar.Twix = WARN, Screen
 
 C<Log::Log4perl> will strip the blanks while parsing your input.
 
 Assignments need to be on a single line. However, you can break the
 line if you want to by using a continuation character at the end of the
 line. Instead of writing
 
     log4perl.appender.A1.layout=Log::Log4perl::Layout::SimpleLayout
 
 you can break the line at any point by putting a backslash at the very (!)
 end of the line to be continued:
 
     log4perl.appender.A1.layout=\
         Log::Log4perl::Layout::SimpleLayout
 
 Watch out for trailing blanks after the backslash, which would prevent
 the line from being properly concatenated.
 
 =head2 Loggers
 
 Loggers are addressed by category:
 
     log4perl.logger.Bar.Twix      = WARN, Screen
 
 This sets all loggers under the C<Bar::Twix> hierarchy on priority
 C<WARN> and attaches a later-to-be-defined C<Screen> appender to them.
 Settings for the root appender (which doesn't have a name) can be
 accomplished by simply omitting the name:
 
     log4perl.logger = FATAL, Database, Mailer 
 
 This sets the root appender's level to C<FATAL> and also attaches the 
 later-to-be-defined appenders C<Database> and C<Mailer> to it.
 
 The additivity flag of a logger is set or cleared via the 
 C<additivity> keyword:
 
     log4perl.additivity.Bar.Twix = 0|1
 
 (Note the reversed order of keyword and logger name, resulting
 from the dilemma that a logger name could end in C<.additivity>
 according to the log4j documentation).
 
 =head2 Appenders and Layouts
 
 Appender names used in Log4perl configuration file
 lines need to be resolved later on, in order to
 define the appender's properties and its layout. To specify properties
 of an appender, just use the C<appender> keyword after the
 C<log4perl> intro and the appender's name:
 
         # The Bar::Twix logger and its appender
     log4perl.logger.Bar.Twix = DEBUG, A1
     log4perl.appender.A1=Log::Log4perl::Appender::File
     log4perl.appender.A1.filename=test.log
     log4perl.appender.A1.mode=append
     log4perl.appender.A1.layout=Log::Log4perl::Layout::SimpleLayout
 
 This sets a priority of C<DEBUG> for loggers in the C<Bar::Twix>
 hierarchy and assigns the C<A1> appender to it, which is later on
 resolved to be an appender of type C<Log::Log4perl::Appender::File>, simply
 appending to a log file. According to the C<Log::Log4perl::Appender::File>
 manpage, the C<filename> parameter specifies the name of the log file
 and the C<mode> parameter can be set to C<append> or C<write> (the
 former will append to the logfile if one with the specified name
 already exists while the latter would clobber and overwrite it).
 
 The order of the entries in the configuration file is not important,
 C<Log::Log4perl> will read in the entire file first and try to make
 sense of the lines after it knows the entire context.
 
 You can very well define all loggers first and then their appenders
 (you could even define your appenders first and then your loggers,
 but let's not go there):
 
     log4perl.logger.Bar.Twix = DEBUG, A1
     log4perl.logger.Bar.Snickers = FATAL, A2
 
     log4perl.appender.A1=Log::Log4perl::Appender::File
     log4perl.appender.A1.filename=test.log
     log4perl.appender.A1.mode=append
     log4perl.appender.A1.layout=Log::Log4perl::Layout::SimpleLayout
 
     log4perl.appender.A2=Log::Log4perl::Appender::Screen
     log4perl.appender.A2.stderr=0
     log4perl.appender.A2.layout=Log::Log4perl::Layout::PatternLayout
     log4perl.appender.A2.layout.ConversionPattern = %d %m %n
 
 Note that you have to specify the full path to the layout class
 and that C<ConversionPattern> is the keyword to specify the printf-style
 formatting instructions.
 
 =head1 Configuration File Cookbook
 
 Here's some examples of often-used Log4perl configuration files:
 
 =head2 Append to STDERR
 
     log4perl.category.Bar.Twix      = WARN, Screen
     log4perl.appender.Screen        = Log::Log4perl::Appender::Screen
     log4perl.appender.Screen.layout = \
         Log::Log4perl::Layout::PatternLayout
     log4perl.appender.Screen.layout.ConversionPattern = %d %m %n
 
 =head2 Append to STDOUT
 
     log4perl.category.Bar.Twix      = WARN, Screen
     log4perl.appender.Screen        = Log::Log4perl::Appender::Screen
     log4perl.appender.Screen.stderr = 0
     log4perl.appender.Screen.layout = \
         Log::Log4perl::Layout::PatternLayout
     log4perl.appender.Screen.layout.ConversionPattern = %d %m %n
 
 =head2 Append to a log file
 
     log4perl.logger.Bar.Twix = DEBUG, A1
     log4perl.appender.A1=Log::Log4perl::Appender::File
     log4perl.appender.A1.filename=test.log
     log4perl.appender.A1.mode=append
     log4perl.appender.A1.layout = \
         Log::Log4perl::Layout::PatternLayout
     log4perl.appender.A1.layout.ConversionPattern = %d %m %n
 
 Note that you could even leave out 
 
     log4perl.appender.A1.mode=append
 
 and still have the logger append to the logfile by default, although
 the C<Log::Log4perl::Appender::File> module does exactly the opposite.
 This is due to some nasty trickery C<Log::Log4perl> performs behind 
 the scenes to make sure that beginner's CGI applications don't clobber 
 the log file every time they're called.
 
 =head2 Write a log file from scratch
 
 If you loathe the Log::Log4perl's append-by-default strategy, you can
 certainly override it:
 
     log4perl.logger.Bar.Twix = DEBUG, A1
     log4perl.appender.A1=Log::Log4perl::Appender::File
     log4perl.appender.A1.filename=test.log
     log4perl.appender.A1.mode=write
     log4perl.appender.A1.layout=Log::Log4perl::Layout::SimpleLayout
 
 C<write> is the C<mode> that has C<Log::Log4perl::Appender::File>
 explicitly clobber the log file if it exists.
 
 =head2 Configuration files encoded in utf-8
 
 If your configuration file is encoded in utf-8 (which matters if you 
 e.g. specify utf8-encoded appender filenames in it), then you need to 
 tell Log4perl before running init():
 
     use Log::Log4perl::Config;
     Log::Log4perl::Config->utf( 1 );
 
     Log::Log4perl->init( ... );
 
 This makes sure Log4perl interprets utf8-encoded config files correctly.
 This setting might become the default at some point.
 
 =head1 SEE ALSO
 
 Log::Log4perl::Config::PropertyConfigurator
 
 Log::Log4perl::Config::DOMConfigurator
 
 Log::Log4perl::Config::LDAPConfigurator (coming soon!)
 
 =head1 LICENSE
 
 Copyright 2002-2013 by Mike Schilli E<lt>m@perlmeister.comE<gt> 
 and Kevin Goess E<lt>cpan@goess.orgE<gt>.
 
 This library is free software; you can redistribute it and/or modify
 it under the same terms as Perl itself. 
 
 =head1 AUTHOR
 
 Please contribute patches to the project on Github:
 
     http://github.com/mschilli/log4perl
 
 Send bug reports or requests for enhancements to the authors via our
 
 MAILING LIST (questions, bug reports, suggestions/patches): 
 log4perl-devel@lists.sourceforge.net
 
 Authors (please contact them via the list above, not directly):
 Mike Schilli <m@perlmeister.com>,
 Kevin Goess <cpan@goess.org>
 
 Contributors (in alphabetical order):
 Ateeq Altaf, Cory Bennett, Jens Berthold, Jeremy Bopp, Hutton
 Davidson, Chris R. Donnelly, Matisse Enzer, Hugh Esco, Anthony
 Foiani, James FitzGibbon, Carl Franks, Dennis Gregorovic, Andy
 Grundman, Paul Harrington, Alexander Hartmaier  David Hull, 
 Robert Jacobson, Jason Kohles, Jeff Macdonald, Markus Peter, 
 Brett Rann, Peter Rabbitson, Erik Selberg, Aaron Straup Cope, 
 Lars Thegler, David Viner, Mac Yang.
 
### Log/Log4perl/Config/BaseConfigurator.pm ###
 package Log::Log4perl::Config::BaseConfigurator;
 
 use warnings;
 use strict;
 use constant _INTERNAL_DEBUG => 0;
 
 *eval_if_perl      = \&Log::Log4perl::Config::eval_if_perl;
 *compile_if_perl   = \&Log::Log4perl::Config::compile_if_perl;
 *leaf_path_to_hash = \&Log::Log4perl::Config::leaf_path_to_hash;
 
 ################################################
 sub new {
 ################################################
     my($class, %options) = @_;
 
     my $self = { 
         utf8 => 0,
         %options,
     };
 
     bless $self, $class;
 
     $self->file($self->{file}) if exists $self->{file};
     $self->text($self->{text}) if exists $self->{text};
 
     return $self;
 }
 
 ################################################
 sub text {
 ################################################
     my($self, $text) = @_;
 
         # $text is an array of scalars (lines)
     if(defined $text) {
         if(ref $text eq "ARRAY") {
             $self->{text} = $text;
         } else {
             $self->{text} = [split "\n", $text];
         }
     }
 
     return $self->{text};
 }
 
 ################################################
 sub file {
 ################################################
     my($self, $filename) = @_;
 
     open my $fh, "$filename" or die "Cannot open $filename ($!)";
 
     if( $self->{ utf8 } ) {
         binmode $fh, ":utf8";
     }
 
     $self->file_h_read( $fh );
     close $fh;
 }
 
 ################################################
 sub file_h_read {
 ################################################
     my($self, $fh) = @_;
 
         # Dennis Gregorovic <dgregor@redhat.com> added this
         # to protect apps which are tinkering with $/ globally.
     local $/ = "\n";
 
     $self->{text} = [<$fh>];
 }
 
 ################################################
 sub parse {
 ################################################
     die __PACKAGE__ . "::parse() is a virtual method. " .
         "It must be implemented " .
         "in a derived class (currently: ", ref(shift), ")";
 }
 
 ################################################
 sub parse_post_process {
 ################################################
     my($self, $data, $leaf_paths) = @_;
     
     #   [
     #     'category',
     #     'value',
     #     'WARN, Logfile'
     #   ],
     #   [
     #     'appender',
     #     'Logfile',
     #     'value',
     #     'Log::Log4perl::Appender::File'
     #   ],
     #   [
     #     'appender',
     #     'Logfile',
     #     'filename',
     #     'value',
     #     'test.log'
     #   ],
     #   [
     #     'appender',
     #     'Logfile',
     #     'layout',
     #     'value',
     #     'Log::Log4perl::Layout::PatternLayout'
     #   ],
     #   [
     #     'appender',
     #     'Logfile',
     #     'layout',
     #     'ConversionPattern',
     #     'value',
     #     '%d %F{1} %L> %m %n'
     #   ]
 
     for my $path ( @{ Log::Log4perl::Config::leaf_paths( $data )} ) {
 
         print "path=@$path\n" if _INTERNAL_DEBUG;
 
         if(0) {
         } elsif( 
             $path->[0] eq "appender" and
             $path->[2] eq "trigger"
           ) {
             my $ref = leaf_path_to_hash( $path, $data );
             my $code = compile_if_perl( $$ref );
 
             if(_INTERNAL_DEBUG) {
                 if($code) {
                     print "Code compiled: $$ref\n";
                 } else {
                     print "Not compiled: $$ref\n";
                 }
             }
 
             $$ref = $code if defined $code;
         } elsif (
             $path->[0] eq "filter"
           ) {
             # do nothing
         } elsif (
             $path->[0] eq "appender" and
             $path->[2] eq "warp_message"
           ) {
             # do nothing
         } elsif (
             $path->[0] eq "appender" and
             $path->[3] eq "cspec" or
             $path->[1] eq "cspec"
           ) {
               # could be either
               #    appender appndr layout cspec
               # or 
               #    PatternLayout cspec U value ...
               #
             # do nothing
         } else {
             my $ref = leaf_path_to_hash( $path, $data );
 
             if(_INTERNAL_DEBUG) {
                 print "Calling eval_if_perl on $$ref\n";
             }
 
             $$ref = eval_if_perl( $$ref );
         }
     }
 
     return $data;
 }
 
 1;
 
 __END__
 
 =encoding utf8
 
 =head1 NAME
 
 Log::Log4perl::Config::BaseConfigurator - Configurator Base Class
 
 =head1 SYNOPSIS
 
 This is a virtual base class, all configurators should be derived from it.
 
 =head1 DESCRIPTION
 
 =head2 METHODS
 
 =over 4
 
 =item C<< new >>
 
 Constructor, typically called like
 
     my $config_parser = SomeConfigParser->new(
         file => $file,
     );
 
     my $data = $config_parser->parse();
 
 Instead of C<file>, the derived class C<SomeConfigParser> may define any 
 type of configuration input medium (e.g. C<url =E<gt> 'http://foobar'>).
 It just has to make sure its C<parse()> method will later pull the input
 data from the medium specified.
 
 The base class accepts a filename or a reference to an array
 of text lines:
 
 =over 4
 
 =item C<< file >>
 
 Specifies a file which the C<parse()> method later parses.
 
 =item C<< text >>
 
 Specifies a reference to an array of scalars, representing configuration
 records (typically lines of a file). Also accepts a simple scalar, which it 
 splits at its newlines and transforms it into an array:
 
     my $config_parser = MyYAMLParser->new(
         text => ['foo: bar',
                  'baz: bam',
                 ],
     );
 
     my $data = $config_parser->parse();
 
 =back
 
 If either C<file> or C<text> parameters have been specified in the 
 constructor call, a later call to the configurator's C<text()> method
 will return a reference to an array of configuration text lines.
 This will typically be used by the C<parse()> method to process the 
 input.
 
 =item C<< parse >>
 
 Virtual method, needs to be defined by the derived class.
 
 =back
 
 =head2 Parser requirements
 
 =over 4
 
 =item *
 
 If the parser provides variable substitution functionality, it has
 to implement it.
 
 =item *
 
 The parser's C<parse()> method returns a reference to a hash of hashes (HoH). 
 The top-most hash contains the
 top-level keywords (C<category>, C<appender>) as keys, associated
 with values which are references to more deeply nested hashes.
 
 =item *
 
 The C<log4perl.> prefix (e.g. as used in the PropertyConfigurator class)
 is stripped, it's not part in the HoH structure.
 
 =item *
 
 Each Log4perl config value is indicated by the C<value> key, as in
 
     $data->{category}->{Bar}->{Twix}->{value} = "WARN, Logfile"
 
 =back
 
 =head2 EXAMPLES
 
 The following Log::Log4perl configuration:
 
     log4perl.category.Bar.Twix        = WARN, Screen
     log4perl.appender.Screen          = Log::Log4perl::Appender::File
     log4perl.appender.Screen.filename = test.log
     log4perl.appender.Screen.layout   = Log::Log4perl::Layout::SimpleLayout
 
 needs to be transformed by the parser's C<parse()> method 
 into this data structure:
 
     { appender => {
         Screen  => {
           layout => { 
             value  => "Log::Log4perl::Layout::SimpleLayout" },
             value  => "Log::Log4perl::Appender::Screen",
         },
       },
       category => { 
         Bar => { 
           Twix => { 
             value => "WARN, Screen" } 
         } }
     }
 
 For a full-fledged example, check out the sample YAML parser implementation 
 in C<eg/yamlparser>. It uses a simple YAML syntax to specify the Log4perl 
 configuration to illustrate the concept.
 
 =head1 SEE ALSO
 
 Log::Log4perl::Config::PropertyConfigurator
 
 Log::Log4perl::Config::DOMConfigurator
 
 Log::Log4perl::Config::LDAPConfigurator (tbd!)
 
 =head1 LICENSE
 
 Copyright 2002-2013 by Mike Schilli E<lt>m@perlmeister.comE<gt> 
 and Kevin Goess E<lt>cpan@goess.orgE<gt>.
 
 This library is free software; you can redistribute it and/or modify
 it under the same terms as Perl itself. 
 
 =head1 AUTHOR
 
 Please contribute patches to the project on Github:
 
     http://github.com/mschilli/log4perl
 
 Send bug reports or requests for enhancements to the authors via our
 
 MAILING LIST (questions, bug reports, suggestions/patches): 
 log4perl-devel@lists.sourceforge.net
 
 Authors (please contact them via the list above, not directly):
 Mike Schilli <m@perlmeister.com>,
 Kevin Goess <cpan@goess.org>
 
 Contributors (in alphabetical order):
 Ateeq Altaf, Cory Bennett, Jens Berthold, Jeremy Bopp, Hutton
 Davidson, Chris R. Donnelly, Matisse Enzer, Hugh Esco, Anthony
 Foiani, James FitzGibbon, Carl Franks, Dennis Gregorovic, Andy
 Grundman, Paul Harrington, Alexander Hartmaier  David Hull, 
 Robert Jacobson, Jason Kohles, Jeff Macdonald, Markus Peter, 
 Brett Rann, Peter Rabbitson, Erik Selberg, Aaron Straup Cope, 
 Lars Thegler, David Viner, Mac Yang.
 
### Log/Log4perl/Config/DOMConfigurator.pm ###
 package Log::Log4perl::Config::DOMConfigurator;
 use Log::Log4perl::Config::BaseConfigurator;
 
 our @ISA = qw(Log::Log4perl::Config::BaseConfigurator);
 
 #todo
 # DONE(param-text) some params not attrs but values, like <sql>...</sql>
 # DONE see DEBUG!!!  below
 # NO, (really is only used for AsyncAppender) appender-ref in <appender>
 # DONE check multiple appenders in a category
 # DONE in Config.pm re URL loading, steal from XML::DOM
 # DONE, OK see PropConfigurator re importing unlog4j, eval_if_perl
 # NO (is specified in DTD) - need to handle 0/1, true/false?
 # DONE see Config, need to check version of XML::DOM
 # OK user defined levels? see parse_level
 # OK make sure 2nd test is using log4perl constructs, not log4j
 # OK handle new filter stuff
 # make sure sample code actually works
 # try removing namespace prefixes in the xml
 
 use XML::DOM;
 use Log::Log4perl::Level;
 use strict;
 
 use constant _INTERNAL_DEBUG => 0;
 
 our $VERSION = 0.03;
 
 our $APPENDER_TAG = qr/^((log4j|log4perl):)?appender$/;
 
 our $FILTER_TAG = qr/^(log4perl:)?filter$/;
 our $FILTER_REF_TAG = qr/^(log4perl:)?filter-ref$/;
 
 #can't use ValParser here because we're using namespaces? 
 #doesn't seem to work - kg 3/2003 
 our $PARSER_CLASS = 'XML::DOM::Parser';
 
 our $LOG4J_PREFIX = 'log4j';
 our $LOG4PERL_PREFIX = 'log4perl';
     
 
 #poor man's export
 *eval_if_perl = \&Log::Log4perl::Config::eval_if_perl;
 *unlog4j      = \&Log::Log4perl::Config::unlog4j;
 
 
 ###################################################
 sub parse {
 ###################################################
     my($self, $newtext) = @_;
 
     $self->text($newtext) if defined $newtext;
     my $text = $self->{text};
 
     my $parser = $PARSER_CLASS->new;
     my $doc = $parser->parse (join('',@$text));
 
 
     my $l4p_tree = {};
     
     my $config = $doc->getElementsByTagName("$LOG4J_PREFIX:configuration")->item(0)||
                  $doc->getElementsByTagName("$LOG4PERL_PREFIX:configuration")->item(0);
 
     my $threshold = uc(subst($config->getAttribute('threshold')));
     if ($threshold) {
         $l4p_tree->{threshold}{value} = $threshold;
     }
 
     if (subst($config->getAttribute('oneMessagePerAppender')) eq 'true') {
         $l4p_tree->{oneMessagePerAppender}{value} = 1;
     }
 
     for my $kid ($config->getChildNodes){
 
         next unless $kid->getNodeType == ELEMENT_NODE;
 
         my $tag_name = $kid->getTagName;
 
         if ($tag_name =~ $APPENDER_TAG) {
             &parse_appender($l4p_tree, $kid);
 
         }elsif ($tag_name eq 'category' || $tag_name eq 'logger'){
             &parse_category($l4p_tree, $kid);
             #Treating them the same is not entirely accurate, 
             #the dtd says 'logger' doesn't accept
             #a 'class' attribute while 'category' does.
             #But that's ok, log4perl doesn't do anything with that attribute
 
         }elsif ($tag_name eq 'root'){
             &parse_root($l4p_tree, $kid);
 
         }elsif ($tag_name =~ $FILTER_TAG){
             #parse log4perl's chainable boolean filters
             &parse_l4p_filter($l4p_tree, $kid);
 
         }elsif ($tag_name eq 'renderer'){
             warn "Log4perl: ignoring renderer tag in config, unimplemented";
             #"log4j will render the content of the log message according to 
             # user specified criteria. For example, if you frequently need 
             # to log Oranges, an object type used in your current project, 
             # then you can register an OrangeRenderer that will be invoked 
             # whenever an orange needs to be logged. "
          
         }elsif ($tag_name eq 'PatternLayout'){#log4perl only
             &parse_patternlayout($l4p_tree, $kid);
         }
     }
     $doc->dispose;
 
     return $l4p_tree;
 }
 
 #this is just for toplevel log4perl.PatternLayout tags
 #holding the custom cspecs
 sub parse_patternlayout {
     my ($l4p_tree, $node) = @_;
 
     my $l4p_branch = {};
 
     for my $child ($node->getChildNodes) {
         next unless $child->getNodeType == ELEMENT_NODE;
 
         my $name = subst($child->getAttribute('name'));
         my $value;
 
         foreach my $grandkid ($child->getChildNodes){
             if ($grandkid->getNodeType == TEXT_NODE) {
                 $value .= $grandkid->getData;
             }
         }
         $value =~ s/^ +//;  #just to make the unit tests pass
         $value =~ s/ +$//;
         $l4p_branch->{$name}{value} = subst($value);
     }
     $l4p_tree->{PatternLayout}{cspec} = $l4p_branch;
 }
 
 
 #for parsing the root logger, if any
 sub parse_root {
     my ($l4p_tree, $node) = @_;
 
     my $l4p_branch = {};
 
     &parse_children_of_logger_element($l4p_branch, $node);
 
     $l4p_tree->{category}{value} = $l4p_branch->{value};
 
 }
 
 
 #this parses a custom log4perl-specific filter set up under
 #the root element, as opposed to children of the appenders
 sub parse_l4p_filter {
     my ($l4p_tree, $node) = @_;
 
     my $l4p_branch = {};
 
     my $name = subst($node->getAttribute('name'));
 
     my $class = subst($node->getAttribute('class'));
     my $value = subst($node->getAttribute('value'));
 
     if ($class && $value) {
         die "Log4perl: only one of class or value allowed, not both, "
             ."in XMLConfig filter '$name'";
     }elsif ($class || $value){
         $l4p_branch->{value} = ($value || $class);
 
     }
 
     for my $child ($node->getChildNodes) {
 
         if ($child->getNodeType == ELEMENT_NODE){
 
             my $tag_name = $child->getTagName();
 
             if ($tag_name =~ /^(param|param-nested|param-text)$/) {
                 &parse_any_param($l4p_branch, $child);
             }
         }elsif ($child->getNodeType == TEXT_NODE){
             my $text = $child->getData;
             next unless $text =~ /\S/;
             if ($class && $value) {
                 die "Log4perl: only one of class, value or PCDATA allowed, "
                     ."in XMLConfig filter '$name'";
             }
             $l4p_branch->{value} .= subst($text); 
         }
     }
 
     $l4p_tree->{filter}{$name} = $l4p_branch;
 }
 
    
 #for parsing a category/logger element
 sub parse_category {
     my ($l4p_tree, $node) = @_;
 
     my $name = subst($node->getAttribute('name'));
 
     $l4p_tree->{category} ||= {};
  
     my $ptr = $l4p_tree->{category};
 
     for my $part (split /\.|::/, $name) {
         $ptr->{$part} = {} unless exists $ptr->{$part};
         $ptr = $ptr->{$part};
     }
 
     my $l4p_branch = $ptr;
 
     my $class = subst($node->getAttribute('class'));
     $class                       && 
        $class ne 'Log::Log4perl' &&
        $class ne 'org.apache.log4j.Logger' &&
        warn "setting category $name to class $class ignored, only Log::Log4perl implemented";
 
     #this is kind of funky, additivity has its own spot in the tree
     my $additivity = subst(subst($node->getAttribute('additivity')));
     if (length $additivity > 0) {
         $l4p_tree->{additivity} ||= {};
         my $add_ptr = $l4p_tree->{additivity};
 
         for my $part (split /\.|::/, $name) {
             $add_ptr->{$part} = {} unless exists $add_ptr->{$part};
             $add_ptr = $add_ptr->{$part};
         }
         $add_ptr->{value} = &parse_boolean($additivity);
     }
 
     &parse_children_of_logger_element($l4p_branch, $node);
 }
 
 # parses the children of a category element
 sub parse_children_of_logger_element {
     my ($l4p_branch, $node) = @_;
 
     my (@appenders, $priority);
 
     for my $child ($node->getChildNodes) {
         next unless $child->getNodeType == ELEMENT_NODE;
             
         my $tag_name = $child->getTagName();
 
         if ($tag_name eq 'param') {
             my $name = subst($child->getAttribute('name'));
             my $value = subst($child->getAttribute('value'));
             if ($value =~ /^(all|debug|info|warn|error|fatal|off|null)^/) {
                 $value = uc $value;
             }
             $l4p_branch->{$name} = {value => $value};
         
         }elsif ($tag_name eq 'appender-ref'){
             push @appenders, subst($child->getAttribute('ref'));
             
         }elsif ($tag_name eq 'level' || $tag_name eq 'priority'){
             $priority = &parse_level($child);
         }
     }
     $l4p_branch->{value} = $priority.', '.join(',', @appenders);
     
     return;
 }
 
 
 sub parse_level {
     my $node = shift;
 
     my $level = uc (subst($node->getAttribute('value')));
 
     die "Log4perl: invalid level in config: $level"
         unless Log::Log4perl::Level::is_valid($level);
 
     return $level;
 }
 
 
 
 sub parse_appender {
     my ($l4p_tree, $node) = @_;
 
     my $name = subst($node->getAttribute("name"));
 
     my $l4p_branch = {};
 
     my $class = subst($node->getAttribute("class"));
 
     $l4p_branch->{value} = $class;
 
     print "looking at $name----------------------\n"  if _INTERNAL_DEBUG;
 
     for my $child ($node->getChildNodes) {
         next unless $child->getNodeType == ELEMENT_NODE;
 
         my $tag_name = $child->getTagName();
 
         my $name = unlog4j(subst($child->getAttribute('name')));
 
         if ($tag_name =~ /^(param|param-nested|param-text)$/) {
 
             &parse_any_param($l4p_branch, $child);
 
             my $value;
 
         }elsif ($tag_name =~ /($LOG4PERL_PREFIX:)?layout/){
             $l4p_branch->{layout} = parse_layout($child);
 
         }elsif ($tag_name =~  $FILTER_TAG){
             $l4p_branch->{Filter} = parse_filter($child);
 
         }elsif ($tag_name =~ $FILTER_REF_TAG){
             $l4p_branch->{Filter} = parse_filter_ref($child);
 
         }elsif ($tag_name eq 'errorHandler'){
             die "errorHandlers not supported yet";
 
         }elsif ($tag_name eq 'appender-ref'){
             #dtd: Appenders may also reference (or include) other appenders. 
             #This feature in log4j is only for appenders who implement the 
             #AppenderAttachable interface, and the only one that does that
             #is the AsyncAppender, which writes logs in a separate thread.
             #I don't see the need to support this on the perl side any 
             #time soon.  --kg 3/2003
             die "Log4perl: in config file, <appender-ref> tag is unsupported in <appender>";
         }else{
             die "Log4perl: in config file, <$tag_name> is unsupported\n";
         }
     }
     $l4p_tree->{appender}{$name} = $l4p_branch;
 }
 
 sub parse_any_param {
     my ($l4p_branch, $child) = @_;
 
     my $tag_name = $child->getTagName();
     my $name = subst($child->getAttribute('name'));
     my $value;
 
     print "parse_any_param: <$tag_name name=$name\n" if _INTERNAL_DEBUG;
 
     #<param-nested>
     #note we don't set it to { value => $value }
     #and we don't test for multiple values
     if ($tag_name eq 'param-nested'){
         
         if ($l4p_branch->{$name}){
             die "Log4perl: in config file, multiple param-nested tags for $name not supported";
         }
         $l4p_branch->{$name} = &parse_param_nested($child); 
 
         return;
 
     #<param>
     }elsif ($tag_name eq 'param') {
 
          $value = subst($child->getAttribute('value'));
 
          print "parse_param_nested: got param $name = $value\n"  
              if _INTERNAL_DEBUG;
         
          if ($value =~ /^(all|debug|info|warn|error|fatal|off|null)$/) {
              $value = uc $value;
          }
 
          if ($name !~ /warp_message|filter/ &&
             $child->getParentNode->getAttribute('name') ne 'cspec') {
             $value = eval_if_perl($value);
          }
     #<param-text>
     }elsif ($tag_name eq 'param-text'){
 
         foreach my $grandkid ($child->getChildNodes){
             if ($grandkid->getNodeType == TEXT_NODE) {
                 $value .= $grandkid->getData;
             }
         }
         if ($name !~ /warp_message|filter/ &&
             $child->getParentNode->getAttribute('name') ne 'cspec') {
             $value = eval_if_perl($value);
         }
     }
 
     $value = subst($value);
 
      #multiple values for the same param name
      if (defined $l4p_branch->{$name}{value} ) {
          if (ref $l4p_branch->{$name}{value} ne 'ARRAY'){
              my $temp = $l4p_branch->{$name}{value};
              $l4p_branch->{$name}{value} = [$temp];
          }
          push @{$l4p_branch->{$name}{value}}, $value;
      }else{
          $l4p_branch->{$name} = {value => $value};
      }
 }
 
 #handles an appender's <param-nested> elements
 sub parse_param_nested {
     my ($node) = shift;
 
     my $l4p_branch = {};
 
     for my $child ($node->getChildNodes) {
         next unless $child->getNodeType == ELEMENT_NODE;
 
         my $tag_name = $child->getTagName();
 
         if ($tag_name =~ /^param|param-nested|param-text$/) {
             &parse_any_param($l4p_branch, $child);
         }
     }
 
     return $l4p_branch;
 }
 
 #this handles filters that are children of appenders, as opposed
 #to the custom filters that go under the root element
 sub parse_filter {
     my $node = shift;
 
     my $filter_tree = {};
 
     my $class_name = subst($node->getAttribute('class'));
 
     $filter_tree->{value} = $class_name;
 
     print "\tparsing filter on class $class_name\n"  if _INTERNAL_DEBUG;  
 
     for my $child ($node->getChildNodes) {
         next unless $child->getNodeType == ELEMENT_NODE;
 
         my $tag_name = $child->getTagName();
 
         if ($tag_name =~ 'param|param-nested|param-text') {
             &parse_any_param($filter_tree, $child);
         
         }else{
             die "Log4perl: don't know what to do with a ".$child->getTagName()
                 ."inside a filter element";
         }
     }
     return $filter_tree;
 }
 
 sub parse_filter_ref {
     my $node = shift;
 
     my $filter_tree = {};
 
     my $filter_id = subst($node->getAttribute('id'));
 
     $filter_tree->{value} = $filter_id;
 
     return $filter_tree;
 }
 
 
 
 sub parse_layout {
     my $node = shift;
 
     my $layout_tree = {};
 
     my $class_name = subst($node->getAttribute('class'));
     
     $layout_tree->{value} = $class_name;
     #
     print "\tparsing layout $class_name\n"  if _INTERNAL_DEBUG;  
     for my $child ($node->getChildNodes) {
         next unless $child->getNodeType == ELEMENT_NODE;
         if ($child->getTagName() eq 'param') {
             my $name = subst($child->getAttribute('name'));
             my $value = subst($child->getAttribute('value'));
             if ($value =~ /^(all|debug|info|warn|error|fatal|off|null)$/) {
                 $value = uc $value;
             }
             print "\tparse_layout: got param $name = $value\n"
                 if _INTERNAL_DEBUG;
             $layout_tree->{$name}{value} = $value;  
 
         }elsif ($child->getTagName() eq 'cspec') {
             my $name = subst($child->getAttribute('name'));
             my $value;
             foreach my $grandkid ($child->getChildNodes){
                 if ($grandkid->getNodeType == TEXT_NODE) {
                     $value .= $grandkid->getData;
                 }
             }
             $value =~ s/^ +//;
             $value =~ s/ +$//;
             $layout_tree->{cspec}{$name}{value} = subst($value);  
         }
     }
     return $layout_tree;
 }
 
 sub parse_boolean {
     my $a = shift;
 
     if ($a eq '0' || lc $a eq 'false') {
         return '0';
     }elsif ($a eq '1' || lc $a eq 'true'){
         return '1';
     }else{
         return $a; #probably an error, punt
     }
 }
 
 
 #this handles variable substitution
 sub subst {
     my $val = shift;
 
     $val =~ s/\$\{(.*?)}/
                       Log::Log4perl::Config::var_subst($1, {})/gex;
     return $val;
 }
 
 1;
 
 __END__
 
 =encoding utf8
 
 =head1 NAME
 
 Log::Log4perl::Config::DOMConfigurator - reads xml config files
 
 =head1 SYNOPSIS
 
     --------------------------
     --using the log4j DTD--
     --------------------------
 
     <?xml version="1.0" encoding="UTF-8"?>
     <!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
 
     <log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
 
     <appender name="FileAppndr1" class="org.apache.log4j.FileAppender">
         <layout class="Log::Log4perl::Layout::PatternLayout">
                 <param name="ConversionPattern"
                        value="%d %4r [%t] %-5p %c %t - %m%n"/>
         </layout>
         <param name="File" value="t/tmp/DOMtest"/>
         <param name="Append" value="false"/>
     </appender>
 
     <category name="a.b.c.d" additivity="false">
         <level value="warn"/>  <!-- note lowercase! -->
         <appender-ref ref="FileAppndr1"/>
     </category>
 
    <root>
         <priority value="warn"/>
         <appender-ref ref="FileAppndr1"/>
    </root>
 
    </log4j:configuration>
    
    
    
    --------------------------
    --using the log4perl DTD--
    --------------------------
    
    <?xml version="1.0" encoding="UTF-8"?>
     <!DOCTYPE log4perl:configuration SYSTEM "log4perl.dtd">
 
     <log4perl:configuration xmlns:log4perl="http://log4perl.sourceforge.net/"
         threshold="debug" oneMessagePerAppender="true">
 
     <log4perl:appender name="jabbender" class="Log::Dispatch::Jabber">
 
             <param-nested name="login">
                    <param name="hostname" value="a.jabber.server"/>
                    <param name="password" value="12345"/>
                    <param name="port"     value="5222"/>
                    <param name="resource" value="logger"/>
                    <param name="username" value="bobjones"/>
             </param-nested>
 
             <param name="to" value="bob@a.jabber.server"/>
 
             <param-text name="to">
                   mary@another.jabber.server
             </param-text>
 
             <log4perl:layout class="org.apache.log4j.PatternLayout">
                 <param name="ConversionPattern" value = "%K xx %G %U"/>
                 <cspec name="K">
                     sub { return sprintf "%1x", $$}
                 </cspec>
                 <cspec name="G">
                     sub {return 'thisistheGcspec'}
                 </cspec>
             </log4perl:layout>
     </log4perl:appender>
 
     <log4perl:appender name="DBAppndr2" class="Log::Log4perl::Appender::DBI">
               <param name="warp_message" value="0"/>
               <param name="datasource" value="DBI:CSV:f_dir=t/tmp"/>
               <param name="bufferSize" value="2"/>
               <param name="password" value="sub { $ENV{PWD} }"/>
               <param name="username" value="bobjones"/>
 
               <param-text name="sql">
                   INSERT INTO log4perltest
                             (loglevel, message, shortcaller, thingid,
                             category, pkg, runtime1, runtime2)
                   VALUES
                              (?,?,?,?,?,?,?,?)
               </param-text>
 
                <param-nested name="params">
                     <param name="1" value="%p"/>
                     <param name="3" value="%5.5l"/>
                     <param name="5" value="%c"/>
                     <param name="6" value="%C"/>
                </param-nested>
 
                <layout class="Log::Log4perl::Layout::NoopLayout"/>
     </log4perl:appender>
 
     <category name="animal.dog">
                <priority value="info"/>
                <appender-ref ref="jabbender"/>
                <appender-ref ref="DBAppndr2"/>
     </category>
 
     <category name="plant">
             <priority value="debug"/>
             <appender-ref ref="DBAppndr2"/>
     </category>
 
     <PatternLayout>
         <cspec name="U"><![CDATA[
             sub {
                 return "UID $< GID $(";
             }
         ]]></cspec>
     </PatternLayout>
 
     </log4perl:configuration>
     
 
 
 
 =head1 DESCRIPTION
 
 This module implements an XML config, complementing the properties-style
 config described elsewhere.
 
 =head1 WHY
 
 "Why would I want my config in XML?" you ask.  Well, there are a couple
 reasons you might want to.  Maybe you have a personal preference
 for XML.  Maybe you manage your config with other tools that have an
 affinity for XML, like XML-aware editors or automated config
 generators.  Or maybe (and this is the big one) you don't like
 having to run your application just to check the syntax of your
 config file.
 
 By using an XML config and referencing a DTD, you can use a namespace-aware
 validating parser to see if your XML config at least follows the rules set 
 in the DTD. 
 
 =head1 HOW
 
 To reference a DTD, drop this in after the <?xml...> declaration
 in your config file:
 
     <!DOCTYPE log4perl:configuration SYSTEM "log4perl.dtd">
 
 That tells the parser to validate your config against the DTD in
 "log4perl.dtd", which is available in the xml/ directory of
 the log4perl distribution.  Note that you'll also need to grab
 the log4j-1.2.dtd from there as well, since the it's included
 by log4perl.dtd.
 
 Namespace-aware validating parsers are not the norm in Perl.  
 But the Xerces project 
 (http://xml.apache.org/xerces-c/index.html --lots of binaries available, 
 even rpm's)  does provide just such a parser
 that you can use like this:
 
     StdInParse -ns -v < my-log4perl-config.xml
 
 This module itself does not use a validating parser, the obvious
 one XML::DOM::ValParser doesn't seem to handle namespaces.
 
 =head1 WHY TWO DTDs
 
 The log4j DTD is from the log4j project, they designed it to 
 handle their needs.  log4perl has added some extensions to the 
 original log4j functionality which needed some extensions to the
 log4j DTD.  If you aren't using these features then you can validate
 your config against the log4j dtd and know that you're using
 unadulterated log4j config tags.   
 
 The features added by the log4perl dtd are:
 
 =over 4
 
 =item 1 oneMessagePerAppender global setting
 
     log4perl.oneMessagePerAppender=1
 
 =item 2 globally defined user conversion specifiers
 
     log4perl.PatternLayout.cspec.G=sub { return "UID $< GID $("; }
 
 =item 3 appender-local custom conversion specifiers
 
      log4j.appender.appndr1.layout.cspec.K = sub {return sprintf "%1x", $$ }
 
 =item 4 nested options
 
      log4j.appender.jabbender          = Log::Dispatch::Jabber
      #(note how these are nested under 'login')
      log4j.appender.jabbender.login.hostname = a.jabber.server
      log4j.appender.jabbender.login.port     = 5222
      log4j.appender.jabbender.login.username = bobjones
 
 =item 5 the log4perl-specific filters, see L<Log::Log4perl::Filter>,
 lots of examples in t/044XML-Filter.t, here's a short one:
 
 
   <?xml version="1.0" encoding="UTF-8"?> 
   <!DOCTYPE log4perl:configuration SYSTEM "log4perl.dtd">
 
   <log4perl:configuration xmlns:log4perl="http://log4perl.sourceforge.net/">
    
   <appender name="A1" class="Log::Log4perl::Appender::TestBuffer">
         <layout class="Log::Log4perl::Layout::SimpleLayout"/>
         <filter class="Log::Log4perl::Filter::Boolean">
             <param name="logic" value="!Match3 &amp;&amp; (Match1 || Match2)"/> 
         </filter>
   </appender>   
   
   <appender name="A2" class="Log::Log4perl::Appender::TestBuffer">
         <layout class="Log::Log4perl::Layout::SimpleLayout"/>
         <filter-ref id="Match1"/>
   </appender>   
   
   <log4perl:filter name="Match1" value="sub { /let this through/ }" />
   
   <log4perl:filter name="Match2">
         sub { 
             /and that, too/ 
         }
    </log4perl:filter>
   
   <log4perl:filter name="Match3" class="Log::Log4perl::Filter::StringMatch">
     <param name="StringToMatch" value="suppress"/>
     <param name="AcceptOnMatch" value="true"/>
   </log4perl:filter>
   
   <log4perl:filter name="MyBoolean" class="Log::Log4perl::Filter::Boolean">
     <param name="logic" value="!Match3 &amp;&amp; (Match1 || Match2)"/>
   </log4perl:filter>
   
    
    <root>
            <priority value="info"/>
            <appender-ref ref="A1"/>
    </root>
    
    </log4perl:configuration>
 
 
 =back
 
 
 So we needed to extend the log4j dtd to cover these additions.
 Now I could have just taken a 'steal this code' approach and mixed
 parts of the log4j dtd into a log4perl dtd, but that would be
 cut-n-paste programming.  So I've used namespaces and
 
 =over 4
 
 =item * 
 
 replaced three elements:
 
 =over 4
 
 =item <log4perl:configuration>
 
 handles #1) and accepts <PatternLayout>
 
 =item <log4perl:appender> 
 
 accepts <param-nested> and <param-text>
 
 =item <log4perl:layout> 
 
 accepts custom cspecs for #3)
 
 =back
 
 =item * 
 
 added a <param-nested> element (complementing the <param> element)
     to handle #4)
 
 =item * 
 
 added a root <PatternLayout> element to handle #2)
 
 =item * 
 
 added <param-text> which lets you put things like perl code
     into escaped CDATA between the tags, so you don't have to worry
     about escaping characters and quotes
 
 =item * 
 
 added <cspec>
 
 =back
 
 See the examples up in the L<"SYNOPSIS"> for how all that gets used.
 
 =head1 WHY NAMESPACES
 
 I liked the idea of using the log4j DTD I<in situ>, so I used namespaces
 to extend it.  If you really don't like having to type <log4perl:appender>
 instead of just <appender>, you can make your own DTD combining
 the two DTDs and getting rid of the namespace prefixes.  Then you can
 validate against that, and log4perl should accept it just fine.
 
 =head1 VARIABLE SUBSTITUTION
 
 This supports variable substitution like C<${foobar}> in text and in 
 attribute values except for appender-ref.  If an environment variable is defined
 for that name, its value is substituted. So you can do stuff like
 
         <param name="${hostname}" value="${hostnameval}.foo.com"/>
         <param-text name="to">${currentsysadmin}@foo.com</param-text>
 
 
 =head1 REQUIRES
 
 To use this module you need XML::DOM installed.  
 
 To use the log4perl.dtd, you'll have to reference it in your XML config,
 and you'll also need to note that log4perl.dtd references the 
 log4j dtd as "log4j-1.2.dtd", so your validator needs to be able
 to find that file as well.  If you don't like having to schlep two
 files around, feel free
 to dump the contents of "log4j-1.2.dtd" into your "log4perl.dtd" file.
 
 =head1 CAVEATS
 
 You can't mix a multiple param-nesteds with the same name, I'm going to
 leave that for now, there's presently no need for a list of structs
 in the config.
 
 =head1 CHANGES
 
 0.03 2/26/2003 Added support for log4perl extensions to the log4j dtd
 
 =head1 SEE ALSO
 
 t/038XML-DOM1.t, t/039XML-DOM2.t for examples
 
 xml/log4perl.dtd, xml/log4j-1.2.dtd
 
 Log::Log4perl::Config
 
 Log::Log4perl::Config::PropertyConfigurator
 
 Log::Log4perl::Config::LDAPConfigurator (coming soon!)
 
 The code is brazenly modeled on log4j's DOMConfigurator class, (by 
 Christopher Taylor, Ceki Gülcü, and Anders Kristensen) and any
 perceived similarity is not coincidental.
 
 =head1 LICENSE
 
 Copyright 2002-2013 by Mike Schilli E<lt>m@perlmeister.comE<gt> 
 and Kevin Goess E<lt>cpan@goess.orgE<gt>.
 
 This library is free software; you can redistribute it and/or modify
 it under the same terms as Perl itself. 
 
 =head1 AUTHOR
 
 Please contribute patches to the project on Github:
 
     http://github.com/mschilli/log4perl
 
 Send bug reports or requests for enhancements to the authors via our
 
 MAILING LIST (questions, bug reports, suggestions/patches): 
 log4perl-devel@lists.sourceforge.net
 
 Authors (please contact them via the list above, not directly):
 Mike Schilli <m@perlmeister.com>,
 Kevin Goess <cpan@goess.org>
 
 Contributors (in alphabetical order):
 Ateeq Altaf, Cory Bennett, Jens Berthold, Jeremy Bopp, Hutton
 Davidson, Chris R. Donnelly, Matisse Enzer, Hugh Esco, Anthony
 Foiani, James FitzGibbon, Carl Franks, Dennis Gregorovic, Andy
 Grundman, Paul Harrington, Alexander Hartmaier  David Hull, 
 Robert Jacobson, Jason Kohles, Jeff Macdonald, Markus Peter, 
 Brett Rann, Peter Rabbitson, Erik Selberg, Aaron Straup Cope, 
 Lars Thegler, David Viner, Mac Yang.
 
### Log/Log4perl/Config/PropertyConfigurator.pm ###
 package Log::Log4perl::Config::PropertyConfigurator;
 use Log::Log4perl::Config::BaseConfigurator;
 
 use warnings;
 use strict;
 
 our @ISA = qw(Log::Log4perl::Config::BaseConfigurator);
 
 our %NOT_A_MULT_VALUE = map { $_ => 1 }
     qw(conversionpattern);
 
 #poor man's export
 *eval_if_perl = \&Log::Log4perl::Config::eval_if_perl;
 *compile_if_perl = \&Log::Log4perl::Config::compile_if_perl;
 *unlog4j      = \&Log::Log4perl::Config::unlog4j;
 
 use constant _INTERNAL_DEBUG => 0;
 
 our $COMMENT_REGEX = qr/[#;!]/;
 
 ################################################
 sub parse {
 ################################################
     my($self, $newtext) = @_;
 
     $self->text($newtext) if defined $newtext;
 
     my $text = $self->{text};
 
     die "Config parser has nothing to parse" unless defined $text;
 
     my $data = {};
     my %var_subst = ();
 
     while (@$text) {
         local $_ = shift @$text;
         s/^\s*$COMMENT_REGEX.*//;
         next unless /\S/;
     
         my @parts = ();
 
         while (/(.+?)\\\s*$/) {
             my $prev = $1;
             my $next = shift(@$text);
             $next =~ s/^ +//g;  #leading spaces
             $next =~ s/^$COMMENT_REGEX.*//;
             $_ = $prev. $next;
             chomp;
         }
 
         if(my($key, $val) = /(\S+?)\s*=\s*(.*)/) {
 
             my $key_org = $key;
 
             $val =~ s/\s+$//;
 
                 # Everything could potentially be a variable assignment
             $var_subst{$key} = $val;
 
                 # Substitute any variables
             $val =~ s/\$\{(.*?)\}/
                       Log::Log4perl::Config::var_subst($1, \%var_subst)/gex;
 
             $key = unlog4j($key);
 
             my $how_deep = 0;
             my $ptr = $data;
             for my $part (split /\.|::/, $key) {
                 push @parts, $part;
                 $ptr->{$part} = {} unless exists $ptr->{$part};
                 $ptr = $ptr->{$part};
                 ++$how_deep;
             }
 
             #here's where we deal with turning multiple values like this:
             # log4j.appender.jabbender.to = him@a.jabber.server
             # log4j.appender.jabbender.to = her@a.jabber.server
             #into an arrayref like this:
             #to => { value => 
             #       ["him\@a.jabber.server", "her\@a.jabber.server"] },
             # 
             # This only is allowed for properties of appenders
             # not listed in %NOT_A_MULT_VALUE (see top of file).
             if (exists $ptr->{value} && 
                 $how_deep > 2 &&
                 defined $parts[0] && lc($parts[0]) eq "appender" && 
                 defined $parts[2] && ! exists $NOT_A_MULT_VALUE{lc($parts[2])}
                ) {
                 if (ref ($ptr->{value}) ne 'ARRAY') {
                     my $temp = $ptr->{value};
                     $ptr->{value} = [];
                     push (@{$ptr->{value}}, $temp);
                 }
                 push (@{$ptr->{value}}, $val);
             }else{
                 if(defined $ptr->{value}) {
                     if(! $Log::Log4perl::Logger::NO_STRICT) {
                         die "$key_org redefined";
                     }
                 }
                 $ptr->{value} = $val;
             }
         }
     }
     $self->{data} = $data;
     return $data;
 }
 
 ################################################
 sub value {
 ################################################
   my($self, $path) = @_;
 
   $path = unlog4j($path);
 
   my @p = split /::/, $path;
 
   my $found = 0;
   my $r = $self->{data};
 
   while (my $n = shift @p) {
       if (exists $r->{$n}) {
           $r = $r->{$n};
           $found = 1;
       } else {
           $found = 0;
       }
   }
 
   if($found and exists $r->{value}) {
       return $r->{value};
   } else {
       return undef;
   }
 }
 
 1;
 
 __END__
 
 =encoding utf8
 
 =head1 NAME
 
 Log::Log4perl::Config::PropertyConfigurator - reads properties file
 
 =head1 SYNOPSIS
 
     # This class is used internally by Log::Log4perl
 
     use Log::Log4perl::Config::PropertyConfigurator;
 
     my $conf = Log::Log4perl::Config::PropertyConfigurator->new();
     $conf->file("l4p.conf");
     $conf->parse(); # will die() on error
 
     my $value = $conf->value("log4perl.appender.LOGFILE.filename");
    
     if(defined $value) {
         printf("The appender's file name is $value\n");
     } else {
         printf("The appender's file name is not defined.\n");
     }
 
 =head1 DESCRIPTION
 
 Initializes log4perl from a properties file, stuff like
 
     log4j.category.a.b.c.d = WARN, A1
     log4j.category.a.b = INFO, A1
 
 It also understands variable substitution, the following
 configuration is equivalent to the previous one:
 
     settings = WARN, A1
     log4j.category.a.b.c.d = ${settings}
     log4j.category.a.b = INFO, A1
 
 =head1 SEE ALSO
 
 Log::Log4perl::Config
 
 Log::Log4perl::Config::BaseConfigurator
 
 Log::Log4perl::Config::DOMConfigurator
 
 Log::Log4perl::Config::LDAPConfigurator (tbd!)
 
 =head1 LICENSE
 
 Copyright 2002-2013 by Mike Schilli E<lt>m@perlmeister.comE<gt> 
 and Kevin Goess E<lt>cpan@goess.orgE<gt>.
 
 This library is free software; you can redistribute it and/or modify
 it under the same terms as Perl itself. 
 
 =head1 AUTHOR
 
 Please contribute patches to the project on Github:
 
     http://github.com/mschilli/log4perl
 
 Send bug reports or requests for enhancements to the authors via our
 
 MAILING LIST (questions, bug reports, suggestions/patches): 
 log4perl-devel@lists.sourceforge.net
 
 Authors (please contact them via the list above, not directly):
 Mike Schilli <m@perlmeister.com>,
 Kevin Goess <cpan@goess.org>
 
 Contributors (in alphabetical order):
 Ateeq Altaf, Cory Bennett, Jens Berthold, Jeremy Bopp, Hutton
 Davidson, Chris R. Donnelly, Matisse Enzer, Hugh Esco, Anthony
 Foiani, James FitzGibbon, Carl Franks, Dennis Gregorovic, Andy
 Grundman, Paul Harrington, Alexander Hartmaier  David Hull, 
 Robert Jacobson, Jason Kohles, Jeff Macdonald, Markus Peter, 
 Brett Rann, Peter Rabbitson, Erik Selberg, Aaron Straup Cope, 
 Lars Thegler, David Viner, Mac Yang.
 
### Log/Log4perl/Config/Watch.pm ###
 package Log::Log4perl::Config::Watch;
 
 use constant _INTERNAL_DEBUG => 0;
 
 our $NEXT_CHECK_TIME;
 our $SIGNAL_CAUGHT;
 
 our $L4P_TEST_CHANGE_DETECTED;
 our $L4P_TEST_CHANGE_CHECKED;
 
 ###########################################
 sub new {
 ###########################################
     my($class, %options) = @_;
 
     my $self = { file            => "",
                  check_interval  => 30,
                  l4p_internal    => 0,
                  signal          => undef,
                  %options,
                  _last_checked_at => 0,
                  _last_timestamp  => 0,
                };
 
     bless $self, $class;
 
     if($self->{signal}) {
             # We're in signal mode, set up the handler
         print "Setting up signal handler for '$self->{signal}'\n" if
             _INTERNAL_DEBUG;
 
         # save old signal handlers; they belong to other appenders or
         # possibly something else in the consuming application
         my $old_sig_handler = $SIG{$self->{signal}};
         $SIG{$self->{signal}} = sub { 
             print "Caught $self->{signal} signal\n" if _INTERNAL_DEBUG;
             $self->force_next_check();
             $old_sig_handler->(@_) if $old_sig_handler and ref $old_sig_handler eq 'CODE';
         };
             # Reset the marker. The handler is going to modify it.
         $self->{signal_caught} = 0;
         $SIGNAL_CAUGHT = 0 if $self->{l4p_internal};
     } else {
             # Just called to initialize
         $self->change_detected(undef, 1);
         $self->file_has_moved(undef, 1);
     }
 
     return $self;
 }
 
 ###########################################
 sub force_next_check {
 ###########################################
     my($self) = @_;
 
     $self->{signal_caught}   = 1;
     $self->{next_check_time} = 0;
 
     if( $self->{l4p_internal} ) {
         $SIGNAL_CAUGHT = 1;
         $NEXT_CHECK_TIME = 0;
     }
 }
 
 ###########################################
 sub force_next_check_reset {
 ###########################################
     my($self) = @_;
 
     $self->{signal_caught} = 0;
     $SIGNAL_CAUGHT = 0 if $self->{l4p_internal};
 }
 
 ###########################################
 sub file {
 ###########################################
     my($self) = @_;
 
     return $self->{file};
 }
 
 ###########################################
 sub signal {
 ###########################################
     my($self) = @_;
 
     return $self->{signal};
 }
 
 ###########################################
 sub check_interval {
 ###########################################
     my($self) = @_;
 
     return $self->{check_interval};
 }
 
 ###########################################
 sub file_has_moved {
 ###########################################
     my($self, $time, $force) = @_;
 
     my $task = sub {
         my @stat = stat($self->{file});
 
         my $has_moved = 0;
 
         if(! $stat[0]) {
             # The file's gone, obviously it got moved or deleted.
             print "File is gone\n" if _INTERNAL_DEBUG;
             return 1;
         }
 
         my $current_inode = "$stat[0]:$stat[1]";
         print "Current inode: $current_inode\n" if _INTERNAL_DEBUG;
 
         if(exists $self->{_file_inode} and 
             $self->{_file_inode} ne $current_inode) {
             print "Inode changed from $self->{_file_inode} to ",
                   "$current_inode\n" if _INTERNAL_DEBUG;
             $has_moved = 1;
         }
 
         $self->{_file_inode} = $current_inode;
         return $has_moved;
     };
 
     return $self->check($time, $task, $force);
 }
 
 ###########################################
 sub change_detected {
 ###########################################
     my($self, $time, $force) = @_;
 
     my $task = sub {
         my @stat = stat($self->{file});
         my $new_timestamp = $stat[9];
 
         $L4P_TEST_CHANGE_CHECKED = 1;
 
         if(! defined $new_timestamp) {
             if($self->{l4p_internal}) {
                 # The file is gone? Let it slide, we don't want L4p to re-read
                 # the config now, it's gonna die.
                 return undef;
             }
             $L4P_TEST_CHANGE_DETECTED = 1;
             return 1;
         }
 
         if($new_timestamp > $self->{_last_timestamp}) {
             $self->{_last_timestamp} = $new_timestamp;
             print "Change detected (file=$self->{file} store=$new_timestamp)\n"
                   if _INTERNAL_DEBUG;
             $L4P_TEST_CHANGE_DETECTED = 1;
             return 1; # Has changed
         }
            
         print "$self->{file} unchanged (file=$new_timestamp ",
               "stored=$self->{_last_timestamp})!\n" if _INTERNAL_DEBUG;
         return "";  # Hasn't changed
     };
 
     return $self->check($time, $task, $force);
 }
 
 ###########################################
 sub check {
 ###########################################
     my($self, $time, $task, $force) = @_;
 
     $time = time() unless defined $time;
 
     if( $self->{signal_caught} or $SIGNAL_CAUGHT ) {
        $force = 1;
        $self->force_next_check_reset();
        print "Caught signal, forcing check\n" if _INTERNAL_DEBUG;
 
     }
 
     print "Soft check (file=$self->{file} time=$time)\n" if _INTERNAL_DEBUG;
 
         # Do we need to check?
     if(!$force and
        $self->{_last_checked_at} + 
        $self->{check_interval} > $time) {
         print "No need to check\n" if _INTERNAL_DEBUG;
         return ""; # don't need to check, return false
     }
        
     $self->{_last_checked_at} = $time;
 
     # Set global var for optimizations in case we just have one watcher
     # (like in Log::Log4perl)
     $self->{next_check_time} = $time + $self->{check_interval};
     $NEXT_CHECK_TIME = $self->{next_check_time} if $self->{l4p_internal};
 
     print "Hard check (file=$self->{file} time=$time)\n" if _INTERNAL_DEBUG;
     return $task->($time);
 }
 
 1;
 
 __END__
 
 =encoding utf8
 
 =head1 NAME
 
 Log::Log4perl::Config::Watch - Detect file changes
 
 =head1 SYNOPSIS
 
     use Log::Log4perl::Config::Watch;
 
     my $watcher = Log::Log4perl::Config::Watch->new(
                           file            => "/data/my.conf",
                           check_interval  => 30,
                   );
 
     while(1) {
         if($watcher->change_detected()) {
             print "Change detected!\n";
         }
         sleep(1);
     }
 
 =head1 DESCRIPTION
 
 This module helps detecting changes in files. Although it comes with the
 C<Log::Log4perl> distribution, it can be used independently.
 
 The constructor defines the file to be watched and the check interval 
 in seconds. Subsequent calls to C<change_detected()> will 
 
 =over 4
 
 =item *
 
 return a false value immediately without doing physical file checks
 if C<check_interval> hasn't elapsed.
 
 =item *
 
 perform a physical test on the specified file if the number
 of seconds specified in C<check_interval> 
 have elapsed since the last physical check. If the file's modification
 date has changed since the last physical check, it will return a true 
 value, otherwise a false value is returned.
 
 =back
 
 Bottom line: C<check_interval> allows you to call the function
 C<change_detected()> as often as you like, without paying the performing
 a significant performance penalty because file system operations 
 are being performed (however, you pay the price of not knowing about
 file changes until C<check_interval> seconds have elapsed).
 
 The module clearly distinguishes system time from file system time. 
 If your (e.g. NFS mounted) file system is off by a constant amount
 of time compared to the executing computer's clock, it'll just
 work fine.
 
 To disable the resource-saving delay feature, just set C<check_interval> 
 to 0 and C<change_detected()> will run a physical file test on
 every call.
 
 If you already have the current time available, you can pass it
 on to C<change_detected()> as an optional parameter, like in
 
     change_detected($time)
 
 which then won't trigger a call to C<time()>, but use the value
 provided.
 
 =head2 SIGNAL MODE
 
 Instead of polling time and file changes, C<new()> can be instructed 
 to set up a signal handler. If you call the constructor like
 
     my $watcher = Log::Log4perl::Config::Watch->new(
                           file    => "/data/my.conf",
                           signal  => 'HUP'
                   );
 
 then a signal handler will be installed, setting the object's variable 
 C<$self-E<gt>{signal_caught}> to a true value when the signal arrives.
 Comes with all the problems that signal handlers go along with.
 
 =head2 TRIGGER CHECKS
 
 To trigger a physical file check on the next call to C<change_detected()>
 regardless if C<check_interval> has expired or not, call
 
     $watcher->force_next_check();
 
 on the watcher object.
 
 =head2 DETECT MOVED FILES
 
 The watcher can also be used to detect files that have moved. It will 
 not only detect if a watched file has disappeared, but also if it has
 been replaced by a new file in the meantime.
 
     my $watcher = Log::Log4perl::Config::Watch->new(
         file           => "/data/my.conf",
         check_interval => 30,
     );
 
     while(1) {
         if($watcher->file_has_moved()) {
             print "File has moved!\n";
         }
         sleep(1);
     }
 
 The parameters C<check_interval> and C<signal> limit the number of physical 
 file system checks, similarily as with C<change_detected()>.
 
 =head1 LICENSE
 
 Copyright 2002-2013 by Mike Schilli E<lt>m@perlmeister.comE<gt> 
 and Kevin Goess E<lt>cpan@goess.orgE<gt>.
 
 This library is free software; you can redistribute it and/or modify
 it under the same terms as Perl itself. 
 
 =head1 AUTHOR
 
 Please contribute patches to the project on Github:
 
     http://github.com/mschilli/log4perl
 
 Send bug reports or requests for enhancements to the authors via our
 
 MAILING LIST (questions, bug reports, suggestions/patches): 
 log4perl-devel@lists.sourceforge.net
 
 Authors (please contact them via the list above, not directly):
 Mike Schilli <m@perlmeister.com>,
 Kevin Goess <cpan@goess.org>
 
 Contributors (in alphabetical order):
 Ateeq Altaf, Cory Bennett, Jens Berthold, Jeremy Bopp, Hutton
 Davidson, Chris R. Donnelly, Matisse Enzer, Hugh Esco, Anthony
 Foiani, James FitzGibbon, Carl Franks, Dennis Gregorovic, Andy
 Grundman, Paul Harrington, Alexander Hartmaier  David Hull, 
 Robert Jacobson, Jason Kohles, Jeff Macdonald, Markus Peter, 
 Brett Rann, Peter Rabbitson, Erik Selberg, Aaron Straup Cope, 
 Lars Thegler, David Viner, Mac Yang.
 
### Log/Log4perl/DateFormat.pm ###
 ###########################################
 package Log::Log4perl::DateFormat;
 ###########################################
 use warnings;
 use strict;
 
 use Carp qw( croak );
 
 our $GMTIME = 0;
 
 my @MONTH_NAMES = qw(
 January February March April May June July
 August September October November December);
 
 my @WEEK_DAYS = qw(
 Sunday Monday Tuesday Wednesday Thursday Friday Saturday);
 
 ###########################################
 sub new {
 ###########################################
     my($class, $format) = @_;
 
     my $self = { 
                   stack => [],
                   fmt   => undef,
                };
 
     bless $self, $class;
 
         # Predefined formats
     if($format eq "ABSOLUTE") {
         $format = "HH:mm:ss,SSS";
     } elsif($format eq "DATE") {
         $format = "dd MMM yyyy HH:mm:ss,SSS";
     } elsif($format eq "ISO8601") {
         $format = "yyyy-MM-dd HH:mm:ss,SSS";
     } elsif($format eq "APACHE") {
         $format = "[EEE MMM dd HH:mm:ss yyyy]";
     }
 
     if($format) { 
         $self->prepare($format);
     }
 
     return $self;
 }
 
 ###########################################
 sub prepare {
 ###########################################
     my($self, $format) = @_;
 
     # the actual DateTime spec allows for literal text delimited by
     # single quotes; a single quote can be embedded in the literal
     # text by using two single quotes.
     #
     # my strategy here is to split the format into active and literal
     # "chunks"; active chunks are prepared using $self->rep() as
     # before, while literal chunks get transformed to accommodate
     # single quotes and to protect percent signs.
     #
     # motivation: the "recommended" ISO-8601 date spec for a time in
     # UTC is actually:
     #
     #     YYYY-mm-dd'T'hh:mm:ss.SSS'Z'
 
     my $fmt = "";
 
     foreach my $chunk ( split /('(?:''|[^'])*')/, $format ) {
         if ( $chunk =~ /\A'(.*)'\z/ ) {
               # literal text
             my $literal = $1;
             $literal =~ s/''/'/g;
             $literal =~ s/\%/\%\%/g;
             $fmt .= $literal;
         } elsif ( $chunk =~ /'/ ) {
               # single quotes should always be in a literal
             croak "bad date format \"$format\": " .
                   "unmatched single quote in chunk \"$chunk\"";
         } else {
             # handle active chunks just like before
             $chunk =~ s/(([GyMdhHmsSEeDFwWakKzZ])\2*)/$self->rep($1)/ge;
             $fmt .= $chunk;
         }
     }
 
     return $self->{fmt} = $fmt;
 }
 
 ###########################################
 sub rep {
 ###########################################
     my ($self, $string) = @_;
 
     my $first = substr $string, 0, 1;
     my $len   = length $string;
 
     my $time=time();
     my @g = gmtime($time);
     my @t = localtime($time);
     my $z = $t[1]-$g[1]+($t[2]-$g[2])*60+($t[7]-$g[7])*1440+
             ($t[5]-$g[5])*(525600+(abs($t[7]-$g[7])>364)*1440);
     my $offset = sprintf("%+.2d%.2d", $z/60, "00");
 
     #my ($s,$mi,$h,$d,$mo,$y,$wd,$yd,$dst) = localtime($time);
 
     # Here's how this works:
     # Detect what kind of parameter we're dealing with and determine
     # what type of sprintf-placeholder to return (%d, %02d, %s or whatever).
     # Then, we're setting up an array, specific to the current format,
     # that can be used later on to compute the components of the placeholders
     # one by one when we get the components of the current time later on
     # via localtime.
     
     # So, we're parsing the "yyyy/MM" format once, replace it by, say
     # "%04d:%02d" and store an array that says "for the first placeholder,
     # get the localtime-parameter on index #5 (which is years since the
     # epoch), add 1900 to it and pass it on to sprintf(). For the 2nd 
     # placeholder, get the localtime component at index #2 (which is hours)
     # and pass it on unmodified to sprintf.
     
     # So, the array to compute the time format at logtime contains
     # as many elements as the original SimpleDateFormat contained. Each
     # entry is a array ref, holding an array with 2 elements: The index
     # into the localtime to obtain the value and a reference to a subroutine
     # to do computations eventually. The subroutine expects the original
     # localtime() time component (like year since the epoch) and returns
     # the desired value for sprintf (like y+1900).
 
     # This way, we're parsing the original format only once (during system
     # startup) and during runtime all we do is call localtime *once* and
     # run a number of blazingly fast computations, according to the number
     # of placeholders in the format.
 
 ###########
 #G - epoch#
 ###########
     if($first eq "G") {
         # Always constant
         return "AD";
 
 ###################
 #e - epoch seconds#
 ###################
     } elsif($first eq "e") {
           # index (0) irrelevant, but we return time() which 
           # comes in as 2nd parameter
         push @{$self->{stack}}, [0, sub { return $_[1] }];
         return "%d";
 
 ##########
 #y - year#
 ##########
     } elsif($first eq "y") {
         if($len >= 4) {
             # 4-digit year
             push @{$self->{stack}}, [5, sub { return $_[0] + 1900 }];
             return "%04d";
         } else {
             # 2-digit year
             push @{$self->{stack}}, [5, sub { $_[0] % 100 }];
             return "%02d";
         }
 
 ###########
 #M - month#
 ###########
     } elsif($first eq "M") {
         if($len >= 3) {
             # Use month name
             push @{$self->{stack}}, [4, sub { return $MONTH_NAMES[$_[0]] }];
            if($len >= 4) {
                 return "%s";
             } else {
                return "%.3s";
             }
         } elsif($len == 2) {
             # Use zero-padded month number
             push @{$self->{stack}}, [4, sub { $_[0]+1 }];
             return "%02d";
         } else {
             # Use zero-padded month number
             push @{$self->{stack}}, [4, sub { $_[0]+1 }];
             return "%d";
         }
 
 ##################
 #d - day of month#
 ##################
     } elsif($first eq "d") {
         push @{$self->{stack}}, [3, sub { return $_[0] }];
         return "%0" . $len . "d";
 
 ##################
 #h - am/pm hour#
 ##################
     } elsif($first eq "h") {
         push @{$self->{stack}}, [2, sub { ($_[0] % 12) || 12 }];
         return "%0" . $len . "d";
 
 ##################
 #H - 24 hour#
 ##################
     } elsif($first eq "H") {
         push @{$self->{stack}}, [2, sub { return $_[0] }];
         return "%0" . $len . "d";
 
 ##################
 #m - minute#
 ##################
     } elsif($first eq "m") {
         push @{$self->{stack}}, [1, sub { return $_[0] }];
         return "%0" . $len . "d";
 
 ##################
 #s - second#
 ##################
     } elsif($first eq "s") {
         push @{$self->{stack}}, [0, sub { return $_[0] }];
         return "%0" . $len . "d";
 
 ##################
 #E - day of week #
 ##################
     } elsif($first eq "E") {
         push @{$self->{stack}}, [6, sub { $WEEK_DAYS[$_[0]] }];
        if($len >= 4) {
             return "%${len}s";
         } else {
            return "%.3s";
         }
 
 ######################
 #D - day of the year #
 ######################
     } elsif($first eq "D") {
         push @{$self->{stack}}, [7, sub { $_[0] + 1}];
         return "%0" . $len . "d";
 
 ######################
 #a - am/pm marker    #
 ######################
     } elsif($first eq "a") {
         push @{$self->{stack}}, [2, sub { $_[0] < 12 ? "AM" : "PM" }];
         return "%${len}s";
 
 ######################
 #S - milliseconds    #
 ######################
     } elsif($first eq "S") {
         push @{$self->{stack}}, 
              [9, sub { substr sprintf("%06d", $_[0]), 0, $len }];
         return "%s";
 
 ###############################
 #Z - RFC 822 time zone  -0800 #
 ###############################
     } elsif($first eq "Z") {
         push @{$self->{stack}}, [10, sub { $offset }];
         return "$offset";
 
 #############################
 #Something that's not defined
 #(F=day of week in month
 # w=week in year W=week in month
 # k=hour in day K=hour in am/pm
 # z=timezone
 #############################
     } else {
         return "-- '$first' not (yet) implemented --";
     }
 
     return $string;
 }
 
 ###########################################
 sub format {
 ###########################################
     my($self, $secs, $msecs) = @_;
 
     $msecs = 0 unless defined $msecs;
 
     my @time; 
 
     if($GMTIME) {
         @time = gmtime($secs);
     } else {
         @time = localtime($secs);
     }
 
         # add milliseconds
     push @time, $msecs;
 
     my @values = ();
 
     for(@{$self->{stack}}) {
         my($val, $code) = @$_;
         if($code) {
             push @values, $code->($time[$val], $secs);
         } else {
             push @values, $time[$val];
         }
     }
 
     return sprintf($self->{fmt}, @values);
 }
 
 1;
 
 __END__
 
 =encoding utf8
 
 =head1 NAME
 
 Log::Log4perl::DateFormat - Log4perl advanced date formatter helper class
 
 =head1 SYNOPSIS
 
     use Log::Log4perl::DateFormat;
 
     my $format = Log::Log4perl::DateFormat->new("HH:mm:ss,SSS");
 
     # Simple time, resolution in seconds
     my $time = time();
     print $format->format($time), "\n";
         # => "17:02:39,000"
 
     # Advanced time, resultion in milliseconds
     use Time::HiRes;
     my ($secs, $msecs) = Time::HiRes::gettimeofday();
     print $format->format($secs, $msecs), "\n";
         # => "17:02:39,959"
 
 =head1 DESCRIPTION
 
 C<Log::Log4perl::DateFormat> is a low-level helper class for the 
 advanced date formatting functions in C<Log::Log4perl::Layout::PatternLayout>.
 
 Unless you're writing your own Layout class like
 L<Log::Log4perl::Layout::PatternLayout>, there's probably not much use
 for you to read this.
 
 C<Log::Log4perl::DateFormat> is a formatter which allows dates to be
 formatted according to the log4j spec on
 
     http://download.oracle.com/javase/1.4.2/docs/api/java/text/SimpleDateFormat.html
 
 which allows the following placeholders to be recognized and processed:
 
     Symbol Meaning              Presentation    Example
     ------ -------              ------------    -------
     G      era designator       (Text)          AD
     e      epoch seconds        (Number)        1315011604
     y      year                 (Number)        1996
     M      month in year        (Text & Number) July & 07
     d      day in month         (Number)        10
     h      hour in am/pm (1~12) (Number)        12
     H      hour in day (0~23)   (Number)        0
     m      minute in hour       (Number)        30
     s      second in minute     (Number)        55
     S      millisecond          (Number)        978
     E      day in week          (Text)          Tuesday
     D      day in year          (Number)        189
     F      day of week in month (Number)        2 (2nd Wed in July)
     w      week in year         (Number)        27
     W      week in month        (Number)        2
     a      am/pm marker         (Text)          PM
     k      hour in day (1~24)   (Number)        24
     K      hour in am/pm (0~11) (Number)        0
     z      time zone            (Text)          Pacific Standard Time
     Z      RFC 822 time zone    (Text)          -0800
     '      escape for text      (Delimiter)
     ''     single quote         (Literal)       '
 
 For example, if you want to format the current Unix time in 
 C<"MM/dd HH:mm"> format, all you have to do is this:
 
     use Log::Log4perl::DateFormat;
 
     my $format = Log::Log4perl::DateFormat->new("MM/dd HH:mm");
 
     my $time = time();
     print $format->format($time), "\n";
 
 While the C<new()> method is expensive, because it parses the format
 strings and sets up all kinds of structures behind the scenes, 
 followup calls to C<format()> are fast, because C<DateFormat> will
 just call C<localtime()> and C<sprintf()> once to return the formatted
 date/time string.
 
 So, typically, you would initialize the formatter once and then reuse
 it over and over again to display all kinds of time values.
 
 Also, for your convenience, 
 the following predefined formats are available, just as outlined in the
 log4j spec:
 
     Format   Equivalent                     Example
     ABSOLUTE "HH:mm:ss,SSS"                 "15:49:37,459"
     DATE     "dd MMM yyyy HH:mm:ss,SSS"     "06 Nov 1994 15:49:37,459"
     ISO8601  "yyyy-MM-dd HH:mm:ss,SSS"      "1999-11-27 15:49:37,459"
     APACHE   "[EEE MMM dd HH:mm:ss yyyy]"   "[Wed Mar 16 15:49:37 2005]"
 
 So, instead of passing 
 
     Log::Log4perl::DateFormat->new("HH:mm:ss,SSS");
 
 you could just as well say
 
     Log::Log4perl::DateFormat->new("ABSOLUTE");
 
 and get the same result later on.
 
 =head2 Known Shortcomings
  
 The following placeholders are currently I<not> recognized, unless
 someone (and that could be you :) implements them:
 
     F day of week in month
     w week in year 
     W week in month
     k hour in day 
     K hour in am/pm
     z timezone (but we got 'Z' for the numeric time zone value)
 
 Also, C<Log::Log4perl::DateFormat> just knows about English week and
 month names, internationalization support has to be added.
 
 =head1 LICENSE
 
 Copyright 2002-2013 by Mike Schilli E<lt>m@perlmeister.comE<gt> 
 and Kevin Goess E<lt>cpan@goess.orgE<gt>.
 
 This library is free software; you can redistribute it and/or modify
 it under the same terms as Perl itself. 
 
 =head1 AUTHOR
 
 Please contribute patches to the project on Github:
 
     http://github.com/mschilli/log4perl
 
 Send bug reports or requests for enhancements to the authors via our
 
 MAILING LIST (questions, bug reports, suggestions/patches): 
 log4perl-devel@lists.sourceforge.net
 
 Authors (please contact them via the list above, not directly):
 Mike Schilli <m@perlmeister.com>,
 Kevin Goess <cpan@goess.org>
 
 Contributors (in alphabetical order):
 Ateeq Altaf, Cory Bennett, Jens Berthold, Jeremy Bopp, Hutton
 Davidson, Chris R. Donnelly, Matisse Enzer, Hugh Esco, Anthony
 Foiani, James FitzGibbon, Carl Franks, Dennis Gregorovic, Andy
 Grundman, Paul Harrington, Alexander Hartmaier  David Hull, 
 Robert Jacobson, Jason Kohles, Jeff Macdonald, Markus Peter, 
 Brett Rann, Peter Rabbitson, Erik Selberg, Aaron Straup Cope, 
 Lars Thegler, David Viner, Mac Yang.
 
### Log/Log4perl/Filter.pm ###
 ##################################################
 package Log::Log4perl::Filter;
 ##################################################
 
 use 5.006;
 use strict;
 use warnings;
 
 use Log::Log4perl::Level;
 use Log::Log4perl::Config;
 
 use constant _INTERNAL_DEBUG => 0;
 
 our %FILTERS_DEFINED = ();
 
 ##################################################
 sub new {
 ##################################################
     my($class, $name, $action) = @_;
   
     print "Creating filter $name\n" if _INTERNAL_DEBUG;
 
     my $self = { name => $name };
     bless $self, $class;
 
     if(ref($action) eq "CODE") {
         # it's a code ref
         $self->{ok} = $action;
     } else {
         # it's something else
         die "Code for ($name/$action) not properly defined";
     }
 
     return $self;
 }
 
 ##################################################
 sub register {         # Register a filter by name
                        # (Passed on to subclasses)
 ##################################################
     my($self) = @_;
 
     by_name($self->{name}, $self);
 }
 
 ##################################################
 sub by_name {        # Get/Set a filter object by name
 ##################################################
     my($name, $value) = @_;
 
     if(defined $value) {
         $FILTERS_DEFINED{$name} = $value;
     }
 
     if(exists $FILTERS_DEFINED{$name}) {
         return $FILTERS_DEFINED{$name};
     } else {
         return undef;
     }
 }
 
 ##################################################
 sub reset {
 ##################################################
     %FILTERS_DEFINED = ();
 }
 
 ##################################################
 sub ok {
 ##################################################
     my($self, %p) = @_;
 
     print "Calling $self->{name}'s ok method\n" if _INTERNAL_DEBUG;
 
         # Force filter classes to define their own
         # ok(). Exempt are only sub {..} ok functions,
         # defined in the conf file.
     die "This is to be overridden by the filter" unless
          defined $self->{ok};
 
     # What should we set the message in $_ to? The most logical
     # approach seems to be to concat all parts together. If some
     # filter wants to dissect the parts, it still can examine %p,
     # which gets passed to the subroutine and contains the chunks
     # in $p{message}.
         # Split because of CVS
     local($_) = join $
                      Log::Log4perl::JOIN_MSG_ARRAY_CHAR, @{$p{message}};
     print "\$_ is '$_'\n" if _INTERNAL_DEBUG;
 
     my $decision = $self->{ok}->(%p);
 
     print "$self->{name}'s ok'ed: ", 
           ($decision ? "yes" : "no"), "\n" if _INTERNAL_DEBUG;
 
     return $decision;
 }
 
 1;
 
 __END__
 
 =encoding utf8
 
 =head1 NAME
 
 Log::Log4perl::Filter - Log4perl Custom Filter Base Class
 
 =head1 SYNOPSIS
 
   use Log::Log4perl;
 
   Log::Log4perl->init(\ <<'EOT');
     log4perl.logger = INFO, Screen
     log4perl.filter.MyFilter        = sub { /let this through/ }
     log4perl.appender.Screen        = Log::Log4perl::Appender::Screen
     log4perl.appender.Screen.Filter = MyFilter
     log4perl.appender.Screen.layout = Log::Log4perl::Layout::SimpleLayout
   EOT
 
       # Define a logger
   my $logger = Log::Log4perl->get_logger("Some");
 
       # Let this through
   $logger->info("Here's the info, let this through!");
 
       # Suppress this
   $logger->info("Here's the info, suppress this!");
 
   #################################################################
   # StringMatch Filter:
   #################################################################
   log4perl.filter.M1               = Log::Log4perl::Filter::StringMatch
   log4perl.filter.M1.StringToMatch = let this through
   log4perl.filter.M1.AcceptOnMatch = true
 
   #################################################################
   # LevelMatch Filter:
   #################################################################
   log4perl.filter.M1               = Log::Log4perl::Filter::LevelMatch
   log4perl.filter.M1.LevelToMatch  = INFO
   log4perl.filter.M1.AcceptOnMatch = true
 
 =head1 DESCRIPTION
 
 Log4perl allows the use of customized filters in its appenders
 to control the output of messages. These filters might grep for
 certain text chunks in a message, verify that its priority
 matches or exceeds a certain level or that this is the 10th
 time the same message has been submitted -- and come to a log/no log 
 decision based upon these circumstantial facts.
 
 Filters have names and can be specified in two different ways in the Log4perl
 configuration file: As subroutines or as filter classes. Here's a 
 simple filter named C<MyFilter> which just verifies that the 
 oncoming message matches the regular expression C</let this through/i>:
 
     log4perl.filter.MyFilter        = sub { /let this through/i }
 
 It exploits the fact that when the subroutine defined
 above is called on a message,
 Perl's special C<$_> variable will be set to the message text (prerendered,
 i.e. concatenated but not layouted) to be logged. 
 The subroutine is expected to return a true value 
 if it wants the message to be logged or a false value if doesn't.
 
 Also, Log::Log4perl will pass a hash to the subroutine,
 containing all key/value pairs that it would pass to the corresponding 
 appender, as specified in Log::Log4perl::Appender. Here's an
 example of a filter checking the priority of the oncoming message:
 
   log4perl.filter.MyFilter        = sub {    \
        my %p = @_;                           \
        if($p{log4p_level} eq "WARN" or       \
           $p{log4p_level} eq "INFO") {       \
            return 1;                         \
        }                                     \
        return 0;                             \
   }     
 
 If the message priority equals C<WARN> or C<INFO>, 
 it returns a true value, causing
 the message to be logged.
 
 =head2 Predefined Filters
 
 For common tasks like verifying that the message priority matches
 a certain priority, there's already a 
 set of predefined filters available. To perform an exact level match, it's
 much cleaner to use Log4perl's C<LevelMatch> filter instead:
 
   log4perl.filter.M1               = Log::Log4perl::Filter::LevelMatch
   log4perl.filter.M1.LevelToMatch  = INFO
   log4perl.filter.M1.AcceptOnMatch = true
 
 This will let the message through if its priority is INFO and suppress
 it otherwise. The statement can be negated by saying
 
   log4perl.filter.M1.AcceptOnMatch = false
 
 instead. This way, the message will be logged if its priority is
 anything but INFO.
 
 On a similar note, Log4perl's C<StringMatch> filter will check the 
 oncoming message for strings or regular expressions:
 
   log4perl.filter.M1               = Log::Log4perl::Filter::StringMatch
   log4perl.filter.M1.StringToMatch = bl.. bl..
   log4perl.filter.M1.AcceptOnMatch = true
 
 This will open the gate for messages like C<blah blah> because the 
 regular expression in the C<StringToMatch> matches them. Again,
 the setting of C<AcceptOnMatch> determines if the filter is defined
 in a positive or negative way.
 
 All class filter entries in the configuration file
 have to adhere to the following rule:
 Only after a filter has been defined by name and class/subroutine,
 its attribute values can be
 assigned, just like the C<true> value above gets assigned to the
 C<AcceptOnMatch> attribute I<after> the
 filter C<M1> has been defined.
 
 =head2 Attaching a filter to an appender
 
 Attaching a filter to an appender is as easy as assigning its name to
 the appender's C<Filter> attribute:
 
     log4perl.appender.MyAppender.Filter = MyFilter
 
 This will cause C<Log::Log4perl> to call the filter subroutine/method
 every time a message is supposed to be passed to the appender. Depending
 on the filter's return value, C<Log::Log4perl> will either continue as
 planned or withdraw immediately.
 
 =head2 Combining filters with Log::Log4perl::Filter::Boolean
 
 Sometimes, it's useful to combine the output of various filters to
 arrive at a log/no log decision. While Log4j, Log4perl's mother ship,
 has chosen to implement this feature as a filter chain, similar to Linux' IP chains,
 Log4perl tries a different approach. 
 
 Typically, filter results will not need to be bumped along chains but 
 combined in a programmatic manner using boolean logic. "Log if
 this filter says 'yes' and that filter says 'no'" 
 is a fairly common requirement, but hard to implement as a chain.
 
 C<Log::Log4perl::Filter::Boolean> is a specially predefined custom filter
 for Log4perl. It combines the results of other custom filters 
 in arbitrary ways, using boolean expressions:
 
     log4perl.logger = WARN, AppWarn, AppError
 
     log4perl.filter.Match1       = sub { /let this through/ }
     log4perl.filter.Match2       = sub { /and that, too/ }
     log4perl.filter.MyBoolean       = Log::Log4perl::Filter::Boolean
     log4perl.filter.MyBoolean.logic = Match1 || Match2
 
     log4perl.appender.Screen        = Log::Log4perl::Appender::Screen
     log4perl.appender.Screen.Filter = MyBoolean
     log4perl.appender.Screen.layout = Log::Log4perl::Layout::SimpleLayout
 
 C<Log::Log4perl::Filter::Boolean>'s boolean expressions allow for combining
 different appenders by name using AND (&& or &), OR (|| or |) and NOT (!) as
 logical expressions. Also, parentheses can be used for defining precedences. 
 Operator precedence follows standard Perl conventions. Here's a bunch of examples:
 
     Match1 && !Match2            # Match1 and not Match2
     !(Match1 || Match2)          # Neither Match1 nor Match2
     (Match1 && Match2) || Match3 # Both Match1 and Match2 or Match3
 
 =head2 Writing your own filter classes
 
 If none of Log::Log4perl's predefined filter classes fits your needs,
 you can easily roll your own: Just define a new class,
 derive it from the baseclass C<Log::Log4perl::Filter>,
 and define its C<new> and C<ok> methods like this:
 
     package Log::Log4perl::Filter::MyFilter;
 
     use base Log::Log4perl::Filter;
 
     sub new {
         my ($class, %options) = @_;
 
         my $self = { %options,
                    };
      
         bless $self, $class;
 
         return $self;
     }
 
     sub ok {
          my ($self, %p) = @_;
 
          # ... decide and return 1 or 0
     }
 
     1;
 
 Log4perl will call the ok() method to determine if the filter
 should let the message pass or not. A true return value indicates
 the message will be logged by the appender, a false value blocks it.
 
 Values you've defined for its attributes in Log4perl's configuration file,
 will be received through its C<new> method:
 
     log4perl.filter.MyFilter       = Log::Log4perl::Filter::MyFilter
     log4perl.filter.MyFilter.color = red
 
 will cause C<Log::Log4perl::Filter::MyFilter>'s constructor to be called
 like this:
 
     Log::Log4perl::Filter::MyFilter->new( name  => "MyFilter",
                                           color => "red" );
 
 The custom filter class should use this to set the object's attributes, 
 to have them available later to base log/nolog decisions on it.
 
 C<ok()> is the filter's method to tell if it agrees or disagrees with logging
 the message. It will be called by Log::Log4perl whenever it needs the
 filter to decide. A false value returned by C<ok()> will block messages,
 a true value will let them through.
 
 =head2 A Practical Example: Level Matching
 
 See L<Log::Log4perl::FAQ> for this.
 
 =head1 SEE ALSO
 
 L<Log::Log4perl::Filter::LevelMatch>,
 L<Log::Log4perl::Filter::LevelRange>,
 L<Log::Log4perl::Filter::StringRange>,
 L<Log::Log4perl::Filter::Boolean>
 
 =head1 LICENSE
 
 Copyright 2002-2013 by Mike Schilli E<lt>m@perlmeister.comE<gt> 
 and Kevin Goess E<lt>cpan@goess.orgE<gt>.
 
 This library is free software; you can redistribute it and/or modify
 it under the same terms as Perl itself. 
 
 =head1 AUTHOR
 
 Please contribute patches to the project on Github:
 
     http://github.com/mschilli/log4perl
 
 Send bug reports or requests for enhancements to the authors via our
 
 MAILING LIST (questions, bug reports, suggestions/patches): 
 log4perl-devel@lists.sourceforge.net
 
 Authors (please contact them via the list above, not directly):
 Mike Schilli <m@perlmeister.com>,
 Kevin Goess <cpan@goess.org>
 
 Contributors (in alphabetical order):
 Ateeq Altaf, Cory Bennett, Jens Berthold, Jeremy Bopp, Hutton
 Davidson, Chris R. Donnelly, Matisse Enzer, Hugh Esco, Anthony
 Foiani, James FitzGibbon, Carl Franks, Dennis Gregorovic, Andy
 Grundman, Paul Harrington, Alexander Hartmaier  David Hull, 
 Robert Jacobson, Jason Kohles, Jeff Macdonald, Markus Peter, 
 Brett Rann, Peter Rabbitson, Erik Selberg, Aaron Straup Cope, 
 Lars Thegler, David Viner, Mac Yang.
 
### Log/Log4perl/Filter/Boolean.pm ###
 ##################################################
 package Log::Log4perl::Filter::Boolean;
 ##################################################
 
 use 5.006;
 
 use strict;
 use warnings;
 
 use Log::Log4perl::Level;
 use Log::Log4perl::Config;
 
 use constant _INTERNAL_DEBUG => 0;
 
 use base qw(Log::Log4perl::Filter);
 
 ##################################################
 sub new {
 ##################################################
     my ($class, %options) = @_;
 
     my $self = { params => {},
                  %options,
                };
      
     bless $self, $class;
      
     print "Compiling '$options{logic}'\n" if _INTERNAL_DEBUG;
 
         # Set up meta-decider for later
     $self->compile_logic($options{logic});
 
     return $self;
 }
 
 ##################################################
 sub ok {
 ##################################################
      my ($self, %p) = @_;
 
      return $self->eval_logic(\%p);
 }
 
 ##################################################
 sub compile_logic {
 ##################################################
     my ($self, $logic) = @_;
 
        # Extract Filter placeholders in logic as defined
        # in configuration file.
     while($logic =~ /([\w_-]+)/g) {
             # Get the corresponding filter object
         my $filter = Log::Log4perl::Filter::by_name($1);
         die "Filter $filter required by Boolean filter, but not defined" 
             unless $filter;
 
         $self->{params}->{$1} = $filter;
     }
 
         # Fabricate a parameter list: A1/A2/A3 => $A1, $A2, $A3
     my $plist = join ', ', map { '$' . $_ } keys %{$self->{params}};
 
         # Replace all the (dollar-less) placeholders in the code with
         # calls to their respective coderefs.  
         $logic =~ s/([\w_-]+)/\&\$$1/g;
 
         # Set up the meta decider, which transforms the config file
         # logic into compiled perl code
     my $func = <<EOT;
         sub { 
             my($plist) = \@_;
             $logic;
         }
 EOT
 
     print "func=$func\n" if _INTERNAL_DEBUG;
 
     my $eval_func = eval $func;
 
     if(! $eval_func) {
         die "Syntax error in Boolean filter logic: $eval_func";
     }
 
     $self->{eval_func} = $eval_func;
 }
 
 ##################################################
 sub eval_logic {
 ##################################################
     my($self, $p) = @_;
 
     my @plist = ();
 
         # Eval the results of all filters referenced
         # in the code (although the order of keys is
         # not predictable, it is consistent :)
     for my $param (keys %{$self->{params}}) {
         # Pass a coderef as a param that will run the filter's ok method and
         # return a 1 or 0.  
         print "Passing filter $param\n" if _INTERNAL_DEBUG;
         push(@plist, sub {
             return $self->{params}->{$param}->ok(%$p) ? 1 : 0
         });
     }
 
         # Now pipe the parameters into the canned function,
         # have it evaluate the logic and return the final
         # decision
     print "Passing in (", join(', ', @plist), ")\n" if _INTERNAL_DEBUG;
     return $self->{eval_func}->(@plist);
 }
 
 1;
 
 __END__
 
 =encoding utf8
 
 =head1 NAME
 
 Log::Log4perl::Filter::Boolean - Special filter to combine the results of others
 
 =head1 SYNOPSIS
 
     log4perl.logger = WARN, AppWarn, AppError
 
     log4perl.filter.Match1       = sub { /let this through/ }
     log4perl.filter.Match2       = sub { /and that, too/ }
     log4perl.filter.MyBoolean       = Log::Log4perl::Filter::Boolean
     log4perl.filter.MyBoolean.logic = Match1 || Match2
 
     log4perl.appender.Screen        = Log::Dispatch::Screen
     log4perl.appender.Screen.Filter = MyBoolean
     log4perl.appender.Screen.layout = Log::Log4perl::Layout::SimpleLayout
 
 =head1 DESCRIPTION
 
 Sometimes, it's useful to combine the output of various filters to
 arrive at a log/no log decision. While Log4j, Log4perl's mother ship,
 chose to implement this feature as a filter chain, similar to Linux' IP chains,
 Log4perl tries a different approach. 
 
 Typically, filter results will not need to be passed along in chains but 
 combined in a programmatic manner using boolean logic. "Log if
 this filter says 'yes' and that filter says 'no'" 
 is a fairly common requirement but hard to implement as a chain.
 
 C<Log::Log4perl::Filter::Boolean> is a special predefined custom filter
 for Log4perl which combines the results of other custom filters 
 in arbitrary ways, using boolean expressions:
 
     log4perl.logger = WARN, AppWarn, AppError
 
     log4perl.filter.Match1       = sub { /let this through/ }
     log4perl.filter.Match2       = sub { /and that, too/ }
     log4perl.filter.MyBoolean       = Log::Log4perl::Filter::Boolean
     log4perl.filter.MyBoolean.logic = Match1 || Match2
 
     log4perl.appender.Screen        = Log::Dispatch::Screen
     log4perl.appender.Screen.Filter = MyBoolean
     log4perl.appender.Screen.layout = Log::Log4perl::Layout::SimpleLayout
 
 C<Log::Log4perl::Filter::Boolean>'s boolean expressions allow for combining
 different appenders by name using AND (&& or &), OR (|| or |) and NOT (!) as
 logical expressions. Parentheses are used for grouping. Precedence follows
 standard Perl. Here's a bunch of examples:
 
     Match1 && !Match2            # Match1 and not Match2
     !(Match1 || Match2)          # Neither Match1 nor Match2
     (Match1 && Match2) || Match3 # Both Match1 and Match2 or Match3
 
 =head1 SEE ALSO
 
 L<Log::Log4perl::Filter>,
 L<Log::Log4perl::Filter::LevelMatch>,
 L<Log::Log4perl::Filter::LevelRange>,
 L<Log::Log4perl::Filter::MDC>,
 L<Log::Log4perl::Filter::StringRange>
 
 =head1 LICENSE
 
 Copyright 2002-2013 by Mike Schilli E<lt>m@perlmeister.comE<gt> 
 and Kevin Goess E<lt>cpan@goess.orgE<gt>.
 
 This library is free software; you can redistribute it and/or modify
 it under the same terms as Perl itself. 
 
 =head1 AUTHOR
 
 Please contribute patches to the project on Github:
 
     http://github.com/mschilli/log4perl
 
 Send bug reports or requests for enhancements to the authors via our
 
 MAILING LIST (questions, bug reports, suggestions/patches): 
 log4perl-devel@lists.sourceforge.net
 
 Authors (please contact them via the list above, not directly):
 Mike Schilli <m@perlmeister.com>,
 Kevin Goess <cpan@goess.org>
 
 Contributors (in alphabetical order):
 Ateeq Altaf, Cory Bennett, Jens Berthold, Jeremy Bopp, Hutton
 Davidson, Chris R. Donnelly, Matisse Enzer, Hugh Esco, Anthony
 Foiani, James FitzGibbon, Carl Franks, Dennis Gregorovic, Andy
 Grundman, Paul Harrington, Alexander Hartmaier  David Hull, 
 Robert Jacobson, Jason Kohles, Jeff Macdonald, Markus Peter, 
 Brett Rann, Peter Rabbitson, Erik Selberg, Aaron Straup Cope, 
 Lars Thegler, David Viner, Mac Yang.
 
### Log/Log4perl/Filter/LevelMatch.pm ###
 ##################################################
 package Log::Log4perl::Filter::LevelMatch;
 ##################################################
 
 use 5.006;
 
 use strict;
 use warnings;
 
 use Log::Log4perl::Level;
 use Log::Log4perl::Config;
 use Log::Log4perl::Util qw( params_check );
 
 use constant _INTERNAL_DEBUG => 0;
 
 use base qw(Log::Log4perl::Filter);
 
 ##################################################
 sub new {
 ##################################################
     my ($class, %options) = @_;
 
     my $self = { LevelToMatch  => '',
                  AcceptOnMatch => 1,
                  %options,
                };
      
     params_check( $self,
                   [ qw( LevelToMatch ) ], 
                   [ qw( name AcceptOnMatch ) ] 
                 );
 
     $self->{AcceptOnMatch} = Log::Log4perl::Config::boolean_to_perlish(
                                                 $self->{AcceptOnMatch});
 
     bless $self, $class;
 
     return $self;
 }
 
 ##################################################
 sub ok {
 ##################################################
      my ($self, %p) = @_;
 
      if($self->{LevelToMatch} eq $p{log4p_level}) {
          print "Levels match\n" if _INTERNAL_DEBUG;
          return $self->{AcceptOnMatch};
      } else {
          print "Levels don't match\n" if _INTERNAL_DEBUG;
          return !$self->{AcceptOnMatch};
      }
 }
 
 1;
 
 __END__
 
 =encoding utf8
 
 =head1 NAME
 
 Log::Log4perl::Filter::LevelMatch - Filter to match the log level exactly
 
 =head1 SYNOPSIS
 
     log4perl.filter.Match1               = Log::Log4perl::Filter::LevelMatch
     log4perl.filter.Match1.LevelToMatch  = ERROR
     log4perl.filter.Match1.AcceptOnMatch = true
 
 =head1 DESCRIPTION
 
 This Log4perl custom filter checks if the currently submitted message
 matches a predefined priority, as set in C<LevelToMatch>.
 The additional parameter C<AcceptOnMatch> defines if the filter
 is supposed to pass or block the message (C<true> or C<false>)
 on a match.
 
 =head1 SEE ALSO
 
 L<Log::Log4perl::Filter>,
 L<Log::Log4perl::Filter::Boolean>,
 L<Log::Log4perl::Filter::LevelRange>,
 L<Log::Log4perl::Filter::MDC>,
 L<Log::Log4perl::Filter::StringMatch>
 
 =head1 LICENSE
 
 Copyright 2002-2013 by Mike Schilli E<lt>m@perlmeister.comE<gt> 
 and Kevin Goess E<lt>cpan@goess.orgE<gt>.
 
 This library is free software; you can redistribute it and/or modify
 it under the same terms as Perl itself. 
 
 =head1 AUTHOR
 
 Please contribute patches to the project on Github:
 
     http://github.com/mschilli/log4perl
 
 Send bug reports or requests for enhancements to the authors via our
 
 MAILING LIST (questions, bug reports, suggestions/patches): 
 log4perl-devel@lists.sourceforge.net
 
 Authors (please contact them via the list above, not directly):
 Mike Schilli <m@perlmeister.com>,
 Kevin Goess <cpan@goess.org>
 
 Contributors (in alphabetical order):
 Ateeq Altaf, Cory Bennett, Jens Berthold, Jeremy Bopp, Hutton
 Davidson, Chris R. Donnelly, Matisse Enzer, Hugh Esco, Anthony
 Foiani, James FitzGibbon, Carl Franks, Dennis Gregorovic, Andy
 Grundman, Paul Harrington, Alexander Hartmaier  David Hull, 
 Robert Jacobson, Jason Kohles, Jeff Macdonald, Markus Peter, 
 Brett Rann, Peter Rabbitson, Erik Selberg, Aaron Straup Cope, 
 Lars Thegler, David Viner, Mac Yang.
 
### Log/Log4perl/Filter/LevelRange.pm ###
 ##################################################
 package Log::Log4perl::Filter::LevelRange;
 ##################################################
 
 use 5.006;
 
 use strict;
 use warnings;
 
 use Log::Log4perl::Level;
 use Log::Log4perl::Config;
 use Log::Log4perl::Util qw( params_check );
 
 use constant _INTERNAL_DEBUG => 0;
 
 use base "Log::Log4perl::Filter";
 
 ##################################################
 sub new {
 ##################################################
     my ($class, %options) = @_;
 
     my $self = { LevelMin      => 'DEBUG',
                  LevelMax      => 'FATAL',
                  AcceptOnMatch => 1,
                  %options,
                };
      
     params_check( $self,
                   [ qw( LevelMin LevelMax ) ], 
                   [ qw( name AcceptOnMatch ) ] 
                 );
 
     $self->{AcceptOnMatch} = Log::Log4perl::Config::boolean_to_perlish(
                                                 $self->{AcceptOnMatch});
 
     bless $self, $class;
 
     return $self;
 }
 
 ##################################################
 sub ok {
 ##################################################
      my ($self, %p) = @_;
 
      if(Log::Log4perl::Level::to_priority($self->{LevelMin}) <= 
         Log::Log4perl::Level::to_priority($p{log4p_level}) and
         Log::Log4perl::Level::to_priority($self->{LevelMax}) >= 
         Log::Log4perl::Level::to_priority($p{log4p_level})) {
          return $self->{AcceptOnMatch};
      } else {
          return ! $self->{AcceptOnMatch};
      }
 }
 
 1;
 
 __END__
 
 =encoding utf8
 
 =head1 NAME
 
 Log::Log4perl::Filter::LevelRange - Filter for a range of log levels
 
 =head1 SYNOPSIS
 
     log4perl.filter.Match1               = Log::Log4perl::Filter::LevelRange
     log4perl.filter.Match1.LevelMin      = INFO
     log4perl.filter.Match1.LevelMax      = ERROR
     log4perl.filter.Match1.AcceptOnMatch = true
 
 =head1 DESCRIPTION
 
 This Log4perl custom filter checks if the current message
 has a priority matching a predefined range. 
 The C<LevelMin> and C<LevelMax> parameters define the levels
 (choose from C<DEBUG>, C<INFO>, C<WARN>, C<ERROR>, C<FATAL>) marking
 the window of allowed messages priorities.
 
 C<LevelMin> defaults to C<DEBUG>, and C<LevelMax> to C<FATAL>.
 
 The additional parameter C<AcceptOnMatch> defines if the filter
 is supposed to pass or block the message (C<true> or C<false>).
 
 =head1 SEE ALSO
 
 L<Log::Log4perl::Filter>,
 L<Log::Log4perl::Filter::Boolean>,
 L<Log::Log4perl::Filter::LevelMatch>,
 L<Log::Log4perl::Filter::MDC>,
 L<Log::Log4perl::Filter::StringMatch>
 
 =head1 LICENSE
 
 Copyright 2002-2013 by Mike Schilli E<lt>m@perlmeister.comE<gt> 
 and Kevin Goess E<lt>cpan@goess.orgE<gt>.
 
 This library is free software; you can redistribute it and/or modify
 it under the same terms as Perl itself. 
 
 =head1 AUTHOR
 
 Please contribute patches to the project on Github:
 
     http://github.com/mschilli/log4perl
 
 Send bug reports or requests for enhancements to the authors via our
 
 MAILING LIST (questions, bug reports, suggestions/patches): 
 log4perl-devel@lists.sourceforge.net
 
 Authors (please contact them via the list above, not directly):
 Mike Schilli <m@perlmeister.com>,
 Kevin Goess <cpan@goess.org>
 
 Contributors (in alphabetical order):
 Ateeq Altaf, Cory Bennett, Jens Berthold, Jeremy Bopp, Hutton
 Davidson, Chris R. Donnelly, Matisse Enzer, Hugh Esco, Anthony
 Foiani, James FitzGibbon, Carl Franks, Dennis Gregorovic, Andy
 Grundman, Paul Harrington, Alexander Hartmaier  David Hull, 
 Robert Jacobson, Jason Kohles, Jeff Macdonald, Markus Peter, 
 Brett Rann, Peter Rabbitson, Erik Selberg, Aaron Straup Cope, 
 Lars Thegler, David Viner, Mac Yang.
 
### Log/Log4perl/Filter/MDC.pm ###
 package Log::Log4perl::Filter::MDC;
 use strict;
 use warnings;
 
 use Log::Log4perl::Util qw( params_check );
 
 use base "Log::Log4perl::Filter";
 
 sub new {
     my ( $class, %options ) = @_;
 
     my $self = {%options};
 
     params_check( $self, [qw( KeyToMatch RegexToMatch )] );
 
     $self->{RegexToMatch} = qr/$self->{RegexToMatch}/;
 
     bless $self, $class;
 
     return $self;
 }
 
 sub ok {
     my ( $self, %p ) = @_;
 
     my $context = Log::Log4perl::MDC->get_context;
 
     my $value = $context->{ $self->{KeyToMatch} };
     return 1
         if defined $value && $value =~ $self->{RegexToMatch};
 
     return 0;
 }
 
 1;
 
 __END__
 
 =encoding utf8
 
 =head1 NAME
 
 Log::Log4perl::Filter::MDC - Filter to match on values of a MDC key
 
 =head1 SYNOPSIS
 
     log4perl.filter.Match1               = Log::Log4perl::Filter::MDC
     log4perl.filter.Match1.KeyToMatch    = foo
     log4perl.filter.Match1.RegexToMatch  = bar
 
 =head1 DESCRIPTION
 
 This Log4perl filter checks if a predefined MDC key, as set in C<KeyToMatch>,
 of the currently submitted message matches a predefined regex, as set in
 C<RegexToMatch>.
 
 =head1 SEE ALSO
 
 L<Log::Log4perl::Filter>,
 L<Log::Log4perl::Filter::Boolean>,
 L<Log::Log4perl::Filter::LevelMatch>,
 L<Log::Log4perl::Filter::LevelRange>,
 L<Log::Log4perl::Filter::MDC>,
 L<Log::Log4perl::Filter::StringMatch>
 
 =head1 LICENSE
 
 Copyright 2002-2013 by Mike Schilli E<lt>m@perlmeister.comE<gt> 
 and Kevin Goess E<lt>cpan@goess.orgE<gt>.
 
 This library is free software; you can redistribute it and/or modify
 it under the same terms as Perl itself. 
 
 =head1 AUTHOR
 
 Please contribute patches to the project on Github:
 
     http://github.com/mschilli/log4perl
 
 Send bug reports or requests for enhancements to the authors via our
 
 MAILING LIST (questions, bug reports, suggestions/patches): 
 log4perl-devel@lists.sourceforge.net
 
 Authors (please contact them via the list above, not directly):
 Mike Schilli <m@perlmeister.com>,
 Kevin Goess <cpan@goess.org>
 
 Contributors (in alphabetical order):
 Ateeq Altaf, Cory Bennett, Jens Berthold, Jeremy Bopp, Hutton
 Davidson, Chris R. Donnelly, Matisse Enzer, Hugh Esco, Anthony
 Foiani, James FitzGibbon, Carl Franks, Dennis Gregorovic, Andy
 Grundman, Paul Harrington, Alexander Hartmaier  David Hull, 
 Robert Jacobson, Jason Kohles, Jeff Macdonald, Markus Peter, 
 Brett Rann, Peter Rabbitson, Erik Selberg, Aaron Straup Cope, 
 Lars Thegler, David Viner, Mac Yang.
 
### Log/Log4perl/Filter/StringMatch.pm ###
 ##################################################
 package Log::Log4perl::Filter::StringMatch;
 ##################################################
 
 use 5.006;
 
 use strict;
 use warnings;
 
 use Log::Log4perl::Config;
 use Log::Log4perl::Util qw( params_check );
 
 use constant _INTERNAL_DEBUG => 0;
 
 use base "Log::Log4perl::Filter";
 
 ##################################################
 sub new {
 ##################################################
      my ($class, %options) = @_;
 
      print join('-', %options) if _INTERNAL_DEBUG;
 
      my $self = { StringToMatch => undef,
                   AcceptOnMatch => 1,
                   %options,
                 };
      
      params_check( $self,
                   [ qw( StringToMatch ) ], 
                   [ qw( name AcceptOnMatch ) ] 
                 );
 
      $self->{AcceptOnMatch} = Log::Log4perl::Config::boolean_to_perlish(
                                                  $self->{AcceptOnMatch});
 
      $self->{StringToMatch} = qr($self->{StringToMatch});
 
      bless $self, $class;
 
      return $self;
 }
 
 ##################################################
 sub ok {
 ##################################################
      my ($self, %p) = @_;
 
      local($_) = join $
                      Log::Log4perl::JOIN_MSG_ARRAY_CHAR, @{$p{message}};
 
      if($_ =~ $self->{StringToMatch}) {
          print "Strings match\n" if _INTERNAL_DEBUG;
          return $self->{AcceptOnMatch};
      } else {
          print "Strings don't match ($_/$self->{StringToMatch})\n" 
              if _INTERNAL_DEBUG;
          return !$self->{AcceptOnMatch};
      }
 }
 
 1;
 
 __END__
 
 =encoding utf8
 
 =head1 NAME
 
 Log::Log4perl::Filter::StringMatch - Filter on log message string
 
 =head1 SYNOPSIS
 
     log4perl.filter.Match1               = Log::Log4perl::Filter::StringMatch
     log4perl.filter.Match1.StringToMatch = blah blah
     log4perl.filter.Match1.AcceptOnMatch = true
 
 =head1 DESCRIPTION
 
 This Log4perl custom filter checks if the currently submitted message
 matches a predefined regular expression, as set in the C<StringToMatch>
 parameter. It uses common Perl 5 regexes.
 
 The additional parameter C<AcceptOnMatch> defines if the filter
 is supposed to pass or block the message on a match (C<true> or C<false>).
 
 =head1 SEE ALSO
 
 L<Log::Log4perl::Filter>,
 L<Log::Log4perl::Filter::Boolean>,
 L<Log::Log4perl::Filter::LevelMatch>,
 L<Log::Log4perl::Filter::LevelRange>,
 L<Log::Log4perl::Filter::MDC>
 
 =head1 LICENSE
 
 Copyright 2002-2013 by Mike Schilli E<lt>m@perlmeister.comE<gt> 
 and Kevin Goess E<lt>cpan@goess.orgE<gt>.
 
 This library is free software; you can redistribute it and/or modify
 it under the same terms as Perl itself. 
 
 =head1 AUTHOR
 
 Please contribute patches to the project on Github:
 
     http://github.com/mschilli/log4perl
 
 Send bug reports or requests for enhancements to the authors via our
 
 MAILING LIST (questions, bug reports, suggestions/patches): 
 log4perl-devel@lists.sourceforge.net
 
 Authors (please contact them via the list above, not directly):
 Mike Schilli <m@perlmeister.com>,
 Kevin Goess <cpan@goess.org>
 
 Contributors (in alphabetical order):
 Ateeq Altaf, Cory Bennett, Jens Berthold, Jeremy Bopp, Hutton
 Davidson, Chris R. Donnelly, Matisse Enzer, Hugh Esco, Anthony
 Foiani, James FitzGibbon, Carl Franks, Dennis Gregorovic, Andy
 Grundman, Paul Harrington, Alexander Hartmaier  David Hull, 
 Robert Jacobson, Jason Kohles, Jeff Macdonald, Markus Peter, 
 Brett Rann, Peter Rabbitson, Erik Selberg, Aaron Straup Cope, 
 Lars Thegler, David Viner, Mac Yang.
 
### Log/Log4perl/InternalDebug.pm ###
 package Log::Log4perl::InternalDebug;
 use warnings;
 use strict;
 
 use File::Temp qw(tempfile);
 use File::Spec;
 
 require Log::Log4perl::Resurrector;
 
 ###########################################
 sub enable {
 ###########################################
     unshift @INC, \&internal_debug_loader;
 }
 
 ##################################################
 sub internal_debug_fh {
 ##################################################
     my($file) = @_;
 
     local($/) = undef;
     open FILE, "<$file" or die "Cannot open $file";
     my $text = <FILE>;
     close FILE;
 
     my($tmp_fh, $tmpfile) = tempfile( UNLINK => 1 );
 
     $text =~ s/_INTERNAL_DEBUG(?!\s*=>)/1/g;
 
     print $tmp_fh $text;
     seek $tmp_fh, 0, 0;
 
     return $tmp_fh;
 }
 
 ###########################################
 sub internal_debug_loader {
 ###########################################
     my ($code, $module) = @_;
 
       # Skip non-Log4perl modules
     if($module !~ m#^Log/Log4perl#) {
         return undef;
     }
 
     my $path = $module;
     if(!-f $path) {
         $path = Log::Log4perl::Resurrector::pm_search( $module );
     }
 
     my $fh = internal_debug_fh($path);
 
     my $abs_path = File::Spec->rel2abs( $path );
     $INC{$module} = $abs_path;
 
     return $fh;
 }
 
 ###########################################
 sub resurrector_init {
 ###########################################
     unshift @INC, \&resurrector_loader;
 }
 
 ###########################################
 sub import {
 ###########################################
     # enable it on import
   enable();
 }
 
 1;
 
 __END__
 
 =encoding utf8
 
 =head1 NAME
 
 Log::Log4perl::InternalDebug - Dark Magic to enable _INTERNAL_DEBUG
 
 =head1 DESCRIPTION
 
 When called with
 
     perl -MLog::Log4perl::InternalDebug t/001Test.t
 
 scripts will run with _INTERNAL_DEBUG set to a true value and hence
 print internal Log4perl debugging information.
 
 =head1 LICENSE
 
 Copyright 2002-2013 by Mike Schilli E<lt>m@perlmeister.comE<gt> 
 and Kevin Goess E<lt>cpan@goess.orgE<gt>.
 
 This library is free software; you can redistribute it and/or modify
 it under the same terms as Perl itself. 
 
 =head1 AUTHOR
 
 Please contribute patches to the project on Github:
 
     http://github.com/mschilli/log4perl
 
 Send bug reports or requests for enhancements to the authors via our
 
 MAILING LIST (questions, bug reports, suggestions/patches): 
 log4perl-devel@lists.sourceforge.net
 
 Authors (please contact them via the list above, not directly):
 Mike Schilli <m@perlmeister.com>,
 Kevin Goess <cpan@goess.org>
 
 Contributors (in alphabetical order):
 Ateeq Altaf, Cory Bennett, Jens Berthold, Jeremy Bopp, Hutton
 Davidson, Chris R. Donnelly, Matisse Enzer, Hugh Esco, Anthony
 Foiani, James FitzGibbon, Carl Franks, Dennis Gregorovic, Andy
 Grundman, Paul Harrington, Alexander Hartmaier  David Hull, 
 Robert Jacobson, Jason Kohles, Jeff Macdonald, Markus Peter, 
 Brett Rann, Peter Rabbitson, Erik Selberg, Aaron Straup Cope, 
 Lars Thegler, David Viner, Mac Yang.
 
### Log/Log4perl/JavaMap.pm ###
 package Log::Log4perl::JavaMap;
 
 use Carp;
 use strict;
 
 use constant _INTERNAL_DEBUG => 0;
 
 our %translate = (
     'org.apache.log4j.ConsoleAppender' => 
         'Log::Log4perl::JavaMap::ConsoleAppender',
     'org.apache.log4j.FileAppender'    => 
         'Log::Log4perl::JavaMap::FileAppender',
     'org.apache.log4j.RollingFileAppender'    => 
         'Log::Log4perl::JavaMap::RollingFileAppender',
     'org.apache.log4j.TestBuffer'    => 
         'Log::Log4perl::JavaMap::TestBuffer',
      'org.apache.log4j.jdbc.JDBCAppender'    => 
         'Log::Log4perl::JavaMap::JDBCAppender',
      'org.apache.log4j.SyslogAppender'    => 
         'Log::Log4perl::JavaMap::SyslogAppender',
      'org.apache.log4j.NTEventLogAppender'    => 
         'Log::Log4perl::JavaMap::NTEventLogAppender',
 );
 
 our %user_defined;
 
 sub get {
     my ($appender_name, $appender_data) = @_;
 
     print "Trying to map $appender_name\n" if _INTERNAL_DEBUG;
 
     $appender_data->{value} ||
             die "ERROR: you didn't tell me how to implement your appender " .
                 "'$appender_name'";
 
     my $perl_class = $translate{$appender_data->{value}} || 
                      $user_defined{$appender_data->{value}} ||
             die "ERROR:  I don't know how to make a '$appender_data->{value}' " .
                 "to implement your appender '$appender_name', that's not a " .
                 "supported class\n";
     eval {
         eval "require $perl_class";  #see 'perldoc -f require' for why two evals
         die $@ if $@;
     };
     $@ and die "ERROR: trying to set appender for $appender_name to " .
                "$appender_data->{value} using $perl_class failed\n$@  \n";
 
     my $app = $perl_class->new($appender_name, $appender_data);
     return $app;
 }
 
 #an external api to the two hashes
 sub translate {
     my $java_class = shift;
 
     return $translate{$java_class} || 
             $user_defined{$java_class};
 }
 
 1;
 
 
 =encoding utf8
 
 =head1 NAME
 
 Log::Log4perl::JavaMap - maps java log4j appenders to Log::Dispatch classes
 
 =head1 SYNOPSIS
 
      ###############################
      log4j.appender.FileAppndr1        = org.apache.log4j.FileAppender
      log4j.appender.FileAppndr1.File   = /var/log/onetime.log
      log4j.appender.FileAppndr1.Append = false
 
      log4j.appender.FileAppndr1.layout = org.apache.log4j.PatternLayout
      log4j.appender.FileAppndr1.layout.ConversionPattern=%d %4r [%t] %-5p %c %x - %m%n
      ###############################
 
 
 =head1 DESCRIPTION
 
 If somebody wants to create an appender called C<org.apache.log4j.ConsoleAppender>,
 we want to translate it to Log::Dispatch::Screen, and then translate
 the log4j options into Log::Dispatch parameters..
 
 =head2 What's Implemented
 
 (Note that you can always use the Log::Dispatch::* module.  By 'implemented'
 I mean having a translation class that translates log4j options into
 the Log::Dispatch options so you can use log4j rather than log4perl 
 syntax in your config file.)
 
 Here's the list of appenders I see on the current (6/2002) log4j site.
 
 These are implemented
 
     ConsoleAppender     - Log::Dispatch::Screen
     FileAppender        - Log::Dispatch::File
     RollingFileAppender - Log::Dispatch::FileRotate (by Mark Pfeiffer)
     JDBCAppender        - Log::Log4perl::Appender::DBI
     SyslogAppender      - Log::Dispatch::Syslog
     NTEventLogAppender  - Log::Dispatch::Win32EventLog
 
 
 These should/will/might be implemented
     
     DailyRollingFileAppender - 
     SMTPAppender     - Log::Dispatch::Email::MailSender
     
 
 These might be implemented but they don't have corresponding classes
 in Log::Dispatch (yet):
 
     NullAppender
     TelnetAppender
 
 These might be simulated
 
     LF5Appender - use Tk?
     ExternallyRolledFileAppender - catch a HUP instead?
 
 These will probably not be implemented
 
     AsyncAppender
     JMSAppender
     SocketAppender - (ships a serialized LoggingEvent to the server side)
     SocketHubAppender
 
 =head1 ROLL YOUR OWN
 
 Let's say you've in a mixed Java/Perl environment and you've
 come up with some custom Java appender with behavior you want to 
 use in both worlds, C<myorg.customAppender>.  You write a
 Perl appender with the same behavior C<Myorg::CustomAppender>. You
 want to use one config file across both applications, so the
 config file will have to say 'myorg.customAppender'.  But
 the mapping from C<myorg.customAppender> to C<Myorg::CustomAppender>
 isn't in this JavaMap class, so what do you do?
 
 In  your Perl code, before you call Log::Log4perl::init(), do this:
 
     $Log::Log4perl::JavaMap::user_defined{'myorg.customAppender'} = 
         'Myorg::CustomAppender';
 
 and you can use 'myorg.customAppender' in your config file with
 impunity.
 
 =head1 SEE ALSO
 
 http://jakarta.apache.org/log4j/docs/
 
 =head1 LICENSE
 
 Copyright 2002-2013 by Mike Schilli E<lt>m@perlmeister.comE<gt> 
 and Kevin Goess E<lt>cpan@goess.orgE<gt>.
 
 This library is free software; you can redistribute it and/or modify
 it under the same terms as Perl itself. 
 
 =head1 AUTHOR
 
 Please contribute patches to the project on Github:
 
     http://github.com/mschilli/log4perl
 
 Send bug reports or requests for enhancements to the authors via our
 
 MAILING LIST (questions, bug reports, suggestions/patches): 
 log4perl-devel@lists.sourceforge.net
 
 Authors (please contact them via the list above, not directly):
 Mike Schilli <m@perlmeister.com>,
 Kevin Goess <cpan@goess.org>
 
 Contributors (in alphabetical order):
 Ateeq Altaf, Cory Bennett, Jens Berthold, Jeremy Bopp, Hutton
 Davidson, Chris R. Donnelly, Matisse Enzer, Hugh Esco, Anthony
 Foiani, James FitzGibbon, Carl Franks, Dennis Gregorovic, Andy
 Grundman, Paul Harrington, Alexander Hartmaier  David Hull, 
 Robert Jacobson, Jason Kohles, Jeff Macdonald, Markus Peter, 
 Brett Rann, Peter Rabbitson, Erik Selberg, Aaron Straup Cope, 
 Lars Thegler, David Viner, Mac Yang.
 
### Log/Log4perl/JavaMap/ConsoleAppender.pm ###
 package Log::Log4perl::JavaMap::ConsoleAppender;
 
 use Carp;
 use strict;
 use Log::Dispatch::Screen;
 
 
 sub new {
     my ($class, $appender_name, $data) = @_;
     my $stderr;
 
     if (my $t = $data->{Target}{value}) {
         if ($t eq 'System.out') {
             $stderr = 0;
         }elsif ($t eq 'System.err') {
             $stderr = 1;
         }else{
             die "ERROR: illegal value '$t' for $data->{value}.Target' in appender $appender_name\n";
         }
     }elsif (defined $data->{stderr}{value}){
         $stderr = $data->{stderr}{value};
     }else{
         $stderr = 0;
     }
 
     return Log::Log4perl::Appender->new("Log::Dispatch::Screen",
         name   => $appender_name,
         stderr => $stderr );
 }
 
 
 1;
 
 
 =encoding utf8
 
 =head1 NAME
 
 Log::Log4perl::JavaMap::ConsoleAppender - wraps Log::Dispatch::Screen
 
 =head1 SYNOPSIS
 
 
 =head1 DESCRIPTION
 
 Possible config properties for log4j ConsoleAppender are 
 
     Target (System.out, System.err, default is System.out)
 
 Possible config properties for Log::Dispatch::Screen are
 
     stderr (0 or 1)
 
 =head1 SEE ALSO
 
 http://jakarta.apache.org/log4j/docs/
 
 Log::Log4perl::Javamap
 
 Log::Dispatch::Screen
 
 =cut 
 
 =head1 LICENSE
 
 Copyright 2002-2013 by Mike Schilli E<lt>m@perlmeister.comE<gt> 
 and Kevin Goess E<lt>cpan@goess.orgE<gt>.
 
 This library is free software; you can redistribute it and/or modify
 it under the same terms as Perl itself. 
 
 =head1 AUTHOR
 
 Please contribute patches to the project on Github:
 
     http://github.com/mschilli/log4perl
 
 Send bug reports or requests for enhancements to the authors via our
 
 MAILING LIST (questions, bug reports, suggestions/patches): 
 log4perl-devel@lists.sourceforge.net
 
 Authors (please contact them via the list above, not directly):
 Mike Schilli <m@perlmeister.com>,
 Kevin Goess <cpan@goess.org>
 
 Contributors (in alphabetical order):
 Ateeq Altaf, Cory Bennett, Jens Berthold, Jeremy Bopp, Hutton
 Davidson, Chris R. Donnelly, Matisse Enzer, Hugh Esco, Anthony
 Foiani, James FitzGibbon, Carl Franks, Dennis Gregorovic, Andy
 Grundman, Paul Harrington, Alexander Hartmaier  David Hull, 
 Robert Jacobson, Jason Kohles, Jeff Macdonald, Markus Peter, 
 Brett Rann, Peter Rabbitson, Erik Selberg, Aaron Straup Cope, 
 Lars Thegler, David Viner, Mac Yang.
 
### Log/Log4perl/JavaMap/FileAppender.pm ###
 package Log::Log4perl::JavaMap::FileAppender;
 
 use Carp;
 use strict;
 use Log::Dispatch::File;
 
 
 sub new {
     my ($class, $appender_name, $data) = @_;
     my $stderr;
 
     my $filename =  $data->{File}{value} || 
                 $data->{filename}{value} || 
                 die "'File' not supplied for appender '$appender_name', required for a '$data->{value}'\n";
 
     my $mode;
     if (defined($data->{Append}{value})){
         if (lc $data->{Append}{value} eq 'true' || $data->{Append}{value} == 1){
             $mode = 'append';
         }elsif (lc $data->{Append}{value} eq 'false' || $data->{Append}{value} == 0) {
             $mode = 'write';
         }elsif($data->{Append} =~ /^(write|append)$/){
             $mode = $data->{Append}
         }else{
             die "'$data->{Append}' is not a legal value for Append for appender '$appender_name', '$data->{value}'\n";
         }
     }else{
         $mode = 'append';
     }
 
     my $autoflush;
     if (defined($data->{BufferedIO}{value})){
         if (lc $data->{BufferedIO}{value} eq 'true' || $data->{BufferedIO}{value}){
             $autoflush = 1;
         }elsif (lc $data->{BufferedIO}{value} eq 'true' || ! $data->{BufferedIO}{value}) {
             $autoflush = 0;
         }else{
             die "'$data->{BufferedIO}' is not a legal value for BufferedIO for appender '$appender_name', '$data->{value}'\n";
         }
     }else{
         $autoflush = 1;
     }
 
 
     return Log::Log4perl::Appender->new("Log::Dispatch::File",
         name      => $appender_name,
         filename  => $filename,
         mode      => $mode,
         autoflush => $autoflush,
     );
 }
 
 1;
 
 =encoding utf8
 
 =head1 NAME
 
 Log::Log4perl::JavaMap::FileAppender - wraps Log::Dispatch::File
 
 =head1 SYNOPSIS
 
 
 =head1 DESCRIPTION
 
 Possible config properties for log4j ConsoleAppender are 
 
     File
     Append      "true|false|1|0" default=true
     BufferedIO  "true|false|1|0" default=false (i.e. autoflush is on)
 
 Possible config properties for Log::Dispatch::File are
 
     filename
     mode  "write|append"
     autoflush 0|1
 
 =head1 SEE ALSO
 
 http://jakarta.apache.org/log4j/docs/
 
 Log::Log4perl::Javamap
 
 Log::Dispatch::File
 
 =head1 LICENSE
 
 Copyright 2002-2013 by Mike Schilli E<lt>m@perlmeister.comE<gt> 
 and Kevin Goess E<lt>cpan@goess.orgE<gt>.
 
 This library is free software; you can redistribute it and/or modify
 it under the same terms as Perl itself. 
 
 =head1 AUTHOR
 
 Please contribute patches to the project on Github:
 
     http://github.com/mschilli/log4perl
 
 Send bug reports or requests for enhancements to the authors via our
 
 MAILING LIST (questions, bug reports, suggestions/patches): 
 log4perl-devel@lists.sourceforge.net
 
 Authors (please contact them via the list above, not directly):
 Mike Schilli <m@perlmeister.com>,
 Kevin Goess <cpan@goess.org>
 
 Contributors (in alphabetical order):
 Ateeq Altaf, Cory Bennett, Jens Berthold, Jeremy Bopp, Hutton
 Davidson, Chris R. Donnelly, Matisse Enzer, Hugh Esco, Anthony
 Foiani, James FitzGibbon, Carl Franks, Dennis Gregorovic, Andy
 Grundman, Paul Harrington, Alexander Hartmaier  David Hull, 
 Robert Jacobson, Jason Kohles, Jeff Macdonald, Markus Peter, 
 Brett Rann, Peter Rabbitson, Erik Selberg, Aaron Straup Cope, 
 Lars Thegler, David Viner, Mac Yang.
 
### Log/Log4perl/JavaMap/JDBCAppender.pm ###
 package Log::Log4perl::JavaMap::JDBCAppender;
 
 use Carp;
 use strict;
 
 sub new {
     my ($class, $appender_name, $data) = @_;
     my $stderr;
 
     my $pwd =  $data->{password}{value} || 
                 die "'password' not supplied for appender '$appender_name', required for a '$data->{value}'\n";
 
     my $username =  $data->{user}{value} || 
                 $data->{username}{value} || 
                 die "'user' not supplied for appender '$appender_name', required for a '$data->{value}'\n";
 
 
     my $sql =  $data->{sql}{value} || 
                 die "'sql' not supplied for appender '$appender_name', required for a '$data->{value}'\n";
 
 
     my $dsn;
 
     my $databaseURL = $data->{URL}{value};
     if ($databaseURL) {
         $databaseURL =~ m|^jdbc:(.+?):(.+?)://(.+?):(.+?);(.+)|;
         my $driverName = $1;
         my $databaseName = $2;
         my $hostname = $3;
         my $port = $4;
         my $params = $5;
         $dsn = "dbi:$driverName:database=$databaseName;host=$hostname;port=$port;$params";
     }elsif ($data->{datasource}{value}){
         $dsn = $data->{datasource}{value};
     }else{
         die "'databaseURL' not supplied for appender '$appender_name', required for a '$data->{value}'\n";
     }
 
 
     #this part isn't supported by log4j, it's my Log4perl
     #hack, but I think it's so useful I'm going to implement it
     #anyway
     my %bind_value_params;
     foreach my $p (keys %{$data->{params}}){
         $bind_value_params{$p} =  $data->{params}{$p}{value};
     }
 
     return Log::Log4perl::Appender->new("Log::Log4perl::Appender::DBI",
         datasource    => $dsn,
         username      => $username,
         password      => $pwd, 
         sql           => $sql,
         params        => \%bind_value_params,
             #warp_message also not a log4j thing, but see above
         warp_message=> $data->{warp_message}{value},  
     );
 }
 
 1;
 
 =encoding utf8
 
 =head1 NAME
 
 Log::Log4perl::JavaMap::JDBCAppender - wraps Log::Log4perl::Appender::DBI
 
 =head1 SYNOPSIS
 
 
 =head1 DESCRIPTION
 
 Possible config properties for log4j JDBCAppender are 
 
     bufferSize 
     sql
     password
     user
     URL - attempting to translate a JDBC URL into DBI parameters,
         let me know if you find problems
 
 Possible config properties for Log::Log4perl::Appender::DBI are
 
     bufferSize 
     sql
     password
     username
     datasource
     
     usePreparedStmt 0|1
     
     (patternLayout).dontCollapseArrayRefs 0|1
     
     
 =head1 SEE ALSO
 
 http://jakarta.apache.org/log4j/docs/
 
 Log::Log4perl::Javamap
 
 Log::Log4perl::Appender::DBI
 
 =head1 LICENSE
 
 Copyright 2002-2013 by Mike Schilli E<lt>m@perlmeister.comE<gt> 
 and Kevin Goess E<lt>cpan@goess.orgE<gt>.
 
 This library is free software; you can redistribute it and/or modify
 it under the same terms as Perl itself. 
 
 =head1 AUTHOR
 
 Please contribute patches to the project on Github:
 
     http://github.com/mschilli/log4perl
 
 Send bug reports or requests for enhancements to the authors via our
 
 MAILING LIST (questions, bug reports, suggestions/patches): 
 log4perl-devel@lists.sourceforge.net
 
 Authors (please contact them via the list above, not directly):
 Mike Schilli <m@perlmeister.com>,
 Kevin Goess <cpan@goess.org>
 
 Contributors (in alphabetical order):
 Ateeq Altaf, Cory Bennett, Jens Berthold, Jeremy Bopp, Hutton
 Davidson, Chris R. Donnelly, Matisse Enzer, Hugh Esco, Anthony
 Foiani, James FitzGibbon, Carl Franks, Dennis Gregorovic, Andy
 Grundman, Paul Harrington, Alexander Hartmaier  David Hull, 
 Robert Jacobson, Jason Kohles, Jeff Macdonald, Markus Peter, 
 Brett Rann, Peter Rabbitson, Erik Selberg, Aaron Straup Cope, 
 Lars Thegler, David Viner, Mac Yang.
 
### Log/Log4perl/JavaMap/NTEventLogAppender.pm ###
 package Log::Log4perl::JavaMap::NTEventLogAppender;
 
 use Carp;
 use strict;
 
 
 
 sub new {
     my ($class, $appender_name, $data) = @_;
     my $stderr;
 
     my ($source,   #        
         );
 
     if (defined $data->{Source}{value}) {
         $source = $data->{Source}{value}
     }elsif (defined $data->{source}{value}){
         $source = $data->{source}{value};
     }else{
         $source = 'user';
     }
 
     
     return Log::Log4perl::Appender->new("Log::Dispatch::Win32EventLog",
         name      => $appender_name,
         source    => $source,
         min_level => 'debug',
     );
 }
 
 1;
 
 =encoding utf8
 
 =head1 NAME
 
 Log::Log4perl::JavaMap::NTEventLogAppender - wraps Log::Dispatch::Win32EventLog
 
 
 =head1 DESCRIPTION
 
 This maps log4j's NTEventLogAppender to Log::Dispatch::Win32EventLog
 
 Possible config properties for log4j NTEventLogAppender are 
 
     Source
 
 Possible config properties for Log::Dispatch::Win32EventLog are
 
     source
 
 Boy, that was hard.
 
 =head1 SEE ALSO
 
 http://jakarta.apache.org/log4j/docs/
 
 Log::Log4perl::Javamap
 
 =head1 LICENSE
 
 Copyright 2002-2013 by Mike Schilli E<lt>m@perlmeister.comE<gt> 
 and Kevin Goess E<lt>cpan@goess.orgE<gt>.
 
 This library is free software; you can redistribute it and/or modify
 it under the same terms as Perl itself. 
 
 =head1 AUTHOR
 
 Please contribute patches to the project on Github:
 
     http://github.com/mschilli/log4perl
 
 Send bug reports or requests for enhancements to the authors via our
 
 MAILING LIST (questions, bug reports, suggestions/patches): 
 log4perl-devel@lists.sourceforge.net
 
 Authors (please contact them via the list above, not directly):
 Mike Schilli <m@perlmeister.com>,
 Kevin Goess <cpan@goess.org>
 
 Contributors (in alphabetical order):
 Ateeq Altaf, Cory Bennett, Jens Berthold, Jeremy Bopp, Hutton
 Davidson, Chris R. Donnelly, Matisse Enzer, Hugh Esco, Anthony
 Foiani, James FitzGibbon, Carl Franks, Dennis Gregorovic, Andy
 Grundman, Paul Harrington, Alexander Hartmaier  David Hull, 
 Robert Jacobson, Jason Kohles, Jeff Macdonald, Markus Peter, 
 Brett Rann, Peter Rabbitson, Erik Selberg, Aaron Straup Cope, 
 Lars Thegler, David Viner, Mac Yang.
 
### Log/Log4perl/JavaMap/RollingFileAppender.pm ###
 package Log::Log4perl::JavaMap::RollingFileAppender;
 
 use Carp;
 use strict;
 use Log::Dispatch::FileRotate 1.10;
 
 
 sub new {
     my ($class, $appender_name, $data) = @_;
     my $stderr;
 
     my $filename =  $data->{File}{value} || 
                 $data->{filename}{value} || 
                 die "'File' not supplied for appender '$appender_name', required for a '$data->{value}'\n";
 
     my $mode;
     if (defined($data->{Append}{value})){
         if (lc $data->{Append}{value} eq 'true' || $data->{Append}{value} == 1){
             $mode = 'append';
         }elsif (lc $data->{Append}{value} eq 'false' || $data->{Append}{value} == 0) {
             $mode = 'write';
         }elsif($data->{Append} =~ /^(write|append)$/){
             $mode = $data->{Append}
         }else{
             die "'$data->{Append}' is not a legal value for Append for appender '$appender_name', '$data->{value}'\n";
         }
     }else{
         $mode = 'append';
     }
 
     my $autoflush;
     if (defined($data->{BufferedIO}{value})){
         if (lc $data->{BufferedIO}{value} eq 'true' || $data->{BufferedIO}{value}){
             $autoflush = 1;
         }elsif (lc $data->{BufferedIO}{value} eq 'true' || ! $data->{BufferedIO}{value}) {
             $autoflush = 0;
         }else{
             die "'$data->{BufferedIO}' is not a legal value for BufferedIO for appender '$appender_name', '$data->{value}'\n";
         }
     }else{
         $autoflush = 1;
     }
 
     my $max;
     if (defined $data->{MaxBackupIndex}{value}) {
         $max = $data->{MaxBackupIndex}{value};
     }elsif (defined $data->{max}{value}){
         $max = $data->{max}{value};
     }else{
         $max = 1;
 
     }
 
     my $size;
     if (defined $data->{MaxFileSize}{value}) {
         $size = $data->{MaxFileSize}{value}
     }elsif (defined $data->{size}{value}){
         $size = $data->{size}{value};
     }else{
         $size = 10_000_000;
     }
 
 
     return Log::Log4perl::Appender->new("Log::Dispatch::FileRotate",
         name      => $appender_name,
         filename  => $filename,
         mode      => $mode,
         autoflush => $autoflush,
         size      => $size,
         max       => $max,
     );
 }
 
 1;
 
 =encoding utf8
 
 =head1 NAME
 
 Log::Log4perl::JavaMap::RollingFileAppender - wraps Log::Dispatch::FileRotate
 
 =head1 SYNOPSIS
 
 
 =head1 DESCRIPTION
 
 This maps log4j's RollingFileAppender to Log::Dispatch::FileRotate 
 by Mark Pfeiffer, <markpf@mlp-consulting.com.au>.
 
 Possible config properties for log4j ConsoleAppender are 
 
     File
     Append      "true|false|1|0" default=true
     BufferedIO  "true|false|1|0" default=false (i.e. autoflush is on)
     MaxFileSize default 10_000_000
     MaxBackupIndex default is 1
 
 Possible config properties for Log::Dispatch::FileRotate are
 
     filename
     mode  "write|append"
     autoflush 0|1
     size
     max
 
 =head1 SEE ALSO
 
 http://jakarta.apache.org/log4j/docs/
 
 Log::Log4perl::Javamap
 
 =head1 LICENSE
 
 Copyright 2002-2013 by Mike Schilli E<lt>m@perlmeister.comE<gt> 
 and Kevin Goess E<lt>cpan@goess.orgE<gt>.
 
 This library is free software; you can redistribute it and/or modify
 it under the same terms as Perl itself. 
 
 =head1 AUTHOR
 
 Please contribute patches to the project on Github:
 
     http://github.com/mschilli/log4perl
 
 Send bug reports or requests for enhancements to the authors via our
 
 MAILING LIST (questions, bug reports, suggestions/patches): 
 log4perl-devel@lists.sourceforge.net
 
 Authors (please contact them via the list above, not directly):
 Mike Schilli <m@perlmeister.com>,
 Kevin Goess <cpan@goess.org>
 
 Contributors (in alphabetical order):
 Ateeq Altaf, Cory Bennett, Jens Berthold, Jeremy Bopp, Hutton
 Davidson, Chris R. Donnelly, Matisse Enzer, Hugh Esco, Anthony
 Foiani, James FitzGibbon, Carl Franks, Dennis Gregorovic, Andy
 Grundman, Paul Harrington, Alexander Hartmaier  David Hull, 
 Robert Jacobson, Jason Kohles, Jeff Macdonald, Markus Peter, 
 Brett Rann, Peter Rabbitson, Erik Selberg, Aaron Straup Cope, 
 Lars Thegler, David Viner, Mac Yang.
 
### Log/Log4perl/JavaMap/SyslogAppender.pm ###
 package Log::Log4perl::JavaMap::SyslogAppender;
 
 use Carp;
 use strict;
 use Log::Dispatch::Syslog;
 
 
 sub new {
     my ($class, $appender_name, $data) = @_;
     my $stderr;
 
     my ($ident,    #defaults to $0
         $logopt,   #Valid options are 'cons', 'pid', 'ndelay', and 'nowait'.
         $facility, #Valid options are 'auth', 'authpriv',
                    #  'cron', 'daemon', 'kern', 'local0' through 'local7',
                    #   'mail, 'news', 'syslog', 'user', 'uucp'.  Defaults to
                    #   'user'
         $socket,   #Valid options are 'unix' or 'inet'. Defaults to 'inet'
         );
 
     if (defined $data->{Facility}{value}) {
         $facility = $data->{Facility}{value}
     }elsif (defined $data->{facility}{value}){
         $facility = $data->{facility}{value};
     }else{
         $facility = 'user';
     }
 
     if (defined $data->{Ident}{value}) {
         $ident = $data->{Ident}{value}
     }elsif (defined $data->{ident}{value}){
         $ident = $data->{ident}{value};
     }else{
         $ident = $0;
     }
     
     return Log::Log4perl::Appender->new("Log::Dispatch::Syslog",
         name      => $appender_name,
         facility  => $facility,
         ident     => $ident,
         min_level => 'debug',
     );
 }
 
 1;
 
 =encoding utf8
 
 =head1 NAME
 
 Log::Log4perl::JavaMap::SysLogAppender - wraps Log::Dispatch::Syslog
 
 
 =head1 DESCRIPTION
 
 This maps log4j's SyslogAppender to Log::Dispatch::Syslog
 
 Possible config properties for log4j SyslogAppender are 
 
     SyslogHost (Log::Dispatch::Syslog only accepts 'localhost')
     Facility
 
 Possible config properties for Log::Dispatch::Syslog are
 
     min_level (debug)
     max_level
     ident    (defaults to $0)
     logopt
     facility 
     socket   (defaults to 'inet')
 
 =head1 SEE ALSO
 
 http://jakarta.apache.org/log4j/docs/
 
 Log::Log4perl::Javamap
 
 =head1 LICENSE
 
 Copyright 2002-2013 by Mike Schilli E<lt>m@perlmeister.comE<gt> 
 and Kevin Goess E<lt>cpan@goess.orgE<gt>.
 
 This library is free software; you can redistribute it and/or modify
 it under the same terms as Perl itself. 
 
 =head1 AUTHOR
 
 Please contribute patches to the project on Github:
 
     http://github.com/mschilli/log4perl
 
 Send bug reports or requests for enhancements to the authors via our
 
 MAILING LIST (questions, bug reports, suggestions/patches): 
 log4perl-devel@lists.sourceforge.net
 
 Authors (please contact them via the list above, not directly):
 Mike Schilli <m@perlmeister.com>,
 Kevin Goess <cpan@goess.org>
 
 Contributors (in alphabetical order):
 Ateeq Altaf, Cory Bennett, Jens Berthold, Jeremy Bopp, Hutton
 Davidson, Chris R. Donnelly, Matisse Enzer, Hugh Esco, Anthony
 Foiani, James FitzGibbon, Carl Franks, Dennis Gregorovic, Andy
 Grundman, Paul Harrington, Alexander Hartmaier  David Hull, 
 Robert Jacobson, Jason Kohles, Jeff Macdonald, Markus Peter, 
 Brett Rann, Peter Rabbitson, Erik Selberg, Aaron Straup Cope, 
 Lars Thegler, David Viner, Mac Yang.
 
### Log/Log4perl/JavaMap/TestBuffer.pm ###
 package Log::Log4perl::JavaMap::TestBuffer;
 
 use Carp;
 use strict;
 use Log::Log4perl::Appender::TestBuffer;
 
 use constant _INTERNAL_DEBUG => 0;
 
 sub new {
     my ($class, $appender_name, $data) = @_;
     my $stderr;
 
     return Log::Log4perl::Appender->new("Log::Log4perl::Appender::TestBuffer",
                                         name => $appender_name);
 }
 
 1;
 
 =encoding utf8
 
 =head1 NAME
 
 Log::Log4perl::JavaMap::TestBuffer - wraps Log::Log4perl::Appender::TestBuffer
 
 =head1 SYNOPSIS
 
 =head1 DESCRIPTION
 
 Just for testing the Java mapping.
 
 =head1 SEE ALSO
 
 http://jakarta.apache.org/log4j/docs/
 
 Log::Log4perl::Javamap
 
 Log::Dispatch::Screen
 
 =head1 LICENSE
 
 Copyright 2002-2013 by Mike Schilli E<lt>m@perlmeister.comE<gt> 
 and Kevin Goess E<lt>cpan@goess.orgE<gt>.
 
 This library is free software; you can redistribute it and/or modify
 it under the same terms as Perl itself. 
 
 =head1 AUTHOR
 
 Please contribute patches to the project on Github:
 
     http://github.com/mschilli/log4perl
 
 Send bug reports or requests for enhancements to the authors via our
 
 MAILING LIST (questions, bug reports, suggestions/patches): 
 log4perl-devel@lists.sourceforge.net
 
 Authors (please contact them via the list above, not directly):
 Mike Schilli <m@perlmeister.com>,
 Kevin Goess <cpan@goess.org>
 
 Contributors (in alphabetical order):
 Ateeq Altaf, Cory Bennett, Jens Berthold, Jeremy Bopp, Hutton
 Davidson, Chris R. Donnelly, Matisse Enzer, Hugh Esco, Anthony
 Foiani, James FitzGibbon, Carl Franks, Dennis Gregorovic, Andy
 Grundman, Paul Harrington, Alexander Hartmaier  David Hull, 
 Robert Jacobson, Jason Kohles, Jeff Macdonald, Markus Peter, 
 Brett Rann, Peter Rabbitson, Erik Selberg, Aaron Straup Cope, 
 Lars Thegler, David Viner, Mac Yang.
 
### Log/Log4perl/Layout.pm ###
 package Log::Log4perl::Layout;
 
 
 use Log::Log4perl::Layout::SimpleLayout;
 use Log::Log4perl::Layout::PatternLayout;
 use Log::Log4perl::Layout::PatternLayout::Multiline;
 
 
 ####################################################
 sub appender_name {
 ####################################################
     my ($self, $arg) = @_;
 
     if ($arg) {
         die "setting appender_name unimplemented until it makes sense";
     }
     return $self->{appender_name};
 }
 
 
 ##################################################
 sub define {
 ##################################################
     ;  #subclasses may implement
 }
 
 
 ##################################################
 sub render {
 ##################################################
     die "subclass must implement render";
 }
 
 1;
 
 __END__
 
 =encoding utf8
 
 =head1 NAME
 
 Log::Log4perl::Layout - Log4perl Layout Virtual Base Class
 
 =head1 SYNOPSIS
 
     # Not to be used directly, see below
 
 =head1 DESCRIPTION
 
 C<Log::Log4perl::Layout> is a virtual base class for the two currently 
 implemented layout types
 
     Log::Log4perl::Layout::SimpleLayout
     Log::Log4perl::Layout::PatternLayout
 
 Unless you're implementing a new layout class for Log4perl, you shouldn't
 use this class directly, but rather refer to
 L<Log::Log4perl::Layout::SimpleLayout> or 
 L<Log::Log4perl::Layout::PatternLayout>.
 
 =head1 LICENSE
 
 Copyright 2002-2013 by Mike Schilli E<lt>m@perlmeister.comE<gt> 
 and Kevin Goess E<lt>cpan@goess.orgE<gt>.
 
 This library is free software; you can redistribute it and/or modify
 it under the same terms as Perl itself. 
 
 =head1 AUTHOR
 
 Please contribute patches to the project on Github:
 
     http://github.com/mschilli/log4perl
 
 Send bug reports or requests for enhancements to the authors via our
 
 MAILING LIST (questions, bug reports, suggestions/patches): 
 log4perl-devel@lists.sourceforge.net
 
 Authors (please contact them via the list above, not directly):
 Mike Schilli <m@perlmeister.com>,
 Kevin Goess <cpan@goess.org>
 
 Contributors (in alphabetical order):
 Ateeq Altaf, Cory Bennett, Jens Berthold, Jeremy Bopp, Hutton
 Davidson, Chris R. Donnelly, Matisse Enzer, Hugh Esco, Anthony
 Foiani, James FitzGibbon, Carl Franks, Dennis Gregorovic, Andy
 Grundman, Paul Harrington, Alexander Hartmaier  David Hull, 
 Robert Jacobson, Jason Kohles, Jeff Macdonald, Markus Peter, 
 Brett Rann, Peter Rabbitson, Erik Selberg, Aaron Straup Cope, 
 Lars Thegler, David Viner, Mac Yang.
 
### Log/Log4perl/Layout/NoopLayout.pm ###
 ##################################################
 package Log::Log4perl::Layout::NoopLayout;
 ##################################################
 
 
 ##################################################
 sub new {
 ##################################################
     my $class = shift;
     $class = ref ($class) || $class;
 
     my $self = {
         format      => undef,
         info_needed => {},
         stack       => [],
     };
 
     bless $self, $class;
 
     return $self;
 }
 
 ##################################################
 sub render {
 ##################################################
     #my($self, $message, $category, $priority, $caller_level) = @_;
     return $_[1];;
 }
 
 1;
 
 __END__
 
 =encoding utf8
 
 =head1 NAME
 
 Log::Log4perl::Layout::NoopLayout - Pass-thru Layout
 
 =head1 SYNOPSIS
 
   use Log::Log4perl::Layout::NoopLayout;
   my $layout = Log::Log4perl::Layout::NoopLayout->new();
 
 =head1 DESCRIPTION
 
 This is a no-op layout, returns the logging message unaltered,
 useful for implementing the DBI logger.
 
 =head1 LICENSE
 
 Copyright 2002-2013 by Mike Schilli E<lt>m@perlmeister.comE<gt> 
 and Kevin Goess E<lt>cpan@goess.orgE<gt>.
 
 This library is free software; you can redistribute it and/or modify
 it under the same terms as Perl itself. 
 
 =head1 AUTHOR
 
 Please contribute patches to the project on Github:
 
     http://github.com/mschilli/log4perl
 
 Send bug reports or requests for enhancements to the authors via our
 
 MAILING LIST (questions, bug reports, suggestions/patches): 
 log4perl-devel@lists.sourceforge.net
 
 Authors (please contact them via the list above, not directly):
 Mike Schilli <m@perlmeister.com>,
 Kevin Goess <cpan@goess.org>
 
 Contributors (in alphabetical order):
 Ateeq Altaf, Cory Bennett, Jens Berthold, Jeremy Bopp, Hutton
 Davidson, Chris R. Donnelly, Matisse Enzer, Hugh Esco, Anthony
 Foiani, James FitzGibbon, Carl Franks, Dennis Gregorovic, Andy
 Grundman, Paul Harrington, Alexander Hartmaier  David Hull, 
 Robert Jacobson, Jason Kohles, Jeff Macdonald, Markus Peter, 
 Brett Rann, Peter Rabbitson, Erik Selberg, Aaron Straup Cope, 
 Lars Thegler, David Viner, Mac Yang.
 
### Log/Log4perl/Layout/PatternLayout.pm ###
 ##################################################
 package Log::Log4perl::Layout::PatternLayout;
 ##################################################
 
 use 5.006;
 use strict;
 use warnings;
 
 use constant _INTERNAL_DEBUG => 0;
 
 use Carp;
 use Log::Log4perl::Util;
 use Log::Log4perl::Level;
 use Log::Log4perl::DateFormat;
 use Log::Log4perl::NDC;
 use Log::Log4perl::MDC;
 use Log::Log4perl::Util::TimeTracker;
 use File::Spec;
 use File::Basename;
 
 our $TIME_HIRES_AVAILABLE_WARNED = 0;
 our $HOSTNAME;
 our %GLOBAL_USER_DEFINED_CSPECS = ();
 
 our $CSPECS = 'cCdFHIlLmMnpPrRtTxX%';
 
 BEGIN {
     # Check if we've got Sys::Hostname. If not, just punt.
     $HOSTNAME = "unknown.host";
     if(Log::Log4perl::Util::module_available("Sys::Hostname")) {
         require Sys::Hostname;
         $HOSTNAME = Sys::Hostname::hostname();
     }
 }
 
 use base qw(Log::Log4perl::Layout);
 
 no strict qw(refs);
 
 ##################################################
 sub new {
 ##################################################
     my $class = shift;
     $class = ref ($class) || $class;
 
     my $options       = ref $_[0] eq "HASH" ? shift : {};
     my $layout_string = @_ ? shift : '%m%n';
     
     my $self = {
         format                => undef,
         info_needed           => {},
         stack                 => [],
         CSPECS                => $CSPECS,
         dontCollapseArrayRefs => $options->{dontCollapseArrayRefs}{value},
         last_time             => undef,
         undef_column_value    => 
             (exists $options->{ undef_column_value } 
                 ? $options->{ undef_column_value } 
                 : "[undef]"),
     };
 
     $self->{timer} = Log::Log4perl::Util::TimeTracker->new(
         time_function => $options->{time_function}
     );
 
     if(exists $options->{ConversionPattern}->{value}) {
         $layout_string = $options->{ConversionPattern}->{value};
     }
 
     if(exists $options->{message_chomp_before_newline}) {
         $self->{message_chomp_before_newline} = 
           $options->{message_chomp_before_newline}->{value};
     } else {
         $self->{message_chomp_before_newline} = 1;
     }
 
     bless $self, $class;
 
     #add the global user-defined cspecs
     foreach my $f (keys %GLOBAL_USER_DEFINED_CSPECS){
             #add it to the list of letters
         $self->{CSPECS} .= $f;
              #for globals, the coderef is already evaled, 
         $self->{USER_DEFINED_CSPECS}{$f} = $GLOBAL_USER_DEFINED_CSPECS{$f};
     }
 
     #add the user-defined cspecs local to this appender
     foreach my $f (keys %{$options->{cspec}}){
         $self->add_layout_cspec($f, $options->{cspec}{$f}{value});
     }
 
     # non-portable line breaks
     $layout_string =~ s/\\n/\n/g;
     $layout_string =~ s/\\r/\r/g;
 
     $self->define($layout_string);
 
     return $self;
 }
 
 ##################################################
 sub define {
 ##################################################
     my($self, $format) = @_;
 
         # If the message contains a %m followed by a newline,
         # make a note of that so that we can cut a superfluous 
         # \n off the message later on
     if($self->{message_chomp_before_newline} and $format =~ /%m%n/) {
         $self->{message_chompable} = 1;
     } else {
         $self->{message_chompable} = 0;
     }
 
     # Parse the format
     $format =~ s/%(-?\d*(?:\.\d+)?) 
                        ([$self->{CSPECS}])
                        (?:{(.*?)})*/
                        rep($self, $1, $2, $3);
                       /gex;
 
     $self->{printformat} = $format;
 }
 
 ##################################################
 sub rep {
 ##################################################
     my($self, $num, $op, $curlies) = @_;
 
     return "%%" if $op eq "%";
 
     # If it's a %d{...} construct, initialize a simple date
     # format formatter, so that we can quickly render later on.
     # If it's just %d, assume %d{yyyy/MM/dd HH:mm:ss}
     if($op eq "d") {
         if(defined $curlies) {
             $curlies = Log::Log4perl::DateFormat->new($curlies);
         } else {
             $curlies = Log::Log4perl::DateFormat->new("yyyy/MM/dd HH:mm:ss");
         }
     } elsif($op eq "m") {
         $curlies = $self->curlies_csv_parse($curlies);
     }
 
     push @{$self->{stack}}, [$op, $curlies];
 
     $self->{info_needed}->{$op}++;
 
     return "%${num}s";
 }
 
 ###########################################
 sub curlies_csv_parse {
 ###########################################
     my($self, $curlies) = @_;
 
     my $data = {};
 
     if(defined $curlies and length $curlies) {
         $curlies =~ s/\s//g;
 
         for my $field (split /,/, $curlies) {
             my($key, $value) = split /=/, $field;
             $data->{$key} = $value;
         }
     }
 
     return $data;
 }
 
 ##################################################
 sub render {
 ##################################################
     my($self, $message, $category, $priority, $caller_level) = @_;
 
     $caller_level = 0 unless defined  $caller_level;
 
     my %info    = ();
 
     $info{m}    = $message;
         # See 'define'
     chomp $info{m} if $self->{message_chompable};
 
     my @results = ();
 
     my $caller_offset = Log::Log4perl::caller_depth_offset( $caller_level );
 
     if($self->{info_needed}->{L} or
        $self->{info_needed}->{F} or
        $self->{info_needed}->{C} or
        $self->{info_needed}->{l} or
        $self->{info_needed}->{M} or
        $self->{info_needed}->{T} or
        0
       ) {
 
         my ($package, $filename, $line, 
             $subroutine, $hasargs,
             $wantarray, $evaltext, $is_require, 
             $hints, $bitmask) = caller($caller_offset);
 
         # If caller() choked because of a whacko caller level,
         # correct undefined values to '[undef]' in order to prevent 
         # warning messages when interpolating later
         unless(defined $bitmask) {
             for($package, 
                 $filename, $line,
                 $subroutine, $hasargs,
                 $wantarray, $evaltext, $is_require,
                 $hints, $bitmask) {
                 $_ = '[undef]' unless defined $_;
             }
         }
 
         $info{L} = $line;
         $info{F} = $filename;
         $info{C} = $package;
 
         if($self->{info_needed}->{M} or
            $self->{info_needed}->{l} or
            0) {
             # To obtain the name of the subroutine which triggered the 
             # logger, we need to go one additional level up.
             my $levels_up = 1; 
             {
                 my @callinfo = caller($caller_offset+$levels_up);
 
                 if(_INTERNAL_DEBUG) {
                     callinfo_dump( $caller_offset, \@callinfo );
                 }
 
                 $subroutine = $callinfo[3];
                     # If we're inside an eval, go up one level further.
                 if(defined $subroutine and
                    $subroutine eq "(eval)") {
                     print "Inside an eval, one up\n" if _INTERNAL_DEBUG;
                     $levels_up++;
                     redo;
                 }
             }
             $subroutine = "main::" unless $subroutine;
             print "Subroutine is '$subroutine'\n" if _INTERNAL_DEBUG;
             $info{M} = $subroutine;
             $info{l} = "$subroutine $filename ($line)";
         }
     }
 
     $info{X} = "[No curlies defined]";
     $info{x} = Log::Log4perl::NDC->get() if $self->{info_needed}->{x};
     $info{c} = $category;
     $info{d} = 1; # Dummy value, corrected later
     $info{n} = "\n";
     $info{p} = $priority;
     $info{P} = $$;
     $info{H} = $HOSTNAME;
 
     my $current_time;
 
     if($self->{info_needed}->{r} or $self->{info_needed}->{R}) {
         if(!$TIME_HIRES_AVAILABLE_WARNED++ and 
            !$self->{timer}->hires_available()) {
             warn "Requested %r/%R pattern without installed Time::HiRes\n";
         }
         $current_time = [$self->{timer}->gettimeofday()];
     }
 
     if($self->{info_needed}->{r}) {
         $info{r} = $self->{timer}->milliseconds( $current_time );
     }
     if($self->{info_needed}->{R}) {
         $info{R} = $self->{timer}->delta_milliseconds( $current_time );
     }
 
         # Stack trace wanted?
     if($self->{info_needed}->{T}) {
         local $Carp::CarpLevel =
               $Carp::CarpLevel + $caller_offset;
         my $mess = Carp::longmess(); 
         chomp($mess);
         # $mess =~ s/(?:\A\s*at.*\n|^\s*Log::Log4perl.*\n|^\s*)//mg;
         $mess =~ s/(?:\A\s*at.*\n|^\s*)//mg;
         $mess =~ s/\n/, /g;
         $info{T} = $mess;
     }
 
         # As long as they're not implemented yet ..
     $info{t} = "N/A";
 
         # Iterate over all info fields on the stack
     for my $e (@{$self->{stack}}) {
         my($op, $curlies) = @$e;
 
         my $result;
 
         if(exists $self->{USER_DEFINED_CSPECS}->{$op}) {
             next unless $self->{info_needed}->{$op};
             $self->{curlies} = $curlies;
             $result = $self->{USER_DEFINED_CSPECS}->{$op}->($self, 
                               $message, $category, $priority, 
                               $caller_offset+1);
         } elsif(exists $info{$op}) {
             $result = $info{$op};
             if($curlies) {
                 $result = $self->curly_action($op, $curlies, $info{$op},
                                               $self->{printformat}, \@results);
             } else {
                 # just for %d
                 if($op eq 'd') {
                     $result = $info{$op}->format($self->{timer}->gettimeofday());
                 }
             }
         } else {
             warn "Format %'$op' not implemented (yet)";
             $result = "FORMAT-ERROR";
         }
 
         $result = $self->{undef_column_value} unless defined $result;
         push @results, $result;
     }
 
       # dbi appender needs that
     if( scalar @results == 1 and
         !defined $results[0] ) {
         return undef;
     }
 
     return (sprintf $self->{printformat}, @results);
 }
 
 ##################################################
 sub curly_action {
 ##################################################
     my($self, $ops, $curlies, $data, $printformat, $results) = @_;
 
     if($ops eq "c") {
         $data = shrink_category($data, $curlies);
     } elsif($ops eq "C") {
         $data = shrink_category($data, $curlies);
     } elsif($ops eq "X") {
         $data = Log::Log4perl::MDC->get($curlies);
     } elsif($ops eq "d") {
         $data = $curlies->format( $self->{timer}->gettimeofday() );
     } elsif($ops eq "M") {
         $data = shrink_category($data, $curlies);
     } elsif($ops eq "m") {
         if(exists $curlies->{chomp}) {
             chomp $data;
         }
         if(exists $curlies->{indent}) {
             if(defined $curlies->{indent}) {
                   # fixed indent
                 $data =~ s/\n/ "\n" . (" " x $curlies->{indent})/ge;
             } else {
                   # indent on the lead-in
                 no warnings; # trailing array elements are undefined
                 my $indent = length sprintf $printformat, @$results;
                 $data =~ s/\n/ "\n" . (" " x $indent)/ge;
             }
         }
     } elsif($ops eq "F") {
         my @parts = File::Spec->splitdir($data);
             # Limit it to max curlies entries
         if(@parts > $curlies) {
             splice @parts, 0, @parts - $curlies;
         }
         $data = File::Spec->catfile(@parts);
     } elsif($ops eq "p") {
         $data = substr $data, 0, $curlies;
     }
 
     return $data;
 }
 
 ##################################################
 sub shrink_category {
 ##################################################
     my($category, $len) = @_;
 
     my @components = split /\.|::/, $category;
 
     if(@components > $len) {
         splice @components, 0, @components - $len;
         $category = join '.', @components;
     } 
 
     return $category;
 }
 
 ##################################################
 sub add_global_cspec {
 ##################################################
 # This is a Class method.
 # Accepts a coderef or text
 ##################################################
 
     unless($Log::Log4perl::ALLOW_CODE_IN_CONFIG_FILE) {
         die "\$Log::Log4perl::ALLOW_CODE_IN_CONFIG_FILE setting " .
             "prohibits user defined cspecs";
     }
 
     my ($letter, $perlcode) = @_;
 
     croak "Illegal value '$letter' in call to add_global_cspec()"
         unless ($letter =~ /^[a-zA-Z]$/);
 
     croak "Missing argument for perlcode for 'cspec.$letter' ".
           "in call to add_global_cspec()"
         unless $perlcode;
 
     croak "Please don't redefine built-in cspecs [$CSPECS]\n".
           "like you do for \"cspec.$letter\"\n "
         if ($CSPECS =~/$letter/);
 
     if (ref $perlcode eq 'CODE') {
         $GLOBAL_USER_DEFINED_CSPECS{$letter} = $perlcode;
 
     }elsif (! ref $perlcode){
         
         $GLOBAL_USER_DEFINED_CSPECS{$letter} = 
             Log::Log4perl::Config::compile_if_perl($perlcode);
 
         if ($@) {
             die qq{Compilation failed for your perl code for }.
                 qq{"log4j.PatternLayout.cspec.$letter":\n}.
                 qq{This is the error message: \t$@\n}.
                 qq{This is the code that failed: \n$perlcode\n};
         }
 
         croak "eval'ing your perlcode for 'log4j.PatternLayout.cspec.$letter' ".
               "doesn't return a coderef \n".
               "Here is the perl code: \n\t$perlcode\n "
             unless (ref $GLOBAL_USER_DEFINED_CSPECS{$letter} eq 'CODE');
 
     }else{
         croak "I don't know how to handle perlcode=$perlcode ".
               "for 'cspec.$letter' in call to add_global_cspec()";
     }
 }
 
 ##################################################
 sub add_layout_cspec {
 ##################################################
 # object method
 # adds a cspec just for this layout
 ##################################################
     my ($self, $letter, $perlcode) = @_;
 
     unless($Log::Log4perl::ALLOW_CODE_IN_CONFIG_FILE) {
         die "\$Log::Log4perl::ALLOW_CODE_IN_CONFIG_FILE setting " .
             "prohibits user defined cspecs";
     }
 
     croak "Illegal value '$letter' in call to add_layout_cspec()"
         unless ($letter =~ /^[a-zA-Z]$/);
 
     croak "Missing argument for perlcode for 'cspec.$letter' ".
           "in call to add_layout_cspec()"
         unless $perlcode;
 
     croak "Please don't redefine built-in cspecs [$CSPECS] \n".
           "like you do for 'cspec.$letter'"
         if ($CSPECS =~/$letter/);
 
     if (ref $perlcode eq 'CODE') {
 
         $self->{USER_DEFINED_CSPECS}{$letter} = $perlcode;
 
     }elsif (! ref $perlcode){
         
         $self->{USER_DEFINED_CSPECS}{$letter} =
             Log::Log4perl::Config::compile_if_perl($perlcode);
 
         if ($@) {
             die qq{Compilation failed for your perl code for }.
                 qq{"cspec.$letter":\n}.
                 qq{This is the error message: \t$@\n}.
                 qq{This is the code that failed: \n$perlcode\n};
         }
         croak "eval'ing your perlcode for 'cspec.$letter' ".
               "doesn't return a coderef \n".
               "Here is the perl code: \n\t$perlcode\n "
             unless (ref $self->{USER_DEFINED_CSPECS}{$letter} eq 'CODE');
 
 
     }else{
         croak "I don't know how to handle perlcode=$perlcode ".
               "for 'cspec.$letter' in call to add_layout_cspec()";
     }
 
     $self->{CSPECS} .= $letter;
 }
 
 ###########################################
 sub callinfo_dump {
 ###########################################
     my($level, $info) = @_;
 
     my @called_by = caller(0);
 
     # Just for internal debugging
     $called_by[1] = basename $called_by[1];
     print "caller($level) at $called_by[1]-$called_by[2] returned ";
 
     my @by_idx;
 
     # $info->[1] = basename $info->[1] if defined $info->[1];
 
     my $i = 0;
     for my $field (qw(package filename line subroutine hasargs
                       wantarray evaltext is_require hints bitmask)) {
         $by_idx[$i] = $field;
         $i++;
     }
 
     $i = 0;
     for my $value (@$info) {
         my $field = $by_idx[ $i ];
         print "$field=", 
               (defined $info->[$i] ? $info->[$i] : "[undef]"),
               " ";
         $i++;
     }
 
     print "\n";
 }
 
 1;
 
 __END__
 
 =encoding utf8
 
 =head1 NAME
 
 Log::Log4perl::Layout::PatternLayout - Pattern Layout
 
 =head1 SYNOPSIS
 
   use Log::Log4perl::Layout::PatternLayout;
 
   my $layout = Log::Log4perl::Layout::PatternLayout->new(
                                                    "%d (%F:%L)> %m");
 
 
 =head1 DESCRIPTION
 
 Creates a pattern layout according to
 http://jakarta.apache.org/log4j/docs/api/org/apache/log4j/PatternLayout.html
 and a couple of Log::Log4perl-specific extensions.
 
 The C<new()> method creates a new PatternLayout, specifying its log
 format. The format
 string can contain a number of placeholders which will be
 replaced by the logging engine when it's time to log the message:
 
     %c Category of the logging event.
     %C Fully qualified package (or class) name of the caller
     %d Current date in yyyy/MM/dd hh:mm:ss format
     %d{...} Current date in customized format (see below)
     %F File where the logging event occurred
     %H Hostname (if Sys::Hostname is available)
     %l Fully qualified name of the calling method followed by the
        callers source the file name and line number between 
        parentheses.
     %L Line number within the file where the log statement was issued
     %m The message to be logged
     %m{chomp} Log message, stripped off a trailing newline
     %m{indent} Log message, multi-lines indented so they line up with first
     %m{indent=n} Log message, multi-lines indented by n spaces
     %M Method or function where the logging request was issued
     %n Newline (OS-independent)
     %p Priority of the logging event (%p{1} shows the first letter)
     %P pid of the current process
     %r Number of milliseconds elapsed from program start to logging 
        event
     %R Number of milliseconds elapsed from last logging event to
        current logging event 
     %T A stack trace of functions called
     %x The topmost NDC (see below)
     %X{key} The entry 'key' of the MDC (see below)
     %% A literal percent (%) sign
 
 NDC and MDC are explained in L<Log::Log4perl/"Nested Diagnostic Context (NDC)">
 and L<Log::Log4perl/"Mapped Diagnostic Context (MDC)">.
 
 The granularity of time values is milliseconds if Time::HiRes is available.
 If not, only full seconds are used.
 
 Every once in a while, someone uses the "%m%n" pattern and
 additionally provides an extra newline in the log message (e.g.
 C<-E<gt>log("message\n")>. To avoid printing an extra newline in
 this case, the PatternLayout will chomp the message, printing only
 one newline. This option can be controlled by PatternLayout's
 C<message_chomp_before_newline> option. See L<Advanced options>
 for details.
 
 =head2 Quantify placeholders
 
 All placeholders can be extended with formatting instructions,
 just like in I<printf>:
 
     %20c   Reserve 20 chars for the category, right-justify and fill
            with blanks if it is shorter
     %-20c  Same as %20c, but left-justify and fill the right side 
            with blanks
     %09r   Zero-pad the number of milliseconds to 9 digits
     %.8c   Specify the maximum field with and have the formatter
            cut off the rest of the value
 
 =head2 Fine-tuning with curlies
 
 Some placeholders have special functions defined if you add curlies 
 with content after them:
 
     %c{1}  Just show the right-most category compontent, useful in large
            class hierarchies (Foo::Baz::Bar -> Bar)
     %c{2}  Just show the two right most category components
            (Foo::Baz::Bar -> Baz::Bar)
 
     %F     Display source file including full path
     %F{1}  Just display filename
     %F{2}  Display filename and last path component (dir/test.log)
     %F{3}  Display filename and last two path components (d1/d2/test.log)
 
     %M     Display fully qualified method/function name
     %M{1}  Just display method name (foo)
     %M{2}  Display method name and last path component (main::foo)
 
 In this way, you're able to shrink the displayed category or
 limit file/path components to save space in your logs.
 
 =head2 Fine-tune the date
 
 If you're not happy with the default %d format for the date which 
 looks like
 
     yyyy/MM/DD HH:mm:ss
 
 (which is slightly different from Log4j which uses C<yyyy-MM-dd HH:mm:ss,SSS>)
 you're free to fine-tune it in order to display only certain characteristics
 of a date, according to the SimpleDateFormat in the Java World
 (http://java.sun.com/j2se/1.3/docs/api/java/text/SimpleDateFormat.html):
 
     %d{HH:mm}     "23:45" -- Just display hours and minutes
     %d{yy, EEEE}  "02, Monday" -- Just display two-digit year 
                                   and spelled-out weekday
 Here's the symbols and their meaning, according to the SimpleDateFormat
 specification:
 
     Symbol   Meaning                 Presentation     Example
     ------   -------                 ------------     -------
     G        era designator          (Text)           AD
     y        year                    (Number)         1996 
     M        month in year           (Text & Number)  July & 07
     d        day in month            (Number)         10
     h        hour in am/pm (1-12)    (Number)         12
     H        hour in day (0-23)      (Number)         0
     m        minute in hour          (Number)         30
     s        second in minute        (Number)         55
     E        day in week             (Text)           Tuesday
     D        day in year             (Number)         189
     a        am/pm marker            (Text)           PM
     e        epoch seconds           (Number)         1315011604
 
     (Text): 4 or more pattern letters--use full form, < 4--use short or 
             abbreviated form if one exists. 
 
     (Number): the minimum number of digits. Shorter numbers are 
               zero-padded to this amount. Year is handled 
               specially; that is, if the count of 'y' is 2, the 
               Year will be truncated to 2 digits. 
 
     (Text & Number): 3 or over, use text, otherwise use number. 
 
 There's also a bunch of pre-defined formats:
 
     %d{ABSOLUTE}   "HH:mm:ss,SSS"
     %d{DATE}       "dd MMM yyyy HH:mm:ss,SSS"
     %d{ISO8601}    "yyyy-MM-dd HH:mm:ss,SSS"
 
 =head2 Custom cspecs
 
 First of all, "cspecs" is short for "conversion specifiers", which is 
 the log4j and the printf(3) term for what Mike is calling "placeholders."
 I suggested "cspecs" for this part of the api before I saw that Mike was 
 using "placeholders" consistently in the log4perl documentation.  Ah, the
 joys of collaboration ;=) --kg
 
 If the existing corpus of placeholders/cspecs isn't good enough for you,
 you can easily roll your own:
 
     #'U' a global user-defined cspec     
     log4j.PatternLayout.cspec.U = sub { return "UID: $< "}
     
     #'K' cspec local to appndr1                 (pid in hex)
     log4j.appender.appndr1.layout.cspec.K = sub { return sprintf "%1x", $$}
     
     #and now you can use them
     log4j.appender.appndr1.layout.ConversionPattern = %K %U %m%n
 
 The benefit of this approach is that you can define and use the cspecs 
 right next to each other in the config file.
 
 If you're an API kind of person, there's also this call:
 
     Log::Log4perl::Layout::PatternLayout::
                     add_global_cspec('Z', sub {'zzzzzzzz'}); #snooze?
 
 When the log message is being put together, your anonymous sub 
 will be called with these arguments:
 
     ($layout, $message, $category, $priority, $caller_level);
     
     layout: the PatternLayout object that called it
     message: the logging message (%m)
     category: e.g. groceries.beverages.adult.beer.schlitz
     priority: e.g. DEBUG|WARN|INFO|ERROR|FATAL
     caller_level: how many levels back up the call stack you have 
         to go to find the caller
 
 Please note that the subroutines you're defining in this way are going
 to be run in the C<main> namespace, so be sure to fully qualify functions
 and variables if they're located in different packages. I<Also make sure
 these subroutines aren't using Log4perl, otherwise Log4perl will enter 
 an infinite recursion.>
 
 With Log4perl 1.20 and better, cspecs can be written with parameters in
 curly braces. Writing something like
 
     log4perl.appender.Screen.layout.ConversionPattern = %U{user} %U{id} %m%n
 
 will cause the cspec function defined for %U to be called twice, once
 with the parameter 'user' and then again with the parameter 'id', 
 and the placeholders in the cspec string will be replaced with
 the respective return values.
 
 The parameter value is available in the 'curlies' entry of the first
 parameter passed to the subroutine (the layout object reference). 
 So, if you wanted to map %U{xxx} to entries in the POE session hash, 
 you'd write something like:
 
    log4perl.PatternLayout.cspec.U = sub { \
      POE::Kernel->get_active_session->get_heap()->{ $_[0]->{curlies} } }
                                           
 B<SECURITY NOTE>
   
 This feature means arbitrary perl code can be embedded in the config file. 
 In the rare case where the people who have access to your config file are
 different from the people who write your code and shouldn't have execute
 rights, you might want to set
 
     $Log::Log4perl::Config->allow_code(0);
 
 before you call init().  Alternatively you can supply a restricted set of
 Perl opcodes that can be embedded in the config file as described in
 L<Log::Log4perl/"Restricting what Opcodes can be in a Perl Hook">.
   
 =head2 Advanced Options
 
 The constructor of the C<Log::Log4perl::Layout::PatternLayout> class
 takes an optional hash reference as a first argument to specify
 additional options in order to (ab)use it in creative ways:
 
   my $layout = Log::Log4perl::Layout::PatternLayout->new(
     { time_function       => \&my_time_func,
     }, 
     "%d (%F:%L)> %m");
 
 Here's a list of parameters:
 
 =over 4
 
 =item time_function
 
 Takes a reference to a function returning the time for the time/date
 fields, either in seconds
 since the epoch or as an array, carrying seconds and 
 microseconds, just like C<Time::HiRes::gettimeofday> does.
 
 =item message_chomp_before_newline
 
 If a layout contains the pattern "%m%n" and the message ends with a newline,
 PatternLayout will chomp the message, to prevent printing two newlines. 
 If this is not desired, and you want two newlines in this case, 
 the feature can be turned off by setting the
 C<message_chomp_before_newline> option to a false value:
 
   my $layout = Log::Log4perl::Layout::PatternLayout->new(
       { message_chomp_before_newline => 0
       }, 
       "%d (%F:%L)> %m%n");
 
 In a Log4perl configuration file, the feature can be turned off like this:
 
     log4perl.appender.App.layout   = PatternLayout
     log4perl.appender.App.layout.ConversionPattern = %d %m%n
       # Yes, I want two newlines
     log4perl.appender.App.layout.message_chomp_before_newline = 0
 
 =back
 
 =head2 Getting rid of newlines
 
 If your code contains logging statements like 
 
       # WRONG, don't do that!
     $logger->debug("Some message\n");
 
 then it's usually best to strip the newlines from these calls. As explained
 in L<Log::Log4perl/Logging newlines>, logging statements should never contain
 newlines, but rely on appender layouts to add necessary newlines instead.
 
 If changing the code is not an option, use the special PatternLayout 
 placeholder %m{chomp} to refer to the message excluding a trailing 
 newline:
 
     log4perl.appender.App.layout.ConversionPattern = %d %m{chomp}%n
 
 This will add a single newline to every message, regardless if it
 complies with the Log4perl newline guidelines or not (thanks to 
 Tim Bunce for this idea).
 
 =head2 Multi Lines
 
 If a log message consists of several lines, like
 
     $logger->debug("line1\nline2\nline3");
 
 then by default, they get logged like this (assuming the the layout is
 set to "%d>%m%n"):
 
       # layout %d>%m%n
     2014/07/27 12:46:16>line1
     line2
     line3
 
 If you'd rather have the messages aligned like
 
       # layout %d>%m{indent}%n
     2014/07/27 12:46:16>line1
                         line2
                         line3
 
 then use the C<%m{indent}> option for the %m specifier. This option
 can also take a fixed value, as in C<%m{indent=2}>, which indents
 subsequent lines by two spaces:
 
       # layout %d>%m{indent=2}%n
     2014/07/27 12:46:16>line1
       line2
       line3
 
 Note that you can still add the C<chomp> option for the C<%m> specifier
 in this case (see above what it does), simply add it after a 
 separating comma, like in C<%m{indent=2,chomp}>.
 
 =head1 LICENSE
 
 Copyright 2002-2013 by Mike Schilli E<lt>m@perlmeister.comE<gt> 
 and Kevin Goess E<lt>cpan@goess.orgE<gt>.
 
 This library is free software; you can redistribute it and/or modify
 it under the same terms as Perl itself. 
 
 =head1 AUTHOR
 
 Please contribute patches to the project on Github:
 
     http://github.com/mschilli/log4perl
 
 Send bug reports or requests for enhancements to the authors via our
 
 MAILING LIST (questions, bug reports, suggestions/patches): 
 log4perl-devel@lists.sourceforge.net
 
 Authors (please contact them via the list above, not directly):
 Mike Schilli <m@perlmeister.com>,
 Kevin Goess <cpan@goess.org>
 
 Contributors (in alphabetical order):
 Ateeq Altaf, Cory Bennett, Jens Berthold, Jeremy Bopp, Hutton
 Davidson, Chris R. Donnelly, Matisse Enzer, Hugh Esco, Anthony
 Foiani, James FitzGibbon, Carl Franks, Dennis Gregorovic, Andy
 Grundman, Paul Harrington, Alexander Hartmaier  David Hull, 
 Robert Jacobson, Jason Kohles, Jeff Macdonald, Markus Peter, 
 Brett Rann, Peter Rabbitson, Erik Selberg, Aaron Straup Cope, 
 Lars Thegler, David Viner, Mac Yang.
 
### Log/Log4perl/Layout/PatternLayout/Multiline.pm ###
 #!/usr/bin/perl
 
 package Log::Log4perl::Layout::PatternLayout::Multiline;
 use base qw(Log::Log4perl::Layout::PatternLayout);
 
 ###########################################
 sub render {
 ###########################################
     my($self, $message, $category, $priority, $caller_level) = @_;
 
     my @messages = split /\r?\n/, $message;
 
     $caller_level = 0 unless defined $caller_level;
 
     my $result = '';
 
     for my $msg ( @messages ) {
         $result .= $self->SUPER::render(
             $msg, $category, $priority, $caller_level + 1
         );
     }
     return $result;
 }
 
 1;
 
 __END__
 
 =encoding utf8
 
 =head1 NAME
 
     Log::Log4perl::Layout::PatternLayout::Multiline
 
 =head1 SYNOPSIS
 
     use Log::Log4perl::Layout::PatternLayout::Multiline;
 
     my $layout = Log::Log4perl::Layout::PatternLayout::Multiline->new(
         "%d (%F:%L)> %m");
 
 =head1 DESCRIPTION
 
 C<Log::Log4perl::Layout::PatternLayout::Multiline> is a subclass
 of Log4perl's PatternLayout and is helpful if you send multiline
 messages to your appenders which appear as
 
     2007/04/04 23:59:01 This is
     a message with
     multiple lines
 
 and you want them to appear as 
 
     2007/04/04 23:59:01 This is
     2007/04/04 23:59:01 a message with
     2007/04/04 23:59:01 multiple lines
 
 instead. This layout class simply splits up the incoming message into
 several chunks split by line breaks and renders them with PatternLayout
 just as if it had arrived in separate chunks in the first place.
 
 =head1 LICENSE
 
 Copyright 2002-2013 by Mike Schilli E<lt>m@perlmeister.comE<gt> 
 and Kevin Goess E<lt>cpan@goess.orgE<gt>.
 
 This library is free software; you can redistribute it and/or modify
 it under the same terms as Perl itself. 
 
 =head1 AUTHOR
 
 Please contribute patches to the project on Github:
 
     http://github.com/mschilli/log4perl
 
 Send bug reports or requests for enhancements to the authors via our
 
 MAILING LIST (questions, bug reports, suggestions/patches): 
 log4perl-devel@lists.sourceforge.net
 
 Authors (please contact them via the list above, not directly):
 Mike Schilli <m@perlmeister.com>,
 Kevin Goess <cpan@goess.org>
 
 Contributors (in alphabetical order):
 Ateeq Altaf, Cory Bennett, Jens Berthold, Jeremy Bopp, Hutton
 Davidson, Chris R. Donnelly, Matisse Enzer, Hugh Esco, Anthony
 Foiani, James FitzGibbon, Carl Franks, Dennis Gregorovic, Andy
 Grundman, Paul Harrington, Alexander Hartmaier  David Hull, 
 Robert Jacobson, Jason Kohles, Jeff Macdonald, Markus Peter, 
 Brett Rann, Peter Rabbitson, Erik Selberg, Aaron Straup Cope, 
 Lars Thegler, David Viner, Mac Yang.
 
### Log/Log4perl/Layout/SimpleLayout.pm ###
 ##################################################
 package Log::Log4perl::Layout::SimpleLayout;
 ##################################################
 # as documented in
 # http://jakarta.apache.org/log4j/docs/api/org/apache/log4j/SimpleLayout.html
 ##################################################
 
 use 5.006;
 use strict;
 use warnings;
 use Log::Log4perl::Level;
 
 no strict qw(refs);
 use base qw(Log::Log4perl::Layout);
 
 ##################################################
 sub new {
 ##################################################
     my $class = shift;
     $class = ref ($class) || $class;
 
     my $self = {
         format      => undef,
         info_needed => {},
         stack       => [],
     };
 
     bless $self, $class;
 
     return $self;
 }
 
 ##################################################
 sub render {
 ##################################################
     my($self, $message, $category, $priority, $caller_level) = @_;
 
     return "$priority - $message\n";
 }
 
 1;
 
 __END__
 
 =encoding utf8
 
 =head1 NAME
 
 Log::Log4perl::Layout::SimpleLayout - Simple Layout
 
 =head1 SYNOPSIS
 
   use Log::Log4perl::Layout::SimpleLayout;
   my $layout = Log::Log4perl::Layout::SimpleLayout->new();
 
 =head1 DESCRIPTION
 
 This class implements the C<log4j> simple layout format -- it basically 
 just prints the message priority and the message, that's all.
 Check 
 http://jakarta.apache.org/log4j/docs/api/org/apache/log4j/SimpleLayout.html
 for details.
 
 =head1 SEE ALSO
 
 =head1 LICENSE
 
 Copyright 2002-2013 by Mike Schilli E<lt>m@perlmeister.comE<gt> 
 and Kevin Goess E<lt>cpan@goess.orgE<gt>.
 
 This library is free software; you can redistribute it and/or modify
 it under the same terms as Perl itself. 
 
 =head1 AUTHOR
 
 Please contribute patches to the project on Github:
 
     http://github.com/mschilli/log4perl
 
 Send bug reports or requests for enhancements to the authors via our
 
 MAILING LIST (questions, bug reports, suggestions/patches): 
 log4perl-devel@lists.sourceforge.net
 
 Authors (please contact them via the list above, not directly):
 Mike Schilli <m@perlmeister.com>,
 Kevin Goess <cpan@goess.org>
 
 Contributors (in alphabetical order):
 Ateeq Altaf, Cory Bennett, Jens Berthold, Jeremy Bopp, Hutton
 Davidson, Chris R. Donnelly, Matisse Enzer, Hugh Esco, Anthony
 Foiani, James FitzGibbon, Carl Franks, Dennis Gregorovic, Andy
 Grundman, Paul Harrington, Alexander Hartmaier  David Hull, 
 Robert Jacobson, Jason Kohles, Jeff Macdonald, Markus Peter, 
 Brett Rann, Peter Rabbitson, Erik Selberg, Aaron Straup Cope, 
 Lars Thegler, David Viner, Mac Yang.
 
### Log/Log4perl/Level.pm ###
 ###############r###################################
 package Log::Log4perl::Level;
 ##################################################
 
 use 5.006;
 use strict;
 use warnings;
 use Carp;
 
 # log4j, for whatever reason, puts 0 as all and MAXINT as OFF.
 # this seems less optimal, as more logging would imply a higher
 # level. But oh well. Probably some brokenness that has persisted. :)
 use constant ALL_INT   => 0;
 use constant TRACE_INT =>  5000;
 use constant DEBUG_INT => 10000;
 use constant INFO_INT  => 20000;
 use constant WARN_INT  => 30000;
 use constant ERROR_INT => 40000;
 use constant FATAL_INT => 50000;
 use constant OFF_INT   => (2 ** 31) - 1;
 
 no strict qw(refs);
 use vars qw(%PRIORITY %LEVELS %SYSLOG %L4P_TO_LD);
 
 %PRIORITY = (); # unless (%PRIORITY);
 %LEVELS = () unless (%LEVELS);
 %SYSLOG = () unless (%SYSLOG);
 %L4P_TO_LD = () unless (%L4P_TO_LD);
 
 sub add_priority {
   my ($prio, $intval, $syslog, $log_dispatch_level) = @_;
   $prio = uc($prio); # just in case;
 
   $PRIORITY{$prio}    = $intval;
   $LEVELS{$intval}    = $prio;
 
   # Set up the mapping between Log4perl integer levels and 
   # Log::Dispatch levels
   # Note: Log::Dispatch uses the following levels:
   # 0 debug
   # 1 info
   # 2 notice
   # 3 warning
   # 4 error
   # 5 critical
   # 6 alert
   # 7 emergency
 
       # The equivalent Log::Dispatch level is optional, set it to 
       # the highest value (7=emerg) if it's not provided.
   $log_dispatch_level = 7 unless defined $log_dispatch_level;
   
   $L4P_TO_LD{$prio}  = $log_dispatch_level;
 
   $SYSLOG{$prio}      = $syslog if defined($syslog);
 }
 
 # create the basic priorities
 add_priority("OFF",   OFF_INT,   -1, 7);
 add_priority("FATAL", FATAL_INT,  0, 7);
 add_priority("ERROR", ERROR_INT,  3, 4);
 add_priority("WARN",  WARN_INT,   4, 3);
 add_priority("INFO",  INFO_INT,   6, 1);
 add_priority("DEBUG", DEBUG_INT,  7, 0);
 add_priority("TRACE", TRACE_INT,  8, 0);
 add_priority("ALL",   ALL_INT,    8, 0);
 
 # we often sort numerically, so a helper func for readability
 sub numerically {$a <=> $b}
 
 ###########################################
 sub import {
 ###########################################
     my($class, $namespace) = @_;
            
     if(defined $namespace) {
         # Export $OFF, $FATAL, $ERROR etc. to
         # the given namespace
         $namespace .= "::" unless $namespace =~ /::$/;
     } else {
         # Export $OFF, $FATAL, $ERROR etc. to
         # the caller's namespace
         $namespace = caller(0) . "::";
     }
 
     for my $key (keys %PRIORITY) {
         my $name  = "$namespace$key";
         my $value = $PRIORITY{$key};
         *{"$name"} = \$value;
 	my $nameint = "$namespace${key}_INT";
 	my $func = uc($key) . "_INT";
 	*{"$nameint"} = \&$func;
     }
 }
 
 ##################################################
 sub new { 
 ##################################################
     # We don't need any of this class nonsense
     # in Perl, because we won't allow subclassing
     # from this. We're optimizing for raw speed.
 }
 
 ##################################################
 sub to_priority {
 # changes a level name string to a priority numeric
 ##################################################
     my($string) = @_;
 
     if(exists $PRIORITY{$string}) {
         return $PRIORITY{$string};
     }else{
         croak "level '$string' is not a valid error level (".join ('|', keys %PRIORITY),')';
     }
 }
 
 ##################################################
 sub to_level {
 # changes a priority numeric constant to a level name string 
 ##################################################
     my ($priority) = @_;
     if (exists $LEVELS{$priority}) {
         return $LEVELS{$priority}
     }else {
       croak("priority '$priority' is not a valid error level number (",
 	  join("|", sort numerically keys %LEVELS), "
           )");
     }
 
 }
 
 ##################################################
 sub to_LogDispatch_string {
 # translates into strings that Log::Dispatch recognizes
 ##################################################
     my($priority) = @_;
 
     confess "do what? no priority?" unless defined $priority;
 
     my $string;
 
     if(exists $LEVELS{$priority}) {
         $string = $LEVELS{$priority};
     }
 
         # Log::Dispatch idiosyncrasies
     if($priority == $PRIORITY{WARN}) {
         $string = "WARNING";
     }
          
     if($priority == $PRIORITY{FATAL}) {
         $string = "EMERGENCY";
     }
          
     return $string;
 }
 
 ###################################################
 sub is_valid {
 ###################################################
     my $q = shift;
 
     if ($q =~ /[A-Z]/) {
         return exists $PRIORITY{$q};
     }else{
         return $LEVELS{$q};
     }
     
 }
 
 sub get_higher_level {
     my ($old_priority, $delta) = @_;
 
     $delta ||= 1;
 
     my $new_priority = 0;
 
     foreach (1..$delta){
         #so the list is TRACE, DEBUG, INFO, WARN, ERROR, FATAL
       # but remember, the numbers go in reverse order!
         foreach my $p (sort numerically keys %LEVELS){
             if ($p > $old_priority) {
                 $new_priority = $p;
                 last;
             }
         }
         $old_priority = $new_priority;
     }
     return $new_priority;
 }
 
 sub get_lower_level {
     my ($old_priority, $delta) = @_;
 
     $delta ||= 1;
 
     my $new_priority = 0;
 
     foreach (1..$delta){
         #so the list is FATAL, ERROR, WARN, INFO, DEBUG, TRACE
       # but remember, the numbers go in reverse order!
         foreach my $p (reverse sort numerically keys %LEVELS){
             if ($p < $old_priority) {
                 $new_priority = $p;
                 last;
             }
         }
         $old_priority = $new_priority;
     }
     return $new_priority;
 }
 
 sub isGreaterOrEqual {
   my $lval = shift;
   my $rval = shift;
   
   # in theory, we should check if the above really ARE valid levels.
   # but we just use numeric comparison, since they aren't really classes.
 
   # oh, yeah, and 'cuz level ints go from 0 .. N with 0 being highest,
   # these are reversed.
   return $lval <= $rval;
 }
 
 ######################################################################
 # 
 # since the integer representation of levels is reversed from what
 # we normally want, we don't want to use < and >... instead, we
 # want to use this comparison function
 
 
 1;
 
 __END__
 
 =encoding utf8
 
 =head1 NAME
 
 Log::Log4perl::Level - Predefined log levels
 
 =head1 SYNOPSIS
 
   use Log::Log4perl::Level;
   print $ERROR, "\n";
 
   # -- or --
 
   use Log::Log4perl qw(:levels);
   print $ERROR, "\n";
 
 =head1 DESCRIPTION
 
 C<Log::Log4perl::Level> simply exports a predefined set of I<Log4perl> log
 levels into the caller's name space. It is used internally by 
 C<Log::Log4perl>. The following scalars are defined:
 
     $OFF
     $FATAL
     $ERROR
     $WARN
     $INFO
     $DEBUG
     $TRACE
     $ALL
 
 C<Log::Log4perl> also exports these constants into the caller's namespace
 if you pull it in providing the C<:levels> tag:
 
     use Log::Log4perl qw(:levels);
 
 This is the preferred way, there's usually no need to call 
 C<Log::Log4perl::Level> explicitly.
 
 The numerical values assigned to these constants are purely virtual,
 only used by Log::Log4perl internally and can change at any time,
 so please don't make any assumptions. You can test for numerical equality
 by directly comparing two level values, that's ok:
 
     if( get_logger()->level() == $DEBUG ) {
         print "The logger's level is DEBUG\n";
     }
 
 But if you want to figure out which of two levels is more verbose, use
 Log4perl's own comparator:
 
     if( Log::Log4perl::Level::isGreaterOrEqual( $level1, $level2 ) ) {
         print Log::Log4perl::Level::to_level( $level1 ), 
             " is equal or more verbose than ", 
             Log::Log4perl::Level::to_level( $level2 ), "\n";
     }
 
 If the caller wants to import level constants into a different namespace,
 it can be provided with the C<use> command:
 
     use Log::Log4perl::Level qw(MyNameSpace);
 
 After this C<$MyNameSpace::ERROR>, C<$MyNameSpace::INFO> etc. 
 will be defined accordingly.
 
 =head2 Numeric levels and Strings
 
 Level variables like $DEBUG or $WARN have numeric values that are 
 internal to Log4perl. Transform them to strings that can be used
 in a Log4perl configuration file, use the c<to_level()> function
 provided by Log::Log4perl::Level:
 
     use Log::Log4perl qw(:easy);
     use Log::Log4perl::Level;
 
         # prints "DEBUG"
     print Log::Log4perl::Level::to_level( $DEBUG ), "\n";
 
 To perform the reverse transformation, which takes a string like
 "DEBUG" and converts it into a constant like C<$DEBUG>, use the
 to_priority() function:
 
     use Log::Log4perl qw(:easy);
     use Log::Log4perl::Level;
 
     my $numval = Log::Log4perl::Level::to_priority( "DEBUG" );
 
 after which $numval could be used where a numerical value is required:
 
     Log::Log4perl->easy_init( $numval );
 
 =head1 LICENSE
 
 Copyright 2002-2013 by Mike Schilli E<lt>m@perlmeister.comE<gt> 
 and Kevin Goess E<lt>cpan@goess.orgE<gt>.
 
 This library is free software; you can redistribute it and/or modify
 it under the same terms as Perl itself. 
 
 =head1 AUTHOR
 
 Please contribute patches to the project on Github:
 
     http://github.com/mschilli/log4perl
 
 Send bug reports or requests for enhancements to the authors via our
 
 MAILING LIST (questions, bug reports, suggestions/patches): 
 log4perl-devel@lists.sourceforge.net
 
 Authors (please contact them via the list above, not directly):
 Mike Schilli <m@perlmeister.com>,
 Kevin Goess <cpan@goess.org>
 
 Contributors (in alphabetical order):
 Ateeq Altaf, Cory Bennett, Jens Berthold, Jeremy Bopp, Hutton
 Davidson, Chris R. Donnelly, Matisse Enzer, Hugh Esco, Anthony
 Foiani, James FitzGibbon, Carl Franks, Dennis Gregorovic, Andy
 Grundman, Paul Harrington, Alexander Hartmaier  David Hull, 
 Robert Jacobson, Jason Kohles, Jeff Macdonald, Markus Peter, 
 Brett Rann, Peter Rabbitson, Erik Selberg, Aaron Straup Cope, 
 Lars Thegler, David Viner, Mac Yang.
 
### Log/Log4perl/Logger.pm ###
 ##################################################
 package Log::Log4perl::Logger;
 ##################################################
 
 use 5.006;
 use strict;
 use warnings;
 
 use Log::Log4perl;
 use Log::Log4perl::Level;
 use Log::Log4perl::Layout;
 use Log::Log4perl::Appender;
 use Log::Log4perl::Appender::String;
 use Log::Log4perl::Filter;
 use Carp;
 
 $Carp::Internal{"Log::Log4perl"}++;
 $Carp::Internal{"Log::Log4perl::Logger"}++;
 
 use constant _INTERNAL_DEBUG => 0;
 
     # Initialization
 our $ROOT_LOGGER;
 our $LOGGERS_BY_NAME = {};
 our %APPENDER_BY_NAME = ();
 our $INITIALIZED = 0;
 our $NON_INIT_WARNED;
 our $DIE_DEBUG = 0;
 our $DIE_DEBUG_BUFFER = "";
     # Define the default appender that's used for formatting
     # warn/die/croak etc. messages.
 our $STRING_APP_NAME = "_l4p_warn";
 our $STRING_APP      = Log::Log4perl::Appender->new(
                           "Log::Log4perl::Appender::String",
                           name => $STRING_APP_NAME);
 $STRING_APP->layout(Log::Log4perl::Layout::PatternLayout->new("%m"));
 our $STRING_APP_CODEREF = generate_coderef([[$STRING_APP_NAME, $STRING_APP]]);
 
 __PACKAGE__->reset();
 
 ###########################################
 sub warning_render {
 ###########################################
     my($logger, @message) = @_;
 
     $STRING_APP->string("");
     $STRING_APP_CODEREF->($logger, 
                           @message, 
                           Log::Log4perl::Level::to_level($ALL));
     return $STRING_APP->string();
 }
 
 ##################################################
 sub cleanup {
 ##################################################
     # warn "Logger cleanup";
 
     # Nuke all convenience loggers to avoid them causing cleanup to 
     # be delayed until global destruction. Problem is that something like
     #     *{"DEBUG"} = sub { $logger->debug };
     # ties up a reference to $logger until global destruction, so we 
     # need to clean up all :easy shortcuts, hence freeing the last
     # logger references, to then rely on the garbage collector for cleaning
     # up the loggers.
     Log::Log4perl->easy_closure_global_cleanup();
 
     # Delete all loggers
     $LOGGERS_BY_NAME = {};
 
     # Delete the root logger
     undef $ROOT_LOGGER;
 
     # Delete all appenders
     %APPENDER_BY_NAME   = ();
 
     undef $INITIALIZED;
 }
 
 ##################################################
 sub DESTROY {
 ##################################################
     CORE::warn "Destroying logger $_[0] ($_[0]->{category})" 
             if $Log::Log4perl::CHATTY_DESTROY_METHODS;
 }
 
 ##################################################
 sub reset {
 ##################################################
     $ROOT_LOGGER        = __PACKAGE__->_new("", $OFF);
 #    $LOGGERS_BY_NAME    = {};  #leave this alone, it's used by 
                                 #reset_all_output_methods when 
                                 #the config changes
 
     %APPENDER_BY_NAME   = ();
     undef $INITIALIZED;
     undef $NON_INIT_WARNED;
     Log::Log4perl::Appender::reset();
 
     #clear out all the existing appenders
     foreach my $logger (values %$LOGGERS_BY_NAME){
         $logger->{appender_names} = [];
 
 	#this next bit deals with an init_and_watch case where a category
 	#is deleted from the config file, we need to zero out the existing
 	#loggers so ones not in the config file not continue with their old
 	#behavior --kg
         next if $logger eq $ROOT_LOGGER;
         $logger->{level} = undef;
         $logger->level();  #set it from the hierarchy
     }
 
     # Clear all filters
     Log::Log4perl::Filter::reset();
 }
 
 ##################################################
 sub _new {
 ##################################################
     my($class, $category, $level) = @_;
 
     print("_new: $class/$category/", defined $level ? $level : "undef",
           "\n") if _INTERNAL_DEBUG;
 
     die "usage: __PACKAGE__->_new(category)" unless
         defined $category;
     
     $category  =~ s/::/./g;
 
        # Have we created it previously?
     if(exists $LOGGERS_BY_NAME->{$category}) {
         print "_new: exists already\n" if _INTERNAL_DEBUG;
         return $LOGGERS_BY_NAME->{$category};
     }
 
     my $self  = {
         category  => $category,
         num_appenders => 0,
         additivity    => 1,
         level         => $level,
         layout        => undef,
                 };
 
    bless $self, $class;
 
    $level ||= $self->level();
 
         # Save it in global structure
    $LOGGERS_BY_NAME->{$category} = $self;
 
    $self->set_output_methods;
 
    print("Created logger $self ($category)\n") if _INTERNAL_DEBUG;
 
    return $self;
 }
 
 ##################################################
 sub category {
 ##################################################
    my ($self) = @_;
 
    return $self->{ category };
 }
 
 ##################################################
 sub reset_all_output_methods {
 ##################################################
     print "reset_all_output_methods: \n" if _INTERNAL_DEBUG;
 
     foreach my $loggername ( keys %$LOGGERS_BY_NAME){
         $LOGGERS_BY_NAME->{$loggername}->set_output_methods;
     }
     $ROOT_LOGGER->set_output_methods;
 }
 
 ##################################################
 sub set_output_methods {
 # Here's a big performance increase.  Instead of having the logger
 # calculate whether to log and whom to log to every time log() is called,
 # we calculate it once when the logger is created, and recalculate
 # it if the config information ever changes.
 #
 ##################################################
    my ($self) = @_;
     
    my (@appenders, %seen);
 
    my ($level) = $self->level();
 
    print "set_output_methods: $self->{category}/$level\n" if _INTERNAL_DEBUG;
 
    #collect the appenders in effect for this category    
 
    for(my $logger = $self; $logger; $logger = parent_logger($logger)) {
 
         foreach my $appender_name (@{$logger->{appender_names}}){
 
                 #only one message per appender, (configurable)
             next if $seen{$appender_name} ++ && 
                     $Log::Log4perl::one_message_per_appender;
 
             push (@appenders,     
                    [$appender_name,
                     $APPENDER_BY_NAME{$appender_name},
                    ]
             );
         }
         last unless $logger->{additivity};
     }
 
         #make a no-op coderef for inactive levels
     my $noop = generate_noop_coderef();
 
        #make a coderef
     my $coderef = (! @appenders ? $noop : &generate_coderef(\@appenders)); 
 
     my %priority = %Log::Log4perl::Level::PRIORITY; #convenience and cvs
 
    # changed to >= from <= as level ints were reversed
     foreach my $levelname (keys %priority){
         if (Log::Log4perl::Level::isGreaterOrEqual($level,
 						   $priority{$levelname}
 						   )) {
             print "  ($priority{$levelname} <= $level)\n"
                   if _INTERNAL_DEBUG;
             $self->{$levelname}      = $coderef;
             $self->{"is_$levelname"} = generate_is_xxx_coderef("1");
             print "Setting is_$levelname to 1\n" if _INTERNAL_DEBUG;
         }else{
             print "  ($priority{$levelname} > $level)\n" if _INTERNAL_DEBUG;
             $self->{$levelname}      = $noop;
             $self->{"is_$levelname"} = generate_is_xxx_coderef("0");
             print "Setting is_$levelname to 0\n" if _INTERNAL_DEBUG;
         }
 
         print("  Setting [$self] $self->{category}.$levelname to ",
               ($self->{$levelname} == $noop ? "NOOP" : 
               ("Coderef [$coderef]: " . scalar @appenders . " appenders")), 
               "\n") if _INTERNAL_DEBUG;
     }
 }
 
 ##################################################
 sub generate_coderef {
 ##################################################
     my $appenders = shift;
                     
     print "generate_coderef: ", scalar @$appenders, 
           " appenders\n" if _INTERNAL_DEBUG;
 
     my $watch_check_code = generate_watch_code("logger", 1);
 
     return sub {
       my $logger = shift;
       my $level  = pop;
 
       my $message;
       my $appenders_fired = 0;
       
       # Evaluate all parameters that need to be evaluated. Two kinds:
       #
       # (1) It's a hash like { filter => "filtername",
       #                        value  => "value" }
       #     => filtername(value)
       #
       # (2) It's a code ref
       #     => coderef()
       #
 
       $message   = [map { ref $_ eq "HASH" && 
                            exists $_->{filter} && 
                            ref $_->{filter} eq 'CODE' ?
                                $_->{filter}->($_->{value}) :
                            ref $_ eq "CODE" ?
                                $_->() : $_ 
                           } @_];                  
 
       print("coderef: $logger->{category}\n") if _INTERNAL_DEBUG;
 
       if(defined $Log::Log4perl::Config::WATCHER) {
           return unless $watch_check_code->($logger, @_, $level);
       }
 
       foreach my $a (@$appenders) {   #note the closure here
           my ($appender_name, $appender) = @$a;
 
           print("  Sending message '<$message->[0]>' ($level) " .
                 "to $appender_name\n") if _INTERNAL_DEBUG;
                 
           $appender->log(
               #these get passed through to Log::Dispatch
               { name    => $appender_name,
                 level   => $Log::Log4perl::Level::L4P_TO_LD{
                                $level},   
                 message => $message,
               },
               #these we need
               $logger->{category},
               $level,
           ) and $appenders_fired++;
               # Only counting it if it returns a true value. Otherwise
               # the appender threshold might have suppressed it after all.
     
       } #end foreach appenders
     
       return $appenders_fired;
 
     }; #end coderef
 }
 
 ##################################################
 sub generate_noop_coderef {
 ##################################################
     my $watch_delay_code;
 
     # This might seem crazy at first, but even in a Log4perl noop, we
     # need to check if the configuration changed in a init_and_watch 
     # situation. Why? Say, an application is running in a loop that
     # constantly tries to issue debug() messages, but they're suppressed by
     # the current Log4perl configuration. If debug() (which is a noop
     # here) wasn't watching the configuration for changes, it would never
     # catch the case where someone bumps up the log level and expects
     # the application to pick it up and start logging debug() statements.
 
     my $watch_check_code = generate_watch_code("logger", 1);
 
     my $coderef;
 
     if(defined $Log::Log4perl::Config::WATCHER) {
         $coderef = $watch_check_code;
     } else {
         $coderef = sub { undef };
     }
 
     return $coderef;
 }
 
 ##################################################
 sub generate_is_xxx_coderef {
 ##################################################
     my($return_token) = @_;
 
     return generate_watch_code("checker", $return_token);
 }
 
 ##################################################
 sub generate_watch_code {
 ##################################################
     my($type, $return_token) = @_;
 
     print "generate_watch_code:\n" if _INTERNAL_DEBUG;
 
       # No watcher configured, return a no-op as watch code.
     if(! defined $Log::Log4perl::Config::WATCHER) {
         return sub { $return_token };
     }
 
     my $cond = generate_watch_conditional();
 
     return sub {
         print "exe_watch_code:\n" if _INTERNAL_DEBUG;
 
        if(_INTERNAL_DEBUG) {
            print "Next check: ",
              "$Log::Log4perl::Config::Watch::NEXT_CHECK_TIME ",
              " Now: ", time(), " Mod: ",
              (stat($Log::Log4perl::Config::WATCHER->file()))[9],
              "\n";
        }
 
        if( $cond->() ) {
            my $init_permitted = 1;
 
            if(exists $Log::Log4perl::Config::OPTS->{ preinit_callback } ) {
                print "Calling preinit_callback\n" if _INTERNAL_DEBUG;
                $init_permitted = 
                $Log::Log4perl::Config::OPTS->{ preinit_callback }->( 
                    Log::Log4perl::Config->watcher()->file() );
                print "Callback returned $init_permitted\n" if _INTERNAL_DEBUG;
            }
 
            if( $init_permitted ) {
                Log::Log4perl->init_and_watch();
            } else {
                # It was time to reinit, but init wasn't permitted.
                # Return true, so that the logger continues as if
                # it wasn't time to reinit.
                return 1;
            }
 
            my $logger = shift;
            my $level  = pop;
 
            # Forward call to new configuration
            if($type eq "checker") {
                return $logger->$level();
 
            } elsif( $type eq "logger") {
                my $methodname = lc($level);
 
                # Bump up the caller level by three, since
                # we've artificially introduced additional levels.
                local $Log::Log4perl::caller_depth =
                      $Log::Log4perl::caller_depth + 3;
 
                # Get a new logger for the same category (the old
                # logger might be obsolete because of the re-init)
                $logger = Log::Log4perl::get_logger( $logger->{category} );
 
                $logger->$methodname(@_); # send the message
                # to the new configuration
                return undef;     # Return false, so the logger finishes
                # prematurely and doesn't log the same 
                # message again.
            } else {
                die "internal error: unknown type";
            }
        } else {
            if(_INTERNAL_DEBUG) {
                print "Conditional returned false\n";
            }
            return $return_token;
        }
    };
 }
 
 ##################################################
 sub generate_watch_conditional {
 ##################################################
 
     if(defined $Log::Log4perl::Config::Watch::SIGNAL_CAUGHT) {
         # In this mode, we just check for the variable indicating
         # that the signal has been caught
         return sub {
             return $Log::Log4perl::Config::Watch::SIGNAL_CAUGHT;
         };
     }
 
     return sub {
         return 
             ( time() > $Log::Log4perl::Config::Watch::NEXT_CHECK_TIME and 
               $Log::Log4perl::Config::WATCHER->change_detected() );
     };
 }
 
 ##################################################
 sub parent_string {
 ##################################################
     my($string) = @_;
 
     if($string eq "") {
         return undef; # root doesn't have a parent.
     }
 
     my @components = split /\./, $string;
     
     if(@components == 1) {
         return "";
     }
 
     pop @components;
 
     return join('.', @components);
 }
 
 ##################################################
 sub level {
 ##################################################
     my($self, $level, $dont_reset_all) = @_;
 
         # 'Set' function
     if(defined $level) {
         croak "invalid level '$level'" 
                 unless Log::Log4perl::Level::is_valid($level);
         if ($level =~ /\D/){
             $level = Log::Log4perl::Level::to_priority($level);
         }
         $self->{level} = $level;   
 
         &reset_all_output_methods
             unless $dont_reset_all;  #keep us from getting overworked 
                                      #if it's the config file calling us 
 
         return $level;
     }
 
         # 'Get' function
     if(defined $self->{level}) {
         return $self->{level};
     }
 
     for(my $logger = $self; $logger; $logger = parent_logger($logger)) {
 
         # Does the current logger have the level defined?
 
         if($logger->{category} eq "") {
             # It's the root logger
             return $ROOT_LOGGER->{level};
         }
             
         if(defined $LOGGERS_BY_NAME->{$logger->{category}}->{level}) {
             return $LOGGERS_BY_NAME->{$logger->{category}}->{level};
         }
     }
 
     # We should never get here because at least the root logger should
     # have a level defined
     die "We should never get here.";
 }
 
 ##################################################
 sub parent_logger {
 # Get the parent of the current logger or undef
 ##################################################
     my($logger) = @_;
 
         # Is it the root logger?
     if($logger->{category} eq "") {
         # Root has no parent
         return undef;
     }
 
         # Go to the next defined (!) parent
     my $parent_class = parent_string($logger->{category});
 
     while($parent_class ne "" and
           ! exists $LOGGERS_BY_NAME->{$parent_class}) {
         $parent_class = parent_string($parent_class);
         $logger =  $LOGGERS_BY_NAME->{$parent_class};
     }
 
     if($parent_class eq "") {
         $logger = $ROOT_LOGGER;
     } else {
         $logger = $LOGGERS_BY_NAME->{$parent_class};
     }
 
     return $logger;
 }
 
 ##################################################
 sub get_root_logger {
 ##################################################
     my($class) = @_;
     return $ROOT_LOGGER;    
 }
 
 ##################################################
 sub additivity {
 ##################################################
     my($self, $onoff, $no_reinit) = @_;
 
     if(defined $onoff) {
         $self->{additivity} = $onoff;
     }
 
     if( ! $no_reinit ) {
         $self->set_output_methods();
     }
 
     return $self->{additivity};
 }
 
 ##################################################
 sub get_logger {
 ##################################################
     my($class, $category) = @_;
 
     unless(defined $ROOT_LOGGER) {
         Carp::confess "Internal error: Root Logger not initialized.";
     }
 
     return $ROOT_LOGGER if $category eq "";
 
     my $logger = $class->_new($category);
     return $logger;
 }
 
 ##################################################
 sub add_appender {
 ##################################################
     my($self, $appender, $dont_reset_all) = @_;
 
         # We take this as an indicator that we're initialized.
     $INITIALIZED = 1;
 
     my $appender_name = $appender->name();
 
     $self->{num_appenders}++;  #should this be inside the unless?
 
       # Add newly created appender to the end of the appender array
     unless (grep{$_ eq $appender_name} @{$self->{appender_names}}){
         $self->{appender_names} = [sort @{$self->{appender_names}}, 
                                         $appender_name];
     }
 
     $APPENDER_BY_NAME{$appender_name} = $appender;
 
     reset_all_output_methods
                 unless $dont_reset_all;  # keep us from getting overworked
                                          # if it's  the config file calling us
 
         # For chaining calls ...
     return $appender;
 }
 
 ##################################################
 sub remove_appender {
 ##################################################
     my($self, $appender_name, $dont_reset_all, $sloppy) = @_;
 
     my %appender_names = map { $_ => 1 } @{$self->{appender_names}};
     
     if(!exists $appender_names{$appender_name}) {
         die "No such appender: $appender_name" unless $sloppy;
         return undef;
     }
 
     delete $appender_names{$appender_name};
     $self->{num_appenders}--;
     $self->{appender_names} = [sort keys %appender_names];
 
     &reset_all_output_methods
                 unless $dont_reset_all; 
 }
 
 ##################################################
 sub eradicate_appender {
 ##################################################
         # If someone calls Logger->... and not Logger::...
     shift if $_[0] eq __PACKAGE__;
 
     my($appender_name, $dont_reset_all) = @_;
 
     return 0 unless exists 
         $APPENDER_BY_NAME{$appender_name};
 
         # Remove the given appender from all loggers
         # and delete all references to it, causing
         # its DESTROY method to be called.
     foreach my $logger (values %$LOGGERS_BY_NAME){
         $logger->remove_appender($appender_name, 0, 1);
     }
         # Also remove it from the root logger
     $ROOT_LOGGER->remove_appender($appender_name, 0, 1);
     
     delete $APPENDER_BY_NAME{$appender_name};
 
     &reset_all_output_methods
                 unless $dont_reset_all; 
 
     return 1;
 }
 
 ##################################################
 sub has_appenders {
 ##################################################
     my($self) = @_;
 
     return $self->{num_appenders};
 }
 
 ##################################################
 sub log {
 # external api
 ##################################################
     my ($self, $priority, @messages) = @_;
 
     confess("log: No priority given!") unless defined($priority);
 
        # Just in case of 'init_and_watch' -- see Changes 0.21
     $_[0] = $LOGGERS_BY_NAME->{$_[0]->{category}} if 
         defined $Log::Log4perl::Config::WATCHER;
 
     init_warn() unless $INITIALIZED or $NON_INIT_WARNED;
 
     croak "priority $priority isn't numeric" if ($priority =~ /\D/);
 
     my $which = Log::Log4perl::Level::to_level($priority);
 
     $self->{$which}->($self, @messages, 
                     Log::Log4perl::Level::to_level($priority));
 }
 
 ######################################################################
 #
 # create_custom_level 
 # creates a custom level
 # in theory, could be used to create the default ones
 ######################################################################
 sub create_custom_level {
 ######################################################################
   my $level = shift || die("create_custom_level: " .
                            "forgot to pass in a level string!");
   my $after = shift || die("create_custom_level: " .
                            "forgot to pass in a level after which to " .
                            "place the new level!");
   my $syslog_equiv = shift; # can be undef
   my $log_dispatch_level = shift; # optional
 
   ## only let users create custom levels before initialization
 
   die("create_custom_level must be called before init or " .
       "first get_logger() call") if ($INITIALIZED);
 
   my %PRIORITY = %Log::Log4perl::Level::PRIORITY; #convenience
 
   die("create_custom_level: no such level \"$after\"! Use one of: ", 
      join(", ", sort keys %PRIORITY)) unless $PRIORITY{$after};
 
   # figure out new int value by AFTER + (AFTER+ 1) / 2
 
   my $next_prio = Log::Log4perl::Level::get_lower_level($PRIORITY{$after}, 1);
   my $cust_prio = int(($PRIORITY{$after} + $next_prio) / 2);
 
   die(qq{create_custom_level: Calculated level of $cust_prio already exists!
       This should only happen if you've made some insane number of custom
       levels (like 15 one after another)
       You can usually fix this by re-arranging your code from:
       create_custom_level("cust1", X);
       create_custom_level("cust2", X);
       create_custom_level("cust3", X);
       create_custom_level("cust4", X);
       create_custom_level("cust5", X);
       into:
       create_custom_level("cust3", X);
       create_custom_level("cust5", X);
       create_custom_level("cust4", 4);
       create_custom_level("cust2", cust3);
       create_custom_level("cust1", cust2);
    }) if (${Log::Log4perl::Level::LEVELS{$cust_prio}});
 
   Log::Log4perl::Level::add_priority($level, $cust_prio, $syslog_equiv,
                                      $log_dispatch_level);
 
   print("Adding prio $level at $cust_prio\n") if _INTERNAL_DEBUG;
 
   # get $LEVEL into namespace of Log::Log4perl::Logger to 
   # create $logger->foo nd $logger->is_foo
   my $name = "Log::Log4perl::Logger::";
   my $key = $level;
 
   no strict qw(refs);
   # be sure to use ${Log...} as CVS adds log entries for Log
   *{"$name$key"} = \${Log::Log4perl::Level::PRIORITY{$level}};
 
   # now, stick it in the caller's namespace
   $name = caller(0) . "::";
   *{"$name$key"} = \${Log::Log4perl::Level::PRIORITY{$level}};
   use strict qw(refs);
 
   create_log_level_methods($level);
 
   return 0;
 
 }
 
 ########################################
 #
 # if we were hackin' lisp (or scheme), we'd be returning some lambda
 # expressions. But we aren't. :) So we'll just create some strings and
 # eval them.
 ########################################
 sub create_log_level_methods {
 ########################################
   my $level = shift || die("create_log_level_methods: " .
                            "forgot to pass in a level string!");
   my $lclevel = lc($level);
   my $levelint = uc($level) . "_INT";
   my $initial_cap = ucfirst($lclevel);
 
   no strict qw(refs);
 
   # This is a bit better way to create code on the fly than eval'ing strings.
   # -erik
 
   *{__PACKAGE__ . "::$lclevel"} = sub {
         if(_INTERNAL_DEBUG) {
             my $level_disp = (defined $_[0]->{level} ? $_[0]->{level} 
                                                      : "[undef]");
             print "$lclevel: ($_[0]->{category}/$level_disp) [@_]\n";
         }
         init_warn() unless $INITIALIZED or $NON_INIT_WARNED;
         $_[0]->{$level}->(@_, $level) if defined $_[0]->{$level};
      };
 
   # Added these to have is_xxx functions as fast as xxx functions
   # -ms
   
   my $islevel   = "is_" . $level;
   my $islclevel = "is_" . $lclevel;
 
   *{__PACKAGE__ . "::is_$lclevel"} = sub {
       $_[0]->{$islevel}->($_[0], $islclevel);
   };
   
   # Add the isXxxEnabled() methods as identical to the is_xxx
   # functions. - dviner
   
   *{__PACKAGE__ . "::is".$initial_cap."Enabled"} = 
                            \&{__PACKAGE__ . "::is_$lclevel"};
   
   use strict qw(refs);
 
   return 0;
 }
 
 #now lets autogenerate the logger subs based on the defined priorities
 foreach my $level (keys %Log::Log4perl::Level::PRIORITY){
   create_log_level_methods($level);
 }
 
 ##################################################
 sub init_warn {
 ##################################################
     CORE::warn "Log4perl: Seems like no initialization happened. " .
                "Forgot to call init()?\n";
     # Only tell this once;
     $NON_INIT_WARNED = 1;
 }
 
 #######################################################
 # call me from a sub-func to spew the sub-func's caller
 #######################################################
 sub callerline {
   my $message = join ('', @_);
 
   my $caller_offset = 
     Log::Log4perl::caller_depth_offset( 
         $Log::Log4perl::caller_depth + 1 );
 
   my ($pack, $file, $line) = caller($caller_offset);
 
   if (not chomp $message) {     # no newline
     $message .= " at $file line $line";
 
     # Someday, we'll use Threads. Really.
     if (defined &Thread::tid) {
       my $tid = Thread->self->tid;
       $message .= " thread $tid" if $tid;
     }
   }
 
   return ($message, "\n");
 }
 
 #######################################################
 sub and_warn {
 #######################################################
   my $self = shift;
   CORE::warn(callerline($self->warning_render(@_)));
 }
 
 #######################################################
 sub and_die {
 #######################################################
   my $self = shift;
   my $arg  = $_[0];
 
   my($msg) = callerline($self->warning_render(@_));
 
   if($DIE_DEBUG) {
       $DIE_DEBUG_BUFFER = "DIE_DEBUG: $msg";
   } else {
       if( $Log::Log4perl::STRINGIFY_DIE_MESSAGE ) {
           die("$msg\n");
       }
       die $arg;
   }
 }
 
 ##################################################
 sub logwarn {
 ##################################################
   my $self = shift;
 
   local $Log::Log4perl::caller_depth = 
         $Log::Log4perl::caller_depth + 1;
 
   if ($self->is_warn()) {
         # Since we're one caller level off now, compensate for that.
     my @chomped = @_;
     chomp($chomped[-1]);
     $self->warn(@chomped);
   }
 
   $self->and_warn(@_);
 }
 
 ##################################################
 sub logdie {
 ##################################################
   my $self = shift;
 
   local $Log::Log4perl::caller_depth = 
         $Log::Log4perl::caller_depth + 1;
 
   if ($self->is_fatal()) {
         # Since we're one caller level off now, compensate for that.
     my @chomped = @_;
     chomp($chomped[-1]);
     $self->fatal(@chomped);
   }
 
   $Log::Log4perl::LOGDIE_MESSAGE_ON_STDERR ? 
       $self->and_die(@_) : 
         exit($Log::Log4perl::LOGEXIT_CODE);
 }
 
 ##################################################
 sub logexit {
 ##################################################
   my $self = shift;
 
   local $Log::Log4perl::caller_depth = 
         $Log::Log4perl::caller_depth + 1;
 
   if ($self->is_fatal()) {
         # Since we're one caller level off now, compensate for that.
     my @chomped = @_;
     chomp($chomped[-1]);
     $self->fatal(@chomped);
   }
 
   exit $Log::Log4perl::LOGEXIT_CODE;
 }
 
 ##################################################
 # clucks and carps are WARN level
 sub logcluck {
 ##################################################
   my $self = shift;
 
   local $Log::Log4perl::caller_depth = 
         $Log::Log4perl::caller_depth + 1;
 
   local $Carp::CarpLevel = 
         $Carp::CarpLevel + 1;
 
   my $msg = $self->warning_render(@_);
 
   if ($self->is_warn()) {
     my $message = Carp::longmess($msg);
     foreach (split(/\n/, $message)) {
       $self->warn("$_\n");
     }
   }
 
   Carp::cluck($msg);
 }
 
 ##################################################
 sub logcarp {
 ##################################################
   my $self = shift;
 
   local $Carp::CarpLevel = $Carp::CarpLevel + 1;
 
   local $Log::Log4perl::caller_depth = 
         $Log::Log4perl::caller_depth + 1;
 
   my $msg = $self->warning_render(@_);
 
   if ($self->is_warn()) {
     my $message = Carp::shortmess($msg);
     foreach (split(/\n/, $message)) {
       $self->warn("$_\n");
     }
   }
 
   Carp::carp($msg);
 }
 
 ##################################################
 # croaks and confess are FATAL level
 ##################################################
 sub logcroak {
 ##################################################
   my $self = shift;
   my $arg  = $_[0];
 
   my $msg = $self->warning_render(@_);
 
   local $Carp::CarpLevel = 
         $Carp::CarpLevel + 1;
 
   local $Log::Log4perl::caller_depth = 
         $Log::Log4perl::caller_depth + 1;
 
   if ($self->is_fatal()) {
     my $message = Carp::shortmess($msg);
     foreach (split(/\n/, $message)) {
       $self->fatal("$_\n");
     }
   }
 
   my $croak_msg = $arg;
 
   if( $Log::Log4perl::STRINGIFY_DIE_MESSAGE ) {
       $croak_msg = $msg;
   }
 
   $Log::Log4perl::LOGDIE_MESSAGE_ON_STDERR ? 
       Carp::croak($croak_msg) : 
         exit($Log::Log4perl::LOGEXIT_CODE);
 }
 
 ##################################################
 sub logconfess {
 ##################################################
   my $self = shift;
   my $arg  = $_[0];
 
   local $Carp::CarpLevel = 
         $Carp::CarpLevel + 1;
 
   local $Log::Log4perl::caller_depth = 
         $Log::Log4perl::caller_depth + 1;
 
   my $msg = $self->warning_render(@_);
 
   if ($self->is_fatal()) {
     my $message = Carp::longmess($msg);
     foreach (split(/\n/, $message)) {
       $self->fatal("$_\n");
     }
   }
 
   my $confess_msg = $arg;
 
   if( $Log::Log4perl::STRINGIFY_DIE_MESSAGE ) {
       $confess_msg = $msg;
   }
 
   $Log::Log4perl::LOGDIE_MESSAGE_ON_STDERR ? 
       confess($confess_msg) :
         exit($Log::Log4perl::LOGEXIT_CODE);
 }
 
 ##################################################
 # in case people prefer to use error for warning
 ##################################################
 sub error_warn {
 ##################################################
   my $self = shift;
 
   local $Log::Log4perl::caller_depth = 
         $Log::Log4perl::caller_depth + 1;
 
   if ($self->is_error()) {
     $self->error(@_);
   }
 
   $self->and_warn(@_);
 }
 
 ##################################################
 sub error_die {
 ##################################################
   my $self = shift;
 
   local $Log::Log4perl::caller_depth = 
         $Log::Log4perl::caller_depth + 1;
 
   my $msg = $self->warning_render(@_);
 
   if ($self->is_error()) {
     $self->error($msg);
   }
 
   $Log::Log4perl::LOGDIE_MESSAGE_ON_STDERR ? 
       $self->and_die($msg) :
         exit($Log::Log4perl::LOGEXIT_CODE);
 }
 
 ##################################################
 sub more_logging {
 ##################################################
   my ($self) = shift;
   return $self->dec_level(@_);
 }
 
 ##################################################
 sub inc_level {
 ##################################################
     my ($self, $delta) = @_;
 
     $delta ||= 1;
 
     $self->level(Log::Log4perl::Level::get_higher_level($self->level(), 
                                                         $delta));
 
     $self->set_output_methods;
 }
 
 ##################################################
 sub less_logging {
 ##################################################
   my ($self) = shift;
   return $self->inc_level(@_);
 }
 
 ##################################################
 sub dec_level {
 ##################################################
     my ($self, $delta) = @_;
 
     $delta ||= 1;
 
     $self->level(Log::Log4perl::Level::get_lower_level($self->level(), $delta));
 
     $self->set_output_methods;
 }
 
 1;
 
 __END__
 
 =encoding utf8
 
 =head1 NAME
 
 Log::Log4perl::Logger - Main Logger Class
 
 =head1 SYNOPSIS
 
     # It's not here
 
 =head1 DESCRIPTION
 
 While everything that makes Log4perl tick is implemented here,
 please refer to L<Log::Log4perl> for documentation.
 
 =head1 LICENSE
 
 Copyright 2002-2013 by Mike Schilli E<lt>m@perlmeister.comE<gt> 
 and Kevin Goess E<lt>cpan@goess.orgE<gt>.
 
 This library is free software; you can redistribute it and/or modify
 it under the same terms as Perl itself. 
 
 =head1 AUTHOR
 
 Please contribute patches to the project on Github:
 
     http://github.com/mschilli/log4perl
 
 Send bug reports or requests for enhancements to the authors via our
 
 MAILING LIST (questions, bug reports, suggestions/patches): 
 log4perl-devel@lists.sourceforge.net
 
 Authors (please contact them via the list above, not directly):
 Mike Schilli <m@perlmeister.com>,
 Kevin Goess <cpan@goess.org>
 
 Contributors (in alphabetical order):
 Ateeq Altaf, Cory Bennett, Jens Berthold, Jeremy Bopp, Hutton
 Davidson, Chris R. Donnelly, Matisse Enzer, Hugh Esco, Anthony
 Foiani, James FitzGibbon, Carl Franks, Dennis Gregorovic, Andy
 Grundman, Paul Harrington, Alexander Hartmaier  David Hull, 
 Robert Jacobson, Jason Kohles, Jeff Macdonald, Markus Peter, 
 Brett Rann, Peter Rabbitson, Erik Selberg, Aaron Straup Cope, 
 Lars Thegler, David Viner, Mac Yang.
 
### Log/Log4perl/MDC.pm ###
 ##################################################
 package Log::Log4perl::MDC;
 ##################################################
 
 use 5.006;
 use strict;
 use warnings;
 
 our %MDC_HASH = ();
 
 ###########################################
 sub get {
 ###########################################
     my($class, $key) = @_;
 
     if($class ne __PACKAGE__) {
         # Somebody called us with Log::Log4perl::MDC::get($key)
         $key = $class;
     }
 
     if(exists $MDC_HASH{$key}) {
         return $MDC_HASH{$key};
     } else {
         return undef;
     }
 }
 
 ###########################################
 sub put {
 ###########################################
     my($class, $key, $value) = @_;
 
     if($class ne __PACKAGE__) {
         # Somebody called us with Log::Log4perl::MDC::put($key, $value)
         $value = $key;
         $key   = $class;
     }
 
     $MDC_HASH{$key} = $value;
 }
 
 ###########################################
 sub remove {
 ###########################################
     %MDC_HASH = ();
 
     1;
 }
 
 ###########################################
 sub get_context {
 ###########################################
     return \%MDC_HASH;
 }
 
 1;
 
 __END__
 
 =encoding utf8
 
 =head1 NAME
 
 Log::Log4perl::MDC - Mapped Diagnostic Context
 
 =head1 DESCRIPTION
 
 Log::Log4perl allows loggers to maintain global thread-specific data, 
 called the Nested Diagnostic Context (NDC) and 
 Mapped Diagnostic Context (MDC).
 
 The MDC is a simple thread-specific hash table, in which the application
 can stuff values under certain keys and retrieve them later
 via the C<"%X{key}"> placeholder in 
 C<Log::Log4perl::Layout::PatternLayout>s.
 
 =over 4
 
 =item Log::Log4perl::MDC->put($key, $value);
 
 Store a value C<$value> under key C<$key> in the map.
 
 =item my $value = Log::Log4perl::MDC->get($key);
 
 Retrieve the content of the map under the specified key.
 Typically done by C<%X{key}> in
 C<Log::Log4perl::Layout::PatternLayout>.
 If no value exists to the given key, C<undef> is returned.
 
 =item my $text = Log::Log4perl::MDC->remove();
 
 Delete all entries from the map.
 
 =item Log::Log4perl::MDC->get_context();
 
 Returns a reference to the hash table.
 
 =back
 
 Please note that all of the methods above are class methods, there's no
 instances of this class. Since the thread model in perl 5.8.0 is
 "no shared data unless explicitly requested" the data structures
 used are just global (and therefore thread-specific).
 
 =head1 LICENSE
 
 Copyright 2002-2013 by Mike Schilli E<lt>m@perlmeister.comE<gt> 
 and Kevin Goess E<lt>cpan@goess.orgE<gt>.
 
 This library is free software; you can redistribute it and/or modify
 it under the same terms as Perl itself. 
 
 =head1 AUTHOR
 
 Please contribute patches to the project on Github:
 
     http://github.com/mschilli/log4perl
 
 Send bug reports or requests for enhancements to the authors via our
 
 MAILING LIST (questions, bug reports, suggestions/patches): 
 log4perl-devel@lists.sourceforge.net
 
 Authors (please contact them via the list above, not directly):
 Mike Schilli <m@perlmeister.com>,
 Kevin Goess <cpan@goess.org>
 
 Contributors (in alphabetical order):
 Ateeq Altaf, Cory Bennett, Jens Berthold, Jeremy Bopp, Hutton
 Davidson, Chris R. Donnelly, Matisse Enzer, Hugh Esco, Anthony
 Foiani, James FitzGibbon, Carl Franks, Dennis Gregorovic, Andy
 Grundman, Paul Harrington, Alexander Hartmaier  David Hull, 
 Robert Jacobson, Jason Kohles, Jeff Macdonald, Markus Peter, 
 Brett Rann, Peter Rabbitson, Erik Selberg, Aaron Straup Cope, 
 Lars Thegler, David Viner, Mac Yang.
 
### Log/Log4perl/NDC.pm ###
 ##################################################
 package Log::Log4perl::NDC;
 ##################################################
 
 use 5.006;
 use strict;
 use warnings;
 
 our @NDC_STACK = ();
 our $MAX_SIZE  = 5;
 
 ###########################################
 sub get {
 ###########################################
     if(@NDC_STACK) {
         # Return elements blank separated
         return join " ", @NDC_STACK;
     } else {
         return "[undef]";
     }
 }
 
 ###########################################
 sub pop {
 ###########################################
     if(@NDC_STACK) {
         return pop @NDC_STACK;
     } else {
         return undef;
     }
 }
 
 ###########################################
 sub push {
 ###########################################
     my($self, $text) = @_;
 
     unless(defined $text) {
         # Somebody called us via Log::Log4perl::NDC::push("blah") ?
         $text = $self;
     }
 
     if(@NDC_STACK >= $MAX_SIZE) {
         CORE::pop(@NDC_STACK);
     }
 
     return push @NDC_STACK, $text;
 }
 
 ###########################################
 sub remove {
 ###########################################
     @NDC_STACK = ();
 }
 
 __END__
 
 =encoding utf8
 
 =head1 NAME
 
 Log::Log4perl::NDC - Nested Diagnostic Context
 
 =head1 DESCRIPTION
 
 Log::Log4perl allows loggers to maintain global thread-specific data, 
 called the Nested Diagnostic Context (NDC).
 
 At some point, the application might decide to push a piece of
 data onto the NDC stack, which other parts of the application might 
 want to reuse. For example, at the beginning of a web request in a server,
 the application might decide to push the IP address of the client
 onto the stack to provide it for other loggers down the road without
 having to pass the data from function to function.
 
 The Log::Log4perl::Layout::PatternLayout class even provides the handy
 C<%x> placeholder which is replaced by the blank-separated list
 of elements currently on the stack.
 
 This module maintains a simple stack which you can push data on to, query
 what's on top, pop it off again or delete the entire stack.
 
 Its purpose is to provide a thread-specific context which all 
 Log::Log4perl loggers can refer to without the application having to
 pass around the context data between its functions.
 
 Since in 5.8.0 perl's threads don't share data only upon request,
 global data is by definition thread-specific.
 
 =over 4
 
 =item Log::Log4perl::NDC->push($text);
 
 Push an item onto the stack. If the stack grows beyond the defined
 limit (C<$Log::Log4perl::NDC::MAX_SIZE>), just the topmost element
 will be replated.
 
 This is typically done when a context is entered.
 
 =item Log::Log4perl::NDC->pop();
 
 Discard the upmost element of the stack. This is typically done when
 a context is left.
 
 =item my $text = Log::Log4perl::NDC->get();
 
 Retrieve the content of the stack as a string of blank-separated values
 without disrupting the stack structure. Typically done by C<%x>.
 If the stack is empty the value C<"[undef]"> is being returned.
 
 =item Log::Log4perl::NDC->remove();
 
 Reset the stack, remove all items.
 
 =back
 
 Please note that all of the methods above are class methods, there's no
 instances of this class.
 
 =head1 LICENSE
 
 Copyright 2002-2013 by Mike Schilli E<lt>m@perlmeister.comE<gt> 
 and Kevin Goess E<lt>cpan@goess.orgE<gt>.
 
 This library is free software; you can redistribute it and/or modify
 it under the same terms as Perl itself. 
 
 =head1 AUTHOR
 
 Please contribute patches to the project on Github:
 
     http://github.com/mschilli/log4perl
 
 Send bug reports or requests for enhancements to the authors via our
 
 MAILING LIST (questions, bug reports, suggestions/patches): 
 log4perl-devel@lists.sourceforge.net
 
 Authors (please contact them via the list above, not directly):
 Mike Schilli <m@perlmeister.com>,
 Kevin Goess <cpan@goess.org>
 
 Contributors (in alphabetical order):
 Ateeq Altaf, Cory Bennett, Jens Berthold, Jeremy Bopp, Hutton
 Davidson, Chris R. Donnelly, Matisse Enzer, Hugh Esco, Anthony
 Foiani, James FitzGibbon, Carl Franks, Dennis Gregorovic, Andy
 Grundman, Paul Harrington, Alexander Hartmaier  David Hull, 
 Robert Jacobson, Jason Kohles, Jeff Macdonald, Markus Peter, 
 Brett Rann, Peter Rabbitson, Erik Selberg, Aaron Straup Cope, 
 Lars Thegler, David Viner, Mac Yang.
 
### Log/Log4perl/Resurrector.pm ###
 package Log::Log4perl::Resurrector;
 use warnings;
 use strict;
 
 # [rt.cpan.org #84818]
 use if $^O eq "MSWin32", "Win32"; 
 
 use File::Temp qw(tempfile);
 use File::Spec;
 
 use constant INTERNAL_DEBUG => 0;
 
 our $resurrecting = '';
 
 ###########################################
 sub import {
 ###########################################
     resurrector_init();
 }
 
 ##################################################
 sub resurrector_fh {
 ##################################################
     my($file) = @_;
 
     local($/) = undef;
     open FILE, "<$file" or die "Cannot open $file";
     my $text = <FILE>;
     close FILE;
 
     print "Read ", length($text), " bytes from $file\n" if INTERNAL_DEBUG;
 
     my($tmp_fh, $tmpfile) = tempfile( UNLINK => 1 );
     print "Opened tmpfile $tmpfile\n" if INTERNAL_DEBUG;
 
     $text =~ s/^\s*###l4p//mg;
 
     print "Text=[$text]\n" if INTERNAL_DEBUG;
 
     print $tmp_fh $text;
     seek $tmp_fh, 0, 0;
 
     return $tmp_fh;
 }
 
 ###########################################
 sub resurrector_loader {
 ###########################################
     my ($code, $module) = @_;
 
     print "resurrector_loader called with $module\n" if INTERNAL_DEBUG;
 
       # Avoid recursion
     if($resurrecting eq $module) {
         print "ignoring $module (recursion)\n" if INTERNAL_DEBUG;
         return undef;
     }
     
     local $resurrecting = $module;
     
     
       # Skip Log4perl appenders
     if($module =~ m#^Log/Log4perl/Appender#) {
         print "Ignoring $module (Log4perl-internal)\n" if INTERNAL_DEBUG;
         return undef;
     }
 
     my $path = $module;
 
       # Skip unknown files
     if(!-f $module) {
           # We might have a 'use lib' statement that modified the
           # INC path, search again.
         $path = pm_search($module);
         if(! defined $path) {
             print "File $module not found\n" if INTERNAL_DEBUG;
             return undef;
         }
         print "File $module found in $path\n" if INTERNAL_DEBUG;
     }
 
     print "Resurrecting module $path\n" if INTERNAL_DEBUG;
 
     my $fh = resurrector_fh($path);
 
     my $abs_path = File::Spec->rel2abs( $path );
     print "Setting %INC entry of $module to $abs_path\n" if INTERNAL_DEBUG;
     $INC{$module} = $abs_path;
 
     return $fh;
 }
 
 ###########################################
 sub pm_search {
 ###########################################
     my($pmfile) = @_;
 
     for(@INC) {
           # Skip subrefs
         next if ref($_);
         my $path = File::Spec->catfile($_, $pmfile);
         return $path if -f $path;
     }
 
     return undef;
 }
 
 ###########################################
 sub resurrector_init {
 ###########################################
     unshift @INC, \&resurrector_loader;
 }
 
 1;
 
 __END__
 
 =encoding utf8
 
 =head1 NAME
 
 Log::Log4perl::Resurrector - Dark Magic to resurrect hidden L4p statements
 
 =head1 DESCRIPTION
 
 Loading C<use Log::Log4perl::Resurrector> causes subsequently loaded
 modules to have their hidden
 
     ###l4p use Log::Log4perl qw(:easy);
 
     ###l4p DEBUG(...)
     ###l4p INFO(...)
     ...
 
 statements uncommented and therefore 'resurrected', i.e. activated.
 
 This allows for a module C<Foobar.pm> to be written with Log4perl
 statements commented out and running at full speed in normal mode.
 When loaded via
 
     use Foobar;
 
 all hidden Log4perl statements will be ignored.
 
 However, if a script loads the module C<Foobar> I<after> loading 
 C<Log::Log4perl::Resurrector>, as in
 
     use Log::Log4perl::Resurrector;
     use Foobar;
 
 then C<Log::Log4perl::Resurrector> will have put a source filter in place
 that will extract all hidden Log4perl statements in C<Foobar> before 
 C<Foobar> actually gets loaded. 
 
 Therefore, C<Foobar> will then behave as if the
 
     ###l4p use Log::Log4perl qw(:easy);
 
     ###l4p DEBUG(...)
     ###l4p INFO(...)
     ...
 
 statements were actually written like
 
     use Log::Log4perl qw(:easy);
 
     DEBUG(...)
     INFO(...)
     ...
 
 and the module C<Foobar> will indeed be Log4perl-enabled. Whether any
 activated Log4perl statement will actually trigger log
 messages, is up to the Log4perl configuration, of course.
 
 There's a startup cost to using C<Log::Log4perl::Resurrector> (all
 subsequently loaded modules are examined) but once the compilation
 phase has finished, the perl program will run at full speed.
 
 Some of the techniques used in this module have been stolen from the
 C<Acme::Incorporated> CPAN module, written by I<chromatic>. Long
 live CPAN!
  
 =head1 LICENSE
 
 Copyright 2002-2013 by Mike Schilli E<lt>m@perlmeister.comE<gt> 
 and Kevin Goess E<lt>cpan@goess.orgE<gt>.
 
 This library is free software; you can redistribute it and/or modify
 it under the same terms as Perl itself. 
 
 =head1 AUTHOR
 
 Please contribute patches to the project on Github:
 
     http://github.com/mschilli/log4perl
 
 Send bug reports or requests for enhancements to the authors via our
 
 MAILING LIST (questions, bug reports, suggestions/patches): 
 log4perl-devel@lists.sourceforge.net
 
 Authors (please contact them via the list above, not directly):
 Mike Schilli <m@perlmeister.com>,
 Kevin Goess <cpan@goess.org>
 
 Contributors (in alphabetical order):
 Ateeq Altaf, Cory Bennett, Jens Berthold, Jeremy Bopp, Hutton
 Davidson, Chris R. Donnelly, Matisse Enzer, Hugh Esco, Anthony
 Foiani, James FitzGibbon, Carl Franks, Dennis Gregorovic, Andy
 Grundman, Paul Harrington, Alexander Hartmaier  David Hull, 
 Robert Jacobson, Jason Kohles, Jeff Macdonald, Markus Peter, 
 Brett Rann, Peter Rabbitson, Erik Selberg, Aaron Straup Cope, 
 Lars Thegler, David Viner, Mac Yang.
 
### Log/Log4perl/Util.pm ###
 package Log::Log4perl::Util;
 
 require Exporter;
 our @EXPORT_OK = qw( params_check );
 our @ISA       = qw( Exporter );
 
 use File::Spec;
 
 ###########################################
 sub params_check {
 ###########################################
     my( $hash, $required, $optional ) = @_;
 
     my $pkg       = caller();
     my %hash_copy = %$hash;
 
     if( defined $required ) {
         for my $p ( @$required ) {
             if( !exists $hash->{ $p } or
                 !defined $hash->{ $p } ) {
                 die "$pkg: Required parameter $p missing.";
             }
             delete $hash_copy{ $p };
         }
     }
 
     if( defined $optional ) {
         for my $p ( @$optional ) {
             delete $hash_copy{ $p };
         }
         if( scalar keys %hash_copy ) {
             die "$pkg: Unknown parameter: ", join( ",", keys %hash_copy );
         }
     }
 }
 
 ##################################################
 sub module_available {  # Check if a module is available
 ##################################################
     my($full_name) = @_;
 
       # Weird cases like "strict;" (including the semicolon) would 
       # succeed with the eval below, so check those up front. 
       # I can't believe Perl doesn't have a proper way to check if a 
       # module is available or not!
     return 0 if $full_name =~ /[^\w:]/;
 
     local $SIG{__DIE__} = sub {};
 
     eval "require $full_name";
 
     if($@) {
         return 0;
     }
 
     return 1;
 }
 
 ##################################################
 sub tmpfile_name {  # File::Temp without the bells and whistles
 ##################################################
 
     my $name = File::Spec->catfile(File::Spec->tmpdir(), 
                               'l4p-tmpfile-' . 
                               "$$-" .
                               int(rand(9999999)));
 
         # Some crazy versions of File::Spec use backslashes on Win32
     $name =~ s#\\#/#g;
     return $name;
 }
 
 1;
 
 __END__
 
 =encoding utf8
 
 =head1 NAME
 
 Log::Log4perl::Util - Internal utility functions
 
 =head1 DESCRIPTION
 
 Only internal functions here. Don't peek.
 
 =head1 LICENSE
 
 Copyright 2002-2013 by Mike Schilli E<lt>m@perlmeister.comE<gt> 
 and Kevin Goess E<lt>cpan@goess.orgE<gt>.
 
 This library is free software; you can redistribute it and/or modify
 it under the same terms as Perl itself. 
 
 =head1 AUTHOR
 
 Please contribute patches to the project on Github:
 
     http://github.com/mschilli/log4perl
 
 Send bug reports or requests for enhancements to the authors via our
 
 MAILING LIST (questions, bug reports, suggestions/patches): 
 log4perl-devel@lists.sourceforge.net
 
 Authors (please contact them via the list above, not directly):
 Mike Schilli <m@perlmeister.com>,
 Kevin Goess <cpan@goess.org>
 
 Contributors (in alphabetical order):
 Ateeq Altaf, Cory Bennett, Jens Berthold, Jeremy Bopp, Hutton
 Davidson, Chris R. Donnelly, Matisse Enzer, Hugh Esco, Anthony
 Foiani, James FitzGibbon, Carl Franks, Dennis Gregorovic, Andy
 Grundman, Paul Harrington, Alexander Hartmaier  David Hull, 
 Robert Jacobson, Jason Kohles, Jeff Macdonald, Markus Peter, 
 Brett Rann, Peter Rabbitson, Erik Selberg, Aaron Straup Cope, 
 Lars Thegler, David Viner, Mac Yang.
 
### Log/Log4perl/Util/Semaphore.pm ###
 #//////////////////////////////////////////
 package Log::Log4perl::Util::Semaphore;
 #//////////////////////////////////////////
 use IPC::SysV qw(IPC_RMID IPC_CREAT IPC_EXCL SEM_UNDO IPC_NOWAIT 
                  IPC_SET IPC_STAT SETVAL);
 use IPC::Semaphore;
 use POSIX qw(EEXIST);
 use strict;
 use warnings;
 use constant INTERNAL_DEBUG => 0;
 
 ###########################################
 sub new {
 ###########################################
     my($class, %options) = @_;
 
     my $self = {
         key           => undef,
         mode          => undef,
         uid           => undef,
         gid           => undef,
         destroy       => undef,
         semop_wait    => .1,
         semop_retries => 1,
 	creator       => $$,
         %options,
     };
 
     $self->{ikey} = unpack("i", pack("A4", $self->{key}));
 
       # Accept usernames in the uid field as well
     if(defined $self->{uid} and 
        $self->{uid} =~ /\D/) {
         $self->{uid} = (getpwnam $self->{uid})[2];
     }
 
     bless $self, $class;
     $self->init();
 
     my @values = ();
     for my $param (qw(mode uid gid)) {
         push @values, $param, $self->{$param} if defined $self->{$param};
     }
     $self->semset(@values) if @values;
 
     return $self;
 }
 
 ###########################################
 sub init {
 ###########################################
     my($self) = @_;
 
     print "Semaphore init '$self->{key}'/'$self->{ikey}'\n" if INTERNAL_DEBUG;
 
     $self->{id} = semget( $self->{ikey}, 
                           1, 
                           &IPC_EXCL|&IPC_CREAT|($self->{mode}||0777),
                   );
    
    if(! defined $self->{id} and
       $! == EEXIST) {
        print "Semaphore '$self->{key}' already exists\n" if INTERNAL_DEBUG;
        $self->{id} = semget( $self->{ikey}, 1, 0 )
            or die "semget($self->{ikey}) failed: $!";
    } elsif($!) {
        die "Cannot create semaphore $self->{key}/$self->{ikey} ($!)";
    }
 }
 
 ###########################################
 sub status_as_string {
 ###########################################
     my($self, @values) = @_;
 
     my $sem = IPC::Semaphore->new($self->{ikey}, 1, 0);
 
     my $values  = join('/', $sem->getall());
     my $ncnt    = $sem->getncnt(0);
     my $pidlast = $sem->getpid(0);
     my $zcnt    = $sem->getzcnt(0);
     my $id      = $sem->id();
 
     return <<EOT;
 Semaphore Status
 Key ...................................... $self->{key}
 iKey ..................................... $self->{ikey}
 Id ....................................... $id
 Values ................................... $values
 Processes waiting for counter increase ... $ncnt
 Processes waiting for counter to hit 0 ... $zcnt
 Last process to perform an operation ..... $pidlast
 EOT
 }
 
 ###########################################
 sub semsetval {
 ###########################################
     my($self, %keyvalues) = @_;
 
     my $sem = IPC::Semaphore->new($self->{ikey}, 1, 0);
     $sem->setval(%keyvalues);
 }
 
 ###########################################
 sub semset {
 ###########################################
     my($self, @values) = @_;
 
     print "Setting values for semaphore $self->{key}/$self->{ikey}\n" if
         INTERNAL_DEBUG;
 
     my $sem = IPC::Semaphore->new($self->{ikey}, 1, 0);
     $sem->set(@values);
 }
 
 ###########################################
 sub semlock {
 ###########################################
     my($self) = @_;
 
     my $operation = pack("s!*", 
                           # wait until it's 0
                          0, 0, 0,
                           # increment by 1
                          0, 1, SEM_UNDO
                         );
 
     print "Locking semaphore '$self->{key}'\n" if INTERNAL_DEBUG;
     $self->semop($self->{id}, $operation);
 }
 
 ###########################################
 sub semunlock {
 ###########################################
     my($self) = @_;
 
 #    my $operation = pack("s!*", 
 #                          # decrement by 1
 #                         0, -1, SEM_UNDO
 #                        );
 #
     print "Unlocking semaphore '$self->{key}'\n" if INTERNAL_DEBUG;
 
 #      # ignore errors, as they might result from trying to unlock an
 #      # already unlocked semaphore.
 #    semop($self->{id}, $operation);
 
     semctl $self->{id}, 0, SETVAL, 0;
 }
 
 ###########################################
 sub remove {
 ###########################################
     my($self) = @_;
 
     print "Removing semaphore '$self->{key}'\n" if INTERNAL_DEBUG;
 
     semctl ($self->{id}, 0, &IPC_RMID, 0) or 
         die "Removing semaphore $self->{key} failed: $!";
 }
 
 ###########################################
 sub DESTROY {
 ###########################################
     my($self) = @_;
 
     if($self->{destroy} && $$==$self->{creator}) {
         $self->remove();
     }
 }
 
 ###########################################
 sub semop {
 ###########################################
     my($self, @args) = @_;
 
     my $retries     = $self->{semop_retries};
 
     my $rc;
 
     {
         $rc = semop($args[0], $args[1]);
 
         if(!$rc and 
            $! =~ /temporarily unavailable/ and
            $retries-- > 0) {
             $rc = 'undef' unless defined $rc;
             print "semop failed (rc=$rc), retrying\n", 
                   $self->status_as_string if INTERNAL_DEBUG;
             select undef, undef, undef, $self->{semop_wait};
             redo;
         }
     }
 
     $rc or die "semop(@args) failed: $! ";
     $rc;
 }
 
 1;
 
 __END__
 
 =encoding utf8
 
 =head1 NAME
 
 Log::Log4perl::Util::Semaphore - Easy to use semaphores
 
 =head1 SYNOPSIS
 
     use Log::Log4perl::Util::Semaphore;
     my $sem = Log::Log4perl::Util::Semaphore->new( key => "abc" );
 
     $sem->semlock();
       # ... critical section 
     $sem->semunlock();
 
     $sem->semset( uid  => (getpwnam("hugo"))[2], 
                   gid  => 102,
                   mode => 0644
                 );
 
 =head1 DESCRIPTION
 
 Log::Log4perl::Util::Semaphore provides the synchronisation mechanism
 for the Synchronized.pm appender in Log4perl, but can be used independently
 of Log4perl.
 
 As a convenience, the C<uid> field accepts user names as well, which it 
 translates into the corresponding uid by running C<getpwnam>.
 
 =head1 LICENSE
 
 Copyright 2002-2013 by Mike Schilli E<lt>m@perlmeister.comE<gt> 
 and Kevin Goess E<lt>cpan@goess.orgE<gt>.
 
 This library is free software; you can redistribute it and/or modify
 it under the same terms as Perl itself. 
 
 =head1 AUTHOR
 
 Please contribute patches to the project on Github:
 
     http://github.com/mschilli/log4perl
 
 Send bug reports or requests for enhancements to the authors via our
 
 MAILING LIST (questions, bug reports, suggestions/patches): 
 log4perl-devel@lists.sourceforge.net
 
 Authors (please contact them via the list above, not directly):
 Mike Schilli <m@perlmeister.com>,
 Kevin Goess <cpan@goess.org>
 
 Contributors (in alphabetical order):
 Ateeq Altaf, Cory Bennett, Jens Berthold, Jeremy Bopp, Hutton
 Davidson, Chris R. Donnelly, Matisse Enzer, Hugh Esco, Anthony
 Foiani, James FitzGibbon, Carl Franks, Dennis Gregorovic, Andy
 Grundman, Paul Harrington, Alexander Hartmaier  David Hull, 
 Robert Jacobson, Jason Kohles, Jeff Macdonald, Markus Peter, 
 Brett Rann, Peter Rabbitson, Erik Selberg, Aaron Straup Cope, 
 Lars Thegler, David Viner, Mac Yang.
 
### Log/Log4perl/Util/TimeTracker.pm ###
 ##################################################
 package Log::Log4perl::Util::TimeTracker;
 ##################################################
 
 use 5.006;
 use strict;
 use warnings;
 use Log::Log4perl::Util;
 use Carp;
 
 our $TIME_HIRES_AVAILABLE;
 
 BEGIN {
     # Check if we've got Time::HiRes. If not, don't make a big fuss,
     # just set a flag so we know later on that we can't have fine-grained
     # time stamps
     $TIME_HIRES_AVAILABLE = 0;
     if(Log::Log4perl::Util::module_available("Time::HiRes")) {
         require Time::HiRes;
         $TIME_HIRES_AVAILABLE = 1;
     }
 }
 
 ##################################################
 sub new {
 ##################################################
     my $class = shift;
     $class = ref ($class) || $class;
 
     my $self = {
         reset_time            => undef,
         @_,
     };
 
     $self->{time_function} = \&_gettimeofday unless 
         defined $self->{time_function};
 
     bless $self, $class;
 
     $self->reset();
 
     return $self;
 }
 
 ##################################################
 sub hires_available {
 ##################################################
     return $TIME_HIRES_AVAILABLE;
 }
 
 ##################################################
 sub _gettimeofday {
 ##################################################
     # Return secs and optionally msecs if we have Time::HiRes
     if($TIME_HIRES_AVAILABLE) {
         return (Time::HiRes::gettimeofday());
     } else {
         return (time(), 0);
     }
 }
 
 ##################################################
 sub gettimeofday {
 ##################################################
     my($self) = @_;
 
     my($seconds, $microseconds) = $self->{time_function}->();
 
     $microseconds = 0 if ! defined $microseconds;
     return($seconds, $microseconds);
 }
 
 ##################################################
 sub reset {
 ##################################################
     my($self) = @_;
 
     my $current_time = [$self->gettimeofday()];
     $self->{reset_time} = $current_time;
     $self->{last_call_time} = $current_time;
 
     return $current_time;
 }
 
 ##################################################
 sub time_diff {
 ##################################################
     my($time_from, $time_to) = @_;
 
     my $seconds = $time_to->[0] -
                   $time_from->[0];
 
     my $milliseconds = int(( $time_to->[1] -
                              $time_from->[1] ) / 1000);
 
     if($milliseconds < 0) {
         $milliseconds = 1000 + $milliseconds;
         $seconds--;
     }
 
     return($seconds, $milliseconds);
 }
 
 ##################################################
 sub milliseconds {
 ##################################################
     my($self, $current_time) = @_;
 
     $current_time = [ $self->gettimeofday() ] unless
         defined $current_time;
 
     my($seconds, $milliseconds) = time_diff(
             $self->{reset_time}, 
             $current_time);
 
     return $seconds*1000 + $milliseconds;
 }
 
 ##################################################
 sub delta_milliseconds {
 ##################################################
     my($self, $current_time) = @_;
 
     $current_time = [ $self->gettimeofday() ] unless
         defined $current_time;
 
     my($seconds, $milliseconds) = time_diff(
             $self->{last_call_time}, 
             $current_time);
 
     $self->{last_call_time} = $current_time;
 
     return $seconds*1000 + $milliseconds;
 }
 
 1;
 
 __END__
 
 =encoding utf8
 
 =head1 NAME
 
 Log::Log4perl::Util::TimeTracker - Track time elapsed
 
 =head1 SYNOPSIS
 
   use Log::Log4perl::Util::TimeTracker;
 
   my $timer = Log::Log4perl::Util::TimeTracker->new();
 
     # equivalent to Time::HiRes::gettimeofday(), regardless
     # if Time::HiRes is present or not. 
   my($seconds, $microseconds) = $timer->gettimeofday();
 
     # reset internal timer
   $timer->reset();
 
     # return milliseconds since last reset
   $msecs = $timer->milliseconds();
 
     # return milliseconds since last call
   $msecs = $timer->delta_milliseconds();
 
 =head1 DESCRIPTION
 
 This utility module helps tracking time elapsed for PatternLayout's
 date and time placeholders. Its accuracy depends on the availability
 of the Time::HiRes module. If it's available, its granularity is
 milliseconds, if not, seconds.
 
 The most common use of this module is calling the gettimeofday() 
 method:
 
   my($seconds, $microseconds) = $timer->gettimeofday();
 
 It returns seconds and microseconds of the current epoch time. If 
 Time::HiRes is installed, it will simply defer to its gettimeofday()
 function, if it's missing, time() will be called instead and $microseconds
 will always be 0.
 
 To measure time elapsed in milliseconds, use the reset() method to 
 reset the timer to the current time, followed by one or more calls to
 the milliseconds() method:
 
     # reset internal timer
   $timer->reset();
 
     # return milliseconds since last reset
   $msecs = $timer->milliseconds();
 
 On top of the time span between the last reset and the current time, 
 the module keeps track of the time between calls to delta_milliseconds():
 
   $msecs = $timer->delta_milliseconds();
 
 On the first call, this will return the number of milliseconds since the
 last reset(), on subsequent calls, it will return the time elapsed in
 milliseconds since the last call to delta_milliseconds() instead. Note
 that reset() also resets the time of the last call.
 
 The internal timer of this module gets its time input from the POSIX time() 
 function, or, if the Time::HiRes module is available, from its 
 gettimeofday() function. To figure out which one it is, use
 
     if( $timer->hires_available() ) {
         print "Hooray, we get real milliseconds!\n";
     } else {
         print "Milliseconds are just bogus\n";
     }
 
 For testing purposes, a different time source can be provided, so test
 suites can simulate time passing by without actually having to wait:
 
   my $start_time = time();
 
   my $timer = Log::Log4perl::Util::TimeTracker->new(
           time_function => sub {
               return $start_time++;
           },
   );
 
 Every call to $timer->epoch() will then return a time value that is one
 second ahead of the value returned on the previous call. This also means
 that every call to delta_milliseconds() will return a value that exceeds
 the value returned on the previous call by 1000.
 
 =head1 LICENSE
 
 Copyright 2002-2013 by Mike Schilli E<lt>m@perlmeister.comE<gt> 
 and Kevin Goess E<lt>cpan@goess.orgE<gt>.
 
 This library is free software; you can redistribute it and/or modify
 it under the same terms as Perl itself. 
 
 =head1 AUTHOR
 
 Please contribute patches to the project on Github:
 
     http://github.com/mschilli/log4perl
 
 Send bug reports or requests for enhancements to the authors via our
 
 MAILING LIST (questions, bug reports, suggestions/patches): 
 log4perl-devel@lists.sourceforge.net
 
 Authors (please contact them via the list above, not directly):
 Mike Schilli <m@perlmeister.com>,
 Kevin Goess <cpan@goess.org>
 
 Contributors (in alphabetical order):
 Ateeq Altaf, Cory Bennett, Jens Berthold, Jeremy Bopp, Hutton
 Davidson, Chris R. Donnelly, Matisse Enzer, Hugh Esco, Anthony
 Foiani, James FitzGibbon, Carl Franks, Dennis Gregorovic, Andy
 Grundman, Paul Harrington, Alexander Hartmaier  David Hull, 
 Robert Jacobson, Jason Kohles, Jeff Macdonald, Markus Peter, 
 Brett Rann, Peter Rabbitson, Erik Selberg, Aaron Straup Cope, 
 Lars Thegler, David Viner, Mac Yang.
 
### Method/Generate/Accessor.pm ###
 package Method::Generate::Accessor;
 
 use Moo::_strictures;
 use Moo::_Utils;
 use Moo::Object ();
 our @ISA = qw(Moo::Object);
 use Sub::Quote qw(quote_sub quoted_from_sub quotify);
 use Scalar::Util 'blessed';
 use overload ();
 use Module::Runtime qw(use_module);
 BEGIN {
   our $CAN_HAZ_XS =
     !$ENV{MOO_XS_DISABLE}
       &&
     _maybe_load_module('Class::XSAccessor')
       &&
     (eval { Class::XSAccessor->VERSION('1.07') })
   ;
   our $CAN_HAZ_XS_PRED =
     $CAN_HAZ_XS &&
     (eval { Class::XSAccessor->VERSION('1.17') })
   ;
 }
 
 my $module_name_only = qr/\A$Module::Runtime::module_name_rx\z/;
 
 sub _die_overwrite
 {
   my ($pkg, $method, $type) = @_;
   die "You cannot overwrite a locally defined method ($method) with "
     . ( $type || 'an accessor' );
 }
 
 sub generate_method {
   my ($self, $into, $name, $spec, $quote_opts) = @_;
   $spec->{allow_overwrite}++ if $name =~ s/^\+//;
   die "Must have an is" unless my $is = $spec->{is};
   if ($is eq 'ro') {
     $spec->{reader} = $name unless exists $spec->{reader};
   } elsif ($is eq 'rw') {
     $spec->{accessor} = $name unless exists $spec->{accessor}
       or ( $spec->{reader} and $spec->{writer} );
   } elsif ($is eq 'lazy') {
     $spec->{reader} = $name unless exists $spec->{reader};
     $spec->{lazy} = 1;
     $spec->{builder} ||= '_build_'.$name unless exists $spec->{default};
   } elsif ($is eq 'rwp') {
     $spec->{reader} = $name unless exists $spec->{reader};
     $spec->{writer} = "_set_${name}" unless exists $spec->{writer};
   } elsif ($is ne 'bare') {
     die "Unknown is ${is}";
   }
   if (exists $spec->{builder}) {
     if(ref $spec->{builder}) {
       $self->_validate_codulatable('builder', $spec->{builder},
         "$into->$name", 'or a method name');
       $spec->{builder_sub} = $spec->{builder};
       $spec->{builder} = 1;
     }
     $spec->{builder} = '_build_'.$name if ($spec->{builder}||0) eq 1;
     die "Invalid builder for $into->$name - not a valid method name"
       if $spec->{builder} !~ $module_name_only;
   }
   if (($spec->{predicate}||0) eq 1) {
     $spec->{predicate} = $name =~ /^_/ ? "_has${name}" : "has_${name}";
   }
   if (($spec->{clearer}||0) eq 1) {
     $spec->{clearer} = $name =~ /^_/ ? "_clear${name}" : "clear_${name}";
   }
   if (($spec->{trigger}||0) eq 1) {
     $spec->{trigger} = quote_sub('shift->_trigger_'.$name.'(@_)');
   }
   if (($spec->{coerce}||0) eq 1) {
     my $isa = $spec->{isa};
     if (blessed $isa and $isa->can('coercion')) {
       $spec->{coerce} = $isa->coercion;
     } elsif (blessed $isa and $isa->can('coerce')) {
       $spec->{coerce} = sub { $isa->coerce(@_) };
     } else {
       die "Invalid coercion for $into->$name - no appropriate type constraint";
     }
   }
 
   foreach my $setting (qw( isa coerce )) {
     next if !exists $spec->{$setting};
     $self->_validate_codulatable($setting, $spec->{$setting}, "$into->$name");
   }
 
   if (exists $spec->{default}) {
     if (ref $spec->{default}) {
       $self->_validate_codulatable('default', $spec->{default}, "$into->$name",
         'or a non-ref');
     }
   }
 
   if (exists $spec->{moosify}) {
     if (ref $spec->{moosify} ne 'ARRAY') {
       $spec->{moosify} = [$spec->{moosify}];
     }
 
     foreach my $spec (@{$spec->{moosify}}) {
       $self->_validate_codulatable('moosify', $spec, "$into->$name");
     }
   }
 
   my %methods;
   if (my $reader = $spec->{reader}) {
     _die_overwrite($into, $reader, 'a reader')
       if !$spec->{allow_overwrite} && defined &{"${into}::${reader}"};
     if (our $CAN_HAZ_XS && $self->is_simple_get($name, $spec)) {
       $methods{$reader} = $self->_generate_xs(
         getters => $into, $reader, $name, $spec
       );
     } else {
       $self->{captures} = {};
       $methods{$reader} =
         quote_sub "${into}::${reader}"
           => '    die "'.$reader.' is a read-only accessor" if @_ > 1;'."\n"
              .$self->_generate_get($name, $spec)
           => delete $self->{captures}
         ;
     }
   }
   if (my $accessor = $spec->{accessor}) {
     _die_overwrite($into, $accessor, 'an accessor')
       if !$spec->{allow_overwrite} && defined &{"${into}::${accessor}"};
     if (
       our $CAN_HAZ_XS
       && $self->is_simple_get($name, $spec)
       && $self->is_simple_set($name, $spec)
     ) {
       $methods{$accessor} = $self->_generate_xs(
         accessors => $into, $accessor, $name, $spec
       );
     } else {
       $self->{captures} = {};
       $methods{$accessor} =
         quote_sub "${into}::${accessor}"
           => $self->_generate_getset($name, $spec)
           => delete $self->{captures}
         ;
     }
   }
   if (my $writer = $spec->{writer}) {
     _die_overwrite($into, $writer, 'a writer')
       if !$spec->{allow_overwrite} && defined &{"${into}::${writer}"};
     if (
       our $CAN_HAZ_XS
       && $self->is_simple_set($name, $spec)
     ) {
       $methods{$writer} = $self->_generate_xs(
         setters => $into, $writer, $name, $spec
       );
     } else {
       $self->{captures} = {};
       $methods{$writer} =
         quote_sub "${into}::${writer}"
           => $self->_generate_set($name, $spec)
           => delete $self->{captures}
         ;
     }
   }
   if (my $pred = $spec->{predicate}) {
     _die_overwrite($into, $pred, 'a predicate')
       if !$spec->{allow_overwrite} && defined &{"${into}::${pred}"};
     if (our $CAN_HAZ_XS && our $CAN_HAZ_XS_PRED) {
       $methods{$pred} = $self->_generate_xs(
         exists_predicates => $into, $pred, $name, $spec
       );
     } else {
       $methods{$pred} =
         quote_sub "${into}::${pred}" =>
           '    '.$self->_generate_simple_has('$_[0]', $name, $spec)."\n"
         ;
     }
   }
   if (my $pred = $spec->{builder_sub}) {
     _install_coderef( "${into}::$spec->{builder}" => $spec->{builder_sub} );
   }
   if (my $cl = $spec->{clearer}) {
     _die_overwrite($into, $cl, 'a clearer')
       if !$spec->{allow_overwrite} && defined &{"${into}::${cl}"};
     $methods{$cl} =
       quote_sub "${into}::${cl}" =>
         $self->_generate_simple_clear('$_[0]', $name, $spec)."\n"
       ;
   }
   if (my $hspec = $spec->{handles}) {
     my $asserter = $spec->{asserter} ||= '_assert_'.$name;
     my @specs = do {
       if (ref($hspec) eq 'ARRAY') {
         map [ $_ => $_ ], @$hspec;
       } elsif (ref($hspec) eq 'HASH') {
         map [ $_ => ref($hspec->{$_}) ? @{$hspec->{$_}} : $hspec->{$_} ],
           keys %$hspec;
       } elsif (!ref($hspec)) {
         map [ $_ => $_ ], use_module('Moo::Role')->methods_provided_by(use_module($hspec))
       } else {
         die "You gave me a handles of ${hspec} and I have no idea why";
       }
     };
     foreach my $delegation_spec (@specs) {
       my ($proxy, $target, @args) = @$delegation_spec;
       _die_overwrite($into, $proxy, 'a delegation')
         if !$spec->{allow_overwrite} && defined &{"${into}::${proxy}"};
       $self->{captures} = {};
       $methods{$proxy} =
         quote_sub "${into}::${proxy}" =>
           $self->_generate_delegation($asserter, $target, \@args),
           delete $self->{captures}
         ;
     }
   }
   if (my $asserter = $spec->{asserter}) {
     $self->{captures} = {};
 
 
     $methods{$asserter} =
       quote_sub "${into}::${asserter}" =>
         $self->_generate_asserter($name, $spec),
         delete $self->{captures};
   }
   \%methods;
 }
 
 sub is_simple_attribute {
   my ($self, $name, $spec) = @_;
   # clearer doesn't have to be listed because it doesn't
   # affect whether defined/exists makes a difference
   !grep $spec->{$_},
     qw(lazy default builder coerce isa trigger predicate weak_ref);
 }
 
 sub is_simple_get {
   my ($self, $name, $spec) = @_;
   !($spec->{lazy} and (exists $spec->{default} or $spec->{builder}));
 }
 
 sub is_simple_set {
   my ($self, $name, $spec) = @_;
   !grep $spec->{$_}, qw(coerce isa trigger weak_ref);
 }
 
 sub has_default {
   my ($self, $name, $spec) = @_;
   $spec->{builder} or exists $spec->{default} or (($spec->{is}||'') eq 'lazy');
 }
 
 sub has_eager_default {
   my ($self, $name, $spec) = @_;
   (!$spec->{lazy} and (exists $spec->{default} or $spec->{builder}));
 }
 
 sub _generate_get {
   my ($self, $name, $spec) = @_;
   my $simple = $self->_generate_simple_get('$_[0]', $name, $spec);
   if ($self->is_simple_get($name, $spec)) {
     $simple;
   } else {
     $self->_generate_use_default(
       '$_[0]', $name, $spec,
       $self->_generate_simple_has('$_[0]', $name, $spec),
     );
   }
 }
 
 sub generate_simple_has {
   my $self = shift;
   $self->{captures} = {};
   my $code = $self->_generate_simple_has(@_);
   ($code, delete $self->{captures});
 }
 
 sub _generate_simple_has {
   my ($self, $me, $name) = @_;
   "exists ${me}->{${\quotify $name}}";
 }
 
 sub _generate_simple_clear {
   my ($self, $me, $name) = @_;
   "    delete ${me}->{${\quotify $name}}\n"
 }
 
 sub generate_get_default {
   my $self = shift;
   $self->{captures} = {};
   my $code = $self->_generate_get_default(@_);
   ($code, delete $self->{captures});
 }
 
 sub generate_use_default {
   my $self = shift;
   $self->{captures} = {};
   my $code = $self->_generate_use_default(@_);
   ($code, delete $self->{captures});
 }
 
 sub _generate_use_default {
   my ($self, $me, $name, $spec, $test) = @_;
   my $get_value = $self->_generate_get_default($me, $name, $spec);
   if ($spec->{coerce}) {
     $get_value = $self->_generate_coerce(
       $name, $get_value,
       $spec->{coerce}
     )
   }
   $test." ? \n"
   .$self->_generate_simple_get($me, $name, $spec)."\n:"
   .($spec->{isa} ?
        "    do {\n      my \$value = ".$get_value.";\n"
       ."      ".$self->_generate_isa_check($name, '$value', $spec->{isa}).";\n"
       ."      ".$self->_generate_simple_set($me, $name, $spec, '$value')."\n"
       ."    }\n"
     : '    ('.$self->_generate_simple_set($me, $name, $spec, $get_value).")\n"
   );
 }
 
 sub _generate_get_default {
   my ($self, $me, $name, $spec) = @_;
   if (exists $spec->{default}) {
     ref $spec->{default}
       ? $self->_generate_call_code($name, 'default', $me, $spec->{default})
     : quotify $spec->{default};
   }
   else {
     "${me}->${\$spec->{builder}}"
   }
 }
 
 sub generate_simple_get {
   my ($self, @args) = @_;
   $self->{captures} = {};
   my $code = $self->_generate_simple_get(@args);
   ($code, delete $self->{captures});
 }
 
 sub _generate_simple_get {
   my ($self, $me, $name) = @_;
   my $name_str = quotify $name;
   "${me}->{${name_str}}";
 }
 
 sub _generate_set {
   my ($self, $name, $spec) = @_;
   if ($self->is_simple_set($name, $spec)) {
     $self->_generate_simple_set('$_[0]', $name, $spec, '$_[1]');
   } else {
     my ($coerce, $trigger, $isa_check) = @{$spec}{qw(coerce trigger isa)};
     my $value_store = '$_[0]';
     my $code;
     if ($coerce) {
       $value_store = '$value';
       $code = "do { my (\$self, \$value) = \@_;\n"
         ."        \$value = "
         .$self->_generate_coerce($name, $value_store, $coerce).";\n";
     }
     else {
       $code = "do { my \$self = shift;\n";
     }
     if ($isa_check) {
       $code .=
         "        ".$self->_generate_isa_check($name, $value_store, $isa_check).";\n";
     }
     my $simple = $self->_generate_simple_set('$self', $name, $spec, $value_store);
     if ($trigger) {
       my $fire = $self->_generate_trigger($name, '$self', $value_store, $trigger);
       $code .=
         "        ".$simple.";\n        ".$fire.";\n"
         ."        $value_store;\n";
     } else {
       $code .= "        ".$simple.";\n";
     }
     $code .= "      }";
     $code;
   }
 }
 
 sub generate_coerce {
   my $self = shift;
   $self->{captures} = {};
   my $code = $self->_generate_coerce(@_);
   ($code, delete $self->{captures});
 }
 
 sub _attr_desc {
   my ($name, $init_arg) = @_;
   return quotify($name) if !defined($init_arg) or $init_arg eq $name;
   return quotify($name).' (constructor argument: '.quotify($init_arg).')';
 }
 
 sub _generate_coerce {
   my ($self, $name, $value, $coerce, $init_arg) = @_;
   $self->_wrap_attr_exception(
     $name,
     "coercion",
     $init_arg,
     $self->_generate_call_code($name, 'coerce', "${value}", $coerce),
     1,
   );
 }
 
 sub generate_trigger {
   my $self = shift;
   $self->{captures} = {};
   my $code = $self->_generate_trigger(@_);
   ($code, delete $self->{captures});
 }
 
 sub _generate_trigger {
   my ($self, $name, $obj, $value, $trigger) = @_;
   $self->_generate_call_code($name, 'trigger', "${obj}, ${value}", $trigger);
 }
 
 sub generate_isa_check {
   my ($self, @args) = @_;
   $self->{captures} = {};
   my $code = $self->_generate_isa_check(@args);
   ($code, delete $self->{captures});
 }
 
 sub _wrap_attr_exception {
   my ($self, $name, $step, $arg, $code, $want_return) = @_;
   my $prefix = quotify("${step} for "._attr_desc($name, $arg).' failed: ');
   "do {\n"
   .'  local $Method::Generate::Accessor::CurrentAttribute = {'."\n"
   .'    init_arg => '.quotify($arg).",\n"
   .'    name     => '.quotify($name).",\n"
   .'    step     => '.quotify($step).",\n"
   ."  };\n"
   .($want_return ? '  my $_return;'."\n" : '')
   .'  my $_error;'."\n"
   ."  {\n"
   .'    my $_old_error = $@;'."\n"
   ."    if (!eval {\n"
   .'      $@ = $_old_error;'."\n"
   .($want_return ? '      $_return ='."\n" : '')
   .'      '.$code.";\n"
   ."      1;\n"
   ."    }) {\n"
   .'      $_error = $@;'."\n"
   .'      if (!ref $_error) {'."\n"
   .'        $_error = '.$prefix.'.$_error;'."\n"
   ."      }\n"
   ."    }\n"
   .'    $@ = $_old_error;'."\n"
   ."  }\n"
   .'  die $_error if $_error;'."\n"
   .($want_return ? '  $_return;'."\n" : '')
   ."}\n"
 }
 
 sub _generate_isa_check {
   my ($self, $name, $value, $check, $init_arg) = @_;
   $self->_wrap_attr_exception(
     $name,
     "isa check",
     $init_arg,
     $self->_generate_call_code($name, 'isa_check', $value, $check)
   );
 }
 
 sub _generate_call_code {
   my ($self, $name, $type, $values, $sub) = @_;
   $sub = \&{$sub} if blessed($sub);  # coderef if blessed
   if (my $quoted = quoted_from_sub($sub)) {
     my $local = 1;
     if ($values eq '@_' || $values eq '$_[0]') {
       $local = 0;
       $values = '@_';
     }
     my $code = $quoted->[1];
     if (my $captures = $quoted->[2]) {
       my $cap_name = qq{\$${type}_captures_for_}.$self->_sanitize_name($name);
       $self->{captures}->{$cap_name} = \$captures;
       Sub::Quote::inlinify($code, $values,
         Sub::Quote::capture_unroll($cap_name, $captures, 6), $local);
     } else {
       Sub::Quote::inlinify($code, $values, undef, $local);
     }
   } else {
     my $cap_name = qq{\$${type}_for_}.$self->_sanitize_name($name);
     $self->{captures}->{$cap_name} = \$sub;
     "${cap_name}->(${values})";
   }
 }
 
 sub _sanitize_name {
   my ($self, $name) = @_;
   $name =~ s/([_\W])/sprintf('_%x', ord($1))/ge;
   $name;
 }
 
 sub generate_populate_set {
   my $self = shift;
   $self->{captures} = {};
   my $code = $self->_generate_populate_set(@_);
   ($code, delete $self->{captures});
 }
 
 sub _generate_populate_set {
   my ($self, $me, $name, $spec, $source, $test, $init_arg) = @_;
   if ($self->has_eager_default($name, $spec)) {
     my $get_indent = ' ' x ($spec->{isa} ? 6 : 4);
     my $get_default = $self->_generate_get_default(
                         '$new', $name, $spec
                       );
     my $get_value =
       defined($spec->{init_arg})
         ? "(\n${get_indent}  ${test}\n"
             ."${get_indent}   ? ${source}\n${get_indent}   : "
             .$get_default
             ."\n${get_indent})"
         : $get_default;
     if ($spec->{coerce}) {
       $get_value = $self->_generate_coerce(
         $name, $get_value,
         $spec->{coerce}, $init_arg
       )
     }
     ($spec->{isa}
       ? "    {\n      my \$value = ".$get_value.";\n      "
         .$self->_generate_isa_check(
           $name, '$value', $spec->{isa}, $init_arg
         ).";\n"
         .'      '.$self->_generate_simple_set($me, $name, $spec, '$value').";\n"
         ."    }\n"
       : '    '.$self->_generate_simple_set($me, $name, $spec, $get_value).";\n"
     )
     .($spec->{trigger}
       ? '    '
         .$self->_generate_trigger(
           $name, $me, $self->_generate_simple_get($me, $name, $spec),
           $spec->{trigger}
         )." if ${test};\n"
       : ''
     );
   } else {
     "    if (${test}) {\n"
       .($spec->{coerce}
         ? "      $source = "
           .$self->_generate_coerce(
             $name, $source,
             $spec->{coerce}, $init_arg
           ).";\n"
         : ""
       )
       .($spec->{isa}
         ? "      "
           .$self->_generate_isa_check(
             $name, $source, $spec->{isa}, $init_arg
           ).";\n"
         : ""
       )
       ."      ".$self->_generate_simple_set($me, $name, $spec, $source).";\n"
       .($spec->{trigger}
         ? "      "
           .$self->_generate_trigger(
             $name, $me, $self->_generate_simple_get($me, $name, $spec),
             $spec->{trigger}
           ).";\n"
         : ""
       )
       ."    }\n";
   }
 }
 
 sub _generate_core_set {
   my ($self, $me, $name, $spec, $value) = @_;
   my $name_str = quotify $name;
   "${me}->{${name_str}} = ${value}";
 }
 
 sub _generate_simple_set {
   my ($self, $me, $name, $spec, $value) = @_;
   my $name_str = quotify $name;
   my $simple = $self->_generate_core_set($me, $name, $spec, $value);
 
   if ($spec->{weak_ref}) {
     require Scalar::Util;
     my $get = $self->_generate_simple_get($me, $name, $spec);
 
     # Perl < 5.8.3 can't weaken refs to readonly vars
     # (e.g. string constants). This *can* be solved by:
     #
     # &Internals::SvREADONLY($foo, 0);
     # Scalar::Util::weaken($foo);
     # &Internals::SvREADONLY($foo, 1);
     #
     # but requires Internal functions and is just too damn crazy
     # so simply throw a better exception
     my $weak_simple = "do { Scalar::Util::weaken(${simple}); no warnings 'void'; $get }";
     Moo::_Utils::lt_5_8_3() ? <<"EOC" : $weak_simple;
       eval { Scalar::Util::weaken($simple); 1 }
         ? do { no warnings 'void'; $get }
         : do {
           if( \$@ =~ /Modification of a read-only value attempted/) {
             require Carp;
             Carp::croak( sprintf (
               'Reference to readonly value in "%s" can not be weakened on Perl < 5.8.3',
               $name_str,
             ) );
           } else {
             die \$@;
           }
         }
 EOC
   } else {
     $simple;
   }
 }
 
 sub _generate_getset {
   my ($self, $name, $spec) = @_;
   q{(@_ > 1}."\n      ? ".$self->_generate_set($name, $spec)
     ."\n      : ".$self->_generate_get($name, $spec)."\n    )";
 }
 
 sub _generate_asserter {
   my ($self, $name, $spec) = @_;
 
   "do {\n"
    ."  my \$val = ".$self->_generate_get($name, $spec).";\n"
    ."  unless (".$self->_generate_simple_has('$_[0]', $name, $spec).") {\n"
    .qq!    die "Attempted to access '${name}' but it is not set";\n!
    ."  }\n"
    ."  \$val;\n"
    ."}\n";
 }
 sub _generate_delegation {
   my ($self, $asserter, $target, $args) = @_;
   my $arg_string = do {
     if (@$args) {
       # I could, I reckon, linearise out non-refs here using quotify
       # plus something to check for numbers but I'm unsure if it's worth it
       $self->{captures}{'@curries'} = $args;
       '@curries, @_';
     } else {
       '@_';
     }
   };
   "shift->${asserter}->${target}(${arg_string});";
 }
 
 sub _generate_xs {
   my ($self, $type, $into, $name, $slot) = @_;
   Class::XSAccessor->import(
     class => $into,
     $type => { $name => $slot },
     replace => 1,
   );
   $into->can($name);
 }
 
 sub default_construction_string { '{}' }
 
 sub _validate_codulatable {
   my ($self, $setting, $value, $into, $appended) = @_;
   my $invalid = "Invalid $setting '" . overload::StrVal($value)
     . "' for $into not a coderef";
   $invalid .= " $appended" if $appended;
 
   unless (ref $value and (ref $value eq 'CODE' or blessed($value))) {
     die "$invalid or code-convertible object";
   }
 
   unless (eval { \&$value }) {
     die "$invalid and could not be converted to a coderef: $@";
   }
 
   1;
 }
 
 1;
### Method/Generate/BuildAll.pm ###
 package Method::Generate::BuildAll;
 
 use Moo::_strictures;
 use Moo::Object ();
 our @ISA = qw(Moo::Object);
 use Sub::Quote qw(quote_sub quotify);
 use Moo::_Utils;
 
 sub generate_method {
   my ($self, $into) = @_;
   quote_sub "${into}::BUILDALL", join '',
     $self->_handle_subbuild($into),
     qq{    my \$self = shift;\n},
     $self->buildall_body_for($into, '$self', '@_'),
     qq{    return \$self\n};
 }
 
 sub _handle_subbuild {
   my ($self, $into) = @_;
   '    if (ref($_[0]) ne '.quotify($into).') {'."\n".
   '      return shift->Moo::Object::BUILDALL(@_)'.";\n".
   '    }'."\n";
 }
 
 sub buildall_body_for {
   my ($self, $into, $me, $args) = @_;
   my @builds =
     grep *{_getglob($_)}{CODE},
     map "${_}::BUILD",
     reverse @{mro::get_linear_isa($into)};
   '    unless (('.$args.')[0]->{__no_BUILD__}) {'."\n"
   .join('', map qq{      ${me}->${_}(${args});\n}, @builds)
   ."   }\n";
 }
 
 1;
### Method/Generate/Constructor.pm ###
 package Method::Generate::Constructor;
 
 use Moo::_strictures;
 use Sub::Quote qw(quote_sub unquote_sub quotify);
 use Sub::Defer;
 use Moo::_Utils qw(_getstash _getglob);
 use Moo;
 
 sub register_attribute_specs {
   my ($self, @new_specs) = @_;
   $self->assert_constructor;
   my $specs = $self->{attribute_specs}||={};
   while (my ($name, $new_spec) = splice @new_specs, 0, 2) {
     if ($name =~ s/^\+//) {
       die "has '+${name}' given but no ${name} attribute already exists"
         unless my $old_spec = $specs->{$name};
       foreach my $key (keys %$old_spec) {
         if (!exists $new_spec->{$key}) {
           $new_spec->{$key} = $old_spec->{$key}
             unless $key eq 'handles';
         }
         elsif ($key eq 'moosify') {
           $new_spec->{$key} = [
             map { ref $_ eq 'ARRAY' ? @$_ : $_ }
               ($old_spec->{$key}, $new_spec->{$key})
           ];
         }
       }
     }
     if ($new_spec->{required}
       && !(
         $self->accessor_generator->has_default($name, $new_spec)
         || !exists $new_spec->{init_arg}
         || defined $new_spec->{init_arg}
       )
     ) {
       die "You cannot have a required attribute (${name})"
         . " without a default, builder, or an init_arg";
     }
     $new_spec->{index} = scalar keys %$specs
       unless defined $new_spec->{index};
     $specs->{$name} = $new_spec;
   }
   $self;
 }
 
 sub all_attribute_specs {
   $_[0]->{attribute_specs}
 }
 
 sub accessor_generator {
   $_[0]->{accessor_generator}
 }
 
 sub construction_string {
   my ($self) = @_;
   $self->{construction_string}
     ||= $self->_build_construction_string;
 }
 
 sub buildall_generator {
   require Method::Generate::BuildAll;
   Method::Generate::BuildAll->new;
 }
 
 sub _build_construction_string {
   my ($self) = @_;
   my $builder = $self->{construction_builder};
   $builder ? $self->$builder
     : 'bless('
     .$self->accessor_generator->default_construction_string
     .', $class);'
 }
 
 sub install_delayed {
   my ($self) = @_;
   $self->assert_constructor;
   my $package = $self->{package};
   my (undef, @isa) = @{mro::get_linear_isa($package)};
   my $isa = join ',', @isa;
   $self->{deferred_constructor} = defer_sub "${package}::new" => sub {
     my (undef, @new_isa) = @{mro::get_linear_isa($package)};
     if (join(',', @new_isa) ne $isa) {
       my ($expected_new) = grep { *{_getglob($_.'::new')}{CODE} } @isa;
       my ($found_new) = grep { *{_getglob($_.'::new')}{CODE} } @new_isa;
       if (($found_new||'') ne ($expected_new||'')) {
         $found_new ||= 'none';
         $expected_new ||= 'none';
         die "Expected parent constructor of $package expected to be"
         . " $expected_new, but found $found_new: changing the inheritance"
         . " chain (\@ISA) at runtime is unsupported";
       }
     }
     unquote_sub $self->generate_method(
       $package, 'new', $self->{attribute_specs}, { no_install => 1 }
     )
   };
   $self;
 }
 
 sub current_constructor {
   my ($self, $package) = @_;
   return *{_getglob("${package}::new")}{CODE};
 }
 
 sub assert_constructor {
   my ($self) = @_;
   my $package = $self->{package} or return 1;
   my $current = $self->current_constructor($package)
     or return 1;
   my $deferred = $self->{deferred_constructor}
     or die "Unknown constructor for $package already exists";
   return 1
     if $deferred == $current;
   my $current_deferred = (Sub::Defer::defer_info($current)||[])->[3];
   if ($current_deferred && $current_deferred == $deferred) {
     die "Constructor for $package has been inlined and cannot be updated";
   }
   die "Constructor for $package has been replaced with an unknown sub";
 }
 
 sub generate_method {
   my ($self, $into, $name, $spec, $quote_opts) = @_;
   foreach my $no_init (grep !exists($spec->{$_}{init_arg}), keys %$spec) {
     $spec->{$no_init}{init_arg} = $no_init;
   }
   local $self->{captures} = {};
   my $body = '    my $class = shift;'."\n"
             .'    $class = ref($class) if ref($class);'."\n";
   $body .= $self->_handle_subconstructor($into, $name);
   my $into_buildargs = $into->can('BUILDARGS');
   if ( $into_buildargs && $into_buildargs != \&Moo::Object::BUILDARGS ) {
       $body .= $self->_generate_args_via_buildargs;
   } else {
       $body .= $self->_generate_args;
   }
   $body .= $self->_check_required($spec);
   $body .= '    my $new = '.$self->construction_string.";\n";
   $body .= $self->_assign_new($spec);
   if ($into->can('BUILD')) {
     $body .= $self->buildall_generator->buildall_body_for(
       $into, '$new', '$args'
     );
   }
   $body .= '    return $new;'."\n";
   if ($into->can('DEMOLISH')) {
     require Method::Generate::DemolishAll;
     Method::Generate::DemolishAll->new->generate_method($into);
   }
   quote_sub
     "${into}::${name}" => $body,
     $self->{captures}, $quote_opts||{}
   ;
 }
 
 sub _handle_subconstructor {
   my ($self, $into, $name) = @_;
   if (my $gen = $self->{subconstructor_handler}) {
     '    if ($class ne '.quotify($into).') {'."\n".
     $gen.
     '    }'."\n";
   } else {
     ''
   }
 }
 
 sub _cap_call {
   my ($self, $code, $captures) = @_;
   @{$self->{captures}}{keys %$captures} = values %$captures if $captures;
   $code;
 }
 
 sub _generate_args_via_buildargs {
   my ($self) = @_;
   q{    my $args = $class->BUILDARGS(@_);}."\n"
   .q{    die "BUILDARGS did not return a hashref" unless ref($args) eq 'HASH';}
   ."\n";
 }
 
 # inlined from Moo::Object - update that first.
 sub _generate_args {
   my ($self) = @_;
   return <<'_EOA';
     my $args;
     if ( scalar @_ == 1 ) {
         unless ( defined $_[0] && ref $_[0] eq 'HASH' ) {
             die "Single parameters to new() must be a HASH ref"
                 ." data => ". $_[0] ."\n";
         }
         $args = { %{ $_[0] } };
     }
     elsif ( @_ % 2 ) {
         die "The new() method for $class expects a hash reference or a"
           . " key/value list. You passed an odd number of arguments\n";
     }
     else {
         $args = {@_};
     }
 _EOA
 
 }
 
 sub _assign_new {
   my ($self, $spec) = @_;
   my $ag = $self->accessor_generator;
   my %test;
   NAME: foreach my $name (sort keys %$spec) {
     my $attr_spec = $spec->{$name};
     next NAME unless defined($attr_spec->{init_arg})
                        or $ag->has_eager_default($name, $attr_spec);
     $test{$name} = $attr_spec->{init_arg};
   }
   join '', map {
     my $arg_key = quotify($test{$_});
     my $test = "exists \$args->{$arg_key}";
     my $source = "\$args->{$arg_key}";
     my $attr_spec = $spec->{$_};
     $self->_cap_call($ag->generate_populate_set(
       '$new', $_, $attr_spec, $source, $test, $test{$_},
     ));
   } sort keys %test;
 }
 
 sub _check_required {
   my ($self, $spec) = @_;
   my @required_init =
     map $spec->{$_}{init_arg},
       grep {
         my %s = %{$spec->{$_}}; # ignore required if default or builder set
         $s{required} and not($s{builder} or exists $s{default})
       } sort keys %$spec;
   return '' unless @required_init;
   '    if (my @missing = grep !exists $args->{$_}, '
     .join(', ', map quotify($_), @required_init).') {'."\n"
     .q{      die "Missing required arguments: ".join(', ', sort @missing);}."\n"
     ."    }\n";
 }
 
 # bootstrap our own constructor
 sub new {
   my $class = shift;
   delete _getstash(__PACKAGE__)->{new};
   bless $class->BUILDARGS(@_), $class;
 }
 Moo->_constructor_maker_for(__PACKAGE__)
 ->register_attribute_specs(
   attribute_specs => {
     is => 'ro',
     reader => 'all_attribute_specs',
   },
   accessor_generator => { is => 'ro' },
   construction_string => { is => 'lazy' },
   construction_builder => { is => 'bare' },
   subconstructor_handler => { is => 'ro' },
   package => { is => 'bare' },
 );
 
 1;
### Method/Generate/DemolishAll.pm ###
 package Method::Generate::DemolishAll;
 
 use Moo::_strictures;
 use Moo::Object ();
 our @ISA = qw(Moo::Object);
 use Sub::Quote qw(quote_sub quotify);
 use Moo::_Utils;
 
 sub generate_method {
   my ($self, $into) = @_;
   quote_sub "${into}::DEMOLISHALL", join '',
     $self->_handle_subdemolish($into),
     qq{    my \$self = shift;\n},
     $self->demolishall_body_for($into, '$self', '@_'),
     qq{    return \$self\n};
   quote_sub "${into}::DESTROY", join '',
     q!    my $self = shift;
     my $e = do {
       local $?;
       local $@;
       require Devel::GlobalDestruction;
       eval {
         $self->DEMOLISHALL(Devel::GlobalDestruction::in_global_destruction);
       };
       $@;
     };
 
     # fatal warnings+die in DESTROY = bad times (perl rt#123398)
     no warnings FATAL => 'all';
     use warnings 'all';
     die $e if $e; # rethrow
   !;
 }
 
 sub demolishall_body_for {
   my ($self, $into, $me, $args) = @_;
   my @demolishers =
     grep *{_getglob($_)}{CODE},
     map "${_}::DEMOLISH",
     @{mro::get_linear_isa($into)};
   join '', map qq{    ${me}->${_}(${args});\n}, @demolishers;
 }
 
 sub _handle_subdemolish {
   my ($self, $into) = @_;
   '    if (ref($_[0]) ne '.quotify($into).') {'."\n".
   '      return shift->Moo::Object::DEMOLISHALL(@_)'.";\n".
   '    }'."\n";
 }
 
 1;
### Method/Inliner.pm ###
 package Method::Inliner;
 
 use Moo::_strictures;
 use Text::Balanced qw(extract_bracketed);
 use Sub::Quote ();
 
 sub slurp { do { local (@ARGV, $/) = $_[0]; <> } }
 sub splat {
   open my $out, '>', $_[1] or die "can't open $_[1]: $!";
   print $out $_[0] or die "couldn't write to $_[1]: $!";
 }
 
 sub inlinify {
   my $file = $_[0];
   my @chunks = split /(^sub.*?^}$)/sm, slurp $file;
   warn join "\n--\n", @chunks;
   my %code;
   foreach my $chunk (@chunks) {
     if (my ($name, $body) =
       $chunk =~ /^sub (\S+) {\n(.*)\n}$/s
     ) {
       $code{$name} = $body;
     }
   }
   foreach my $chunk (@chunks) {
     my ($me) = $chunk =~ /^sub.*{\n  my \((\$\w+).*\) = \@_;\n/ or next;
     my $meq = quotemeta $me;
     #warn $meq, $chunk;
     my $copy = $chunk;
     my ($fixed, $rest);
     while ($copy =~ s/^(.*?)${meq}->(\S+)(?=\()//s) {
       my ($front, $name) = ($1, $2);
       ((my $body), $rest) = extract_bracketed($copy, '()');
       warn "spotted ${name} - ${body}";
       if ($code{$name}) {
       warn "replacing";
         s/^\(//, s/\)$// for $body;
         $body = "${me}, ".$body;
         $fixed .= $front.Sub::Quote::inlinify($code{$name}, $body);
       } else {
         $fixed .= $front.$me.'->'.$name.$body;
       }
       #warn $fixed; warn $rest;
       $copy = $rest;
     }
     $fixed .= $rest if $fixed;
     warn $fixed if $fixed;
     $chunk = $fixed if $fixed;
   }
   print join '', @chunks;
 }
 
 1;
### Mo.pm ###
 package Mo;
 $VERSION=0.39;
 no warnings;my$M=__PACKAGE__.'::';*{$M.Object::new}=sub{my$c=shift;my$s=bless{@_},$c;my%n=%{$c.::.':E'};map{$s->{$_}=$n{$_}->()if!exists$s->{$_}}keys%n;$s};*{$M.import}=sub{import warnings;$^H|=1538;my($P,%e,%o)=caller.'::';shift;eval"no Mo::$_",&{$M.$_.::e}($P,\%e,\%o,\@_)for@_;return if$e{M};%e=(extends,sub{eval"no $_[0]()";@{$P.ISA}=$_[0]},has,sub{my$n=shift;my$m=sub{$#_?$_[0]{$n}=$_[1]:$_[0]{$n}};@_=(default,@_)if!($#_%2);$m=$o{$_}->($m,$n,@_)for sort keys%o;*{$P.$n}=$m},%e,);*{$P.$_}=$e{$_}for keys%e;@{$P.ISA}=$M.Object};
### Mo/Golf.pm ###
 ##
 # name:      Mo::Golf
 # abstract:  Module for Compacting Mo Modules
 # author:    Ingy döt Net <ingy@ingy.net>
 # license:   perl
 # copyright: 2011
 # see:
 # - Mo
 
 use strict;
 use warnings;
 package Mo::Golf;
 
 our $VERSION=0.39;
 
 use PPI;
 
 # This is the mapping of common names to shorter forms that still make some
 # sense.
 my %short_names = (
     (
         map {($_, substr($_, 0, 1))}
         qw(
             args builder class default exports features
             generator import is_lazy method MoPKG name
             nonlazy_defaults options reftype self
         )
     ),
     build_subs => 'B',
     old_constructor => 'C',
     caller_pkg => 'P',
 );
 
 my %short_barewords = ( EAGERINIT => q{':E'}, NONLAZY => q{':N'} );
 
 my %hands_off = map {($_,1)} qw'&import *import';
 
 sub import {
     return unless @_ == 2 and $_[1] eq 'golf';
     binmode STDOUT;
     my $text = do { local $/; <> };
     print STDOUT golf( $text );
 };
 
 sub golf {
     my ( $text ) = @_;
 
     my $tree = PPI::Document->new( \$text );
 
     my %finder_subs = _finder_subs();
 
     my @order = qw( comments duplicate_whitespace whitespace trailing_whitespace );
 
     for my $name ( @order ) {
         my $elements = $tree->find( $finder_subs{$name} );
         die $@ if !defined $elements;
         $_->delete for @{ $elements || [] };
     }
 
     $tree->find( $finder_subs{$_} )
       for qw( del_superfluous_concat del_last_semicolon_in_block separate_version shorten_var_names shorten_barewords );
     die $@ if $@;
 
     for my $name ( 'double_semicolon' ) {
         my $elements = $tree->find( $finder_subs{$name} );
         die $@ if !defined $elements;
         $_->delete for @{ $elements || [] };
     }
 
     return $tree->serialize . "\n";
 }
 
 sub tok { "PPI::Token::$_[0]" }
 
 sub _finder_subs {
     return (
         comments => sub { $_[1]->isa( tok 'Comment' ) },
 
         duplicate_whitespace => sub {
             my ( $top, $current ) = @_;
             return 0 if !$current->isa( tok 'Whitespace' );
 
             $current->set_content(' ') if 1 < length $current->content;
 
             return 0 if !$current->next_token;
             return 0 if !$current->next_token->isa( tok 'Whitespace' );
             return 1;
         },
 
         whitespace => sub {
             my ( $top, $current ) = @_;
             return 0 if !$current->isa( tok 'Whitespace' );
             my $prev = $current->previous_token;
             my $next = $current->next_token;
 
             return 1 if $prev->isa( tok 'Number' ) and $next->isa( tok 'Operator' ) and $next->content =~ /^\W/; # my $P
             return 1 if $prev->isa( tok 'Word' )   and $next->isa( tok 'Operator' ) and $next->content =~ /^\W/; # my $P
             return 1 if $prev->isa( tok 'Symbol' ) and $next->isa( tok 'Operator' ) and $next->content =~ /^\W/; # $VERSION =  but not $v and
 
             return 1 if $prev->isa( tok 'Operator' ) and $next->isa( tok 'Quote::Single' ) and $next->content =~ /^\W/; # eq ''
             return 1 if $prev->isa( tok 'Operator' ) and $next->isa( tok 'Quote::Double' ) and $next->content =~ /^\W/; # eq ""
             return 1 if $prev->isa( tok 'Operator' ) and $next->isa( tok 'Symbol' )        and $next->content =~ /^\W/; # eq $v
             return 1 if $prev->isa( tok 'Operator' ) and $next->isa( tok 'Structure' )     and $next->content =~ /^\W/; # eq (
 
             return 1 if $prev->isa( tok 'Word' )       and $next->isa( tok 'Symbol' );           # my $P
             return 1 if $prev->isa( tok 'Word' )       and $next->isa( tok 'Structure' );        # sub {
             return 1 if $prev->isa( tok 'Word' )       and $next->isa( tok 'Quote::Double' );    # eval "
             return 1 if $prev->isa( tok 'Symbol' )     and $next->isa( tok 'Structure' );        # %a )
             return 1 if $prev->isa( tok 'ArrayIndex' ) and $next->isa( tok 'Operator' );         # $#_ ?
             return 1 if $prev->isa( tok 'Word' )       and $next->isa( tok 'Cast' );             # exists &$_
             return 0;
         },
 
         trailing_whitespace => sub {
             my ( $top, $current ) = @_;
             return 0 if !$current->isa( tok 'Whitespace' );
             my $prev = $current->previous_token;
 
             return 1 if $prev->isa( tok 'Structure' );                                           # ;[\n\s]
             return 1 if $prev->isa( tok 'Operator' ) and $prev->content =~ /\W$/;                # = 0.24
             return 1 if $prev->isa( tok 'Quote::Double' );                                       # " .
             return 1 if $prev->isa( tok 'Quote::Single' );                                       # ' }
 
             return 0;
         },
 
         double_semicolon => sub {
             my ( $top, $current ) = @_;
             return 0 if !$current->isa( tok 'Structure' );
             return 0 if $current->content ne ';';
 
             my $prev = $current->previous_token;
 
             return 0 if !$prev->isa( tok 'Structure' );
             return 0 if $prev->content ne ';';
 
             return 1;
         },
 
         del_last_semicolon_in_block => sub {
             my ( $top, $current ) = @_;
             return 0 if !$current->isa( 'PPI::Structure::Block' );
 
             my $last = $current->last_token;
 
             return 0 if !$last->isa( tok 'Structure' );
             return 0 if $last->content ne '}';
 
             my $maybe_semi = $last->previous_token;
 
             return 0 if !$maybe_semi->isa( tok 'Structure' );
             return 0 if $maybe_semi->content ne ';';
 
             $maybe_semi->delete;
 
             return 1;
         },
 
         del_superfluous_concat => sub {
             my ( $top, $current ) = @_;
             return 0 if !$current->isa( tok 'Operator' );
 
             my $prev = $current->previous_token;
             my $next = $current->next_token;
 
             return 0 if $current->content ne '.';
             return 0 if !$prev->isa( tok 'Quote::Double' );
             return 0 if !$next->isa( tok 'Quote::Double' );
 
             $current->delete;
             $prev->set_content( $prev->{separator} . $prev->string . $next->string . $prev->{separator} );
             $next->delete;
 
             return 1;
         },
 
         separate_version => sub {
             my ( $top, $current ) = @_;
             return 0 if !$current->isa( 'PPI::Statement' );
 
             my $first = $current->first_token;
             return 0 if $first->content ne '$VERSION';
 
             $current->$_( PPI::Token::Whitespace->new( "\n" ) ) for qw( insert_before insert_after );
 
             return 1;
         },
 
         shorten_var_names => sub {
             my ( $top, $current ) = @_;
             return 0 if !$current->isa( tok 'Symbol' );
 
             my $long_name = $current->canonical;
 
             return 1 if $hands_off{$long_name};
             (my $name = $long_name) =~ s/^([\$\@\%])// or die $long_name;
             my $sigil = $1;
             die "variable $long_name conflicts with shortened var name"
                 if grep {
                     $name eq $_
                 } values %short_names;
 
             my $short_name = $short_names{$name};
             $current->set_content( "$sigil$short_name" ) if $short_name;
 
             return 1;
         },
 
         shorten_barewords => sub {
             my ( $top, $current ) = @_;
             return 0 if !$current->isa( tok 'Word' );
 
             my $name = $current->content;
 
             die "bareword $name conflicts with shortened bareword"
                 if grep {
                     $name eq $_
                 } values %short_barewords;
 
             my $short_name = $short_barewords{$name};
             $current->set_content( $short_name ) if $short_name;
 
             return 1;
         },
     );
 }
 
 =head1 SYNOPSIS
 
     perl -MMo::Golf=golf < src/Mo/foo.pm > lib/Mo/foo.pm
 
 =head1 DESCRIPTION
 
 This is the module that is responsible for taking Mo code (which is
 documented and fairly readable) and reducing it to a single undecipherable
 line.
### Mo/Inline.pm ###
 ##
 # name:      Mo::Inline
 # abstract:  Inline Mo and Features into your package
 # author:    Ingy döt Net <ingy@ingy.net>
 # license:   perl
 # copyright: 2011
 # see:
 # - Mo
 
 package Mo::Inline;
 use Mo;
 
 our $VERSION=0.39;
 
 use IO::All;
 
 my $matcher = qr/((?m:^#\s*use Mo(\s.*)?;.*\n))(?:#.*\n)*(?:.{400,}\n)?/;
 
 sub run {
     my $self = shift;
     my @files;
     if (not @_ and -d 'lib') {
         print "Searching the 'lib' directory for a Mo to inline:\n";
         @_ = 'lib';
     }
     if (not @_ or @_ == 1 and $_[0] =~ /^(?:-\?|-h|--help)$/) {
         print usage();
         return 0;
     }
     for my $name (@_) {
         die "No file or directory called '$name'"
             unless -e $name;
         die "'$name' is not a Perl module"
             if -f $name and $name !~ /\.pm$/;
         if (-f $name) {
             push @files, $name;
         }
         elsif (-d $name) {
             push @_, grep /\.pm$/, map { "$_" } io($name)->All_Files;
         }
     }
 
     die "No .pm files specified"
         unless @files;
 
     for my $file (@files) {
         my $text = io($file)->all;
         if ($text !~ $matcher) {
             print "Ignoring $file - No Mo to Inline!\n";
             next;
         }
         $self->inline($file, 1);
     }
 }
 
 sub inline {
     my ($self, $file, $noisy) = @_;
     my $text = io($file)->all;
     $text =~ s/$matcher/"$1" . &inliner($2)/eg;
     io($file)->print($text);
     print "Mo Inlined $file\n"
         if $noisy;
 }
 
 sub inliner {
     my $mo = shift;
     require Mo;
     my @features = grep {$_ ne 'qw'} ($mo =~ /(\w+)/g);
     for (@features) {
         eval "require Mo::$_; 1" or die $@;
     }
     my $inline = '';
     $inline .= $_ for map {
         my $module = $_;
         $module .= '.pm';
         my @lines = io($INC{$module})->chomp->getlines;
         $lines[-1];
     } ('Mo', map { s!::!/!g; "Mo/$_" } @features);
     return <<"...";
 #   The following line of code was produced from the previous line by
 #   Mo::Inline version $VERSION
 $inline\@f=qw[@features];use strict;use warnings;
 ...
 }
 
 sub usage {
     <<'...';
 Usage: mo-linline <perl module files or directories>
 
 ...
 }
 
 1;
 
 =head1 SYNOPSIS
 
 In your Mo module:
 
     # This is effectively your own private Mo(ose) setup
     package MyModule::Mo;
     # use Mo qw'build builder default import';
     1;
 
 From the command line:
 
     > mo-inline lib/MyModule/Mo.pm
 
 or:
 
     > mo-inline lib/
 
 or (if you are really lazy):
 
     > mo-inline
 
 Then from another module:
 
     package MyModule::Foo;
     use MyModule::Mo;       # gets build, builder and default automatically
 
 =head1 DESCRIPTION
 
 Mo is so small that you can easily inline it, along with any feature modules.
 Mo provides a script called C<mo-inline> that will do it for you.
 
 All you need to do is comment out the line that uses Mo, and run C<mo-inline>
 on the file. C<mo-inline> will find such comments and do the inlining for you.
 It will also replace any old inlined Mo with the latest version.
 
 What Mo could you possibly want?
 
 =head1 AUTOMATIC FEATURES
 
 By using the L<Mo::import> feature, all uses of your Mo class will turn on all
 the features you specified. You can override it if you want, but that will be
 the default.
 
 =head1 REAL WORLD EXAMPLES
 
 For real world examples of Mo inlined using C<mo-inline>, see L<YAML::Mo>,
 L<Pegex::Mo> and L<TestML::Mo>.
### Mo/Moose.pm ###
 package Mo::Moose;$M="Mo::";
 $VERSION=0.39;
 *{$M.'Moose::e'}=sub{my($P,$e)=@_;$P=~s/::$//;%$e=(M=>1);require Moose;Moose->import({into=>$P});Moose::Util::MetaRole::apply_metaroles(for=>$P,class_metaroles=>{attribute=>['Attr::Trait']},)};BEGIN{package Attr::Trait;use Moose::Role;around _process_options=>sub{my$orig=shift;my$c=shift;my($n,$o)=@_;$o->{is}||='rw';$o->{lazy}||=1 if defined$o->{default}or defined$o->{builder};$c->$orig(@_)};$INC{'Attr/Trait.pm'}=1}
### Mo/Mouse.pm ###
 package Mo::Mouse;$M="Mo::";
 $VERSION=0.39;
 *{$M.'Mouse::e'}=sub{my($P,$e)=@_;$P=~s/::$//;%$e=(M=>1);require Mouse;require Mouse::Util::MetaRole;Mouse->import({into=>$P});Mouse::Util::MetaRole::apply_metaroles(for=>$P,class_metaroles=>{attribute=>['Attr::Trait']},)};BEGIN{package Attr::Trait;use Mouse::Role;around _process_options=>sub{my$orig=shift;my$c=shift;my($n,$o)=@_;$o->{is}||='rw';$o->{lazy}||=1 if defined$o->{default}or defined$o->{builder};$c->$orig(@_)};$INC{'Attr/Trait.pm'}=1}
### Mo/build.pm ###
 package Mo::build;my$M="Mo::";
 $VERSION=0.39;
 *{$M.'build::e'}=sub{my($P,$e)=@_;$e->{new}=sub{$c=shift;my$s=&{$M.Object::new}($c,@_);my@B;do{@B=($c.::BUILD,@B)}while($c)=@{$c.::ISA};exists&$_&&&$_($s)for@B;$s}};
### Mo/builder.pm ###
 package Mo::builder;my$M="Mo::";
 $VERSION=0.39;
 *{$M.'builder::e'}=sub{my($P,$e,$o)=@_;$o->{builder}=sub{my($m,$n,%a)=@_;my$b=$a{builder}or return$m;my$i=exists$a{lazy}?$a{lazy}:!${$P.':N'};$i or ${$P.':E'}{$n}=\&{$P.$b}and return$m;sub{$#_?$m->(@_):!exists$_[0]{$n}?$_[0]{$n}=$_[0]->$b:$m->(@_)}}};
### Mo/chain.pm ###
 package Mo::chain;my$M="Mo::";
 $VERSION=0.39;
 *{$M.'chain::e'}=sub{my($P,$e,$o)=@_;$o->{chain}=sub{my($m,$n,%a)=@_;$a{chain}or return$m;sub{$#_?($m->(@_),return$_[0]):$m->(@_)}}};
### Mo/coerce.pm ###
 package Mo::coerce;my$M="Mo::";
 $VERSION=0.39;
 *{$M.'coerce::e'}=sub{my($P,$e,$o)=@_;$o->{coerce}=sub{my($m,$n,%a)=@_;$a{coerce}or return$m;sub{$#_?$m->($_[0],$a{coerce}->($_[1])):$m->(@_)}};my$C=$e->{new}||*{$M.Object::new}{CODE};$e->{new}=sub{my$s=$C->(@_);$s->$_($s->{$_})for keys%$s;$s}};
### Mo/default.pm ###
 package Mo::default;my$M="Mo::";
 $VERSION=0.39;
 *{$M.'default::e'}=sub{my($P,$e,$o)=@_;$o->{default}=sub{my($m,$n,%a)=@_;exists$a{default}or return$m;my($d,$r)=$a{default};my$g='HASH'eq($r=ref$d)?sub{+{%$d}}:'ARRAY'eq$r?sub{[@$d]}:'CODE'eq$r?$d:sub{$d};my$i=exists$a{lazy}?$a{lazy}:!${$P.':N'};$i or ${$P.':E'}{$n}=$g and return$m;sub{$#_?$m->(@_):!exists$_[0]{$n}?$_[0]{$n}=$g->(@_):$m->(@_)}}};
### Mo/exporter.pm ###
 package Mo::exporter;my$M="Mo::";
 $VERSION=0.39;
 *{$M.'exporter::e'}=sub{my($P)=@_;if(@{$M.EXPORT}){*{$P.$_}=\&{$M.$_}for@{$M.EXPORT}}};
### Mo/import.pm ###
 package Mo::import;my$M="Mo::";
 $VERSION=0.39;
 my$i=\&import;*{$M.import}=sub{(@_==2 and not$_[1])?pop@_:@_==1?push@_,grep!/import/,@f:();goto&$i};
### Mo/importer.pm ###
 package Mo::importer;my$M="Mo::";
 $VERSION=0.39;
 *{$M.'importer::e'}=sub{my($P,$e,$o,$f)=@_;(my$pkg=$P)=~s/::$//;&{$P.'importer'}($pkg,@$f)if defined&{$P.'importer'}};
### Mo/is.pm ###
 package Mo::is;$M="Mo::";
 $VERSION=0.39;
 *{$M.'is::e'}=sub{my($P,$e,$o)=@_;$o->{is}=sub{my($m,$n,%a)=@_;$a{is}or return$m;sub{$#_&&$a{is}eq'ro'&&caller ne'Mo::coerce'?die$n.' is ro':$m->(@_)}}};
### Mo/nonlazy.pm ###
 package Mo::nonlazy;my$M="Mo::";
 $VERSION=0.39;
 *{$M.'nonlazy::e'}=sub{${shift().':N'}=1};
### Mo/option.pm ###
 package Mo::option;my$M="Mo::";
 $VERSION=0.39;
 *{$M.'option::e'}=sub{my($P,$e,$o)=@_;$o->{option}=sub{my($m,$n,%a)=@_;$a{option}or return$m;my$n2=$n;*{$P."read_$n2"}=sub{$_[0]->{$n2}};sub{$#_?$m->(@_):$m->(@_,1);$_[0]}}};
### Mo/required.pm ###
 package Mo::required;my$M="Mo::";
 $VERSION=0.39;
 *{$M.'required::e'}=sub{my($P,$e,$o)=@_;$o->{required}=sub{my($m,$n,%a)=@_;if($a{required}){my$C=*{$P."new"}{CODE}||*{$M.Object::new}{CODE};no warnings 'redefine';*{$P."new"}=sub{my$s=$C->(@_);my%a=@_[1..$#_];die$n." required"if!exists$a{$n};$s}}$m}};
### Mo/xs.pm ###
 package Mo::xs;my$M="Mo::";
 $VERSION=0.39;
 require Class::XSAccessor;*{$M.'xs::e'}=sub{my($P,$e,$o,$f)=@_;$P=~s/::$//;$e->{has}=sub{my($n,%a)=@_;Class::XSAccessor->import(class=>$P,accessors=>{$n=>$n})}if!grep!/^xs$/,@$f};
### Module/Implementation.pm ###
 package Module::Implementation;
 # git description: v0.08-2-gd599347
 $Module::Implementation::VERSION = '0.09';
 
 use strict;
 use warnings;
 
 use Module::Runtime 0.012 qw( require_module );
 use Try::Tiny;
 
 # This is needed for the benefit of Test::CleanNamespaces, which in turn loads
 # Package::Stash, which in turn loads this module and expects a minimum
 # version.
 unless ( exists $Module::Implementation::{VERSION}
     && ${ $Module::Implementation::{VERSION} } ) {
 
     $Module::Implementation::{VERSION} = \42;
 }
 
 my %Implementation;
 
 sub build_loader_sub {
     my $caller = caller();
 
     return _build_loader( $caller, @_ );
 }
 
 sub _build_loader {
     my $package = shift;
     my %args    = @_;
 
     my @implementations = @{ $args{implementations} };
     my @symbols = @{ $args{symbols} || [] };
 
     my $implementation;
     my $env_var = uc $package;
     $env_var =~ s/::/_/g;
     $env_var .= '_IMPLEMENTATION';
 
     return sub {
         my ( $implementation, $loaded ) = _load_implementation(
             $package,
             $ENV{$env_var},
             \@implementations,
         );
 
         $Implementation{$package} = $implementation;
 
         _copy_symbols( $loaded, $package, \@symbols );
 
         return $loaded;
     };
 }
 
 sub implementation_for {
     my $package = shift;
 
     return $Implementation{$package};
 }
 
 sub _load_implementation {
     my $package         = shift;
     my $env_value       = shift;
     my $implementations = shift;
 
     if ($env_value) {
         die "$env_value is not a valid implementation for $package"
             unless grep { $_ eq $env_value } @{$implementations};
 
         my $requested = "${package}::$env_value";
 
         # Values from the %ENV hash are tainted. We know it's safe to untaint
         # this value because the value was one of our known implementations.
         ($requested) = $requested =~ /^(.+)$/;
 
         try {
             require_module($requested);
         }
         catch {
             require Carp;
             Carp::croak("Could not load $requested: $_");
         };
 
         return ( $env_value, $requested );
     }
     else {
         my $err;
         for my $possible ( @{$implementations} ) {
             my $try = "${package}::$possible";
 
             my $ok;
             try {
                 require_module($try);
                 $ok = 1;
             }
             catch {
                 $err .= $_ if defined $_;
             };
 
             return ( $possible, $try ) if $ok;
         }
 
         require Carp;
         if ( defined $err && length $err ) {
             Carp::croak(
                 "Could not find a suitable $package implementation: $err");
         }
         else {
             Carp::croak(
                 'Module::Runtime failed to load a module but did not throw a real error. This should never happen. Something is very broken'
             );
         }
     }
 }
 
 sub _copy_symbols {
     my $from_package = shift;
     my $to_package   = shift;
     my $symbols      = shift;
 
     for my $sym ( @{$symbols} ) {
         my $type = $sym =~ s/^([\$\@\%\&\*])// ? $1 : '&';
 
         my $from = "${from_package}::$sym";
         my $to   = "${to_package}::$sym";
 
         {
             no strict 'refs';
             no warnings 'once';
 
             # Copied from Exporter
             *{$to}
                 = $type eq '&' ? \&{$from}
                 : $type eq '$' ? \${$from}
                 : $type eq '@' ? \@{$from}
                 : $type eq '%' ? \%{$from}
                 : $type eq '*' ? *{$from}
                 : die
                 "Can't copy symbol from $from_package to $to_package: $type$sym";
         }
     }
 }
 
 1;
 
 # ABSTRACT: Loads one of several alternate underlying implementations for a module
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Module::Implementation - Loads one of several alternate underlying implementations for a module
 
 =head1 VERSION
 
 version 0.09
 
 =head1 SYNOPSIS
 
   package Foo::Bar;
 
   use Module::Implementation;
 
   BEGIN {
       my $loader = Module::Implementation::build_loader_sub(
           implementations => [ 'XS',  'PurePerl' ],
           symbols         => [ 'run', 'check' ],
       );
 
       $loader->();
   }
 
   package Consumer;
 
   # loads the first viable implementation
   use Foo::Bar;
 
 =head1 DESCRIPTION
 
 This module abstracts out the process of choosing one of several underlying
 implementations for a module. This can be used to provide XS and pure Perl
 implementations of a module, or it could be used to load an implementation for
 a given OS or any other case of needing to provide multiple implementations.
 
 This module is only useful when you know all the implementations ahead of
 time. If you want to load arbitrary implementations then you probably want
 something like a plugin system, not this module.
 
 =head1 API
 
 This module provides two subroutines, neither of which are exported.
 
 =head2 Module::Implementation::build_loader_sub(...)
 
 This subroutine takes the following arguments.
 
 =over 4
 
 =item * implementations
 
 This should be an array reference of implementation names. Each name should
 correspond to a module in the caller's namespace.
 
 In other words, using the example in the L</SYNOPSIS>, this module will look
 for the C<Foo::Bar::XS> and C<Foo::Bar::PurePerl> modules.
 
 This argument is required.
 
 =item * symbols
 
 A list of symbols to copy from the implementation package to the calling
 package.
 
 These can be prefixed with a variable type: C<$>, C<@>, C<%>, C<&>, or
 C<*)>. If no prefix is given, the symbol is assumed to be a subroutine.
 
 This argument is optional.
 
 =back
 
 This subroutine I<returns> the implementation loader as a sub reference.
 
 It is up to you to call this loader sub in your code.
 
 I recommend that you I<do not> call this loader in an C<import()> sub. If a
 caller explicitly requests no imports, your C<import()> sub will not be run at
 all, which can cause weird breakage.
 
 =head2 Module::Implementation::implementation_for($package)
 
 Given a package name, this subroutine returns the implementation that was
 loaded for the package. This is not a full package name, just the suffix that
 identifies the implementation. For the L</SYNOPSIS> example, this subroutine
 would be called as C<Module::Implementation::implementation_for('Foo::Bar')>,
 and it would return "XS" or "PurePerl".
 
 =head1 HOW THE IMPLEMENTATION LOADER WORKS
 
 The implementation loader works like this ...
 
 First, it checks for an C<%ENV> var specifying the implementation to load. The
 env var is based on the package name which loads the implementations. The
 C<::> package separator is replaced with C<_>, and made entirely
 upper-case. Finally, we append "_IMPLEMENTATION" to this name.
 
 So in our L</SYNOPSIS> example, the corresponding C<%ENV> key would be
 C<FOO_BAR_IMPLEMENTATION>.
 
 If this is set, then the loader will B<only> try to load this one
 implementation.
 
 If the env var requests an implementation which doesn't match one of the
 implementations specified when the loader was created, an error is thrown.
 
 If this one implementation fails to load then loader throws an error. This is
 useful for testing. You can request a specific implementation in a test file
 by writing something like this:
 
   BEGIN { $ENV{FOO_BAR_IMPLEMENTATION} = 'XS' }
   use Foo::Bar;
 
 If the environment variable is I<not> set, then the loader simply tries the
 implementations originally passed to C<Module::Implementation>. The
 implementations are tried in the order in which they were originally passed.
 
 The loader will use the first implementation that loads without an error. It
 will copy any requested symbols from this implementation.
 
 If none of the implementations can be loaded, then the loader throws an
 exception.
 
 The loader returns the name of the package it loaded.
 
 =head1 AUTHOR
 
 Dave Rolsky <autarch@urth.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is Copyright (c) 2014 by Dave Rolsky.
 
 This is free software, licensed under:
 
   The Artistic License 2.0 (GPL Compatible)
 
 =cut
### Module/List.pm ###
 =head1 NAME
 
 Module::List - module `directory' listing
 
 =head1 SYNOPSIS
 
 	use Module::List qw(list_modules);
 
 	$id_modules = list_modules("Data::ID::",
 			{ list_modules => 1});
 	$prefixes = list_modules("",
 			{ list_prefixes => 1, recurse => 1 });
 
 =head1 DESCRIPTION
 
 This module deals with the examination of the namespace of Perl modules.
 The contents of the module namespace is split across several physical
 directory trees, but this module hides that detail, providing instead
 a view of the abstract namespace.
 
 =cut
 
 package Module::List;
 
 { use 5.006; }
 use warnings;
 use strict;
 
 use Carp qw(croak);
 use File::Spec;
 use IO::Dir 1.03;
 
 our $VERSION = "0.003";
 
 use parent "Exporter";
 our @EXPORT_OK = qw(list_modules);
 
 =head1 FUNCTIONS
 
 =over
 
 =item list_modules(PREFIX, OPTIONS)
 
 This function generates a listing of the contents of part of the module
 namespace.  The part of the namespace under the module name prefix PREFIX
 is examined, and information about it returned as specified by OPTIONS.
 
 Module names are handled by this function in standard bareword syntax.
 They are always fully-qualified; isolated name components are never used.
 A module name prefix is the part of a module name that comes before
 a component of the name, and so either ends with "::" or is the empty
 string.
 
 OPTIONS is a reference to a hash, the elements of which specify what is
 to be returned.  The options are:
 
 =over
 
 =item list_modules
 
 Truth value, default false.  If true, return names of modules in the relevant
 part of the namespace.
 
 =item list_prefixes
 
 Truth value, default false.  If true, return module name prefixes in the
 relevant part of the namespace.  Note that prefixes are returned if the
 corresponding directory exists, even if there is nothing in it.
 
 =item list_pod
 
 Truth value, default false.  If true, return names of POD documentation
 files that are in the module namespace.
 
 =item trivial_syntax
 
 Truth value, default false.  If false, only valid bareword names are
 permitted.  If true, bareword syntax is ignored, and any "::"-separated
 name that can be turned into a correct filename by interpreting name
 components as filename components is permitted.  This is of no use in
 listing actual Perl modules, because the illegal names can't be used in
 Perl, but some programs such as B<perldoc> use a "::"-separated name for
 the sake of appearance without really using bareword syntax.  The loosened
 syntax applies both to the names returned and to the I<PREFIX> parameter.
 
 Precisely, the `trivial syntax' is that each "::"-separated component
 cannot be "." or "..", cannot contain "::" or "/", and (except for the
 final component of a leaf name) cannot end with ":".  This is precisely
 what is required to achieve a unique interconvertible "::"-separated path
 syntax on Unix.  This criterion might change in the future on non-Unix
 systems, where the filename syntax differs.
 
 =item recurse
 
 Truth value, default false.  If false, only names at the next level down
 from PREFIX (having one more component) are returned.  If true, names
 at all lower levels are returned.
 
 =item use_pod_dir
 
 Truth value, default false.  If false, POD documentation files are
 expected to be in the same directory that the corresponding module file
 would be in.  If true, POD files may also be in a subdirectory of that
 named "C<pod>".  (Any POD files in such a subdirectory will therefore be
 visible under two module names, one treating the "C<pod>" subdirectory
 level as part of the module name.)
 
 =back
 
 Note that the default behaviour, if an empty options hash is supplied, is
 to return nothing.  You I<must> specify what kind of information you want.
 
 The function returns a reference to a hash, the keys of which are the
 names of interest.  The value associated with each of these keys is undef.
 
 =cut
 
 sub list_modules($$) {
 	my($prefix, $options) = @_;
 	my $trivial_syntax = $options->{trivial_syntax};
 	my($root_leaf_rx, $root_notleaf_rx);
 	my($notroot_leaf_rx, $notroot_notleaf_rx);
 	if($trivial_syntax) {
 		$root_leaf_rx = $notroot_leaf_rx = qr#:?(?:[^/:]+:)*[^/:]+:?#;
 		$root_notleaf_rx = $notroot_notleaf_rx =
 			qr#:?(?:[^/:]+:)*[^/:]+#;
 	} else {
 		$root_leaf_rx = $root_notleaf_rx = qr/[a-zA-Z_][0-9a-zA-Z_]*/;
 		$notroot_leaf_rx = $notroot_notleaf_rx = qr/[0-9a-zA-Z_]+/;
 	}
 	croak "bad module name prefix `$prefix'"
 		unless $prefix =~ /\A(?:${root_notleaf_rx}::
 					 (?:${notroot_notleaf_rx}::)*)?\z/x &&
 			 $prefix !~ /(?:\A|[^:]::)\.\.?::/;
 	my $list_modules = $options->{list_modules};
 	my $list_prefixes = $options->{list_prefixes};
 	my $list_pod = $options->{list_pod};
 	my $use_pod_dir = $options->{use_pod_dir};
 	return {} unless $list_modules || $list_prefixes || $list_pod;
 	my $recurse = $options->{recurse};
 	my @prefixes = ($prefix);
 	my %seen_prefixes;
 	my %results;
 	while(@prefixes) {
 		my $prefix = pop(@prefixes);
 		my @dir_suffix = split(/::/, $prefix);
 		my $module_rx =
 			$prefix eq "" ? $root_leaf_rx : $notroot_leaf_rx;
 		my $pm_rx = qr/\A($module_rx)\.pmc?\z/;
 		my $pod_rx = qr/\A($module_rx)\.pod\z/;
 		my $dir_rx =
 			$prefix eq "" ? $root_notleaf_rx : $notroot_notleaf_rx;
 		$dir_rx = qr/\A$dir_rx\z/;
 		foreach my $incdir (@INC) {
 			my $dir = File::Spec->catdir($incdir, @dir_suffix);
 			my $dh = IO::Dir->new($dir) or next;
 			while(defined(my $entry = $dh->read)) {
 				if(($list_modules && $entry =~ $pm_rx) ||
 						($list_pod &&
 							$entry =~ $pod_rx)) {
 					$results{$prefix.$1} = undef;
 				} elsif(($list_prefixes || $recurse) &&
 						File::Spec
 							->no_upwards($entry) &&
 						$entry =~ $dir_rx &&
 						-d File::Spec->catdir($dir,
 							$entry)) {
 					my $newpfx = $prefix.$entry."::";
 					next if exists $seen_prefixes{$newpfx};
 					$results{$newpfx} = undef
 						if $list_prefixes;
 					push @prefixes, $newpfx if $recurse;
 				}
 			}
 			next unless $list_pod && $use_pod_dir;
 			$dir = File::Spec->catdir($dir, "pod");
 			$dh = IO::Dir->new($dir) or next;
 			while(defined(my $entry = $dh->read)) {
 				if($entry =~ $pod_rx) {
 					$results{$prefix.$1} = undef;
 				}
 			}
 		}
 	}
 	return \%results;
 }
 
 =back
 
 =head1 SEE ALSO
 
 L<Module::Runtime>
 
 =head1 AUTHOR
 
 Andrew Main (Zefram) <zefram@fysh.org>
 
 =head1 COPYRIGHT
 
 Copyright (C) 2004, 2006, 2009, 2011
 Andrew Main (Zefram) <zefram@fysh.org>
 
 =head1 LICENSE
 
 This module is free software; you can redistribute it and/or modify it
 under the same terms as Perl itself.
 
 =cut
 
 1;
### Module/Path/More.pm ###
 package Module::Path::More;
 
 our $DATE = '2015-09-03'; # DATE
 our $VERSION = '0.29'; # VERSION
 
 use 5.010001;
 use strict;
 use warnings;
 
 require Exporter;
 our @ISA       = qw(Exporter);
 our @EXPORT_OK = qw(module_path pod_path);
 
 my $SEPARATOR;
 
 our %SPEC;
 
 $SPEC{':package'} = {
     v => 1.1,
     summary => 'Get path to locally installed Perl module',
 };
 
 BEGIN {
     if ($^O =~ /^(dos|os2)/i) {
         $SEPARATOR = '\\';
     } elsif ($^O =~ /^MacOS/i) {
         $SEPARATOR = ':';
     } else {
         $SEPARATOR = '/';
     }
 }
 
 $SPEC{module_path} = {
     v => 1.1,
     summary => 'Get path to locally installed Perl module',
     description => <<'_',
 
 Search `@INC` (reference entries are skipped) and return path(s) to Perl module
 files with the requested name.
 
 This function is like the one from `Module::Path`, except with a different
 interface and more options (finding all matches instead of the first, the option
 of not absolutizing paths, finding `.pmc` & `.pod` files, finding module
 prefixes).
 
 _
     args => {
         module => {
             summary => 'Module name to search',
             schema  => 'str*',
             req     => 1,
             pos     => 0,
         },
         find_pm => {
             summary => 'Whether to find .pm files',
             schema  => 'bool',
             default => 1,
         },
         find_pmc => {
             summary => 'Whether to find .pmc files',
             schema  => 'bool',
             default => 1,
         },
         find_pod => {
             summary => 'Whether to find .pod files',
             schema  => 'bool',
             default => 0,
         },
         find_prefix => {
             summary => 'Whether to find module prefixes',
             schema  => 'bool',
             default => 0,
         },
         all => {
             summary => 'Return all results instead of just the first',
             schema  => 'bool',
             default => 0,
         },
         abs => {
             summary => 'Whether to return absolute paths',
             schema  => 'bool',
             default => 0,
         },
     },
     result => {
         schema => ['any' => of => ['str*', ['array*' => of => 'str*']]],
     },
     result_naked => 1,
 };
 sub module_path {
     my %args = @_;
 
     my $module = $args{module} or die "Please specify module";
 
     $args{abs}         //= 0;
     $args{all}         //= 0;
     $args{find_pm}     //= 1;
     $args{find_pmc}    //= 1;
     $args{find_pod}    //= 0;
     $args{find_prefix} //= 0;
 
     require Cwd if $args{abs};
 
     my @res;
     my $add = sub { push @res, $args{abs} ? Cwd::abs_path($_[0]) : $_[0] };
 
     my $relpath;
 
     ($relpath = $module) =~ s/::/$SEPARATOR/g;
     $relpath =~ s/\.(pm|pmc|pod)\z//i;
 
     foreach my $dir (@INC) {
         next if not defined($dir);
         next if ref($dir);
 
         my $prefix = $dir . $SEPARATOR . $relpath;
         if ($args{find_pmc}) {
             my $file = $prefix . ".pmc";
             if (-f $file) {
                 $add->($file);
                 last unless $args{all};
             }
         }
         if ($args{find_pm}) {
             my $file = $prefix . ".pm";
             if (-f $file) {
                 $add->($file);
                 last unless $args{all};
             }
         }
         if ($args{find_pod}) {
             my $file = $prefix . ".pod";
             if (-f $file) {
                 $add->($file);
                 last unless $args{all};
             }
         }
         if ($args{find_prefix}) {
             if (-d $prefix) {
                 $add->($prefix);
                 last unless $args{all};
             }
         }
     }
 
     if ($args{all}) {
         return \@res;
     } else {
         return @res ? $res[0] : undef;
     }
 }
 
 $SPEC{pod_path} = {
     v => 1.1,
     summary => 'Get path to locally installed POD',
     description => <<'_',
 
 This is a shortcut for:
 
     module_path(%args, find_pm=>0, find_pmc=>0, find_pod=>1, find_prefix=>0)
 
 _
     args => {
         module => {
             summary => 'Module name to search',
             schema  => 'str*',
             req     => 1,
             pos     => 0,
         },
         all => {
             summary => 'Return all results instead of just the first',
             schema  => 'bool',
             default => 0,
         },
         abs => {
             summary => 'Whether to return absolute paths',
             schema  => 'bool',
             default => 0,
         },
     },
     result => {
         schema => ['any' => of => ['str*', ['array*' => of => 'str*']]],
     },
     result_naked => 1,
 };
 sub pod_path {
     module_path(@_, find_pm=>0, find_pmc=>0, find_pod=>1, find_prefix=>0);
 }
 
 1;
 # ABSTRACT: Get path to locally installed Perl module
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Module::Path::More - Get path to locally installed Perl module
 
 =head1 VERSION
 
 This document describes version 0.29 of Module::Path::More (from Perl distribution Module-Path-More), released on 2015-09-03.
 
 =head1 SYNOPSIS
 
  use Module::Path::More qw(module_path pod_path);
 
  $path = module_path(module=>'Test::More');
  if (defined($path)) {
    print "Test::More found at $path\n";
  } else {
    print "Danger Will Robinson!\n";
  }
 
  # find all found modules, as well as .pmc and .pod files
  @path = module_path(module=>'Foo::Bar', all=>1, find_pmc=>1, find_pod=>1);
 
  # just a shortcut for module_path(module=>'Foo',
  #                                 find_pm=>0, find_pmc=>0, find_pod=>1);
  $path = pod_path(module=>'Foo');
 
 =head1 DESCRIPTION
 
 Module::Path::More provides a function, C<module_path()>, which will find where
 a module (or module prefix, or .pod file) is installed locally. (There is also
 another function C<pod_path()> which is just a convenience wrapper.)
 
 It works by looking in all the directories in @INC for an appropriately named
 file. If module is C<Foo::Bar>, will search for C<Foo/Bar.pm>, C<Foo/Bar.pmc>
 (if C<find_pmc> argument is true), C<Foo/Bar> directory (if C<find_prefix>
 argument is true), or C<Foo/Bar.pod> (if C<find_pod> argument is true).
 
 Caveats: Obviously this only works where the module you're after has its own
 C<.pm> file. If a file defines multiple packages, this won't work. This also
 won't find any modules that are being loaded in some special way, for example
 using a code reference in C<@INC>, as described in C<require> in L<perlfunc>.
 
 To check whether a module is available/loadable, it's generally better to use
 something like:
 
  if (eval { require Some::Module; 1 }) {
      # module is available
  }
 
 because this works with fatpacking or any other C<@INC> hook that might be
 installed. If you use:
 
  if (module_path(module => "Some::Module")) {
      # module is available
  }
 
 then it only works if the module is locatable in the filesystem. But on the
 other hand this method can avoid actual loading of the module.
 
 =head1 FUNCTIONS
 
 
 =head2 module_path(%args) -> str|array[str]
 
 Get path to locally installed Perl module.
 
 Search C<@INC> (reference entries are skipped) and return path(s) to Perl module
 files with the requested name.
 
 This function is like the one from C<Module::Path>, except with a different
 interface and more options (finding all matches instead of the first, the option
 of not absolutizing paths, finding C<.pmc> & C<.pod> files, finding module
 prefixes).
 
 Arguments ('*' denotes required arguments):
 
 =over 4
 
 =item * B<abs> => I<bool> (default: 0)
 
 Whether to return absolute paths.
 
 =item * B<all> => I<bool> (default: 0)
 
 Return all results instead of just the first.
 
 =item * B<find_pm> => I<bool> (default: 1)
 
 Whether to find .pm files.
 
 =item * B<find_pmc> => I<bool> (default: 1)
 
 Whether to find .pmc files.
 
 =item * B<find_pod> => I<bool> (default: 0)
 
 Whether to find .pod files.
 
 =item * B<find_prefix> => I<bool> (default: 0)
 
 Whether to find module prefixes.
 
 =item * B<module>* => I<str>
 
 Module name to search.
 
 =back
 
 Return value:  (str|array[str])
 
 
 =head2 pod_path(%args) -> str|array[str]
 
 Get path to locally installed POD.
 
 This is a shortcut for:
 
  module_path(%args, find_pm=>0, find_pmc=>0, find_pod=>1, find_prefix=>0)
 
 Arguments ('*' denotes required arguments):
 
 =over 4
 
 =item * B<abs> => I<bool> (default: 0)
 
 Whether to return absolute paths.
 
 =item * B<all> => I<bool> (default: 0)
 
 Return all results instead of just the first.
 
 =item * B<module>* => I<str>
 
 Module name to search.
 
 =back
 
 Return value:  (str|array[str])
 
 =head1 SEE ALSO
 
 L<Module::Path>. Module::Path::More is actually a fork of Module::Path.
 Module::Path::More contains features that are not (or have not been accepted) in
 the original module, namely: finding all matches instead of the first found
 match, and finding C<.pmc/.pod> in addition to .pm files. B<Note that the
 interface is different> (Module::Path::More accepts hash/named arguments) so the
 two modules are not drop-in replacements for each other. Also, note that by
 default Module::Path::More does B<not> do an C<abs_path()> to each file it
 finds. I think this module's choice (not doing abs_path) is a more sensible
 default, because usually there is no actual need to do so and doing abs_path()
 or resolving symlinks will sometimes fail or expose filesystem quirks that we
 might not want to deal with at all. However, if you want to do abs_path, you can
 do so by setting C<abs> option to true.
 
 Command-line utility is not included in this distribution, unlike L<mpath> in
 C<Module-Path>. However, you can use L<pmpath> from C<App-PMUtils> which uses
 this module.
 
 References:
 
 =over
 
 =item * L<https://github.com/neilbowers/Module-Path/issues/6>
 
 =item * L<https://github.com/neilbowers/Module-Path/issues/7>
 
 =item * L<https://github.com/neilbowers/Module-Path/issues/10>
 
 =item * L<https://rt.cpan.org/Public/Bug/Display.html?id=100979>
 
 =back
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Module-Path-More>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Module-Path-More>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Module-Path-More>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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
### Module/Runtime.pm ###
 =head1 NAME
 
 Module::Runtime - runtime module handling
 
 =head1 SYNOPSIS
 
 	use Module::Runtime qw(
 		$module_name_rx is_module_name check_module_name
 		module_notional_filename require_module
 	);
 
 	if($module_name =~ /\A$module_name_rx\z/o) { ...
 	if(is_module_name($module_name)) { ...
 	check_module_name($module_name);
 
 	$notional_filename = module_notional_filename($module_name);
 	require_module($module_name);
 
 	use Module::Runtime qw(use_module use_package_optimistically);
 
 	$bi = use_module("Math::BigInt", 1.31)->new("1_234");
 	$widget = use_package_optimistically("Local::Widget")->new;
 
 	use Module::Runtime qw(
 		$top_module_spec_rx $sub_module_spec_rx
 		is_module_spec check_module_spec
 		compose_module_name
 	);
 
 	if($spec =~ /\A$top_module_spec_rx\z/o) { ...
 	if($spec =~ /\A$sub_module_spec_rx\z/o) { ...
 	if(is_module_spec("Standard::Prefix", $spec)) { ...
 	check_module_spec("Standard::Prefix", $spec);
 
 	$module_name =
 		compose_module_name("Standard::Prefix", $spec);
 
 =head1 DESCRIPTION
 
 The functions exported by this module deal with runtime handling of
 Perl modules, which are normally handled at compile time.  This module
 avoids using any other modules, so that it can be used in low-level
 infrastructure.
 
 The parts of this module that work with module names apply the same syntax
 that is used for barewords in Perl source.  In principle this syntax
 can vary between versions of Perl, and this module applies the syntax of
 the Perl on which it is running.  In practice the usable syntax hasn't
 changed yet.  There's some intent for Unicode module names to be supported
 in the future, but this hasn't yet amounted to any consistent facility.
 
 The functions of this module whose purpose is to load modules include
 workarounds for three old Perl core bugs regarding C<require>.  These
 workarounds are applied on any Perl version where the bugs exist, except
 for a case where one of the bugs cannot be adequately worked around in
 pure Perl.
 
 =head2 Module name syntax
 
 The usable module name syntax has not changed from Perl 5.000 up to
 Perl 5.19.8.  The syntax is composed entirely of ASCII characters.
 From Perl 5.6 onwards there has been some attempt to allow the use of
 non-ASCII Unicode characters in Perl source, but it was fundamentally
 broken (like the entirety of Perl 5.6's Unicode handling) and remained
 pretty much entirely unusable until it got some attention in the Perl
 5.15 series.  Although Unicode is now consistently accepted by the
 parser in some places, it remains broken for module names.  Furthermore,
 there has not yet been any work on how to map Unicode module names into
 filenames, so in that respect also Unicode module names are unusable.
 
 The module name syntax is, precisely: the string must consist of one or
 more segments separated by C<::>; each segment must consist of one or more
 identifier characters (ASCII alphanumerics plus "_"); the first character
 of the string must not be a digit.  Thus "C<IO::File>", "C<warnings>",
 and "C<foo::123::x_0>" are all valid module names, whereas "C<IO::>"
 and "C<1foo::bar>" are not.  C<'> separators are not permitted by this
 module, though they remain usable in Perl source, being translated to
 C<::> in the parser.
 
 =head2 Core bugs worked around
 
 The first bug worked around is core bug [perl #68590], which causes
 lexical state in one file to leak into another that is C<require>d/C<use>d
 from it.  This bug is present from Perl 5.6 up to Perl 5.10, and is
 fixed in Perl 5.11.0.  From Perl 5.9.4 up to Perl 5.10.0 no satisfactory
 workaround is possible in pure Perl.  The workaround means that modules
 loaded via this module don't suffer this pollution of their lexical
 state.  Modules loaded in other ways, or via this module on the Perl
 versions where the pure Perl workaround is impossible, remain vulnerable.
 The module L<Lexical::SealRequireHints> provides a complete workaround
 for this bug.
 
 The second bug worked around causes some kinds of failure in module
 loading, principally compilation errors in the loaded module, to be
 recorded in C<%INC> as if they were successful, so later attempts to load
 the same module immediately indicate success.  This bug is present up
 to Perl 5.8.9, and is fixed in Perl 5.9.0.  The workaround means that a
 compilation error in a module loaded via this module won't be cached as
 a success.  Modules loaded in other ways remain liable to produce bogus
 C<%INC> entries, and if a bogus entry exists then it will mislead this
 module if it is used to re-attempt loading.
 
 The third bug worked around causes the wrong context to be seen at
 file scope of a loaded module, if C<require> is invoked in a location
 that inherits context from a higher scope.  This bug is present up to
 Perl 5.11.2, and is fixed in Perl 5.11.3.  The workaround means that
 a module loaded via this module will always see the correct context.
 Modules loaded in other ways remain vulnerable.
 
 =cut
 
 package Module::Runtime;
 
 # Don't "use 5.006" here, because Perl 5.15.6 will load feature.pm if
 # the version check is done that way.
 BEGIN { require 5.006; }
 # Don't "use warnings" here, to avoid dependencies.  Do standardise the
 # warning status by lexical override; unfortunately the only safe bitset
 # to build in is the empty set, equivalent to "no warnings".
 BEGIN { ${^WARNING_BITS} = ""; }
 # Don't "use strict" here, to avoid dependencies.
 
 our $VERSION = "0.014";
 
 # Don't use Exporter here, to avoid dependencies.
 our @EXPORT_OK = qw(
 	$module_name_rx is_module_name is_valid_module_name check_module_name
 	module_notional_filename require_module
 	use_module use_package_optimistically
 	$top_module_spec_rx $sub_module_spec_rx
 	is_module_spec is_valid_module_spec check_module_spec
 	compose_module_name
 );
 my %export_ok = map { ($_ => undef) } @EXPORT_OK;
 sub import {
 	my $me = shift;
 	my $callpkg = caller(0);
 	my $errs = "";
 	foreach(@_) {
 		if(exists $export_ok{$_}) {
 			# We would need to do "no strict 'refs'" here
 			# if we had enabled strict at file scope.
 			if(/\A\$(.*)\z/s) {
 				*{$callpkg."::".$1} = \$$1;
 			} else {
 				*{$callpkg."::".$_} = \&$_;
 			}
 		} else {
 			$errs .= "\"$_\" is not exported by the $me module\n";
 		}
 	}
 	if($errs ne "") {
 		die "${errs}Can't continue after import errors ".
 			"at @{[(caller(0))[1]]} line @{[(caller(0))[2]]}.\n";
 	}
 }
 
 # Logic duplicated from Params::Classify.  Duplicating it here avoids
 # an extensive and potentially circular dependency graph.
 sub _is_string($) {
 	my($arg) = @_;
 	return defined($arg) && ref(\$arg) eq "SCALAR";
 }
 
 =head1 REGULAR EXPRESSIONS
 
 These regular expressions do not include any anchors, so to check
 whether an entire string matches a syntax item you must supply the
 anchors yourself.
 
 =over
 
 =item $module_name_rx
 
 Matches a valid Perl module name in bareword syntax.
 
 =cut
 
 our $module_name_rx = qr/[A-Z_a-z][0-9A-Z_a-z]*(?:::[0-9A-Z_a-z]+)*/;
 
 =item $top_module_spec_rx
 
 Matches a module specification for use with L</compose_module_name>,
 where no prefix is being used.
 
 =cut
 
 my $qual_module_spec_rx =
 	qr#(?:/|::)[A-Z_a-z][0-9A-Z_a-z]*(?:(?:/|::)[0-9A-Z_a-z]+)*#;
 
 my $unqual_top_module_spec_rx =
 	qr#[A-Z_a-z][0-9A-Z_a-z]*(?:(?:/|::)[0-9A-Z_a-z]+)*#;
 
 our $top_module_spec_rx = qr/$qual_module_spec_rx|$unqual_top_module_spec_rx/o;
 
 =item $sub_module_spec_rx
 
 Matches a module specification for use with L</compose_module_name>,
 where a prefix is being used.
 
 =cut
 
 my $unqual_sub_module_spec_rx = qr#[0-9A-Z_a-z]+(?:(?:/|::)[0-9A-Z_a-z]+)*#;
 
 our $sub_module_spec_rx = qr/$qual_module_spec_rx|$unqual_sub_module_spec_rx/o;
 
 =back
 
 =head1 FUNCTIONS
 
 =head2 Basic module handling
 
 =over
 
 =item is_module_name(ARG)
 
 Returns a truth value indicating whether I<ARG> is a plain string
 satisfying Perl module name syntax as described for L</$module_name_rx>.
 
 =cut
 
 sub is_module_name($) { _is_string($_[0]) && $_[0] =~ /\A$module_name_rx\z/o }
 
 =item is_valid_module_name(ARG)
 
 Deprecated alias for L</is_module_name>.
 
 =cut
 
 *is_valid_module_name = \&is_module_name;
 
 =item check_module_name(ARG)
 
 Check whether I<ARG> is a plain string
 satisfying Perl module name syntax as described for L</$module_name_rx>.
 Return normally if it is, or C<die> if it is not.
 
 =cut
 
 sub check_module_name($) {
 	unless(&is_module_name) {
 		die +(_is_string($_[0]) ? "`$_[0]'" : "argument").
 			" is not a module name\n";
 	}
 }
 
 =item module_notional_filename(NAME)
 
 Generates a notional relative filename for a module, which is used in
 some Perl core interfaces.
 The I<NAME> is a string, which should be a valid module name (one or
 more C<::>-separated segments).  If it is not a valid name, the function
 C<die>s.
 
 The notional filename for the named module is generated and returned.
 This filename is always in Unix style, with C</> directory separators
 and a C<.pm> suffix.  This kind of filename can be used as an argument to
 C<require>, and is the key that appears in C<%INC> to identify a module,
 regardless of actual local filename syntax.
 
 =cut
 
 sub module_notional_filename($) {
 	&check_module_name;
 	my($name) = @_;
 	$name =~ s!::!/!g;
 	return $name.".pm";
 }
 
 =item require_module(NAME)
 
 This is essentially the bareword form of C<require>, in runtime form.
 The I<NAME> is a string, which should be a valid module name (one or
 more C<::>-separated segments).  If it is not a valid name, the function
 C<die>s.
 
 The module specified by I<NAME> is loaded, if it hasn't been already,
 in the manner of the bareword form of C<require>.  That means that a
 search through C<@INC> is performed, and a byte-compiled form of the
 module will be used if available.
 
 The return value is as for C<require>.  That is, it is the value returned
 by the module itself if the module is loaded anew, or C<1> if the module
 was already loaded.
 
 =cut
 
 # Don't "use constant" here, to avoid dependencies.
 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};
 }
 
 BEGIN { if(_WORK_AROUND_BROKEN_MODULE_STATE) { eval q{
 	sub Module::Runtime::__GUARD__::DESTROY {
 		delete $INC{$_[0]->[0]} if @{$_[0]};
 	}
 	1;
 }; die $@ if $@ ne ""; } }
 
 sub require_module($) {
 	# Localise %^H to work around [perl #68590], where the bug exists
 	# and this is a satisfactory workaround.  The bug consists of
 	# %^H state leaking into each required module, polluting the
 	# module's lexical state.
 	local %^H if _WORK_AROUND_HINT_LEAKAGE;
 	if(_WORK_AROUND_BROKEN_MODULE_STATE) {
 		my $notional_filename = &module_notional_filename;
 		my $guard = bless([ $notional_filename ],
 				"Module::Runtime::__GUARD__");
 		my $result = CORE::require($notional_filename);
 		pop @$guard;
 		return $result;
 	} else {
 		return scalar(CORE::require(&module_notional_filename));
 	}
 }
 
 =back
 
 =head2 Structured module use
 
 =over
 
 =item use_module(NAME[, VERSION])
 
 This is essentially C<use> in runtime form, but without the importing
 feature (which is fundamentally a compile-time thing).  The I<NAME> is
 handled just like in C<require_module> above: it must be a module name,
 and the named module is loaded as if by the bareword form of C<require>.
 
 If a I<VERSION> is specified, the C<VERSION> method of the loaded module is
 called with the specified I<VERSION> as an argument.  This normally serves to
 ensure that the version loaded is at least the version required.  This is
 the same functionality provided by the I<VERSION> parameter of C<use>.
 
 On success, the name of the module is returned.  This is unlike
 L</require_module>, and is done so that the entire call to L</use_module>
 can be used as a class name to call a constructor, as in the example in
 the synopsis.
 
 =cut
 
 sub use_module($;$) {
 	my($name, $version) = @_;
 	require_module($name);
 	$name->VERSION($version) if @_ >= 2;
 	return $name;
 }
 
 =item use_package_optimistically(NAME[, VERSION])
 
 This is an analogue of L</use_module> for the situation where there is
 uncertainty as to whether a package/class is defined in its own module
 or by some other means.  It attempts to arrange for the named package to
 be available, either by loading a module or by doing nothing and hoping.
 
 An attempt is made to load the named module (as if by the bareword form
 of C<require>).  If the module cannot be found then it is assumed that
 the package was actually already loaded by other means, and no error
 is signalled.  That's the optimistic bit.
 
 This is mostly the same operation that is performed by the L<base> pragma
 to ensure that the specified base classes are available.  The behaviour
 of L<base> was simplified in version 2.18, and later improved in version
 2.20, and on both occasions this function changed to match.
 
 If a I<VERSION> is specified, the C<VERSION> method of the loaded package is
 called with the specified I<VERSION> as an argument.  This normally serves
 to ensure that the version loaded is at least the version required.
 On success, the name of the package is returned.  These aspects of the
 function work just like L</use_module>.
 
 =cut
 
 sub use_package_optimistically($;$) {
 	my($name, $version) = @_;
 	my $fn = module_notional_filename($name);
 	eval { local $SIG{__DIE__}; require_module($name); };
 	die $@ if $@ ne "" &&
 		($@ !~ /\ACan't locate \Q$fn\E .+ at \Q@{[__FILE__]}\E line/s ||
 		 $@ =~ /^Compilation\ failed\ in\ require
 			 \ at\ \Q@{[__FILE__]}\E\ line/xm);
 	$name->VERSION($version) if @_ >= 2;
 	return $name;
 }
 
 =back
 
 =head2 Module name composition
 
 =over
 
 =item is_module_spec(PREFIX, SPEC)
 
 Returns a truth value indicating
 whether I<SPEC> is valid input for L</compose_module_name>.
 See below for what that entails.  Whether a I<PREFIX> is supplied affects
 the validity of I<SPEC>, but the exact value of the prefix is unimportant,
 so this function treats I<PREFIX> as a truth value.
 
 =cut
 
 sub is_module_spec($$) {
 	my($prefix, $spec) = @_;
 	return _is_string($spec) &&
 		$spec =~ ($prefix ? qr/\A$sub_module_spec_rx\z/o :
 				    qr/\A$top_module_spec_rx\z/o);
 }
 
 =item is_valid_module_spec(PREFIX, SPEC)
 
 Deprecated alias for L</is_module_spec>.
 
 =cut
 
 *is_valid_module_spec = \&is_module_spec;
 
 =item check_module_spec(PREFIX, SPEC)
 
 Check whether I<SPEC> is valid input for L</compose_module_name>.
 Return normally if it is, or C<die> if it is not.
 
 =cut
 
 sub check_module_spec($$) {
 	unless(&is_module_spec) {
 		die +(_is_string($_[1]) ? "`$_[1]'" : "argument").
 			" is not a module specification\n";
 	}
 }
 
 =item compose_module_name(PREFIX, SPEC)
 
 This function is intended to make it more convenient for a user to specify
 a Perl module name at runtime.  Users have greater need for abbreviations
 and context-sensitivity than programmers, and Perl module names get a
 little unwieldy.  I<SPEC> is what the user specifies, and this function
 translates it into a module name in standard form, which it returns.
 
 I<SPEC> has syntax approximately that of a standard module name: it
 should consist of one or more name segments, each of which consists
 of one or more identifier characters.  However, C</> is permitted as a
 separator, in addition to the standard C<::>.  The two separators are
 entirely interchangeable.
 
 Additionally, if I<PREFIX> is not C<undef> then it must be a module
 name in standard form, and it is prefixed to the user-specified name.
 The user can inhibit the prefix addition by starting I<SPEC> with a
 separator (either C</> or C<::>).
 
 =cut
 
 sub compose_module_name($$) {
 	my($prefix, $spec) = @_;
 	check_module_name($prefix) if defined $prefix;
 	&check_module_spec;
 	if($spec =~ s#\A(?:/|::)##) {
 		# OK
 	} else {
 		$spec = $prefix."::".$spec if defined $prefix;
 	}
 	$spec =~ s#/#::#g;
 	return $spec;
 }
 
 =back
 
 =head1 BUGS
 
 On Perl versions 5.7.2 to 5.8.8, if C<require> is overridden by the
 C<CORE::GLOBAL> mechanism, it is likely to break the heuristics used by
 L</use_package_optimistically>, making it signal an error for a missing
 module rather than assume that it was already loaded.  From Perl 5.8.9
 onwards, and on 5.7.1 and earlier, this module can avoid being confused
 by such an override.  On the affected versions, a C<require> override
 might be installed by L<Lexical::SealRequireHints>, if something requires
 its bugfix but for some reason its XS implementation isn't available.
 
 =head1 SEE ALSO
 
 L<Lexical::SealRequireHints>,
 L<base>,
 L<perlfunc/require>,
 L<perlfunc/use>
 
 =head1 AUTHOR
 
 Andrew Main (Zefram) <zefram@fysh.org>
 
 =head1 COPYRIGHT
 
 Copyright (C) 2004, 2006, 2007, 2009, 2010, 2011, 2012, 2014
 Andrew Main (Zefram) <zefram@fysh.org>
 
 =head1 LICENSE
 
 This module is free software; you can redistribute it and/or modify it
 under the same terms as Perl itself.
 
 =cut
 
 1;
### Monkey/Patch/Action.pm ###
 package Monkey::Patch::Action;
 
 use 5.010;
 use warnings;
 use strict;
 
 our $VERSION = '0.04'; # VERSION
 
 use Monkey::Patch::Action::Handle;
 
 use Exporter qw(import);
 our @EXPORT_OK = qw(patch_package);
 our %EXPORT_TAGS = (all => \@EXPORT_OK);
 
 sub patch_package {
     my ($package, $subname, $action, $code, @extra) = @_;
 
     die "Please specify action" unless $action;
     if ($action eq 'delete') {
         die "code not needed for 'delete' action" if $code;
     } else {
         die "Please specify code" unless $code;
     }
 
     my $name = "$package\::$subname";
     my $type;
     if ($action eq 'add') {
         die "Adding $name: must not already exist" if defined(&$name);
         $type = 'sub';
     } elsif ($action eq 'replace') {
         die "Replacing $name: must already exist" unless defined(&$name);
         $type = 'sub';
     } elsif ($action eq 'add_or_replace') {
         $type = 'sub';
     } elsif ($action eq 'wrap') {
         die "Wrapping $name: must already exist" unless defined(&$name);
         $type = 'wrap';
     } elsif ($action eq 'delete') {
         $type = 'delete';
     } else {
         die "Unknown action '$action', please use either ".
             "wrap/add/replace/add_or_replace/delete";
     }
 
     my @caller = caller(0);
 
     Monkey::Patch::Action::Handle->new(
         package => $package,
         subname => $subname,
         extra   => \@extra,
         patcher => \@caller,
         code    => $code,
 
         -type   => $type,
     );
 }
 
 1;
 # ABSTRACT: Wrap/add/replace/delete subs from other package (with restore)
 
 
 __END__
 =pod
 
 =head1 NAME
 
 Monkey::Patch::Action - Wrap/add/replace/delete subs from other package (with restore)
 
 =head1 VERSION
 
 version 0.04
 
 =head1 SYNOPSIS
 
  use Monkey::Patch::Action qw(patch_package);
 
  package Foo;
  sub sub1  { say "Foo's sub1" }
  sub sub2  { say "Foo's sub2, args=", join(",", @_) }
  sub meth1 { my $self = shift; say "Foo's meth1" }
 
  package Bar;
  our @ISA = qw(Foo);
 
  package main;
  my $h; # handle object
  my $foo = Foo->new;
  my $bar = Bar->new;
 
  # replacing a subroutine
  $h = patch_package('Foo', 'sub1', 'replace', sub { "qux" });
  Foo::sub1(); # says "qux"
  undef $h;
  Foo::sub1(); # says "Foo's sub1"
 
  # adding a subroutine
  $h = patch_package('Foo', 'sub3', 'add', sub { "qux" });
  Foo::sub3(); # says "qux"
  undef $h;
  Foo::sub3(); # dies
 
  # deleting a subroutine
  $h = patch_package('Foo', 'sub2', 'delete');
  Foo::sub2(); # dies
  undef $h;
  Foo::sub2(); # says "Foo's sub2, args="
 
  # wrapping a subroutine
  $h = patch_package('Foo', 'sub2', 'wrap',
      sub {
          my $ctx = shift;
          say "wrapping $ctx->{package}::$ctx->{subname}";
          $ctx->{orig}->(@_);
      }
  );
  Foo::sub2(1,2,3); # says "wrapping Foo::sub2" then "Foo's sub2, args=1,2,3"
  undef $h;
  Foo::sub2(1,2,3); # says "Foo's sub2, args=1,2,3"
 
  # stacking patches (note: can actually be unapplied in random order)
  my ($h2, $h3);
  $h  = patch_package('Foo', 'sub1', 'replace', sub { "qux" });
  Foo::sub1(); # says "qux"
  $h2 = patch_package('Foo', 'sub1', 'delete');
  Foo::sub1(); # dies
  $h3 = patch_package('Foo', 'sub1', 'replace', sub { "quux" });
  Foo::sub1(); # says "quux"
  undef $h3;
  Foo::sub1(); # dies
  undef $h2;
  Foo::sub1(); # says "qux"
  undef $h;
  Foo::sub1(); # says "Foo's sub1"
 
 =head1 DESCRIPTION
 
 Monkey-patching is the act of modifying a package at runtime: adding a
 subroutine/method, replacing/deleting/wrapping another, etc. Perl makes it easy
 to do that, for example:
 
  # add a subroutine
  *{"Target::sub1"} = sub { ... };
 
  # another way, can be done from any file
  package Target;
  sub sub2 { ... }
 
  # delete a subroutine
  undef *{"Target::sub3"};
 
 This module makes things even easier by helping you apply a stack of patches and
 unapply them later in flexible order.
 
 =head1 FUNCTIONS
 
 =head2 patch_package($package, $subname, $action, $code, @extra) => HANDLE
 
 Patch C<$package>'s subroutine named C<$subname>. C<$action> is either:
 
 =over 4
 
 =item * C<wrap>
 
 C<$subname> must already exist. C<code> is required.
 
 Your code receives a context hash as its first argument, followed by any
 arguments the subroutine would have normally gotten. Context hash contains:
 C<orig> (the original subroutine that is being wrapped), C<subname>, C<package>,
 C<extra>.
 
 =item * C<add>
 
 C<subname> must not already exist. C<code> is required.
 
 =item * C<replace>
 
 C<subname> must already exist. C<code> is required.
 
 =item * C<add_or_replace>
 
 C<code> is required.
 
 =item * C<delete>
 
 C<code> is not needed.
 
 =back
 
 Die on error.
 
 Function returns a handle object. As soon as you lose the value of the handle
 (by calling in void context, assigning over the variable, undeffing the
 variable, letting it go out of scope, etc), the patch is unapplied.
 
 Patches can be unapplied in random order, but unapplying a patch where the next
 patch is a wrapper can lead to an error. Example: first patch (P1) adds a
 subroutine and second patch (P2) wraps it. If P1 is unapplied before P2, the
 subroutine is now no longer there, and P2 no longer works. Unapplying P1 after
 P2 works, of course.
 
 =head1 FAQ
 
 =head2 Differences with Monkey::Patch?
 
 This module is based on the wonderful L<Monkey::Patch> by Paul Driver. The
 differences are:
 
 =over 4
 
 =item *
 
 This module adds the ability to add/replace/delete subroutines instead of just
 wrapping them.
 
 =item *
 
 Interface to patch_package() is slightly different (see previous item for the
 cause).
 
 =item *
 
 Using this module, the wrapper receives a context hash instead of just the
 original subroutine.
 
 =item *
 
 Monkey::Patch adds convenience for patching classes and objects. To keep things
 simple, no such convenience is currently provided by this module.
 C<patch_package()> *can* patch classes and objects as well (see the next FAQ
 entry).
 
 =back
 
 =head2 How to patch classes and objects?
 
 Patching a class is basically the same as patching any other package, since Perl
 implements a class with a package. One thing to note is that to call a parent's
 method inside your wrapper code, instead of:
 
  $self->SUPER::methname(...)
 
 you need to do something like:
 
  use SUPER;
  SUPER::find_parent(ref($self), 'methname')->methname(...)
 
 Patching an object is also basically patching a class/package, because Perl does
 not have per-object method like Ruby. But if you just want to provide a modified
 behavior for a certain object only, you can do something like:
 
  patch_package($package, $methname, 'wrap',
  sub {
      my $ctx = shift;
      my $self = shift;
 
      my $obj = $ctx->{extra}[0];
      no warnings 'numeric';
      if ($obj == $self) {
          # do stuff
      }
      $ctx->{orig}->(@_);
  }, $obj);
 
 =head1 SEE ALSO
 
 L<Monkey::Patch>
 
 =head1 AUTHOR
 
 Steven Haryanto <stevenharyanto@gmail.com>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2012 by Steven Haryanto.
 
 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
 
### Monkey/Patch/Action/Handle.pm ###
 package Monkey::Patch::Action::Handle;
 
 use 5.010;
 use strict;
 use warnings;
 
 use Scalar::Util qw(weaken);
 use Sub::Delete;
 
 our $VERSION = '0.04'; # VERSION
 
 my %stacks;
 
 sub __find_previous {
     my ($stack, $code) = @_;
     state $empty = sub {};
 
     for my $i (1..$#$stack) {
         if ($stack->[$i][1] == $code) {
             return $stack->[$i-1][2] // $stack->[$i-1][1];
         }
     }
     $empty;
 }
 
 sub new {
     my ($class, %args) = @_;
 
     my $type = $args{-type};
     delete $args{-type};
 
     my $code = $args{code};
 
     my $name = "$args{package}::$args{subname}";
     my $stack;
     if (!$stacks{$name}) {
         $stacks{$name} = [];
         push @{$stacks{$name}}, [sub => \&$name] if defined(&$name);
     }
     $stack = $stacks{$name};
 
     my $self = bless \%args, $class;
 
     no strict 'refs';
     no warnings 'redefine';
     if ($type eq 'sub') {
         push @$stack, [$type => $code];
         *$name = $code;
     } elsif ($type eq 'delete') {
         $code = sub {};
         $args{code} = $code;
         push @$stack, [$type, $code];
         delete_sub $name;
     } elsif ($type eq 'wrap') {
         weaken($self);
         my $wrapper = sub {
             my $ctx = {
                 package => $self->{package},
                 subname => $self->{subname},
                 extra   => $self->{extra},
                 orig    => __find_previous($stack, $self->{code}),
             };
             unshift @_, $ctx;
             goto &{$self->{code}};
         };
         push @$stack, [$type => $code => $wrapper];
         *$name = $wrapper;
     }
 
     $self;
 }
 
 sub DESTROY {
     my $self = shift;
 
     my $name  = "$self->{package}::$self->{subname}";
     my $stack = $stacks{$name};
     my $code  = $self->{code};
 
     for my $i (0..$#$stack) {
         if($stack->[$i][1] == $code) {
             if ($stack->[$i+1]) {
                 # check conflict
                 if ($stack->[$i+1][0] eq 'wrap' &&
                         ($i == 0 || $stack->[$i-1][0] eq 'delete')) {
                     my $p = $self->{patcher};
                     warn "Warning: unapplying patch to $name ".
                         "(applied in $p->[1]:$p->[2]) before a wrapping patch";
                 }
             }
 
             no strict 'refs';
             if ($i == @$stack-1) {
                 if ($i) {
                     no warnings 'redefine';
                     if ($stack->[$i-1][0] eq 'delete') {
                         delete_sub $name;
                     } else {
                         *$name = $stack->[$i-1][2] // $stack->[$i-1][1];
                     }
                 } else {
                     delete_sub $name;
                 }
             }
             splice @$stack, $i, 1;
             last;
         }
     }
 }
 
 1;
 
 
 __END__
 =pod
 
 =head1 NAME
 
 Monkey::Patch::Action::Handle
 
 =head1 VERSION
 
 version 0.04
 
 =for Pod::Coverage .*
 
 =head1 AUTHOR
 
 Steven Haryanto <stevenharyanto@gmail.com>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2012 by Steven Haryanto.
 
 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
 
### Moo.pm ###
 package Moo;
 
 use Moo::_strictures;
 use Moo::_Utils;
 
 our $VERSION = '2.000002';
 $VERSION = eval $VERSION;
 
 require Moo::sification;
 Moo::sification->import;
 
 our %MAKERS;
 
 sub _install_tracked {
   my ($target, $name, $code) = @_;
   $MAKERS{$target}{exports}{$name} = $code;
   _install_coderef "${target}::${name}" => "Moo::${name}" => $code;
 }
 
 sub import {
   my $target = caller;
   my $class = shift;
   _set_loaded(caller);
 
   strict->import;
   warnings->import;
 
   if ($INC{'Role/Tiny.pm'} and Role::Tiny->is_role($target)) {
     die "Cannot import Moo into a role";
   }
   $MAKERS{$target} ||= {};
   _install_tracked $target => extends => sub {
     $class->_set_superclasses($target, @_);
     $class->_maybe_reset_handlemoose($target);
     return;
   };
   _install_tracked $target => with => sub {
     require Moo::Role;
     Moo::Role->apply_roles_to_package($target, @_);
     $class->_maybe_reset_handlemoose($target);
   };
   _install_tracked $target => has => sub {
     my $name_proto = shift;
     my @name_proto = ref $name_proto eq 'ARRAY' ? @$name_proto : $name_proto;
     if (@_ % 2 != 0) {
       require Carp;
       Carp::croak("Invalid options for " . join(', ', map "'$_'", @name_proto)
         . " attribute(s): even number of arguments expected, got " . scalar @_)
     }
     my %spec = @_;
     foreach my $name (@name_proto) {
       # Note that when multiple attributes specified, each attribute
       # needs a separate \%specs hashref
       my $spec_ref = @name_proto > 1 ? +{%spec} : \%spec;
       $class->_constructor_maker_for($target)
             ->register_attribute_specs($name, $spec_ref);
       $class->_accessor_maker_for($target)
             ->generate_method($target, $name, $spec_ref);
       $class->_maybe_reset_handlemoose($target);
     }
     return;
   };
   foreach my $type (qw(before after around)) {
     _install_tracked $target => $type => sub {
       require Class::Method::Modifiers;
       _install_modifier($target, $type, @_);
       return;
     };
   }
   return if $MAKERS{$target}{is_class}; # already exported into this package
   my $stash = _getstash($target);
   my @not_methods = map { *$_{CODE}||() } grep !ref($_), values %$stash;
   @{$MAKERS{$target}{not_methods}={}}{@not_methods} = @not_methods;
   $MAKERS{$target}{is_class} = 1;
   {
     no strict 'refs';
     @{"${target}::ISA"} = do {
       require Moo::Object; ('Moo::Object');
     } unless @{"${target}::ISA"};
   }
   if ($INC{'Moo/HandleMoose.pm'}) {
     Moo::HandleMoose::inject_fake_metaclass_for($target);
   }
 }
 
 sub unimport {
   my $target = caller;
   _unimport_coderefs($target, $MAKERS{$target});
 }
 
 sub _set_superclasses {
   my $class = shift;
   my $target = shift;
   foreach my $superclass (@_) {
     _load_module($superclass);
     if ($INC{'Role/Tiny.pm'} && Role::Tiny->is_role($superclass)) {
       require Carp;
       Carp::croak("Can't extend role '$superclass'");
     }
   }
   # Can't do *{...} = \@_ or 5.10.0's mro.pm stops seeing @ISA
   @{*{_getglob("${target}::ISA")}{ARRAY}} = @_;
   if (my $old = delete $Moo::MAKERS{$target}{constructor}) {
     $old->assert_constructor;
     delete _getstash($target)->{new};
     Moo->_constructor_maker_for($target)
        ->register_attribute_specs(%{$old->all_attribute_specs});
   }
   elsif (!$target->isa('Moo::Object')) {
     Moo->_constructor_maker_for($target);
   }
   no warnings 'once'; # piss off. -- mst
   $Moo::HandleMoose::MOUSE{$target} = [
     grep defined, map Mouse::Util::find_meta($_), @_
   ] if Mouse::Util->can('find_meta');
 }
 
 sub _maybe_reset_handlemoose {
   my ($class, $target) = @_;
   if ($INC{"Moo/HandleMoose.pm"}) {
     Moo::HandleMoose::maybe_reinject_fake_metaclass_for($target);
   }
 }
 
 sub _accessor_maker_for {
   my ($class, $target) = @_;
   return unless $MAKERS{$target};
   $MAKERS{$target}{accessor} ||= do {
     my $maker_class = do {
       if (my $m = do {
             require Sub::Defer;
             if (my $defer_target =
                   (Sub::Defer::defer_info($target->can('new'))||[])->[0]
               ) {
               my ($pkg) = ($defer_target =~ /^(.*)::[^:]+$/);
               $MAKERS{$pkg} && $MAKERS{$pkg}{accessor};
             } else {
               undef;
             }
           }) {
         ref($m);
       } else {
         require Method::Generate::Accessor;
         'Method::Generate::Accessor'
       }
     };
     $maker_class->new;
   }
 }
 
 sub _constructor_maker_for {
   my ($class, $target) = @_;
   return unless $MAKERS{$target};
   $MAKERS{$target}{constructor} ||= do {
     require Method::Generate::Constructor;
     require Sub::Defer;
 
     my %construct_opts = (
       package => $target,
       accessor_generator => $class->_accessor_maker_for($target),
       subconstructor_handler => (
         '      if ($Moo::MAKERS{$class}) {'."\n"
         .'        if ($Moo::MAKERS{$class}{constructor}) {'."\n"
         .'          return $class->'.$target.'::SUPER::new(@_);'."\n"
         .'        }'."\n"
         .'        '.$class.'->_constructor_maker_for($class);'."\n"
         .'        return $class->new(@_)'.";\n"
         .'      } elsif ($INC{"Moose.pm"} and my $meta = Class::MOP::get_metaclass_by_name($class)) {'."\n"
         .'        return $meta->new_object('."\n"
         .'          $class->can("BUILDARGS") ? $class->BUILDARGS(@_)'."\n"
         .'                      : $class->Moo::Object::BUILDARGS(@_)'."\n"
         .'        );'."\n"
         .'      }'."\n"
       ),
     );
 
     my $con;
     my @isa = @{mro::get_linear_isa($target)};
     shift @isa;
     if (my ($parent_new) = grep { *{_getglob($_.'::new')}{CODE} } @isa) {
       if ($parent_new eq 'Moo::Object') {
         # no special constructor needed
       }
       elsif (my $makers = $MAKERS{$parent_new}) {
         $con = $makers->{constructor};
         $construct_opts{construction_string} = $con->construction_string
           if $con;
       }
       elsif ($parent_new->can('BUILDALL')) {
         $construct_opts{construction_builder} = sub {
           my $inv = $target->can('BUILDARGS') ? '' : 'Moo::Object::';
           'do {'
           .'  my $args = $class->'.$inv.'BUILDARGS(@_);'
           .'  $args->{__no_BUILD__} = 1;'
           .'  $class->'.$target.'::SUPER::new($args);'
           .'}'
         };
       }
       else {
         $construct_opts{construction_builder} = sub {
           '$class->'.$target.'::SUPER::new('
             .($target->can('FOREIGNBUILDARGS') ?
               '$class->FOREIGNBUILDARGS(@_)' : '@_')
             .')'
         };
       }
     }
     ($con ? ref($con) : 'Method::Generate::Constructor')
       ->new(%construct_opts)
       ->install_delayed
       ->register_attribute_specs(%{$con?$con->all_attribute_specs:{}})
   }
 }
 
 sub _concrete_methods_of {
   my ($me, $role) = @_;
   my $makers = $MAKERS{$role};
   # grab role symbol table
   my $stash = _getstash($role);
   # reverse so our keys become the values (captured coderefs) in case
   # they got copied or re-used since
   my $not_methods = { reverse %{$makers->{not_methods}||{}} };
   +{
     # grab all code entries that aren't in the not_methods list
     map {
       my $code = *{$stash->{$_}}{CODE};
       ( ! $code or exists $not_methods->{$code} ) ? () : ($_ => $code)
     } grep !ref($stash->{$_}), keys %$stash
   };
 }
 
 1;
 __END__
 
 =pod
 
 =encoding utf-8
 
 =head1 NAME
 
 Moo - Minimalist Object Orientation (with Moose compatibility)
 
 =head1 SYNOPSIS
 
  package Cat::Food;
 
  use Moo;
  use strictures 2;
  use namespace::clean;
 
  sub feed_lion {
    my $self = shift;
    my $amount = shift || 1;
 
    $self->pounds( $self->pounds - $amount );
  }
 
  has taste => (
    is => 'ro',
  );
 
  has brand => (
    is  => 'ro',
    isa => sub {
      die "Only SWEET-TREATZ supported!" unless $_[0] eq 'SWEET-TREATZ'
    },
  );
 
  has pounds => (
    is  => 'rw',
    isa => sub { die "$_[0] is too much cat food!" unless $_[0] < 15 },
  );
 
  1;
 
 And elsewhere:
 
  my $full = Cat::Food->new(
     taste  => 'DELICIOUS.',
     brand  => 'SWEET-TREATZ',
     pounds => 10,
  );
 
  $full->feed_lion;
 
  say $full->pounds;
 
 =head1 DESCRIPTION
 
 C<Moo> is an extremely light-weight Object Orientation system. It allows one to
 concisely define objects and roles with a convenient syntax that avoids the
 details of Perl's object system.  C<Moo> contains a subset of L<Moose> and is
 optimised for rapid startup.
 
 C<Moo> avoids depending on any XS modules to allow for simple deployments.  The
 name C<Moo> is based on the idea that it provides almost -- but not quite --
 two thirds of L<Moose>.
 
 Unlike L<Mouse> this module does not aim at full compatibility with
 L<Moose>'s surface syntax, preferring instead to provide full interoperability
 via the metaclass inflation capabilities described in L</MOO AND MOOSE>.
 
 For a full list of the minor differences between L<Moose> and L<Moo>'s surface
 syntax, see L</INCOMPATIBILITIES WITH MOOSE>.
 
 =head1 WHY MOO EXISTS
 
 If you want a full object system with a rich Metaprotocol, L<Moose> is
 already wonderful.
 
 But if you don't want to use L<Moose>, you may not want "less metaprotocol"
 like L<Mouse> offers, but you probalby want "no metaprotocol", which is what
 Moo provides. C<Moo> is ideal for some situations where deployment or startup
 time precludes using L<Moose> and L<Mouse>:
 
 =over 2
 
 =item a command line or CGI script where fast startup is essential
 
 =item code designed to be deployed as a single file via L<App::FatPacker>
 
 =item a CPAN module that may be used by others in the above situations
 
 =back
 
 C<Moo> maintains transparent compatibility with L<Moose> so if you install and
 load L<Moose> you can use Moo clases and roles in L<Moose> code without
 modification.
 
 Moo -- Minimal Object Orientation -- aims to make it smooth to upgrade to
 L<Moose> when you need more than the minimal features offered by Moo.
 
 =head1 MOO AND MOOSE
 
 If L<Moo> detects L<Moose> being loaded, it will automatically register
 metaclasses for your L<Moo> and L<Moo::Role> packages, so you should be able
 to use them in L<Moose> code without modification.
 
 L<Moo> will also create L<Moose type constraints|Moose::Manual::Types> for
 L<Moo> classes and roles, so that in Moose classes C<< isa => 'MyMooClass' >>
 and C<< isa => 'MyMooRole' >> work the same as for L<Moose> classes and roles.
 
 Extending a L<Moose> class or consuming a L<Moose::Role> will also work.
 
 Extending a L<Mouse> class or consuming a L<Mouse::Role> will also work. But
 note that we don't provide L<Mouse> metaclasses or metaroles so the other way
 around doesn't work. This feature exists for L<Any::Moose> users porting to
 L<Moo>; enabling L<Mouse> users to use L<Moo> classes is not a priority for us.
 
 This means that there is no need for anything like L<Any::Moose> for Moo
 code - Moo and Moose code should simply interoperate without problem. To
 handle L<Mouse> code, you'll likely need an empty Moo role or class consuming
 or extending the L<Mouse> stuff since it doesn't register true L<Moose>
 metaclasses like L<Moo> does.
 
 If you need to disable the metaclass creation, add:
 
   no Moo::sification;
 
 to your code before Moose is loaded, but bear in mind that this switch is
 global and turns the mechanism off entirely so don't put this in library code.
 
 =head1 MOO AND CLASS::XSACCESSOR
 
 If a new enough version of L<Class::XSAccessor> is available, it
 will be used to generate simple accessors, readers, and writers for
 better performance.  Simple accessors are those without lazy defaults,
 type checks/coercions, or triggers.  Readers and writers generated
 by L<Class::XSAccessor> will behave slightly differently: they will
 reject attempts to call them with the incorrect number of parameters.
 
 =head1 MOO VERSUS ANY::MOOSE
 
 L<Any::Moose> will load L<Mouse> normally, and L<Moose> in a program using
 L<Moose> - which theoretically allows you to get the startup time of L<Mouse>
 without disadvantaging L<Moose> users.
 
 Sadly, this doesn't entirely work, since the selection is load order dependent
 - L<Moo>'s metaclass inflation system explained above in L</MOO AND MOOSE> is
 significantly more reliable.
 
 So if you want to write a CPAN module that loads fast or has only pure perl
 dependencies but is also fully usable by L<Moose> users, you should be using
 L<Moo>.
 
 For a full explanation, see the article
 L<http://shadow.cat/blog/matt-s-trout/moo-versus-any-moose> which explains
 the differing strategies in more detail and provides a direct example of
 where L<Moo> succeeds and L<Any::Moose> fails.
 
 =head1 IMPORTED METHODS
 
 =head2 new
 
  Foo::Bar->new( attr1 => 3 );
 
 or
 
  Foo::Bar->new({ attr1 => 3 });
 
 =head2 BUILDARGS
 
  sub BUILDARGS {
    my ( $class, @args ) = @_;
 
    unshift @args, "attr1" if @args % 2 == 1;
 
    return { @args };
  }
 
  Foo::Bar->new( 3 );
 
 The default implementation of this method accepts a hash or hash reference of
 named parameters. If it receives a single argument that isn't a hash reference
 it throws an error.
 
 You can override this method in your class to handle other types of options
 passed to the constructor.
 
 This method should always return a hash reference of named options.
 
 =head2 FOREIGNBUILDARGS
 
 If you are inheriting from a non-Moo class, the arguments passed to the parent
 class constructor can be manipulated by defining a C<FOREIGNBUILDARGS> method.
 It will receive the same arguments as C<BUILDARGS>, and should return a list
 of arguments to pass to the parent class constructor.
 
 =head2 BUILD
 
 Define a C<BUILD> method on your class and the constructor will automatically
 call the C<BUILD> method from parent down to child after the object has
 been instantiated.  Typically this is used for object validation or possibly
 logging.
 
 =head2 DEMOLISH
 
 If you have a C<DEMOLISH> method anywhere in your inheritance hierarchy,
 a C<DESTROY> method is created on first object construction which will call
 C<< $instance->DEMOLISH($in_global_destruction) >> for each C<DEMOLISH>
 method from child upwards to parents.
 
 Note that the C<DESTROY> method is created on first construction of an object
 of your class in order to not add overhead to classes without C<DEMOLISH>
 methods; this may prove slightly surprising if you try and define your own.
 
 =head2 does
 
  if ($foo->does('Some::Role1')) {
    ...
  }
 
 Returns true if the object composes in the passed role.
 
 =head1 IMPORTED SUBROUTINES
 
 =head2 extends
 
  extends 'Parent::Class';
 
 Declares a base class. Multiple superclasses can be passed for multiple
 inheritance but please consider using L<roles|Moo::Role> instead.  The class
 will be loaded but no errors will be triggered if the class can't be found and
 there are already subs in the class.
 
 Calling extends more than once will REPLACE your superclasses, not add to
 them like 'use base' would.
 
 =head2 with
 
  with 'Some::Role1';
 
 or
 
  with 'Some::Role1', 'Some::Role2';
 
 Composes one or more L<Moo::Role> (or L<Role::Tiny>) roles into the current
 class.  An error will be raised if these roles cannot be composed because they
 have conflicting method definitions.  The roles will be loaded using the same
 mechansim as C<extends> uses.
 
 =head2 has
 
  has attr => (
    is => 'ro',
  );
 
 Declares an attribute for the class.
 
  package Foo;
  use Moo;
  has 'attr' => (
    is => 'ro'
  );
 
  package Bar;
  use Moo;
  extends 'Foo';
  has '+attr' => (
    default => sub { "blah" },
  );
 
 Using the C<+> notation, it's possible to override an attribute.
 
 The options for C<has> are as follows:
 
 =over 2
 
 =item * C<is>
 
 B<required>, may be C<ro>, C<lazy>, C<rwp> or C<rw>.
 
 C<ro> stands for "read-only" and generates an accessor that dies if you attempt
 to write to it - i.e.  a getter only - by defaulting C<reader> to the name of
 the attribute.
 
 C<lazy> generates a reader like C<ro>, but also sets C<lazy> to 1 and
 C<builder> to C<_build_${attribute_name}> to allow on-demand generated
 attributes.  This feature was my attempt to fix my incompetence when
 originally designing C<lazy_build>, and is also implemented by
 L<MooseX::AttributeShortcuts>. There is, however, nothing to stop you
 using C<lazy> and C<builder> yourself with C<rwp> or C<rw> - it's just that
 this isn't generally a good idea so we don't provide a shortcut for it.
 
 C<rwp> stands for "read-write protected" and generates a reader like C<ro>, but
 also sets C<writer> to C<_set_${attribute_name}> for attributes that are
 designed to be written from inside of the class, but read-only from outside.
 This feature comes from L<MooseX::AttributeShortcuts>.
 
 C<rw> stands for "read-write" and generates a normal getter/setter by
 defaulting the C<accessor> to the name of the attribute specified.
 
 =item * C<isa>
 
 Takes a coderef which is used to validate the attribute.  Unlike L<Moose>, Moo
 does not include a basic type system, so instead of doing C<< isa => 'Num' >>,
 one should do
 
  use Scalar::Util qw(looks_like_number);
  ...
  isa => sub {
    die "$_[0] is not a number!" unless looks_like_number $_[0]
  },
 
 Note that the return value for C<isa> is discarded. Only if the sub dies does
 type validation fail.
 
 L<Sub::Quote aware|/SUB QUOTE AWARE>
 
 Since L<Moo> does B<not> run the C<isa> check before C<coerce> if a coercion
 subroutine has been supplied, C<isa> checks are not structural to your code
 and can, if desired, be omitted on non-debug builds (although if this results
 in an uncaught bug causing your program to break, the L<Moo> authors guarantee
 nothing except that you get to keep both halves).
 
 If you want L<Moose> compatible or L<MooseX::Types> style named types, look at
 L<Type::Tiny>.
 
 To cause your C<isa> entries to be automatically mapped to named
 L<Moose::Meta::TypeConstraint> objects (rather than the default behaviour
 of creating an anonymous type), set:
 
   $Moo::HandleMoose::TYPE_MAP{$isa_coderef} = sub {
     require MooseX::Types::Something;
     return MooseX::Types::Something::TypeName();
   };
 
 Note that this example is purely illustrative; anything that returns a
 L<Moose::Meta::TypeConstraint> object or something similar enough to it to
 make L<Moose> happy is fine.
 
 =item * C<coerce>
 
 Takes a coderef which is meant to coerce the attribute.  The basic idea is to
 do something like the following:
 
  coerce => sub {
    $_[0] % 2 ? $_[0] : $_[0] + 1
  },
 
 Note that L<Moo> will always execute your coercion: this is to permit
 C<isa> entries to be used purely for bug trapping, whereas coercions are
 always structural to your code. We do, however, apply any supplied C<isa>
 check after the coercion has run to ensure that it returned a valid value.
 
 L<Sub::Quote aware|/SUB QUOTE AWARE>
 
 If the C<isa> option is a blessed object providing a C<coerce> or
 C<coercion> method, then the C<coerce> option may be set to just C<1>.
 
 =item * C<handles>
 
 Takes a string
 
   handles => 'RobotRole'
 
 Where C<RobotRole> is a L<role|Moo::Role> that defines an interface which
 becomes the list of methods to handle.
 
 Takes a list of methods
 
  handles => [ qw( one two ) ]
 
 Takes a hashref
 
  handles => {
    un => 'one',
  }
 
 =item * C<trigger>
 
 Takes a coderef which will get called any time the attribute is set. This
 includes the constructor, but not default or built values. The coderef will be
 invoked against the object with the new value as an argument.
 
 If you set this to just C<1>, it generates a trigger which calls the
 C<_trigger_${attr_name}> method on C<$self>. This feature comes from
 L<MooseX::AttributeShortcuts>.
 
 Note that Moose also passes the old value, if any; this feature is not yet
 supported.
 
 L<Sub::Quote aware|/SUB QUOTE AWARE>
 
 =item * C<default>
 
 Takes a coderef which will get called with $self as its only argument to
 populate an attribute if no value for that attribute was supplied to the
 constructor. Alternatively, if the attribute is lazy, C<default> executes when
 the attribute is first retrieved if no value has yet been provided.
 
 If a simple scalar is provided, it will be inlined as a string. Any non-code
 reference (hash, array) will result in an error - for that case instead use
 a code reference that returns the desired value.
 
 Note that if your default is fired during new() there is no guarantee that
 other attributes have been populated yet so you should not rely on their
 existence.
 
 L<Sub::Quote aware|/SUB QUOTE AWARE>
 
 =item * C<predicate>
 
 Takes a method name which will return true if an attribute has a value.
 
 If you set this to just C<1>, the predicate is automatically named
 C<has_${attr_name}> if your attribute's name does not start with an
 underscore, or C<_has_${attr_name_without_the_underscore}> if it does.
 This feature comes from L<MooseX::AttributeShortcuts>.
 
 =item * C<builder>
 
 Takes a method name which will be called to create the attribute - functions
 exactly like default except that instead of calling
 
   $default->($self);
 
 Moo will call
 
   $self->$builder;
 
 The following features come from L<MooseX::AttributeShortcuts>:
 
 If you set this to just C<1>, the builder is automatically named
 C<_build_${attr_name}>.
 
 If you set this to a coderef or code-convertible object, that variable will be
 installed under C<$class::_build_${attr_name}> and the builder set to the same
 name.
 
 =item * C<clearer>
 
 Takes a method name which will clear the attribute.
 
 If you set this to just C<1>, the clearer is automatically named
 C<clear_${attr_name}> if your attribute's name does not start with an
 underscore, or C<_clear_${attr_name_without_the_underscore}> if it does.
 This feature comes from L<MooseX::AttributeShortcuts>.
 
 B<NOTE:> If the attribute is C<lazy>, it will be regenerated from C<default> or
 C<builder> the next time it is accessed. If it is not lazy, it will be C<undef>.
 
 =item * C<lazy>
 
 B<Boolean>.  Set this if you want values for the attribute to be grabbed
 lazily.  This is usually a good idea if you have a L</builder> which requires
 another attribute to be set.
 
 =item * C<required>
 
 B<Boolean>.  Set this if the attribute must be passed on object instantiation.
 
 =item * C<reader>
 
 The name of the method that returns the value of the attribute.  If you like
 Java style methods, you might set this to C<get_foo>
 
 =item * C<writer>
 
 The value of this attribute will be the name of the method to set the value of
 the attribute.  If you like Java style methods, you might set this to
 C<set_foo>.
 
 =item * C<weak_ref>
 
 B<Boolean>.  Set this if you want the reference that the attribute contains to
 be weakened. Use this when circular references, which cause memory leaks, are
 possible.
 
 =item * C<init_arg>
 
 Takes the name of the key to look for at instantiation time of the object.  A
 common use of this is to make an underscored attribute have a non-underscored
 initialization name. C<undef> means that passing the value in on instantiation
 is ignored.
 
 =item * C<moosify>
 
 Takes either a coderef or array of coderefs which is meant to transform the
 given attributes specifications if necessary when upgrading to a Moose role or
 class. You shouldn't need this by default, but is provided as a means of
 possible extensibility.
 
 =back
 
 =head2 before
 
  before foo => sub { ... };
 
 See L<< Class::Method::Modifiers/before method(s) => sub { ... }; >> for full
 documentation.
 
 =head2 around
 
  around foo => sub { ... };
 
 See L<< Class::Method::Modifiers/around method(s) => sub { ... }; >> for full
 documentation.
 
 =head2 after
 
  after foo => sub { ... };
 
 See L<< Class::Method::Modifiers/after method(s) => sub { ... }; >> for full
 documentation.
 
 =head1 SUB QUOTE AWARE
 
 L<Sub::Quote/quote_sub> allows us to create coderefs that are "inlineable,"
 giving us a handy, XS-free speed boost.  Any option that is L<Sub::Quote>
 aware can take advantage of this.
 
 To do this, you can write
 
   use Sub::Quote;
 
   use Moo;
   use namespace::clean;
 
   has foo => (
     is => 'ro',
     isa => quote_sub(q{ die "Not <3" unless $_[0] < 3 })
   );
 
 which will be inlined as
 
   do {
     local @_ = ($_[0]->{foo});
     die "Not <3" unless $_[0] < 3;
   }
 
 or to avoid localizing @_,
 
   has foo => (
     is => 'ro',
     isa => quote_sub(q{ my ($val) = @_; die "Not <3" unless $val < 3 })
   );
 
 which will be inlined as
 
   do {
     my ($val) = ($_[0]->{foo});
     die "Not <3" unless $val < 3;
   }
 
 See L<Sub::Quote> for more information, including how to pass lexical
 captures that will also be compiled into the subroutine.
 
 =head1 CLEANING UP IMPORTS
 
 L<Moo> will not clean up imported subroutines for you; you will have
 to do that manually. The recommended way to do this is to declare your
 imports first, then C<use Moo>, then C<use namespace::clean>.
 Anything imported before L<namespace::clean> will be scrubbed.
 Anything imported or declared after will be still be available.
 
  package Record;
 
  use Digest::MD5 qw(md5_hex);
 
  use Moo;
  use namespace::clean;
 
  has name => (is => 'ro', required => 1);
  has id => (is => 'lazy');
  sub _build_id {
    my ($self) = @_;
    return md5_hex($self->name);
  }
 
  1;
 
 If you were to import C<md5_hex> after L<namespace::clean> you would
 be able to call C<< ->md5_hex() >> on your C<Record> instances (and it
 probably wouldn't do what you expect!).
 
 L<Moo::Role>s behave slightly differently.  Since their methods are
 composed into the consuming class, they can do a little more for you
 automatically.  As long as you declare your imports before calling
 C<use Moo::Role>, those imports and the ones L<Moo::Role> itself
 provides will not be composed into consuming classes so there's usually
 no need to use L<namespace::clean>.
 
 B<On L<namespace::autoclean>:> Older versions of L<namespace::autoclean> would
 inflate Moo classes to full L<Moose> classes, losing the benefits of Moo.  If
 you want to use L<namespace::autoclean> with a Moo class, make sure you are
 using version 0.16 or newer.
 
 =head1 INCOMPATIBILITIES WITH MOOSE
 
 There is no built-in type system.  C<isa> is verified with a coderef; if you
 need complex types, L<Type::Tiny> can provide types, type libraries, and
 will work seamlessly with both L<Moo> and L<Moose>.  L<Type::Tiny> can be
 considered the successor to L<MooseX::Types> and provides a similar API, so
 that you can write
 
   use Types::Standard;
   has days_to_live => (is => 'ro', isa => Int);
 
 C<initializer> is not supported in core since the author considers it to be a
 bad idea and Moose best practices recommend avoiding it. Meanwhile C<trigger> or
 C<coerce> are more likely to be able to fulfill your needs.
 
 There is no meta object.  If you need this level of complexity you need
 L<Moose> - Moo is small because it explicitly does not provide a metaprotocol.
 However, if you load L<Moose>, then
 
   Class::MOP::class_of($moo_class_or_role)
 
 will return an appropriate metaclass pre-populated by L<Moo>.
 
 No support for C<super>, C<override>, C<inner>, or C<augment> - the author
 considers augment to be a bad idea, and override can be translated:
 
   override foo => sub {
     ...
     super();
     ...
   };
 
   around foo => sub {
     my ($orig, $self) = (shift, shift);
     ...
     $self->$orig(@_);
     ...
   };
 
 The C<dump> method is not provided by default. The author suggests loading
 L<Devel::Dwarn> into C<main::> (via C<perl -MDevel::Dwarn ...> for example) and
 using C<$obj-E<gt>$::Dwarn()> instead.
 
 L</default> only supports coderefs and plain scalars, because passing a hash
 or array reference as a default is almost always incorrect since the value is
 then shared between all objects using that default.
 
 C<lazy_build> is not supported; you are instead encouraged to use the
 C<< is => 'lazy' >> option supported by L<Moo> and
 L<MooseX::AttributeShortcuts>.
 
 C<auto_deref> is not supported since the author considers it a bad idea and
 it has been considered best practice to avoid it for some time.
 
 C<documentation> will show up in a L<Moose> metaclass created from your class
 but is otherwise ignored. Then again, L<Moose> ignores it as well, so this
 is arguably not an incompatibility.
 
 Since C<coerce> does not require C<isa> to be defined but L<Moose> does
 require it, the metaclass inflation for coerce alone is a trifle insane
 and if you attempt to subtype the result will almost certainly break.
 
 C<BUILDARGS> is not triggered if your class does not have any attributes.
 Without attributes, C<BUILDARGS> return value would be ignored, so we just
 skip calling the method instead.
 
 Handling of warnings: when you C<use Moo> we enable strict and warnings, in a
 similar way to Moose. The authors recommend the use of C<strictures>, which
 enables FATAL warnings, and several extra pragmas when used in development:
 L<indirect>, L<multidimensional>, and L<bareword::filehandles>.
 
 Additionally, L<Moo> supports a set of attribute option shortcuts intended to
 reduce common boilerplate.  The set of shortcuts is the same as in the L<Moose>
 module L<MooseX::AttributeShortcuts> as of its version 0.009+.  So if you:
 
     package MyClass;
     use Moo;
     use strictures 2;
 
 The nearest L<Moose> invocation would be:
 
     package MyClass;
 
     use Moose;
     use warnings FATAL => "all";
     use MooseX::AttributeShortcuts;
 
 or, if you're inheriting from a non-Moose class,
 
     package MyClass;
 
     use Moose;
     use MooseX::NonMoose;
     use warnings FATAL => "all";
     use MooseX::AttributeShortcuts;
 
 Finally, Moose requires you to call
 
     __PACKAGE__->meta->make_immutable;
 
 at the end of your class to get an inlined (i.e. not horribly slow)
 constructor. Moo does it automatically the first time ->new is called
 on your class. (C<make_immutable> is a no-op in Moo to ease migration.)
 
 An extension L<MooX::late> exists to ease translating Moose packages
 to Moo by providing a more Moose-like interface.
 
 =head1 SUPPORT
 
 Users' IRC: #moose on irc.perl.org
 
 =for :html
 L<(click for instant chatroom login)|http://chat.mibbit.com/#moose@irc.perl.org>
 
 Development and contribution IRC: #web-simple on irc.perl.org
 
 =for :html
 L<(click for instant chatroom login)|http://chat.mibbit.com/#web-simple@irc.perl.org>
 
 Bugtracker: L<https://rt.cpan.org/Public/Dist/Display.html?Name=Moo>
 
 Git repository: L<git://github.com/moose/Moo.git>
 
 Git browser: L<https://github.com/moose/Moo>
 
 =head1 AUTHOR
 
 mst - Matt S. Trout (cpan:MSTROUT) <mst@shadowcat.co.uk>
 
 =head1 CONTRIBUTORS
 
 dg - David Leadbeater (cpan:DGL) <dgl@dgl.cx>
 
 frew - Arthur Axel "fREW" Schmidt (cpan:FREW) <frioux@gmail.com>
 
 hobbs - Andrew Rodland (cpan:ARODLAND) <arodland@cpan.org>
 
 jnap - John Napiorkowski (cpan:JJNAPIORK) <jjn1056@yahoo.com>
 
 ribasushi - Peter Rabbitson (cpan:RIBASUSHI) <ribasushi@cpan.org>
 
 chip - Chip Salzenberg (cpan:CHIPS) <chip@pobox.com>
 
 ajgb - Alex J. G. Burzyński (cpan:AJGB) <ajgb@cpan.org>
 
 doy - Jesse Luehrs (cpan:DOY) <doy at tozt dot net>
 
 perigrin - Chris Prather (cpan:PERIGRIN) <chris@prather.org>
 
 Mithaldu - Christian Walde (cpan:MITHALDU) <walde.christian@googlemail.com>
 
 ilmari - Dagfinn Ilmari Mannsåker (cpan:ILMARI) <ilmari@ilmari.org>
 
 tobyink - Toby Inkster (cpan:TOBYINK) <tobyink@cpan.org>
 
 haarg - Graham Knop (cpan:HAARG) <haarg@cpan.org>
 
 mattp - Matt Phillips (cpan:MATTP) <mattp@cpan.org>
 
 bluefeet - Aran Deltac (cpan:BLUEFEET) <bluefeet@gmail.com>
 
 bubaflub - Bob Kuo (cpan:BUBAFLUB) <bubaflub@cpan.org>
 
 ether = Karen Etheridge (cpan:ETHER) <ether@cpan.org>
 
 =head1 COPYRIGHT
 
 Copyright (c) 2010-2015 the Moo L</AUTHOR> and L</CONTRIBUTORS>
 as listed above.
 
 =head1 LICENSE
 
 This library is free software and may be distributed under the same terms
 as perl itself. See L<http://dev.perl.org/licenses/>.
 
 =cut
### Moo/HandleMoose.pm ###
 package Moo::HandleMoose;
 use Moo::_strictures;
 no warnings 'once';
 use Moo::_Utils;
 use Sub::Quote qw(quotify);
 
 our %TYPE_MAP;
 
 our $SETUP_DONE;
 
 sub import { return if $SETUP_DONE; inject_all(); $SETUP_DONE = 1; }
 
 sub inject_all {
   die "Can't inflate Moose metaclass with Moo::sification disabled"
     if $Moo::sification::disabled;
   require Class::MOP;
   inject_fake_metaclass_for($_)
     for grep $_ ne 'Moo::Object', do { no warnings 'once'; keys %Moo::MAKERS };
   inject_fake_metaclass_for($_) for keys %Moo::Role::INFO;
   require Moose::Meta::Method::Constructor;
   @Moo::HandleMoose::FakeConstructor::ISA = 'Moose::Meta::Method::Constructor';
   @Moo::HandleMoose::FakeMeta::ISA = 'Moose::Meta::Method::Meta';
 }
 
 sub maybe_reinject_fake_metaclass_for {
   my ($name) = @_;
   our %DID_INJECT;
   if (delete $DID_INJECT{$name}) {
     unless ($Moo::Role::INFO{$name}) {
       Moo->_constructor_maker_for($name)->install_delayed;
     }
     inject_fake_metaclass_for($name);
   }
 }
 
 sub inject_fake_metaclass_for {
   my ($name) = @_;
   require Class::MOP;
   require Moo::HandleMoose::FakeMetaClass;
   Class::MOP::store_metaclass_by_name(
     $name, bless({ name => $name }, 'Moo::HandleMoose::FakeMetaClass')
   );
   require Moose::Util::TypeConstraints;
   if ($Moo::Role::INFO{$name}) {
     Moose::Util::TypeConstraints::find_or_create_does_type_constraint($name);
   } else {
     Moose::Util::TypeConstraints::find_or_create_isa_type_constraint($name);
   }
 }
 
 {
   package Moo::HandleMoose::FakeConstructor;
 
   sub _uninlined_body { \&Moose::Object::new }
 }
 
 sub inject_real_metaclass_for {
   my ($name) = @_;
   our %DID_INJECT;
   return Class::MOP::get_metaclass_by_name($name) if $DID_INJECT{$name};
   require Moose; require Moo; require Moo::Role; require Scalar::Util;
   Class::MOP::remove_metaclass_by_name($name);
   my ($am_role, $am_class, $meta, $attr_specs, $attr_order) = do {
     if (my $info = $Moo::Role::INFO{$name}) {
       my @attr_info = @{$info->{attributes}||[]};
       (1, 0, Moose::Meta::Role->initialize($name),
        { @attr_info },
        [ @attr_info[grep !($_ % 2), 0..$#attr_info] ]
       )
     } elsif ( my $cmaker = Moo->_constructor_maker_for($name) ) {
       my $specs = $cmaker->all_attribute_specs;
       (0, 1, Moose::Meta::Class->initialize($name), $specs,
        [ sort { $specs->{$a}{index} <=> $specs->{$b}{index} } keys %$specs ]
       );
     } else {
        # This codepath is used if $name does not exist in $Moo::MAKERS
        (0, 0, Moose::Meta::Class->initialize($name), {}, [] )
     }
   };
 
   foreach my $spec (values %$attr_specs) {
     if (my $inflators = delete $spec->{moosify}) {
       $_->($spec) for @$inflators;
     }
   }
 
   my %methods
     = %{($am_role ? 'Moo::Role' : 'Moo')->_concrete_methods_of($name)};
 
   # if stuff gets added afterwards, _maybe_reset_handlemoose should
   # trigger the recreation of the metaclass but we need to ensure the
   # Moo::Role cache is cleared so we don't confuse Moo itself.
   if (my $info = $Moo::Role::INFO{$name}) {
     delete $info->{methods};
   }
 
   # needed to ensure the method body is stable and get things named
   Sub::Defer::undefer_sub($_) for grep defined, values %methods;
   my @attrs;
   {
     # This local is completely not required for roles but harmless
     local @{_getstash($name)}{keys %methods};
     my %seen_name;
     foreach my $name (@$attr_order) {
       $seen_name{$name} = 1;
       my %spec = %{$attr_specs->{$name}};
       my %spec_map = (
         map { $_->name => $_->init_arg||$_->name }
         (
           (grep { $_->has_init_arg }
              $meta->attribute_metaclass->meta->get_all_attributes),
           grep { exists($_->{init_arg}) ? defined($_->init_arg) : 1 }
           map {
             my $meta = Moose::Util::resolve_metatrait_alias('Attribute', $_)
                          ->meta;
             map $meta->get_attribute($_), $meta->get_attribute_list
           }  @{$spec{traits}||[]}
         )
       );
       # have to hard code this because Moose's role meta-model is lacking
       $spec_map{traits} ||= 'traits';
 
       $spec{is} = 'ro' if $spec{is} eq 'lazy' or $spec{is} eq 'rwp';
       my $coerce = $spec{coerce};
       if (my $isa = $spec{isa}) {
         my $tc = $spec{isa} = do {
           if (my $mapped = $TYPE_MAP{$isa}) {
             my $type = $mapped->();
             unless ( Scalar::Util::blessed($type)
                 && $type->isa("Moose::Meta::TypeConstraint") ) {
               die "error inflating attribute '$name' for package '$_[0]': "
                 ."\$TYPE_MAP{$isa} did not return a valid type constraint'";
             }
             $coerce ? $type->create_child_type(name => $type->name) : $type;
           } else {
             Moose::Meta::TypeConstraint->new(
               constraint => sub { eval { &$isa; 1 } }
             );
           }
         };
         if ($coerce) {
           $tc->coercion(Moose::Meta::TypeCoercion->new)
              ->_compiled_type_coercion($coerce);
           $spec{coerce} = 1;
         }
       } elsif ($coerce) {
         my $attr = quotify($name);
         my $tc = Moose::Meta::TypeConstraint->new(
                    constraint => sub { die "This is not going to work" },
                    inlined => sub {
                       'my $r = $_[42]{'.$attr.'}; $_[42]{'.$attr.'} = 1; $r'
                    },
                  );
         $tc->coercion(Moose::Meta::TypeCoercion->new)
            ->_compiled_type_coercion($coerce);
         $spec{isa} = $tc;
         $spec{coerce} = 1;
       }
       %spec =
         map { $spec_map{$_} => $spec{$_} }
         grep { exists $spec_map{$_} }
         keys %spec;
       push @attrs, $meta->add_attribute($name => %spec);
     }
     foreach my $mouse (do { our %MOUSE; @{$MOUSE{$name}||[]} }) {
       foreach my $attr ($mouse->get_all_attributes) {
         my %spec = %{$attr};
         delete @spec{qw(
           associated_class associated_methods __METACLASS__
           provides curries
         )};
         my $name = delete $spec{name};
         next if $seen_name{$name}++;
         push @attrs, $meta->add_attribute($name => %spec);
       }
     }
   }
   foreach my $meth_name (keys %methods) {
     my $meth_code = $methods{$meth_name};
     $meta->add_method($meth_name, $meth_code) if $meth_code;
   }
 
   if ($am_role) {
     my $info = $Moo::Role::INFO{$name};
     $meta->add_required_methods(@{$info->{requires}});
     foreach my $modifier (@{$info->{modifiers}}) {
       my ($type, @args) = @$modifier;
       my $code = pop @args;
       $meta->${\"add_${type}_method_modifier"}($_, $code) for @args;
     }
   }
   elsif ($am_class) {
     foreach my $attr (@attrs) {
       foreach my $method (@{$attr->associated_methods}) {
         $method->{body} = $name->can($method->name);
       }
     }
     bless(
       $meta->find_method_by_name('new'),
       'Moo::HandleMoose::FakeConstructor',
     );
     my $meta_meth;
     if (
       $meta_meth = $meta->find_method_by_name('meta')
       and $meta_meth->body == \&Moo::Object::meta
     ) {
       bless($meta_meth, 'Moo::HandleMoose::FakeMeta');
     }
     # a combination of Moo and Moose may bypass a Moo constructor but still
     # use a Moo DEMOLISHALL.  We need to make sure this is loaded before
     # global destruction.
     require Method::Generate::DemolishAll;
   }
   $meta->add_role(Class::MOP::class_of($_))
     for grep !/\|/ && $_ ne $name, # reject Foo|Bar and same-role-as-self
       do { no warnings 'once'; keys %{$Moo::Role::APPLIED_TO{$name}} };
   $DID_INJECT{$name} = 1;
   $meta;
 }
 
 1;
### Moo/HandleMoose/FakeMetaClass.pm ###
 package Moo::HandleMoose::FakeMetaClass;
 use Moo::_strictures;
 
 sub DESTROY { }
 
 sub AUTOLOAD {
   my ($meth) = (our $AUTOLOAD =~ /([^:]+)$/);
   my $self = shift;
   die "Can't call $meth without object instance"
     if !ref $self;
   die "Can't inflate Moose metaclass with Moo::sification disabled"
     if $Moo::sification::disabled;
   require Moo::HandleMoose;
   Moo::HandleMoose::inject_real_metaclass_for($self->{name})->$meth(@_)
 }
 sub can {
   my $self = shift;
   return $self->SUPER::can(@_)
     if !ref $self or $Moo::sification::disabled;
   require Moo::HandleMoose;
   Moo::HandleMoose::inject_real_metaclass_for($self->{name})->can(@_)
 }
 sub isa {
   my $self = shift;
   return $self->SUPER::isa(@_)
     if !ref $self or $Moo::sification::disabled;
   require Moo::HandleMoose;
   Moo::HandleMoose::inject_real_metaclass_for($self->{name})->isa(@_)
 }
 sub make_immutable { $_[0] }
 
 1;
### Moo/HandleMoose/_TypeMap.pm ###
 package Moo::HandleMoose::_TypeMap;
 use Moo::_strictures;
 
 package
   Moo::HandleMoose;
 our %TYPE_MAP;
 
 package Moo::HandleMoose::_TypeMap;
 
 use Scalar::Util ();
 use Config;
 
 our %WEAK_TYPES;
 
 sub _str_to_ref {
   my $in = shift;
   return $in
     if ref $in;
 
   if ($in =~ /(?:^|=)[A-Z]+\(0x([0-9a-zA-Z]+)\)$/) {
     my $id = do { no warnings 'portable'; hex "$1" };
     require B;
     my $sv = bless \$id, 'B::SV';
     my $ref = eval { $sv->object_2svref };
     if (!defined $ref) {
       die <<'END_ERROR';
 Moo initialization encountered types defined in a parent thread - ensure that
 Moo is require()d before any further thread spawns following a type definition.
 END_ERROR
     }
     return $ref;
   }
   return $in;
 }
 
 sub TIEHASH  { bless {}, $_[0] }
 
 sub STORE {
   my ($self, $key, $value) = @_;
   my $type = _str_to_ref($key);
   $WEAK_TYPES{$type} = $type;
   Scalar::Util::weaken($WEAK_TYPES{$type})
     if ref $type;
   $self->{$key} = $value;
 }
 
 sub FETCH    { $_[0]->{$_[1]} }
 sub FIRSTKEY { my $a = scalar keys %{$_[0]}; each %{$_[0]} }
 sub NEXTKEY  { each %{$_[0]} }
 sub EXISTS   { exists $_[0]->{$_[1]} }
 sub DELETE   { delete $_[0]->{$_[1]} }
 sub CLEAR    { %{$_[0]} = () }
 sub SCALAR   { scalar %{$_[0]} }
 
 sub CLONE {
   my @types = map {
     defined $WEAK_TYPES{$_} ? ($WEAK_TYPES{$_} => $TYPE_MAP{$_}) : ()
   } keys %TYPE_MAP;
   %WEAK_TYPES = ();
   %TYPE_MAP = @types;
 }
 
 sub DESTROY {
   my %types = %{$_[0]};
   untie %TYPE_MAP;
   %TYPE_MAP = %types;
 }
 
 if ($Config{useithreads}) {
   my @types = %TYPE_MAP;
   tie %TYPE_MAP, __PACKAGE__;
   %TYPE_MAP = @types;
 }
 
 1;
### Moo/Object.pm ###
 package Moo::Object;
 
 use Moo::_strictures;
 
 our %NO_BUILD;
 our %NO_DEMOLISH;
 our $BUILD_MAKER;
 our $DEMOLISH_MAKER;
 
 sub new {
   my $class = shift;
   unless (exists $NO_DEMOLISH{$class}) {
     unless ($NO_DEMOLISH{$class} = !$class->can('DEMOLISH')) {
       ($DEMOLISH_MAKER ||= do {
         require Method::Generate::DemolishAll;
         Method::Generate::DemolishAll->new
       })->generate_method($class);
     }
   }
   my $proto = $class->BUILDARGS(@_);
   $NO_BUILD{$class} and
     return bless({}, $class);
   $NO_BUILD{$class} = !$class->can('BUILD') unless exists $NO_BUILD{$class};
   $NO_BUILD{$class}
     ? bless({}, $class)
     : bless({}, $class)->BUILDALL($proto);
 }
 
 # Inlined into Method::Generate::Constructor::_generate_args() - keep in sync
 sub BUILDARGS {
     my $class = shift;
     if ( scalar @_ == 1 ) {
         unless ( defined $_[0] && ref $_[0] eq 'HASH' ) {
             die "Single parameters to new() must be a HASH ref"
                 ." data => ". $_[0] ."\n";
         }
         return { %{ $_[0] } };
     }
     elsif ( @_ % 2 ) {
         die "The new() method for $class expects a hash reference or a"
           . " key/value list. You passed an odd number of arguments\n";
     }
     else {
         return {@_};
     }
 }
 
 sub BUILDALL {
   my $self = shift;
   $self->${\(($BUILD_MAKER ||= do {
     require Method::Generate::BuildAll;
     Method::Generate::BuildAll->new
   })->generate_method(ref($self)))}(@_);
 }
 
 sub DEMOLISHALL {
   my $self = shift;
   $self->${\(($DEMOLISH_MAKER ||= do {
     require Method::Generate::DemolishAll;
     Method::Generate::DemolishAll->new
   })->generate_method(ref($self)))}(@_);
 }
 
 sub does {
   return !!0
     unless ($INC{'Moose/Role.pm'} || $INC{'Role/Tiny.pm'});
   require Moo::Role;
   my $does = Moo::Role->can("does_role");
   { no warnings 'redefine'; *does = $does }
   goto &$does;
 }
 
 # duplicated in Moo::Role
 sub meta {
   require Moo::HandleMoose::FakeMetaClass;
   my $class = ref($_[0])||$_[0];
   bless({ name => $class }, 'Moo::HandleMoose::FakeMetaClass');
 }
 
 1;
### Moo/Role.pm ###
 package Moo::Role;
 
 use Moo::_strictures;
 use Moo::_Utils;
 use Role::Tiny ();
 our @ISA = qw(Role::Tiny);
 
 our $VERSION = '2.000002';
 $VERSION = eval $VERSION;
 
 require Moo::sification;
 Moo::sification->import;
 
 BEGIN {
     *INFO = \%Role::Tiny::INFO;
     *APPLIED_TO = \%Role::Tiny::APPLIED_TO;
     *ON_ROLE_CREATE = \@Role::Tiny::ON_ROLE_CREATE;
 }
 
 our %INFO;
 our %APPLIED_TO;
 our %APPLY_DEFAULTS;
 our @ON_ROLE_CREATE;
 
 sub _install_tracked {
   my ($target, $name, $code) = @_;
   $INFO{$target}{exports}{$name} = $code;
   _install_coderef "${target}::${name}" => "Moo::Role::${name}" => $code;
 }
 
 sub import {
   my $target = caller;
   my ($me) = @_;
 
   _set_loaded(caller);
   strict->import;
   warnings->import;
   if ($Moo::MAKERS{$target} and $Moo::MAKERS{$target}{is_class}) {
     die "Cannot import Moo::Role into a Moo class";
   }
   $INFO{$target} ||= {};
   # get symbol table reference
   my $stash = _getstash($target);
   _install_tracked $target => has => sub {
     my $name_proto = shift;
     my @name_proto = ref $name_proto eq 'ARRAY' ? @$name_proto : $name_proto;
     if (@_ % 2 != 0) {
       require Carp;
       Carp::croak("Invalid options for " . join(', ', map "'$_'", @name_proto)
         . " attribute(s): even number of arguments expected, got " . scalar @_)
     }
     my %spec = @_;
     foreach my $name (@name_proto) {
       my $spec_ref = @name_proto > 1 ? +{%spec} : \%spec;
       ($INFO{$target}{accessor_maker} ||= do {
         require Method::Generate::Accessor;
         Method::Generate::Accessor->new
       })->generate_method($target, $name, $spec_ref);
       push @{$INFO{$target}{attributes}||=[]}, $name, $spec_ref;
       $me->_maybe_reset_handlemoose($target);
     }
   };
   # install before/after/around subs
   foreach my $type (qw(before after around)) {
     _install_tracked $target => $type => sub {
       require Class::Method::Modifiers;
       push @{$INFO{$target}{modifiers}||=[]}, [ $type => @_ ];
       $me->_maybe_reset_handlemoose($target);
     };
   }
   _install_tracked $target => requires => sub {
     push @{$INFO{$target}{requires}||=[]}, @_;
     $me->_maybe_reset_handlemoose($target);
   };
   _install_tracked $target => with => sub {
     $me->apply_roles_to_package($target, @_);
     $me->_maybe_reset_handlemoose($target);
   };
   return if $me->is_role($target); # already exported into this package
   $INFO{$target}{is_role} = 1;
   *{_getglob("${target}::meta")} = $me->can('meta');
   # grab all *non-constant* (stash slot is not a scalarref) subs present
   # in the symbol table and store their refaddrs (no need to forcibly
   # inflate constant subs into real subs) - also add '' to here (this
   # is used later) with a map to the coderefs in case of copying or re-use
   my @not_methods = ('', map { *$_{CODE}||() } grep !ref($_), values %$stash);
   @{$INFO{$target}{not_methods}={}}{@not_methods} = @not_methods;
   # a role does itself
   $APPLIED_TO{$target} = { $target => undef };
 
   $_->($target)
     for @ON_ROLE_CREATE;
 }
 
 push @ON_ROLE_CREATE, sub {
   my $target = shift;
   if ($INC{'Moo/HandleMoose.pm'}) {
     Moo::HandleMoose::inject_fake_metaclass_for($target);
   }
 };
 
 # duplicate from Moo::Object
 sub meta {
   require Moo::HandleMoose::FakeMetaClass;
   my $class = ref($_[0])||$_[0];
   bless({ name => $class }, 'Moo::HandleMoose::FakeMetaClass');
 }
 
 sub unimport {
   my $target = caller;
   _unimport_coderefs($target, $INFO{$target});
 }
 
 sub _maybe_reset_handlemoose {
   my ($class, $target) = @_;
   if ($INC{"Moo/HandleMoose.pm"}) {
     Moo::HandleMoose::maybe_reinject_fake_metaclass_for($target);
   }
 }
 
 sub methods_provided_by {
   my ($self, $role) = @_;
   _load_module($role);
   $self->_inhale_if_moose($role);
   die "${role} is not a Moo::Role" unless $self->is_role($role);
   return $self->SUPER::methods_provided_by($role);
 }
 
 sub is_role {
   my ($self, $role) = @_;
   $self->_inhale_if_moose($role);
   $self->SUPER::is_role($role);
 }
 
 sub _inhale_if_moose {
   my ($self, $role) = @_;
   my $meta;
   if (!$self->SUPER::is_role($role)
       and (
         $INC{"Moose.pm"}
         and $meta = Class::MOP::class_of($role)
         and ref $meta ne 'Moo::HandleMoose::FakeMetaClass'
         and $meta->isa('Moose::Meta::Role')
       )
       or (
         Mouse::Util->can('find_meta')
         and $meta = Mouse::Util::find_meta($role)
         and $meta->isa('Mouse::Meta::Role')
      )
   ) {
     my $is_mouse = $meta->isa('Mouse::Meta::Role');
     $INFO{$role}{methods} = {
       map +($_ => $role->can($_)),
         grep $role->can($_),
         grep !($is_mouse && $_ eq 'meta'),
         grep !$meta->get_method($_)->isa('Class::MOP::Method::Meta'),
           $meta->get_method_list
     };
     $APPLIED_TO{$role} = {
       map +($_->name => 1), $meta->calculate_all_roles
     };
     $INFO{$role}{requires} = [ $meta->get_required_method_list ];
     $INFO{$role}{attributes} = [
       map +($_ => do {
         my $attr = $meta->get_attribute($_);
         my $spec = { %{ $is_mouse ? $attr : $attr->original_options } };
 
         if ($spec->{isa}) {
 
           my $get_constraint = do {
             my $pkg = $is_mouse
                         ? 'Mouse::Util::TypeConstraints'
                         : 'Moose::Util::TypeConstraints';
             _load_module($pkg);
             $pkg->can('find_or_create_isa_type_constraint');
           };
 
           my $tc = $get_constraint->($spec->{isa});
           my $check = $tc->_compiled_type_constraint;
 
           $spec->{isa} = sub {
             &$check or die "Type constraint failed for $_[0]"
           };
 
           if ($spec->{coerce}) {
 
              # Mouse has _compiled_type_coercion straight on the TC object
              $spec->{coerce} = $tc->${\(
                $tc->can('coercion')||sub { $_[0] }
              )}->_compiled_type_coercion;
           }
         }
         $spec;
       }), $meta->get_attribute_list
     ];
     my $mods = $INFO{$role}{modifiers} = [];
     foreach my $type (qw(before after around)) {
       # Mouse pokes its own internals so we have to fall back to doing
       # the same thing in the absence of the Moose API method
       my $map = $meta->${\(
         $meta->can("get_${type}_method_modifiers_map")
         or sub { shift->{"${type}_method_modifiers"} }
       )};
       foreach my $method (keys %$map) {
         foreach my $mod (@{$map->{$method}}) {
           push @$mods, [ $type => $method => $mod ];
         }
       }
     }
     require Class::Method::Modifiers if @$mods;
     $INFO{$role}{inhaled_from_moose} = 1;
     $INFO{$role}{is_role} = 1;
   }
 }
 
 sub _maybe_make_accessors {
   my ($self, $target, $role) = @_;
   my $m;
   if ($INFO{$role} && $INFO{$role}{inhaled_from_moose}
       or $INC{"Moo.pm"}
       and $m = Moo->_accessor_maker_for($target)
       and ref($m) ne 'Method::Generate::Accessor') {
     $self->_make_accessors($target, $role);
   }
 }
 
 sub _make_accessors_if_moose {
   my ($self, $target, $role) = @_;
   if ($INFO{$role} && $INFO{$role}{inhaled_from_moose}) {
     $self->_make_accessors($target, $role);
   }
 }
 
 sub _make_accessors {
   my ($self, $target, $role) = @_;
   my $acc_gen = ($Moo::MAKERS{$target}{accessor} ||= do {
     require Method::Generate::Accessor;
     Method::Generate::Accessor->new
   });
   my $con_gen = $Moo::MAKERS{$target}{constructor};
   my @attrs = @{$INFO{$role}{attributes}||[]};
   while (my ($name, $spec) = splice @attrs, 0, 2) {
     # needed to ensure we got an index for an arrayref based generator
     if ($con_gen) {
       $spec = $con_gen->all_attribute_specs->{$name};
     }
     $acc_gen->generate_method($target, $name, $spec);
   }
 }
 
 sub role_application_steps {
   qw(_handle_constructor _maybe_make_accessors),
     $_[0]->SUPER::role_application_steps;
 }
 
 sub apply_roles_to_package {
   my ($me, $to, @roles) = @_;
   foreach my $role (@roles) {
     _load_module($role);
     $me->_inhale_if_moose($role);
     die "${role} is not a Moo::Role" unless $me->is_role($role);
   }
   $me->SUPER::apply_roles_to_package($to, @roles);
 }
 
 sub apply_single_role_to_package {
   my ($me, $to, $role) = @_;
   _load_module($role);
   $me->_inhale_if_moose($role);
   die "${role} is not a Moo::Role" unless $me->is_role($role);
   $me->SUPER::apply_single_role_to_package($to, $role);
 }
 
 sub create_class_with_roles {
   my ($me, $superclass, @roles) = @_;
 
   my ($new_name, $compose_name) = $me->_composite_name($superclass, @roles);
 
   return $new_name if $Role::Tiny::COMPOSED{class}{$new_name};
 
   foreach my $role (@roles) {
       _load_module($role);
       $me->_inhale_if_moose($role);
   }
 
   my $m;
   if ($INC{"Moo.pm"}
       and $m = Moo->_accessor_maker_for($superclass)
       and ref($m) ne 'Method::Generate::Accessor') {
     # old fashioned way time.
     *{_getglob("${new_name}::ISA")} = [ $superclass ];
     $Moo::MAKERS{$new_name} = {is_class => 1};
     $me->apply_roles_to_package($new_name, @roles);
     _set_loaded($new_name, (caller)[1]);
     return $new_name;
   }
 
   $me->SUPER::create_class_with_roles($superclass, @roles);
 
   foreach my $role (@roles) {
     die "${role} is not a Moo::Role" unless $me->is_role($role);
   }
 
   $Moo::MAKERS{$new_name} = {is_class => 1};
 
   $me->_handle_constructor($new_name, $_) for @roles;
 
   _set_loaded($new_name, (caller)[1]);
   return $new_name;
 }
 
 sub apply_roles_to_object {
   my ($me, $object, @roles) = @_;
   my $new = $me->SUPER::apply_roles_to_object($object, @roles);
   _set_loaded(ref $new, (caller)[1]);
 
   my $apply_defaults = $APPLY_DEFAULTS{ref $new} ||= do {
     my %attrs = map { @{$INFO{$_}{attributes}||[]} } @roles;
 
     if ($INC{'Moo.pm'}
         and keys %attrs
         and my $con_gen = Moo->_constructor_maker_for(ref $new)
         and my $m = Moo->_accessor_maker_for(ref $new)) {
       require Sub::Quote;
 
       my $specs = $con_gen->all_attribute_specs;
 
       my $assign = "{no warnings 'void';\n";
       my %captures;
       foreach my $name ( keys %attrs ) {
         my $spec = $specs->{$name};
         if ($m->has_eager_default($name, $spec)) {
           my ($has, $has_cap)
             = $m->generate_simple_has('$_[0]', $name, $spec);
           my ($code, $pop_cap)
             = $m->generate_use_default('$_[0]', $name, $spec, $has);
 
           $assign .= $code . ";\n";
           @captures{keys %$has_cap, keys %$pop_cap}
             = (values %$has_cap, values %$pop_cap);
         }
       }
       $assign .= "}";
       Sub::Quote::quote_sub($assign, \%captures);
     }
     else {
       sub {};
     }
   };
   $new->$apply_defaults;
   return $new;
 }
 
 sub _composable_package_for {
   my ($self, $role) = @_;
   my $composed_name = 'Role::Tiny::_COMPOSABLE::'.$role;
   return $composed_name if $Role::Tiny::COMPOSED{role}{$composed_name};
   $self->_make_accessors_if_moose($composed_name, $role);
   $self->SUPER::_composable_package_for($role);
 }
 
 sub _install_single_modifier {
   my ($me, @args) = @_;
   _install_modifier(@args);
 }
 
 sub _install_does {
     my ($me, $to) = @_;
 
     # If Role::Tiny actually installed the DOES, give it a name
     my $new = $me->SUPER::_install_does($to) or return;
     return _name_coderef("${to}::DOES", $new);
 }
 
 sub does_role {
   my ($proto, $role) = @_;
   return 1
     if Role::Tiny::does_role($proto, $role);
   my $meta;
   if ($INC{'Moose.pm'}
       and $meta = Class::MOP::class_of($proto)
       and ref $meta ne 'Moo::HandleMoose::FakeMetaClass'
       and $meta->can('does_role')
   ) {
     return $meta->does_role($role);
   }
   return 0;
 }
 
 sub _handle_constructor {
   my ($me, $to, $role) = @_;
   my $attr_info = $INFO{$role} && $INFO{$role}{attributes};
   return unless $attr_info && @$attr_info;
   my $info = $INFO{$to};
   my $con = $INC{"Moo.pm"} && Moo->_constructor_maker_for($to);
   my %existing
     = $info ? @{$info->{attributes} || []}
     : $con  ? %{$con->all_attribute_specs || {}}
     : ();
 
   my @attr_info =
     map { @{$attr_info}[$_, $_+1] }
     grep { ! $existing{$attr_info->[$_]} }
     map { 2 * $_ } 0..@$attr_info/2-1;
 
   if ($info) {
     push @{$info->{attributes}||=[]}, @attr_info;
   }
   elsif ($con) {
     # shallow copy of the specs since the constructor will assign an index
     $con->register_attribute_specs(map ref() ? { %$_ } : $_, @attr_info);
   }
 }
 
 1;
 __END__
 
 =head1 NAME
 
 Moo::Role - Minimal Object Orientation support for Roles
 
 =head1 SYNOPSIS
 
  package My::Role;
 
  use Moo::Role;
  use strictures 2;
 
  sub foo { ... }
 
  sub bar { ... }
 
  has baz => (
    is => 'ro',
  );
 
  1;
 
 And elsewhere:
 
  package Some::Class;
 
  use Moo;
  use strictures 2;
 
  # bar gets imported, but not foo
  with('My::Role');
 
  sub foo { ... }
 
  1;
 
 =head1 DESCRIPTION
 
 C<Moo::Role> builds upon L<Role::Tiny>, so look there for most of the
 documentation on how this works.  The main addition here is extra bits to make
 the roles more "Moosey;" which is to say, it adds L</has>.
 
 =head1 IMPORTED SUBROUTINES
 
 See L<Role::Tiny/IMPORTED SUBROUTINES> for all the other subroutines that are
 imported by this module.
 
 =head2 has
 
  has attr => (
    is => 'ro',
  );
 
 Declares an attribute for the class to be composed into.  See
 L<Moo/has> for all options.
 
 =head1 CLEANING UP IMPORTS
 
 L<Moo::Role> cleans up its own imported methods and any imports
 declared before the C<use Moo::Role> statement automatically.
 Anything imported after C<use Moo::Role> will be composed into
 consuming packages.  A package that consumes this role:
 
  package My::Role::ID;
 
  use Digest::MD5 qw(md5_hex);
  use Moo::Role;
  use Digest::SHA qw(sha1_hex);
 
  requires 'name';
 
  sub as_md5  { my ($self) = @_; return md5_hex($self->name);  }
  sub as_sha1 { my ($self) = @_; return sha1_hex($self->name); }
 
  1;
 
 ..will now have a C<< $self->sha1_hex() >> method available to it
 that probably does not do what you expect.  On the other hand, a call
 to C<< $self->md5_hex() >> will die with the helpful error message:
 C<Can't locate object method "md5_hex">.
 
 See L<Moo/"CLEANING UP IMPORTS"> for more details.
 
 =head1 SUPPORT
 
 See L<Moo> for support and contact information.
 
 =head1 AUTHORS
 
 See L<Moo> for authors.
 
 =head1 COPYRIGHT AND LICENSE
 
 See L<Moo> for the copyright and license.
 
 =cut
### Moo/_Utils.pm ###
 package Moo::_Utils;
 
 no warnings 'once'; # guard against -w
 
 sub _getglob { \*{$_[0]} }
 sub _getstash { \%{"$_[0]::"} }
 
 use constant lt_5_8_3 => ( $] < 5.008003 or $ENV{MOO_TEST_PRE_583} ) ? 1 : 0;
 use constant can_haz_subutil => (
     $INC{"Sub/Util.pm"}
     || ( !$INC{"Sub/Name.pm"} && eval { require Sub::Util } )
   ) && defined &Sub::Util::set_subname;
 use constant can_haz_subname => (
     $INC{"Sub/Name.pm"}
     || ( !$INC{"Sub/Util.pm"} && eval { require Sub::Name } )
   ) && defined &Sub::Name::subname;
 
 use Moo::_strictures;
 use Module::Runtime qw(use_package_optimistically module_notional_filename);
 
 use Devel::GlobalDestruction ();
 use Exporter qw(import);
 use Moo::_mro;
 use Config;
 
 our @EXPORT = qw(
     _getglob _install_modifier _load_module _maybe_load_module
     _get_linear_isa _getstash _install_coderef _name_coderef
     _unimport_coderefs _in_global_destruction _set_loaded
 );
 
 sub _in_global_destruction ();
 *_in_global_destruction = \&Devel::GlobalDestruction::in_global_destruction;
 
 sub _install_modifier {
   my ($into, $type, $name, $code) = @_;
 
   if (my $to_modify = $into->can($name)) { # CMM will throw for us if not
     require Sub::Defer;
     Sub::Defer::undefer_sub($to_modify);
   }
 
   Class::Method::Modifiers::install_modifier(@_);
 }
 
 our %MAYBE_LOADED;
 
 sub _load_module {
   my $module = $_[0];
   my $file = module_notional_filename($module);
   use_package_optimistically($module);
   return 1
     if $INC{$file};
   my $error = $@ || "Can't locate $file";
 
   # can't just ->can('can') because a sub-package Foo::Bar::Baz
   # creates a 'Baz::' key in Foo::Bar's symbol table
   my $stash = _getstash($module)||{};
   return 1 if grep +(!ref($_) and *$_{CODE}), values %$stash;
   return 1
     if $INC{"Moose.pm"} && Class::MOP::class_of($module)
     or Mouse::Util->can('find_meta') && Mouse::Util::find_meta($module);
   die $error;
 }
 
 sub _maybe_load_module {
   my $module = $_[0];
   return $MAYBE_LOADED{$module}
     if exists $MAYBE_LOADED{$module};
   if(! eval { use_package_optimistically($module) }) {
     warn "$module exists but failed to load with error: $@";
   }
   elsif ( $INC{module_notional_filename($module)} ) {
     return $MAYBE_LOADED{$module} = 1;
   }
   return $MAYBE_LOADED{$module} = 0;
 }
 
 sub _set_loaded {
   $INC{Module::Runtime::module_notional_filename($_[0])} ||= $_[1];
 }
 
 sub _get_linear_isa {
   return mro::get_linear_isa($_[0]);
 }
 
 sub _install_coderef {
   my ($glob, $code) = (_getglob($_[0]), _name_coderef(@_));
   no warnings 'redefine';
   if (*{$glob}{CODE}) {
     *{$glob} = $code;
   }
   # perl will sometimes warn about mismatched prototypes coming from the
   # inheritance cache, so disable them if we aren't redefining a sub
   else {
     no warnings 'prototype';
     *{$glob} = $code;
   }
 }
 
 sub _name_coderef {
   shift if @_ > 2; # three args is (target, name, sub)
   can_haz_subutil ? Sub::Util::set_subname(@_) :
     can_haz_subname ? Sub::Name::subname(@_) : $_[1];
 }
 
 sub _unimport_coderefs {
   my ($target, $info) = @_;
   return unless $info and my $exports = $info->{exports};
   my %rev = reverse %$exports;
   my $stash = _getstash($target);
   foreach my $name (keys %$exports) {
     if ($stash->{$name} and defined(&{$stash->{$name}})) {
       if ($rev{$target->can($name)}) {
         my $old = delete $stash->{$name};
         my $full_name = join('::',$target,$name);
         # Copy everything except the code slot back into place (e.g. $has)
         foreach my $type (qw(SCALAR HASH ARRAY IO)) {
           next unless defined(*{$old}{$type});
           no strict 'refs';
           *$full_name = *{$old}{$type};
         }
       }
     }
   }
 }
 
 if ($Config{useithreads}) {
   require Moo::HandleMoose::_TypeMap;
 }
 
 1;
### Moo/_mro.pm ###
 package Moo::_mro;
 use Moo::_strictures;
 
 if ($] >= 5.010) {
   require mro;
 } else {
   require MRO::Compat;
 }
 
 1;
### Moo/_strictures.pm ###
 package Moo::_strictures;
 use strict;
 use warnings;
 
 sub import {
   if ($ENV{MOO_FATAL_WARNINGS}) {
     require strictures;
     strictures->VERSION(2);
     @_ = ('strictures');
     goto &strictures::import;
   }
   else {
     strict->import;
     warnings->import;
   }
 }
 
 1;
### Moo/sification.pm ###
 package Moo::sification;
 
 use Moo::_strictures;
 no warnings 'once';
 use Devel::GlobalDestruction qw(in_global_destruction);
 
 sub unimport {
   die "Can't disable Moo::sification after inflation has been done"
     if $Moo::HandleMoose::SETUP_DONE;
   our $disabled = 1;
 }
 
 sub Moo::HandleMoose::AuthorityHack::DESTROY {
   unless (our $disabled or in_global_destruction) {
     require Moo::HandleMoose;
     Moo::HandleMoose->import;
   }
 }
 
 sub import {
   return
     if our $setup_done;
   if ($INC{"Moose.pm"}) {
     require Moo::HandleMoose;
     Moo::HandleMoose->import;
   } else {
     $Moose::AUTHORITY = bless({}, 'Moo::HandleMoose::AuthorityHack');
   }
   $setup_done = 1;
 }
 
 1;
### PERLANCAR/File/HomeDir.pm ###
 package PERLANCAR::File::HomeDir;
 
 our $DATE = '2015-04-08'; # DATE
 our $VERSION = '0.02'; # VERSION
 
 use 5.010001;
 use strict;
 use warnings;
 
 use Exporter qw(import);
 our @EXPORT_OK = qw(
                        get_my_home_dir
                );
 
 our $DIE_ON_FAILURE = 0;
 
 # borrowed from File::HomeDir, with some modifications
 sub get_my_home_dir {
     if ($^O eq 'MSWin32') {
         # File::HomeDir always uses exists($ENV{x}) first, does it want to avoid
         # accidentally creating env vars?
         return $ENV{HOME} if $ENV{HOME};
         return $ENV{USERPROFILE} if $ENV{USERPROFILE};
         return join($ENV{HOMEDRIVE}, "\\", $ENV{HOMEPATH})
             if $ENV{HOMEDRIVE} && $ENV{HOMEPATH};
     } else {
         return $ENV{HOME} if $ENV{HOME};
         my @pw = getpwuid($>);
         return $pw[7] if @pw;
     }
 
     if ($DIE_ON_FAILURE) {
         die "Can't get home directory";
     } else {
         return undef;
     }
 }
 
 1;
 # ABSTRACT: Lightweight way to get current user's home directory
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 PERLANCAR::File::HomeDir - Lightweight way to get current user's home directory
 
 =head1 VERSION
 
 This document describes version 0.02 of PERLANCAR::File::HomeDir (from Perl distribution PERLANCAR-File-HomeDir), released on 2015-04-08.
 
 =head1 SYNOPSIS
 
  use PERLANCAR::Home::Dir qw(get_my_home_dir);
 
  my $dir = get_my_home_dir();
 
 =head1 DESCRIPTION
 
 This is a (temporary?) module to get user's home directory. It is a lightweight
 version of L<File::HomeDir> with fewer OS support (only Windows and Unix) and
 fewer logic/heuristic.
 
 =head1 VARIABLES
 
 =head2 $DIE_ON_FAILURE => bool (default: 0)
 
 If set to true, will die on failure. Else, function usually return undef on
 failure.
 
 =head1 FUNCTIONS
 
 None are exported by default, but they are exportable.
 
 =head2 get_my_home_dir() => str
 
 Try several ways to get home directory. Return undef or die (depends on
 C<$DIE_ON_FAILURE>) if everything fails.
 
 =head1 SEE ALSO
 
 L<File::HomeDir>
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/PERLANCAR-File-HomeDir>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-PERLANCAR-File-HomeDir>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=PERLANCAR-File-HomeDir>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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
### Package/MoreUtil.pm ###
 package Package::MoreUtil;
 
 our $DATE = '2014-12-05'; # DATE
 our $VERSION = '0.58'; # VERSION
 
 use 5.010001;
 use strict;
 use warnings;
 
 require Exporter;
 our @ISA = qw(Exporter);
 our @EXPORT_OK = qw(
                        package_exists
                        list_package_contents
                        list_subpackages
                );
 
 sub package_exists {
     no strict 'refs';
 
     my $pkg = shift;
 
     return unless $pkg =~ /\A\w+(::\w+)*\z/;
     if ($pkg =~ s/::(\w+)\z//) {
         return !!${$pkg . "::"}{$1 . "::"};
     } else {
         return !!$::{$pkg . "::"};
     }
 }
 
 # XXX incomplete/improper
 sub list_package_contents {
     no strict 'refs';
 
     my $pkg = shift;
 
     return () unless !length($pkg) || package_exists($pkg);
     my $symtbl = \%{$pkg . "::"};
 
     my %res;
     while (my ($k, $v) = each %$symtbl) {
         next if $k =~ /::$/; # subpackage
         my $n;
         if ("$v" !~ /^\*/) {
             # constant
             $res{$k} = $v;
             next;
         }
         if (defined *$v{CODE}) {
             $res{$k} = *$v{CODE}; # subroutine
             $n++;
         }
         if (defined *$v{HASH}) {
             $res{"\%$k"} = \%{*$v}; # hash
             $n++;
         }
         if (defined *$v{ARRAY}) {
             $res{"\@$k"} = \@{*$v}; # array
             $n++;
         }
         if (defined(*$v{SCALAR}) # XXX always defined?
                 && defined(${*$v})) { # currently we filter undef values
             $res{"\$$k"} = \${*$v}; # scalar
             $n++;
         }
 
         if (!$n) {
             $res{"\*$k"} = $v; # glob
         }
     }
 
     %res;
 }
 
 sub list_subpackages {
     no strict 'refs';
 
     my ($pkg, $recursive, $cur_res, $ref_mem) = @_;
 
     return () unless !length($pkg) || package_exists($pkg);
 
     # this is used to avoid deep recursion. for example (the only one?) %:: and
     # %main:: point to the same thing.
     $ref_mem //= {};
 
     my $symtbl = \%{$pkg . "::"};
     return () if $ref_mem->{"$symtbl"}++;
 
     my $res = $cur_res // [];
     for (sort keys %$symtbl) {
         next unless s/::$//;
         my $name = (length($pkg) ? "$pkg\::" : "" ) . $_;
         push @$res, $name;
         list_subpackages($name, 1, $res, $ref_mem) if $recursive;
     }
 
     @$res;
 }
 
 1;
 # ABSTRACT: Package-related utilities
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Package::MoreUtil - Package-related utilities
 
 =head1 VERSION
 
 This document describes version 0.58 of Package::MoreUtil (from Perl distribution Package-MoreUtil), released on 2014-12-05.
 
 =head1 SYNOPSIS
 
  use Package::MoreUtil qw(
      package_exists
      list_package_contents
      list_subpackages
  );
 
  print "Package Foo::Bar exists" if package_exists("Foo::Bar");
  my %content   = list_package_contents("Foo::Bar");
  my @subpkg    = list_subpackages("Foo::Bar");
  my @allsubpkg = list_subpackages("Foo::Bar", 1); # recursive
 
 =head1 DESCRIPTION
 
 =head1 FUNCTIONS
 
 =head2 package_exists($name) => BOOL
 
 Return true if package "exists". By "exists", it means that the package has been
 defined by C<package> statement or some entries have been created in the symbol
 table (e.g. C<$Foo::var = 1;> will make the C<Foo> package "exist").
 
 This function can be used e.g. for checking before aliasing one package to
 another. Or to casually check whether a module has been loaded.
 
 =head2 list_package_contents($name) => %res
 
 Return a hash containing package contents. For example:
 
  (
      sub1  => \&Foo::Bar::sub1,
      sub2  => \&Foo::Bar::sub2,
      '%h1' => \%Foo::Bar::h1,
      '@a1' => \@Foo::Bar::a1,
      ...
  )
 
 This module won't list subpackages. Use list_subpackages() for that.
 
 =head2 list_subpackages($name[, $recursive]) => @res
 
 List subpackages, e.g.:
 
  (
      "Foo::Bar::Baz",
      "Foo::Bar::Qux",
      ...
  )
 
 If $recursive is true, will also list subpackages of subpackages, and so on.
 
 =head1 FAQ
 
 =head2 How to list all existing packages?
 
 You can recurse from the top, e.g.:
 
  list_subpackages("", 1);
 
 =head1 SEE ALSO
 
 L<perlmod>
 
 L<Package::Util> (currently empty/placeholder at the time of this writing)
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Package-MoreUtil>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Package-MoreUtil>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Package-MoreUtil>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2014 by perlancar@cpan.org.
 
 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
### Package/Stash.pm ###
 package Package::Stash;
 BEGIN {
   $Package::Stash::AUTHORITY = 'cpan:DOY';
 }
 $Package::Stash::VERSION = '0.37';
 use strict;
 use warnings;
 use 5.008001;
 # ABSTRACT: routines for manipulating stashes
 
 our $IMPLEMENTATION;
 
 use Module::Implementation 0.06;
 
 BEGIN {
     local $ENV{PACKAGE_STASH_IMPLEMENTATION} = $IMPLEMENTATION
       if ( $IMPLEMENTATION and not $ENV{PACKAGE_STASH_IMPLEMENTATION} );
 
     Module::Implementation::build_loader_sub(
         implementations => [ 'XS', 'PP' ],
         symbols         => [qw(
             new
             name
             namespace
             add_symbol
             remove_glob
             has_symbol
             get_symbol
             get_or_add_symbol
             remove_symbol
             list_all_symbols
             get_all_symbols
         )],
     )->();
     $IMPLEMENTATION = Module::Implementation::implementation_for(__PACKAGE__);
 }
 
 
 1;
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Package::Stash - routines for manipulating stashes
 
 =head1 VERSION
 
 version 0.37
 
 =head1 SYNOPSIS
 
   my $stash = Package::Stash->new('Foo');
   $stash->add_symbol('%foo', {bar => 1});
   # $Foo::foo{bar} == 1
   $stash->has_symbol('$foo') # false
   my $namespace = $stash->namespace;
   *{ $namespace->{foo} }{HASH} # {bar => 1}
 
 =head1 DESCRIPTION
 
 Manipulating stashes (Perl's symbol tables) is occasionally necessary, but
 incredibly messy, and easy to get wrong. This module hides all of that behind a
 simple API.
 
 NOTE: Most methods in this class require a variable specification that includes
 a sigil. If this sigil is absent, it is assumed to represent the IO slot.
 
 Due to limitations in the typeglob API available to perl code, and to typeglob
 manipulation in perl being quite slow, this module provides two
 implementations - one in pure perl, and one using XS. The XS implementation is
 to be preferred for most usages; the pure perl one is provided for cases where
 XS modules are not a possibility. The current implementation in use can be set
 by setting C<$ENV{PACKAGE_STASH_IMPLEMENTATION}> or
 C<$Package::Stash::IMPLEMENTATION> before loading Package::Stash (with the
 environment variable taking precedence), otherwise, it will use the XS
 implementation if possible, falling back to the pure perl one.
 
 =head1 METHODS
 
 =head2 new $package_name
 
 Creates a new C<Package::Stash> object, for the package given as the only
 argument.
 
 =head2 name
 
 Returns the name of the package that this object represents.
 
 =head2 namespace
 
 Returns the raw stash itself.
 
 =head2 add_symbol $variable $value %opts
 
 Adds a new package symbol, for the symbol given as C<$variable>, and optionally
 gives it an initial value of C<$value>. C<$variable> should be the name of
 variable including the sigil, so
 
   Package::Stash->new('Foo')->add_symbol('%foo')
 
 will create C<%Foo::foo>.
 
 Valid options (all optional) are C<filename>, C<first_line_num>, and
 C<last_line_num>.
 
 C<$opts{filename}>, C<$opts{first_line_num}>, and C<$opts{last_line_num}> can
 be used to indicate where the symbol should be regarded as having been defined.
 Currently these values are only used if the symbol is a subroutine ('C<&>'
 sigil) and only if C<$^P & 0x10> is true, in which case the special C<%DB::sub>
 hash is updated to record the values of C<filename>, C<first_line_num>, and
 C<last_line_num> for the subroutine. If these are not passed, their values are
 inferred (as much as possible) from C<caller> information.
 
 This is especially useful for debuggers and profilers, which use C<%DB::sub> to
 determine where the source code for a subroutine can be found.  See
 L<http://perldoc.perl.org/perldebguts.html#Debugger-Internals> for more
 information about C<%DB::sub>.
 
 =head2 remove_glob $name
 
 Removes all package variables with the given name, regardless of sigil.
 
 =head2 has_symbol $variable
 
 Returns whether or not the given package variable (including sigil) exists.
 
 =head2 get_symbol $variable
 
 Returns the value of the given package variable (including sigil).
 
 =head2 get_or_add_symbol $variable
 
 Like C<get_symbol>, except that it will return an empty hashref or
 arrayref if the variable doesn't exist.
 
 =head2 remove_symbol $variable
 
 Removes the package variable described by C<$variable> (which includes the
 sigil); other variables with the same name but different sigils will be
 untouched.
 
 =head2 list_all_symbols $type_filter
 
 Returns a list of package variable names in the package, without sigils. If a
 C<type_filter> is passed, it is used to select package variables of a given
 type, where valid types are the slots of a typeglob ('SCALAR', 'CODE', 'HASH',
 etc). Note that if the package contained any C<BEGIN> blocks, perl will leave
 an empty typeglob in the C<BEGIN> slot, so this will show up if no filter is
 used (and similarly for C<INIT>, C<END>, etc).
 
 =head2 get_all_symbols $type_filter
 
 Returns a hashref, keyed by the variable names in the package. If
 C<$type_filter> is passed, the hash will contain every variable of that type in
 the package as values, otherwise, it will contain the typeglobs corresponding
 to the variable names (basically, a clone of the stash).
 
 =head1 WORKING WITH VARIABLES
 
 It is important to note, that when working with scalar variables, the default
 behavior is to B<copy> values.
 
   my $stash = Package::Stash->new('Some::Namespace');
   my $variable = 1;
   # $Some::Namespace::name is a copy of $variable
   $stash->add_symbol('$name', $variable);
   $variable++
   # $Some::Namespace::name == 1 , $variable == 2
 
 This will likely confuse people who expect it to work the same as typeglob
 assignment, which simply creates new references to existing variables.
 
   my $variable = 1;
   {
       no strict 'refs';
       # assign $Package::Stash::name = $variable
       *{'Package::Stash::name'} = \$variable;
   }
   $variable++ # affects both names
 
 If this behaviour is desired when working with Package::Stash, simply pass
 Package::Stash a scalar ref:
 
   my $stash = Package::Stash->new('Some::Namespace');
   my $variable = 1;
   # $Some::Namespace::name is now $variable
   $stash->add_symbol('$name', \$variable);
   $variable++
   # $Some::Namespace::name == 2 , $variable == 2
 
 This will be what you want as well if you're ever working with L<Readonly>
 variables:
 
   use Readonly;
   Readonly my $value, 'hello';
 
   $stash->add_symbol('$name', \$value); # reference
   print $Some::Namespace::name; # hello
   # Tries to modify the read-only 'hello' and dies.
   $Some::Namespace::name .= " world";
 
   $stash->add_symbol('$name', $value); # copy
   print $Some::Namespace::name; # hello
   # No problem, modifying a copy, not the original
   $Some::Namespace::name .= " world";
 
 =head1 BUGS / CAVEATS
 
 =over 4
 
 =item * Prior to perl 5.10, scalar slots are only considered to exist if they are defined
 
 This is due to a shortcoming within perl itself. See
 L<perlref/Making References> point 7 for more information.
 
 =item * GLOB and FORMAT variables are not (yet) accessible through this module.
 
 =item * Also, see the BUGS section for the specific backends (L<Package::Stash::XS> and L<Package::Stash::PP>)
 
 =back
 
 Please report any bugs to GitHub Issues at
 L<https://github.com/doy/package-stash/issues>.
 
 =head1 SEE ALSO
 
 =over 4
 
 =item * L<Class::MOP::Package>
 
 This module is a factoring out of code that used to live here
 
 =back
 
 =head1 SUPPORT
 
 You can find this documentation for this module with the perldoc command.
 
     perldoc Package::Stash
 
 You can also look for information at:
 
 =over 4
 
 =item * MetaCPAN
 
 L<https://metacpan.org/release/Package-Stash>
 
 =item * Github
 
 L<https://github.com/doy/package-stash>
 
 =item * RT: CPAN's request tracker
 
 L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=Package-Stash>
 
 =item * CPAN Ratings
 
 L<http://cpanratings.perl.org/d/Package-Stash>
 
 =back
 
 =head1 HISTORY
 
 Based on code from L<Class::MOP::Package>, by Stevan Little and the Moose
 Cabal.
 
 =head1 AUTHOR
 
 Jesse Luehrs <doy@tozt.net>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2014 by Jesse Luehrs.
 
 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
### Package/Stash/PP.pm ###
 package Package::Stash::PP;
 BEGIN {
   $Package::Stash::PP::AUTHORITY = 'cpan:DOY';
 }
 $Package::Stash::PP::VERSION = '0.37';
 use strict;
 use warnings;
 # ABSTRACT: pure perl implementation of the Package::Stash API
 
 use B;
 use Carp qw(confess);
 use Scalar::Util qw(blessed reftype weaken);
 use Symbol;
 # before 5.12, assigning to the ISA glob would make it lose its magical ->isa
 # powers
 use constant BROKEN_ISA_ASSIGNMENT => ($] < 5.012);
 # before 5.10, stashes don't ever seem to drop to a refcount of zero, so
 # weakening them isn't helpful
 use constant BROKEN_WEAK_STASH     => ($] < 5.010);
 # before 5.10, the scalar slot was always treated as existing if the
 # glob existed
 use constant BROKEN_SCALAR_INITIALIZATION => ($] < 5.010);
 # add_method on anon stashes triggers rt.perl #1804 otherwise
 # fixed in perl commit v5.13.3-70-g0fe688f
 use constant BROKEN_GLOB_ASSIGNMENT => ($] < 5.013004);
 # pre-5.10, ->isa lookups were cached in the ::ISA::CACHE:: slot
 use constant HAS_ISA_CACHE => ($] < 5.010);
 
 
 sub new {
     my $class = shift;
     my ($package) = @_;
 
     if (!defined($package) || (ref($package) && reftype($package) ne 'HASH')) {
         confess "Package::Stash->new must be passed the name of the "
               . "package to access";
     }
     elsif (ref($package) && reftype($package) eq 'HASH') {
         confess "The PP implementation of Package::Stash does not support "
               . "anonymous stashes before perl 5.14"
             if BROKEN_GLOB_ASSIGNMENT;
 
         return bless {
             'namespace' => $package,
         }, $class;
     }
     elsif ($package =~ /\A[0-9A-Z_a-z]+(?:::[0-9A-Z_a-z]+)*\z/) {
         return bless {
             'package' => $package,
         }, $class;
     }
     else {
         confess "$package is not a module name";
     }
 
 }
 
 sub name {
     confess "Can't call name as a class method"
         unless blessed($_[0]);
     confess "Can't get the name of an anonymous package"
         unless defined($_[0]->{package});
     return $_[0]->{package};
 }
 
 sub namespace {
     confess "Can't call namespace as a class method"
         unless blessed($_[0]);
 
     if (BROKEN_WEAK_STASH) {
         no strict 'refs';
         return \%{$_[0]->name . '::'};
     }
     else {
         return $_[0]->{namespace} if defined $_[0]->{namespace};
 
         {
             no strict 'refs';
             $_[0]->{namespace} = \%{$_[0]->name . '::'};
         }
 
         weaken($_[0]->{namespace});
 
         return $_[0]->{namespace};
     }
 }
 
 {
     my %SIGIL_MAP = (
         '$' => 'SCALAR',
         '@' => 'ARRAY',
         '%' => 'HASH',
         '&' => 'CODE',
         ''  => 'IO',
     );
 
     sub _deconstruct_variable_name {
         my ($variable) = @_;
 
         my @ret;
         if (ref($variable) eq 'HASH') {
             @ret = @{$variable}{qw[name sigil type]};
         }
         else {
             (defined $variable && length $variable)
                 || confess "You must pass a variable name";
 
             my $sigil = substr($variable, 0, 1, '');
 
             if (exists $SIGIL_MAP{$sigil}) {
                 @ret = ($variable, $sigil, $SIGIL_MAP{$sigil});
             }
             else {
                 @ret = ("${sigil}${variable}", '', $SIGIL_MAP{''});
             }
         }
 
         # XXX in pure perl, this will access things in inner packages,
         # in xs, this will segfault - probably look more into this at
         # some point
         ($ret[0] !~ /::/)
             || confess "Variable names may not contain ::";
 
         return @ret;
     }
 }
 
 sub _valid_for_type {
     my ($value, $type) = @_;
     if ($type eq 'HASH' || $type eq 'ARRAY'
      || $type eq 'IO'   || $type eq 'CODE') {
         return reftype($value) eq $type;
     }
     else {
         my $ref = reftype($value);
         return !defined($ref) || $ref eq 'SCALAR' || $ref eq 'REF' || $ref eq 'LVALUE' || $ref eq 'REGEXP' || $ref eq 'VSTRING';
     }
 }
 
 sub add_symbol {
     my ($self, $variable, $initial_value, %opts) = @_;
 
     my ($name, $sigil, $type) = _deconstruct_variable_name($variable);
 
     if (@_ > 2) {
         _valid_for_type($initial_value, $type)
             || confess "$initial_value is not of type $type";
 
         # cheap fail-fast check for PERLDBf_SUBLINE and '&'
         if ($^P and $^P & 0x10 && $sigil eq '&') {
             my $filename = $opts{filename};
             my $first_line_num = $opts{first_line_num};
 
             (undef, $filename, $first_line_num) = caller
                 if not defined $filename;
 
             my $last_line_num = $opts{last_line_num} || ($first_line_num ||= 0);
 
             # http://perldoc.perl.org/perldebguts.html#Debugger-Internals
             $DB::sub{$self->name . '::' . $name} = "$filename:$first_line_num-$last_line_num";
         }
     }
 
     if (BROKEN_GLOB_ASSIGNMENT) {
         if (@_ > 2) {
             no strict 'refs';
             no warnings 'redefine';
             *{ $self->name . '::' . $name } = ref $initial_value
                 ? $initial_value : \$initial_value;
         }
         else {
             no strict 'refs';
             if (BROKEN_ISA_ASSIGNMENT && $name eq 'ISA') {
                 *{ $self->name . '::' . $name };
             }
             else {
                 my $undef = _undef_ref_for_type($type);
                 *{ $self->name . '::' . $name } = $undef;
             }
         }
     }
     else {
         my $namespace = $self->namespace;
         {
             # using glob aliasing instead of Symbol::gensym, because otherwise,
             # magic doesn't get applied properly.
             # see <20120710063744.19360.qmail@lists-nntp.develooper.com> on p5p
             local *__ANON__:: = $namespace;
             no strict 'refs';
             no warnings 'void';
             no warnings 'once';
             *{"__ANON__::$name"};
         }
 
         if (@_ > 2) {
             no warnings 'redefine';
             *{ $namespace->{$name} } = ref $initial_value
                 ? $initial_value : \$initial_value;
         }
         else {
             return if BROKEN_ISA_ASSIGNMENT && $name eq 'ISA';
             *{ $namespace->{$name} } = _undef_ref_for_type($type);
         }
     }
 }
 
 sub _undef_ref_for_type {
     my ($type) = @_;
 
     if ($type eq 'ARRAY') {
         return [];
     }
     elsif ($type eq 'HASH') {
         return {};
     }
     elsif ($type eq 'SCALAR') {
         return \undef;
     }
     elsif ($type eq 'IO') {
         return Symbol::geniosym;
     }
     elsif ($type eq 'CODE') {
         confess "Don't know how to vivify CODE variables";
     }
     else {
         confess "Unknown type $type in vivication";
     }
 }
 
 sub remove_glob {
     my ($self, $name) = @_;
     delete $self->namespace->{$name};
 }
 
 sub has_symbol {
     my ($self, $variable) = @_;
 
     my ($name, $sigil, $type) = _deconstruct_variable_name($variable);
 
     my $namespace = $self->namespace;
 
     return unless exists $namespace->{$name};
 
     my $entry_ref = \$namespace->{$name};
     if (reftype($entry_ref) eq 'GLOB') {
         if ($type eq 'SCALAR') {
             if (BROKEN_SCALAR_INITIALIZATION) {
                 return defined ${ *{$entry_ref}{$type} };
             }
             else {
                 my $sv = B::svref_2object($entry_ref)->SV;
                 return $sv->isa('B::SV')
                     || ($sv->isa('B::SPECIAL')
                      && $B::specialsv_name[$$sv] ne 'Nullsv');
             }
         }
         else {
             return defined *{$entry_ref}{$type};
         }
     }
     else {
         # a symbol table entry can be -1 (stub), string (stub with prototype),
         # or reference (constant)
         return $type eq 'CODE';
     }
 }
 
 sub get_symbol {
     my ($self, $variable, %opts) = @_;
 
     my ($name, $sigil, $type) = _deconstruct_variable_name($variable);
 
     my $namespace = $self->namespace;
 
     if (!exists $namespace->{$name}) {
         if ($opts{vivify}) {
             $self->add_symbol($variable);
         }
         else {
             return undef;
         }
     }
 
     my $entry_ref = \$namespace->{$name};
 
     if (ref($entry_ref) eq 'GLOB') {
         return *{$entry_ref}{$type};
     }
     else {
         if ($type eq 'CODE') {
             if (BROKEN_GLOB_ASSIGNMENT || defined($self->{package})) {
                 no strict 'refs';
                 return \&{ $self->name . '::' . $name };
             }
 
             # XXX we should really be able to support arbitrary anonymous
             # stashes here... (not just via Package::Anon)
             if (blessed($namespace) && $namespace->isa('Package::Anon')) {
                 # ->can will call gv_init for us, which inflates the glob
                 # don't know how to do this in general
                 $namespace->bless(\(my $foo))->can($name);
             }
             else {
                 confess "Don't know how to inflate a " . ref($entry_ref)
                       . " into a full coderef (perhaps you could use"
                       . " Package::Anon instead of a bare stash?)"
             }
 
             return *{ $namespace->{$name} }{CODE};
         }
         else {
             return undef;
         }
     }
 }
 
 sub get_or_add_symbol {
     my $self = shift;
     $self->get_symbol(@_, vivify => 1);
 }
 
 sub remove_symbol {
     my ($self, $variable) = @_;
 
     my ($name, $sigil, $type) = _deconstruct_variable_name($variable);
 
     # FIXME:
     # no doubt this is grossly inefficient and
     # could be done much easier and faster in XS
 
     my %desc = (
         SCALAR => { sigil => '$', type => 'SCALAR', name => $name },
         ARRAY  => { sigil => '@', type => 'ARRAY',  name => $name },
         HASH   => { sigil => '%', type => 'HASH',   name => $name },
         CODE   => { sigil => '&', type => 'CODE',   name => $name },
         IO     => { sigil => '',  type => 'IO',     name => $name },
     );
     confess "This should never ever ever happen" if !$desc{$type};
 
     my @types_to_store = grep { $type ne $_ && $self->has_symbol($desc{$_}) }
                               keys %desc;
     my %values = map { $_, $self->get_symbol($desc{$_}) } @types_to_store;
 
     $values{SCALAR} = $self->get_symbol($desc{SCALAR})
       if !defined $values{SCALAR}
         && $type ne 'SCALAR'
         && BROKEN_SCALAR_INITIALIZATION;
 
     $self->remove_glob($name);
 
     $self->add_symbol($desc{$_} => $values{$_})
         for grep { defined $values{$_} } keys %values;
 }
 
 sub list_all_symbols {
     my ($self, $type_filter) = @_;
 
     my $namespace = $self->namespace;
     if (HAS_ISA_CACHE) {
         return grep { $_ ne '::ISA::CACHE::' } keys %{$namespace}
             unless defined $type_filter;
     }
     else {
         return keys %{$namespace}
             unless defined $type_filter;
     }
 
     # NOTE:
     # or we can filter based on
     # type (SCALAR|ARRAY|HASH|CODE)
     if ($type_filter eq 'CODE') {
         return grep {
             # any non-typeglob in the symbol table is a constant or stub
             ref(\$namespace->{$_}) ne 'GLOB'
                 # regular subs are stored in the CODE slot of the typeglob
                 || defined(*{$namespace->{$_}}{CODE})
         } keys %{$namespace};
     }
     elsif ($type_filter eq 'SCALAR') {
         return grep {
             !(HAS_ISA_CACHE && $_ eq '::ISA::CACHE::') &&
             (BROKEN_SCALAR_INITIALIZATION
                 ? (ref(\$namespace->{$_}) eq 'GLOB'
                       && defined(${*{$namespace->{$_}}{'SCALAR'}}))
                 : (do {
                       my $entry = \$namespace->{$_};
                       ref($entry) eq 'GLOB'
                           && B::svref_2object($entry)->SV->isa('B::SV')
                   }))
         } keys %{$namespace};
     }
     else {
         return grep {
             ref(\$namespace->{$_}) eq 'GLOB'
                 && defined(*{$namespace->{$_}}{$type_filter})
         } keys %{$namespace};
     }
 }
 
 sub get_all_symbols {
     my ($self, $type_filter) = @_;
 
     my $namespace = $self->namespace;
     return { %{$namespace} } unless defined $type_filter;
 
     return {
         map { $_ => $self->get_symbol({name => $_, type => $type_filter}) }
             $self->list_all_symbols($type_filter)
     }
 }
 
 
 1;
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Package::Stash::PP - pure perl implementation of the Package::Stash API
 
 =head1 VERSION
 
 version 0.37
 
 =head1 SYNOPSIS
 
   use Package::Stash;
 
 =head1 DESCRIPTION
 
 This is a backend for L<Package::Stash> implemented in pure perl, for those without a compiler or who would like to use this inline in scripts.
 
 =head1 BUGS
 
 =over 4
 
 =item * remove_symbol also replaces the associated typeglob
 
 This can cause unexpected behavior when doing manipulation at compile time -
 removing subroutines will still allow them to be called from within the package
 as subroutines (although they will not be available as methods). This can be
 considered a feature in some cases (this is how L<namespace::clean> works, for
 instance), but should not be relied upon - use C<remove_glob> directly if you
 want this behavior.
 
 =item * Some minor memory leaks
 
 The pure perl implementation has a couple minor memory leaks (see the TODO
 tests in t/20-leaks.t) that I'm having a hard time tracking down - these may be
 core perl bugs, it's hard to tell.
 
 =back
 
 Please report any bugs through RT: email
 C<bug-package-stash at rt.cpan.org>, or browse to
 L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Package-Stash>.
 
 =head1 SEE ALSO
 
 =over 4
 
 =item * L<Class::MOP::Package>
 
 This module is a factoring out of code that used to live here
 
 =back
 
 =head1 SUPPORT
 
 You can find this documentation for this module with the perldoc command.
 
     perldoc Package::Stash
 
 You can also look for information at:
 
 =over 4
 
 =item * AnnoCPAN: Annotated CPAN documentation
 
 L<http://annocpan.org/dist/Package-Stash>
 
 =item * CPAN Ratings
 
 L<http://cpanratings.perl.org/d/Package-Stash>
 
 =item * RT: CPAN's request tracker
 
 L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=Package-Stash>
 
 =item * Search CPAN
 
 L<http://search.cpan.org/dist/Package-Stash>
 
 =back
 
 =head1 AUTHOR
 
 Jesse Luehrs <doy at tozt dot net>
 
 Mostly copied from code from L<Class::MOP::Package>, by Stevan Little and the
 Moose Cabal.
 
 =for Pod::Coverage BROKEN_ISA_ASSIGNMENT
 add_symbol
 get_all_symbols
 get_or_add_symbol
 get_symbol
 has_symbol
 list_all_symbols
 name
 namespace
 new
 remove_glob
 
 =head1 AUTHOR
 
 Jesse Luehrs <doy@tozt.net>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2014 by Jesse Luehrs.
 
 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
### Params/Util.pm ###
 package Params::Util;
 
 =pod
 
 =head1 NAME
 
 Params::Util - Simple, compact and correct param-checking functions
 
 =head1 SYNOPSIS
 
   # Import some functions
   use Params::Util qw{_SCALAR _HASH _INSTANCE};
   
   # If you are lazy, or need a lot of them...
   use Params::Util ':ALL';
   
   sub foo {
       my $object  = _INSTANCE(shift, 'Foo') or return undef;
       my $image   = _SCALAR(shift)          or return undef;
       my $options = _HASH(shift)            or return undef;
       # etc...
   }
 
 =head1 DESCRIPTION
 
 C<Params::Util> provides a basic set of importable functions that makes
 checking parameters a hell of a lot easier
 
 While they can be (and are) used in other contexts, the main point
 behind this module is that the functions B<both> Do What You Mean,
 and Do The Right Thing, so they are most useful when you are getting
 params passed into your code from someone and/or somewhere else
 and you can't really trust the quality.
 
 Thus, C<Params::Util> is of most use at the edges of your API, where
 params and data are coming in from outside your code.
 
 The functions provided by C<Params::Util> check in the most strictly
 correct manner known, are documented as thoroughly as possible so their
 exact behaviour is clear, and heavily tested so make sure they are not
 fooled by weird data and Really Bad Things.
 
 To use, simply load the module providing the functions you want to use
 as arguments (as shown in the SYNOPSIS).
 
 To aid in maintainability, C<Params::Util> will B<never> export by
 default.
 
 You must explicitly name the functions you want to export, or use the
 C<:ALL> param to just have it export everything (although this is not
 recommended if you have any _FOO functions yourself with which future
 additions to C<Params::Util> may clash)
 
 =head1 FUNCTIONS
 
 =cut
 
 use 5.00503;
 use strict;
 require overload;
 require Exporter;
 require Scalar::Util;
 require DynaLoader;
 
 use vars qw{$VERSION @ISA @EXPORT_OK %EXPORT_TAGS};
 
 $VERSION   = '1.07';
 @ISA       = qw{
 	Exporter
 	DynaLoader
 };
 @EXPORT_OK = qw{
 	_STRING     _IDENTIFIER
 	_CLASS      _CLASSISA   _SUBCLASS  _DRIVER  _CLASSDOES
 	_NUMBER     _POSINT     _NONNEGINT
 	_SCALAR     _SCALAR0
 	_ARRAY      _ARRAY0     _ARRAYLIKE
 	_HASH       _HASH0      _HASHLIKE
 	_CODE       _CODELIKE
 	_INVOCANT   _REGEX      _INSTANCE  _INSTANCEDOES
 	_SET        _SET0
 	_HANDLE
 };
 %EXPORT_TAGS = ( ALL => \@EXPORT_OK );
 
 eval {
 	local $ENV{PERL_DL_NONLAZY} = 0 if $ENV{PERL_DL_NONLAZY};
 	bootstrap Params::Util $VERSION;
 	1;
 } unless $ENV{PERL_PARAMS_UTIL_PP};
 
 # Use a private pure-perl copy of looks_like_number if the version of
 # Scalar::Util is old (for whatever reason).
 my $SU = eval "$Scalar::Util::VERSION" || 0;
 if ( $SU >= 1.18 ) { 
 	Scalar::Util->import('looks_like_number');
 } else {
 	eval <<'END_PERL';
 sub looks_like_number {
 	local $_ = shift;
 
 	# checks from perlfaq4
 	return 0 if !defined($_);
 	if (ref($_)) {
 		return overload::Overloaded($_) ? defined(0 + $_) : 0;
 	}
 	return 1 if (/^[+-]?[0-9]+$/); # is a +/- integer
 	return 1 if (/^([+-]?)(?=[0-9]|\.[0-9])[0-9]*(\.[0-9]*)?([Ee]([+-]?[0-9]+))?$/); # a C float
 	return 1 if ($] >= 5.008 and /^(Inf(inity)?|NaN)$/i) or ($] >= 5.006001 and /^Inf$/i);
 
 	0;
 }
 END_PERL
 }
 
 
 
 
 
 #####################################################################
 # Param Checking Functions
 
 =pod
 
 =head2 _STRING $string
 
 The C<_STRING> function is intended to be imported into your
 package, and provides a convenient way to test to see if a value is
 a normal non-false string of non-zero length.
 
 Note that this will NOT do anything magic to deal with the special
 C<'0'> false negative case, but will return it.
 
   # '0' not considered valid data
   my $name = _STRING(shift) or die "Bad name";
   
   # '0' is considered valid data
   my $string = _STRING($_[0]) ? shift : die "Bad string";
 
 Please also note that this function expects a normal string. It does
 not support overloading or other magic techniques to get a string.
 
 Returns the string as a conveince if it is a valid string, or
 C<undef> if not.
 
 =cut
 
 eval <<'END_PERL' unless defined &_STRING;
 sub _STRING ($) {
 	(defined $_[0] and ! ref $_[0] and length($_[0])) ? $_[0] : undef;
 }
 END_PERL
 
 =pod
 
 =head2 _IDENTIFIER $string
 
 The C<_IDENTIFIER> function is intended to be imported into your
 package, and provides a convenient way to test to see if a value is
 a string that is a valid Perl identifier.
 
 Returns the string as a convenience if it is a valid identifier, or
 C<undef> if not.
 
 =cut
 
 eval <<'END_PERL' unless defined &_IDENTIFIER;
 sub _IDENTIFIER ($) {
 	(defined $_[0] and ! ref $_[0] and $_[0] =~ m/^[^\W\d]\w*\z/s) ? $_[0] : undef;
 }
 END_PERL
 
 =pod
 
 =head2 _CLASS $string
 
 The C<_CLASS> function is intended to be imported into your
 package, and provides a convenient way to test to see if a value is
 a string that is a valid Perl class.
 
 This function only checks that the format is valid, not that the
 class is actually loaded. It also assumes "normalised" form, and does
 not accept class names such as C<::Foo> or C<D'Oh>.
 
 Returns the string as a convenience if it is a valid class name, or
 C<undef> if not.
 
 =cut
 
 eval <<'END_PERL' unless defined &_CLASS;
 sub _CLASS ($) {
 	(defined $_[0] and ! ref $_[0] and $_[0] =~ m/^[^\W\d]\w*(?:::\w+)*\z/s) ? $_[0] : undef;
 }
 END_PERL
 
 =pod
 
 =head2 _CLASSISA $string, $class
 
 The C<_CLASSISA> function is intended to be imported into your
 package, and provides a convenient way to test to see if a value is
 a string that is a particularly class, or a subclass of it.
 
 This function checks that the format is valid and calls the -E<gt>isa
 method on the class name. It does not check that the class is actually
 loaded.
 
 It also assumes "normalised" form, and does
 not accept class names such as C<::Foo> or C<D'Oh>.
 
 Returns the string as a convenience if it is a valid class name, or
 C<undef> if not.
 
 =cut
 
 eval <<'END_PERL' unless defined &_CLASSISA;
 sub _CLASSISA ($$) {
 	(defined $_[0] and ! ref $_[0] and $_[0] =~ m/^[^\W\d]\w*(?:::\w+)*\z/s and $_[0]->isa($_[1])) ? $_[0] : undef;
 }
 END_PERL
 
 =head2 _CLASSDOES $string, $role
 
 This routine behaves exactly like C<L</_CLASSISA>>, but checks with C<< ->DOES
 >> rather than C<< ->isa >>.  This is probably only a good idea to use on Perl
 5.10 or later, when L<UNIVERSAL::DOES|UNIVERSAL::DOES/DOES> has been
 implemented.
 
 =cut
 
 eval <<'END_PERL' unless defined &_CLASSDOES;
 sub _CLASSDOES ($$) {
 	(defined $_[0] and ! ref $_[0] and $_[0] =~ m/^[^\W\d]\w*(?:::\w+)*\z/s and $_[0]->DOES($_[1])) ? $_[0] : undef;
 }
 END_PERL
 
 =pod
 
 =head2 _SUBCLASS $string, $class
 
 The C<_SUBCLASS> function is intended to be imported into your
 package, and provides a convenient way to test to see if a value is
 a string that is a subclass of a specified class.
 
 This function checks that the format is valid and calls the -E<gt>isa
 method on the class name. It does not check that the class is actually
 loaded.
 
 It also assumes "normalised" form, and does
 not accept class names such as C<::Foo> or C<D'Oh>.
 
 Returns the string as a convenience if it is a valid class name, or
 C<undef> if not.
 
 =cut
 
 eval <<'END_PERL' unless defined &_SUBCLASS;
 sub _SUBCLASS ($$) {
 	(defined $_[0] and ! ref $_[0] and $_[0] =~ m/^[^\W\d]\w*(?:::\w+)*\z/s and $_[0] ne $_[1] and $_[0]->isa($_[1])) ? $_[0] : undef;
 }
 END_PERL
 
 =pod
 
 =head2 _NUMBER $scalar
 
 The C<_NUMBER> function is intended to be imported into your
 package, and provides a convenient way to test to see if a value is
 a number. That is, it is defined and perl thinks it's a number.
 
 This function is basically a Params::Util-style wrapper around the
 L<Scalar::Util> C<looks_like_number> function.
 
 Returns the value as a convience, or C<undef> if the value is not a
 number.
 
 =cut
 
 eval <<'END_PERL' unless defined &_NUMBER;
 sub _NUMBER ($) {
 	( defined $_[0] and ! ref $_[0] and looks_like_number($_[0]) )
 	? $_[0]
 	: undef;
 }
 END_PERL
 
 =pod
 
 =head2 _POSINT $integer
 
 The C<_POSINT> function is intended to be imported into your
 package, and provides a convenient way to test to see if a value is
 a positive integer (of any length).
 
 Returns the value as a convience, or C<undef> if the value is not a
 positive integer.
 
 The name itself is derived from the XML schema constraint of the same
 name.
 
 =cut
 
 eval <<'END_PERL' unless defined &_POSINT;
 sub _POSINT ($) {
 	(defined $_[0] and ! ref $_[0] and $_[0] =~ m/^[1-9]\d*$/) ? $_[0] : undef;
 }
 END_PERL
 
 =pod
 
 =head2 _NONNEGINT $integer
 
 The C<_NONNEGINT> function is intended to be imported into your
 package, and provides a convenient way to test to see if a value is
 a non-negative integer (of any length). That is, a positive integer,
 or zero.
 
 Returns the value as a convience, or C<undef> if the value is not a
 non-negative integer.
 
 As with other tests that may return false values, care should be taken
 to test via "defined" in boolean validy contexts.
 
   unless ( defined _NONNEGINT($value) ) {
      die "Invalid value";
   }
 
 The name itself is derived from the XML schema constraint of the same
 name.
 
 =cut
 
 eval <<'END_PERL' unless defined &_NONNEGINT;
 sub _NONNEGINT ($) {
 	(defined $_[0] and ! ref $_[0] and $_[0] =~ m/^(?:0|[1-9]\d*)$/) ? $_[0] : undef;
 }
 END_PERL
 
 =pod
 
 =head2 _SCALAR \$scalar
 
 The C<_SCALAR> function is intended to be imported into your package,
 and provides a convenient way to test for a raw and unblessed
 C<SCALAR> reference, with content of non-zero length.
 
 For a version that allows zero length C<SCALAR> references, see
 the C<_SCALAR0> function.
 
 Returns the C<SCALAR> reference itself as a convenience, or C<undef>
 if the value provided is not a C<SCALAR> reference.
 
 =cut
 
 eval <<'END_PERL' unless defined &_SCALAR;
 sub _SCALAR ($) {
 	(ref $_[0] eq 'SCALAR' and defined ${$_[0]} and ${$_[0]} ne '') ? $_[0] : undef;
 }
 END_PERL
 
 =pod
 
 =head2 _SCALAR0 \$scalar
 
 The C<_SCALAR0> function is intended to be imported into your package,
 and provides a convenient way to test for a raw and unblessed
 C<SCALAR0> reference, allowing content of zero-length.
 
 For a simpler "give me some content" version that requires non-zero
 length, C<_SCALAR> function.
 
 Returns the C<SCALAR> reference itself as a convenience, or C<undef>
 if the value provided is not a C<SCALAR> reference.
 
 =cut
 
 eval <<'END_PERL' unless defined &_SCALAR0;
 sub _SCALAR0 ($) {
 	ref $_[0] eq 'SCALAR' ? $_[0] : undef;
 }
 END_PERL
 
 =pod
 
 =head2 _ARRAY $value
 
 The C<_ARRAY> function is intended to be imported into your package,
 and provides a convenient way to test for a raw and unblessed
 C<ARRAY> reference containing B<at least> one element of any kind.
 
 For a more basic form that allows zero length ARRAY references, see
 the C<_ARRAY0> function.
 
 Returns the C<ARRAY> reference itself as a convenience, or C<undef>
 if the value provided is not an C<ARRAY> reference.
 
 =cut
 
 eval <<'END_PERL' unless defined &_ARRAY;
 sub _ARRAY ($) {
 	(ref $_[0] eq 'ARRAY' and @{$_[0]}) ? $_[0] : undef;
 }
 END_PERL
 
 =pod
 
 =head2 _ARRAY0 $value
 
 The C<_ARRAY0> function is intended to be imported into your package,
 and provides a convenient way to test for a raw and unblessed
 C<ARRAY> reference, allowing C<ARRAY> references that contain no
 elements.
 
 For a more basic "An array of something" form that also requires at
 least one element, see the C<_ARRAY> function.
 
 Returns the C<ARRAY> reference itself as a convenience, or C<undef>
 if the value provided is not an C<ARRAY> reference.
 
 =cut
 
 eval <<'END_PERL' unless defined &_ARRAY0;
 sub _ARRAY0 ($) {
 	ref $_[0] eq 'ARRAY' ? $_[0] : undef;
 }
 END_PERL
 
 =pod
 
 =head2 _ARRAYLIKE $value
 
 The C<_ARRAYLIKE> function tests whether a given scalar value can respond to
 array dereferencing.  If it can, the value is returned.  If it cannot,
 C<_ARRAYLIKE> returns C<undef>.
 
 =cut
 
 eval <<'END_PERL' unless defined &_ARRAYLIKE;
 sub _ARRAYLIKE {
 	(defined $_[0] and ref $_[0] and (
 		(Scalar::Util::reftype($_[0]) eq 'ARRAY')
 		or
 		overload::Method($_[0], '@{}')
 	)) ? $_[0] : undef;
 }
 END_PERL
 
 =pod
 
 =head2 _HASH $value
 
 The C<_HASH> function is intended to be imported into your package,
 and provides a convenient way to test for a raw and unblessed
 C<HASH> reference with at least one entry.
 
 For a version of this function that allows the C<HASH> to be empty,
 see the C<_HASH0> function.
 
 Returns the C<HASH> reference itself as a convenience, or C<undef>
 if the value provided is not an C<HASH> reference.
 
 =cut
 
 eval <<'END_PERL' unless defined &_HASH;
 sub _HASH ($) {
 	(ref $_[0] eq 'HASH' and scalar %{$_[0]}) ? $_[0] : undef;
 }
 END_PERL
 
 =pod
 
 =head2 _HASH0 $value
 
 The C<_HASH0> function is intended to be imported into your package,
 and provides a convenient way to test for a raw and unblessed
 C<HASH> reference, regardless of the C<HASH> content.
 
 For a simpler "A hash of something" version that requires at least one
 element, see the C<_HASH> function.
 
 Returns the C<HASH> reference itself as a convenience, or C<undef>
 if the value provided is not an C<HASH> reference.
 
 =cut
 
 eval <<'END_PERL' unless defined &_HASH0;
 sub _HASH0 ($) {
 	ref $_[0] eq 'HASH' ? $_[0] : undef;
 }
 END_PERL
 
 =pod
 
 =head2 _HASHLIKE $value
 
 The C<_HASHLIKE> function tests whether a given scalar value can respond to
 hash dereferencing.  If it can, the value is returned.  If it cannot,
 C<_HASHLIKE> returns C<undef>.
 
 =cut
 
 eval <<'END_PERL' unless defined &_HASHLIKE;
 sub _HASHLIKE {
 	(defined $_[0] and ref $_[0] and (
 		(Scalar::Util::reftype($_[0]) eq 'HASH')
 		or
 		overload::Method($_[0], '%{}')
 	)) ? $_[0] : undef;
 }
 END_PERL
 
 =pod
 
 =head2 _CODE $value
 
 The C<_CODE> function is intended to be imported into your package,
 and provides a convenient way to test for a raw and unblessed
 C<CODE> reference.
 
 Returns the C<CODE> reference itself as a convenience, or C<undef>
 if the value provided is not an C<CODE> reference.
 
 =cut
 
 eval <<'END_PERL' unless defined &_CODE;
 sub _CODE ($) {
 	ref $_[0] eq 'CODE' ? $_[0] : undef;
 }
 END_PERL
 
 =pod
 
 =head2 _CODELIKE $value
 
 The C<_CODELIKE> is the more generic version of C<_CODE>. Unlike C<_CODE>,
 which checks for an explicit C<CODE> reference, the C<_CODELIKE> function
 also includes things that act like them, such as blessed objects that
 overload C<'&{}'>.
 
 Please note that in the case of objects overloaded with '&{}', you will
 almost always end up also testing it in 'bool' context at some stage.
 
 For example:
 
   sub foo {
       my $code1 = _CODELIKE(shift) or die "No code param provided";
       my $code2 = _CODELIKE(shift);
       if ( $code2 ) {
            print "Got optional second code param";
       }
   }
 
 As such, you will most likely always want to make sure your class has
 at least the following to allow it to evaluate to true in boolean
 context.
 
   # Always evaluate to true in boolean context
   use overload 'bool' => sub () { 1 };
 
 Returns the callable value as a convenience, or C<undef> if the
 value provided is not callable.
 
 Note - This function was formerly known as _CALLABLE but has been renamed
 for greater symmetry with the other _XXXXLIKE functions.
 
 The use of _CALLABLE has been deprecated. It will continue to work, but
 with a warning, until end-2006, then will be removed.
 
 I apologise for any inconvenience caused.
 
 =cut
 
 eval <<'END_PERL' unless defined &_CODELIKE;
 sub _CODELIKE($) {
 	(
 		(Scalar::Util::reftype($_[0])||'') eq 'CODE'
 		or
 		Scalar::Util::blessed($_[0]) and overload::Method($_[0],'&{}')
 	)
 	? $_[0] : undef;
 }
 END_PERL
 
 =pod
 
 =head2 _INVOCANT $value
 
 This routine tests whether the given value is a valid method invocant.
 This can be either an instance of an object, or a class name.
 
 If so, the value itself is returned.  Otherwise, C<_INVOCANT>
 returns C<undef>.
 
 =cut
 
 eval <<'END_PERL' unless defined &_INVOCANT;
 sub _INVOCANT($) {
 	(defined $_[0] and
 		(defined Scalar::Util::blessed($_[0])
 		or      
 		# We used to check for stash definedness, but any class-like name is a
 		# valid invocant for UNIVERSAL methods, so we stopped. -- rjbs, 2006-07-02
 		Params::Util::_CLASS($_[0]))
 	) ? $_[0] : undef;
 }
 END_PERL
 
 =pod
 
 =head2 _INSTANCE $object, $class
 
 The C<_INSTANCE> function is intended to be imported into your package,
 and provides a convenient way to test for an object of a particular class
 in a strictly correct manner.
 
 Returns the object itself as a convenience, or C<undef> if the value
 provided is not an object of that type.
 
 =cut
 
 eval <<'END_PERL' unless defined &_INSTANCE;
 sub _INSTANCE ($$) {
 	(Scalar::Util::blessed($_[0]) and $_[0]->isa($_[1])) ? $_[0] : undef;
 }
 END_PERL
 
 =head2 _INSTANCEDOES $object, $role
 
 This routine behaves exactly like C<L</_INSTANCE>>, but checks with C<< ->DOES
 >> rather than C<< ->isa >>.  This is probably only a good idea to use on Perl
 5.10 or later, when L<UNIVERSAL::DOES|UNIVERSAL::DOES/DOES> has been
 implemented.
 
 =cut
 
 eval <<'END_PERL' unless defined &_INSTANCEDOES;
 sub _INSTANCEDOES ($$) {
 	(Scalar::Util::blessed($_[0]) and $_[0]->DOES($_[1])) ? $_[0] : undef;
 }
 END_PERL
 
 =pod
 
 =head2 _REGEX $value
 
 The C<_REGEX> function is intended to be imported into your package,
 and provides a convenient way to test for a regular expression.
 
 Returns the value itself as a convenience, or C<undef> if the value
 provided is not a regular expression.
 
 =cut
 
 eval <<'END_PERL' unless defined &_REGEX;
 sub _REGEX ($) {
 	(defined $_[0] and 'Regexp' eq ref($_[0])) ? $_[0] : undef;
 }
 END_PERL
 
 =pod
 
 =head2 _SET \@array, $class
 
 The C<_SET> function is intended to be imported into your package,
 and provides a convenient way to test for set of at least one object of
 a particular class in a strictly correct manner.
 
 The set is provided as a reference to an C<ARRAY> of objects of the
 class provided.
 
 For an alternative function that allows zero-length sets, see the
 C<_SET0> function.
 
 Returns the C<ARRAY> reference itself as a convenience, or C<undef> if
 the value provided is not a set of that class.
 
 =cut
 
 eval <<'END_PERL' unless defined &_SET;
 sub _SET ($$) {
 	my $set = shift;
 	_ARRAY($set) or return undef;
 	foreach my $item ( @$set ) {
 		_INSTANCE($item,$_[0]) or return undef;
 	}
 	$set;
 }
 END_PERL
 
 =pod
 
 =head2 _SET0 \@array, $class
 
 The C<_SET0> function is intended to be imported into your package,
 and provides a convenient way to test for a set of objects of a
 particular class in a strictly correct manner, allowing for zero objects.
 
 The set is provided as a reference to an C<ARRAY> of objects of the
 class provided.
 
 For an alternative function that requires at least one object, see the
 C<_SET> function.
 
 Returns the C<ARRAY> reference itself as a convenience, or C<undef> if
 the value provided is not a set of that class.
 
 =cut
 
 eval <<'END_PERL' unless defined &_SET0;
 sub _SET0 ($$) {
 	my $set = shift;
 	_ARRAY0($set) or return undef;
 	foreach my $item ( @$set ) {
 		_INSTANCE($item,$_[0]) or return undef;
 	}
 	$set;
 }
 END_PERL
 
 =pod
 
 =head2 _HANDLE
 
 The C<_HANDLE> function is intended to be imported into your package,
 and provides a convenient way to test whether or not a single scalar
 value is a file handle.
 
 Unfortunately, in Perl the definition of a file handle can be a little
 bit fuzzy, so this function is likely to be somewhat imperfect (at first
 anyway).
 
 That said, it is implement as well or better than the other file handle
 detectors in existance (and we stole from the best of them).
 
 =cut
 
 # We're doing this longhand for now. Once everything is perfect,
 # we'll compress this into something that compiles more efficiently.
 # Further, testing file handles is not something that is generally
 # done millions of times, so doing it slowly is not a big speed hit.
 eval <<'END_PERL' unless defined &_HANDLE;
 sub _HANDLE {
 	my $it = shift;
 
 	# It has to be defined, of course
 	unless ( defined $it ) {
 		return undef;
 	}
 
 	# Normal globs are considered to be file handles
 	if ( ref $it eq 'GLOB' ) {
 		return $it;
 	}
 
 	# Check for a normal tied filehandle
 	# Side Note: 5.5.4's tied() and can() doesn't like getting undef
 	if ( tied($it) and tied($it)->can('TIEHANDLE') ) {
 		return $it;
 	}
 
 	# There are no other non-object handles that we support
 	unless ( Scalar::Util::blessed($it) ) {
 		return undef;
 	}
 
 	# Check for a common base classes for conventional IO::Handle object
 	if ( $it->isa('IO::Handle') ) {
 		return $it;
 	}
 
 
 	# Check for tied file handles using Tie::Handle
 	if ( $it->isa('Tie::Handle') ) {
 		return $it;
 	}
 
 	# IO::Scalar is not a proper seekable, but it is valid is a
 	# regular file handle
 	if ( $it->isa('IO::Scalar') ) {
 		return $it;
 	}
 
 	# Yet another special case for IO::String, which refuses (for now
 	# anyway) to become a subclass of IO::Handle.
 	if ( $it->isa('IO::String') ) {
 		return $it;
 	}
 
 	# This is not any sort of object we know about
 	return undef;
 }
 END_PERL
 
 =pod
 
 =head2 _DRIVER $string
 
   sub foo {
     my $class = _DRIVER(shift, 'My::Driver::Base') or die "Bad driver";
     ...
   }
 
 The C<_DRIVER> function is intended to be imported into your
 package, and provides a convenient way to load and validate
 a driver class.
 
 The most common pattern when taking a driver class as a parameter
 is to check that the name is a class (i.e. check against _CLASS)
 and then to load the class (if it exists) and then ensure that
 the class returns true for the isa method on some base driver name.
 
 Return the value as a convenience, or C<undef> if the value is not
 a class name, the module does not exist, the module does not load,
 or the class fails the isa test.
 
 =cut
 
 eval <<'END_PERL' unless defined &_DRIVER;
 sub _DRIVER ($$) {
 	(defined _CLASS($_[0]) and eval "require $_[0];" and ! $@ and $_[0]->isa($_[1]) and $_[0] ne $_[1]) ? $_[0] : undef;
 }
 END_PERL
 
 1;
 
 =pod
 
 =head1 TO DO
 
 - Add _CAN to help resolve the UNIVERSAL::can debacle
 
 - Would be even nicer if someone would demonstrate how the hell to
 build a Module::Install dist of the ::Util dual Perl/XS type. :/
 
 - Implement an assertion-like version of this module, that dies on
 error.
 
 - Implement a Test:: version of this module, for use in testing
 
 =head1 SUPPORT
 
 Bugs should be reported via the CPAN bug tracker at
 
 L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Params-Util>
 
 For other issues, contact the author.
 
 =head1 AUTHOR
 
 Adam Kennedy E<lt>adamk@cpan.orgE<gt>
 
 =head1 SEE ALSO
 
 L<Params::Validate>
 
 =head1 COPYRIGHT
 
 Copyright 2005 - 2012 Adam Kennedy.
 
 This program is free software; you can redistribute
 it and/or modify it under the same terms as Perl itself.
 
 The full text of the license can be found in the
 LICENSE file included with this module.
 
 =cut
### Params/Validate.pm ###
 package Params::Validate;
 
 use 5.008001;
 
 use strict;
 use warnings;
 
 our $VERSION = '1.21';
 
 use Exporter;
 use Module::Implementation;
 use Params::Validate::Constants;
 
 use vars qw( $NO_VALIDATION %OPTIONS $options );
 
 our @ISA = 'Exporter';
 
 my @types = qw(
     SCALAR
     ARRAYREF
     HASHREF
     CODEREF
     GLOB
     GLOBREF
     SCALARREF
     HANDLE
     BOOLEAN
     UNDEF
     OBJECT
 );
 
 our %EXPORT_TAGS = (
     'all' => [
         qw( validate validate_pos validation_options validate_with ),
         @types
     ],
     types => \@types,
 );
 
 our @EXPORT_OK = ( @{ $EXPORT_TAGS{all} }, 'set_options' );
 our @EXPORT = qw( validate validate_pos );
 
 $NO_VALIDATION = $ENV{PERL_NO_VALIDATION};
 
 {
     my $loader = Module::Implementation::build_loader_sub(
         implementations => [ 'XS', 'PP' ],
         symbols         => [
             qw(
                 validate
                 validate_pos
                 validate_with
                 validation_options
                 set_options
                 ),
         ],
     );
 
     $ENV{PARAMS_VALIDATE_IMPLEMENTATION} = 'PP' if $ENV{PV_TEST_PERL};
 
     $loader->();
 }
 
 1;
 
 # ABSTRACT: Validate method/function parameters
 
 __END__
 
 =pod
 
 =head1 NAME
 
 Params::Validate - Validate method/function parameters
 
 =head1 VERSION
 
 version 1.21
 
 =head1 SYNOPSIS
 
     use Params::Validate qw(:all);
 
     # takes named params (hash or hashref)
     sub foo {
         validate(
             @_, {
                 foo => 1,    # mandatory
                 bar => 0,    # optional
             }
         );
     }
 
     # takes positional params
     sub bar {
         # first two are mandatory, third is optional
         validate_pos( @_, 1, 1, 0 );
     }
 
     sub foo2 {
         validate(
             @_, {
                 foo =>
                     # specify a type
                     { type => ARRAYREF },
                 bar =>
                     # specify an interface
                     { can => [ 'print', 'flush', 'frobnicate' ] },
                 baz => {
                     type      => SCALAR,     # a scalar ...
                                              # ... that is a plain integer ...
                     regex     => qr/^\d+$/,
                     callbacks => {           # ... and smaller than 90
                         'less than 90' => sub { shift() < 90 },
                     },
                 }
             }
         );
     }
 
     sub callback_with_custom_error {
         validate(
             @_,
             {
                 foo => callbacks => {
                     'is an integer' => sub {
                         return 1 if $_[0] =~ /^-?[1-9][0-9]*$/;
                         die "$_[0] is not a valid integer value";
                     },
                 }
             }
         );
     }
 
     sub with_defaults {
         my %p = validate(
             @_, {
                 # required
                 foo => 1,
                 # $p{bar} will be 99 if bar is not given. bar is now
                 # optional.
                 bar => { default => 99 }
             }
         );
     }
 
     sub pos_with_defaults {
         my @p = validate_pos( @_, 1, { default => 99 } );
     }
 
     sub sets_options_on_call {
         my %p = validate_with(
             params => \@_,
             spec   => { foo => { type => SCALAR, default => 2 } },
             normalize_keys => sub { $_[0] =~ s/^-//; lc $_[0] },
         );
     }
 
 =head1 DESCRIPTION
 
 The Params::Validate module allows you to validate method or function
 call parameters to an arbitrary level of specificity. At the simplest
 level, it is capable of validating the required parameters were given
 and that no unspecified additional parameters were passed in.
 
 It is also capable of determining that a parameter is of a specific
 type, that it is an object of a certain class hierarchy, that it
 possesses certain methods, or applying validation callbacks to
 arguments.
 
 =head2 EXPORT
 
 The module always exports the C<validate()> and C<validate_pos()>
 functions.
 
 It also has an additional function available for export,
 C<validate_with>, which can be used to validate any type of
 parameters, and set various options on a per-invocation basis.
 
 In addition, it can export the following constants, which are used as
 part of the type checking. These are C<SCALAR>, C<ARRAYREF>,
 C<HASHREF>, C<CODEREF>, C<GLOB>, C<GLOBREF>, and C<SCALARREF>,
 C<UNDEF>, C<OBJECT>, C<BOOLEAN>, and C<HANDLE>. These are explained
 in the section on L<Type Validation|Params::Validate/Type Validation>.
 
 The constants are available via the export tag C<:types>. There is
 also an C<:all> tag which includes all of the constants as well as the
 C<validation_options()> function.
 
 =encoding UTF-8
 
 =head1 PARAMETER VALIDATION
 
 The validation mechanisms provided by this module can handle both
 named or positional parameters. For the most part, the same features
 are available for each. The biggest difference is the way that the
 validation specification is given to the relevant subroutine. The
 other difference is in the error messages produced when validation
 checks fail.
 
 When handling named parameters, the module will accept either a hash
 or a hash reference.
 
 Subroutines expecting named parameters should call the C<validate()>
 subroutine like this:
 
     validate(
         @_, {
             parameter1 => validation spec,
             parameter2 => validation spec,
             ...
         }
     );
 
 Subroutines expecting positional parameters should call the
 C<validate_pos()> subroutine like this:
 
     validate_pos( @_, { validation spec }, { validation spec } );
 
 =head2 Mandatory/Optional Parameters
 
 If you just want to specify that some parameters are mandatory and
 others are optional, this can be done very simply.
 
 For a subroutine expecting named parameters, you would do this:
 
     validate( @_, { foo => 1, bar => 1, baz => 0 } );
 
 This says that the "foo" and "bar" parameters are mandatory and that
 the "baz" parameter is optional. The presence of any other
 parameters will cause an error.
 
 For a subroutine expecting positional parameters, you would do this:
 
     validate_pos( @_, 1, 1, 0, 0 );
 
 This says that you expect at least 2 and no more than 4 parameters.
 If you have a subroutine that has a minimum number of parameters but
 can take any maximum number, you can do this:
 
     validate_pos( @_, 1, 1, (0) x (@_ - 2) );
 
 This will always be valid as long as at least two parameters are
 given. A similar construct could be used for the more complex
 validation parameters described further on.
 
 Please note that this:
 
     validate_pos( @_, 1, 1, 0, 1, 1 );
 
 makes absolutely no sense, so don't do it. Any zeros must come at the
 end of the validation specification.
 
 In addition, if you specify that a parameter can have a default, then
 it is considered optional.
 
 =head2 Type Validation
 
 This module supports the following simple types, which can be
 L<exported as constants|/EXPORT>:
 
 =over 4
 
 =item * SCALAR
 
 A scalar which is not a reference, such as C<10> or C<'hello'>. A
 parameter that is undefined is B<not> treated as a scalar. If you
 want to allow undefined values, you will have to specify C<SCALAR |
 UNDEF>.
 
 =item * ARRAYREF
 
 An array reference such as C<[1, 2, 3]> or C<\@foo>.
 
 =item * HASHREF
 
 A hash reference such as C<< { a => 1, b => 2 } >> or C<\%bar>.
 
 =item * CODEREF
 
 A subroutine reference such as C<\&foo_sub> or C<sub { print "hello" }>.
 
 =item * GLOB
 
 This one is a bit tricky. A glob would be something like C<*FOO>, but
 not C<\*FOO>, which is a glob reference. It should be noted that this
 trick:
 
     my $fh = do { local *FH; };
 
 makes C<$fh> a glob, not a glob reference. On the other hand, the
 return value from C<Symbol::gensym> is a glob reference. Either can
 be used as a file or directory handle.
 
 =item * GLOBREF
 
 A glob reference such as C<\*FOO>. See the L<GLOB|GLOB> entry above
 for more details.
 
 =item * SCALARREF
 
 A reference to a scalar such as C<\$x>.
 
 =item * UNDEF
 
 An undefined value
 
 =item * OBJECT
 
 A blessed reference.
 
 =item * BOOLEAN
 
 This is a special option, and is just a shortcut for C<UNDEF | SCALAR>.
 
 =item * HANDLE
 
 This option is also special, and is just a shortcut for C<GLOB |
 GLOBREF>. However, it seems likely that most people interested in
 either globs or glob references are likely to really be interested in
 whether the parameter in question could be a valid file or directory
 handle.
 
 =back
 
 To specify that a parameter must be of a given type when using named
 parameters, do this:
 
     validate(
         @_, {
             foo => { type => SCALAR },
             bar => { type => HASHREF }
         }
     );
 
 If a parameter can be of more than one type, just use the bitwise or
 (C<|>) operator to combine them.
 
     validate( @_, { foo => { type => GLOB | GLOBREF } );
 
 For positional parameters, this can be specified as follows:
 
     validate_pos( @_, { type => SCALAR | ARRAYREF }, { type => CODEREF } );
 
 =head2 Interface Validation
 
 To specify that a parameter is expected to have a certain set of
 methods, we can do the following:
 
     validate(
         @_, {
             foo =>
                 # just has to be able to ->bar
                 { can => 'bar' }
         }
     );
 
  ... or ...
 
     validate(
         @_, {
             foo =>
                 # must be able to ->bar and ->print
                 { can => [qw( bar print )] }
         }
     );
 
 =head2 Class Validation
 
 A word of warning. When constructing your external interfaces, it is
 probably better to specify what methods you expect an object to
 have rather than what class it should be of (or a child of). This
 will make your API much more flexible.
 
 With that said, if you want to validate that an incoming parameter
 belongs to a class (or child class) or classes, do:
 
     validate(
         @_,
         { foo => { isa => 'My::Frobnicator' } }
     );
 
  ... or ...
 
     validate(
         @_,
         # must be both, not either!
         { foo => { isa => [qw( My::Frobnicator IO::Handle )] } }
     );
 
 =head2 Regex Validation
 
 If you want to specify that a given parameter must match a specific
 regular expression, this can be done with "regex" spec key. For
 example:
 
     validate(
         @_,
         { foo => { regex => qr/^\d+$/ } }
     );
 
 The value of the "regex" key may be either a string or a pre-compiled
 regex created via C<qr>.
 
 If the value being checked against a regex is undefined, the regex is
 explicitly checked against the empty string ('') instead, in order to
 avoid "Use of uninitialized value" warnings.
 
 The C<Regexp::Common> module on CPAN is an excellent source of regular
 expressions suitable for validating input.
 
 =head2 Callback Validation
 
 If none of the above are enough, it is possible to pass in one or more
 callbacks to validate the parameter. The callback will be given the
 B<value> of the parameter as its first argument. Its second argument
 will be all the parameters, as a reference to either a hash or array.
 Callbacks are specified as hash reference. The key is an id for the
 callback (used in error messages) and the value is a subroutine
 reference, such as:
 
     validate(
         @_,
         {
             foo => {
                 callbacks => {
                     'smaller than a breadbox' => sub { shift() < $breadbox },
                     'green or blue'           => sub {
                         return 1 if $_[0] eq 'green' || $_[0] eq 'blue';
                         die "$_[0] is not green or blue!";
                     }
                 }
             }
         }
     );
 
     validate(
         @_, {
             foo => {
                 callbacks => {
                     'bigger than baz' => sub { $_[0] > $_[1]->{baz} }
                 }
             }
         }
     );
 
 The callback should return a true value if the value is valid. If not, it can
 return false or die. If you return false, a generic error message will be
 thrown by C<Params::Validate>.
 
 If your callback dies instead you can provide a custom error message. If the
 callback dies with a plain string, this string will be appended to an
 exception message generated by C<Params::Validate>. If the callback dies with
 a reference (blessed or not), then this will be rethrown as-is by
 C<Params::Validate>.
 
 =head2 Untainting
 
 If you want values untainted, set the "untaint" key in a spec hashref
 to a true value, like this:
 
     my %p = validate(
         @_, {
             foo => { type => SCALAR, untaint => 1 },
             bar => { type => ARRAYREF }
         }
     );
 
 This will untaint the "foo" parameter if the parameters are valid.
 
 Note that untainting is only done if I<all parameters> are valid.
 Also, only the return values are untainted, not the original values
 passed into the validation function.
 
 Asking for untainting of a reference value will not do anything, as
 C<Params::Validate> will only attempt to untaint the reference itself.
 
 =head2 Mandatory/Optional Revisited
 
 If you want to specify something such as type or interface, plus the
 fact that a parameter can be optional, do this:
 
     validate(
         @_, {
             foo => { type => SCALAR },
             bar => { type => ARRAYREF, optional => 1 }
         }
     );
 
 or this for positional parameters:
 
     validate_pos(
         @_,
         { type => SCALAR },
         { type => ARRAYREF, optional => 1 }
     );
 
 By default, parameters are assumed to be mandatory unless specified as
 optional.
 
 =head2 Dependencies
 
 It also possible to specify that a given optional parameter depends on
 the presence of one or more other optional parameters.
 
     validate(
         @_, {
             cc_number => {
                 type     => SCALAR,
                 optional => 1,
                 depends  => [ 'cc_expiration', 'cc_holder_name' ],
             },
             cc_expiration  => { type => SCALAR, optional => 1 },
             cc_holder_name => { type => SCALAR, optional => 1 },
         }
     );
 
 In this case, "cc_number", "cc_expiration", and "cc_holder_name" are
 all optional. However, if "cc_number" is provided, then
 "cc_expiration" and "cc_holder_name" must be provided as well.
 
 This allows you to group together sets of parameters that all must be
 provided together.
 
 The C<validate_pos()> version of dependencies is slightly different,
 in that you can only depend on one other parameter. Also, if for
 example, the second parameter 2 depends on the fourth parameter, then
 it implies a dependency on the third parameter as well. This is
 because if the fourth parameter is required, then the user must also
 provide a third parameter so that there can be four parameters in
 total.
 
 C<Params::Validate> will die if you try to depend on a parameter not
 declared as part of your parameter specification.
 
 =head2 Specifying defaults
 
 If the C<validate()> or C<validate_pos()> functions are called in a list
 context, they will return a hash or containing the original parameters plus
 defaults as indicated by the validation spec.
 
 If the function is not called in a list context, providing a default
 in the validation spec still indicates that the parameter is optional.
 
 The hash or array returned from the function will always be a copy of
 the original parameters, in order to leave C<@_> untouched for the
 calling function.
 
 Simple examples of defaults would be:
 
     my %p = validate( @_, { foo => 1, bar => { default => 99 } } );
 
     my @p = validate_pos( @_, 1, { default => 99 } );
 
 In scalar context, a hash reference or array reference will be
 returned, as appropriate.
 
 =head1 USAGE NOTES
 
 =head2 Validation failure
 
 By default, when validation fails C<Params::Validate> calls
 C<Carp::confess()>. This can be overridden by setting the C<on_fail>
 option, which is described in the L<"GLOBAL" OPTIONS|"GLOBAL" OPTIONS>
 section.
 
 =head2 Method calls
 
 When using this module to validate the parameters passed to a method
 call, you will probably want to remove the class/object from the
 parameter list B<before> calling C<validate()> or C<validate_pos()>.
 If your method expects named parameters, then this is necessary for
 the C<validate()> function to actually work, otherwise C<@_> will not
 be usable as a hash, because it will first have your object (or
 class) B<followed> by a set of keys and values.
 
 Thus the idiomatic usage of C<validate()> in a method call will look
 something like this:
 
     sub method {
         my $self = shift;
 
         my %params = validate(
             @_, {
                 foo => 1,
                 bar => { type => ARRAYREF },
             }
         );
     }
 
 =head2 Speeding Up Validation
 
 In most cases, the validation spec will remain the same for each call to a
 subroutine. In that case, you can speed up validation by defining the
 validation spec just once, rather than on each call to the subroutine:
 
     my %spec = ( ... );
     sub foo {
         my %params = validate( @_, \%spec );
     }
 
 You can also use the C<state> feature to do this:
 
     use feature 'state';
 
     sub foo {
         state $spec = { ... };
         my %params = validate( @_, $spec );
     }
 
 =head1 "GLOBAL" OPTIONS
 
 Because the API for the C<validate()> and C<validate_pos()> functions does not
 make it possible to specify any options other than the validation spec, it is
 possible to set some options as pseudo-'globals'. These allow you to specify
 such things as whether or not the validation of named parameters should be
 case sensitive, for one example.
 
 These options are called pseudo-'globals' because these settings are
 B<only applied to calls originating from the package that set the
 options>.
 
 In other words, if I am in package C<Foo> and I call
 C<validation_options()>, those options are only in effect when I call
 C<validate()> from package C<Foo>.
 
 While this is quite different from how most other modules operate, I
 feel that this is necessary in able to make it possible for one
 module/application to use Params::Validate while still using other
 modules that also use Params::Validate, perhaps with different
 options set.
 
 The downside to this is that if you are writing an app with a standard
 calling style for all functions, and your app has ten modules, B<each
 module must include a call to C<validation_options()>>. You could of
 course write a module that all your modules use which uses various
 trickery to do this when imported.
 
 =head2 Options
 
 =over 4
 
 =item * normalize_keys => $callback
 
 This option is only relevant when dealing with named parameters.
 
 This callback will be used to transform the hash keys of both the
 parameters and the parameter spec when C<validate()> or
 C<validate_with()> are called.
 
 Any alterations made by this callback will be reflected in the
 parameter hash that is returned by the validation function. For
 example:
 
     sub foo {
         return validate_with(
             params => \@_,
             spec   => { foo => { type => SCALAR } },
             normalize_keys =>
                 sub { my $k = shift; $k =~ s/^-//; return uc $k },
         );
 
     }
 
     %p = foo( foo => 20 );
 
     # $p{FOO} is now 20
 
     %p = foo( -fOo => 50 );
 
     # $p{FOO} is now 50
 
 The callback must return a defined value.
 
 If a callback is given then the deprecated "ignore_case" and
 "strip_leading" options are ignored.
 
 =item * allow_extra => $boolean
 
 If true, then the validation routine will allow extra parameters not
 named in the validation specification. In the case of positional
 parameters, this allows an unlimited number of maximum parameters
 (though a minimum may still be set). Defaults to false.
 
 =item * on_fail => $callback
 
 If given, this callback will be called whenever a validation check
 fails. It will be called with a single parameter, which will be a
 string describing the failure. This is useful if you wish to have
 this module throw exceptions as objects rather than as strings, for
 example.
 
 This callback is expected to C<die()> internally. If it does not, the
 validation will proceed onwards, with unpredictable results.
 
 The default is to simply use the Carp module's C<confess()> function.
 
 =item * stack_skip => $number
 
 This tells Params::Validate how many stack frames to skip when finding
 a subroutine name to use in error messages. By default, it looks one
 frame back, at the immediate caller to C<validate()> or
 C<validate_pos()>. If this option is set, then the given number of
 frames are skipped instead.
 
 =item * ignore_case => $boolean
 
 DEPRECATED
 
 This is only relevant when dealing with named parameters. If it is
 true, then the validation code will ignore the case of parameter
 names. Defaults to false.
 
 =item * strip_leading => $characters
 
 DEPRECATED
 
 This too is only relevant when dealing with named parameters. If this
 is given then any parameters starting with these characters will be
 considered equivalent to parameters without them entirely. For
 example, if this is specified as '-', then C<-foo> and C<foo> would be
 considered identical.
 
 =back
 
 =head1 PER-INVOCATION OPTIONS
 
 The C<validate_with()> function can be used to set the options listed
 above on a per-invocation basis. For example:
 
     my %p = validate_with(
         params => \@_,
         spec   => {
             foo => { type    => SCALAR },
             bar => { default => 10 }
         },
         allow_extra => 1,
     );
 
 In addition to the options listed above, it is also possible to set
 the option "called", which should be a string. This string will be
 used in any error messages caused by a failure to meet the validation
 spec.
 
 This subroutine will validate named parameters as a hash if the "spec"
 parameter is a hash reference. If it is an array reference, the
 parameters are assumed to be positional.
 
     my %p = validate_with(
         params => \@_,
         spec   => {
             foo => { type    => SCALAR },
             bar => { default => 10 }
         },
         allow_extra => 1,
         called      => 'The Quux::Baz class constructor',
     );
 
     my @p = validate_with(
         params => \@_,
         spec   => [
             { type    => SCALAR },
             { default => 10 }
         ],
         allow_extra => 1,
         called      => 'The Quux::Baz class constructor',
     );
 
 =head1 DISABLING VALIDATION
 
 If the environment variable C<PERL_NO_VALIDATION> is set to something
 true, then validation is turned off. This may be useful if you only
 want to use this module during development but don't want the speed
 hit during production.
 
 The only error that will be caught will be when an odd number of
 parameters are passed into a function/method that expects a hash.
 
 If you want to selectively turn validation on and off at runtime, you
 can directly set the C<$Params::Validate::NO_VALIDATION> global
 variable. It is B<strongly> recommended that you B<localize> any
 changes to this variable, because other modules you are using may
 expect validation to be on when they execute. For example:
 
     {
         local $Params::Validate::NO_VALIDATION = 1;
 
         # no error
         foo( bar => 2 );
     }
 
     # error
     foo( bar => 2 );
 
     sub foo {
         my %p = validate( @_, { foo => 1 } );
         ...;
     }
 
 But if you want to shoot yourself in the foot and just turn it off, go
 ahead!
 
 =head1 TAINT MODE
 
 The XS implementation of this module has some problems Under taint mode with
 version of Perl before 5.14. If validation I<fails>, then instead of getting
 the expected error message you'll get a message like "Insecure dependency in
 eval_sv". This can be worked around by either untainting the arguments
 yourself, using the pure Perl implementation, or upgrading your Perl.
 
 =head1 LIMITATIONS
 
 Right now there is no way (short of a callback) to specify that
 something must be of one of a list of classes, or that it must possess
 one of a list of methods. If this is desired, it can be added in the
 future.
 
 Ideally, there would be only one validation function. If someone
 figures out how to do this, please let me know.
 
 =head1 SUPPORT
 
 Please submit bugs and patches to the CPAN RT system at
 http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Params%3A%3AValidate or
 via email at bug-params-validate@rt.cpan.org.
 
 Support questions can be sent to Dave at autarch@urth.org.
 
 =head1 DONATIONS
 
 If you'd like to thank me for the work I've done on this module,
 please consider making a "donation" to me via PayPal. I spend a lot of
 free time creating free software, and would appreciate any support
 you'd care to offer.
 
 Please note that B<I am not suggesting that you must do this> in order
 for me to continue working on this particular software. I will
 continue to do so, inasmuch as I have in the past, for as long as it
 interests me.
 
 Similarly, a donation made in this way will probably not make me work
 on this software much more, unless I get so many donations that I can
 consider working on free software full time, which seems unlikely at
 best.
 
 To donate, log into PayPal and send money to autarch@urth.org or use
 the button on this page:
 L<http://www.urth.org/~autarch/fs-donation.html>
 
 =head1 AUTHORS
 
 =over 4
 
 =item *
 
 Dave Rolsky <autarch@urth.org>
 
 =item *
 
 Ilya Martynov <ilya@martynov.org>
 
 =back
 
 =head1 CONTRIBUTORS
 
 =for stopwords Ivan Bessarabov J.R. Mash Noel Maddy Olivier Mengué Vincent Pit
 
 =over 4
 
 =item *
 
 Ivan Bessarabov <ivan@bessarabov.ru>
 
 =item *
 
 J.R. Mash <jmash.code@gmail.com>
 
 =item *
 
 Noel Maddy <zhtwnpanta@gmail.com>
 
 =item *
 
 Olivier Mengué <dolmen@cpan.org>
 
 =item *
 
 Vincent Pit <perl@profvince.com>
 
 =back
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is Copyright (c) 2001 - 2015 by Dave Rolsky and Ilya Martynov.
 
 This is free software, licensed under:
 
   The Artistic License 2.0 (GPL Compatible)
 
 =cut
### Params/Validate/Constants.pm ###
 package Params::Validate::Constants;
 
 use strict;
 use warnings;
 
 our $VERSION = '1.21';
 
 our @ISA = 'Exporter';
 
 our @EXPORT = qw(
     SCALAR
     ARRAYREF
     HASHREF
     CODEREF
     GLOB
     GLOBREF
     SCALARREF
     HANDLE
     BOOLEAN
     UNDEF
     OBJECT
     UNKNOWN
 );
 
 sub SCALAR ()    { 1 }
 sub ARRAYREF ()  { 2 }
 sub HASHREF ()   { 4 }
 sub CODEREF ()   { 8 }
 sub GLOB ()      { 16 }
 sub GLOBREF ()   { 32 }
 sub SCALARREF () { 64 }
 sub UNKNOWN ()   { 128 }
 sub UNDEF ()     { 256 }
 sub OBJECT ()    { 512 }
 
 sub HANDLE ()  { 16 | 32 }
 sub BOOLEAN () { 1 | 256 }
 
 1;
### Params/Validate/PP.pm ###
 package Params::Validate::PP;
 
 use strict;
 use warnings;
 
 our $VERSION = '1.21';
 
 use Params::Validate::Constants;
 use Scalar::Util 1.10 ();
 
 our $options;
 
 # Various internals notes (for me and any future readers of this
 # monstrosity):
 #
 # - A lot of the weirdness is _intentional_, because it optimizes for
 #   the _success_ case.  It does not really matter how slow the code is
 #   after it enters a path that leads to reporting failure.  But the
 #   "success" path should be as fast as possible.
 #
 # -- We only calculate $called as needed for this reason, even though it
 #    means copying code all over.
 #
 # - All the validation routines need to be careful never to alter the
 #   references that are passed.
 #
 # -- The code assumes that _most_ callers will not be using the
 #    skip_leading or ignore_case features.  In order to not alter the
 #    references passed in, we copy them wholesale when normalizing them
 #    to make these features work.  This is slower but lets us be faster
 #    when not using them.
 
 # Matt Sergeant came up with this prototype, which slickly takes the
 # first array (which should be the caller's @_), and makes it a
 # reference.  Everything after is the parameters for validation.
 sub validate_pos (\@@) {
     return if $Params::Validate::NO_VALIDATION && !defined wantarray;
 
     my $p = shift;
 
     my @specs = @_;
 
     my @p = @$p;
     if ($Params::Validate::NO_VALIDATION) {
 
         # if the spec is bigger that's where we can start adding
         # defaults
         for ( my $x = $#p + 1; $x <= $#specs; $x++ ) {
             $p[$x] = $specs[$x]->{default}
                 if ref $specs[$x] && exists $specs[$x]->{default};
         }
 
         return wantarray ? @p : \@p;
     }
 
     # I'm too lazy to pass these around all over the place.
     local $options ||= _get_options( ( caller(0) )[0] )
         unless defined $options;
 
     my $min = 0;
 
     while (1) {
         last
             unless (
             ref $specs[$min]
             ? !( exists $specs[$min]->{default} || $specs[$min]->{optional} )
             : $specs[$min]
             );
 
         $min++;
     }
 
     my $max = scalar @specs;
 
     my $actual = scalar @p;
     unless ( $actual >= $min
         && ( $options->{allow_extra} || $actual <= $max ) ) {
         my $minmax = (
             $options->{allow_extra}
             ? "at least $min"
             : ( $min != $max ? "$min - $max" : $max )
         );
 
         my $val = $options->{allow_extra} ? $min : $max;
         $minmax .= $val != 1 ? ' were' : ' was';
 
         my $called = _get_called();
 
         $options->{on_fail}->( "$actual parameter"
                 . ( $actual != 1 ? 's'    : '' ) . " "
                 . ( $actual != 1 ? 'were' : 'was' )
                 . " passed to $called but $minmax expected\n" );
     }
 
     my $bigger = $#p > $#specs ? $#p : $#specs;
     foreach ( 0 .. $bigger ) {
         my $spec = $specs[$_];
 
         next unless ref $spec;
 
         if ( $_ <= $#p ) {
             _validate_one_param(
                 $p[$_], \@p, $spec,
                 'Parameter #' . ( $_ + 1 ) . ' (%s)'
             );
         }
 
         $p[$_] = $spec->{default} if $_ > $#p && exists $spec->{default};
     }
 
     _validate_pos_depends( \@p, \@specs );
 
     foreach (
         grep {
                    defined $p[$_]
                 && !ref $p[$_]
                 && ref $specs[$_]
                 && $specs[$_]{untaint}
         } 0 .. $bigger
         ) {
         ( $p[$_] ) = $p[$_] =~ /(.+)/;
     }
 
     return wantarray ? @p : \@p;
 }
 
 sub _validate_pos_depends {
     my ( $p, $specs ) = @_;
 
     for my $p_idx ( 0 .. $#$p ) {
         my $spec = $specs->[$p_idx];
 
         next
             unless $spec
             && UNIVERSAL::isa( $spec, 'HASH' )
             && exists $spec->{depends};
 
         my $depends = $spec->{depends};
 
         if ( ref $depends ) {
             require Carp;
             local $Carp::CarpLevel = 2;
             Carp::croak(
                 "Arguments to 'depends' for validate_pos() must be a scalar");
         }
 
         my $p_size = scalar @$p;
         if ( $p_size < $depends - 1 ) {
             my $error
                 = (   "Parameter #"
                     . ( $p_idx + 1 )
                     . " depends on parameter #"
                     . $depends
                     . ", which was not given" );
 
             $options->{on_fail}->($error);
         }
     }
     return 1;
 }
 
 sub _validate_named_depends {
     my ( $p, $specs ) = @_;
 
     foreach my $pname ( keys %$p ) {
         my $spec = $specs->{$pname};
 
         next
             unless $spec
             && UNIVERSAL::isa( $spec, 'HASH' )
             && $spec->{depends};
 
         unless ( UNIVERSAL::isa( $spec->{depends}, 'ARRAY' )
             || !ref $spec->{depends} ) {
             require Carp;
             local $Carp::CarpLevel = 2;
             Carp::croak(
                 "Arguments to 'depends' must be a scalar or arrayref");
         }
 
         foreach my $depends_name (
             ref $spec->{depends}
             ? @{ $spec->{depends} }
             : $spec->{depends}
             ) {
             unless ( exists $p->{$depends_name} ) {
                 my $error
                     = (   "Parameter '$pname' depends on parameter '"
                         . $depends_name
                         . "', which was not given" );
 
                 $options->{on_fail}->($error);
             }
         }
     }
 }
 
 sub validate (\@$) {
     return if $Params::Validate::NO_VALIDATION && !defined wantarray;
 
     my $p = $_[0];
 
     my $specs = $_[1];
     local $options = _get_options( ( caller(0) )[0] ) unless defined $options;
 
     if ( ref $p eq 'ARRAY' ) {
 
         # we were called as validate( @_, ... ) where @_ has a
         # single element, a hash reference
         if ( ref $p->[0] ) {
             $p = { %{ $p->[0] } };
         }
         elsif ( @$p % 2 ) {
             my $called = _get_called();
 
             $options->{on_fail}
                 ->(   "Odd number of parameters in call to $called "
                     . "when named parameters were expected\n" );
         }
         else {
             $p = {@$p};
         }
     }
 
     if ( $options->{normalize_keys} ) {
         $specs = _normalize_callback( $specs, $options->{normalize_keys} );
         $p     = _normalize_callback( $p,     $options->{normalize_keys} );
     }
     elsif ( $options->{ignore_case} || $options->{strip_leading} ) {
         $specs = _normalize_named($specs);
         $p     = _normalize_named($p);
     }
 
     if ($Params::Validate::NO_VALIDATION) {
         return (
             wantarray
             ? (
 
                 # this is a hash containing just the defaults
                 (
                     map { $_ => $specs->{$_}->{default} }
                         grep {
                         ref $specs->{$_}
                             && exists $specs->{$_}->{default}
                         }
                         keys %$specs
                 ),
                 (
                     ref $p eq 'ARRAY'
                     ? (
                         ref $p->[0]
                         ? %{ $p->[0] }
                         : @$p
                         )
                     : %$p
                 )
                 )
             : do {
                 my $ref = (
                     ref $p eq 'ARRAY'
                     ? (
                         ref $p->[0]
                         ? $p->[0]
                         : {@$p}
                         )
                     : $p
                 );
 
                 foreach (
                     grep {
                         ref $specs->{$_}
                             && exists $specs->{$_}->{default}
                     }
                     keys %$specs
                     ) {
                     $ref->{$_} = $specs->{$_}->{default}
                         unless exists $ref->{$_};
                 }
 
                 return $ref;
                 }
         );
     }
 
     _validate_named_depends( $p, $specs );
 
     unless ( $options->{allow_extra} ) {
         if ( my @unmentioned = grep { !exists $specs->{$_} } keys %$p ) {
             my $called = _get_called();
 
             $options->{on_fail}->( "The following parameter"
                     . ( @unmentioned > 1 ? 's were' : ' was' )
                     . " passed in the call to $called but "
                     . ( @unmentioned > 1 ? 'were' : 'was' )
                     . " not listed in the validation options: @unmentioned\n"
             );
         }
     }
 
     my @missing;
 
     # the iterator needs to be reset in case the same hashref is being
     # passed to validate() on successive calls, because we may not go
     # through all the hash's elements
     keys %$specs;
 OUTER:
     while ( my ( $key, $spec ) = each %$specs ) {
         if (
             !exists $p->{$key}
             && (
                 ref $spec
                 ? !(
                     do {
 
                         # we want to short circuit the loop here if we
                         # can assign a default, because there's no need
                         # check anything else at all.
                         if ( exists $spec->{default} ) {
                             $p->{$key} = $spec->{default};
                             next OUTER;
                         }
                     }
                     || do {
 
                         # Similarly, an optional parameter that is
                         # missing needs no additional processing.
                         next OUTER if $spec->{optional};
                     }
                 )
                 : $spec
             )
             ) {
             push @missing, $key;
         }
 
         # Can't validate a non hashref spec beyond the presence or
         # absence of the parameter.
         elsif ( ref $spec ) {
             my $value = defined $p->{$key} ? qq|"$p->{$key}"| : 'undef';
             _validate_one_param(
                 $p->{$key}, $p, $spec,
                 qq{The '$key' parameter (%s)}
             );
         }
     }
 
     if (@missing) {
         my $called = _get_called();
 
         my $missing = join ', ', map {"'$_'"} @missing;
         $options->{on_fail}->( "Mandatory parameter"
                 . ( @missing > 1 ? 's' : '' )
                 . " $missing missing in call to $called\n" );
     }
 
     # do untainting after we know everything passed
     foreach my $key (
         grep {
                    defined $p->{$_}
                 && !ref $p->{$_}
                 && ref $specs->{$_}
                 && $specs->{$_}{untaint}
         }
         keys %$p
         ) {
         ( $p->{$key} ) = $p->{$key} =~ /(.+)/;
     }
 
     return wantarray ? %$p : $p;
 }
 
 sub validate_with {
     return if $Params::Validate::NO_VALIDATION && !defined wantarray;
 
     my %p = @_;
 
     local $options = _get_options( ( caller(0) )[0], %p );
 
     unless ($Params::Validate::NO_VALIDATION) {
         unless ( exists $options->{called} ) {
             $options->{called} = ( caller( $options->{stack_skip} ) )[3];
         }
 
     }
 
     if ( UNIVERSAL::isa( $p{spec}, 'ARRAY' ) ) {
         return validate_pos( @{ $p{params} }, @{ $p{spec} } );
     }
     else {
 
         # intentionally ignore the prototype because this contains
         # either an array or hash reference, and validate() will
         # handle either one properly
         return &validate( $p{params}, $p{spec} );
     }
 }
 
 sub _normalize_callback {
     my ( $p, $func ) = @_;
 
     my %new;
 
     foreach my $key ( keys %$p ) {
         my $new_key = $func->($key);
 
         unless ( defined $new_key ) {
             die
                 "The normalize_keys callback did not return a defined value when normalizing the key '$key'";
         }
 
         if ( exists $new{$new_key} ) {
             die
                 "The normalize_keys callback returned a key that already exists, '$new_key', when normalizing the key '$key'";
         }
 
         $new{$new_key} = $p->{$key};
     }
 
     return \%new;
 }
 
 sub _normalize_named {
 
     # intentional copy so we don't destroy original
     my %h = ( ref $_[0] ) =~ /ARRAY/ ? @{ $_[0] } : %{ $_[0] };
 
     if ( $options->{ignore_case} ) {
         $h{ lc $_ } = delete $h{$_} for keys %h;
     }
 
     if ( $options->{strip_leading} ) {
         foreach my $key ( keys %h ) {
             my $new;
             ( $new = $key ) =~ s/^\Q$options->{strip_leading}\E//;
             $h{$new} = delete $h{$key};
         }
     }
 
     return \%h;
 }
 
 my %Valid = map { $_ => 1 }
     qw( callbacks can default depends isa optional regex type untaint  );
 
 sub _validate_one_param {
     my ( $value, $params, $spec, $id ) = @_;
 
     # for my $key ( keys %{$spec} ) {
     #     unless ( $Valid{$key} ) {
     #         $options->{on_fail}
     #             ->(qq{"$key" is not an allowed validation spec key});
     #     }
     # }
 
     if ( exists $spec->{type} ) {
         unless ( defined $spec->{type}
             && Scalar::Util::looks_like_number( $spec->{type} )
             && $spec->{type} > 0 ) {
             my $msg
                 = "$id has a type specification which is not a number. It is ";
             if ( defined $spec->{type} ) {
                 $msg .= "a string - $spec->{type}";
             }
             else {
                 $msg .= "undef";
             }
 
             $msg
                 .= ".\n Use the constants exported by Params::Validate to declare types.";
 
             $options->{on_fail}->( sprintf( $msg, _stringify($value) ) );
         }
 
         unless ( _get_type($value) & $spec->{type} ) {
             my $type = _get_type($value);
 
             my @is      = _typemask_to_strings($type);
             my @allowed = _typemask_to_strings( $spec->{type} );
             my $article = $is[0] =~ /^[aeiou]/i ? 'an' : 'a';
 
             my $called = _get_called(1);
 
             $options->{on_fail}->(
                 sprintf(
                     "$id to $called was $article '@is', which "
                         . "is not one of the allowed types: @allowed\n",
                     _stringify($value)
                 )
             );
         }
     }
 
     # short-circuit for common case
     return
         unless ( $spec->{isa}
         || $spec->{can}
         || $spec->{callbacks}
         || $spec->{regex} );
 
     if ( exists $spec->{isa} ) {
         foreach ( ref $spec->{isa} ? @{ $spec->{isa} } : $spec->{isa} ) {
             unless (
                 do {
                     local $@ = q{};
                     eval { $value->isa($_) };
                 }
                 ) {
                 my $is = ref $value ? ref $value : 'plain scalar';
                 my $article1 = $_ =~ /^[aeiou]/i  ? 'an' : 'a';
                 my $article2 = $is =~ /^[aeiou]/i ? 'an' : 'a';
 
                 my $called = _get_called(1);
 
                 $options->{on_fail}->(
                     sprintf(
                               "$id to $called was not $article1 '$_' "
                             . "(it is $article2 $is)\n", _stringify($value)
                     )
                 );
             }
         }
     }
 
     if ( exists $spec->{can} ) {
         foreach ( ref $spec->{can} ? @{ $spec->{can} } : $spec->{can} ) {
             unless (
                 do {
                     local $@ = q{};
                     eval { $value->can($_) };
                 }
                 ) {
                 my $called = _get_called(1);
 
                 $options->{on_fail}->(
                     sprintf(
                         "$id to $called does not have the method: '$_'\n",
                         _stringify($value)
                     )
                 );
             }
         }
     }
 
     if ( $spec->{callbacks} ) {
         unless ( UNIVERSAL::isa( $spec->{callbacks}, 'HASH' ) ) {
             my $called = _get_called(1);
 
             $options->{on_fail}->(
                 "'callbacks' validation parameter for $called must be a hash reference\n"
             );
         }
 
         foreach ( keys %{ $spec->{callbacks} } ) {
             unless ( UNIVERSAL::isa( $spec->{callbacks}{$_}, 'CODE' ) ) {
                 my $called = _get_called(1);
 
                 $options->{on_fail}->(
                     "callback '$_' for $called is not a subroutine reference\n"
                 );
             }
 
             my $ok;
             my $e = do {
                 local $@ = q{};
                 local $SIG{__DIE__};
                 $ok = eval { $spec->{callbacks}{$_}->( $value, $params ) };
                 $@;
             };
 
             if ( !$ok ) {
                 my $called = _get_called(1);
 
                 if ( ref $e ) {
                     $options->{on_fail}->($e);
                 }
                 else {
                     my $msg = "$id to $called did not pass the '$_' callback";
                     $msg .= ": $e" if length $e;
                     $msg .= "\n";
                     $options->{on_fail}->( sprintf( $msg, _stringify($value) ) );
                 }
             }
         }
     }
 
     if ( exists $spec->{regex} ) {
         unless ( ( defined $value ? $value : '' ) =~ /$spec->{regex}/ ) {
             my $called = _get_called(1);
 
             $options->{on_fail}->(
                 sprintf(
                     "$id to $called did not pass regex check\n",
                     _stringify($value)
                 )
             );
         }
     }
 }
 
 {
     # if it UNIVERSAL::isa the string on the left then its the type on
     # the right
     my %isas = (
         'ARRAY'  => ARRAYREF,
         'HASH'   => HASHREF,
         'CODE'   => CODEREF,
         'GLOB'   => GLOBREF,
         'SCALAR' => SCALARREF,
         'REGEXP' => SCALARREF,
     );
     my %simple_refs = map { $_ => 1 } keys %isas;
 
     sub _get_type {
         return UNDEF unless defined $_[0];
 
         my $ref = ref $_[0];
         unless ($ref) {
 
             # catches things like:  my $fh = do { local *FH; };
             return GLOB if UNIVERSAL::isa( \$_[0], 'GLOB' );
             return SCALAR;
         }
 
         return $isas{$ref} if $simple_refs{$ref};
 
         foreach ( keys %isas ) {
             return $isas{$_} | OBJECT if UNIVERSAL::isa( $_[0], $_ );
         }
 
         # I really hope this never happens.
         return UNKNOWN;
     }
 }
 
 {
     my %type_to_string = (
         SCALAR()    => 'scalar',
         ARRAYREF()  => 'arrayref',
         HASHREF()   => 'hashref',
         CODEREF()   => 'coderef',
         GLOB()      => 'glob',
         GLOBREF()   => 'globref',
         SCALARREF() => 'scalarref',
         UNDEF()     => 'undef',
         OBJECT()    => 'object',
         UNKNOWN()   => 'unknown',
     );
 
     sub _typemask_to_strings {
         my $mask = shift;
 
         my @types;
         foreach (
             SCALAR,    ARRAYREF, HASHREF, CODEREF, GLOB, GLOBREF,
             SCALARREF, UNDEF,    OBJECT,  UNKNOWN
             ) {
             push @types, $type_to_string{$_} if $mask & $_;
         }
         return @types ? @types : ('unknown');
     }
 }
 
 {
     my %defaults = (
         ignore_case   => 0,
         strip_leading => 0,
         allow_extra   => 0,
         on_fail       => sub {
             require Carp;
             Carp::confess( $_[0] );
         },
         stack_skip     => 1,
         normalize_keys => undef,
     );
 
     *set_options = \&validation_options;
 
     sub validation_options {
         my %opts = @_;
 
         my $caller = caller;
 
         foreach ( keys %defaults ) {
             $opts{$_} = $defaults{$_} unless exists $opts{$_};
         }
 
         $Params::Validate::OPTIONS{$caller} = \%opts;
     }
 
     sub _get_options {
         my $caller = shift;
 
         if (@_) {
 
             return (
                 $Params::Validate::OPTIONS{$caller}
                 ? {
                     %{ $Params::Validate::OPTIONS{$caller} },
                     @_
                     }
                 : { %defaults, @_ }
             );
         }
         else {
             return (
                 exists $Params::Validate::OPTIONS{$caller}
                 ? $Params::Validate::OPTIONS{$caller}
                 : \%defaults
             );
         }
     }
 }
 
 sub _get_called {
     my $extra_skip = $_[0] || 0;
 
     # always add one more for this sub
     $extra_skip++;
 
     my $called = (
         exists $options->{called}
         ? $options->{called}
         : ( caller( $options->{stack_skip} + $extra_skip ) )[3]
     );
 
     $called = 'N/A' unless defined $called;
 
     return $called;
 }
 
 sub _stringify {
     return defined $_[0] ? qq{"$_[0]"} : 'undef';
 }
 
 1;
### Params/Validate/XS.pm ###
 package Params::Validate::XS;
 
 use strict;
 use warnings;
 
 our $VERSION = '1.21';
 
 use Carp;
 
 my $default_fail = sub {
     Carp::confess( $_[0] );
 };
 
 {
     my %defaults = (
         ignore_case    => 0,
         strip_leading  => 0,
         allow_extra    => 0,
         on_fail        => $default_fail,
         stack_skip     => 1,
         normalize_keys => undef,
     );
 
     *set_options = \&validation_options;
 
     sub validation_options {
         my %opts = @_;
 
         my $caller = caller;
 
         foreach ( keys %defaults ) {
             $opts{$_} = $defaults{$_} unless exists $opts{$_};
         }
 
         $Params::Validate::OPTIONS{$caller} = \%opts;
     }
 
     use XSLoader;
     XSLoader::load(
         __PACKAGE__,
         exists $Params::Validate::XS::{VERSION}
         ? ${ $Params::Validate::XS::{VERSION} }
         : (),
     );
 }
 
 sub _check_regex_from_xs {
     return ( defined $_[0] ? $_[0] : '' ) =~ /$_[1]/ ? 1 : 0;
 }
 
 1;
### Parse/VarName.pm ###
 package Parse::VarName;
 
 our $DATE = '2015-09-03'; # DATE
 our $VERSION = '0.02'; # VERSION
 
 use 5.010001;
 use strict;
 use warnings;
 
 use Exporter::Lite;
 our @EXPORT_OK = qw(split_varname_words);
 
 our %SPEC;
 
 $SPEC{':package'} = {
     v => 1.1,
     summary => 'Routines to parse variable name',
 };
 
 # cannot be put inside sub, warning "Variable %s will not stay shared"
 my @res;
 
 $SPEC{split_varname_words} = {
     v => 1.1,
     summary => 'Split words found in variable name',
     description => <<'_',
 
 Try to split words found in a variable name, e.g. mTime -> [m, Time], foo1Bar ->
 [foo, 1, Bar], Foo::barBaz::Qux2 -> [Foo, bar, Baz, Qux, 2].
 
 _
     args => {
         varname => {
             schema => 'str*',
             req => 1,
             pos => 1,
         },
         include_sep => {
             summary => 'Whether to include non-alphanum separator in result',
             description => <<'_',
 
 For example, under include_sep=true, Foo::barBaz::Qux2 -> [Foo, ::, bar, Baz,
 ::, Qux, 2].
 
 _
             schema => [bool => {default=>0}],
         },
     },
     result_naked => 1,
 };
 sub split_varname_words {
     my %args = @_;
     my $v = $args{varname} or return [400, "Please specify varname"];
 
     #no warnings;
     @res = ();
     $v =~ m!\A(?:
                 (
                     [A-Z][A-Z]+ |
                     [A-Z][a-z]+ |
                     [a-z]+ |
                     [0-9]+ |
                     [^A-Za-z0-9]+
                 )
                 (?{ push @res, $1 })
             )+\z!sxg
                 or return [];
     unless ($args{include_sep}) {
         @res = grep {/[A-Za-z0-9]/} @res;
     }
 
     \@res;
 }
 
 1;
 # ABSTRACT: Routines to parse variable name
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Parse::VarName - Routines to parse variable name
 
 =head1 VERSION
 
 This document describes version 0.02 of Parse::VarName (from Perl distribution Parse-VarName), released on 2015-09-03.
 
 =head1 FUNCTIONS
 
 
 =head2 split_varname_words(%args) -> any
 
 Split words found in variable name.
 
 Try to split words found in a variable name, e.g. mTime -> [m, Time], foo1Bar ->
 [foo, 1, Bar], Foo::barBaz::Qux2 -> [Foo, bar, Baz, Qux, 2].
 
 Arguments ('*' denotes required arguments):
 
 =over 4
 
 =item * B<include_sep> => I<bool> (default: 0)
 
 Whether to include non-alphanum separator in result.
 
 For example, under include_sep=true, Foo::barBaz::Qux2 -> [Foo, ::, bar, Baz,
 ::, Qux, 2].
 
 =item * B<varname>* => I<str>
 
 =back
 
 Return value:  (any)
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Parse-VarName>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Parse-VarName>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Parse-VarName>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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
### Perinci/Access.pm ###
 package Perinci::Access;
 
 our $DATE = '2015-09-03'; # DATE
 our $VERSION = '0.43'; # VERSION
 
 use 5.010001;
 use strict;
 use warnings;
 use Log::Any::IfLOG '$log';
 
 use Scalar::Util qw(blessed);
 use URI::Split qw(uri_split uri_join);
 
 our $Log_Request  = $ENV{LOG_RIAP_REQUEST}  // 0;
 our $Log_Response = $ENV{LOG_RIAP_RESPONSE} // 0;
 
 sub new {
     my ($class, %opts) = @_;
 
     $opts{riap_version}           //= 1.1;
     $opts{handlers}               //= {};
     $opts{handlers}{''}           //= 'Perinci::Access::Schemeless';
     $opts{handlers}{pl}           //= 'Perinci::Access::Perl';
     $opts{handlers}{http}         //= 'Perinci::Access::HTTP::Client';
     $opts{handlers}{https}        //= 'Perinci::Access::HTTP::Client';
     $opts{handlers}{'riap+tcp'}   //= 'Perinci::Access::Simple::Client';
     $opts{handlers}{'riap+unix'}  //= 'Perinci::Access::Simple::Client';
     $opts{handlers}{'riap+pipe'}  //= 'Perinci::Access::Simple::Client';
 
     $opts{_handler_objs}          //= {};
     bless \%opts, $class;
 }
 
 sub _request_or_parse_url {
     my $self = shift;
     my $which = shift;
 
     my ($action, $uri, $extra, $copts);
     if ($which eq 'request') {
         ($action, $uri, $extra, $copts) = @_;
     } else {
         ($uri, $copts) = @_;
     }
 
     my ($sch, $auth, $path, $query, $frag) = uri_split($uri);
     $sch //= "";
     die "Can't handle scheme '$sch' in URL" unless $self->{handlers}{$sch};
 
     # convert riap://perl/Foo/Bar to pl:/Foo/Bar/ as Perl only accepts pl
     if ($sch eq 'riap') {
         $auth //= '';
         die "Unsupported auth '$auth' in riap: scheme, ".
             "only 'perl' is supported" unless $auth eq 'perl';
         $sch = 'pl';
         $auth = undef;
         $uri = uri_join($sch, $auth, $path, $query, $frag);
     }
 
     unless ($self->{_handler_objs}{$sch}) {
         if (blessed($self->{handlers}{$sch})) {
             $self->{_handler_objs}{$sch} = $self->{handlers}{$sch};
         } else {
             my $modp = $self->{handlers}{$sch};
             $modp =~ s!::!/!g; $modp .= ".pm";
             require $modp;
             #$log->tracef("TMP: Creating Riap client object for schema %s with args %s", $sch, $self->{handler_args});
             $self->{_handler_objs}{$sch} = $self->{handlers}{$sch}->new(
                 riap_version => $self->{riap_version},
                 %{ $self->{handler_args} // {}});
         }
     }
 
     my $res;
     if ($which eq 'request') {
         if ($Log_Request && $log->is_trace) {
             $log->tracef(
                 "Riap request (%s): %s -> %s (%s)",
                 ref($self->{_handler_objs}{$sch}),
                 $action, $uri, $extra, $copts);
         }
         $res = $self->{_handler_objs}{$sch}->request(
             $action, $uri, $extra, $copts);
         if ($Log_Response && $log->is_trace) {
             $log->tracef("Riap response: %s", $res);
         }
     } else {
         $res = $self->{_handler_objs}{$sch}->parse_url($uri, $copts);
     }
     $res;
 }
 
 sub request {
     my $self = shift;
     $self->_request_or_parse_url('request', @_);
 }
 
 sub parse_url {
     my $self = shift;
     $self->_request_or_parse_url('parse_url', @_);
 }
 
 1;
 # ABSTRACT: Wrapper for Perinci Riap clients
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Perinci::Access - Wrapper for Perinci Riap clients
 
 =head1 VERSION
 
 This document describes version 0.43 of Perinci::Access (from Perl distribution Perinci-Access), released on 2015-09-03.
 
 =head1 SYNOPSIS
 
  use Perinci::Access;
 
  my $pa = Perinci::Access->new;
  my $res;
 
  ### launching Riap request
 
  # use Perinci::Access::Perl
  $res = $pa->request(call => "pl:/Mod/SubMod/func");
 
  # use Perinci::Access::Schemeless
  $res = $pa->request(call => "/Mod/SubMod/func");
 
  # use Perinci::Access::HTTP::Client
  $res = $pa->request(info => "http://example.com/Sub/ModSub/func",
                      {uri=>'/Sub/ModSub/func'});
 
  # use Perinci::Access::Simple::Client
  $res = $pa->request(meta => "riap+tcp://localhost:7001/Sub/ModSub/");
 
  # dies, unknown scheme
  $res = $pa->request(call => "baz://example.com/Sub/ModSub/");
 
  ### parse URI
 
  $res = $pa->parse_url("/Foo/bar");                              # {proto=>'pl', path=>"/Foo/bar"}
  $res = $pa->parse_url("pl:/Foo/bar");                           # ditto
  $res = $pa->parse_url("riap+unix:/var/run/apid.sock//Foo/bar"); # {proto=>'riap+unix', path=>"/Foo/bar", unix_sock_path=>"/var/run/apid.sock"}
  $res = $pa->parse_url("riap+tcp://localhost:7001/Sub/ModSub/"); # {proto=>'riap+tcp', path=>"/Sub/ModSub/", host=>"localhost", port=>7001}
  $res = $pa->parse_url("http://cpanlists.org/api/");             # {proto=>'http', path=>"/App/cpanlists/Server/"} # will perform an 'info' Riap request to the server first
 
 =head1 DESCRIPTION
 
 This module provides a convenient wrapper to select appropriate Riap client
 (Perinci::Access::*) objects based on URI scheme.
 
  /Foo/Bar/             -> Perinci::Access::Schemeless
  pl:/Foo/Bar           -> Perinci::Access::Perl
  riap://perl/Foo/Bar/  -> Perinci::Access::Perl (converted to pl:/Foo/Bar/)
  http://...            -> Perinci::Access::HTTP::Client
  https://...           -> Perinci::Access::HTTP::Client
  riap+tcp://...        -> Perinci::Access::Simple::Client
  riap+unix://...       -> Perinci::Access::Simple::Client
  riap+pipe://...       -> Perinci::Access::Simple::Client
 
 For more details on each scheme, please consult the appropriate module.
 
 You can customize or add supported schemes by providing class name or object to
 the B<handlers> attribute (see its documentation for more details).
 
 =head1 VARIABLES
 
 =head2 $Log_Request (BOOL)
 
 Whether to log every Riap request. Default is from environment variable
 LOG_RIAP_REQUEST, or false. Logging is done with L<Log::Any> at trace level.
 
 =head2 $Log_Response (BOOL)
 
 Whether to log every Riap response. Default is from environment variable
 LOG_RIAP_RESPONSE, or false. Logging is done with L<Log::Any> at trace level.
 
 =head1 METHODS
 
 =head2 new(%opts) -> OBJ
 
 Create new instance. Known options:
 
 =over 4
 
 =item * handlers => HASH
 
 A mapping of scheme names and class names or objects. If values are class names,
 they will be require'd and instantiated. The default is:
 
  {
    ''           => 'Perinci::Access::Schemeless',
    pl           => 'Perinci::Access::Perl',
    http         => 'Perinci::Access::HTTP::Client',
    https        => 'Perinci::Access::HTTP::Client',
    'riap+tcp'   => 'Perinci::Access::Simple::Client',
    'riap+unix'  => 'Perinci::Access::Simple::Client',
    'riap+pipe'  => 'Perinci::Access::Simple::Client',
  }
 
 Objects can be given instead of class names. This is used if you need to pass
 special options when instantiating the class.
 
 =item * handler_args => HASH
 
 Arguments to pass to handler objects' constructors.
 
 =back
 
 =head2 $pa->request($action, $server_url[, \%extra_keys[, \%client_opts]]) -> RESP
 
 Send Riap request to Riap server. Pass the request to the appropriate Riap
 client (as configured in C<handlers> constructor options). RESP is the enveloped
 result.
 
 C<%extra_keys> is optional, containing Riap request keys (the C<action> request
  key is taken from C<$action>).
 
 C<%client_opts> is optional, containing Riap-client-specific options. For
 example, to pass HTTP credentials to C<Perinci::Access::HTTP::Client>, you can
 do:
 
  $pa->request(call => 'http://example.com/Foo/bar', {args=>{a=>1}},
               {user=>'admin', password=>'secret'});
 
 =head2 $pa->parse_url($server_url[, \%client_opts]) => HASH
 
 Parse C<$server_url> into its components. Will be done by respective subclasses.
 Die on failure (e.g. invalid URL). Return a hash on success, containing at least
 these keys:
 
 =over
 
 =item * proto => STR
 
 =item * path => STR
 
 Code entity path. Most URL schemes include the code entity path as part of the
 URL, e.g. C<pl>, C<riap+unix>, C<riap+tcp>, or C<riap+pipe>. Some do not, e.g.
 C<http> and C<https>. For the latter case, an C<info> Riap request will be sent
 to the server first to find out the code entity path .
 
 =back
 
 Subclasses will add other appropriate keys.
 
 =head1 ENVIRONMENT
 
 LOG_RIAP_REQUEST
 
 LOG_RIAP_RESPONSE
 
 =head1 SEE ALSO
 
 L<Perinci::Access::Schemeless>
 
 L<Perinci::Access::Perl>
 
 L<Perinci::Access::HTTP::Client>
 
 L<Perinci::Access::Simple::Client>
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Perinci-Access>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Perinci-Access>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Perinci-Access>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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
### Perinci/Access/Base.pm ###
 package Perinci::Access::Base;
 
 use 5.010001;
 use strict;
 use warnings;
 
 use URI::Split qw(uri_split);
 
 our $VERSION = '0.33'; # VERSION
 
 sub new {
     my ($class, %opts) = @_;
     $opts{riap_version} //= 1.1;
     bless \%opts, $class;
 }
 
 our $re_var     = qr/\A[A-Za-z_][A-Za-z_0-9]*\z/;
 our $re_req_key = $re_var;
 our $re_action  = $re_var;
 
 # do some basic sanity checks on request
 sub check_request {
     my ($self, $req) = @_;
 
     # XXX schema
     #$req //= {};
     #return [400, "Invalid req: must be hashref"]
     #    unless ref($req) eq 'HASH';
 
     # skipped for squeezing out performance
     #for my $k (keys %$req) {
     #    return [400, "Invalid request key '$k', ".
     #                "please only use letters/numbers"]
     #        unless $k =~ $re_req_key;
     #}
 
     $req->{v} //= 1.1;
     return [500, "Protocol version not supported"]
         if $req->{v} ne '1.1' && $req->{v} ne '1.2';
 
     my $action = $req->{action};
     return [400, "Please specify action"] unless $action;
     return [400, "Invalid action, please only use letters/numbers"]
         unless $action =~ $re_action;
 
     if (defined $req->{uri}) {
         ($req->{-uri_scheme}, $req->{-uri_auth}, $req->{-uri_path},
          $req->{-uri_query}, $req->{-uri_frag}) = uri_split($req->{uri});
     }
 
     # return success for further processing
     0;
 }
 
 1;
 # ABSTRACT: Base class for all Perinci Riap clients
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Perinci::Access::Base - Base class for all Perinci Riap clients
 
 =head1 VERSION
 
 This document describes version 0.33 of Perinci::Access::Base (from Perl distribution Perinci-Access-Base), released on 2015-09-06.
 
 =head1 DESCRIPTION
 
 This is a thin base class for all Riap clients (C<Perinci::Access::*>). It
 currently only provides check_request() which does the following:
 
 =over
 
 =item * perform some basic sanity checking of the Riap request hash C<$req>
 
 =item * split request keys C<uri>
 
 Split result is put in C<< $req->{-uri_scheme} >>, C<< $req->{-uri_auth} >>, C<<
 $req->{-uri_path} >>, C<< $req->{-uri_query} >>, and C<< $req->{-uri_frag} >>.
 
 =back
 
 =head1 ATTRIBUTES
 
 =head2 riap_version => float (default: 1.1)
 
 =head1 METHODS
 
 =head2 new(%args) => OBJ
 
 Constructor. Does nothing except creating a blessed hashref from C<%args>.
 Subclasses should override this method and do additional stuffs as needed.
 
 =head2 check_request($req) => RESP|undef
 
 Should be called by subclasses during the early phase in C<request()>. Will
 return an enveloped error response on error, or undef on success.
 
 =head1 SEE ALSO
 
 L<Perinci::Access>
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Perinci-Access-Base>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Perinci-Access-Base>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Perinci-Access-Base>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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
### Perinci/Access/HTTP/Client.pm ###
 package Perinci::Access::HTTP::Client;
 
 our $DATE = '2015-09-06'; # DATE
 our $VERSION = '0.22'; # VERSION
 
 use 5.010001;
 use strict;
 use warnings;
 use experimental 'smartmatch';
 use Log::Any '$log';
 
 use Perinci::AccessUtil qw(strip_riap_stuffs_from_res);
 use Scalar::Util qw(blessed);
 
 use parent qw(Perinci::Access::Base);
 
 my @logging_methods = Log::Any->logging_methods();
 
 sub new {
     my $class = shift;
 
     my $self = $class->SUPER::new(@_);
 
     # attributes
     $self->{retries}         //= 2;
     $self->{retry_delay}     //= 3;
     unless (defined $self->{log_level}) {
         $self->{log_level} =
             $ENV{TRACE} ? 6 :
                 $ENV{DEBUG} ? 5 :
                     $ENV{VERBOSE} ? 4 :
                         $ENV{QUIET} ? 2 :
                             0;
     }
     $self->{log_callback}    //= undef;
     $self->{ssl_cert_file}   //= $ENV{SSL_CERT_FILE};
     $self->{ssl_ca_file}     //= $ENV{SSL_CA_FILE};
     $self->{user}            //= $ENV{PERINCI_HTTP_USER};
     $self->{password}        //= $ENV{PERINCI_HTTP_PASSWORD};
 
     $self;
 }
 
 # for older Perinci::Access::Base 0.28-, to remove later
 sub _init {}
 
 sub request {
     my ($self, $action, $server_url, $extra, $copts) = @_;
     $extra //= {};
     $copts //= {};
     $log->tracef(
         "=> %s\::request(action=%s, server_url=%s, extra=%s)",
         __PACKAGE__, $action, $server_url, $extra);
     return [400, "Please specify server_url"] unless $server_url;
     my $rreq = { v=>$self->{riap_version},
                  action=>$action,
                  ua=>"Perinci/".($Perinci::Access::HTTP::Client::VERSION//"?"),
                  %$extra };
     my $res = $self->check_request($rreq);
     return $res if $res;
 
     state $json = do {
         require JSON;
         JSON->new->allow_nonref;
     };
 
     state $ua;
     state $callback = sub {
         my ($resp, $ua, $h, $data) = @_;
 
         # we collect HTTP response body into __buffer first. if __mark is set
         # then we need to separate each log message and response part.
         # otherwise, everything just needs to go to __body.
 
         #$log->tracef("got resp: %s (%d bytes)", $data, length($data));
         #say sprintf("D:got resp: %s (%d bytes)", $data, length($data));
 
         if ($ua->{__mark}) {
             $ua->{__buffer} .= $data;
             if ($ua->{__buffer} =~ /\A([lr])(\d+) /) {
                 my ($chtype, $chlen) = ($1, $2);
                 # not enough data yet
                 my $hlen = 1+length($chlen)+1;
                 return 1 unless length($ua->{__buffer}) >= $hlen + $chlen;
                 my $chdata = substr($ua->{__buffer}, $hlen, $chlen);
                 substr($ua->{__buffer}, 0, $hlen+$chlen) = "";
                 if ($chtype eq 'l') {
                     if ($self->{log_callback}) {
                         $self->{log_callback}->($chdata);
                     } else {
                         $chdata =~ s/^\[(\w+)\]//;
                         my $method = $1;
                         $method = "error" unless $method ~~ @logging_methods;
                         $log->$method("[$server_url] $chdata");
                     }
                     return 1;
                 } elsif ($chtype eq 'r') {
                     $ua->{__body} .= $chdata;
                 } else {
                     $ua->{__body} = "[500,\"Unknown chunk type $chtype".
                         "try updating ${\(__PACKAGE__)} version\"]";
                     return 0;
                 }
             } else {
                 $ua->{__body} = "[500,\"Invalid response from server,".
                     " server is probably using older version of ".
                         "Riap::HTTP server library\"]";
                 return 0;
             }
         } else {
             $ua->{__body} .= $data;
         }
     };
 
     if (!$ua) {
         require LWP::UserAgent;
         $ua = LWP::UserAgent->new(
             ssl_opts => {
                 SSL_cert_file => $self->{ssl_cert_file},
                 SSL_ca_file   => $self->{ssl_ca_file},
             },
         );
         $ua->env_proxy;
         $ua->set_my_handler(
             "request_send", sub {
                 my ($req, $ua, $h) = @_;
                 $ua->{__buffer} = "";
                 $ua->{__body} = "";
             });
         $ua->set_my_handler(
             "response_header", sub {
                 my ($resp, $ua, $h) = @_;
                 if ($resp->header('x-riap-logging')) {
                     $ua->{__mark} = 1;
                 } else {
                     $ua->{__log_level} = 0;
                 }
             });
         $ua->set_my_handler(
             "response_data", $callback);
     }
 
     my $authuser = $copts->{user}     // $self->{user};
     my $authpass = $copts->{password} // $self->{password};
     if (defined $authuser) {
         require URI;
         my $suri = URI->new($server_url);
         my $host = $suri->host;
         my $port = $suri->port;
         $ua->credentials(
             "$host:$port",
             $self->{realm} // "restricted area",
             $authuser,
             $authpass,
         );
     }
 
     my $http_req = HTTP::Request->new(POST => $server_url);
     for (keys %$rreq) {
         next if /\A(?:args|fmt|loglevel|_.*)\z/;
         my $hk = "x-riap-$_";
         my $hv = $rreq->{$_};
         if (!defined($hv) || ref($hv)) {
             $hk = "$hk-j-";
             $hv = $json->encode($hv);
         }
         $http_req->header($hk => $hv);
     }
     $ua->{__log_level} = $self->{log_level};
     $http_req->header('x-riap-loglevel' => $ua->{__log_level});
     $http_req->header('x-riap-fmt'      => 'json');
 
     my %args;
     if ($rreq->{args}) {
         for (keys %{$rreq->{args}}) {
             $args{$_} = $rreq->{args}{$_};
         }
     }
     my $args_s = $json->encode(\%args);
     $http_req->header('Content-Type' => 'application/json');
     $http_req->header('Content-Length' => length($args_s));
     $http_req->content($args_s);
 
     #use Data::Dump; dd $http_req;
 
     my $custom_lwp_imp;
     if ($server_url =~ m!\Ahttps?:/[^/]!i) { # XXX we don't support https, rite?
         require LWP::Protocol::http::SocketUnixAlt;
         $custom_lwp_imp = "LWP::Protocol::http::SocketUnixAlt";
     }
 
     my $attempts = 0;
     my $do_retry;
     my $http_res;
     while (1) {
         $do_retry = 0;
 
         my $old_imp;
         if ($custom_lwp_imp) {
             $old_imp = LWP::Protocol::implementor("http");
             LWP::Protocol::implementor("http", $custom_lwp_imp);
         }
 
         eval { $http_res = $ua->request($http_req) };
         my $eval_err = $@;
 
         if ($old_imp) {
             LWP::Protocol::implementor("http", $old_imp);
         }
 
         return [500, "Client died: $eval_err"] if $eval_err;
 
         if ($http_res->code >= 500) {
             $log->warnf("Network failure (%d - %s), retrying ...",
                         $http_res->code, $http_res->message);
             $do_retry++;
         }
 
         if ($do_retry && $attempts++ < $self->{retries}) {
             sleep $self->{retry_delay};
         } else {
             last;
         }
     }
 
     return [500, "Network failure: ".$http_res->code." - ".$http_res->message]
         unless $http_res->is_success;
 
     # empty __buffer
     $callback->($http_res, $ua, undef, "") if length($ua->{__buffer});
 
     return [500, "Empty response from server (1)"]
         if !length($http_res->content);
     return [500, "Empty response from server (2)"]
         unless length($ua->{__body});
 
     eval {
         #say "D:body=$ua->{__body}";
         $log->tracef("body: %s", $ua->{__body});
         $res = $json->decode($ua->{__body});
     };
     my $eval_err = $@;
     return [500, "Invalid JSON from server: $eval_err"] if $eval_err;
 
     #use Data::Dump; dd $res;
     strip_riap_stuffs_from_res($res);
 }
 
 sub parse_url {
     require URI::Split;
 
     my ($self, $uri, $copts) = @_;
     die "Please specify url" unless $uri;
 
     my $res = $self->request(info => $uri, {}, $copts);
     die "Can't 'info' on $uri: $res->[0] - $res->[1]" unless $res->[0] == 200;
 
     my $resuri = $res->[2]{uri};
     my ($sch, $auth, $path) = URI::Split::uri_split($resuri);
     $sch //= "pl";
 
     {proto=>$sch, path=>$path};
 }
 
 1;
 # ABSTRACT: Riap::HTTP client
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Perinci::Access::HTTP::Client - Riap::HTTP client
 
 =head1 VERSION
 
 This document describes version 0.22 of Perinci::Access::HTTP::Client (from Perl distribution Perinci-Access-HTTP-Client), released on 2015-09-06.
 
 =head1 SYNOPSIS
 
  use Perinci::Access::HTTP::Client;
  my $pa = Perinci::Access::HTTP::Client->new;
 
  ## perform Riap requests
 
  # list all functions in package
  my $res = $pa->request(list => 'http://localhost:5000/api/',
                         {uri=>'/Some/Module/', type=>'function'});
  # -> [200, "OK", ['/Some/Module/mult2', '/Some/Module/mult2']]
 
  # call function
  $res = $pa->request(call => 'http://localhost:5000/api/',
                      {uri=>'/Some/Module/mult2', args=>{a=>2, b=>3}});
  # -> [200, "OK", 6]
 
  # get function metadata
  $res = $pa->request(meta => 'http://localhost:5000/api/',
                      {uri=>'/Foo/Bar/multn'});
  # -> [200, "OK", {v=>1.1, summary=>'Multiple many numbers', ...}]
 
  # pass HTTP credentials (via object attribute)
  my $pa = Perinci::Access::HTTP::Client->new(user => 'admin', password=>'123');
  my $res = $pa->request(call => '...', {...});
  # -> [200, "OK", 'result']
 
  # HTTP credentials can also be passed on a per-request basis
  my $pa = Perinci::Access::HTTP::Client->new();
  my $res = $pa->request(call => '...', {...}, {user=>'admin', password=>'123'});
 
  ## parse server URL
  $res = $pa->parse_url("https://cpanlists.org/api/"); # {proto=>"https", path=>"/App/cpanlists/Server/"}
 
 =head1 DESCRIPTION
 
 This class implements L<Riap::HTTP> client.
 
 =for Pod::Coverage ^action_.+
 
 =head1 ATTRIBUTES
 
 =over
 
 =item * realm => STR
 
 For HTTP basic authentication. Defaults to "restricted area" (this is the
 default realm used by L<Plack::Middleware::Auth::Basic>).
 
 =item * user => STR
 
 For HTTP basic authentication. Default will be taken from environment
 C<PERINCI_HTTP_USER>.
 
 =item * password => STR
 
 For HTTP basic authentication. Default will be taken from environment
 C<PERINCI_HTTP_PASSWORD>.
 
 =item * ssl_cert_file => STR
 
 Path to SSL client certificate. Default will be taken from environment
 C<SSL_CERT_FILE>.
 
 =item * ssl_cert_file => STR
 
 Path to SSL CA certificate. Default will be taken from environment
 C<SSL_CA_FILE>.
 
 =back
 
 =head1 METHODS
 
 =head2 PKG->new(%attrs) => OBJ
 
 Instantiate object. Known attributes:
 
 =over
 
 =item * retries => INT (default 2)
 
 Number of retries to do on network failure. Setting it to 0 will disable
 retries.
 
 =item * retry_delay => INT (default 3)
 
 Number of seconds to wait between retries.
 
 =item * log_level => INT (default 0 or from environment)
 
 Will be fed into Riap request key 'loglevel' (if >0). Note that some servers
 might forbid setting log level.
 
 If TRACE environment variable is true, default log_level will be set to 6. If
 DEBUG, 5. If VERBOSE, 4. If quiet, 1. Else 0.
 
 =item * log_callback => CODE
 
 Pass log messages from the server to this subroutine. If not specified, log
 messages will be "rethrown" into Log::Any logging methods (e.g. $log->warn(),
 $log->debug(), etc).
 
 =back
 
 =head2 $pa->request($action => $server_url[, \%extra_keys[, \%client_opts]]) => $res
 
 Send Riap request to $server_url. Note that $server_url is the HTTP URL of Riap
 server. You will need to specify code entity URI via C<uri> key in %extra_keys.
 
 C<%extra_keys> is optional and contains additional Riap request keys (except
 C<action>, which is taken from C<$action>).
 
 C<%client_opts> is optional and contains additional information, like C<user>
 (HTTP authentication user, overrides one in object attribute), C<password> (HTTP
 authentication user, overrides one in object attribute).
 
 =head2 $pa->parse_url($server_url[, \%client_opts]) => HASH
 
 =head1 ENVIRONMENT
 
 C<PERINCI_HTTP_USER>.
 
 C<PERINCI_HTTP_PASSWORD>.
 
 C<SSL_CERT_FILE>, C<SSL_CA_FILE>.
 
 =head1 FAQ
 
 =head2 How do I connect to a HTTP server that listens on a Unix socket?
 
 This class can switch to using L<LWP::Protocol::http::SocketUnixAlt> when it
 detects that the server is on a Unix socket, using this syntax (notice the
 single instead of double slash after C<http:>):
 
  http:/path/to/unix.sock//uri
 
 =head2 How do I connect to an HTTPS server without a "real" SSL certificate?
 
 Since this module is using L<LWP>, you can set environment variable
 C<PERL_LWP_SSL_VERIFY_HOSTNAME> to 0. See LWP for more details.
 
 =head1 SEE ALSO
 
 L<Perinci::Access::HTTP::Server>
 
 L<Riap>, L<Rinci>
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Perinci-Access-HTTP-Client>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Perinci-Access-HTTP-Client>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Perinci-Access-HTTP-Client>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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
### Perinci/Access/Lite.pm ###
 package Perinci::Access::Lite;
 
 our $DATE = '2015-09-03'; # DATE
 our $VERSION = '0.11'; # VERSION
 
 use 5.010001;
 use strict;
 use warnings;
 
 use Perinci::AccessUtil qw(strip_riap_stuffs_from_res);
 
 sub new {
     my ($class, %args) = @_;
     $args{riap_version} //= 1.1;
     bless \%args, $class;
 }
 
 # copy-pasted from SHARYANTO::Package::Util
 sub __package_exists {
     no strict 'refs';
 
     my $pkg = shift;
 
     return unless $pkg =~ /\A\w+(::\w+)*\z/;
     if ($pkg =~ s/::(\w+)\z//) {
         return !!${$pkg . "::"}{$1 . "::"};
     } else {
         return !!$::{$pkg . "::"};
     }
 }
 
 sub request {
     no strict 'refs';
 
     my ($self, $action, $url, $extra) = @_;
 
     #say "D:request($action => $url)";
 
     $extra //= {};
 
     my $v = $extra->{v} // 1.1;
     if ($v ne '1.1' && $v ne '1.2') {
         return [501, "Riap protocol not supported, must be 1.1 or 1.2"];
     }
 
     my $res;
     if ($url =~ m!\A(?:pl:)?/(\w+(?:/\w+)*)/(\w*)\z!) {
         my ($mod_uripath, $func) = ($1, $2);
         (my $pkg = $mod_uripath) =~ s!/!::!g;
         my $mod_pm = "$mod_uripath.pm";
 
         my $pkg_exists;
 
       LOAD:
         {
             last if exists $INC{$mod_pm};
             $pkg_exists = __package_exists($pkg);
             # special names
             last LOAD if $pkg =~ /\A(main)\z/;
             last if $pkg_exists && defined(${"$pkg\::VERSION"});
             #say "D:Loading $pkg ...";
             eval { require $mod_pm };
             return [500, "Can't load module $pkg: $@"] if $@;
         }
 
         if ($action eq 'list') {
             return [501, "Action 'list' not implemented for ".
                         "non-package entities"]
                 if length($func);
             no strict 'refs';
             my $spec = \%{"$pkg\::SPEC"};
             return [200, "OK (list)", [grep {/\A\w+\z/} sort keys %$spec]];
         } elsif ($action eq 'info') {
             my $data = {
                 uri => "$mod_uripath/$func",
                 type => (!length($func) ? "package" :
                              $func =~ /\A\w+\z/ ? "function" :
                                  $func =~ /\A[\@\$\%]/ ? "variable" :
                                      "?"),
             };
             return [200, "OK (info)", $data];
         } elsif ($action eq 'meta' || $action eq 'call') {
             return [501, "Action 'call' not implemented for package entity"]
                 if !length($func) && $action eq 'call';
             my $meta;
             {
                 no strict 'refs';
                 if (length $func) {
                     $meta = ${"$pkg\::SPEC"}{$func}
                         or return [
                             500, "No metadata for '$url' (".
                                 ($pkg_exists ? "package '$pkg' exists, perhaps you mentioned '$pkg' somewhere without actually loading the module, or perhaps '$func' is a typo?" :
                                      "package '$pkg' doesn't exist, perhaps '$mod_uripath' or '$func' is a typo?") .
                                 ")"];
                 } else {
                     $meta = ${"$pkg\::SPEC"}{':package'} // {v=>1.1};
                 }
                 $meta->{entity_v}    //= ${"$pkg\::VERSION"};
                 $meta->{entity_date} //= ${"$pkg\::DATE"};
             }
 
             require Perinci::Sub::Normalize;
             $meta = Perinci::Sub::Normalize::normalize_function_metadata($meta);
             return [200, "OK ($action)", $meta] if $action eq 'meta';
 
             # form args (and add special args)
             my $args = { %{$extra->{args} // {}} }; # shallow copy
             if ($meta->{features} && $meta->{features}{progress}) {
                 require Progress::Any;
                 $args->{-progress} = Progress::Any->get_indicator;
             }
 
             # convert args
             my $aa = $meta->{args_as} // 'hash';
             my @args;
             if ($aa =~ /array/) {
                 require Perinci::Sub::ConvertArgs::Array;
                 my $convres = Perinci::Sub::ConvertArgs::Array::convert_args_to_array(
                     args => $args, meta => $meta,
                 );
                 return $convres unless $convres->[0] == 200;
                 if ($aa =~ /ref/) {
                     @args = ($convres->[2]);
                 } else {
                     @args = @{ $convres->[2] };
                 }
             } elsif ($aa eq 'hashref') {
                 @args = ({ %$args });
             } else {
                 # hash
                 @args = %$args;
             }
 
             # call!
             {
                 no strict 'refs';
                 $res = &{"$pkg\::$func"}(@args);
             }
 
             # add envelope
             if ($meta->{result_naked}) {
                 $res = [200, "OK (envelope added by ".__PACKAGE__.")", $res];
             }
 
             # add hint that result is binary
             if (defined $res->[2]) {
                 if ($meta->{result} && $meta->{result}{schema} &&
                         $meta->{result}{schema}[0] eq 'buf') {
                     $res->[3]{'x.hint.result_binary'} = 1;
                 }
             }
 
         } else {
             return [501, "Unknown/unsupported action '$action'"];
         }
     } elsif ($url =~ m!\Ahttps?:/(/?)!i) {
         my $is_unix = !$1;
         my $ht;
         require JSON;
         state $json = JSON->new->allow_nonref;
         if ($is_unix) {
             require HTTP::Tiny::UNIX;
             $ht = HTTP::Tiny::UNIX->new;
         } else {
             require HTTP::Tiny;
             $ht = HTTP::Tiny->new;
         }
         my %headers = (
             "x-riap-v" => $self->{riap_version},
             "x-riap-action" => $action,
             "x-riap-fmt" => "json",
             "content-type" => "application/json",
         );
         my $args = $extra->{args} // {};
         for (keys %$extra) {
             next if /\Aargs\z/;
             $headers{"x-riap-$_"} = $extra->{$_};
         }
         my $htres = $ht->post(
             $url, {
                 headers => \%headers,
                 content => $json->encode($args),
             });
         return [500, "Network error: $htres->{status} - $htres->{reason}"]
             if $htres->{status} != 200;
         return [500, "Server error: didn't return JSON (".$htres->{headers}{'content-type'}.")"]
             unless $htres->{headers}{'content-type'} eq 'application/json';
         return [500, "Server error: didn't return Riap 1.1 response (".$htres->{headers}{'x-riap-v'}.")"]
             unless $htres->{headers}{'x-riap-v'} =~ /\A1\.1(\.\d+)?\z/;
         $res = $json->decode($htres->{content});
     } else {
         return [501, "Unsupported scheme or bad URL '$url'"];
     }
 
     strip_riap_stuffs_from_res($res);
 }
 
 1;
 # ABSTRACT: A lightweight Riap client library
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Perinci::Access::Lite - A lightweight Riap client library
 
 =head1 VERSION
 
 This document describes version 0.11 of Perinci::Access::Lite (from Perl distribution Perinci-Access-Lite), released on 2015-09-03.
 
 =head1 DESCRIPTION
 
 This module is a lightweight alternative to L<Perinci::Access>. It has less
 prerequisites but does fewer things. The things it supports:
 
 =over
 
 =item * Local (in-process) access to Perl modules and functions
 
 Currently only C<call>, C<meta>, and C<list> actions are implemented. Variables
 and other entities are not yet supported.
 
 The C<list> action only gathers keys from C<%SPEC> and do not yet list
 subpackages.
 
 =item * HTTP/HTTPS
 
 =item * HTTP over Unix socket
 
 =back
 
 Differences with Perinci::Access:
 
 =over
 
 =item * For network access, uses HTTP::Tiny module family instead of LWP
 
 This results in fewer dependencies.
 
 =item * No wrapping, no argument checking
 
 For 'pl' or schemeless URL, no wrapping (L<Perinci::Sub::Wrapper>) is done, only
 normalization (using L<Perinci::Sub::Normalize>).
 
 =item * No transaction or logging support
 
 =item * No support for some schemes
 
 This includes: Riap::Simple over pipe/TCP socket.
 
 =back
 
 =head1 ATTRIBUTES
 
 =head2 riap_version => float (default: 1.1)
 
 =head1 METHODS
 
 =head2 new(%attrs) => obj
 
 =head2 $pa->request($action, $url, $extra) => hash
 
 =head1 ADDED RESULT METADATA
 
 This class might add the following property/attribute in result metadata:
 
 =head2 x.hint.result_binary => bool
 
 If result's schema type is C<buf>, then this class will set this attribute to
 true, to give hints to result formatters.
 
 =head1 SEE ALSO
 
 L<Perinci::Access>
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Perinci-Access-Lite>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Perinci-Access-Lite>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Perinci-Access-Lite>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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
### Perinci/Access/Perl.pm ###
 package Perinci::Access::Perl;
 
 our $DATE = '2015-09-03'; # DATE
 our $VERSION = '0.84'; # VERSION
 
 use 5.010001;
 use strict;
 use warnings;
 
 use URI::Split qw(uri_split);
 
 use parent qw(Perinci::Access::Schemeless);
 
 sub new {
     my $class = shift;
 
     my $self = $class->SUPER::new(@_);
 
     # The pl: uri scheme has a 1:1 mapping between Perl package and path, so
     # /Foo/Bar/ must mean the Foo::Bar package. We don't allow package_prefix or
     # anything fancy like that.
     delete $self->{package_prefix};
 
     $self->{allow_schemes} = ['pl', ''];
     $self->{deny_schemes} = undef;
 
     $self;
 }
 
 sub parse_url {
     my ($self, $uri) = @_;
     die "Please specify url" unless $uri;
 
     my ($sch, $auth, $path) = uri_split($uri);
     $sch //= "";
 
     die "Only pl uri scheme is supported" unless $sch eq 'pl';
     {proto=>"pl", path=>$path};
 }
 
 1;
 # ABSTRACT: Access Perl module, functions, variables through Riap
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Perinci::Access::Perl - Access Perl module, functions, variables through Riap
 
 =head1 VERSION
 
 This document describes version 0.84 of Perinci::Access::Perl (from Perl distribution Perinci-Access-Perl), released on 2015-09-03.
 
 =head1 SYNOPSIS
 
 First write your code and add Rinci metadata to them:
 
  package MyMod::MySubMod;
 
  our %SPEC;
 
  $SPEC{':package'} = {
      v => 1.1,
      summary => 'This package is blah blah',
  };
 
  $SPEC{'$var1'} = {
      v => 1.1,
      summary => 'This variable is blah blah',
  };
  our $var1;
 
  $SPEC{func1} = {
      v => 1.1,
      summary => 'This function does blah blah',
      args => {
          a => { schema => 'int', req => 1 },
          b => { schema => 'int' },
      },
  };
  sub func1 {
      ...
  }
  1;
 
 then access them through Riap:
 
  use Perinci::Access::Perl;
  my $pa = Perinci::Access::Perl->new;
 
  # call function
  $res = $pa->request(call => '/MyMod/MySubMod/func1', {args=>{a=>1, b=>2}});
 
  # get variables
  $res = $pa->request(get => '/MyMod/MySubMod/$var1');
 
 =head1 DESCRIPTION
 
 This class allows you to access Perl modules, functions, and variables through
 Riap. Only those which have L<Rinci> metadata are accessible. The metadata is
 put in C<%SPEC> package variables, with function names as keys, or C<:package>
 for package metadata, or C<$NAME> for variables. Functions will be wrapped
 before executed (unless you pass C<< wrap => 0 >> to the constructor).
 
 You should probably use this through L<Perinci::Access>.
 
 =head1 FUNCTIONS
 
 =head2 new(%opts) => OBJ
 
 Constructor. For a list of options, see superclass
 L<Perinci::Access::Schemeless> except for C<package_prefix> which are not
 recognized by this class.
 
 =head2 $pa->request($action, $uri, \%extras) => RESP
 
 =head2 $pa->parse_url($url) => HASH
 
 =head1 FAQ
 
 =head2 Why C<%SPEC> (instead of C<%META>, C<%METADATA>, C<%RINCI>, etc)?
 
 The name was first chosen during Sub::Spec era (see BackPAN) in 2011, it stuck.
 By that time I already had had a lot of code written using C<%SPEC>.
 
 =head2 Why wrap?
 
 The wrapping process accomplishes several things, among others: checking of
 metadata, normalization of schemas in metadata, also argument validation and
 exception trapping in function.
 
 The function wrapping introduces a small overhead when performing a sub call
 (typically around several to tens of microseconds on an Intel Core i5 1.7GHz
 notebook). This is usually smaller than the overhead of Perinci::Access::Perl
 itself (typically in the range of 100 microseconds). But if you are concerned
 about the wrapping overhead, see the C<< wrap => 0 >> option.
 
 =head1 SEE ALSO
 
 L<Perinci::Access::Schemeless>
 
 L<Perinci::Access>
 
 L<Riap>
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Perinci-Access-Perl>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Perinci-Access-Perl>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Perinci-Access-Perl>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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
### Perinci/Access/Schemeless.pm ###
 package Perinci::Access::Schemeless;
 
 our $DATE = '2015-09-03'; # DATE
 our $VERSION = '0.84'; # VERSION
 
 use 5.010001;
 use strict;
 use warnings;
 use experimental 'smartmatch';
 use Log::Any::IfLOG '$log';
 
 use parent qw(Perinci::Access::Base);
 
 use List::Util qw(first);
 use Perinci::Object;
 use Perinci::Sub::Normalize qw(normalize_function_metadata);
 use Perinci::Sub::Util qw(err);
 use Scalar::Util qw(blessed);
 use Module::Path::More qw(module_path);
 use Package::MoreUtil qw(package_exists);
 use Tie::Cache;
 use URI::Split qw(uri_split uri_join);
 
 our $re_perl_package =
     qr/\A[A-Za-z_][A-Za-z_0-9]*(::[A-Za-z_][A-Za-z_0-9]*)*\z/;
 
 sub new {
     require Class::Inspector;
 
     my $class = shift;
     my $self = $class->SUPER::new(@_);
 
     # build a list of supported actions for each type of entity
     my %typeacts = (
         package  => [],
         function => [],
         variable => [],
     ); # key = type, val = [[ACTION, META], ...]
 
     my @comacts;
     for my $meth (@{Class::Inspector->methods(ref $self)}) {
         next unless $meth =~ /^actionmeta_(.+)/;
         my $act = $1;
         my $meta = $self->$meth();
         $self->{_actionmetas}{$act} = $meta;
         for my $type (@{$meta->{applies_to}}) {
             if ($type eq '*') {
                 push @comacts, [$act, $meta];
             } else {
                 push @{$typeacts{$type}}, [$act, $meta];
             }
         }
     }
     for my $type (keys %typeacts) {
         $typeacts{$type} = { map {$_->[0] => $_->[1]}
                                  @{$typeacts{$type}}, @comacts };
     }
     $self->{_typeacts} = \%typeacts;
 
     $self->{cache_size}              //= 100; # for caching metadata & code
     #$self->{use_tx}                  //= 0;
     $self->{wrap}                    //= 1;
     #$self->{custom_tx_manager}       //= undef;
     $self->{load}                    //= 1;
     $self->{set_function_properties} //= {};
     $self->{normalize_metadata}      //= 1;
     #$self->{after_load}
     #$self->{allow_paths}
     #$self->{deny_paths}
     #$self->{allow_schemes}
     #$self->{deny_schemes}
     #$self->{package_prefix}
     $self->{debug}                   //= $ENV{PERINCI_ACCESS_SCHEMELESS_DEBUG} // 0;
     $self->{accept_argv}             //= 1;
 
     if ($self->{cache_size} > 0) {
         my %metacache;
         tie %metacache, 'Tie::Cache', $self->{cache_size};
         $self->{_meta_cache} = \%metacache;
         my %codecache;
         tie %codecache, 'Tie::Cache', $self->{cache_size};
         $self->{_code_cache} = \%codecache;
     }
 
     $self;
 }
 
 # for older Perinci::Access::Base 0.28-, to remove later
 sub _init {}
 
 # if paths=/a/b, will match /a/b as well as /a/b/c
 sub __match_paths {
     my ($path, $paths) = @_;
 
     my $pathslash = $path =~ m!/\z! ? $path : "$path/";
 
     for (ref($paths) eq 'ARRAY' ? @$paths : $paths) {
         if (ref($_) eq 'Regexp') {
             return 1 if $path =~ $_;
         } else {
             if (m!/\z!) {
                 return 1 if $_ eq $pathslash || index($pathslash, $_) == 0;
             } else {
                 my $p = "$_/";
                 return 1 if $p eq $path || index($pathslash, $p) == 0;
             }
         }
     }
     0;
 }
 
 # if paths=/a/b, will match /a/b as well as /a/b/c AS WELL AS /a and /. only
 # suitable for 'list' action, e.g. allow_path is '/a/b' but we can do 'list /'
 # and 'list /a' too (but not 'list /c').
 sub __match_paths2 {
     my ($path, $paths) = @_;
 
     my $pathslash = $path =~ m!/\z! ? $path : "$path/";
 
     for (ref($paths) eq 'ARRAY' ? @$paths : $paths) {
         if (ref($_) eq 'Regexp') {
             # we can't match a regex against a string, so we just pass here
             return 1;
         } else {
             if (m!/\z!) {
                 return 1 if $_ eq $pathslash || index($_, $pathslash) == 0 ||
                     index($pathslash, $_) == 0;
             } else {
                 my $p = "$_/";
                 return 1 if $p eq $path || index($p, $pathslash) == 0 ||
                     index($pathslash, $p) == 0 ;
             }
         }
     }
     0;
 }
 
 sub _parse_uri {
     my ($self, $req) = @_;
 
     my $path = $req->{-uri_path};
     if (defined $self->{allow_paths}) {
         my $allow;
         if ($self->{_actionmetas}{$req->{action}}{allow_request_parent_path}) {
             $allow = __match_paths2($path, $self->{allow_paths});
         } else {
             $allow = __match_paths($path, $self->{allow_paths});
         }
         return err(403, "Forbidden uri path (does not match allow_paths)")
             unless $allow;
     }
     if (defined($self->{deny_paths}) &&
             __match_paths($path, $self->{deny_paths})) {
         return err(403, "Forbidden uri path (matches deny_paths)");
     }
 
     my $sch = $req->{-uri_scheme} // "";
     if (defined($self->{allow_schemes}) && !($sch ~~ $self->{allow_schemes})) {
         return err(501,
                    "Unsupported uri scheme (does not match allow_schemes)");
     }
     if (defined($self->{deny_schemes}) && ($sch ~~ $self->{deny_schemes})) {
         return err(501, "Unsupported uri scheme (matches deny_schemes)");
     }
 
     my ($dir, $leaf, $perl_package);
     if ($path =~ m!(.*)/(.*)!) {
         $dir  = $1;
         $leaf = $2;
     } else {
         $dir  = $path;
         $leaf = '';
     }
     for ($perl_package) {
         $_ = $dir;
         s!^/+!!;
         s!/+!::!g;
         if (defined $self->{package_prefix}) {
             $_ = $self->{package_prefix} . (length($_) ? "::":"") . $_;
         }
     }
     return err(400, "Invalid perl package name: $perl_package")
         if $perl_package && $perl_package !~ $re_perl_package;
 
     my $type;
     if (length $leaf) {
         if ($leaf =~ /^[%\@\$]/) {
             $type = 'variable';
         } else {
             $type = 'function';
         }
     } else {
         $type = 'package';
         # make sure path ends in /, to ease processing
         $req->{-uri_path} .= "/" unless $path =~ m!/\z!;
     }
 
     $req->{-uri_dir}      = $dir;
     $req->{-uri_leaf}     = $leaf;
     $req->{-perl_package} = $perl_package;
     $req->{-type}         = $type;
 
     #$log->tracef("TMP: req=%s", $req);
     return;
 }
 
 # key = module_p, val = error resp or undef if successful
 my %loadcache;
 tie %loadcache, 'Tie::Cache', 200;
 
 sub _load_module {
     my ($self, $req) = @_;
 
     my $pkg = $req->{-perl_package};
 
     # skip there is no module to load
     return if !$pkg;
 
     # if we are instructed not to load any module, we just check via existence
     # of packages
     unless ($self->{load}) {
         return if package_exists($pkg);
         return err(500, "Package $pkg does not exist");
     }
 
     my $module_p = $pkg;
     $module_p =~ s!::!/!g;
     $module_p .= ".pm";
 
     # module has been required before and successfully loaded
     return if $INC{$module_p};
 
     # module has been required before and failed
     return err(500, "Module $pkg has failed to load previously" .
                    $loadcache{$module_p} ?
                        ": $loadcache{$module_p}[0] - $loadcache{$module_p}[1]" :
                            "")
         if exists($INC{$module_p});
 
     # use cache result (for caching errors, or packages like 'main' and 'CORE'
     # where no modules for such packages exist)
     return $loadcache{$module_p} if exists $loadcache{$module_p};
 
     # load and cache negative result
     my $res;
     {
         my $fullpath = module_path(module=>$pkg, find_pmc=>0, find_prefix=>1);
 
         # when the module path does not exist, but the package does, we can
         # ignore this error. for example: main, CORE, etc.
         my $pkg_exists = package_exists($pkg);
 
         if (!$fullpath) {
             last if $pkg_exists;
             $res = [404, "Can't find module or prefix path for package $pkg"];
             last;
         } elsif ($fullpath !~ /\.pm$/) {
             last if $pkg_exists;
             $res = [405, "Can only find a prefix path for package $pkg"];
             last;
         }
         eval { require $module_p };
         if ($@) {
             $res = [500, "Can't load module $pkg (probably compile error): $@"];
             last;
         }
         # load is successful
         if ($self->{after_load}) {
             eval { $self->{after_load}($self, module=>$pkg) };
             $log->error("after_load for package $pkg dies: $@") if $@;
         }
     }
     $loadcache{$module_p} = $res;
     return $res;
 }
 
 sub __inject_entity_v_date {
     no strict 'refs';
 
     my ($req, $meta) = @_;
 
     my $pkg = $req->{-perl_package};
     unless (defined $meta->{entity_v}) {
         my $ver = ${"$pkg\::VERSION"};
         if (defined $ver) {
             $meta->{entity_v} = $ver;
         }
     }
     unless (defined $meta->{entity_date}) {
         my $date = ${"$pkg\::DATE"};
         if (defined $date) {
             $meta->{entity_date} = $date;
         }
     }
 }
 
 sub get_meta {
     no strict 'refs';
 
     my ($self, $req) = @_;
 
     my $pkg  = $req->{-perl_package};
     my $leaf = $req->{-uri_leaf};
     my $type = $req->{-type};
     if (!length($pkg)) {
         if (length $leaf) {
             # 404 for all non-subpackage entity directly under /
             return [404, "No metadata for ::$leaf (".
                 (package_exists($pkg) ? "package '$pkg' exists, perhaps you mentioned '$pkg' somewhere without actually loading the module, or perhaps '$leaf' is a typo?" :
                      "package '$pkg' doesn't exist, perhaps '$pkg' or '$leaf' is a typo?").
                     ")"
             ];
         } else {
             # empty metadata for root (/)
             $req->{-meta} = {v=>1.1};
             return;
         }
     }
 
     my $name = "$pkg\::$leaf";
     if ($self->{_meta_cache}{$name}) {
         $req->{-meta} = $self->{_meta_cache}{$name};
         return;
     }
 
     my $res = $self->_load_module($req);
     # missing module (but existing prefix) is okay for package, we construct an
     # empty package metadata for it
     return $res if $res && !($type eq 'package' && $res->[0] == 405);
 
     my $meta;
     my $metas = \%{"$pkg\::SPEC"};
     $meta = $metas->{ $leaf || ":package" };
 
     if (!$meta && $type eq 'package') {
         $meta = {v=>1.1};
     }
 
     return err(404,
                join("",
                     "No metadata for $name (package '$pkg' exists, ",
                     "perhaps you mentioned '$pkg' ",
                     "somewhere without actually loading the module, or ",
                     "perhaps '$leaf' is a typo?)",
                 )) unless $meta;
 
     if ($res) {
         if ($res->[0] == 405) {
             $meta = {v=>1.1}; # empty package metadata for dir
         } elsif ($res->[0] != 200) {
             return $res;
         }
     }
 
     # normalize has only been implemented for function
     if ($type eq 'function' && $self->{normalize_metadata}) {
         eval { $meta = normalize_function_metadata($meta) };
         if ($@) {
             return [500, "Can't normalize function metadata: $@"];
         }
 
         $meta->{args} //= {};
         $meta->{args_as} = 'hash';
         $meta->{result_naked} = 0;
         my $sfp = $self->{set_function_properties};
         $meta->{$_} = $sfp->{$_} for keys %$sfp;
     }
 
     __inject_entity_v_date($req, $meta);
 
     if ($self->{cache_size} > 0) {
         $self->{_meta_cache}{$name} = $meta;
     }
 
     $req->{-meta} = $meta;
     return;
 }
 
 sub get_code {
     my ($self, $req) = @_;
 
     # because we're lazy, we assume here that type is already function. it
     # should be okay since get_code() is only called by action_call().
 
     my $name = $req->{-perl_package} . "::" . $req->{-uri_leaf};
     if ($self->{_code_cache}{$name}) {
         $req->{-code} = $self->{_code_cache}{$name};
         return;
     }
 
     my $res = $self->_load_module($req);
     return $res if $res;
 
     return err(404, "Can't find function $req->{-uri_leaf} in ".
                    "module $req->{-perl_package}")
         unless defined &{$name};
 
     # we get our own meta and not use get_meta() because we want to get the
     # original metadata
     my $meta;
     {
         no strict 'refs';
         my $metas = \%{"$req->{-perl_package}::SPEC"};
         $meta = $metas->{ $req->{-uri_leaf} || ":package" };
     }
 
     return err(404, "Can't find function metadata $req->{-uri_leaf} in ".
                    "module $req->{-perl_package}")
         unless $meta;
 
     my $code;
   GET_CODE:
     {
         # we don't need to wrap
         if (!$self->{wrap} ||
                 $meta->{"x.perinci.sub.wrapper.logs"} &&
                     (first {$_->{validate_args}}
                          @{ $meta->{"x.perinci.sub.wrapper.logs"} })
             ) {
             $code = \&{$name};
             last GET_CODE;
         }
 
         require Perinci::Sub::Wrapper;
         my $wrapres = Perinci::Sub::Wrapper::wrap_sub(
             sub_name=>$name, meta=>$meta,
             convert=>{args_as=>'hash', result_naked=>0,
                       %{$self->{set_function_properties}},
                   });
         return err(500, "Can't wrap function", $wrapres)
             unless $wrapres->[0] == 200;
         $code = $wrapres->[2]{sub};
 
         if ($self->{cache_size} > 0) {
             $self->{_code_cache}{$name} = $code;
             # also put wrapper-generated meta in the cache, so further meta
             # request can use this. the metadata from wrapper contains wrapper
             # logs (x.perinci.sub.wrapper.logs) which can be helpful hint for
             # some uses.
             my $meta   = $wrapres->[2]{meta};
             __inject_entity_v_date($req, $meta);
             $self->{_meta_cache}{$name} = $meta;
         }
     }
 
     $req->{-code} = $code;
     return;
 }
 
 sub request {
     no strict 'refs';
 
     my ($self, $action, $uri, $extra) = @_;
 
     return err(400, "Please specify URI") unless $uri;
 
     my $req = { action=>$action, uri=>$uri, %{$extra // {}} };
     my $res = $self->check_request($req);
     return $res if $res;
 
     return err(501, "Action '$action' not implemented")
         unless $self->can("actionmeta_$action");
 
     my $am = $self->${\("actionmeta_$action")};
 
     $res = $self->_parse_uri($req);
     return $res if $res;
 
     return err(501, "Action '$action' not implemented for ".
                    "'$req->{-type}' entity")
         unless $am->{applies_to}[0] eq '*' ||
             $req->{-type} ~~ @{ $am->{applies_to} };
 
     my $meth = "action_$action";
     # check transaction
 
     $res = $self->$meth($req);
     if ($self->{debug}) {
         $res->[3] //= {};
         $res->[3]{debug} = {
             req => $req,
         };
     }
     $res;
 }
 
 sub parse_url {
     my ($self, $uri) = @_;
     die "Please specify url" unless $uri;
     my ($sch, $auth, $path) = uri_split($uri);
     return {
         # to mark that we are schemeless
         proto=>'',
         path=>$path,
     };
 }
 
 sub actionmeta_info { +{
     applies_to => ['*'],
     summary    => "Get general information on code entity",
     needs_meta => 0,
     needs_code => 0,
 } }
 
 sub action_info {
     my ($self, $req) = @_;
 
     my $mres = $self->get_meta($req);
     return $mres if $mres;
 
     my $res = {
         uri  => $req->{uri},
         type => $req->{-type},
     };
 
     [200, "OK (info action)", $res];
 }
 
 sub actionmeta_actions { +{
     applies_to => ['*'],
     summary    => "List available actions for code entity",
     needs_meta => 0,
     needs_code => 0,
 } }
 
 sub action_actions {
     my ($self, $req) = @_;
 
     my $mres = $self->get_meta($req);
     return $mres if $mres;
 
     my @res;
     for my $k (sort keys %{ $self->{_typeacts}{$req->{-type}} }) {
         my $v = $self->{_typeacts}{$req->{-type}}{$k};
         if ($req->{detail}) {
             push @res, {name=>$k, summary=>$v->{summary}};
         } else {
             push @res, $k;
         }
     }
     [200, "OK (actions action)", \@res];
 }
 
 sub actionmeta_list { +{
     applies_to => ['package'],
     summary    => "List code entities inside this package code entity",
     # this means, even if allow_path is '/a/b', we allow request on '/a' or '/'.
     allow_request_parent_path => 1,
 } }
 
 sub action_list {
     require Module::List;
 
     my ($self, $req) = @_;
     my $detail = $req->{detail};
     my $f_type = $req->{type} || "";
 
     my @res;
 
     my $filter_path = sub {
         my $path = shift;
         if (defined($self->{allow_paths}) &&
                 !__match_paths2($path, $self->{allow_paths})) {
             return 0;
         }
         if (defined($self->{deny_paths}) &&
                 __match_paths2($path, $self->{deny_paths})) {
             return 0;
         }
         1;
     };
 
     my %mem;
 
     # get submodules
     unless ($f_type && $f_type ne 'package') {
         my $lres = Module::List::list_modules(
             $req->{-perl_package} ? "$req->{-perl_package}\::" : "",
             {list_modules=>1, list_prefixes=>1});
         my $dir = $req->{-uri_dir};
         for my $m (sort keys %$lres) {
             $m =~ s!::$!!;
             $m =~ s!.+::!!;
             my $path = "$dir/$m/";
             next unless $filter_path->($path);
             next if $mem{$path}++;
             if ($detail) {
                 push @res, {uri=>"$m/", type=>"package"};
             } else {
                 push @res, "$m/";
             }
         }
     }
 
     my $res = $self->_load_module($req);
     return $res if $res && $res->[0] != 405;
 
     # get all entities from this module
     no strict 'refs';
     my $spec = \%{"$req->{-perl_package}\::SPEC"};
     my $dir = $req->{-uri_dir};
     for my $e (sort keys %$spec) {
         next if $e =~ /^:/;
         my $path = "$dir/$e";
         next unless $filter_path->($path);
         next if $mem{$path}++;
         my $t = $e =~ /^[%\@\$]/ ? 'variable' : 'function';
         next if $f_type && $f_type ne $t;
         if ($detail) {
             push @res, {
                 uri=>$e, type=>$t,
             };
         } else {
             push @res, $e;
         }
     }
 
     [200, "OK (list action)", \@res];
 }
 
 sub actionmeta_meta { +{
     applies_to => ['*'],
     summary    => "Get metadata",
 } }
 
 sub action_meta {
     my ($self, $req) = @_;
 
     my $res = $self->get_meta($req);
     return $res if $res;
 
     [200, "OK (meta action)", $req->{-meta}];
 }
 
 sub actionmeta_call { +{
     applies_to => ['function'],
     summary    => "Call function",
 } }
 
 sub action_call {
     require UUID::Random;
 
     my ($self, $req) = @_;
 
     my $res;
 
     my $tm; # = does client mention tx_id?
     if (defined $req->{tx_id}) {
         $res = $self->_pre_tx_action($req);
         return $res if $res;
         $tm = $self->{_tx_manager};
         $tm->{_tx_id} = $req->{tx_id};
     }
 
     $res = $self->get_meta($req);
     return $res if $res;
     $res = $self->get_code($req);
     return $res if $res;
 
     my %args;
 
     # try to convert from argv if given argv
     if (exists($req->{argv}) && $self->{accept_argv}) {
         require Perinci::Sub::GetArgs::Argv;
         $res = Perinci::Sub::GetArgs::Argv::get_args_from_argv(
             argv => [@{ $req->{argv} }],
             meta => $req->{-meta},
         );
         return err(400, "Can't parse argv", $res) unless $res->[0] == 200;
         %args = %{ $res->[2] };
     } else {
         %args = %{ $req->{args} // {} };
     }
 
     my $risub = risub($req->{-meta});
 
     if ($req->{dry_run}) {
         return err(412, "Function does not support dry run")
             unless $risub->can_dry_run;
         if ($risub->feature('dry_run')) {
             $args{-dry_run} = 1;
         } else {
             $args{-dry_run} = 1;
             $args{-tx_action} = 'check_state';
             $args{-tx_action_id} = UUID::Random::generate();
             undef $tm;
         }
     }
 
     if ($risub->feature('progress')) {
         require Progress::Any;
         $args{-progress} = Progress::Any->get_indicator();
     }
 
     if ($tm) {
         $res = $tm->action(
             f => "$req->{-perl_package}::$req->{-uri_leaf}", args=>\%args,
             confirm => $req->{confirm},
         );
         $tm->{_tx_id} = undef if $tm;
     } else {
         $args{-confirm} = 1 if $req->{confirm};
         eval { $res = $req->{-code}->(%args) };
         my $eval_err = $@;
         if ($eval_err) {
             $res = err(500, "Function died: $eval_err");
         }
     }
 
     # add hint that result is binary
     if (defined $res->[2]) {
         if ($req->{-meta}{result} && $req->{-meta}{result}{schema} &&
                 $req->{-meta}{result}{schema}[0] eq 'buf') {
             $res->[3]{'x.hint.result_binary'} = 1;
         }
     }
 
     $res;
 }
 
 sub actionmeta_complete_arg_val { +{
     applies_to => ['function'],
     summary    => "Complete function's argument value"
 } }
 
 sub action_complete_arg_val {
     require Perinci::Sub::Complete;
 
     my ($self, $req) = @_;
     my $arg = $req->{arg} or return err(400, "Please specify arg");
     my $word = $req->{word} // "";
     my $ci = $req->{ci};
 
     my $res = $self->get_meta($req);
     return $res if $res;
     [200, "OK (complete_arg_val action)",
      Perinci::Sub::Complete::complete_arg_val(meta=>$req->{-meta}, word=>$word,
                                               arg=>$arg, ci=>$ci) // []];
 }
 
 sub actionmeta_complete_arg_elem { +{
     applies_to => ['function'],
     summary    => "Complete function's argument element value"
 } }
 
 sub action_complete_arg_elem {
     require Perinci::Sub::Complete;
 
     my ($self, $req) = @_;
     my $arg = $req->{arg} or return err(400, "Please specify arg");
     defined(my $index = $req->{index})
         or return err(400, "Please specify index");
     my $word = $req->{word} // "";
     my $ci = $req->{ci};
 
     my $res = $self->get_meta($req);
     return $res if $res;
     [200, "OK (complete_arg_elem action)",
      Perinci::Sub::Complete::complete_arg_elem(
          meta=>$req->{-meta}, word=>$word, arg=>$arg, ci=>$ci, index=>$index,
      ) // []],
 }
 
 sub actionmeta_child_metas { +{
     applies_to => ['package'],
     summary    => "Get metadata of all child entities",
 } }
 
 sub action_child_metas {
     my ($self, $req) = @_;
 
     my $res = $self->action_list($req);
     return $res unless $res->[0] == 200;
     my $ents = $res->[2];
 
     my %res;
     my %om;
     my $base = uri_join(
         $req->{-uri_scheme}, $req->{-uri_auth}, $req->{-uri_dir});
 
     for my $ent (@$ents) {
         $res = $self->request(meta => "$base/$ent");
         # ignore failed request
         next unless $res->[0] == 200;
         $res{$ent} = $res->[2];
     }
     [200, "OK (child_metas action)", \%res];
 }
 
 sub actionmeta_get { +{
     applies_to => ['variable'],
     summary    => "Get value of variable",
 } }
 
 sub action_get {
     no strict 'refs';
 
     my ($self, $req) = @_;
     local $req->{-uri_leaf} = $req->{-uri_leaf};
 
     # extract prefix
     $req->{-uri_leaf} =~ s/^([%\@\$])//
         or return err(500, "BUG: Unknown variable prefix");
     my $prefix = $1;
     my $name = $req->{-perl_package} . "::" . $req->{-uri_leaf};
     my $res =
         $prefix eq '$' ? ${$name} :
             $prefix eq '@' ? \@{$name} :
                 $prefix eq '%' ? \%{$name} :
                     undef;
     [200, "OK (get action)", $res];
 }
 
 sub _pre_tx_action {
     my ($self, $req) = @_;
 
     return err(501, "Transaction not supported by server")
         unless $self->{use_tx};
 
     # instantiate custom tx manager, per request if necessary
     if (ref($self->{custom_tx_manager}) eq 'CODE') {
         eval {
             $self->{_tx_manager} = $self->{custom_tx_manager}->($self);
             die $self->{_tx_manager} unless blessed($self->{_tx_manager});
         };
         return err(500, "Can't initialize custom tx manager: ".
                        "$self->{_tx_manager}: $@") if $@;
     } elsif (!blessed($self->{_tx_manager})) {
         my $tm_cl = $self->{custom_tx_manager} // "Perinci::Tx::Manager";
         my $tm_cl_p = $tm_cl; $tm_cl_p =~ s!::!/!g; $tm_cl_p .= ".pm";
         eval {
             require $tm_cl_p;
             $self->{_tx_manager} = $tm_cl->new(pa => $self);
             die $self->{_tx_manager} unless blessed($self->{_tx_manager});
         };
         return err(500, "Can't initialize tx manager ($tm_cl): $@") if $@;
         # we just want to force newer version, we currently can't specify this
         # in Makefile.PL because peritm's tests use us. this might be rectified
         # in the future.
         if ($tm_cl eq 'Perinci::Tx::Manager') {
             $Perinci::Tx::Manager::VERSION >= 0.29
                 or die "Your Perinci::Tx::Manager is too old, ".
                     "please install v0.29 or later";
         }
     }
 
     return;
 }
 
 sub actionmeta_begin_tx { +{
     applies_to => ['*'],
     summary    => "Start a new transaction",
 } }
 
 sub action_begin_tx {
     my ($self, $req) = @_;
     my $res = $self->_pre_tx_action($req);
     return $res if $res;
 
     $self->{_tx_manager}->begin(
         tx_id   => $req->{tx_id},
         summary => $req->{summary},
     );
 }
 
 sub actionmeta_commit_tx { +{
     applies_to => ['*'],
     summary    => "Commit a transaction",
 } }
 
 sub action_commit_tx {
     my ($self, $req) = @_;
     my $res = $self->_pre_tx_action($req);
     return $res if $res;
 
     $self->{_tx_manager}->commit(
         tx_id  => $req->{tx_id},
     );
 }
 
 sub actionmeta_savepoint_tx { +{
     applies_to => ['*'],
     summary    => "Create a savepoint in a transaction",
 } }
 
 sub action_savepoint_tx {
     my ($self, $req) = @_;
     my $res = $self->_pre_tx_action($req);
     return $res if $res;
 
     $self->{_tx_manager}->savepoint(
         tx_id => $req->{tx_id},
         sp    => $req->{tx_spid},
     );
 }
 
 sub actionmeta_release_tx_savepoint { +{
     applies_to => ['*'],
     summary    => "Release a transaction savepoint",
 } }
 
 sub action_release_tx_savepoint {
     my ($self, $req) =\ @_;
     my $res = $self->_pre_tx_action($req);
     return $res if $res;
 
     $self->{_tx_manager}->release_savepoint(
         tx_id => $req->{tx_id},
         sp    => $req->{tx_spid},
     );
 }
 
 sub actionmeta_rollback_tx { +{
     applies_to => ['*'],
     summary    => "Rollback a transaction (optionally to a savepoint)",
 } }
 
 sub action_rollback_tx {
     my ($self, $req) = @_;
     my $res = $self->_pre_tx_action($req);
     return $res if $res;
 
     $self->{_tx_manager}->rollback(
         tx_id => $req->{tx_id},
         sp    => $req->{tx_spid},
     );
 }
 
 sub actionmeta_list_txs { +{
     applies_to => ['*'],
     summary    => "List transactions",
 } }
 
 sub action_list_txs {
     my ($self, $req) = @_;
     my $res = $self->_pre_tx_action($req);
     return $res if $res;
 
     $self->{_tx_manager}->list(
         detail    => $req->{detail},
         tx_status => $req->{tx_status},
         tx_id     => $req->{tx_id},
     );
 }
 
 sub actionmeta_undo { +{
     applies_to => ['*'],
     summary    => "Undo a committed transaction",
 } }
 
 sub action_undo {
     my ($self, $req) = @_;
     my $res = $self->_pre_tx_action($req);
     return $res if $res;
 
     $self->{_tx_manager}->undo(
         tx_id   => $req->{tx_id},
         confirm => $req->{confirm},
     );
 }
 
 sub actionmeta_redo { +{
     applies_to => ['*'],
     summary    => "Redo an undone committed transaction",
 } }
 
 sub action_redo {
     my ($self, $req) = @_;
     my $res = $self->_pre_tx_action($req);
     return $res if $res;
 
     $self->{_tx_manager}->redo(
         tx_id   => $req->{tx_id},
         confirm => $req->{confirm},
     );
 }
 
 sub actionmeta_discard_tx { +{
     applies_to => ['*'],
     summary    => "Discard (forget) a committed transaction",
 } }
 
 sub action_discard_tx {
     my ($self, $req) = @_;
     my $res = $self->_pre_tx_action($req);
     return $res if $res;
 
     $self->{_tx_manager}->discard(
         tx_id => $req->{tx_id},
     );
 }
 
 sub actionmeta_discard_all_txs { +{
     applies_to => ['*'],
     summary    => "Discard (forget) all committed transactions",
 } }
 
 sub action_discard_all_txs {
     my ($self, $req) = @_;
     my $res = $self->_pre_tx_action($req);
     return $res if $res;
 
     $self->{_tx_manager}->discard_all(
         # XXX select client
     );
 }
 
 1;
 # ABSTRACT: Base class for Perinci::Access::Perl
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Perinci::Access::Schemeless - Base class for Perinci::Access::Perl
 
 =head1 VERSION
 
 This document describes version 0.84 of Perinci::Access::Schemeless (from Perl distribution Perinci-Access-Perl), released on 2015-09-03.
 
 =head1 DESCRIPTION
 
 This class is the base class for L<Perinci::Access::Perl>, and by default acts
 like Perinci::Access::Perl (e.g. given uri C</Foo/Bar/baz> it will refer to
 function C<baz> in Perl package C<Foo::Bar>; it also looks for Rinci metadata in
 C<%SPEC> package variables by default). But this class is designed to be
 flexible: you can override aspects of it so it can map uri to different Perl
 packages (e.g. using option like C<package_prefix>), you can retrieve Rinci
 metadata from a database or whatever, etc.
 
 Supported features:
 
 =over
 
 =item * Basic Riap actions
 
 These include C<info>, C<actions>, C<meta>, C<list>, and C<call> actions.
 
 =item * Transaction/undo
 
 According to L<Rinci::Transaction>.
 
 =item * Function wrapping
 
 Wrapping is used to convert argument passing style, produce result envelope, add
 argument validation, as well as numerous other functionalities. See
 L<Perinci::Sub::Wrapper> for more details on wrapping. The default behavior will
 call wrapped functions.
 
 =item * Custom location of metadata
 
 By default, metadata are assumed to be stored embedded in Perl source code in
 C<%SPEC> package variables (with keys matching function names, C<$variable>
 names, or C<:package> for the package metadata itself).
 
 You can override C<get_meta()> to provide custom behavior. For example, you can
 store metadata in separate file or database.
 
 =item * Custom code entity tree
 
 By default, tree are formed by traversing Perl packages and their contents, for
 example if a C<list> action is requested on uri C</Foo/Bar/> then the contents
 of package C<Foo::Bar> and its subpackages will be traversed for the entities.
 
 You can override C<action_list()> to provide custom behavior. For example, you
 can lookup from the database.
 
 =item * Progress indicator
 
 Functions can express that they do progress updating through the C<features>
 property in its metadata:
 
  features => {
      progress => 1,
      ...
  }
 
 For these functions, this class will pass a special argument C<-progress>
 containing L<Progress::Any> object. Functions can update progress using this
 object.
 
 =back
 
 =head2 How request is processed
 
 User calls C<< $pa->request($action => $uri, \%extras) >>. Internally, the
 method creates a hash C<$req> which contains Riap request keys as well as
 internal information about the Riap request (the latter will be prefixed with
 dash C<->). Initially it will contain C<action> and C<uri> and the C<%extras>
 keys from the request() arguments sent by the user.
 
 Internal C<_parse_uri()> method will be called to parse C<uri> into C<-uri_dir>
 (the "dir" part), C<-uri_leaf> (the "basename" part), and C<-perl_package>.
 Forbidden or invalid paths will cause this method to return an enveloped error
 response and the request to stop. For example, if C<uri> is C</Foo/Bar/> then
 C<-uri_dir> is C</Foo/Bar/> and C<-uri_leaf> is an empty string. If C<uri> is
 C</Foo/Bar/baz> then C<-uri_dir> is C</Foo/Bar/> while C<-uri_leaf> is C<baz>.
 C<-uri_dir> will be used for the C<list> action. In both cases, C<-perl_package>
 will be set to C<Foo::Bar>.
 
 The code entity type is then determined currently using a few simple heuristic
 rules: if C<-uri_leaf> is empty string, type is C<package>. If C<-uri_leaf>
 begins with C<[$%@]>, type is C<variable>. Otherwise, type is C<function>.
 C<-type> will be set.
 
 After this, the appropriate C<action_ACTION()> method will be called. For
 example if action is C<meta> then C<action_meta()> method will be called, with
 C<$req> as the argument. This will in turn, depending on the action, either call
 C<get_meta()> (for example if action is C<meta>) or C<get_code()> (for example
 if action is C<call>), also with C<$req> as the argument. C<get_meta()> and
 C<get_code()> should return nothing on success, and set either C<-meta> (a
 defhash containing Rinci metadata) or C<-code> (a coderef), respectively. On
 error, they must return an enveloped error response.
 
 C<get_meta()> or C<get_code()> might call C<_load_module()> to load Perl modules
 if the C<load> attribute is set to true.
 
 =for Pod::Coverage ^(actionmeta_.+|action_.+|get_(meta|code))$
 
 =head1 METHODS
 
 =head2 PKG->new(%attrs) => OBJ
 
 Instantiate object. Known attributes:
 
 =over 4
 
 =item * load => BOOL (default: 1)
 
 Whether to load Perl modules that are requested.
 
 =item * after_load => CODE
 
 If set, code will be executed the first time Perl module is successfully loaded.
 
 =item * wrap => BOOL (default: 1)
 
 If set to false, then wil use original subroutine and metadata instead of
 wrapped ones, for example if you are very concerned about performance (do not
 want to add another eval {} and subroutine call introduced by wrapping) or do
 not need the functionality provided by the wrapper (e.g. your function already
 validates its arguments, accepts arguments as hash, and returns enveloped
 result).
 
 Wrapping is implemented inside C<get_code()>.
 
 =item * set_function_properties => HASH
 
 If set, will be passed to L<Perinci::Sub::Wrapper> wrap_sub()'s C<convert>
 argument when wrapping subroutines. Some applications of this include: changing
 C<default_lang> of metadata.
 
 This is only relevant if you enable C<wrap>.
 
 =item * cache_size => INT (default: 100)
 
 Specify cache size (in number of items), for caching metadata and wrapping
 result. Setting this to 0 disables caching.
 
 Caching is implemented inside C<get_meta()> and C<get_code()> so you might want
 to implement your own caching if you override those.
 
 =item * allow_paths => REGEX|STR|ARRAY
 
 If defined, only requests with C<uri> matching specified path will be allowed.
 Can be a string (e.g. C</spanel/api/>) or regex (e.g. C<< qr{^/[^/]+/api/} >>)
 or an array of those.
 
 =item * deny_paths => REGEX|STR|ARRAY
 
 If defined, requests with C<uri> matching specified path will be denied. Like
 C<allow_paths>, value can be a string (e.g. C</spanel/api/>) or regex (e.g. C<<
 qr{^/[^/]+/api/} >>) or an array of those.
 
 =item * allow_schemes => REGEX|STR|ARRAY
 
 By default this class does not care about schemes, it only looks at the uri
 path. You can use this option to limit allowed schemes.
 
 =item * deny_schemes => REGEX|STR|ARRAY
 
 By default this class does not care about schemes, it only looks at the uri
 path. You can use this option to specify forbidden schemes.
 
 =item * use_tx => BOOL (default: 0)
 
 Whether to allow transaction requests from client. Since this can cause the
 server to store transaction/undo data, this must be explicitly allowed.
 
 You need to install L<Perinci::Tx::Manager> for transaction support (unless you
 are using another transaction manager).
 
 =item * custom_tx_manager => STR|CODE
 
 Can be set to a string (class name) or a code that is expected to return a
 transaction manager class.
 
 By default, L<Perinci::Tx::Manager> is instantiated and maintained (not
 reinstantiated on every request), but if C<custom_tx_manager> is a coderef, it
 will be called on each request to get transaction manager. This can be used to
 instantiate Perinci::Tx::Manager in a custom way, e.g. specifying per-user
 transaction data directory and limits, which needs to be done on a per-request
 basis.
 
 =item * accept_argv => BOOL (default: 1)
 
 From version 0.64, C<argv> key is accepted by the C<call> action and will be
 converted to C<args>. This server-side conversion from C<argv> to <args> can
 handle coderefs in C<cmdline_aliases> (and probably other things too) compared
 when doing conversion at the client-side.
 
 This option allows disabling this behavior.
 
 =back
 
 =head2 $pa->request($action => $server_url, \%extra) => $res
 
 Process Riap request and return enveloped result. $server_url will be used as
 the Riap request key 'uri', as there is no server in this case.
 
 =head2 $pa->parse_url($server_url) => HASH
 
 =head1 ADDED RESULT METADATA
 
 This class might add the following property/attribute in result metadata:
 
 =head2 x.hint.result_binary => bool
 
 If result's schema type is C<buf>, then this class will set this attribute to
 true, to give hints to result formatters.
 
 =head1 SEE ALSO
 
 L<Riap>, L<Rinci>
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Perinci-Access-Perl>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Perinci-Access-Perl>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Perinci-Access-Perl>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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
### Perinci/Access/Simple/Client.pm ###
 package Perinci::Access::Simple::Client;
 
 our $DATE = '2015-09-06'; # DATE
 our $VERSION = '0.20'; # VERSION
 
 use 5.010001;
 use strict;
 use warnings;
 use Log::Any '$log';
 
 use Cwd qw(abs_path);
 use Perinci::AccessUtil qw(strip_riap_stuffs_from_res);
 use POSIX qw(:sys_wait_h);
 use Tie::Cache;
 use URI::Split qw(uri_split);
 use URI::Escape;
 
 use parent qw(Perinci::Access::Base);
 
 my @logging_methods = Log::Any->logging_methods();
 
 sub new {
     my $class = shift;
 
     my $self = $class->SUPER::new(@_);
 
     # attributes
     $self->{retries}         //= 2;
     $self->{retry_delay}     //= 3;
     $self->{conn_cache_size} //= 32;
 
     # connection cache, key="tcp:HOST:PORT" OR "unix:ABSPATH" or "pipe:ABSPATH
     # ARGS". value=hash, for tcp & unix {socket=>...} and for pipe {pid=>...,
     # chld_out=>..., chld_in=>...}
     tie my(%conns), 'Tie::Cache', $self->{conn_cache_size};
     $self->{_conns} = \%conns;
 
     $self;
 }
 
 # for older Perinci::Access::Base 0.28-, to remove later
 sub _init {}
 
 sub _delete_cache {
     my ($self, $wanted) = @_;
     my $conns = $self->{_conns};
     return unless $conns;
 
     for my $k ($wanted ? ($wanted) : (keys %$conns)) {
         if ($k =~ /^pipe:/) {
             waitpid($conns->{$k}{pid}, WNOHANG);
         }
         delete $self->{_conns}{$k};
     }
 }
 
 sub DESTROY {
     my ($self) = @_;
 
     #$self->_delete_cache;
 }
 
 sub request {
     my $self = shift;
     $self->_parse_or_request('request', @_);
 }
 
 sub _parse {
     my $self = shift;
     $self->_parse_or_request('parse2', @_);
 }
 
 # which: parse0 = quick parse (for parse_url(), parse2 = more thorough parse
 # (for testing)
 sub _parse_or_request {
     my ($self, $which, $action, $server_url, $extra) = @_;
     $log->tracef("=> %s\::request(action=%s, server_url=%s, extra=%s)",
                  __PACKAGE__, $action, $server_url, $extra);
     return [400, "Please specify server_url"] unless $server_url;
 
     my ($uri,
         $cache_key,
         $host, $port, # tcp
         $path,        # unix & pipe
         $args         # pipe
     );
     my ($srvsch, $srvauth, $srvpath, $srvquery, $srvfrag) =
         uri_split($server_url);
     $srvauth //= "";
     $srvpath //= "";
     return [400, "Please supply only riap+tcp/riap+unix/riap+pipe URL"]
         unless $srvsch =~ /\Ariap\+(tcp|unix|pipe)\z/;
     if ($srvsch eq 'riap+tcp') {
         if ($srvauth =~ m!^(.+):(\d+)$!) {
             ($host, $port) = ($1, $2, $3);
             $uri = $srvpath;
             $cache_key = "tcp:".lc($host).":$port";
         } else {
             return [400, "Invalid riap+tcp URL, please use this format: ".
                 "riap+tcp://host:1234 or riap+tcp://host:1234/uri"];
         }
     } elsif ($srvsch eq 'riap+unix') {
         if ($srvpath =~ m!(.+)/(/.*)!) {
             ($path, $uri) = (uri_unescape($1), $2);
         } elsif ($srvpath =~ m!(.+)!) {
             $path = uri_unescape($1);
         }
         unless ($which eq 'parse0') {
             if (defined($path)) {
                 my $apath = abs_path($path) or
                     return [500, "Can't find absolute path for $path"];
                 $cache_key = "unix:$apath";
             } else {
                 return [400, "Invalid riap+unix URL, please use this format: ".
                             ", e.g.: riap+unix:/path/to/unix/socket or ".
                                 "riap+unix:/path/to/unix/socket//uri"];
             }
         }
     } elsif ($srvsch eq 'riap+pipe') {
         if ($srvpath =~ m!(.+?)//(.*?)/(/.*)!) {
             ($path, $args, $uri) = (uri_unescape($1), $2, $3);
         } elsif ($srvpath =~ m!(.+?)//(.*)!) {
             ($path, $args) = (uri_unescape($1), $2);
         } elsif ($srvpath =~ m!(.+)!) {
             $path = uri_unescape($1);
             $args = '';
         }
         $args = [map {uri_unescape($_)} split m!/!, $args // ''];
         unless ($which eq 'parse0') {
             if (defined($path)) {
                 my $apath = abs_path($path) or
                     return [500, "Can't find absolute path for $path"];
                 $cache_key = "pipe:$apath ".join(" ", @$args);
             } else {
                 return [400, "Invalid riap+pipe URL, please use this format: ".
                             "riap+pipe:/path/to/prog or ".
                                 "riap+pipe:/path/to/prog//arg1/arg2 or ".
                                     "riap+pipe:/path/to/prog//arg1/arg2//uri"];
             }
         }
     }
 
     my $req;
     my $res;
 
     unless ($which eq 'parse0') {
         $req = { v=>$self->{riap_version}, action=>$action, %{$extra // {}} };
         $uri ||= $req->{uri}; $req->{uri} //= $uri;
         $res = $self->check_request($req);
         return $res if $res;
     }
 
     if ($which =~ /parse/) {
         return [200, "OK", {
             args=>$args, host=>$host, path=>$path, port=>$port,
             scheme=>$srvsch, uri=>$uri,
         }];
     }
 
     $log->tracef("Parsed URI, scheme=%s, host=%s, port=%s, path=%s, args=%s, ".
                      "uri=%s", $srvsch, $host, $port, $path, $args, $uri);
 
     require JSON;
     state $json = JSON->new->allow_nonref;
 
     my $attempts = 0;
     my $do_retry;
     my $e;
     while (1) {
         $do_retry = 0;
 
         my ($in, $out);
         my $cache = $self->{_conns}{$cache_key};
         # check cache staleness
         if ($cache) {
             if ($srvsch =~ /tcp|unix/) {
                 if ($cache->{socket}->connected) {
                     $in = $out = $cache->{socket};
                 } else {
                     $log->infof("Stale socket cache (%s), discarded",
                                 $cache_key);
                     $cache = undef;
                 }
             } else {
                 if (kill(0, $cache->{pid})) {
                     $in  = $cache->{chld_out};
                     $out = $cache->{chld_in};
                 } else {
                     $log->infof(
                         "Process (%s) seems dead/unsignalable, discarded",
                         $cache_key);
                     $cache = undef;
                 }
             }
         }
         # connect
         if (!$cache) {
             if ($srvsch =~ /tcp|unix/) {
                 my $sock;
                 if ($srvsch eq 'riap+tcp') {
                     require IO::Socket::INET;
                     $sock = IO::Socket::INET->new(
                         PeerHost => $host,
                         PeerPort => $port,
                         Proto    => 'tcp',
                     );
                 } else {
                     use IO::Socket::UNIX;
                     $sock = IO::Socket::UNIX->new(
                         Type => SOCK_STREAM,
                         Peer => $path,
                     );
                 }
                 $e = $@;
                 if ($sock) {
                     $self->{_conns}{$cache_key} = {socket=>$sock};
                     $in = $out = $sock;
                 } else {
                     $e = $srvsch eq 'riap+tcp' ?
                         "Can't connect to TCP socket $host:$port: $e" :
                             "Can't connect to Unix socket $path: $e";
                     $do_retry++; goto RETRY;
                 }
             } else {
                 # taken from Modern::Perl. enable methods on filehandles;
                 # unnecessary when 5.14 autoloads them
                 require IO::File;
                 require IO::Handle;
 
                 require IPC::Open2;
 
                 require String::ShellQuote;
                 my $cmd = $path . (@$args ? " " . join(" ", map {
                     String::ShellQuote::shell_quote($_) } @$args) : "");
                 $log->tracef("executing cmd: %s", $cmd);
 
                 # using shell
                 #my $pid = IPC::Open2::open2($in, $out, $cmd, @$args);
 
                 # not using shell
                 my $pid = IPC::Open2::open2($in, $out, $path, @$args);
 
                 if ($pid) {
                     $self->{_conns}{$cache_key} = {
                         pid=>$pid, chld_out=>$in, chld_in=>$out};
                 } else {
                     $e = "Can't open2 $cmd: $!";
                     $do_retry++; goto RETRY;
                 }
             }
         }
 
         my $req_json;
         eval { $req_json = $json->encode($req) };
         $e = $@;
         return [400, "Can't encode request as JSON: $e"] if $e;
 
         $out->write("j$req_json\015\012");
         $log->tracef("Sent request to server: %s", $req_json);
 
         # XXX alarm/timeout
         my $line = $in->getline;
         $log->tracef("Got line from server: %s", $line);
         if (!$line) {
             $self->_delete_cache($cache_key);
             return [500, "Empty response from server"];
         } elsif ($line !~ /^j(.+)/) {
             $self->_delete_cache($cache_key);
             return [500, "Invalid response line from server: $line"];
         }
         eval { $res = $json->decode($1) };
         $e = $@;
         if ($e) {
             $self->_delete_cache($cache_key);
             return [500, "Invalid JSON response from server: $e"];
         }
         strip_riap_stuffs_from_res($res);
         return $res;
 
       RETRY:
         if ($do_retry && $attempts++ < $self->{retries}) {
             $log->tracef("Request failed ($e), waiting to retry #%s...",
                          $attempts);
             sleep $self->{retry_delay};
         } else {
             last;
         }
     }
     return [500, "$e (tried $attempts times)"];
 }
 
 sub request_tcp {
     my ($self, $action, $hostport, $extra) = @_;
     $self->request($action, "riap+tcp://$hostport->[0]:$hostport->[1]", $extra);
 }
 
 sub request_unix {
     my ($self, $action, $sockpath, $extra) = @_;
     $self->request($action => "riap+unix:" . uri_escape($sockpath), $extra);
 }
 
 sub request_pipe {
     my ($self, $action, $cmd, $extra) = @_;
     $self->request($action => "riap+pipe:" . uri_escape($cmd->[0]) . "//" .
                        join("/", map {uri_escape($_)} @$cmd[1..@$cmd-1]),
                    $extra);
 }
 
 sub parse_url {
     my ($self, $uri) = @_;
 
     my $res0 = $self->_parse_or_request('parse0', 'dummy', $uri);
     #use Data::Dump; dd $res0;
     die "Can't parse URL $uri: $res0->[0] - $res0->[1]" unless $res0->[0]==200;
     $res0 = $res0->[2];
     my $res = {proto=>$res0->{scheme}, path=>$res0->{uri}};
     if ($res->{proto} eq 'riap+unix') {
         $res->{unix_sock_path} = $res0->{path};
     } elsif ($res->{proto} eq 'riap+tcp') {
         $res->{host} = $res0->{host};
         $res->{port} = $res0->{port};
     } elsif ($res->{proto} eq 'riap+pipe') {
         $res->{prog_path} = $res0->{path};
         $res->{args} = $res0->{args};
     }
 
     $res;
 }
 
 1;
 # ABSTRACT: Riap::Simple client
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Perinci::Access::Simple::Client - Riap::Simple client
 
 =head1 VERSION
 
 This document describes version 0.20 of Perinci::Access::Simple::Client (from Perl distribution Perinci-Access-Simple-Client), released on 2015-09-06.
 
 =head1 SYNOPSIS
 
  use Perinci::Access::Simple::Client;
  my $pa = Perinci::Access::Simple::Client->new;
 
  my $res;
 
  ## performing Riap requests
 
  # to request server over TCP
  $res = $pa->request(call => 'riap+tcp://localhost:5678/Foo/Bar/func',
                      {args => {a1=>1, a2=>2}});
 
  # to request server over Unix socket (separate Unix socket path and Riap
  # request key 'uri' with an extra slash /)
  $res = $pa->request(call => 'riap+unix:/var/run/api.sock//Foo/Bar/func',
                      {args => {a1=>1, a2=>2}});
 
  # to request "server" (program) over pipe (separate program path and first
  # argument with an extra slash /, then separate each program argument with
  # slashes, finally separate last program argument with Riap request key 'uri'
  # with an extra slash /). Arguments are URL-escaped so they can contain slashes
  # if needed (in the encoded form of %2F).
  $res = $pa->request(call => 'riap+pipe:/path/to/prog//arg1/arg2//Foo/Bar/func',
                      {args => {a1=>1, a2=>2}});
 
  # an example for riap+pipe, accessing a remote program via SSH client
  use URI::Escape;
  my @cmd = ('ssh', '-T', 'user@host', '/path/to/program', 'first arg', '2nd');
  my $uri = "/Foo/Bar/func";
  $res = $pa->request(call => 'riap+pipe:' .
                              uri_escape($cmd[0]) . '//' .
                              join('/', map { uri_escape($_) } @cmd[1..@cmd-1]) . '/' .
                              $uri,
                      {args => {a1=>1, a2=>2}});
 
  # helper for riap+tcp
  $res = $pa->request_tcp(call => [$host, $port], \%extra);
 
  # helper for riap+unix
  $res = $pa->request_unix(call => $sockpath, \%extra);
 
  # helper for riap+pipe
  my @cmd = ('/path/to/program', 'first arg', '2nd');
  $res = $pa->request_pipe(call => \@cmd, \%extra);
 
  ## parsing URL
 
  $res = $pa->parse_url("riap+unix:/var/run/apid.sock//Foo/bar");   # -> {proto=>"riap+unix", path=>"/Foo/bar", unix_sock_path=>"/var/run/apid.sock"}
  $res = $pa->parse_url("riap+tcp://localhost:5000/Foo/bar");       # -> {proto=>"riap+tcp" , path=>"/Foo/bar", host=>"localhost", port=>5000}
  $res = $pa->parse_url("riap+pipe:/path/to/prog//a1/a2//Foo/bar"); # -> {proto=>"riap+pipe", path=>"/Foo/bar", prog_path=>"/path/to/prog", args=>["a1", "a2"]}
 
 =head1 DESCRIPTION
 
 This class implements L<Riap::Simple> client. It supports the 'riap+tcp',
 'riap+unix', and 'riap+pipe' schemes for a variety of methods to access the
 server: either via TCP (where the server can be on a remote computer), Unix
 socket, or a program (where the program can also be on a remote computer, e.g.
 accessed via ssh).
 
 =head1 METHODS
 
 =head2 PKG->new(%attrs) => OBJ
 
 Instantiate object. Known attributes:
 
 =over 4
 
 =item * retries => INT (default 2)
 
 Number of retries to do on network failure. Setting it to 0 will disable
 retries.
 
 =item * retry_delay => INT (default 3)
 
 Number of seconds to wait between retries.
 
 =back
 
 =head2 $pa->request($action => $server_url, \%extra) => $res
 
 Send Riap request to C<$server_url>.
 
 =head2 $pa->request_tcp($action => [$host, $port], \%extra) => $res
 
 Helper/wrapper for request(), it forms C<$server_url> using:
 
  "riap+tcp://$host:$port"
 
 You need to specify Riap request key 'uri' in C<%extra>.
 
 =head2 $pa->request_unix($action => $sockpath, \%extra) => $res
 
 Helper/wrapper for request(), it forms C<$server_url> using:
 
  "riap+unix:" . uri_escape($sockpath)
 
 You need to specify Riap request key 'uri' in C<%extra>.
 
 =head2 $pa->request_pipe($action => \@cmd, \%extra) => $res
 
 Helper/wrapper for request(), it forms C<$server_url> using:
 
  "riap+pipe:" . uri_escape($cmd[0]) . "//" .
  join("/", map {uri_escape($_)} @cmd[1..@cmd-1])
 
 You need to specify Riap request key 'uri' in C<%extra>.
 
 =head2 $pa->parse_url($server_url) => HASH
 
 =head1 FAQ
 
 =head2 When I use riap+pipe, is the program executed for each Riap request?
 
 No, this module does some caching, so if you call the same program (with the
 same arguments) 10 times, the same program will be used and it will receive 10
 Riap requests using the L<Riap::Simple> protocol.
 
 =head1 SEE ALSO
 
 L<Perinci::Access::Simple::Server>
 
 L<Riap::Simple>, L<Riap>, L<Rinci>
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Perinci-Access-Simple-Client>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Perinci-Access-Simple-Client>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Perinci-Access-Simple-Client>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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
### Perinci/AccessUtil.pm ###
 package Perinci::AccessUtil;
 
 our $DATE = '2015-09-06'; # DATE
 our $VERSION = '0.06'; # VERSION
 
 use 5.010001;
 use strict;
 use warnings;
 
 use MIME::Base64;
 
 require Exporter;
 our @ISA = qw(Exporter);
 our @EXPORT_OK = qw(insert_riap_stuffs_to_res
                     strip_riap_stuffs_from_res
                     decode_args_in_riap_req);
 
 sub insert_riap_stuffs_to_res {
     my ($res, $def_ver, $nmeta, $encode) = @_;
 
     $res->[3]{'riap.v'} //= $def_ver // 1.1;
     if ($res->[3]{'riap.v'} >= 1.2) {
         # do we need to base64-encode?
         {
             last unless $encode // 1;
             last if $res->[3]{'riap.result_encoding'};
             if ($nmeta) {
                 last unless $nmeta->{result}{schema} &&
                     $nmeta->{result}{schema}[0] eq 'buf';
             }
             last unless defined($res->[2]) && !ref($res->[2]) &&
                 $res->[2] =~ /[^\x20-\x7f]/;
             $res->[2] = encode_base64($res->[2], "");
             $res->[3]{'riap.result_encoding'} = 'base64';
         }
     }
     $res;
 }
 
 sub strip_riap_stuffs_from_res {
     my $res = shift;
 
     my $ver = $res->[3]{'riap.v'} // 1.1;
     return [501, "Riap version returned by server ($ver) is not supported, ".
                 "only recognize v1.1 and v1.2"]
         unless $ver == 1.1 || $ver == 1.2;
 
     if ($ver >= 1.2) {
         # check and strip riap.*
         for my $k (keys %{$res->[3]}) {
             next unless $k =~ /\Ariap\./;
             my $val = $res->[3]{$k};
             if ($k eq 'riap.v') {
             } elsif ($k eq 'riap.result_encoding') {
                 return [501, "Unknown result_encoding returned by server ".
                             "($val), only base64 is supported"]
                     unless $val eq 'base64';
                 $res->[2] = decode_base64($res->[2]//'');
             } else {
                 return [501, "Unknown Riap attribute in result metadata ".
                             "returned by server ($k)"];
             }
             delete $res->[3]{$k};
         }
     }
 
     $res;
 }
 
 sub decode_args_in_riap_req {
     my $req = shift;
 
     my $v = $req->{v} // 1.1;
     if ($v >= 1.2) {
         if ($req->{args}) {
             my $args = $req->{args};
             for (keys %$args) {
                 next unless /\A(.+):base64\z/;
                 $args->{$1} = decode_base64($args->{$_});
                 delete $args->{$_};
             }
         }
     }
     $req;
 }
 
 1;
 # ABSTRACT: Utility module for Riap client/server
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Perinci::AccessUtil - Utility module for Riap client/server
 
 =head1 VERSION
 
 This document describes version 0.06 of Perinci::AccessUtil (from Perl distribution Perinci-AccessUtil), released on 2015-09-06.
 
 =head1 SYNOPSIS
 
  use Perinci::AccessUtil qw(
      strip_riap_stuffs_from_res
      insert_riap_stuffs_to_res
      decode_args_in_riap_req
  );
 
  strip_riap_stuffs_from_res([200,"OK",undef,{"riap.v"=>1.1}]); # => [200,"OK",undef]
  strip_riap_stuffs_from_res([200,"OK",undef,{"riap.foo"=>1}]); # => [501, "Unknown Riap attribute in result metadata: riap.foo"]
 
  insert_riap_stuffs_to_res([200,"OK",undef); # => [200,"OK",undef,{"riap.v"=>1.1}]
 
  decode_args_in_riap_req({v=>1.2, args=>{"a:base64"=>"AAAA"}}); # => {v=>1.2, args=>{a=>"\0\0\0"}}
 
 =head1 DESCRIPTION
 
 =head1 FUNCTIONS
 
 =head2 insert_riap_stuffs_to_res($envres[, $def_ver, $nmeta, $decode]) => array
 
 Starting in Riap protocol v1.2, server is required to return C<riap.v> in result
 metadata. This routine does just that. In addition to that, this routine also
 encodes result with base64 when necessary.
 
 This routine is used by Riap network server libraries, e.g.
 L<Perinci::Access::HTTP::Server> and L<Perinci::Access::Simple::Server>.
 
 =head2 strip_riap_stuffs_from_res($envres) => array
 
 Starting in Riap protocol v1.2, client is required to check and strip all
 C<riap.*> keys in result metadata (C<< $envres->[3] >>). This routine does just
 that. In addition, this routine also decode result if C<riap.result_encoding> is
 set, so the user already gets the decoded content.
 
 This routine is used by Riap client libraries, e.g. L<Perinci::Access::Lite>,
 L<Perinci::Access::Perl>, and L<Perinci::Access::HTTP::Client>,
 L<Perinci::Access::Simple::Client>.
 
 If there is no error, will return C<$envres> with all C<riap.*> keys already
 stripped. If there is an error, an error response will be returned instead.
 Either way, you can use the response returned by this function to user.
 
 =head2 decode_args_in_riap_req($req) => $req
 
 Replace C<ARGNAME:base64> keys in C<arg> in Riap request C<$req> with their
 decoded values. Only done when C<v> key is at least 1.2.
 
 This routine is used in Riap server libraries like in
 L<Perinci::Access::HTTP::Server> and Perinci::Access::Simple::Server::*.
 
 =head1 SEE ALSO
 
 L<Riap>, L<Perinci::Access>.
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Perinci-AccessUtil>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Perinci-AccessUtil-Check>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Perinci-AccessUtil>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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
### Perinci/CmdLine/Base.pm ###
 package Perinci::CmdLine::Base;
 
 our $DATE = '2015-10-20'; # DATE
 our $VERSION = '1.36'; # VERSION
 
 use 5.010001;
 use strict;
 use warnings;
 use Log::Any::IfLOG '$log';
 
 # this class can actually be a role instead of base class for pericmd &
 # pericmd-lite, but Mo is more lightweight than Role::Tiny (also R::T doesn't
 # have attributes), Role::Basic, or Moo::Role.
 
 BEGIN {
     if ($INC{'Perinci/CmdLine/Classic.pm'}) {
         require Moo; Moo->import;
     } else {
         require Mo; Mo->import(qw(build default));
     }
 }
 
 has actions => (is=>'rw');
 has common_opts => (is=>'rw');
 has completion => (is=>'rw');
 has default_subcommand => (is=>'rw');
 has get_subcommand_from_arg => (is=>'rw', default=>1);
 has description => (is=>'rw');
 has exit => (is=>'rw', default=>1);
 has formats => (is=>'rw');
 has pass_cmdline_object => (is=>'rw', default=>0);
 has per_arg_json => (is=>'rw');
 has per_arg_yaml => (is=>'rw');
 has program_name => (
     is=>'rw',
     default => sub {
         my $pn = $ENV{PERINCI_CMDLINE_PROGRAM_NAME};
         if (!defined($pn)) {
             $pn = $0; $pn =~ s!.+/!!;
         }
         $pn;
     });
 has riap_version => (is=>'rw', default=>1.1);
 has riap_client => (is=>'rw');
 has riap_client_args => (is=>'rw');
 has subcommands => (is=>'rw');
 has summary => (is=>'rw');
 has tags => (is=>'rw');
 has url => (is=>'rw');
 
 has read_env => (is=>'rw', default=>1);
 has env_name => (
     is => 'rw',
     lazy => 1,
     default => sub {
         my $self = shift;
         __default_env_name($self->program_name);
     },
 );
 
 has read_config => (is=>'rw', default=>1);
 has config_filename => (is=>'rw');
 has config_dirs => (
     is=>'rw',
     default => sub {
         require Perinci::CmdLine::Util::Config;
         Perinci::CmdLine::Util::Config::get_default_config_dirs();
     },
 );
 
 has cleanser => (
     is => 'rw',
     lazy => 1,
     default => sub {
         require Data::Clean::JSON;
         Data::Clean::JSON->get_cleanser;
     },
 );
 
 has extra_urls_for_version => (is=>'rw');
 
 has skip_format => (is=>'rw');
 
 # role: requires 'hook_after_get_meta'
 # role: requires 'hook_format_row'
 # role: requires 'default_prompt_template'
 
 # role: requires 'hook_before_run'
 # role: requires 'hook_before_read_config_file'
 # role: requires 'hook_after_read_config_file'
 # role: requires 'hook_after_parse_argv'
 # role: requires 'hook_before_action'
 # role: requires 'hook_after_action'
 # role: requires 'hook_format_result'
 # role: requires 'hook_display_result'
 # role: requires 'hook_after_run'
 
 # we put common stuffs here, but PC::Classic's final version will differ from
 # PC::Lite's in several aspects: translation, supported output formats,
 # PC::Classic currently adds some extra keys, some options are not added by
 # PC::Lite (e.g. history/undo stuffs).
 our %copts = (
 
     version => {
         getopt  => "version|v",
         summary => "Display program's version and exit",
         usage   => "--version (or -v)",
         handler => sub {
             my ($go, $val, $r) = @_;
             $r->{action} = 'version';
             $r->{skip_parse_subcommand_argv} = 1;
         },
     },
 
     help => {
         getopt  => 'help|h|?',
         summary => 'Display help message and exit',
         usage   => "--help (or -h, -?)",
         handler => sub {
             my ($go, $val, $r) = @_;
             $r->{action} = 'help';
             $r->{skip_parse_subcommand_argv} = 1;
         },
         order => 0, # high
     },
 
     format => {
         getopt  => 'format=s',
         summary => 'Choose output format, e.g. json, text',
         handler => sub {
             my ($go, $val, $r) = @_;
             $r->{format} = $val;
         },
         default => undef,
         tags => ['category:output'],
         is_settable_via_config => 1,
     },
     json => {
         getopt  => 'json',
         summary => 'Set output format to json',
         handler => sub {
             my ($go, $val, $r) = @_;
             $r->{format} = (-t STDOUT) ? 'json-pretty' : 'json';
         },
         tags => ['category:output'],
     },
 
     naked_res => {
         getopt  => 'naked-res!',
         summary => 'When outputing as JSON, strip result envelope',
         'summary.alt.bool.not' => 'When outputing as JSON, add result envelope',
         description => <<'_',
 
 By default, when outputing as JSON, the full enveloped result is returned, e.g.:
 
     [200,"OK",[1,2,3],{"func.extra"=>4}]
 
 The reason is so you can get the status (1st element), status message (2nd
 element) as well as result metadata/extra result (4th element) instead of just
 the result (3rd element). However, sometimes you want just the result, e.g. when
 you want to pipe the result for more post-processing. In this case you can use
 `--naked-res` so you just get:
 
     [1,2,3]
 
 _
         handler => sub {
             my ($go, $val, $r) = @_;
             $r->{naked_res} = $val ? 1:0;
         },
         default => 0,
         tags => ['category:output'],
         is_settable_via_config => 1,
     },
 
     subcommands => {
         getopt  => 'subcommands',
         summary => 'List available subcommands',
         usage   => "--subcommands",
         show_in_usage => sub {
             my ($self, $r) = @_;
             !$r->{subcommand_name};
         },
         handler => sub {
             my ($go, $val, $r) = @_;
             $r->{action} = 'subcommands';
             $r->{skip_parse_subcommand_argv} = 1;
         },
     },
 
     # 'cmd=SUBCOMMAND_NAME' can be used to select other subcommands when
     # default_subcommand is in effect.
     cmd => {
         getopt  => "cmd=s",
         summary => 'Select subcommand',
         handler => sub {
             my ($go, $val, $r) = @_;
             $r->{subcommand_name} = $val;
             $r->{subcommand_name_from} = '--cmd';
         },
         completion => sub {
             require Complete::Util;
             my %args = @_;
             my $cmdline = $args{cmdline};
             Complete::Util::complete_array_elem(
                 array => [keys %{ $cmdline->list_subcommands }],
                 word  => $args{word},
                 ci    => 1,
             );
         },
     },
 
     config_path => {
         getopt  => 'config-path=s@',
         schema  => ['array*', of => 'str*'],
         'x.schema.element_entity' => 'filename',
         summary => 'Set path to configuration file',
         handler => sub {
             my ($go, $val, $r) = @_;
             $r->{config_paths} //= [];
             push @{ $r->{config_paths} }, $val;
         },
         tags => ['category:configuration'],
     },
     no_config => {
         getopt  => 'no-config',
         summary => 'Do not use any configuration file',
         handler => sub {
             my ($go, $val, $r) = @_;
             $r->{read_config} = 0;
         },
         tags => ['category:configuration'],
     },
     no_env => {
         getopt  => 'no-env',
         summary => 'Do not read environment for default options',
         handler => sub {
             my ($go, $val, $r) = @_;
             $r->{read_env} = 0;
         },
         tags => ['category:environment'],
     },
     config_profile => {
         getopt  => 'config-profile=s',
         summary => 'Set configuration profile to use',
         handler => sub {
             my ($go, $val, $r) = @_;
             $r->{config_profile} = $val;
         },
         completion => sub {
             # return list of profiles in read config file
 
             my %args = @_;
             my $word    = $args{word} // '';
             my $cmdline = $args{cmdline};
             my $r       = $args{r};
 
             # we are not called from cmdline, bail (actually we might want to
             # return list of programs anyway, but we want to read the value of
             # bash_global_dir et al)
             return undef unless $cmdline;
 
             # since this is common option, at this point we haven't parsed
             # argument or even read config file. so we need to do that first.
             {
                 # this is not activated yet
                 $r->{read_config} = 1;
 
                 my $res = $cmdline->parse_argv($r);
                 #return undef unless $res->[0] == 200;
             }
 
             # we are not reading any config file, return empty list
             return [] unless $r->{config};
 
             my @profiles;
             for (keys %{$r->{config}}) {
                 if (length $r->{subcommand_name}) {
                     push @profiles, $1
                         if /\A\Q$r->{subcommand_name}\E \s+ profile=(.+)/x;
                 } else {
                     push @profiles, $1 if /\Aprofile=(.+)/;
                 }
             }
 
             require Complete::Util;
             Complete::Util::complete_array_elem(
                 array=>[sort @profiles], word=>$word, ci=>1);
         },
         tags => ['category:configuration'],
     },
 
     # since the cmdline opts is consumed, Log::Any::App doesn't see this. we
     # currently work around this via setting env.
     log_level => {
         getopt  => 'log-level=s',
         summary => 'Set log level (note: you also need to set LOG=1 to enable logging)',
         schema  => ['str*' => in => [
             qw/trace debug info warn warning error fatal/]],
         handler => sub {
             my ($go, $val, $r) = @_;
             $r->{log_level} = $val;
             $ENV{LOG_LEVEL} = $val;
         },
         is_settable_via_config => 1,
         tags => ['category:logging'],
     },
     trace => {
         getopt  => "trace",
         summary => "Set log level to trace (note: you also need to set LOG=1 to enable logging, or use TRACE=1)",
         handler => sub {
             my ($go, $val, $r) = @_;
             $ENV{TRACE} = 1;
         },
         tags => ['category:logging'],
     },
     debug => {
         getopt  => "debug",
         summary => "Set log level to debug (note: you also need to set LOG=1 to enable logging, or use DEBUG=1)",
         handler => sub {
             my ($go, $val, $r) = @_;
             $ENV{DEBUG} = 1;
         },
         tags => ['category:logging'],
     },
     verbose => {
         getopt  => "verbose",
         summary => "Set log level to info (note: you also need to set LOG=1 to enable logging, or use VERBOSE=1)",
         handler => sub {
             my ($go, $val, $r) = @_;
             $ENV{VERBOSE} = 1;
             $r->{_help_verbose} = 1;
         },
         tags => ['category:logging'],
     },
     quiet => {
         getopt  => "quiet",
         summary => "Set log level to quiet (note: you also need to set LOG=1 to enable logging, or use QUIET=1)",
         handler => sub {
             my ($go, $val, $r) = @_;
             $ENV{QUIET} = 1;
         },
         tags => ['category:logging'],
     },
 
 );
 
 sub __default_env_name {
     my ($prog) = @_;
 
     for ($prog) {
         $_ //= "PROG"; # shouldn't happen
         $_ = uc($_);
         s/[^A-Z0-9]+/_/g;
     }
     "${prog}_OPT";
 }
 
 sub hook_before_run {}
 
 sub hook_before_read_config_file {}
 
 sub hook_after_read_config_file {}
 
 sub hook_before_action {}
 
 sub hook_after_action {}
 
 sub get_meta {
     my ($self, $r, $url) = @_;
 
     my $res = $self->riap_client->request(meta => $url);
     die $res unless $res->[0] == 200;
     my $meta = $res->[2];
     $r->{meta} = $meta;
     $log->tracef("[pericmd] Running hook_after_get_meta ...");
     $self->hook_after_get_meta($r);
     $meta;
 }
 
 sub get_program_and_subcommand_name {
     my ($self, $r) = @_;
     my $res = ($self->program_name // "") . " " .
         ($r->{subcommand_name} // "");
     $res =~ s/\s+$//;
     $res;
 }
 
 sub get_subcommand_data {
     my ($self, $name) = @_;
 
     my $scs = $self->subcommands;
     return undef unless $scs;
 
     if (ref($scs) eq 'CODE') {
         return $scs->($self, name=>$name);
     } else {
         return $scs->{$name};
     }
 }
 
 sub list_subcommands {
     my ($self) = @_;
     return $self->{_cache_subcommands} if $self->{_cache_subcommands};
 
     my $scs = $self->subcommands;
     my $res;
     if ($scs) {
         if (ref($scs) eq 'CODE') {
             $scs = $scs->($self);
             die [500, "BUG: Subcommands code didn't return a hashref"]
                 unless ref($scs) eq 'HASH';
         }
         $res = $scs;
     } else {
         $res = {};
     }
     $self->{_cache_subcommands} = $res;
     $res;
 }
 
 sub status2exitcode {
     my ($self, $status) = @_;
     return 0 if $status =~ /^2..|304/;
     $status - 300;
 }
 
 sub _detect_completion {
     my ($self, $r) = @_;
 
     if ($ENV{COMP_SHELL}) {
         $r->{shell} = $ENV{COMP_SHELL};
         return 1;
     } elsif ($ENV{COMP_LINE}) {
         $r->{shell} = 'bash';
         return 1;
     } elsif ($ENV{COMMAND_LINE}) {
         $r->{shell} = 'tcsh';
         return 1;
     }
 
     $r->{shell} //= 'bash';
     0;
 }
 
 sub _read_env {
     my ($self, $r) = @_;
 
     return [] unless $self->read_env;
     my $env_name = $self->env_name;
     my $env = $ENV{$env_name};
     $log->tracef("[pericmd] Checking env %s: %s", $env_name, $env);
     return [] unless defined $env;
 
     # XXX is it "proper" to use Complete::* modules to parse cmdline, outside
     # the context of completion?
 
     my $words;
     if ($r->{shell} eq 'bash') {
         require Complete::Bash;
         ($words, undef) = @{ Complete::Bash::parse_cmdline($env, 0) };
     } elsif ($r->{shell} eq 'fish') {
         require Complete::Fish;
         ($words, undef) = @{ Complete::Fish::parse_cmdline($env) };
     } elsif ($r->{shell} eq 'tcsh') {
         require Complete::Tcsh;
         ($words, undef) = @{ Complete::Tcsh::parse_cmdline($env) };
     } elsif ($r->{shell} eq 'zsh') {
         require Complete::Zsh;
         ($words, undef) = @{ Complete::Zsh::parse_cmdline($env) };
     } else {
         die "Unsupported shell '$r->{shell}'";
     }
     $log->tracef("[pericmd] Words from env: %s", $words);
     $words;
 }
 
 sub do_completion {
     my ($self, $r) = @_;
 
     local $r->{in_completion} = 1;
 
     my ($words, $cword);
     if ($r->{shell} eq 'bash') {
         require Complete::Bash;
         ($words, $cword) = @{ Complete::Bash::parse_cmdline() };
     } elsif ($r->{shell} eq 'fish') {
         require Complete::Fish;
         ($words, $cword) = @{ Complete::Fish::parse_cmdline() };
     } elsif ($r->{shell} eq 'tcsh') {
         require Complete::Tcsh;
         ($words, $cword) = @{ Complete::Tcsh::parse_cmdline() };
     } elsif ($r->{shell} eq 'zsh') {
         require Complete::Zsh;
         ($words, $cword) = @{ Complete::Zsh::parse_cmdline() };
     } else {
         die "Unsupported shell '$r->{shell}'";
     }
 
     shift @$words; $cword--; # strip program name
 
     # @ARGV given by bash is messed up / different. during completion, we
     # get ARGV from parsing COMP_LINE/COMP_POINT.
     @ARGV = @$words;
 
     # check whether subcommand is defined. try to search from --cmd, first
     # command-line argument, or default_subcommand.
     $self->_parse_argv1($r);
 
     if ($r->{read_env}) {
         my $env_words = $self->_read_env($r);
         unshift @ARGV, @$env_words;
         $cword += @$env_words;
     }
 
     #$log->tracef("ARGV=%s", \@ARGV);
     #$log->tracef("words=%s", $words);
 
     # force format to text for completion, because user might type 'cmd --format
     # blah -^'.
     $r->{format} = 'text';
 
     my $scd = $r->{subcommand_data};
     my $meta = $self->get_meta($r, $scd->{url} // $self->{url});
 
     my $subcommand_name_from = $r->{subcommand_name_from} // '';
 
     require Perinci::Sub::Complete;
     my $compres = Perinci::Sub::Complete::complete_cli_arg(
         meta            => $meta, # must be normalized
         words           => $words,
         cword           => $cword,
         common_opts     => $self->common_opts,
         riap_server_url => $scd->{url},
         riap_uri        => undef,
         riap_client     => $self->riap_client,
         extras          => {r=>$r, cmdline=>$self},
         func_arg_starts_at => ($subcommand_name_from eq 'arg' ? 1:0),
         completion      => sub {
             my %args = @_;
             my $type = $args{type};
 
             # user specifies custom completion routine, so use that first
             if ($self->completion) {
                 my $res = $self->completion(%args);
                 return $res if $res;
             }
             # if subcommand name has not been supplied and we're at arg#0,
             # complete subcommand name
             if ($self->subcommands &&
                     $subcommand_name_from ne '--cmd' &&
                          $type eq 'arg' && $args{argpos}==0) {
                 require Complete::Util;
                 return Complete::Util::complete_array_elem(
                     array => [keys %{ $self->list_subcommands }],
                     word  => $words->[$cword]);
             }
 
             # otherwise let periscomp do its thing
             return undef;
         },
     );
 
     my $formatted;
     if ($r->{shell} eq 'bash') {
         $formatted = Complete::Bash::format_completion(
             $compres, {word=>$words->[$cword]});
     } elsif ($r->{shell} eq 'fish') {
         $formatted = Complete::Fish::format_completion($compres);
     } elsif ($r->{shell} eq 'tcsh') {
         $formatted = Complete::Tcsh::format_completion($compres);
     } elsif ($r->{shell} eq 'zsh') {
         $formatted = Complete::Zsh::format_completion($compres);
     }
 
     [200, "OK", $formatted,
      # these extra result are for debugging
      {
          "func.words" => $words,
          "func.cword" => $cword,
          "cmdline.skip_format" => 1,
      }];
 }
 
 sub _read_config {
     require Perinci::CmdLine::Util::Config;
 
     my ($self, $r) = @_;
 
     $log->tracef("[pericmd] Finding config files ...");
     my $res = Perinci::CmdLine::Util::Config::read_config(
         config_paths    => $r->{config_paths},
         config_filename => $self->config_filename,
         config_dirs     => $self->config_dirs,
         program_name    => $self->program_name,
     );
     die $res unless $res->[0] == 200;
     $r->{config} = $res->[2];
     $r->{read_config_files} = $res->[3]{'func.read_files'};
     $log->tracef("[pericmd] Read config files: %s",
                  $r->{'read_config_files'});
 }
 
 sub __min(@) {
     my $m = $_[0];
     for (@_) {
         $m = $_ if $_ < $m;
     }
     $m;
 }
 
 # straight copy of Wikipedia's "Levenshtein Distance"
 sub __editdist {
     my @a = split //, shift;
     my @b = split //, shift;
 
     # There is an extra row and column in the matrix. This is the distance from
     # the empty string to a substring of the target.
     my @d;
     $d[$_][0] = $_ for 0 .. @a;
     $d[0][$_] = $_ for 0 .. @b;
 
     for my $i (1 .. @a) {
         for my $j (1 .. @b) {
             $d[$i][$j] = (
                 $a[$i-1] eq $b[$j-1]
                     ? $d[$i-1][$j-1]
                     : 1 + __min(
                         $d[$i-1][$j],
                         $d[$i][$j-1],
                         $d[$i-1][$j-1]
                     )
                 );
         }
     }
 
     $d[@a][@b];
 }
 
 sub __uniq {
     my %seen = ();
     my $k;
     my $seen_undef;
     grep { defined $_ ? not $seen{ $k = $_ }++ : not $seen_undef++ } @_;
 }
 
 # $cut is whether we should only compare each element of haystack up to the
 # length of needle, so if needle is "foo" and haystack is ["bar", "baroque",
 # "fizzle", "food"], it will be as if haystack is ["bar", "bar", "fiz", "foo"].
 sub __find_similar_strings {
     my ($needle, $haystack, $cut) = @_;
 
     my $factor   = 1.5;
     my $max_dist = 4;
 
     my @res =
         map { $_->[0] }
         sort { $a->[1] <=> $b->[1] }
         grep { defined }
         map {
             my $el = $_;
             if ($cut && length($_) > length($needle)) {
                 $el = substr($el, 0, length($needle));
             }
             my $d = __editdist($el, $needle);
             my $max_distance = __min(
                 __min(length($el), length($needle))/$factor,
                 $max_dist,
             );
             ($d <= $max_distance) ? [$_, $d] : undef
         } @$haystack;
 
     $cut ? __uniq(@res) : @res;
 }
 
 sub __find_similar_go_opts {
     my ($opt, $go_spec) = @_;
 
     $opt =~ s/^--?//;
 
     my @ospecs0 = ref($go_spec) eq 'ARRAY' ?
         keys(%{ { @$go_spec } }) : keys(%$go_spec);
     my @ospecs;
     for my $o (@ospecs0) {
         $o =~ s/^--?//;
         my $is_neg = $o =~ /\!$/;
         $o =~ s/[=:].+|[?+!]$//;
         for (split /\|/, $o) {
             if ($is_neg && length($_) > 1) {
                 push @ospecs, $_, "no$_", "no-$_";
             } else {
                 push @ospecs, $_;
             }
         }
     }
 
     map { length($_) > 1 ? "--$_" : "-$_" }
         __find_similar_strings($opt, \@ospecs, "cut");
 }
 
 sub _parse_argv1 {
     my ($self, $r) = @_;
 
     # parse common_opts which potentially sets subcommand
     my @go_spec;
     {
         # one small downside for this is that we cannot do autoabbrev here,
         # because we're not yet specifying all options here.
 
         require Getopt::Long;
         my $old_go_conf = Getopt::Long::Configure(
             'pass_through', 'no_ignore_case', 'bundling', 'no_auto_abbrev');
         my $co = $self->common_opts // {};
         for my $k (keys %$co) {
             push @go_spec, $co->{$k}{getopt} => sub {
                 my ($go, $val) = @_;
                 $co->{$k}{handler}->($go, $val, $r);
             };
         }
         #$log->tracef("\@ARGV before parsing common opts: %s", \@ARGV);
         Getopt::Long::GetOptions(@go_spec);
         Getopt::Long::Configure($old_go_conf);
         #$log->tracef("\@ARGV after  parsing common opts: %s", \@ARGV);
     }
 
     # select subcommand and fill subcommand data
     {
         my $scn = $r->{subcommand_name};
         my $scn_from = $r->{subcommand_name_from};
         if (!defined($scn) && defined($self->{default_subcommand})) {
             # get from default_subcommand
             if ($self->get_subcommand_from_arg == 1) {
                 $scn = $self->{default_subcommand};
                 $scn_from = 'default_subcommand';
             } elsif ($self->get_subcommand_from_arg == 2 && !@ARGV) {
                 $scn = $self->{default_subcommand};
                 $scn_from = 'default_subcommand';
             }
         }
         if (!defined($scn) && $self->{subcommands} && @ARGV) {
             # get from first command-line arg
             if ($ARGV[0] =~ /\A-/) {
                 if ($r->{in_completion}) {
                     $scn = shift @ARGV;
                     $scn_from = 'arg';
                 } else {
                     my $suggestion = '';
                     my @similar = __find_similar_go_opts($ARGV[0], \@go_spec);
                     $suggestion = " (perhaps you meant ".
                         join("/", @similar)."?)" if @similar;
                     die [400, "Unknown option: $ARGV[0]".$suggestion];
                 }
             } else {
                 $scn = shift @ARGV;
                 $scn_from = 'arg';
             }
         }
 
         my $scd;
         if (defined $scn) {
             $scd = $self->get_subcommand_data($scn);
             unless ($r->{in_completion}) {
                 unless ($scd) {
                     my $suggestion = '';
                     my $scs = $self->subcommands;
                     if (ref($scs) eq 'HASH') {
                         my @similar =
                             __find_similar_strings($scn, [keys %$scs]);
                         $suggestion = " (perhaps you meant ".
                             join("/", @similar)."?)" if @similar;
                     }
                     die [500, "Unknown subcommand: $scn".$suggestion];
                 }
             }
         } elsif (!$r->{action} && $self->{subcommands}) {
             # program has subcommands but user doesn't specify any subcommand,
             # or specific action. display help instead.
             $r->{action} = 'help';
             $r->{skip_parse_subcommand_argv} = 1;
         } else {
             $scn = '';
             $scd = {
                 url => $self->url,
                 summary => $self->summary,
                 description => $self->description,
                 pass_cmdline_object => $self->pass_cmdline_object,
                 tags => $self->tags,
             };
         }
         $r->{subcommand_name} = $scn;
         $r->{subcommand_name_from} = $scn_from;
         $r->{subcommand_data} = $scd;
     }
 
     # also set dry-run on environment
     $r->{dry_run} = 1 if $ENV{DRY_RUN};
 
     $r->{_parse_argv1_done} = 1;
 }
 
 sub _parse_argv2 {
     require Perinci::CmdLine::Util::Config;
 
     my ($self, $r) = @_;
 
     my %args;
 
     if ($r->{read_env}) {
         my $env_words = $self->_read_env($r);
         unshift @ARGV, @$env_words;
     }
 
     # parse argv for per-subcommand command-line opts
     if ($r->{skip_parse_subcommand_argv}) {
         return [200, "OK (subcommand options parsing skipped)"];
     } else {
         my $scd = $r->{subcommand_data};
         my $meta = $self->get_meta($r, $scd->{url});
 
         # first fill in from subcommand specification
         if ($scd->{args}) {
             $args{$_} = $scd->{args}{$_} for keys %{ $scd->{args} };
         }
 
         # then read from configuration
         if ($r->{read_config}) {
 
             $log->tracef("[pericmd] Running hook_before_read_config_file ...");
             $self->hook_before_read_config_file($r);
 
             $self->_read_config($r);
 
             $log->tracef("[pericmd] Running hook_after_read_config_file ...");
             $self->hook_after_read_config_file($r);
 
             my $res = Perinci::CmdLine::Util::Config::get_args_from_config(
                 r                  => $r,
                 config             => $r->{config},
                 args               => \%args,
                 subcommand_name    => $r->{subcommand_name},
                 config_profile     => $r->{config_profile},
                 common_opts        => $self->common_opts,
                 meta               => $meta,
                 meta_is_normalized => 1,
             );
             die $res unless $res->[0] == 200;
             $log->tracef("[pericmd] args after reading config files: %s",
                          \%args);
             my $found = $res->[3]{'func.found'};
             if (defined($r->{config_profile}) && !$found &&
                     defined($r->{read_config_files}) &&
                         @{$r->{read_config_files}} &&
                             !$r->{ignore_missing_config_profile_section}) {
                 return [412, "Profile '$r->{config_profile}' not found ".
                             "in configuration file"];
             }
 
         }
 
         # finally get from argv
 
         # since get_args_from_argv() doesn't pass $r, we need to wrap it
         my $copts = $self->common_opts;
         my %old_handlers;
         for (keys %$copts) {
             my $h = $copts->{$_}{handler};
             $copts->{$_}{handler} = sub {
                 my ($go, $val) = @_;
                 $h->($go, $val, $r);
             };
             $old_handlers{$_} = $h;
         }
 
         my $has_cmdline_src;
         for my $ak (keys %{$meta->{args} // {}}) {
             my $av = $meta->{args}{$ak};
             if ($av->{cmdline_src}) {
                 $has_cmdline_src = 1;
                 last;
             }
             # this will probably be eventually checked by the rinci function's
             # schema: stream arguments need to have cmdline_src set to
             # stdin_or_file, stdin_or_files, stdin, or file.
             if ($av->{stream}) {
                 unless ($av->{cmdline_src} &&
                             $av->{cmdline_src} =~
                                 /\A(stdin|file|stdin_or_files?)\z/) {
                     die "BUG: stream argument '$ak' needs to have cmdline_src ".
                         "set to stdin, file, stdin_or_file, or stdin_or_files";
                 }
             }
         }
 
         require Perinci::Sub::GetArgs::Argv;
         my $ga_res = Perinci::Sub::GetArgs::Argv::get_args_from_argv(
             argv                => \@ARGV,
             args                => \%args,
             meta                => $meta,
             meta_is_normalized  => 1,
             allow_extra_elems   => $has_cmdline_src ? 1:0,
             per_arg_json        => $self->{per_arg_json},
             per_arg_yaml        => $self->{per_arg_yaml},
             common_opts         => $copts,
             strict              => $r->{in_completion} ? 0:1,
             on_missing_required_args => sub {
                 my %a = @_;
 
                 my ($an, $aa, $as) = ($a{arg}, $a{args}, $a{spec});
                 my $src = $as->{cmdline_src};
                 if ($src && $as->{req}) {
                     # don't complain, we will fill argument from other source
                     return 1;
                 } else {
                     # we have no other sources, so we complain about missing arg
                     return 0;
                 }
             },
         );
 
         return $ga_res unless $ga_res->[0] == 200;
 
         require Perinci::Sub::CoerceArgs;
         my $coerce_res = Perinci::Sub::CoerceArgs::coerce_args(
             meta                => $meta,
             meta_is_normalized  => 1,
             args                => $ga_res->[2],
         );
 
         return $coerce_res unless $coerce_res->[0] == 200;
 
         # restore
         for (keys %$copts) {
             $copts->{$_}{handler} = $old_handlers{$_};
         }
 
         return $ga_res;
     }
 }
 
 sub parse_argv {
     my ($self, $r) = @_;
 
     $log->tracef("[pericmd] Parsing \@ARGV: %s", \@ARGV);
 
     # we parse argv twice. the first parse is with common_opts only so we're
     # able to catch --help, --version, etc early without having to know about
     # subcommands. two reasons for this: sometimes we need to get subcommand
     # name *from* cmdline opts (e.g. --cmd) and thus it's a chicken-and-egg
     # problem. second, it's faster because we don't have to load Riap client and
     # request the meta through it (especially in the case of remote URL).
     #
     # the second parse is after ge get subcommand name and the function
     # metadata. we can parse the remaining argv to get function arguments.
     #
     # note that when doing completion we're not using this algorithem and only
     # parse argv once. this is to make completion work across common- and
     # per-subcommand opts, e.g. --he<tab> resulting in --help (common opt) as
     # well as --height (function argument).
 
     $self->_parse_argv1($r) unless $r->{_parse_argv1_done};
     $self->_parse_argv2($r);
 }
 
 sub __gen_iter {
     require Data::Sah::Util::Type;
 
     my ($fh, $sch, $argname) = @_;
     my $type = Data::Sah::Util::Type::get_type($sch);
 
     if (Data::Sah::Util::Type::is_simple($sch)) {
         return sub {
             # XXX this will be configurable later. currently by default reading
             # binary is per-64k while reading string is line-by-line.
             local $/ = \(64*1024) if $type eq 'buf';
 
             state $eof;
             return undef if $eof;
             my $l = <$fh>;
             unless (defined $l) {
                 $eof++; return undef;
             }
             $l;
         };
     } else {
         # expect JSON stream for non-simple types
         require JSON;
         state $json = JSON->new->allow_nonref;
         my $i = -1;
         return sub {
             state $eof;
             return undef if $eof;
             $i++;
             my $l = <$fh>;
             unless (defined $l) {
                 $eof++; return undef;
             }
             eval { $l = $json->decode($l) };
             if ($@) {
                 die "Invalid JSON in stream argument '$argname' record #$i: $@";
             }
             $l;
         };
     }
 }
 
 # parse cmdline_src argument spec properties for filling argument value from
 # file and/or stdin. currently does not support argument submetadata.
 sub parse_cmdline_src {
     my ($self, $r) = @_;
 
     my $action = $r->{action};
     my $meta   = $r->{meta};
 
     my $url = $r->{subcommand_data}{url} // $self->{url} // '';
     my $is_network = $url =~ m!^(https?|riap[^:]+):!;
 
     # handle cmdline_src
     if ($action eq 'call') {
         my $args_p = $meta->{args} // {};
         my $stdin_seen;
         for my $an (sort {
             my $csa  = $args_p->{$a}{cmdline_src};
             my $csb  = $args_p->{$b}{cmdline_src};
             my $posa = $args_p->{$a}{pos} // 9999;
             my $posb = $args_p->{$b}{pos} // 9999;
 
             # first, always put stdin_line before stdin / stdin_or_files
             (
                 !$csa || !$csb ? 0 :
                     $csa eq 'stdin_line' && $csb eq 'stdin_line' ? 0 :
                     $csa eq 'stdin_line' && $csb =~ /^(stdin|stdin_or_files?)/ ? -1 :
                     $csb eq 'stdin_line' && $csa =~ /^(stdin|stdin_or_files?)/ ? 1 : 0
             )
             ||
 
             # then order by pos
             ($posa <=> $posb)
 
             ||
             # then by name
             ($a cmp $b)
         } keys %$args_p) {
             #$log->tracef("TMP: handle cmdline_src for arg=%s", $an);
             my $as = $args_p->{$an};
             my $src = $as->{cmdline_src};
             my $type = $as->{schema}[0]
                 or die "BUG: No schema is defined for arg '$an'";
             # Riap::HTTP currently does not support streaming input
             my $do_stream = $as->{stream} && $url !~ /^https?:/;
             if ($src) {
                 die [531,
                      "Invalid 'cmdline_src' value for argument '$an': $src"]
                     unless $src =~ /\A(stdin|file|stdin_or_files?|stdin_line)\z/;
                 die [531,
                      "Sorry, argument '$an' is set cmdline_src=$src, but type ".
                          "is not str/buf/array, only those are supported now"]
                     unless $do_stream || $type =~ /\A(str|buf|array)\z/;
                 if ($src =~ /\A(stdin|stdin_or_files?)\z/) {
                     die [531, "Only one argument can be specified ".
                              "cmdline_src stdin/stdin_or_file/stdin_or_files"]
                         if $stdin_seen++;
                 }
                 my $is_ary = $type eq 'array';
                 if ($src eq 'stdin_line' && !exists($r->{args}{$an})) {
                     require Perinci::Object;
                     my $term_readkey_available = eval { require Term::ReadKey; 1 };
                     my $prompt = Perinci::Object::rimeta($as)->langprop('cmdline_prompt') //
                         sprintf($self->default_prompt_template, $an);
                     print $prompt;
                     my $iactive = (-t STDOUT);
                     Term::ReadKey::ReadMode('noecho')
                           if $term_readkey_available && $iactive && $as->{is_password};
                     chomp($r->{args}{$an} = <STDIN>);
                     do { print "\n"; Term::ReadKey::ReadMode(0) if $term_readkey_available }
                         if $iactive && $as->{is_password};
                     $r->{args}{"-cmdline_src_$an"} = 'stdin_line';
                 } elsif ($src eq 'stdin' || $src eq 'file' &&
                         ($r->{args}{$an}//"") eq '-') {
                     die [400, "Argument $an must be set to '-' which means ".
                              "from stdin"]
                         if defined($r->{args}{$an}) &&
                             $r->{args}{$an} ne '-';
                     #$log->trace("Getting argument '$an' value from stdin ...");
                     $r->{args}{$an} = $do_stream ?
                         __gen_iter(\*STDIN, $as->{schema}, $an) :
                             $is_ary ? [<STDIN>] :
                                 do {local $/; ~~<STDIN>};
                     $r->{args}{"-cmdline_src_$an"} = 'stdin';
                 } elsif ($src eq 'stdin_or_file' || $src eq 'stdin_or_files') {
                     # push back argument value to @ARGV so <> can work to slurp
                     # all the specified files
                     local @ARGV = @ARGV;
                     unshift @ARGV, $r->{args}{$an}
                         if defined $r->{args}{$an};
 
                     # with stdin_or_file, we only accept one file
                     splice @ARGV, 1
                         if @ARGV > 1 && $src eq 'stdin_or_file';
 
                     #$log->tracef("Getting argument '$an' value from ".
                     #                 "$src, \@ARGV=%s ...", \@ARGV);
 
                     # perl doesn't seem to check files, so we check it here
                     for (@ARGV) {
                         next if $_ eq '-';
                         die [500, "Can't read file '$_': $!"] if !(-r $_);
                     }
 
                     $r->{args}{"-cmdline_srcfilenames_$an"} = [@ARGV];
                     $r->{args}{$an} = $do_stream ?
                         __gen_iter(\*ARGV, $as->{schema}, $an) :
                             $is_ary ? [<>] :
                                 do {local $/; ~~<>};
                     $r->{args}{"-cmdline_src_$an"} = $src;
                 } elsif ($src eq 'file') {
                     unless (exists $r->{args}{$an}) {
                         if ($as->{req}) {
                             die [400,
                                  "Please specify filename for argument '$an'"];
                         } else {
                             next;
                         }
                     }
                     die [400, "Please specify filename for argument '$an'"]
                         unless defined $r->{args}{$an};
                     #$log->trace("Getting argument '$an' value from ".
                     #                "file ...");
                     my $fh;
                     my $fname = $r->{args}{$an};
                     unless (open $fh, "<", $fname) {
                         die [500, "Can't open file '$fname' for argument '$an'".
                                  ": $!"];
                     }
                     $r->{args}{$an} = $do_stream ?
                         __gen_iter($fh, $as->{schema}, $an) :
                             $is_ary ? [<$fh>] :
                                 do { local $/; ~~<$fh> };
                     $r->{args}{"-cmdline_src_$an"} = 'file';
                     $r->{args}{"-cmdline_srcfilenames_$an"} = [$fname];
                 }
             }
 
             # encode to base64 if binary and we want to cross network (because
             # it's usually JSON)
             if ($self->riap_version == 1.2 && $is_network &&
                     defined($r->{args}{$an}) && $args_p->{$an}{schema} &&
                         $args_p->{$an}{schema}[0] eq 'buf' &&
                             !$r->{args}{"$an:base64"}) {
                 require MIME::Base64;
                 $r->{args}{"$an:base64"} =
                     MIME::Base64::encode_base64($r->{args}{$an}, "");
                 delete $r->{args}{$an};
             }
         } # for arg
     }
     #$log->tracef("args after cmdline_src is processed: %s", $r->{args});
 }
 
 # determine filehandle to output to (normally STDOUT, but we can also send to a
 # pager
 sub select_output_handle {
     my ($self, $r) = @_;
 
     my $resmeta = $r->{res}[3] // {};
 
     my $handle;
     if ($resmeta->{"cmdline.page_result"}) {
         require File::Which;
         my $pager = $resmeta->{"cmdline.pager"} //
             $ENV{PAGER};
         unless (defined $pager) {
             $pager = "less -FRSX" if File::Which::which("less");
         }
         unless (defined $pager) {
             $pager = "more" if File::Which::which("more");
         }
         unless (defined $pager) {
             die [500, "Can't determine PAGER"];
         }
         last unless $pager; # ENV{PAGER} can be set 0/'' to disable paging
         #$log->tracef("Paging output using %s", $pager);
         open $handle, "| $pager";
     }
     $handle //= \*STDOUT;
     $r->{output_handle} = $handle;
 }
 
 sub display_result {
     require Data::Sah::Util::Type;
 
     my ($self, $r) = @_;
 
     my $meta = $r->{meta};
     my $res = $r->{res};
     my $fres = $r->{fres};
     my $resmeta = $res->[3] // {};
 
     my $handle = $r->{output_handle};
 
     my $sch = $meta->{result}{schema};
     my $type = Data::Sah::Util::Type::get_type($sch) // '';
 
     if ($resmeta->{stream} // $meta->{result}{stream}) {
         my $x = $res->[2];
         if (ref($x) eq 'CODE') {
             if (Data::Sah::Util::Type::is_simple($sch)) {
                 while (defined(my $l = $x->())) {
                     print $l;
                     print "\n" unless $type eq 'buf';
                 }
             } else {
                 require JSON;
                 state $json = JSON->new->allow_nonref;
                 while (defined(my $rec = $x->())) {
                     print $json->encode($rec), "\n";
                 }
             }
         } else {
             die [500, "Invalid stream in result (not a coderef)"];
         }
     } else {
         print $handle $fres;
     }
 }
 
 sub run {
     my ($self) = @_;
     $log->tracef("[pericmd] -> run(), \@ARGV=%s", \@ARGV);
 
     my $co = $self->common_opts;
 
     my $r = {
         orig_argv   => [@ARGV],
         common_opts => $co,
     };
 
     # completion is special case, we delegate to do_completion()
     if ($self->_detect_completion($r)) {
         $r->{res} = $self->do_completion($r);
         goto FORMAT;
     }
 
     # set default from common options
     $r->{naked_res} = $co->{naked_res}{default} if $co->{naked_res};
     $r->{format}    = $co->{format}{default} if $co->{format};
 
     if ($self->read_config) {
         # note that we will be reading config file
         $r->{read_config} = 1;
     }
 
     if ($self->read_env) {
         # note that we will be reading env for default options
         $r->{read_env} = 1;
     }
 
     eval {
         $log->tracef("[pericmd] Running hook_before_run ...");
         $self->hook_before_run($r);
 
         my $parse_res = $self->parse_argv($r);
         if ($parse_res->[0] == 501) {
             # we'll need to send ARGV to the server, because it's impossible to
             # get args from ARGV (e.g. there's a cmdline_alias with CODE, which
             # has been transformed into string when crossing network boundary)
             $r->{send_argv} = 1;
         } elsif ($parse_res->[0] != 200) {
             die $parse_res;
         }
         $r->{parse_argv_res} = $parse_res;
         $r->{args} = $parse_res->[2] // {};
 
         # set defaults
         $r->{action} //= 'call';
 
         $log->tracef("[pericmd] Running hook_after_parse_argv ...");
         $self->hook_after_parse_argv($r);
 
         $self->parse_cmdline_src($r);
 
         #$log->tracef("TMP: parse_res: %s", $parse_res);
 
         my $missing = $parse_res->[3]{"func.missing_args"};
         die [400, "Missing required argument(s): ".join(", ", @$missing)]
             if $missing && @$missing;
 
         my $scd = $r->{subcommand_data};
         if ($scd->{pass_cmdline_object} // $self->pass_cmdline_object) {
             $r->{args}{-cmdline} = $self;
             $r->{args}{-cmdline_r} = $r;
         }
 
         $log->tracef("[pericmd] Running hook_before_action ...");
         $self->hook_before_action($r);
 
         my $meth = "action_$r->{action}";
         die [500, "Unknown action $r->{action}"] unless $self->can($meth);
         $log->tracef("[pericmd] Running %s() ...", $meth);
         $r->{res} = $self->$meth($r);
         #$log->tracef("[pericmd] res=%s", $r->{res}); #1
 
         $log->tracef("[pericmd] Running hook_after_action ...");
         $self->hook_after_action($r);
     };
     my $err = $@;
     if ($err || !$r->{res}) {
         if ($err) {
             $err = [500, "Died: $err"] unless ref($err) eq 'ARRAY';
             if (%Devel::Confess::) {
                 require Scalar::Util;
                 my $id = Scalar::Util::refaddr($err);
                 my $stack_trace = $Devel::Confess::MESSAGES{$id};
                 $err->[1] .= "\n$stack_trace" if $stack_trace;
             }
             $err->[1] =~ s/\n+$//;
             $r->{res} = $err;
         } else {
             $r->{res} = [500, "Bug: no response produced"];
         }
     } elsif (ref($r->{res}) ne 'ARRAY') {
         $log->tracef("[pericmd] res=%s", $r->{res}); #2
         $r->{res} = [500, "Bug in program: result not an array"];
     } elsif (!$r->{res}[0] || $r->{res}[0] < 200 || $r->{res}[0] > 555) {
         $log->tracef("[pericmd] res=%s", $r->{res}); #3
         $r->{res} = [500, "Bug in program: invalid result status, ".
                          "must be 200 <= x <= 555"];
     }
     $r->{format} //= $r->{res}[3]{'cmdline.default_format'};
     $r->{format} //= $r->{meta}{'cmdline.default_format'};
     my $restore_orig_result;
     my $orig_result;
     if (exists $r->{res}[3]{'cmdline.result'}) {
         # temporarily change the result for formatting
         $restore_orig_result = 1;
         $orig_result = $r->{res}[2];
         $r->{res}[2] = $r->{res}[3]{'cmdline.result'};
     }
   FORMAT:
     if ($self->skip_format ||
             $r->{meta}{'cmdline.skip_format'} ||
             $r->{res}[3]{'cmdline.skip_format'}) {
         # skip formatting, just print whatever is in res[2] (with a bit of
         # exception)
         if (!($r->{res}[0] =~ /\A2/ || $r->{res}[0] == 304) &&
                 !defined($r->{res}[2])) {
             # [ux] if there is an error and no result, we still show the error
             # message from res[0] & res[1]. otherwise, user might be confused
             # because there is no error message
             $r->{fres} = "ERROR $r->{res}[0]: $r->{res}[1]" .
                 ($r->{res}[1] =~ /\R\z/ ? "" : "\n");
         } else {
             $r->{fres} = $r->{res}[2] // '';
         }
     } elsif ($r->{res}[3]{stream} // $r->{meta}{result}{stream}) {
         # stream will be formatted as displayed by display_result()
     } else {
         $log->tracef("[pericmd] Running hook_format_result ...");
         $r->{fres} = $self->hook_format_result($r) // '';
     }
     $self->select_output_handle($r);
     $log->tracef("[pericmd] Running hook_display_result ...");
     $self->hook_display_result($r);
     $log->tracef("[pericmd] Running hook_after_run ...");
     $self->hook_after_run($r);
 
     if ($restore_orig_result) {
         $r->{res}[2] = $orig_result;
     }
 
     my $exitcode;
     if ($r->{res}[3] && defined($r->{res}[3]{'cmdline.exit_code'})) {
         $exitcode = $r->{res}[3]{'cmdline.exit_code'};
     } else {
         $exitcode = $self->status2exitcode($r->{res}[0]);
     }
     if ($self->exit) {
         $log->tracef("[pericmd] exit(%s)", $exitcode);
         exit $exitcode;
     } else {
         # so this can be tested
         $log->tracef("[pericmd] <- run(), exitcode=%s", $exitcode);
         $r->{res}[3]{'x.perinci.cmdline.base.exit_code'} = $exitcode;
         return $r->{res};
     }
 }
 
 1;
 # ABSTRACT: Base class for Perinci::CmdLine{::Classic,::Lite}
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Perinci::CmdLine::Base - Base class for Perinci::CmdLine{::Classic,::Lite}
 
 =head1 VERSION
 
 This document describes version 1.36 of Perinci::CmdLine::Base (from Perl distribution Perinci-CmdLine-Lite), released on 2015-10-20.
 
 =head1 DESCRIPTION
 
 =for Pod::Coverage ^(.+)$
 
 =head1 PROGRAM FLOW (NORMAL)
 
 If you execute C<run()>, this is what will happen, in order:
 
 =over
 
 =item * Detect if we are running under tab completion mode
 
 This is done by checking the existence of special environment varibles like
 C<COMP_LINE> (bash) or C<COMMAND_LINE> (tcsh). If yes, then jump to L</"PROGRAM
 FLOW (TAB COMPLETION)">. Otherwise, continue.
 
 =item * Run hook_before_run, if defined
 
 This hook (and every other hook) will be passed a single argument C<$r>, a hash
 that contains request data (see L</"REQUEST KEYS">).
 
 Some ideas that you can do in this hook: XXX.
 
 =item * Parse command-line arguments (@ARGV) and set C<action>
 
 If C<read_env> attribute is set to true, and there is environment variable
 defined to set default options (see documentation on C<read_env> and C<env_name>
 attributes) then the environment variable is parsed and prepended first to the
 command-line, so it can be parsed together. For example, if your program is
 called C<foo> and environment variable C<FOO_OPT> is set to C<--opt1 --opt2
 val>. When you execute:
 
  % foo --no-opt1 --trace 1 2
 
 then C<@ARGV> will be set to C<< ('--opt1', '--opt2', 'val', '--no-opt1',
 '--trace', 1, 2) >>. This way, command-line arguments can have a higher
 precedence and override settings from the environment variable (in this example,
 C<--opt1> is negated by C<--no-opt1>).
 
 Currently, parsing is done in two steps. The first step is to extract subcommand
 name. Because we want to allow e.g. C<cmd --verbose subcmd> in addition to C<cmd
 subcmd> (that is, user is allowed to specify options before subcommand name) we
 cannot simply get subcommand name from the first element of C<@ARGV> but must
 parse command-line options. Also, we want to allow user specifying subcommand
 name from option C<cmd --cmd subcmd> because we want to support the notion of
 "default subcommand" (subcommand that takes effect if there is no subcommand
 specified).
 
 In the first step, since we do not know the subcommand yet, we only parse common
 options and strip them. Unknown options at this time will be passed through.
 
 If user specifies common option like C<--help> or C<--version>, then action will
 be set to (respectively) C<help> and C<version> and the second step will be
 skipped. Otherwise we continue the the second step and action by default is set
 to C<call>.
 
 At the end of the first step, we already know the subcommand name (of course, if
 subcommand name is unknown, we exit with error) along with subcommand spec: its
 URL, per-subcommand settings, and so on (see the C<subcommands> attribute). If
 there are no subcommands, subcommand name is set to C<''> (empty string) and the
 subcommand spec is filled from the attributes, e.g. C<url>, C<summary>, <tags>,
 and so on.
 
 We then perform a C<meta> Riap request to the URL to get the Rinci metadata.
 After that, C<hook_after_get_meta> is run if provided. From the Rinci metadata
 we get list of arguments (the C<args> property). From this, we generate a spec
 of command-line options to feed to L<Getopt::Long>. There are some conversions
 being done, e.g. an argument called C<foo_bar> will become command-line option
 C<--foo-bar>. Command-line aliases from metadata are also added to the
 C<Getopt::Long> spec.
 
 It is also at this step that we read config file (if C<read_config> attribute is
 true). We run C<hook_before_read_config_file> first. Some ideas to do in this
 hook: setting default config profile.
 
 We then pass the spec to C<Getopt::Long::GetOptions>, we get function arguments.
 
 We then run C<hook_after_parse_argv>. Some ideas to do in this hook: XXX.
 
 Function arguments that are still missing can be filled from STDIN or files, if
 the metadata specifies C<cmdline_src> property (see L<Rinci::function> for more
 details).
 
 =item * Delegate to C<action_$action> method
 
 Before running the C<action_$action> method, C<hook_before_action> is called
 e.g. to allow changing/fixing action, last chance to check arguments, etc.
 
 After we get the action from the previous step, we delegate to separate
 C<action_$action> method (so there is C<action_version>, C<action_help>, and so
 on; and also C<action_call>). These methods also receive C<$r> as their argument
 and must return an enveloped result (see L<Rinci::function> for more details).
 
 Result is put in C<< $r->{res} >>.
 
 C<hook_after_action> is then called e.g. to preformat result.
 
 =item * Run hook_format_result
 
 Hook must set C<< $r->{fres} >> (formatted result).
 
 If C<skip_format> attribute is true, or function metadata has
 C<cmdline.skip_format> set to true, or result has C<cmdline.skip_format>
 metadata property set to true, then this step is skipped and C<< $r->{fres} >>
 is simply taken from C<< $r->{res}[2] >>.
 
 =item * Run hook_display_result
 
 This hook is used by XXX.
 
 =item * Run hook_after_run, if defined
 
 Some ideas to do in this hook: XXX.
 
 =item * Exit (or return result)
 
 If C<exit> attribute is true, will C<exit()> with the action's envelope result
 status. If status is 200, exit code is 0. Otherwise exit code is status minus
 300. So, a response C<< [501, "Not implemented"] >> will result in exit code of
 201.
 
 If C<exit> attribute is false, will simply return the action result (C<<
 $r->{res} >>). And will also set exit code in C<<
 $r->{res}[3]{'x.perinci.cmdline.base.exit_code'} >>.
 
 =back
 
 =head1 PROGRAM FLOW (TAB COMPLETION)
 
 If program is detected running in tab completion mode, there is some differences
 in the flow. First, C<@ARGV> is set from C<COMP_LINE> (or C<COMMAND_LINE>)
 environment variable. Afterwards, completion is done by calling
 L<Perinci::Sub::Complete>'s C<complete_cli_arg>.
 
 The result is then output to STDOUT (resume from Run hook_format_result step in
 the normal program flow).
 
 =head1 REQUEST KEYS
 
 The various values in the C<$r> hash/stash.
 
 =over
 
 =item * orig_argv => array
 
 Original C<@ARGV> at the beginning of C<run()>.
 
 =item * common_opts => hash
 
 Value of C<common_opts> attribute, for convenience.
 
 =item * action => str
 
 Selected action to use. Usually set from the common options.
 
 =item * format => str
 
 Selected format to use. Usually set from the common option C<--format>.
 
 =item * read_config => bool
 
 This is set in run() to signify that we have tried to read config file (this is
 set to true even though config file does not exist). This is never set to true
 when C<read_config> attribute is set, which means that we never try to read any
 config file.
 
 =item * read_env => bool
 
 This is set in run() to signify that we will try to read env for default
 options. This settng can be turned off e.g. in common option C<no_env>. This is
 never set to true when C<read_env> attribute is set to false, which means that
 we never try to read environment.
 
 =item * config => hash
 
 This is set in the routine that reads config file, containing the config hash.
 It might be an empty hash (if there is on config file to read), or a hash with
 sections as keys and hashrefs as values (configuration for each section). The
 data can be merged from several existing config files.
 
 =item * read_config_files => array
 
 This is set in the routine that reads config file, containing the list of config
 files actually read, in order.
 
 =item * config_paths => array of str
 
 =item * config_profile => str
 
 =item * parse_argv_res => array
 
 Enveloped result of C<parse_argv()>.
 
 =item * ignore_missing_config_profile_section => bool (default 1)
 
 This is checked in the parse_argv(). To aid error checking, when a user
 specifies a profile (e.g. via C<--config-profile FOO>) and config file exists
 but the said profile section is not found in the config file, an error is
 returned. This is to notify user that perhaps she mistypes the profile name.
 
 But this checking can be turned off with this setting. This is sometimes used
 when e.g. a subclass wants to pick a config profile automatically by setting C<<
 $r->{config_profile} >> somewhere before reading config file, but do not want to
 fail execution when config profile is not found. An example of code that does
 this is L<Perinci::CmdLine::depak>.
 
 =item * subcommand_name => str
 
 Also set by C<parse_argv()>. The subcommand name in effect, either set
 explicitly by user using C<--cmd> or the first command-line argument, or set
 implicitly with the C<default_subcommand> attribute. Undef if there is no
 subcommand name in effect.
 
 =item * subcommand_name_from => str
 
 Also set by C<parse_argv()>. Tells how the C<subcommand_name> request key is
 set. Value is either C<--cmd> (if set through C<--cmd> common option), C<arg>
 (if set through first command-line argument), C<default_subcommand> (if set to
 C<default_subcommand> attribute), or undef if there is no subcommand_name set.
 
 =item * subcommand_data => hash
 
 Also set by C<parse_argv()>. Subcommand data, including its URL, summary (if
 exists), and so on. Note that if there is no subcommand, this will contain data
 for the main command, i.e. URL will be set from C<url> attribute, summary from
 C<summary> attribute, and so on. This is a convenient way to get what URL and
 summary to use, and so on.
 
 =item * skip_parse_subcommand_argv => bool
 
 Checked by C<parse_argv()>. Can be set to 1, e.g. in common option handler for
 C<--help> or C<--version> to skip parsing @ARGV for per-subcommand options.
 
 =item * args => hash
 
 Also taken from C<parse_argv()> result.
 
 =item * meta => hash
 
 Result of C<get_meta()>.
 
 =item * dry_run => bool
 
 Whether to pass C<-dry_run> special argument to function.
 
 =item * res => array
 
 Enveloped result of C<action_ACTION()>.
 
 =item * fres => str
 
 Result from C<hook_format_result()>.
 
 =item * output_handle => handle
 
 Set by select_output_handle() to choose output handle. Normally it's STDOUT but
 can also be pipe to pager (if paging is turned on).
 
 =item * naked_res => bool
 
 Set to true if user specifies C<--naked-res>.
 
 =back
 
 =head1 CONFIGURATION
 
 Configuration can be used to set function arguments as well as some common
 options.
 
 Configuration is currently in the L<IOD> (basically INI) format.
 
 By default these paths are searched: C<$HOME/.config/$prog_name.conf>,
 C<$HOME/$prog_name.conf>, C</etc/$prog_name.conf>. The location can be
 customized from command-line option C<--config-path>.
 
 All existing configuration files will be read in order, and the result merged if
 more than one files exist.
 
 Section names map to subcommand names. For application that does not have
 subcommand, you can put parameters outside any section, e.g.:
 
  param=val
  otherparam=val
  ...
 
 For application that has subcommands, put parameters inside section with the
 same name as the subcommand name:
 
  [subcommand1]
  param=val
  ...
 
  [subcommand2]
  param2=val
  ...
 
 Or you can also put some parameters outside the section which will be used for
 all subcommands:
 
  commonarg=val
 
  [subcommand1]
  param1=val
  ...
 
  [subcommand2]
  param2=val
  ...
 
 A configuration file can also have (multiple) profiles, to allow multiple
 configuration to be stored in a single file. Section names can have
 "profile=PROFILENAME" suffix to mark it as belonging to a certain profile.
 Parameters in sections with matching "profile=PROFILENAME" will be read.
 Parameters in sections without any profile names will still be read. Example:
 
  a=0
  b=0
  d=9
 
  [profile=p1]
  a=1
  b=2
 
  [profile=p2]
  a=10
  b=20
 
  [subcommand1 profile=p1]
  c=3
 
  [subcommand1 profile=p2]
  c=1
 
 If you run:
 
  % cmd subcommand1
 
 then your subcommand1 function will get: a=0, b=0, d=9.
 
  % cmd subcommand1 --config-profile p1
 
 then your subcommand1 function will get: a=1, b=2, c=3, d=9. If you run:
 
  % cmd subcommand1 --config-profile p2
 
 then your subcommand1 function will get: a=10, b=20, c=30, d=9.
 
 Parameter names map to function argument names or common option. If a common
 option name clashes with a function argument name, the function argument is
 accessible using the C<NAME.arg> syntax. For example, C<log_level> is a common
 option name. If your function also has a C<log_level> argument, to set this
 function argument, you write:
 
  log_level.arg=blah
 
 =head1 ATTRIBUTES
 
 =head2 actions => array
 
 Contains a list of known actions and their metadata. Keys should be action
 names, values should be metadata. Metadata is a hash containing these keys:
 
 =head2 common_opts => hash
 
 A hash of common options, which are command-line options that are not associated
 with any subcommand. Each option is itself a specification hash containing these
 keys:
 
 =over
 
 =item * category (str)
 
 Optional, for grouping options in help/usage message, defaults to C<Common
 options>.
 
 =item * getopt (str)
 
 Required, for Getopt::Long specification.
 
 =item * handler (code)
 
 Required, for Getopt::Long specification. Note that the handler will receive C<<
 ($geopt, $val, $r) >> (an extra C<$r>).
 
 =item * usage (str)
 
 Optional, displayed in usage line in help/usage text.
 
 =item * summary (str)
 
 Optional, displayed in description of the option in help/usage text.
 
 =item * show_in_usage (bool or code, default: 1)
 
 A flag, can be set to 0 if we want to skip showing this option in usage in
 --help, to save some space. The default is to show all, except --subcommand when
 we are executing a subcommand (obviously).
 
 =item * show_in_options (bool or code, default: 1)
 
 A flag, can be set to 0 if we want to skip showing this option in options in
 --help. The default is to 0 for --help and --version in compact help. Or
 --subcommands, if we are executing a subcommand (obviously).
 
 =item * order (int)
 
 Optional, for ordering. Lower number means higher precedence, defaults to 1.
 
 =back
 
 A partial example from the default set by the framework:
 
  {
      help => {
          category        => 'Common options',
          getopt          => 'help|h|?',
          usage           => '--help (or -h, -?)',
          handler         => sub { ... },
          order           => 0,
          show_in_options => sub { $ENV{VERBOSE} },
      },
      format => {
          category    => 'Common options',
          getopt      => 'format=s',
          summary     => 'Choose output format, e.g. json, text',
          handler     => sub { ... },
      },
      undo => {
          category => 'Undo options',
          getopt   => 'undo',
          ...
      },
      ...
  }
 
 The default contains: help (getopt C<help|h|?>), version (getopt C<version|v>),
 action (getopt C<action>), format (getopt C<format=s>), format_options (getopt
 C<format-options=s>), json). If there are more than one subcommands, this will
 also be added: list (getopt C<list|l>). If dry-run is supported by function,
 there will also be: dry_run (getopt C<dry-run>). If undo is turned on, there
 will also be: undo (getopt C<undo>), redo (getopt C<redo>), history (getopt
 C<history>), clear_history (getopt C<clear-history>).
 
 Sometimes you do not want some options, e.g. to remove C<format> and
 C<format_options>:
 
  delete $cmd->common_opts->{format};
  delete $cmd->common_opts->{format_options};
  $cmd->run;
 
 Sometimes you want to rename some command-line options, e.g. to change version
 to use capital C<-V> instead of C<-v>:
 
  $cmd->common_opts->{version}{getopt} = 'version|V';
 
 Sometimes you want to add subcommands as common options instead. For example:
 
  $cmd->common_opts->{halt} = {
      category    => 'Server options',
      getopt      => 'halt',
      summary     => 'Halt the server',
      handler     => sub {
          my ($go, $val, $r) = @_;
          $r->{subcommand_name} = 'shutdown';
      },
  };
 
 This will make:
 
  % cmd --halt
 
 equivalent to executing the 'shutdown' subcommand:
 
  % cmd shutdown
 
 =head2 completion => code
 
 Will be passed to L<Perinci::Sub::Complete>'s C<complete_cli_arg()>. See its
 documentation for more details.
 
 =head2 default_subcommand => str
 
 Set subcommand to this if user does not specify which to use (either via first
 command-line argument or C<--cmd> option). See also: C<get_subcommand_from_arg>.
 
 =head2 get_subcommand_from_arg => int (default: 1)
 
 The default is 1, which is to get subcommand from the first command-line
 argument except when there is C<default_subcommand> defined. Other valid values
 are: 0 (not getting from first command-line argument), 2 (get from first
 command-line argument even though there is C<default_subcommand> defined).
 
 =head2 description => str
 
 =head2 exit => bool (default: 1)
 
 =head2 formats => array
 
 Available output formats.
 
 =head2 pass_cmdline_object => bool (default: 0)
 
 Whether to pass special argument C<-cmdline> containing the cmdline object to
 function. This can be overriden using the C<pass_cmdline_object> on a
 per-subcommand basis.
 
 In addition to C<-cmdline>, C<-cmdline_r> will also be passed, containing the
 C<$r> per-request stash/hash (see L</"REQUEST KEYS">).
 
 Passing the cmdline object can be useful, e.g. to call action_help(), to get the
 settings of the Perinci::CmdLine, etc.
 
 =head2 program_name => str
 
 Default is from PERINCI_CMDLINE_PROGRAM_NAME environment or from $0.
 
 =head2 riap_client => obj
 
 Set to Riap client instance, should you want to create one yourself. Otherwise
 will be set L<Perinci::Access> (in PC:Classic), or L<Perinci::Access::Lite> (in
 PC:Lite).
 
 =head2 riap_version => float (default: 1.1)
 
 Specify L<Riap> protocol version to use. Will be passed to Riap client
 constructor (unless you already provide a Riap client object, see
 C<riap_client>).
 
 =head2 riap_client_args => hash
 
 Arguments to pass to Riap client constructor. Will be used unless you create
 your own Riap client object (see C<riap_client>). One of the things this
 attribute is used is to pass HTTP basic authentication to Riap client
 (L<Perinci::Access::HTTP::Client>):
 
  riap_client_args => {handler_args => {user=>$USER, password=>$PASS}}
 
 =head2 subcommands => hash | code
 
 Should be a hash of subcommand specifications or a coderef.
 
 Each subcommand specification is also a hash(ref) and should contain these keys:
 
 =over
 
 =item * C<url> (str, required)
 
 Location of function (accessed via Riap).
 
 =item * C<summary> (str, optional)
 
 Will be retrieved from function metadata at C<url> if unset
 
 =item * C<description> (str, optional)
 
 Shown in verbose help message, if description from function metadata is unset.
 
 =item * C<tags> (array of str, optional)
 
 For grouping or categorizing subcommands, e.g. when displaying list of
 subcommands.
 
 =item * C<log_any_app> (bool, optional)
 
 Whether to load Log::Any::App, default is true. For subcommands that need fast
 startup you can try turning this off for said subcommands. See L</"LOGGING"> for
 more details.
 
 =item * C<use_utf8> (bool, optional)
 
 Whether to issue L<< binmode(STDOUT, ":utf8") >>. See L</"LOGGING"> for more
 details.
 
 =item * C<undo> (bool, optional)
 
 Can be set to 0 to disable transaction for this subcommand; this is only
 relevant when C<undo> attribute is set to true.
 
 =item * C<show_in_help> (bool, optional, default 1)
 
 If you have lots of subcommands, and want to show only some of them in --help
 message, set this to 0 for subcommands that you do not want to show.
 
 =item * C<pass_cmdline_object> (bool, optional, default 0)
 
 To override C<pass_cmdline_object> attribute on a per-subcommand basis.
 
 =item * C<args> (hash, optional)
 
 If specified, will send the arguments (as well as arguments specified via the
 command-line). This can be useful for a function that serves more than one
 subcommand, e.g.:
 
  subcommands => {
      sub1 => {
          summary => 'Subcommand one',
          url     => '/some/func',
          args    => {flag=>'one'},
      },
      sub2 => {
          summary => 'Subcommand two',
          url     => '/some/func',
          args    => {flag=>'two'},
      },
  }
 
 In the example above, both subcommand C<sub1> and C<sub2> point to function at
 C</some/func>. But the function can differentiate between the two via the
 C<flag> argument being sent.
 
  % cmdprog sub1 --foo 1 --bar 2
  % cmdprog sub2 --foo 2
 
 In the first invocation, function will receive arguments C<< {foo=>1, bar=>2,
 flag=>'one'} >> and for the second: C<< {foo=>2, flag=>'two'} >>.
 
 =back
 
 Subcommands can also be a coderef, for dynamic list of subcommands. The coderef
 will be called as a method with hash arguments. It can be called in two cases.
 First, if called without argument C<name> (usually when doing --subcommands) it
 must return a hashref of subcommand specifications. If called with argument
 C<name> it must return subcommand specification for subcommand with the
 requested name only.
 
 =head2 summary => str
 
 =head2 tags => array of str
 
 =head2 url => str
 
 Required if you only want to run one function. URL should point to a function
 entity.
 
 Alternatively you can provide multiple functions from which the user can select
 using the first argument (see B<subcommands>).
 
 =head2 read_env => bool (default: 1)
 
 Whether to read environment variable for default options.
 
 =head2 env_name => str
 
 Environment name to read default options from. Default is from program name,
 upper-cased, sequences of dashes/nonalphanums replaced with a single underscore,
 plus a C<_OPT> suffix. So if your program name is called C<cpandb-cpanmeta> the
 default environment name is C<CPANDB_CPANMETA_OPT>.
 
 =head2 read_config => bool (default: 1)
 
 Whether to read configuration files.
 
 =head2 config_dirs => array of str
 
 Which directories to look for configuration file. The default is to look at the
 user's home and then system location. On Unix, it's C<< [ "$ENV{HOME}/.config",
 $ENV{HOME}, "/etc"] >>. If $ENV{HOME} is empty, getpwuid() is used to get home
 directory entry.
 
 =head2 config_filename => str
 
 Configuration filename. The default is C<< program_name . ".conf" >>. For
 example, if your program is named C<foo-bar>, config_filename will be
 C<foo-bar.conf>.
 
 =head2 skip_format => bool
 
 If set to 1, assume that function returns raw text that need not be translated,
 and so will not offer common command-line options C<--format>, C<--json>, as
 well as C<--naked-res>.
 
 As an alternative to this, can also be done on a per-function level by setting
 function metadata property C<cmdline.skip_format> to true. Or, can also be done
 on a per-function result basis by returning result metadata
 C<cmdline.skip_format> set to true.
 
 =head1 METHODS
 
 =head2 $cmd->run() => ENVRES
 
 The main method to run your application. See L</"PROGRAM FLOW"> for more details
 on what this method does.
 
 =head2 $cmd->do_completion() => ENVRES
 
 Called by run().
 
 =head2 $cmd->parse_argv() => ENVRES
 
 Called by run().
 
 =head2 $cmd->get_meta($r, $url) => ENVRES
 
 Called by parse_argv() or do_completion(). Subclass has to implement this.
 
 =head1 HOOKS
 
 All hooks will receive the argument C<$r>, a per-request hash/stash. The list
 below is by order of calling.
 
 =head2 $cmd->hook_before_run($r)
 
 Called at the start of C<run()>. Can be used to set some initial values of other
 C<$r> keys. Or setup the logger.
 
 =head2 $cmd->hook_before_read_config_file($r)
 
 Only called when C<read_config> attribute is true.
 
 =head2 $cmd->hook_after_read_config_file($r)
 
 Only called when C<read_config> attribute is true.
 
 =head2 $cmd->hook_after_get_meta($r)
 
 Called after the C<get_meta> method gets function metadata, which normally
 happens during parsing argument, because parsing function arguments require the
 metadata (list of arguments, etc).
 
 PC:Lite as well as PC:Classic use this hook to insert a common option
 C<--dry-run> if function metadata expresses that function supports dry-run mode.
 
 PC:Lite also checks the C<deps> property here. PC:Classic doesn't do this
 because it uses function wrapper (L<Perinci::Sub::Wrapper>) which does this.
 
 =head2 $cmd->hook_after_parse_argv($r)
 
 Called after C<run()> calls C<parse_argv()> and before it checks the result.
 C<$r->{parse_argv_res}> will contain the result of C<parse_argv()>. The hook
 gets a chance to, e.g. fill missing arguments from other source.
 
 Note that for sources specified in the C<cmdline_src> property, this base class
 will do the filling in after running this hook, so no need to do that here.
 
 PC:Lite uses this hook to give default values to function arguments C<<
 $r->{args} >> from the Rinci metadata. PC:Classic doesn't do this because it
 uses function wrapper (L<Perinci::Sub::Wrapper>) which will do this as well as
 some other stuffs (validate function arguments, etc).
 
 =head2 $cmd->hook_before_action($r)
 
 Called before calling the C<action_ACTION> method. Some ideas to do in this
 hook: modifying action to run (C<< $r->{action} >>), last check of arguments
 (C<< $r->{args} >>) before passing them to function.
 
 PC:Lite uses this hook to validate function arguments. PC:Classic does not do
 this because it uses function wrapper which already does this.
 
 =head2 $cmd->hook_after_action($r)
 
 Called after calling C<action_ACTION> method. Some ideas to do in this hook:
 preformatting result (C<< $r->{res} >>).
 
 =head2 $cmd->hook_format_result($r)
 
 The hook is supposed to format result in C<$res->{res}> (an array).
 
 All direct subclasses of PC:Base do the formatting here.
 
 =head2 $cmd->hook_display_result($r)
 
 The hook is supposed to display the formatted result (stored in C<$r->{fres}>)
 to STDOUT. But in the case of streaming output, this hook can also set it up.
 
 All direct subclasses of PC:Base do the formatting here.
 
 =head2 $cmd->hook_after_run($r)
 
 Called at the end of C<run()>, right before it exits (if C<exit> attribute is
 true) or returns C<$r->{res}>. The hook has a chance to modify exit code or
 result.
 
 =head1 SPECIAL ARGUMENTS
 
 Below is list of special arguments that may be passed to your function by the
 framework. Per L<Rinci> specification, these are prefixed by C<-> (dash).
 
 =head2 -dry_run => bool
 
 Only when in dry run mode, to notify function that we are in dry run mode.
 
 =head2 -cmdline => obj
 
 Only when C<pass_cmdline_object> attribute is set to true. This can be useful
 for the function to know about various stuffs, by probing the framework object.
 
 =head2 -cmdline_r => hash
 
 Only when C<pass_cmdline_object> attribute is set to true. Contains the C<$r>
 per-request hash/stash. This can be useful for the function to know about
 various stuffs, e.g. parsed configuration data, etc.
 
 =head2 -cmdline_src_ARGNAME => str
 
 This will be set if argument is retrieved from C<file>, C<stdin>,
 C<stdin_or_file>, C<stdin_or_files>, or C<stdin_line>.
 
 =head2 -cmdline_srcfilenames_ARGNAME => array
 
 An extra information if argument value is retrieved from file(s), so the
 function can know the filename(s).
 
 =head1 METADATA PROPERTY ATTRIBUTE
 
 This module observes the following Rinci metadata property attributes:
 
 =head2 cmdline.default_format => STR
 
 Set default output format (if user does not specify via --format command-line
 option).
 
 =head2 cmdline.skip_format => bool
 
 If you set it to 1, you specify that function's result never needs formatting
 (i.e. the function outputs raw text to be outputted directly), so no formatting
 will be done. See also: C<skip_format> attribute, C<cmdline.skip_format> result
 metadata attribute.
 
 =head1 RESULT METADATA
 
 This module interprets the following result metadata property/attribute:
 
 =head2 attribute: cmdline.exit_code => int
 
 Instruct to use this exit code, instead of using (function status - 300).
 
 =head2 attribute: cmdline.result => any
 
 Replace result. Can be useful for example in this case:
 
  sub is_palindrome {
      my %args = @_;
      my $str = $args{str};
      my $is_palindrome = $str eq reverse($str);
      [200, "OK", $is_palindrome,
       {"cmdline.result" => ($is_palindrome ? "Palindrome" : "Not palindrome")}];
  }
 
 When called as a normal function we return boolean value. But as a CLI, we
 display a more user-friendly message.
 
 =head2 attribute: cmdline.default_format => str
 
 Default format to use. Can be useful when you want to display the result using a
 certain format by default, but still allows user to override the default.
 
 =head2 attribute: cmdline.page_result => bool
 
 If you want to filter the result through pager (currently defaults to
 C<$ENV{PAGER}> or C<less -FRSX>), you can set C<cmdline.page_result> in result
 metadata to true.
 
 For example:
 
  $SPEC{doc} = { ... };
  sub doc {
      ...
      [200, "OK", $doc, {"cmdline.page_result"=>1}];
  }
 
 =head2 attribute: cmdline.pager => STR
 
 Instruct to use specified pager instead of C<$ENV{PAGER}> or the default C<less>
 or C<more>.
 
 =head2 attribute: cmdline.skip_format => bool (default: 0)
 
 When we want the command-line framework to just print the result without any
 formatting. See also: C<skip_format> attribute, C<cmdline.skip_format> function
 metadata attribute.
 
 =head2 attribute: x.perinci.cmdline.base.exit_code => int
 
 This is added by this module, so exit code can be tested.
 
 =head1 ENVIRONMENT
 
 =over
 
 =item * PAGER => str
 
 Like in other programs, can be set to select the pager program (when
 C<cmdline.page_result> result metadata is active). Can also be set to C<''> or
 C<0> to explicitly disable paging even though C<cmd.page_result> result metadata
 is active.
 
 =item * PERINCI_CMDLINE_PROGRAM_NAME => STR
 
 Can be used to set CLI program name.
 
 =back
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Perinci-CmdLine-Lite>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Perinci-CmdLine-Lite>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Perinci-CmdLine-Lite>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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
### Perinci/CmdLine/Classic.pm ###
 package Perinci::CmdLine::Classic;
 
 our $DATE = '2015-10-20'; # DATE
 our $VERSION = '1.60'; # VERSION
 
 use 5.010001;
 #use strict; # enabled by Moo
 #use warnings; # enabled by Moo
 use Log::Any::IfLOG '$log';
 
 use Moo;
 use experimental 'smartmatch'; # must be after Moo
 use Locale::TextDomain::UTF8 'Perinci-CmdLine-Classic';
 use Perinci::Object;
 use Scalar::Util qw(blessed);
 
 our $REQ_VERSION = 0; # version requested by user
 
 extends 'Perinci::CmdLine::Base';
 
 with 'Color::Theme::Role::ANSI' unless $ENV{COMP_LINE};
 with 'Perinci::CmdLine::Classic::Role::Help' unless $ENV{COMP_LINE};
 with 'Term::App::Role::Attrs' unless $ENV{COMP_LINE};
 
 has log => (is => 'rw', default=>sub{1});
 has undo => (is=>'rw', default=>sub{0});
 has undo_dir => (
     is => 'rw',
     lazy => 1,
     default => sub {
         require File::HomeDir;
 
         my $self = shift;
         my $dir = File::HomeDir->my_home . "/." . $self->program_name;
         mkdir $dir unless -d $dir;
         $dir .= "/.undo";
         mkdir $dir unless -d $dir;
         $dir;
     }
 );
 has riap_client => (
     is => 'rw',
     lazy => 1,
     default => sub {
         my $self = shift;
 
         require Perinci::Access;
         require Perinci::Access::Perl;
         require Perinci::Access::Schemeless;
         my %args = (
             riap_version => $self->riap_version,
             %{$self->riap_client_args // {}},
         );
         my %opts;
         if ($self->undo) {
             $opts{use_tx} = 1;
             $opts{custom_tx_manager} = sub {
                 my $pa = shift;
                 require Perinci::Tx::Manager;
                 state $txm = Perinci::Tx::Manager->new(
                     data_dir => $self->undo_dir,
                     pa => $pa,
                 );
                 $txm;
            };
         }
         $args{handlers} = {
             pl => Perinci::Access::Perl->new(%opts),
             '' => Perinci::Access::Schemeless->new(%opts),
         };
         #$log->tracef("Creating Perinci::Access object with args: %s", \%args);
         Perinci::Access->new(%args);
     }
 );
 has action_metadata => (
     is => 'rw',
     default => sub {
         +{
             clear_history => {
             },
             help => {
                 default_log => 0,
                 use_utf8 => 1,
             },
             history => {
             },
             subcommands => {
                 default_log => 0,
                 use_utf8 => 1,
             },
             redo => {
             },
             call => {
             },
             undo => {
             },
             version => {
                 default_log => 0,
                 use_utf8 => 1,
             },
         },
     },
 );
 has default_prompt_template => (is=>'rw');
 
 # OLD name for backward compat, will be removed later
 sub log_any_app { goto \&log }
 
 sub VERSION {
     my ($pkg, $req) = @_;
     $REQ_VERSION = $req;
 }
 
 sub BUILD {
     my ($self, $args) = @_;
 
     my $formats = [qw(
                          text text-simple text-pretty
                          json json-pretty yaml perl
                          ruby phpserialization)];
 
     if (!$self->{default_prompt_template}) {
         $self->{default_prompt_template} = N__("Enter %s:") . " ",
     }
 
     if (!$self->{actions}) {
         $self->{actions} = {
             version => {
                 default_log => 0,
                 use_utf8 => 1,
             },
             help => {
                 default_log => 0,
                 use_utf8 => 1,
             },
             subcommands => {
                 default_log => 0,
                 use_utf8 => 1,
             },
             call => {},
 
             history => {},
             clear_history => {},
             redo => {},
             undo => {},
         };
     }
 
     # translate summary & usage
     my $_t = sub {
         no warnings;
         my $co_name = shift;
         my $copt = $Perinci::CmdLine::Base::copts{$co_name};
         my %res;
         for (keys %$copt) {
             if ($_ eq 'summary' || $_ eq 'usage') {
                 $res{$_} = N__($copt->{$_});
             } else {
                 $res{$_} = $copt->{$_};
             }
         }
         %res;
     };
 
     if (!$self->{common_opts}) {
         my $copts = {};
 
         $copts->{version} = {
             $_t->('version'),
             show_in_options => sub { $ENV{VERBOSE} },
         };
         $copts->{help} = {
             $_t->('help'),
             show_in_options => sub { $ENV{VERBOSE} },
         };
 
         unless ($self->skip_format) {
             $copts->{format} = {
                 $_t->('format'),
                 schema => ['str*' => in => $formats],
             };
             $copts->{json} = {
                 $_t->('json'),
                 summary => N__("Equivalent to --format=json-pretty"),
             };
             $copts->{naked_res} = {
                 $_t->('naked_res'),
                 summary => N__("When outputing as JSON, strip result envelope"),
             };
             $copts->{format_options} = {
                 getopt  => "format-options=s",
                 summary => N__("Pass options to formatter"),
                 handler => sub {
                     my ($go, $val, $r) = @_;
                     $r->{format_options} = __json_decode($val);
                 },
                 is_settable_via_config => 1,
                 tags => ['category:output'],
             };
         }
 
         if ($self->subcommands) {
             $copts->{subcommands} = {
                 $_t->('subcommands'),
                 show_in_options => sub {
                     my ($self, $r) = @_;
                     $ENV{VERBOSE} && !$r->{subcommand_name};
                 },
                 show_in_help => 0,
             };
         }
 
         if (defined $self->default_subcommand) {
             $copts->{cmd} = { $_t->('cmd') };
         }
 
         if ($self->read_config) {
             $copts->{config_path}    = { $_t->('config_path') };
             $copts->{no_config}      = { $_t->('no_config') };
             $copts->{config_profile} = { $_t->('config_profile') };
         }
 
         if ($self->read_env) {
             $copts->{no_env} = { $_t->('no_env') };
         }
 
         if ($self->log) {
             $copts->{log_level} = { $_t->('log_level'), };
             $copts->{trace}     = { $_t->('trace'), };
             $copts->{debug}     = { $_t->('debug'), };
             $copts->{verbose}   = { $_t->('verbose'), };
             $copts->{quiet}     = { $_t->('quiet'), };
         }
 
         if ($self->undo) {
             $copts->{history} = {
                 getopt  => 'history',
                 summary => N__('List actions history'),
                 handler => sub {
                     my ($go, $val, $r) = @_;
                     $r->{action} = 'history';
                     $r->{skip_parse_subcommand_argv} = 1;
                 },
                 tags => ['category:undo'],
             };
             $copts->{clear_history} = {
                 getopt  => "clear-history",
                 summary => N__('Clear actions history'),
                 handler => sub {
                     my ($go, $val, $r) = @_;
                     $r->{action} = 'clear_history';
                     $r->{skip_parse_subcommand_argv} = 1;
                 },
                 tags => ['category:undo'],
             };
             $copts->{undo} = {
                 getopt  => 'undo',
                 summary => N__('Undo previous action'),
                 handler => sub {
                     my ($go, $val, $r) = @_;
                     $r->{action} = 'undo';
                     $r->{skip_parse_subcommand_argv} = 1;
                 },
                 tags => ['category:undo'],
             };
             $copts->{redo} = {
                 getopt  => 'redo',
                 summary => N__('Redo previous undone action'),
                 handler => sub {
                     my ($go, $val, $r) = @_;
                     $r->{action} = 'redo';
                     $r->{skip_parse_subcommand_argv} = 1;
                 },
             };
         }
         $self->{common_opts} = $copts;
     }
 
     $self->{formats} //= $formats;
     $self->{per_arg_json} //= 1;
     $self->{per_arg_yaml} //= 1;
 
     unless ($ENV{COMP_LINE}) {
         my $ct = $self->{color_theme} // $ENV{PERINCI_CMDLINE_COLOR_THEME};
         if (!$ct) {
             if ($self->use_color) {
                 my $bg = $self->detect_terminal->{default_bgcolor} // '';
                 $ct = 'Default::default' .
                     ($bg eq 'ffffff' ? '_whitebg' : '');
             } else {
                 $ct = 'Default::no_color';
             }
         }
         $self->color_theme($ct);
     }
 }
 
 sub __json_decode {
     require JSON;
     state $json = do { JSON->new->allow_nonref };
     $json->decode(shift);
 }
 
 sub __json_encode {
     require JSON;
     state $json = do { JSON->new->allow_nonref };
     $json->encode(shift);
 }
 
 sub _color {
     my ($self, $color_name, $text) = @_;
     my $color_code = $color_name ?
         $self->get_theme_color_as_ansi($color_name) : "";
     my $reset_code = $color_code ? "\e[0m" : "";
     "$color_code$text$reset_code";
 }
 
 #NOW UNUSED
 #sub err {
 #    my ($self, $msg) = @_;
 #    $msg .= "\n" unless $msg =~ /\n\z/;
 #    $self->_color('error_label', "ERROR: ") . $msg;
 #}
 
 # format array item as row
 sub hook_format_row {
     state $dfpc = do {
         require Data::Format::Pretty::Console;
         Data::Format::Pretty::Console->new({interactive=>0});
     };
 
     my ($self, $r, $row) = @_;
     my $ref = ref($row);
     # we catch common cases to be faster (avoid dfpc's structure identification)
     if (!$ref) {
         # simple scalar
         return ($row // "") . "\n";
     } elsif ($ref eq 'ARRAY' && !(grep {ref($_)} @$row)) {
         # an array of scalars
         return join("\t", map { $dfpc->_format_cell($_) } @$row) . "\n";
     } else {
         # otherwise, just feed it to dfpc
         return $dfpc->_format($row);
     }
 }
 
 sub hook_after_get_meta {
     my ($self, $r) = @_;
 
     if (risub($r->{meta})->can_dry_run) {
         $self->common_opts->{dry_run} = {
             getopt  => 'dry-run',
             summary => N__("Run in simulation mode (also via DRY_RUN=1)"),
             handler => sub {
                 my ($go, $val, $r) = @_;
                 $r->{dry_run} = 1;
                 $ENV{VERBOSE} = 1;
             },
         };
     }
 }
 
 my ($ph1, $ph2); # patch handles
 my $setup_progress;
 sub _setup_progress_output {
     my $self = shift;
 
     if ($ENV{PROGRESS} // (-t STDOUT)) {
         require Progress::Any::Output;
         my $out = Progress::Any::Output->set("TermProgressBarColor");
         $setup_progress = 1;
         # we need to patch the logger adapters so it won't interfere with
         # progress meter's output
         require Monkey::Patch::Action;
         $ph1 = Monkey::Patch::Action::patch_package(
             'Log::Log4perl::Appender::Screen', 'log',
             'replace', sub {
                 my ($self, %params) = @_;
 
                 my $msg = $params{message};
                 $msg =~ s/\n//g;
 
                 # clean currently displayed progress bar first
                 if ($out->{lastlen}) {
                     print
                         "\b" x $out->{lastlen},
                             " " x $out->{lastlen},
                                 "\b" x $out->{lastlen};
                     undef $out->{lastlen};
                 }
 
                 # force output update so progress bar is displayed again
                 # immediately
                 $Progress::Any::output_data{"$out"}{force_update} = 1;
 
                 say $msg;
             },
         ) if defined &{"Log::Log4perl::Appender::Screen::log"};
         $ph2 = Monkey::Patch::Action::patch_package(
             'Log::Log4perl::Appender::ScreenColoredLevels', 'log',
             'replace', sub {
                 my ($self, %params) = @_;
                 # BEGIN copy-paste'ish from ScreenColoredLevels.pm
                 my $msg = $params{message};
                 $msg =~ s/\n//g;
                 if (my $color=$self->{color}->{$params{log4p_level}}) {
                     $msg = Term::ANSIColor::colored($msg, $color);
                 }
                 # END copy-paste'ish
 
                 # clean currently displayed progress bar first
                 if ($out->{lastlen}) {
                     print
                         "\b" x $out->{lastlen},
                             " " x $out->{lastlen},
                                 "\b" x $out->{lastlen};
                     undef $out->{lastlen};
                 }
 
                 # force output update so progress bar is displayed again
                 # immediately
                 $Progress::Any::output_data{"$out"}{force_update} = 1;
 
                 # XXX duplicated code above, perhaps move this to
                 # TermProgressBarColor's clean_bar() or something
 
                 say $msg;
             }
         ) if defined &{"Log::Log4perl::Appender::ScreenColoredLevels::log"};
     }
 }
 
 sub _unsetup_progress_output {
     my $self = shift;
 
     return unless $setup_progress;
     my $out = $Progress::Any::outputs{''}[0];
     $out->cleanup if $out->can("cleanup");
     undef $ph1;
     undef $ph2;
     $setup_progress = 0;
 }
 
 sub _load_log_any_app {
     my ($self, $r) = @_;
     # Log::Any::App::init can already avoid being run twice, but we need to
     # check anyway to avoid logging starting message below twice.
     return if $r->{_log_any_app_loaded}++;
     require Log::Any::App;
     Log::Any::App::init();
 
     # we log this after we initialize Log::Any::App, since Log::Any::App might
     # not be loaded at all. yes, this means that this log message is printed
     # rather late and might not be the first message to be logged (see log
     # messages in run()) if user already loads Log::Any::App by herself.
     $log->debugf("Program %s started with arguments: %s",
                  $0, $r->{orig_argv});
 }
 
 # this hook is called at the start of run(), can be used to initialize stuffs
 sub hook_before_run {
     my ($self, $r) = @_;
 
     $log->tracef("Start of CLI run");
 
     # save, for showing in history, among others
     $r->{orig_argv} = [@ARGV];
 }
 
 sub hook_after_parse_argv {
     my ($self, $r) = @_;
 
     # We load Log::Any::App rather late here, so user can customize level via
     # --debug, --dry-run, etc.
     unless ($ENV{COMP_LINE}) {
         my $do_log = $r->{subcommand_data}{log} //
             $r->{subcommand_data}{log_any_app} # OLD compat, will be removed later
                 if $r->{subcommand_data};
         $do_log //= $ENV{LOG};
         $do_log //= $self->action_metadata->{$r->{action}}{default_log}
             if $self->{action};
         $do_log //= $self->log;
         $self->_load_log_any_app($r) if $do_log;
     }
 }
 
 sub hook_format_result {
     # save startup time under completion
     return if $ENV{COMP_LINE};
 
     my ($self, $r) = @_;
 
     my $res    = $r->{res};
     my $format = $r->{format} // 'text';
     my $meta   = $r->{meta};
 
     require Perinci::Result::Format;
 
     unless ($format ~~ @{ $self->formats }) {
         warn "Unknown output format '$format'";
         $format = 'text';
     }
 
     $res->[3]{format_options} = $r->{format_options} if $r->{format_options};
 
     my $fres;
     if ($res->[3]{is_stream}) {
         $log->tracef("Result is a stream");
         return undef;
     } elsif ($res->[3]{'x.hint.result_binary'} && $format =~ /text/) {
         $fres = $res->[2];
     } else {
         $log->tracef("Formatting output with %s", $format);
         $fres = Perinci::Result::Format::format($res, $format, $r->{naked_res});
     }
 
     # ux: prefix error message with program name
     if ($format=~/text/ && $r->{res}[0] =~ /\A[45]/ && defined($r->{res}[1])) {
         $fres = "$self->{program_name}: $fres";
     }
 
     $fres;
 }
 
 sub hook_display_result {
     my ($self, $r) = @_;
 
     my $res  = $r->{res};
     my $fres = $r->{fres};
     my $resmeta = $res->[3] // {};
 
     my $handle = $r->{output_handle};
 
     # determine whether to binmode(STDOUT,":utf8")
     my $utf8;
     {
         last if defined($utf8 = $ENV{UTF8});
         if ($resmeta->{'x.hint.result_binary'}) {
             # XXX only when format is text?
             $utf8 = 0; last;
         }
         my $am = $self->action_metadata->{$r->{action}}
             if $r->{action};
         last if defined($utf8 //= $am->{use_utf8});
 
         if ($r->{subcommand_data}) {
             last if defined($utf8 //= $r->{subcommand_data}{use_utf8});
         }
 
         $utf8 //= $self->use_utf8
             if $self->can("use_utf8");
     }
     binmode(STDOUT, ":utf8") if $utf8;
 
     if ($ENV{COMP_LINE} || $res->[3]{"cmdline.skip_format"}) {
         print $handle $res->[2];
         return;
     }
 
     $self->display_result($r);
 }
 
 sub hook_after_run {
     my ($self, $r) = @_;
     $self->_unsetup_progress_output;
 }
 
 sub action_subcommands {
     my ($self, $r) = @_;
 
     if (!$self->subcommands) {
         return [200, "OK", __("There are no subcommands") . ".",
                 {"cmdline.skip_format"=>1}];
     }
 
     $r->{_help_buf} = '';
 
     my $subcommands = $self->list_subcommands;
 
     # XXX get summary from Riap if not exist, but this results in multiple Riap
     # requests.
 
     my %percat_subc; # (cat1 => {subcmd1=>..., ...}, ...)
     while (my ($scn, $sc) = each %$subcommands) {
         my $cat = "";
         for my $tag (@{$sc->{tags} // []}) {
             my $tn = ref($tag) ? $tag->{name} : $tag;
             next unless $tn =~ /^category:(.+)/;
             $cat = $1;
             last;
         }
         $percat_subc{$cat}       //= {};
         $percat_subc{$cat}{$scn}   = $sc;
     }
     my $has_many_cats = scalar(keys %percat_subc) > 1;
 
     my $i = 0;
     for my $cat (sort keys %percat_subc) {
         if ($has_many_cats) {
             $self->_help_add_heading(
                 $r,
                 __x("{category} subcommands",
                     category => ucfirst($cat || __("main"))));
         }
         my $subc = $percat_subc{$cat};
         for my $scn (sort keys %$subc) {
             my $sc = $subc->{$scn};
             my $summary = rimeta($sc)->langprop("summary");
             $self->_help_add_row(
                 $r,
                 [$self->_color('program_name', $scn), $summary],
                 {column_widths=>[-17, -40], indent=>1});
         }
     }
     $self->_help_draw_curtbl($r);
 
     [200, "OK", $r->{_help_buf},
      {"cmdline.skip_format"=>1}];
 }
 
 sub action_version {
     no strict 'refs';
 
     my ($self, $r) = @_;
 
     my $url = $r->{subcommand_data}{url} // $self->url;
 
     my @text;
 
     {
         my $meta = $self->get_meta($r, $url);
         push @text, __x(
             "{program} version {version}",
             program => $self->_color('program_name',
                                      $self->get_program_and_subcommand_name),
             version => $self->_color('emphasis', ($meta->{entity_v} // "?")),
         ),
             ($meta->{entity_date} ? " ($meta->{entity_date})" : ""),
             "\n";
         for my $mod (@{ $meta->{'x.dynamic_generator_modules'} // [] }) {
             push @text, "  ", __x(
                 "{program} version {version}",
                 program => $self->_color('emphasis', $mod),
                 version => $self->_color('emphasis', (${"$mod\::VERSION"} // "?")),
             ),
                 (${"$mod\::DATE"} ? " (".${"$mod\::DATE"}.")" : ""),
                     "\n";
         }
     }
 
     for my $url (@{ $self->extra_urls_for_version // [] }) {
         my $meta = $self->get_meta($r, $url);
         push @text, "  ", __x(
             "{program} version {version}",
             program => $self->_color('emphasis', $url),
             version => $self->_color('emphasis', ($meta->{entity_v} // "?")),
         ),
             ($meta->{entity_date} ? " ($meta->{entity_date})" : ''),
             "\n";
     }
 
     push @text, "  ", __x(
         "{program} version {version}",
         program => $self->_color('emphasis', "Perinci::CmdLine::Classic"),
         version => $self->_color('emphasis',
                                  $Perinci::CmdLine::Classic::VERSION || "dev"),
     ),
         ($Perinci::CmdLine::Classic::DATE ? " ($Perinci::CmdLine::Classic::DATE)" : ""),
         "\n";
 
     [200, "OK", join("", @text), {"cmdline.skip_format"=>1}];
 }
 
 sub action_call {
     my ($self, $r) = @_;
 
     my $scn = $r->{subcommand_name};
     my $scd = $r->{subcommand_data};
 
     my %fargs = %{$r->{args} // {}};
 
     my $tx_id;
 
     my $dry_run = $r->{dry_run};
     my $using_tx = !$dry_run && $self->undo && ($scd->{undo} // 1);
 
     # currently we don't attempt to insert tx_id or dry_run when using argv,
     # we'll just give up
     if ($r->{send_argv} && ($dry_run || $using_tx)) {
         return $r->{parse_argv_res};
     }
 
     if ($using_tx) {
         require UUID::Random;
         $tx_id = UUID::Random::generate();
         $tx_id =~ s/-.+//; # 32bit suffices for small number of txs
         my $summary = join(" ", @{ $r->{orig_argv} });
         my $tres = $self->riap_client->request(
             begin_tx => "/", {tx_id=>$tx_id, summary=>$summary});
         if ($tres->[0] != 200) {
             return [$tres->[0], "Can't start transaction '$tx_id': $tres->[1]"];
         }
     }
 
     # setup output progress indicator
     if ($r->{meta}{features}{progress}) {
         $self->_setup_progress_output;
     }
 
     # call function
     my $res;
     if ($r->{send_argv}) {
         $res = $self->riap_client->request(
             call => $scd->{url},
             {argv=>$r->{orig_argv}}, # XXX tx_id, dry_run (see above)
         );
     } else {
         #$log->tracef("Calling function via _pa with arguments: %s", \%fargs);
         $res = $self->riap_client->request(
             call => $scd->{url},
             {args=>\%fargs, tx_id=>$tx_id, dry_run=>$dry_run});
     }
     $log->tracef("call res=%s", $res);
 
     # commit transaction (if using tx)
     if ($using_tx && $res->[0] =~ /\A(?:200|304)\z/) {
         my $tres = $self->riap_client->request(commit_tx => "/", {tx_id=>$tx_id});
         if ($tres->[0] != 200) {
             return [$tres->[0],"Can't commit transaction '$tx_id': $tres->[1]"];
         }
     }
 
     $res;
 }
 
 sub action_history {
     my ($self, $r) = @_;
     my $res = $self->riap_client->request(list_txs => "/", {detail=>1});
     $log->tracef("list_txs res=%s", $res);
     return $res unless $res->[0] == 200;
     $res->[2] = [sort {($b->{tx_commit_time}//0) <=> ($a->{tx_commit_time}//0)}
                      @{$res->[2]}];
     my @txs;
     for my $tx (@{$res->[2]}) {
         next unless $tx->{tx_status} =~ /[CUX]/;
         push @txs, {
             id          => $tx->{tx_id},
             start_time  => $tx->{tx_start_time},
             commit_time => $tx->{tx_commit_time},
             status      => $tx->{tx_status} eq 'X' ? 'error' :
                 $tx->{tx_status} eq 'U' ? 'undone' : '',
             summary     => $tx->{tx_summary},
         };
     }
     [200, "OK", \@txs];
 }
 
 sub action_clear_history {
     my ($self, $r) = @_;
     $self->riap_client->request(discard_all_txs => "/");
 }
 
 sub action_undo {
     my ($self, $r) = @_;
     $self->riap_client->request(undo => "/");
 }
 
 sub action_redo {
     my ($self, $r) = @_;
     $self->riap_client->request(redo => "/");
 }
 
 1;
 # ABSTRACT: Rinci/Riap-based command-line application framework
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Perinci::CmdLine::Classic - Rinci/Riap-based command-line application framework
 
 =head1 VERSION
 
 This document describes version 1.60 of Perinci::CmdLine::Classic (from Perl distribution Perinci-CmdLine-Classic), released on 2015-10-20.
 
 =head1 SYNOPSIS
 
 In C<gen-random-num> script:
 
  use Perinci::CmdLine::Classic;
 
  our %SPEC;
 
  $SPEC{gen_random_num} = {
      v => 1.1,
      summary => 'Generate some random numbers',
      args => {
          count => {
              summary => 'How many numbers to generate',
              schema => ['int*' => min=>0],
              default => 1,
              cmdline_aliases=>{n=>{}},
              req => 1,
              pos => 0,
          },
          min => {
              summary => 'Lower limit of random number',
              schema => 'float*',
              default => 0,
          },
          max => {
              summary => 'Upper limit of random number',
              schema => 'float*',
              default => 1,
          },
      },
      result_naked => 1,
  };
  sub gen_random_num {
      my %args = @_;
 
      my @res;
      for (1..$args{count}) {
          push @res, $args{min} + rand()*($args{max}-$args{min});
      }
      \@res;
  }
 
  Perinci::CmdLine::Classic->new(url => '/main/gen_random_num')->run;
 
 Run your script:
 
  % ./gen-random-num
  0.999473691060306
 
  % ./gen-random-num --min 1 --max 10 5
  1.27390166158969
  1.69077475473679
  8.97748327778684
  5.86943773494068
  8.34341298182493
 
 JSON output support out of the box:
 
  % ./gen-random-num -n3 --json
  [200,"OK (envelope added by Perinci::Access::Lite)",[0.257073684902029,0.393782991540746,0.848740540017513],{}]
 
 Automatic help message:
 
  % ./gen-random-num -h
  gen-random-num - Generate some random numbers
 
  Usage:
    gen-random-num --help (or -h, -?)
    gen-random-num --version (or -v)
    gen-random-num [options] [count]
  Options:
    --config-path=s     Set path to configuration file
    --config-profile=s  Set configuration profile to use
    --count=i, -n       How many numbers to generate (=arg[0]) [1]
    --format=s          Choose output format, e.g. json, text [undef]
    --help, -h, -?      Display this help message
    --json              Set output format to json
    --max=f             Upper limit of random number [1]
    --min=f             Lower limit of random number [0]
    --naked-res         When outputing as JSON, strip result envelope [0]
    --no-config         Do not use any configuration file
    --version, -v
 
 Automatic configuration file support:
 
  % cat ~/gen-random-num.conf
  count=5
  max=0.01
 
  % ./gen-random-num
  0.00105268954838724
  0.00701443611501844
  0.0021247476506154
  0.00813872824513005
  0.00752832346491306
 
 Automatic tab completion support:
 
  % complete -C gen-random-num gen-random-num
  % gen-random-num --mi<tab>
 
 See L<Perinci::CmdLine::Manual> for details on other available features
 (subcommands, automatic formatting of data structures, automatic schema
 validation, dry-run mode, automatic POD generation, remote function support,
 automatic CLI generation, automatic --version, automatic HTTP API,
 undo/transactions, configurable output format, logging, progress bar,
 colors/Unicode, and more).
 
 =head1 DESCRIPTION
 
 Perinci::CmdLine is a command-line application framework. It allows you to
 create full-featured CLI applications easily and quickly.
 
 See L<Perinci::CmdLine::Manual> for more details.
 
 There is also a blog post series on Perinci::CmdLine tutorial:
 L<https://perlancar.wordpress.com/category/pericmd-tut/>
 
 Perinci::CmdLine::Classic is the heavier backend implementation which supports
 some extra features currently not supported by the default backend
 implementation L<Perinci::CmdLine::Lite>. These features come at some startup
 overhead cost and more dependencies. You normally should use
 L<Perinci::CmdLine::Any> instead to be able to switch backend on the fly.
 
 Screenshots:
 
 =for Pod::Coverage ^(.+)$
 
 =begin HTML
 
 <p><img src="http://blogs.perl.org/users/perlancar/screenshot-pericmd-help.jpg" /><br />Autogenerated help message
 
 <p><img src="http://blogs.perl.org/users/perlancar/screenshot-pericmd-help_verbose.jpg" /><br />Autogenerated help message (verbose mode)
 
 <p><img src="http://blogs.perl.org/users/perlancar/progany-tpc.jpg" /><br />Progress bar
 
 <p><img src="http://blogs.perl.org/users/perlancar/screenshot-pericmd-completion.jpg" /><br />Tab completion
 
 <p><img src="http://blogs.perl.org/users/perlancar/screenshot-pericmd-format.jpg" /><br />Some output formats
 
 <p><img src="http://blogs.perl.org/users/perlancar/screenshot-trashu.jpg" /><br />Undo/redo
 
 =end HTML
 
 =head1 REQUEST KEYS
 
 See also L<Perinci::CmdLine::Base>. Extra stuffs put by this module to the C<$r>
 hash/stash.
 
 =over
 
 =item * format_options => hash
 
 =back
 
 =head1 ATTRIBUTES
 
 All the attributes of L<Perinci::CmdLine::Base>, plus:
 
 =head2 log => BOOL (default: 1)
 
 Whether to load L<Log::Any::App> (enable logging output) by default. See
 L</"LOGGING"> for more details.
 
 =head2 use_utf8 => BOOL
 
 From L<Term::App::Role::Attrs> (please see its docs for more details). There are
 several other attributes added by the role.
 
 =head2 undo => BOOL (optional, default 0)
 
 Whether to enable undo/redo functionality. Some things to note if you intend to
 use undo:
 
 =over
 
 =item * These common command-line options will be recognized
 
 C<--undo>, C<--redo>, C<--history>, C<--clear-history>.
 
 =item * Transactions will be used
 
 C<< use_tx=>1 >> will be passed to L<Perinci::Access>, which will cause it to
 initialize the transaction manager. Riap requests begin_tx and commit_tx will
 enclose the call request to function.
 
 =item * Called function will need to support transaction and undo
 
 Function which does not meet qualifications will refuse to be called.
 
 Exception is when subcommand is specified with C<< undo=>0 >>, where transaction
 will not be used for that subcommand. For an example of disabling transaction
 for some subcommands, see C<bin/u-trash> in the distribution.
 
 =back
 
 =head2 undo_dir => STR (optional, default ~/.<program_name>/.undo)
 
 Where to put undo data. This is actually the transaction manager's data dir.
 
 =head1 METHODS
 
 All the methods of L<Perinci::CmdLine::Base>, plus:
 
 =over
 
 =back
 
 =head1 RESULT METADATA
 
 All those supported by L<Perinci::CmdLine::Base>, plus:
 
 =head2 x.hint.result_binary => bool
 
 If set to true, then when formatting to C<text> formats, this class won't print
 any newline to keep the data being printed unmodified.
 
 =head1 ENVIRONMENT
 
 All the environment variables that L<Perinci::CmdLine::Base> supports, plus:
 
 =head2 PERINCI_CMDLINE_COLOR_THEME => STR
 
 Can be used to set C<color_theme>.
 
 =head2 PROGRESS => BOOL
 
 Explicitly turn the progress bar on/off.
 
 =head2 COLOR => INT
 
 Please see L<Term::App::Role::Attrs>.
 
 =head2 UTF8 => BOOL
 
 Please see L<Term::App::Role::Attrs>.
 
 =head1 SEE ALSO
 
 L<Perinci::CmdLine::Any>, L<Perinci::CmdLine::Lite>.
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Perinci-CmdLine-Classic>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Perinci-CmdLine-Classic>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Perinci-CmdLine-Classic>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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
### Perinci/CmdLine/Classic/ColorTheme/Default.pm ###
 package Perinci::CmdLine::Classic::ColorTheme::Default;
 
 our $DATE = '2015-10-20'; # DATE
 our $VERSION = '1.60'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 
 our %color_themes = (
 
     no_color => {
         v => 1.1,
         summary => 'Special theme that means no color',
         colors => {
         },
         no_color => 1,
     },
 
     default => {
         v => 1.1,
         summary => 'Default (for terminals with black background)',
         colors => {
             heading       => 'ff9933',
             text          => undef,
             error_label   => 'cc0000',
             warning_label => 'cccc00',
             program_name  => {ansi_fg=>"\e[1m"}, # bold
             option_name   => 'cc6633',
             emphasis      => {ansi_fg=>"\e[1m"}, # bold
             #option_value  => undef,
             #argument      => undef,
         },
     },
 
     default_whitebg => {
         v => 1.1,
         summary => 'Default (for terminals with white background)',
         colors => {
         },
     },
 
 );
 
 1;
 # ABSTRACT: Default color themes
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Perinci::CmdLine::Classic::ColorTheme::Default - Default color themes
 
 =head1 VERSION
 
 This document describes version 1.60 of Perinci::CmdLine::Classic::ColorTheme::Default (from Perl distribution Perinci-CmdLine-Classic), released on 2015-10-20.
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Perinci-CmdLine-Classic>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Perinci-CmdLine-Classic>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Perinci-CmdLine-Classic>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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
### Perinci/CmdLine/Classic/Role/Help.pm ###
 package Perinci::CmdLine::Classic::Role::Help;
 
 our $DATE = '2015-10-20'; # DATE
 our $VERSION = '1.60'; # VERSION
 
 # split here just so it's more organized
 
 use 5.010;
 use Moo::Role;
 
 use Locale::TextDomain::UTF8 'Perinci-CmdLine';
 use Perinci::Object;
 
 sub _help_draw_curtbl {
     my ($self, $r) = @_;
 
     if ($r->{_help_curtbl}) {
         $r->{_help_buf} .= $r->{_help_curtbl}->draw;
         undef $r->{_help_curtbl};
     }
 }
 
 # ansitables are used to draw formatted help. they are 100% wide, with no
 # borders (except space), but you can customize the number of columns (which
 # will be divided equally)
 sub _help_add_table {
     require Text::ANSITable;
 
     my ($self, $r, %args) = @_;
     my $columns = $args{columns} // 1;
 
     $self->_help_draw_curtbl($r);
     my $t = Text::ANSITable->new;
     $t->border_style('Default::spacei_ascii');
     $t->cell_pad(0);
     if ($args{column_widths}) {
         for (0..$columns-1) {
             $t->set_column_style($_, width => $args{column_widths}[$_]);
         }
     } else {
         my $tw = $self->term_width;
         my $cw = int($tw/$columns)-1;
         $t->cell_width($cw);
     }
     $t->show_header(0);
     $t->column_wrap(0); # we'll do our own wrapping, before indent
     $t->columns([0..$columns-1]);
 
     $r->{_help_curtbl} = $t;
 }
 
 sub _help_add_row {
     my ($self, $r, $row, $args) = @_;
     $args //= {};
     my $wrap    = $args->{wrap}   // 0;
     my $indent  = $args->{indent} // 0;
     my $columns = @$row;
 
     # start a new table if necessary
     $self->_help_add_table(
         $r,
         columns=>$columns, column_widths=>$args->{column_widths})
         if !$r->{_help_curtbl} ||
             $columns != @{ $r->{_help_curtbl}{columns} };
 
     my $t = $r->{_help_curtbl};
     my $rownum = @{ $t->{rows} };
 
     $t->add_row($row);
 
     my $dux_available = eval { require Data::Unixish; 1 } && !$@;
 
     if ($dux_available) {
         for (0..@{$t->{columns}}-1) {
             my %styles = (formats=>[]);
             push @{ $styles{formats} },
                 [wrap=>{ansi=>1, mb=>1, width=>$t->{cell_width}-$indent*2}]
                 if $wrap;
             push @{ $styles{formats} }, [lins=>{text=>"  " x $indent}]
                 if $indent && $_ == 0;
             $t->set_cell_style($rownum, $_, \%styles);
         }
     }
 }
 
 sub _help_add_heading {
     my ($self, $r, $heading) = @_;
     $self->_help_add_row($r, [$self->_color('heading', $heading)]);
 }
 
 sub _color {
     my ($self, $color_name, $text) = @_;
     my $color_code = $color_name ?
         $self->get_theme_color_as_ansi($color_name) : "";
     my $reset_code = $color_code ? "\e[0m" : "";
     "$color_code$text$reset_code";
 }
 
 sub help_section_summary {
     my ($self, $r) = @_;
 
     my $summary = rimeta($r->{_help_meta})->langprop("summary");
     return unless $summary;
 
     my $name = $self->get_program_and_subcommand_name($r);
     my $ct = join(
         "",
         $self->_color('program_name', $name),
         ($name && $summary ? ' - ' : ''),
         $summary // "",
     );
     $self->_help_add_row($r, [$ct], {wrap=>1});
 }
 
 sub help_section_usage {
     my ($self, $r) = @_;
 
     my $co = $self->common_opts;
     my @con = grep {
         my $cov = $co->{$_};
         my $show = $cov->{show_in_usage} // 1;
         for ($show) { if (ref($_) eq 'CODE') { $_ = $_->($self, $r) } }
         $show;
     } sort {
         ($co->{$a}{order}//1) <=> ($co->{$b}{order}//1) || $a cmp $b
     } keys %$co;
 
     my $pn = $self->_color(
         'program_name', $self->get_program_and_subcommand_name($r));
     my $ct = "";
     for my $con (@con) {
         my $cov = $co->{$con};
         next unless $cov->{usage};
         $ct .= ($ct ? "\n" : "") . $pn . " " . __($cov->{usage});
     }
     if ($self->subcommands && !$r->{subcommand_name}) {
         if (defined $self->default_subcommand) {
             $ct .= ($ct ? "\n" : "") . $pn .
                 " " . __("--cmd=<other-subcommand> [options]");
         } else {
             $ct .= ($ct ? "\n" : "") . $pn .
                 " " . __("<subcommand> [options]");
         }
     } else {
         my $usage = $r->{_help_clidocdata}{usage_line};
         $usage =~ s/\[\[prog\]\]/$pn/;
         $usage =~ s/\[options\]/__("[options]")/e;
         $ct .= ($ct ? "\n" : "") . $usage;
     }
     $self->_help_add_heading($r, __("Usage"));
     $self->_help_add_row($r, [$ct], {indent=>1});
 }
 
 sub help_section_options {
     my ($self, $r) = @_;
 
     my $opts = $r->{_help_clidocdata}{opts};
     return unless keys %$opts;
 
     my $verbose = $r->{_help_verbose};
     my $info = $r->{_help_info};
     my $meta = $r->{_help_meta};
     my $args_p = $meta->{args};
     my $sc = $self->subcommands;
 
     # group options by raw category, e.g. $cats{""} (for options
     # without category and common options) or $cat{"cat1"}.
     my %cats; # val = [ospec, ...]
 
     for (keys %$opts) {
         push @{ $cats{$opts->{$_}{raw_category} // ''} }, $_;
     }
 
     for my $cat (sort keys %cats) {
         # find the longest option
         my @opts = sort {length($b)<=>length($a)} @{ $cats{$cat} };
         my $len = length($opts[0]);
         # sort again by name
         @opts = sort {
             (my $a_without_dash = $a) =~ s/^-+//;
             (my $b_without_dash = $b) =~ s/^-+//;
             lc($a) cmp lc($b);
         } @opts;
 
         my $cat_title;
         if ($cat eq '') {
             $cat_title = __("Options");
         } else {
             $cat_title = __x("{category} options", category=>ucfirst($cat));
         }
         $self->_help_add_heading($r, $cat_title);
 
         if ($verbose) {
             for my $opt_name (@opts) {
                 my $opt_spec = $opts->{$opt_name};
                 my $arg_spec = $opt_spec->{arg_spec};
                 my $ct = $self->_color('option_name', $opt_name);
                 # BEGIN DUPE1
                 if ($arg_spec && !$opt_spec->{main_opt} &&
                         defined($arg_spec->{pos})) {
                     if ($arg_spec->{greedy}) {
                         $ct .= " (=arg[$arg_spec->{pos}-])";
                     } else {
                         $ct .= " (=arg[$arg_spec->{pos}])";
                     }
                 }
                 if ($arg_spec && !$opt_spec->{main_opt} &&
                         defined($arg_spec->{cmdline_src})) {
                     $ct .= " (or from $arg_spec->{cmdline_src})";
                     $ct =~ s!_or_!/!;
                 }
                 # END DUPE1
                 $self->_help_add_row($r, [$ct], {indent=>1});
 
                 if ($opt_spec->{summary} || $opt_spec->{description}) {
                     my $ct = "";
                     $ct .= ($ct ? "\n\n":"")."$opt_spec->{summary}."
                         if $opt_spec->{summary};
                     $ct .= ($ct ? "\n\n":"").$opt_spec->{description}
                         if $opt_spec->{description};
                     $self->_help_add_row($r, [$ct], {indent=>2, wrap=>1});
                 }
             }
         } else {
             # for compactness, display in columns
             my $tw = $self->term_width;
             my $columns = int($tw/40); $columns = 1 if $columns < 1;
             while (1) {
                 my @row;
                 for (1..$columns) {
                     last unless @opts;
                     my $opt_name = shift @opts;
                     my $opt_spec = $opts->{$opt_name};
                     my $arg_spec = $opt_spec->{arg_spec};
                     my $ct = $self->_color('option_name', $opt_name);
                     # BEGIN DUPE1
                     if ($arg_spec && !$opt_spec->{main_opt} &&
                             defined($arg_spec->{pos})) {
                         if ($arg_spec->{greedy}) {
                             $ct .= " (=arg[$arg_spec->{pos}-])";
                         } else {
                             $ct .= " (=arg[$arg_spec->{pos}])";
                         }
                     }
                     if ($arg_spec && !$opt_spec->{main_opt} &&
                             defined($arg_spec->{cmdline_src})) {
                         $ct .= " (or from $arg_spec->{cmdline_src})";
                         $ct =~ s!_or_!/!;
                     }
                     # END DUPE1
                     push @row, $ct;
                 }
                 last unless @row;
                 for (@row+1 .. $columns) { push @row, "" }
                 $self->_help_add_row($r, \@row, {indent=>1});
             }
         }
     }
 }
 
 sub help_section_subcommands {
     my ($self, $r) = @_;
 
     my $verbose = $r->{_help_verbose};
     return unless $self->subcommands && !$r->{subcommand_name};
     my $scs = $self->list_subcommands;
 
     my @scs = sort keys %$scs;
     my @shown_scs;
     for my $scn (@scs) {
         my $sc = $scs->{$scn};
         next unless $sc->{show_in_help} // 1;
         $sc->{name} = $scn;
         push @shown_scs, $sc;
     }
 
     # for help_section_hints
     my $some_not_shown = @scs > @shown_scs;
     $r->{_help_hide_some_subcommands} = 1 if $some_not_shown;
 
     $self->_help_add_heading(
         $r, $some_not_shown ? __("Popular subcommands") : __("Subcommands"));
 
     # in compact mode, we try to not exceed one screen, so show long mode only
     # if there are a few subcommands.
     my $long_mode = $verbose || @shown_scs < 12;
     if ($long_mode) {
         for (@shown_scs) {
             my $summary = rimeta($_)->langprop("summary");
             $self->_help_add_row(
                 $r,
                 [$self->_color('program_name', $_->{name}), $summary],
                 {column_widths=>[-17, -40], indent=>1});
         }
     } else {
         # for compactness, display in columns
         my $tw = $self->term_width;
         my $columns = int($tw/25); $columns = 1 if $columns < 1;
             while (1) {
                 my @row;
                 for (1..$columns) {
                     last unless @shown_scs;
                     my $sc = shift @shown_scs;
                     push @row, $sc->{name};
                 }
                 last unless @row;
                 for (@row+1 .. $columns) { push @row, "" }
                 $self->_help_add_row($r, \@row, {indent=>1});
             }
 
     }
 }
 
 sub help_section_hints {
     my ($self, $r) = @_;
 
     my $verbose = $r->{_help_verbose};
     my @hints;
     unless ($verbose) {
         push @hints, N__("For more complete help, use '--help --verbose'");
     }
     if ($r->{_help_hide_some_subcommands}) {
         push @hints,
             N__("To see all available subcommands, use '--subcommands'");
     }
     return unless @hints;
 
     $self->_help_add_row(
         $r, [join(" ", map { __($_)."." } @hints)], {wrap=>1});
 }
 
 sub help_section_description {
     my ($self, $r) = @_;
 
     my $desc = rimeta($r->{_help_meta})->langprop("description") //
         $self->description;
     return unless $desc;
 
     $self->_help_add_heading($r, __("Description"));
     $self->_help_add_row($r, [$desc], {wrap=>1, indent=>1});
 }
 
 sub help_section_examples {
     my ($self, $r) = @_;
 
     my $verbose = $r->{_help_verbose};
     my $meta = $r->{_help_meta};
     my $egs = $r->{_help_clidocdata}{examples};
     return unless $egs && @$egs;
 
     $self->_help_add_heading($r, __("Examples"));
     my $pn = $self->_color(
         'program_name', $self->get_program_and_subcommand_name($r));
     for my $eg (@$egs) {
         my $cmdline = $eg->{cmdline};
         $cmdline =~ s/\[\[prog\]\]/$pn/;
         $self->_help_add_row($r, ["% $cmdline"], {indent=>1});
         if ($verbose) {
             my $ct = "";
             if ($eg->{summary}) { $ct .= "$eg->{summary}." }
             if ($eg->{description}) { $ct .= "\n\n$eg->{description}" }
             $self->_help_add_row($r, [$ct], {indent=>2}) if $ct;
         }
     }
 }
 
 sub help_section_result {
     my ($self, $r) = @_;
 
     my $meta   = $r->{_help_meta};
     my $rmeta  = $meta->{result};
     my $rmetao = rimeta($rmeta);
     my $text;
 
     my $summary = $rmetao->langprop('summary') // '';
     my $desc    = $rmetao->langprop('description') // '';
     $text = $summary . ($summary ? "\n\n" : "") . $desc;
 
     # collect handler
     my %handlers;
     for my $k0 (keys %$rmeta) {
         my $v = $rmeta->{$k0};
 
         my $k = $k0; $k =~ s/\..+//;
         next if $k =~ /\A_/;
 
         # check builtin result spec key
         next if $k =~ /\A(
                            summary|description|tags|default_lang|
                            schema|
                            x
                        )\z/x;
 
         # try a property module first
         require "Perinci/Sub/Property/result/$k.pm";
         my $meth = "help_hookmeta_result__$k";
         unless ($self->can($meth)) {
             die "No help handler for property result/$k0 ($meth)";
         }
         my $hmeta = $self->$meth;
         $handlers{$k} = {
             prio => $hmeta->{prio},
             meth => "help_hook_result__$k",
         };
     }
 
     # call all the handlers in order
     for my $k (sort {$handlers{$a}{prio} <=> $handlers{$b}{prio}}
                    keys %handlers) {
         my $h = $handlers{$k};
         my $meth = $h->{meth};
         my $t = $self->$meth($r);
         $text .= $t if $t;
     }
 
     return unless length $text;
 
     $self->_help_add_heading($r, __("Result"));
     $self->_help_add_row($r, [$text], {wrap=>1, indent=>1});
 }
 
 sub help_section_links {
     # not yet
 }
 
 sub action_help {
     my ($self, $r) = @_;
 
     $r->{_help_buf} = '';
 
     my $verbose = $ENV{VERBOSE} // 0;
     local $r->{_help_verbose} = $verbose;
 
     # get function metadata first
     unless ($r->{_help_meta}) {
         my $url = $r->{subcommand_data}{url} // $self->url;
         my $res = $self->riap_client->request(info => $url);
         die [500, "Can't info '$url': $res->[0] - $res->[1]"]
             unless $res->[0] == 200;
         $r->{_help_info} = $res->[2];
         $res = $self->riap_client->request(meta => $url);
         die [500, "Can't meta '$url': $res->[0] - $res->[1]"]
             unless $res->[0] == 200;
         $r->{_help_meta} = $res->[2]; # cache here
     }
 
     # get cli opt spec
     unless ($r->{_help_clidocdata}) {
         require Perinci::Sub::To::CLIDocData;
         my $res = Perinci::Sub::To::CLIDocData::gen_cli_doc_data_from_meta(
             meta => $r->{_help_meta}, meta_is_normalized => 1,
             common_opts  => $self->common_opts,
             per_arg_json => $self->per_arg_json,
             per_arg_yaml => $self->per_arg_yaml,
         );
         die [500, "Can't gen_cli_doc_data_from_meta: $res->[0] - $res->[1]"]
             unless $res->[0] == 200;
         $r->{_help_clidocdata} = $res->[2]; # cache here
     }
 
     # ux: since --verbose will potentially show lots of paragraph text, let's
     # default to 80 and not wider width, unless user specifically requests
     # column width via COLUMNS.
     if ($verbose && !defined($ENV{COLUMNS}) && $self->term_width > 80) {
         $self->term_width(80);
     }
 
     # determine which help sections should we generate
     my @hsects;
     if ($verbose) {
         @hsects = (
             'summary',
             'usage',
             'subcommands',
             'examples',
             'description',
             'options',
             'result',
             'links',
             'hints',
         );
     } else {
         @hsects = (
             'summary',
             'usage',
             'subcommands',
             'examples',
             'options',
             'hints',
         );
     }
 
     for my $s (@hsects) {
         my $meth = "help_section_$s";
         #say "D:$meth";
         #$log->tracef("=> $meth()");
         $self->$meth($r);
     }
     $self->_help_draw_curtbl($r);
     [200, "OK", $r->{_help_buf}, {"cmdline.skip_format"=>1}];
 }
 
 1;
 # ABSTRACT: Help-related routines
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Perinci::CmdLine::Classic::Role::Help - Help-related routines
 
 =head1 VERSION
 
 This document describes version 1.60 of Perinci::CmdLine::Classic::Role::Help (from Perl distribution Perinci-CmdLine-Classic), released on 2015-10-20.
 
 =for Pod::Coverage ^(.+)$
 
 =head1 REQUEST KEYS
 
 =over
 
 =item * _help_*
 
 Temporary. Various data stored during help generation that is passed between the
 various C<_help_*> methods.
 
 =back
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Perinci-CmdLine-Classic>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Perinci-CmdLine-Classic>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Perinci-CmdLine-Classic>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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
### Perinci/CmdLine/Help.pm ###
 package Perinci::CmdLine::Help;
 
 our $DATE = '2015-09-03'; # DATE
 our $VERSION = '0.08'; # VERSION
 
 use 5.010001;
 use strict;
 use warnings;
 
 require Exporter;
 our @ISA = qw(Exporter);
 our @EXPORT_OK = qw(gen_help);
 
 our %SPEC;
 
 $SPEC{gen_help} = {
     v => 1.1,
     summary => 'Generate help message for Perinci::CmdLine-based app',
     args => {
         program_name => {
             schema => 'str*',
             req => 1,
         },
         program_summary => {
             schema => 'str*',
         },
         subcommands => {
             schema => 'hash',
         },
         meta => {
             summary => 'Function metadata, must be normalized',
             schema => 'hash*',
             req => 1,
         },
         common_opts => {
             schema => 'hash*',
             default => {},
         },
         per_arg_json => {
             schema => 'bool*',
         },
         per_arg_yaml => {
             schema => 'bool*',
         },
     },
 };
 sub gen_help {
     my %args = @_;
 
     my $meta = $args{meta};
     my $common_opts = $args{common_opts} // {};
 
     my @help;
 
     # summary
     my $progname = $args{program_name};
     push @help, $progname;
     {
         my $sum = $args{program_summary} // $meta->{summary};
         last unless $sum;
         push @help, " - ", $sum, "\n";
     }
 
     my $clidocdata;
 
     # usage
     push @help, "\nUsage:\n";
     {
         for (sort {
             ($common_opts->{$a}{order} // 99) <=>
                 ($common_opts->{$b}{order} // 99) ||
                     $a cmp $b
             } keys %$common_opts) {
             my $co = $common_opts->{$_};
             next unless $co->{usage};
             push @help, "  $progname $co->{usage}\n";
         }
 
         require Perinci::Sub::To::CLIDocData;
         my $res = Perinci::Sub::To::CLIDocData::gen_cli_doc_data_from_meta(
             meta => $meta, meta_is_normalized => 1,
             common_opts  => $common_opts,
             per_arg_json => $args{per_arg_json},
             per_arg_yaml => $args{per_arg_yaml},
         );
         die [500, "gen_cli_doc_data_from_meta failed: ".
                  "$res->[0] - $res->[1]"] unless $res->[0] == 200;
         $clidocdata = $res->[2];
         my $usage = $clidocdata->{usage_line};
         $usage =~ s/\[\[prog\]\]/$progname/;
         push @help, "  $usage\n";
     }
 
     # subcommands
     {
         my $subcommands = $args{subcommands} or last;
         push @help, "\nSubcommands:\n";
         if (keys(%$subcommands) >= 12) {
             # comma-separated list
             no warnings 'once';
             require Text::Wrap;
             local $Text::Wrap::columns = $ENV{COLUMNS} // 80;
             push @help, Text::Wrap::wrap(
                 "  ", "  ", join(", ", sort keys %$subcommands)), "\n";
         } else {
             for my $sc_name (sort keys %$subcommands) {
                 my $sc_spec = $subcommands->{$sc_name};
                 next unless $sc_spec->{show_in_help} //1;
                 push @help, "  $sc_name\n";
             }
         }
     }
 
     # example
     {
         # XXX categorize too, like options
         last unless @{ $clidocdata->{examples} };
         push @help, "\nExamples:\n";
         my $i = 0;
         my $egs = $clidocdata->{examples};
         for my $eg (@$egs) {
             $i++;
             my $cmdline = $eg->{cmdline};
             $cmdline =~ s/\[\[prog\]\]/$progname/;
             push @help, "  $eg->{summary}:\n" if $eg->{summary};
             push @help, "  % $cmdline\n";
             push @help, "\n" if $eg->{summary} && $i < @$egs;
         }
     }
 
     # description
     {
         my $desc = $args{program_description} // $meta->{description};
         last unless $desc;
         $desc =~ s/\A\n+//;
         $desc =~ s/\n+\z//;
         push @help, "\n", $desc, "\n" if $desc =~ /\S/;
     }
 
     # options
     {
         require Data::Dmp;
 
         my $opts = $clidocdata->{opts};
         last unless keys %$opts;
 
         # find all the categories
         my %options_by_cat; # val=[options...]
         for my $optkey (keys %$opts) {
             for my $cat (@{ $opts->{$optkey}{categories} }) {
                 push @{ $options_by_cat{$cat} }, $optkey;
             }
         }
 
         my $cats_spec = $clidocdata->{option_categories};
         for my $cat (sort {
             ($cats_spec->{$a}{order} // 50) <=> ($cats_spec->{$b}{order} // 50)
                 || $a cmp $b }
                          keys %options_by_cat) {
             # find the longest option
             my @opts = sort {length($b)<=>length($a)}
                 @{ $options_by_cat{$cat} };
             my $len = length($opts[0]);
             # sort again by name
             @opts = sort {
                 (my $a_without_dash = $a) =~ s/^-+//;
                 (my $b_without_dash = $b) =~ s/^-+//;
                 lc($a) cmp lc($b);
             } @opts;
             push @help, "\n$cat:\n";
             for my $opt (@opts) {
                 my $ospec = $opts->{$opt};
                 my $arg_spec = $ospec->{arg_spec};
                 my $is_bool = $arg_spec->{schema} &&
                     $arg_spec->{schema}[0] eq 'bool';
                 my $show_default = exists($ospec->{default}) &&
                     !$is_bool && !$ospec->{is_base64} &&
                         !$ospec->{is_json} && !$ospec->{is_yaml} &&
                             !$ospec->{is_alias};
 
                 my $add_sum = '';
                 if ($ospec->{is_base64}) {
                     $add_sum = " (base64-encoded)";
                 } elsif ($ospec->{is_json}) {
                     $add_sum = " (JSON-encoded)";
                 } elsif ($ospec->{is_yaml}) {
                     $add_sum = " (YAML-encoded)";
                 }
 
                 my $argv = '';
                 if (!$ospec->{main_opt} && defined($ospec->{pos})) {
                     if ($ospec->{greedy}) {
                         $argv = " (=arg[$ospec->{pos}-])";
                     } else {
                         $argv = " (=arg[$ospec->{pos}])";
                     }
                 }
 
                 my $cmdline_src = '';
                 if (!$ospec->{main_opt} && defined($arg_spec->{cmdline_src})) {
                     $cmdline_src = " (or from $arg_spec->{cmdline_src})";
                     $cmdline_src =~ s!_or_!/!g;
                 }
 
                 push @help, sprintf(
                     "  %-${len}s  %s%s%s%s%s\n",
                     $opt,
                     $ospec->{summary}//'',
                     $add_sum,
                     $argv,
                     $cmdline_src,
                     ($show_default && defined($ospec->{default}) ?
                          " [".Data::Dmp::dmp($ospec->{default})."]":""),
 
                 );
             }
         }
     }
 
     [200, "OK", join("", @help)];
 }
 
 1;
 # ABSTRACT: Generate help message for Perinci::CmdLine-based app
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Perinci::CmdLine::Help - Generate help message for Perinci::CmdLine-based app
 
 =head1 VERSION
 
 This document describes version 0.08 of Perinci::CmdLine::Help (from Perl distribution Perinci-CmdLine-Help), released on 2015-09-03.
 
 =head1 DESCRIPTION
 
 Currently used by L<Perinci::CmdLine::Lite> and L<App::riap>. Eventually I want
 L<Perinci::CmdLine> to use this also (needs prettier and more sophisticated
 formatting options first though).
 
 =head1 FUNCTIONS
 
 
 =head2 gen_help(%args) -> [status, msg, result, meta]
 
 Generate help message for Perinci::CmdLine-based app.
 
 Arguments ('*' denotes required arguments):
 
 =over 4
 
 =item * B<common_opts> => I<hash> (default: {})
 
 =item * B<meta>* => I<hash>
 
 Function metadata, must be normalized.
 
 =item * B<per_arg_json> => I<bool>
 
 =item * B<per_arg_yaml> => I<bool>
 
 =item * B<program_name>* => I<str>
 
 =item * B<program_summary> => I<str>
 
 =item * B<subcommands> => I<hash>
 
 =back
 
 Returns an enveloped result (an array).
 
 First element (status) is an integer containing HTTP status code
 (200 means OK, 4xx caller error, 5xx function error). Second element
 (msg) is a string containing error message, or 'OK' if status is
 200. Third element (result) is optional, the actual result. Fourth
 element (meta) is called result metadata and is optional, a hash
 that contains extra information.
 
 Return value:  (any)
 
 =for Pod::Coverage ^()$
 
 =head1 SEE ALSO
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Perinci-CmdLine-Help>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Perinci-CmdLine-Help>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Perinci-CmdLine-Help>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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
### Perinci/CmdLine/Lite.pm ###
 package Perinci::CmdLine::Lite;
 
 our $DATE = '2015-10-20'; # DATE
 our $VERSION = '1.36'; # VERSION
 
 use 5.010001;
 # use strict; # already enabled by Mo
 # use warnings; # already enabled by Mo
 use Log::Any::IfLOG '$log';
 
 use List::Util qw(first);
 use Mo qw(build default);
 #use Moo;
 extends 'Perinci::CmdLine::Base';
 
 # when debugging, use this instead of the above because Mo doesn't give clear
 # error message if base class has errors.
 #use parent 'Perinci::CmdLine::Base';
 
 has default_prompt_template => (
     is=>'rw',
     default => 'Enter %s: ',
 );
 has log => (
     is=>'rw',
     default => sub {
         if (defined $ENV{LOG}) {
             return $ENV{LOG};
         } elsif ($ENV{LOG_LEVEL} && $ENV{LOG_LEVEL} =~ /^(off|none)$/) {
             return 0;
         } elsif ($ENV{LOG_LEVEL} || $ENV{TRACE} || $ENV{DEBUG} ||
                      $ENV{VERBOSE} || $ENV{QUIET}) {
             return 0;
         }
         0;
     },
 );
 has log_level => (
     is=>'rw',
     default => sub {
         if ($ENV{LOG_LEVEL}) {
             return $ENV{LOG_LEVEL};
         } elsif ($ENV{TRACE}) {
             return 'trace';
         } elsif ($ENV{DEBUG}) {
             return 'debug';
         } elsif ($ENV{VERBOSE}) {
             return 'info';
         } elsif ($ENV{QUIET}) {
             return 'error';
         }
         'warning';
     },
 );
 has validate_args => (
     is=>'rw',
     default => 1,
 );
 
 my $formats = [qw/text text-simple text-pretty json json-pretty/];
 
 sub BUILD {
     my ($self, $args) = @_;
 
     if (!$self->{riap_client}) {
         require Perinci::Access::Lite;
         my %rcargs = (
             riap_version => $self->{riap_version} // 1.1,
             %{ $self->{riap_client_args} // {} },
         );
         $self->{riap_client} = Perinci::Access::Lite->new(%rcargs);
     }
 
     if (!$self->{actions}) {
         $self->{actions} = {
             call => {},
             version => {},
             subcommands => {},
             help => {},
         };
     }
 
     my $_t = sub {
         no warnings;
         my $co_name = shift;
         my $href = $Perinci::CmdLine::Base::copts{$co_name};
         %$href;
     };
 
     if (!$self->{common_opts}) {
         my $copts = {};
 
         $copts->{version}   = { $_t->('version'), };
         $copts->{help}      = { $_t->('help'), };
 
         unless ($self->skip_format) {
             $copts->{format}    = {
                 $_t->('format'),
                 schema => ['str*' => in => $formats],
             };
             $copts->{json}      = { $_t->('json'), };
             $copts->{naked_res} = { $_t->('naked_res'), };
         }
         if ($self->subcommands) {
             $copts->{subcommands} = { $_t->('subcommands'), };
         }
         if ($self->default_subcommand) {
             $copts->{cmd} = { $_t->('cmd') };
         }
         if ($self->read_config) {
             $copts->{config_path}    = { $_t->('config_path') };
             $copts->{no_config}      = { $_t->('no_config') };
             $copts->{config_profile} = { $_t->('config_profile') };
         }
         if ($self->read_env) {
             $copts->{no_env} = { $_t->('no_env') };
         }
         if ($self->log) {
             $copts->{log_level} = { $_t->('log_level'), };
             $copts->{trace}     = { $_t->('trace'), };
             $copts->{debug}     = { $_t->('debug'), };
             $copts->{verbose}   = { $_t->('verbose'), };
             $copts->{quiet}     = { $_t->('quiet'), };
         }
         $self->{common_opts} = $copts;
     }
 
     $self->{formats} //= $formats;
 
     $self->{per_arg_json} //= 1;
 }
 
 my $setup_progress;
 sub _setup_progress_output {
     my $self = shift;
 
     return unless $ENV{PROGRESS} // (-t STDOUT);
 
     require Progress::Any::Output;
     Progress::Any::Output->set("TermProgressBarColor");
     $setup_progress = 1;
 }
 
 sub _unsetup_progress_output {
     my $self = shift;
 
     return unless $setup_progress;
     my $out = $Progress::Any::outputs{''}[0];
     $out->cleanup if $out->can("cleanup");
     $setup_progress = 0;
 }
 
 sub hook_after_parse_argv {
     my ($self, $r) = @_;
 
     # since unlike Perinci::CmdLine, we don't wrap the function (where the
     # wrapper assigns default values for arguments), we must do it here
     # ourselves.
     my $ass  = $r->{meta}{args} // {};
     my $args = $r->{args};
     for (keys %$ass) {
         next if exists $args->{$_};
         my $as = $ass->{$_};
         if (exists $as->{default}) {
             $args->{$_} = $as->{default};
         } elsif ($as->{schema} && exists $as->{schema}[1]{default}) {
             $args->{$_} = $as->{schema}[1]{default};
         }
     }
 
     # set up log adapter
     if ($self->log) {
         require Log::Any::Adapter;
         Log::Any::Adapter->set(
             'Screen',
             min_level => $r->{log_level} // $self->log_level,
             formatter => sub { $self->program_name . ": $_[1]" },
         );
     }
 }
 
 sub hook_before_action {
     my ($self, $r) = @_;
 
     # validate arguments using schema from metadata
   VALIDATE_ARGS:
     {
         last unless $self->validate_args;
 
         # unless we're feeding the arguments to function, don't bother
         # validating arguments
         last unless $r->{action} eq 'call';
 
         my $meta = $r->{meta};
 
         # function is probably already wrapped
         last if $meta->{'x.perinci.sub.wrapper.logs'} &&
             (grep { $_->{validate_args} }
              @{ $meta->{'x.perinci.sub.wrapper.logs'} });
 
         require Data::Sah;
 
         # to be cheap, we simply use "$ref" as key as cache key. to be proper,
         # it should be hash of serialized content.
         my %validators; # key = "$schema"
 
         for my $arg (sort keys %{ $meta->{args} // {} }) {
             next unless exists($r->{args}{$arg});
 
             # we don't support validation of input stream because this must be
             # done after each 'get item' (but periswrap does)
             next if $meta->{args}{$arg}{stream};
 
             my $schema = $meta->{args}{$arg}{schema};
             next unless $schema;
             unless ($validators{"$schema"}) {
                 my $v = Data::Sah::gen_validator($schema, {
                     return_type => 'str',
                     schema_is_normalized => 1,
                 });
                 $validators{"$schema"} = $v;
             }
             my $res = $validators{"$schema"}->($r->{args}{$arg});
             if ($res) {
                 die [400, "Argument '$arg' fails validation: $res"];
             }
         }
 
         if ($meta->{args_rels}) {
             my $schema = [hash => $meta->{args_rels}];
             my $sah = Data::Sah->new;
             my $hc  = $sah->get_compiler("human");
             my $cd  = $hc->init_cd;
             $cd->{args}{lang} //= $cd->{default_lang};
             my $v = Data::Sah::gen_validator($schema, {
                 return_type => 'str',
                 human_hash_values => {
                     field  => $hc->_xlt($cd, "argument"),
                     fields => $hc->_xlt($cd, "arguments"),
                 },
             });
             my $res = $v->($r->{args});
             if ($res) {
                 die [400, $res];
             }
         }
 
     }
 }
 
 sub hook_format_result {
     require Perinci::Result::Format::Lite;
     my ($self, $r) = @_;
 
     my $fmt = $r->{format} // 'text';
 
     my $fres = Perinci::Result::Format::Lite::format(
         $r->{res}, $fmt, $r->{naked_res});
 
     # ux: prefix error message with program name
     if ($fmt =~ /text/ && $r->{res}[0] =~ /\A[45]/ && defined($r->{res}[1])) {
         $fres = $self->program_name . ": $fres";
     }
 
     $fres;
 }
 
 sub hook_format_row {
     my ($self, $r, $row) = @_;
 
     if (ref($row) eq 'ARRAY') {
         return join("\t", @$row) . "\n";
     } else {
         return ($row // "") . "\n";
     }
 }
 
 sub hook_display_result {
     my ($self, $r) = @_;
     $self->display_result($r);
 }
 
 sub hook_after_run {
     my ($self, $r) = @_;
     $self->_unsetup_progress_output;
 }
 
 sub hook_after_get_meta {
     my ($self, $r) = @_;
 
     require Perinci::Object;
     if (Perinci::Object::risub($r->{meta})->can_dry_run) {
         $self->common_opts->{dry_run} = {
             getopt  => 'dry-run',
             summary => "Run in simulation mode (also via DRY_RUN=1)",
             handler => sub {
                 my ($go, $val, $r) = @_;
                 $log->debugf("[pericmd] Dry-run mode is activated");
                 $r->{dry_run} = 1;
                 #$ENV{VERBOSE} = 1;
             },
         };
     }
 
     # check deps property. XXX this should be done only when we don't wrap
     # subroutine, because Perinci::Sub::Wrapper already checks the deps
     # property.
     if ($r->{meta}{deps}) {
         require Perinci::Sub::DepChecker;
         my $res = Perinci::Sub::DepChecker::check_deps($r->{meta}{deps});
         if ($res) {
             die [412, "Dependency failed: $res"];
         }
     }
 }
 
 sub action_subcommands {
     my ($self, $r) = @_;
 
     if (!$self->subcommands) {
         say "There are no subcommands.";
         return 0;
     }
 
     say "Available subcommands:";
     my $scs = $self->list_subcommands;
     my $longest = 6;
     for (keys %$scs) { my $l = length; $longest = $l if $l > $longest }
     [200, "OK",
      join("",
           (map { sprintf("  %-${longest}s  %s\n",$_,$scs->{$_}{summary}//"") }
                sort keys %$scs),
       )];
 }
 
 sub action_version {
     no strict 'refs';
 
     my ($self, $r) = @_;
 
     my @text;
 
     {
         my $meta = $r->{meta} = $self->get_meta($r, $self->url);
         push @text, $self->get_program_and_subcommand_name($r),
             " version ", ($meta->{entity_v} // "?"),
             ($meta->{entity_date} ? " ($meta->{entity_date})" : ''),
             "\n";
         for my $mod (@{ $meta->{'x.dynamic_generator_modules'} // [] }) {
             push @text, "  $mod version ", ${"$mod\::VERSION"},
                 (${"$mod\::DATE"} ? " (".${"$mod\::DATE"}.")" : ""),
                     "\n";
         }
     }
 
     for my $url (@{ $self->extra_urls_for_version // [] }) {
         my $meta = $self->get_meta($r, $url);
         push @text, "  $url version ", ($meta->{entity_v} // "?"),
             ($meta->{entity_date} ? " ($meta->{entity_date})" : ''),
             "\n";
     }
 
     push @text, "  ", __PACKAGE__,
         " version ", ($Perinci::CmdLine::Lite::VERSION // "?"),
         ($Perinci::CmdLine::Lite::DATE ?
          " ($Perinci::CmdLine::Lite::DATE)":''),
         "\n";
 
     [200, "OK", join("", @text)];
 }
 
 sub action_help {
     require Perinci::CmdLine::Help;
 
     my ($self, $r) = @_;
 
     my @help;
     my $scn    = $r->{subcommand_name};
     my $scd    = $r->{subcommand_data};
 
     my $meta = $self->get_meta($r, $scd->{url} // $self->{url});
 
     # XXX use 'delete local' when we bump minimal perl to 5.12
     my $common_opts = { %{$self->common_opts} };
 
     # hide usage '--subcommands' if we have subcommands but user has specified a
     # subcommand to use
     my $has_sc_no_sc = $self->subcommands && !length($r->{subcommand_name});
     delete $common_opts->{subcommands} if $self->subcommands && !$has_sc_no_sc;
 
     my $res = Perinci::CmdLine::Help::gen_help(
         program_name => $self->get_program_and_subcommand_name($r),
         program_summary => ($scd ? $scd->{summary}:undef ) // $meta->{summary},
         program_description => $scd ? $scd->{description} : undef,
         meta => $meta,
         subcommands => $has_sc_no_sc ? $self->list_subcommands : undef,
         common_opts => $common_opts,
         per_arg_json => $self->per_arg_json,
         per_arg_yaml => $self->per_arg_yaml,
     );
 
     $res->[3]{"cmdline.skip_format"} = 1;
     $res;
 }
 
 sub action_call {
     my ($self, $r) = @_;
 
     my %extra;
     if ($r->{send_argv}) {
         $log->tracef("[pericmd] Sending argv to server: %s", $extra{argv});
         $extra{argv} = $r->{orig_argv};
     } else {
         my %extra_args;
         $extra_args{-dry_run} = 1 if $r->{dry_run};
         $extra{args} = {%extra_args, %{$r->{args}}};
     }
 
     $extra{stream_arg} = 1 if $r->{stream_arg};
 
     my $url = $r->{subcommand_data}{url};
 
     # currently we don't log args because it's potentially large
     $log->tracef("[pericmd] Riap request: action=call, url=%s", $url);
 
     #$log->tracef("TMP: extra=%s", \%extra);
 
     # setup output progress indicator
     if ($r->{meta}{features}{progress}) {
         $self->_setup_progress_output;
     }
 
     $self->riap_client->request(
         call => $url, \%extra);
 }
 
 1;
 # ABSTRACT: A lightweight Rinci/Riap-based command-line application framework
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Perinci::CmdLine::Lite - A lightweight Rinci/Riap-based command-line application framework
 
 =head1 VERSION
 
 This document describes version 1.36 of Perinci::CmdLine::Lite (from Perl distribution Perinci-CmdLine-Lite), released on 2015-10-20.
 
 =head1 SYNOPSIS
 
 In C<gen-random-num> script:
 
  use Perinci::CmdLine::Lite;
 
  our %SPEC;
 
  $SPEC{gen_random_num} = {
      v => 1.1,
      summary => 'Generate some random numbers',
      args => {
          count => {
              summary => 'How many numbers to generate',
              schema => ['int*' => min=>0],
              default => 1,
              cmdline_aliases=>{n=>{}},
              req => 1,
              pos => 0,
          },
          min => {
              summary => 'Lower limit of random number',
              schema => 'float*',
              default => 0,
          },
          max => {
              summary => 'Upper limit of random number',
              schema => 'float*',
              default => 1,
          },
      },
      result_naked => 1,
  };
  sub gen_random_num {
      my %args = @_;
 
      my @res;
      for (1..$args{count}) {
          push @res, $args{min} + rand()*($args{max}-$args{min});
      }
      \@res;
  }
 
  Perinci::CmdLine::Lite->new(url => '/main/gen_random_num')->run;
 
 Run your script:
 
  % ./gen-random-num
  0.999473691060306
 
  % ./gen-random-num --min 1 --max 10 5
  1.27390166158969
  1.69077475473679
  8.97748327778684
  5.86943773494068
  8.34341298182493
 
 JSON output support out of the box:
 
  % ./gen-random-num -n3 --json
  [200,"OK (envelope added by Perinci::Access::Lite)",[0.257073684902029,0.393782991540746,0.848740540017513],{}]
 
 Automatic help message:
 
  % ./gen-random-num -h
  gen-random-num - Generate some random numbers
 
  Usage:
    gen-random-num --help (or -h, -?)
    gen-random-num --version (or -v)
    gen-random-num [options] [count]
  Options:
    --config-path=s     Set path to configuration file
    --config-profile=s  Set configuration profile to use
    --count=i, -n       How many numbers to generate (=arg[0]) [1]
    --format=s          Choose output format, e.g. json, text [undef]
    --help, -h, -?      Display this help message
    --json              Set output format to json
    --max=f             Upper limit of random number [1]
    --min=f             Lower limit of random number [0]
    --naked-res         When outputing as JSON, strip result envelope [0]
    --no-config         Do not use any configuration file
    --version, -v
 
 Automatic configuration file support:
 
  % cat ~/gen-random-num.conf
  count=5
  max=0.01
 
  % ./gen-random-num
  0.00105268954838724
  0.00701443611501844
  0.0021247476506154
  0.00813872824513005
  0.00752832346491306
 
 Automatic tab completion support:
 
  % complete -C gen-random-num gen-random-num
  % gen-random-num --mi<tab>
 
 See L<Perinci::CmdLine::Manual> for details on other available features
 (subcommands, automatic formatting of data structures, automatic schema
 validation, dry-run mode, automatic POD generation, remote function support,
 automatic CLI generation, automatic --version, automatic HTTP API,
 undo/transactions, configurable output format, logging, progress bar,
 colors/Unicode, and more).
 
 =head1 DESCRIPTION
 
 Perinci::CmdLine is a command-line application framework. It allows you to
 create full-featured CLI applications easily and quickly.
 
 See L<Perinci::CmdLine::Manual> for more details.
 
 There is also a blog post series on Perinci::CmdLine tutorial:
 L<https://perlancar.wordpress.com/category/pericmd-tut/>
 
 Perinci::CmdLine::Lite is the default backend implementation. You normally
 should use L<Perinci::CmdLine::Any> instead to be able to switch backend on the
 fly.
 
 =for Pod::Coverage ^(BUILD|get_meta|hook_.+|action_.+)$
 
 =head1 REQUEST KEYS
 
 All those supported by L<Perinci::CmdLine::Base>, plus:
 
 =over
 
 =back
 
 =head1 ATTRIBUTES
 
 All the attributes of L<Perinci::CmdLine::Base>, plus:
 
 =head2 log => bool (default: from env or 0)
 
 Whether to enable logging. This currently means setting up L<Log::Any::Adapter>
 to display logging (set in C<hook_after_parse_argv>, so tab completion skips
 this step). To produce log, you use L<Log::Any> in your code.
 
 The default is off. If you set LOG=1 or LOG_LEVEL or TRACE/DEBUG/VERBOSE/QUIET,
 then the default will be on. It defaults to off if you set LOG=0 or
 LOG_LEVEL=off.
 
 =head2 log_level => str (default: from env, or 'warning')
 
 Set default log level. The default can also be set via
 LOG_LEVEL/TRACE/DEBUG/VERBOSE/QUIET.
 
 =head2 validate_args => bool (default: 1)
 
 =head1 METHODS
 
 All the methods of L<Perinci::CmdLine::Base>, plus:
 
 =head1 ENVIRONMENT
 
 All the environment variables that L<Perinci::CmdLine::Base> supports, plus:
 
 =head2 DEBUG
 
 Set log level to 'debug'.
 
 =head2 VERBOSE
 
 Set log level to 'info'.
 
 =head2 QUIET
 
 Set log level to 'error'.
 
 =head2 TRACE
 
 Set log level to 'trace'.
 
 =head2 LOG_LEVEL
 
 Set log level.
 
 =head2 PROGRESS => BOOL
 
 Explicitly turn the progress bar on/off.
 
 =head2 FORMAT_PRETTY_TABLE_COLUMN_ORDERS => array (json)
 
 Set the default of C<table_column_orders> in C<format_options> in result
 metadata, similar to what's implemented in L<Perinci::Result::Format> and
 L<Data::Format::Pretty::Console>.
 
 =head1 RESULT METADATA
 
 All those supported by L<Perinci::CmdLine::Base>, plus:
 
 =head2 x.hint.result_binary => bool
 
 If set to true, then when formatting to C<text> formats, this class won't print
 any newline to keep the data being printed unmodified.
 
 =head1 SEE ALSO
 
 L<Perinci::CmdLine::Any>
 
 L<Perinci::CmdLine::Classic>
 
 L<Perinci::CmdLine::Inline>
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Perinci-CmdLine-Lite>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Perinci-CmdLine-Lite>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Perinci-CmdLine-Lite>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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
### Perinci/CmdLine/Util/Config.pm ###
 package Perinci::CmdLine::Util::Config;
 
 our $DATE = '2015-10-20'; # DATE
 our $VERSION = '1.36'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 use Log::Any::IfLOG '$log';
 
 use PERLANCAR::File::HomeDir qw(get_my_home_dir);
 
 our %SPEC;
 
 $SPEC{get_default_config_dirs} = {
     v => 1.1,
     args => {},
 };
 sub get_default_config_dirs {
     my @dirs;
     local $PERLANCAR::File::HomeDir::DIE_ON_FAILURE = 1;
     my $home = get_my_home_dir();
     if ($^O eq 'MSWin32') {
         push @dirs, $home;
     } else {
         push @dirs, "$home/.config", $home, "/etc";
     }
     \@dirs;
 }
 
 $SPEC{read_config} = {
     v => 1.1,
     args => {
         config_paths => {},
         config_filenames => {},
         config_dirs => {},
         program_name => {},
     },
 };
 sub read_config {
     require Config::IOD::Reader;
 
     my %args = @_;
 
     my $config_dirs = $args{config_dirs} // get_default_config_dirs();
 
     my $paths;
     if ($args{config_paths}) {
         $paths = $args{config_paths};
     } else {
         my $name = $args{config_filename} //
             $args{program_name} . ".conf";
         for my $dir (@$config_dirs) {
             my $path = "$dir/" . $name;
             push @$paths, $path if -e $path;
         }
     }
 
     my $reader = Config::IOD::Reader->new;
     my %res;
     my @read;
     for my $path (@$paths) {
         my $hoh = $reader->read_file($path);
         push @read, $path;
         for my $section (keys %$hoh) {
             my $hash = $hoh->{$section};
             for (keys %$hash) {
                 $res{$section}{$_} = $hash->{$_};
             }
         }
     }
     [200, "OK", \%res, {'func.read_files' => \@read}];
 }
 
 $SPEC{get_args_from_config} = {
     v => 1.1,
     args => {
         r => {},
         config => {},
         args => {},
         subcommand_name => {},
         config_profile => {},
         common_opts => {},
         meta => {},
         meta_is_normalized => {},
     },
 };
 sub get_args_from_config {
     my %fargs = @_;
 
     my $r       = $fargs{r};
     my $conf    = $fargs{config};
     my $scn     = $fargs{subcommand_name} // '';
     my $profile = $fargs{config_profile};
     my $args    = $fargs{args} // {};
     my $copts   = $fargs{common_opts};
     my $meta    = $fargs{meta};
     my $found;
 
     unless ($fargs{meta_is_normalized}) {
         require Perinci::Sub::Normalize;
         $meta = Perinci::Sub::Normalize::normalize_function_metadata($meta);
     }
 
     # put GLOBAL before all other sections
     my @sections = sort {
         ($a eq 'GLOBAL' ? 0:1) <=> ($b eq 'GLOBAL' ? 0:1) ||
             $a cmp $b
         } keys %$conf;
 
     my %seen_profiles; # for debugging message
     for my $section (@sections) {
         my ($sect_scn, $sect_profile);
         if ($section =~ /\Aprofile=(.*)\z/) {
             $sect_scn = 'GLOBAL';
             $sect_profile = $1;
         } elsif ($section =~ /\A\S+\z/) {
             $sect_scn = $section;
         } elsif ($section =~ /\A(\S+)\s+profile=(.*)\z/) {
             $sect_scn = $1;
             $sect_profile = $2;
         } else {
             die [412, "Error in config file: invalid section name ".
                      "'$section', please use subcommand name + optional ".
                          "' profile=PROFILE' only"];
         }
         $seen_profiles{$sect_profile}++ if defined $sect_profile;
         if (length $scn) {
             next if $sect_scn ne 'GLOBAL' && $sect_scn ne $scn;
         } else {
             next if $sect_scn ne 'GLOBAL';
         }
         if (defined $profile) {
             next if defined($sect_profile) && $sect_profile ne $profile;
             $found++ if defined($sect_profile) && $sect_profile eq $profile;
         } else {
             next if defined($sect_profile);
         }
 
         my $as = $meta->{args} // {};
         for my $k (keys %{ $conf->{$section} }) {
             my $v = $conf->{$section}{$k};
             if ($copts->{$k} && $copts->{$k}{is_settable_via_config}) {
                 my $sch = $copts->{$k}{schema};
                 if ($sch) {
                     require Data::Sah::Normalize;
                     $sch = Data::Sah::Normalize::normalize_schema($sch);
                     # since IOD might return a scalar or an array (depending on
                     # whether there is a single param=val or multiple param=
                     # lines), we need to arrayify the value if the argument is
                     # expected to be an array.
                     if (ref($v) ne 'ARRAY' && $sch->[0] eq 'array') {
                         $v = [$v];
                     }
                 }
                 $copts->{$k}{handler}->(undef, $v, $r);
             } else {
                 # when common option clashes with function argument name, user
                 # can use NAME.arg to refer to function argument.
                 $k =~ s/\.arg\z//;
 
                 # since IOD might return a scalar or an array (depending on
                 # whether there is a single param=val or multiple param= lines),
                 # we need to arrayify the value if the argument is expected to
                 # be an array.
                 if (ref($v) ne 'ARRAY' && $as->{$k} && $as->{$k}{schema} &&
                         $as->{$k}{schema}[0] eq 'array') {
                     $v = [$v];
                 }
                 $args->{$k} = $v;
             }
         }
     }
     $log->tracef("[pericmd] Seen config profiles: %s",
                  [sort keys %seen_profiles]);
 
     [200, "OK", $args, {'func.found'=>$found}];
 }
 
 1;
 # ABSTRACT: Utility routines related to config files
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Perinci::CmdLine::Util::Config - Utility routines related to config files
 
 =head1 VERSION
 
 This document describes version 1.36 of Perinci::CmdLine::Util::Config (from Perl distribution Perinci-CmdLine-Lite), released on 2015-10-20.
 
 =head1 FUNCTIONS
 
 
 =head2 get_args_from_config(%args) -> [status, msg, result, meta]
 
 This function is not exportable.
 
 Arguments ('*' denotes required arguments):
 
 =over 4
 
 =item * B<args> => I<any>
 
 =item * B<common_opts> => I<any>
 
 =item * B<config> => I<any>
 
 =item * B<config_profile> => I<any>
 
 =item * B<meta> => I<any>
 
 =item * B<meta_is_normalized> => I<any>
 
 =item * B<r> => I<any>
 
 =item * B<subcommand_name> => I<any>
 
 =back
 
 Returns an enveloped result (an array).
 
 First element (status) is an integer containing HTTP status code
 (200 means OK, 4xx caller error, 5xx function error). Second element
 (msg) is a string containing error message, or 'OK' if status is
 200. Third element (result) is optional, the actual result. Fourth
 element (meta) is called result metadata and is optional, a hash
 that contains extra information.
 
 Return value:  (any)
 
 
 =head2 get_default_config_dirs() -> [status, msg, result, meta]
 
 This function is not exportable.
 
 No arguments.
 
 Returns an enveloped result (an array).
 
 First element (status) is an integer containing HTTP status code
 (200 means OK, 4xx caller error, 5xx function error). Second element
 (msg) is a string containing error message, or 'OK' if status is
 200. Third element (result) is optional, the actual result. Fourth
 element (meta) is called result metadata and is optional, a hash
 that contains extra information.
 
 Return value:  (any)
 
 
 =head2 read_config(%args) -> [status, msg, result, meta]
 
 This function is not exportable.
 
 Arguments ('*' denotes required arguments):
 
 =over 4
 
 =item * B<config_dirs> => I<any>
 
 =item * B<config_filenames> => I<any>
 
 =item * B<config_paths> => I<any>
 
 =item * B<program_name> => I<any>
 
 =back
 
 Returns an enveloped result (an array).
 
 First element (status) is an integer containing HTTP status code
 (200 means OK, 4xx caller error, 5xx function error). Second element
 (msg) is a string containing error message, or 'OK' if status is
 200. Third element (result) is optional, the actual result. Fourth
 element (meta) is called result metadata and is optional, a hash
 that contains extra information.
 
 Return value:  (any)
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Perinci-CmdLine-Lite>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Perinci-CmdLine-Lite>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Perinci-CmdLine-Lite>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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
### Perinci/Object.pm ###
 package Perinci::Object;
 
 our $DATE = '2015-09-03'; # DATE
 our $VERSION = '0.24'; # VERSION
 
 use 5.010001;
 use strict;
 use warnings;
 
 require Exporter;
 our @ISA    = qw(Exporter);
 our @EXPORT = qw(rimeta risub rivar ripkg envres envresmulti riresmeta);
 
 sub rimeta {
     require Perinci::Object::Metadata;
     Perinci::Object::Metadata->new(@_);
 }
 
 sub risub {
     require Perinci::Object::Function;
     Perinci::Object::Function->new(@_);
 }
 
 sub rivar {
     require Perinci::Object::Variable;
     Perinci::Object::Variable->new(@_);
 }
 
 sub ripkg {
     require Perinci::Object::Package;
     Perinci::Object::Package->new(@_);
 }
 
 sub envres {
     require Perinci::Object::EnvResult;
     Perinci::Object::EnvResult->new(@_);
 }
 
 sub envresmulti {
     require Perinci::Object::EnvResultMulti;
     Perinci::Object::EnvResultMulti->new(@_);
 }
 
 sub riresmeta {
     require Perinci::Object::ResMeta;
     Perinci::Object::ResMeta->new(@_);
 }
 
 1;
 # ABSTRACT: Object-oriented interface for Rinci metadata
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Perinci::Object - Object-oriented interface for Rinci metadata
 
 =head1 VERSION
 
 This document describes version 0.24 of Perinci::Object (from Perl distribution Perinci-Object), released on 2015-09-03.
 
 =head1 SYNOPSIS
 
  use Perinci::Object; # automatically exports risub(), rivar(), ripkg(),
                       # envres(), envresmulti(), riresmeta()
  use Data::Dump; # for dd()
 
  # OO interface to function metadata.
 
  my $risub = risub {
      v => 1.1,
      summary => 'Calculate foo and bar',
      "summary.alt.lang.id_ID" => 'Menghitung foo dan bar',
      args => { a1 => { schema => 'int*' }, a2 => { schema => 'str' } },
      features => { pure=>1 },
  };
  dd $risub->type,                                 # "function"
     $risub->v,                                    # 1.1
     $risub->arg('a1'),                            # { schema=>'int*' }
     $risub->arg('a3'),                            # undef
     $risub->feature('pure'),                      # 1
     $risub->feature('foo'),                       # undef
     $risub->langprop('summary'),                  # 'Calculate foo and bar'
     $risub->langprop({lang=>'id_ID'}, 'summary'), # 'Menghitung foo dan bar'
 
  # setting arg and property
  $risub->arg('a3', 'array');  # will actually fail for 1.0 metadata
  $risub->feature('foo', 2);   # ditto
 
  # OO interface to variable metadata
 
  my $rivar = rivar { ... };
 
  # OO interface to package metadata
 
  my $ripkg = ripkg { ... };
 
  # OO interface to enveloped result
 
  my $envres = envres [200, "OK", [1, 2, 3]];
  dd $envres->is_success, # 1
     $envres->status,     # 200
     $envres->message,    # "OK"
     $envres->result,     # [1, 2, 3]
     $envres->meta;       # undef
 
  # setting status, message, result, extra
  $envres->status(404);
  $envres->message('Not found');
  $envres->result(undef);
  $envres->meta({errno=>-100});
 
  # OO interface to function/method result metadata
  my $riresmeta = riresmeta { ... };
 
  # an example of using riresmulti()
  sub myfunc {
      ...
 
      my $envres = envresmulti();
 
      # add result for each item
      $envres->add_result(200, "OK", {item_id=>1});
      $envres->add_result(202, "OK", {item_id=>2, note=>"blah"});
      $envres->add_result(404, "Not found", {item_id=>3});
      ...
 
      # finally, return the result
      return $envres->as_struct;
  }
 
 =head1 DESCRIPTION
 
 L<Rinci> works using pure data structures, but sometimes it's convenient to have
 an object-oriented interface (wrapper) for those data. This module provides just
 that.
 
 =head1 FUNCTIONS
 
 =head2 rimeta $meta => OBJECT
 
 Exported by default. A shortcut for Perinci::Object::Metadata->new($meta).
 
 =head2 risub $meta => OBJECT
 
 Exported by default. A shortcut for Perinci::Object::Function->new($meta).
 
 =head2 rivar $meta => OBJECT
 
 Exported by default. A shortcut for Perinci::Object::Variable->new($meta).
 
 =head2 ripkg $meta => OBJECT
 
 Exported by default. A shortcut for Perinci::Object::Package->new($meta).
 
 =head2 envres $res => OBJECT
 
 Exported by default. A shortcut for Perinci::Object::EnvResult->new($res).
 
 =head2 envresmulti $res => OBJECT
 
 Exported by default. A shortcut for Perinci::Object::EnvResultMulti->new($res).
 
 =head2 riresmeta $resmeta => OBJECT
 
 Exported by default. A shortcut for Perinci::Object::ResMeta->new($res).
 
 =head1 SEE ALSO
 
 L<Rinci>
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Perinci-Object>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Perinci-Object>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Perinci-Object>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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
### Perinci/Object/EnvResult.pm ###
 package Perinci::Object::EnvResult;
 
 our $DATE = '2015-09-03'; # DATE
 our $VERSION = '0.24'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 
 sub new {
     my ($class, $res) = @_;
     $res //= [0, "", undef];
     my $obj = \$res;
     bless $obj, $class;
 }
 
 sub new_ok {
     my $class = shift;
     my $res = [200, "OK"];
     if (@_) {
         push @$res, $_[0];
     }
     $class->new($res);
 }
 
 sub status {
     my ($self, $new) = @_;
     if (defined $new) {
         die "Status must be an integer between 100 and 555" unless
             int($new) eq $new && $new >= 100 && $new <= 555;
         my $old = ${$self}->[0];
         ${$self}->[0] = $new;
         return $old;
     }
     ${$self}->[0];
 }
 
 sub message {
     my ($self, $new) = @_;
     if (defined $new) {
         die "Extra must be a string" if ref($new);
         my $old = ${$self}->[1];
         ${$self}->[1] = $new;
         return $old;
     }
     ${$self}->[1];
 }
 
 # avoid 'result' as this is ambiguous (the enveloped one? the naked one?). even
 # avoid 'enveloped' (the payload being enveloped? the enveloped result
 # (envelope+result inside)?)
 
 sub payload {
     my ($self, $new) = @_;
     if (defined $new) {
         my $old = ${$self}->[2];
         ${$self}->[2] = $new;
         return $old;
     }
     ${$self}->[2];
 }
 
 sub meta {
     my ($self, $new) = @_;
     if (defined $new) {
         die "Extra must be a hashref" unless ref($new) eq 'HASH';
         my $old = ${$self}->[3];
         ${$self}->[3] = $new;
         return $old;
     }
     ${$self}->[3];
 }
 
 sub is_success {
     my ($self) = @_;
     my $status = ${$self}->[0];
     $status >= 200 && $status <= 299;
 }
 
 sub as_struct {
     my ($self) = @_;
     ${$self};
 }
 
 1;
 # ABSTRACT: Represent enveloped result
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Perinci::Object::EnvResult - Represent enveloped result
 
 =head1 VERSION
 
 This document describes version 0.24 of Perinci::Object::EnvResult (from Perl distribution Perinci-Object), released on 2015-09-03.
 
 =head1 SYNOPSIS
 
  use Perinci::Object::EnvResult;
  use Data::Dump; # for dd()
 
  my $envres = Perinci::Object::EnvResult->new([200, "OK", [1, 2, 3]]);
  dd $envres->is_success, # 1
     $envres->status,     # 200
     $envres->message,    # "OK"
     $envres->payload,    # [1, 2, 3]
     $envres->meta,       # undef
     $envres->as_struct;  # [200, "OK", [1, 2, 3]]
 
  # setting status, message, result, extra
  $envres->status(404);
  $envres->message('Not found');
  $envres->payload(undef);
  $envres->meta({errno=>-100});
 
  # shortcut: create a new OK result ([200, "OK"] or [200, "OK", $payload])
  $envres = Perinci::Object::EnvResult->new_ok();
  $envres = Perinci::Object::EnvResult->new_ok(42);
 
 =head1 DESCRIPTION
 
 This class provides an object-oriented interface for enveloped result (see
 L<Rinci::function> for more details).
 
 =head1 METHODS
 
 =head2 new($res) => OBJECT
 
 Create a new object from $res enveloped result array.
 
 =head2 new_ok([ $actual_res ]) => OBJECT
 
 Shortcut for C<< new([200,"OK",$actual_res]) >>, or just C<< new([200,"OK"]) >>
 if C<$actual_res> is not specified.
 
 =head2 $envres->status
 
 Get or set status (the 1st element).
 
 =head2 $envres->message
 
 Get or set message (the 2nd element).
 
 =head2 $envres->payload
 
 Get or set the actual payload (the 3rd element).
 
 =head2 $envres->meta
 
 Get or set result metadata (the 4th element).
 
 =head2 $envres->as_struct
 
 Return the represented data structure.
 
 =head2 $envres->is_success
 
 True if status is between 200-299.
 
 =head1 SEE ALSO
 
 L<Perinci::Object>
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Perinci-Object>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Perinci-Object>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Perinci-Object>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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
### Perinci/Object/EnvResultMulti.pm ###
 package Perinci::Object::EnvResultMulti;
 
 our $DATE = '2015-09-03'; # DATE
 our $VERSION = '0.24'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 
 use parent qw(Perinci::Object::EnvResult);
 
 sub new {
     my ($class, $res) = @_;
     $res //= [200, "Success/no items"];
     my $obj = \$res;
     bless $obj, $class;
 }
 
 sub add_result {
     my ($self, $status, $message, $extra) = @_;
     my $num_ok  = 0;
     my $num_nok = 0;
 
     push @{ ${$self}->[3]{results} },
         {%{ $extra // {} }, status=>$status, message=>$message};
     for (@{ ${$self}->[3]{results} // [] }) {
         if ($_->{status} =~ /\A(2|304)/) {
             $num_ok++;
         } else {
             $num_nok++;
         }
     }
     if ($num_ok) {
         if ($num_nok) {
             ${$self}->[0] = 207;
             ${$self}->[1] = "Partial success";
         } else {
             ${$self}->[0] = 200;
             ${$self}->[1] = "All success";
         }
     } else {
         ${$self}->[0] = $status;
         ${$self}->[1] = $message;
     }
 }
 
 1;
 # ABSTRACT: Represent enveloped result (multistatus)
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Perinci::Object::EnvResultMulti - Represent enveloped result (multistatus)
 
 =head1 VERSION
 
 This document describes version 0.24 of Perinci::Object::EnvResultMulti (from Perl distribution Perinci-Object), released on 2015-09-03.
 
 =head1 SYNOPSIS
 
  use Perinci::Object::EnvResultMulti;
  use Data::Dump; # for dd()
 
  sub myfunc {
      ...
 
      # if unspecified, the default status will be [200, "Success/no items"]
      my $envres = Perinci::Object::EnvResultMulti->new;
 
      # then you can add result for each item
      $envres->add_result(200, "OK", {item_id=>1});
      $envres->add_result(202, "OK", {item_id=>2, note=>"blah"});
      $envres->add_result(404, "Not found", {item_id=>3});
      ...
 
      # if you add a success status, the overall status will still be 200
 
      # if you add a non-success staus, the overall status will be 207, or
      # the non-success status (if no success has been added)
 
      # finally, return the result
      return $envres->as_struct;
 
      # the result from the above will be: [207, "Partial success", undef,
      # {results => [
      #     {success=>200, message=>"OK", item_id=>1},
      #     {success=>201, message=>"OK", item_id=>2, note=>"blah"},
      #     {success=>404, message=>"Not found", item_id=>3},
      # ]}]
  } # myfunc
 
 =head1 DESCRIPTION
 
 This class is a subclass of L<Perinci::Object::EnvResult> and provide a
 convenience method when you want to use multistatus/detailed per-item results
 (specified in L<Rinci> 1.1.63: C<results> result metadata property). In this
 case, response status can be 200, 207, or non-success. As you add more per-item
 results, this class will set/update the overall response status for you.
 
 =head1 METHODS
 
 =head2 new($res) => OBJECT
 
 Create a new object from C<$res> enveloped result array. If C<$res> is not
 specified, the default is C<< [200, "Success/no items"] >>.
 
 =head2 $envres->add_result($status, $message, \%extra)
 
 Add an item result.
 
 =head1 SEE ALSO
 
 L<Perinci::Object>
 
 L<Perinci::Object::EnvResult>
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Perinci-Object>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Perinci-Object>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Perinci-Object>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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
### Perinci/Object/Function.pm ###
 package Perinci::Object::Function;
 
 our $DATE = '2015-09-03'; # DATE
 our $VERSION = '0.24'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 
 use parent qw(Perinci::Object::Metadata);
 
 sub type { "function" }
 
 # convenience for accessing features property
 sub feature {
     my $self = shift;
     my $name = shift;
     if (@_) {
         die "1.0 can't set feature" if $self->v eq 1.0;
         my $value = shift;
         ${$self}->{features} //= {};
         my $old = ${$self}->{features}{$name};
         ${$self}->{features}{$name} = $value;
         return $old;
     } else {
         ${$self}->{features}{$name};
     }
 }
 
 sub features {
     my $self = shift;
     ${$self}->{features} // {};
 }
 
 # transaction can be used to emulate dry run, by calling with -tx_action =>
 # 'check_state' only
 sub can_dry_run {
     my $self = shift;
     my $ff = ${$self}->{features} // {};
     $ff->{dry_run} // $ff->{tx} && $ff->{tx}{v} == 2;
 }
 
 # convenience for accessing args property
 sub arg {
     my $self = shift;
     my $name = shift;
     if (@_) {
         die "1.0 can't set arg" if $self->v eq 1.0;
         my $value = shift;
         ${$self}->{args} //= {};
         my $old = ${$self}->{args}{$name};
         ${$self}->{args}{$name} = $value;
         return $old;
     } else {
         ${$self}->{args}{$name};
     }
 }
 
 1;
 # ABSTRACT: Represent function metadata
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Perinci::Object::Function - Represent function metadata
 
 =head1 VERSION
 
 This document describes version 0.24 of Perinci::Object::Function (from Perl distribution Perinci-Object), released on 2015-09-03.
 
 =head1 SYNOPSIS
 
  use Perinci::Object;
 
  $SPEC{foo} = {
      v        => 1.1,
      args     => { b => {schema=>'int', req=>0} },
      features => {idempotent=>1},
  };
  my $risub = risub $SPEC{foo};
  print $risub->feature('idempotent'), # 1
        $risub->arg('b')->{req},       # 0
        $risub->arg('a');              # undef
 
 =head1 DESCRIPTION
 
 This class provides an object-oriented interface for function metadata.
 
 =head1 METHODS
 
 =head2 new($meta) => OBJECT
 
 Create a new object from $meta. If $meta is undef, creates an empty metadata.
 
 =head2 $risub->type => str
 
 Will return C<function>.
 
 =head2 $risub->features => HASH
 
 Return the C<features> property.
 
 =head2 $risub->feature(NAME[, VALUE])
 
 Get or set named feature (B<features> property in metadata). If a feature
 doesn't exist, undef will be returned.
 
 =head2 $risub->can_dry_run => BOOL
 
 Check whether function can do dry run, either from the C<dry_run> feature, or
 from the C<tx> feature. (Transaction can be used to emulate dry run, by calling
 the function with C<< -tx_action => 'check_state' >> only.)
 
 =head2 $risub->arg(NAME[, VALUE])
 
 Get or set argument (B<args> property in metadata). If an argument doesn't
 exist, undef will be returned.
 
 =head1 SEE ALSO
 
 L<Perinci::Object>
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Perinci-Object>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Perinci-Object>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Perinci-Object>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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
### Perinci/Object/Metadata.pm ###
 package Perinci::Object::Metadata;
 
 our $DATE = '2015-09-03'; # DATE
 our $VERSION = '0.24'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 use String::Trim::More qw(trim_blank_lines);
 
 sub new {
     my ($class, $meta) = @_;
     $meta //= {};
     my $obj = \$meta;
     bless $obj, $class;
 }
 
 sub v {
     my $self = shift;
     ${$self}->{v} // 1.0;
 }
 
 sub type {
     die "BUG: type() must be subclassed";
 }
 
 sub as_struct {
     my $self = shift;
     ${$self};
 }
 
 sub langprop {
     my $self = shift;
     my $opts;
     if (ref($_[0]) eq 'HASH') {
         $opts = shift;
     } else {
         $opts = {};
     }
     my $prop = shift;
 
     my $deflang = ${$self}->{default_lang} // "en_US";
     my $olang   = $opts->{lang} || $ENV{LANGUAGE} || $ENV{LANG} || $deflang;
     $olang =~ s/\W.+//; # change "en_US.UTF-8" to "en_US"
     $olang = "en_US" if $olang eq 'C';
     (my $olang2 = $olang) =~ s/\A([a-z]{2})_[A-Z]{2}\z/$1/; # change "en_US" to "en"
     my $mark    = $opts->{mark_different_lang} // 1;
     #print "deflang=$deflang, olang=$olang, mark_different_lang=$mark\n";
 
     my @k;
     if ($olang eq $deflang) {
         @k = ([$olang, $prop, 0]);
     } else {
         @k = (
             [$olang, "$prop.alt.lang.$olang", 0],
             ([$olang2, "$prop.alt.lang.$olang2", 0]) x !!($olang2 ne $olang),
             [$deflang, $prop, $mark],
         );
     }
 
     my $v;
   GET:
     for my $k (@k) {
         #print "k=".join(", ", @$k)."\n";
         $v = ${$self}->{$k->[1]};
         if (defined $v) {
             if ($k->[2]) {
                 my $has_nl = $v =~ s/\n\z//;
                 $v = "{$olang|$k->[0] $v}" . ($has_nl ? "\n" : "");
             }
             $v = trim_blank_lines($v);
             last GET;
         }
     }
 
     if (@_) {
         # set value
         ${$self}->{$k[0][1]} = $_[0];
     }
 
     $v;
 }
 
 sub name {
     my $self = shift;
     my $opts;
     if (@_ && ref($_[0]) eq 'HASH') {
         $opts = shift;
     } else {
         $opts = {};
     }
     $self->langprop($opts, "name", @_);
 }
 
 sub caption {
     my $self = shift;
     my $opts;
     if (@_ && ref($_[0]) eq 'HASH') {
         $opts = shift;
     } else {
         $opts = {};
     }
     $self->langprop($opts, "caption", @_);
 }
 
 sub summary {
     my $self = shift;
     my $opts;
     if (@_ && ref($_[0]) eq 'HASH') {
         $opts = shift;
     } else {
         $opts = {};
     }
     $self->langprop($opts, "summary", @_);
 }
 
 sub description {
     my $self = shift;
     my $opts;
     if (@_ && ref($_[0]) eq 'HASH') {
         $opts = shift;
     } else {
         $opts = {};
     }
     $self->langprop($opts, "description", @_);
 }
 
 1;
 # ABSTRACT: Base class for Perinci::Object metadata classes
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Perinci::Object::Metadata - Base class for Perinci::Object metadata classes
 
 =head1 VERSION
 
 This document describes version 0.24 of Perinci::Object::Metadata (from Perl distribution Perinci-Object), released on 2015-09-03.
 
 =head1 METHODS
 
 =head2 new => obj
 
 Constructor.
 
 =head2 v => float
 
 Get version.
 
 =head2 as_struct => hash
 
 Get underlying data structure.
 
 =head2 type => str
 
 Return type (e.g. C<function>, C<package>).
 
 =head2 langprop([ \%opts, ]$prop[, $new_value])
 
 Get or set property value in the specified language (i.e., either in C<prop> or
 C<prop.alt.lang.XXX> properties).
 
 Known options:
 
 =over 4
 
 =item * lang => STR
 
 Defaults to metadata's C<default_lang> (which in turns default to C<en_US> if
 unspecified).
 
 =item * mark_different_lang => BOOL (defaults to 1)
 
 If set to true, text with different language than the language requested will be
 marked, e.g. C<"I love you"> requested in Indonesian language where the value
 for that language is unavailable will result in C<"{en_US I love you}"> being
 returned.
 
 =back
 
 =head2 name([ $new_value ]) => $value
 
 Get or set C<name> property. Will call C<langprop()>.
 
 =head2 summary([ $new_value ]) => $value
 
 Get or set C<summary> property. Will call C<langprop()>.
 
 =head2 description([ $new_value ]) => $value
 
 Get or set C<description> property. Will call C<langprop()>.
 
 =head2 caption([ $new_value ]) => $value
 
 Get or set C<caption> property. Will call C<langprop()>.
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Perinci-Object>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Perinci-Object>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Perinci-Object>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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
### Perinci/Object/Package.pm ###
 package Perinci::Object::Package;
 
 our $DATE = '2015-09-03'; # DATE
 our $VERSION = '0.24'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 
 use parent qw(Perinci::Object::Metadata);
 
 sub type { "package" }
 
 1;
 # ABSTRACT: Represent package metadata
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Perinci::Object::Package - Represent package metadata
 
 =head1 VERSION
 
 This document describes version 0.24 of Perinci::Object::Package (from Perl distribution Perinci-Object), released on 2015-09-03.
 
 =head1 METHODS
 
 =head2 $ripkg->type => str
 
 Will return C<package>.
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Perinci-Object>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Perinci-Object>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Perinci-Object>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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
### Perinci/Object/ResMeta.pm ###
 package Perinci::Object::ResMeta;
 
 our $DATE = '2015-09-03'; # DATE
 our $VERSION = '0.24'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 
 use parent qw(Perinci::Object::Metadata);
 
 sub type { "resmeta" }
 
 1;
 # ABSTRACT: Represent function/method result metadata
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Perinci::Object::ResMeta - Represent function/method result metadata
 
 =head1 VERSION
 
 This document describes version 0.24 of Perinci::Object::ResMeta (from Perl distribution Perinci-Object), released on 2015-09-03.
 
 =head1 METHODS
 
 =head2 $riresmeta->type => str
 
 Will return C<resmeta>.
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Perinci-Object>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Perinci-Object>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Perinci-Object>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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
### Perinci/Object/Variable.pm ###
 package Perinci::Object::Variable;
 
 our $DATE = '2015-09-03'; # DATE
 our $VERSION = '0.24'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 
 use parent qw(Perinci::Object::Metadata);
 
 sub type { "variable" }
 
 1;
 # ABSTRACT: Represent variable metadata
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Perinci::Object::Variable - Represent variable metadata
 
 =head1 VERSION
 
 This document describes version 0.24 of Perinci::Object::Variable (from Perl distribution Perinci-Object), released on 2015-09-03.
 
 =head1 METHODS
 
 =head2 $rivar->type => str
 
 Will return C<variable>.
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Perinci-Object>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Perinci-Object>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Perinci-Object>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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
### Perinci/Result/Format.pm ###
 package Perinci::Result::Format;
 
 our $DATE = '2015-10-20'; # DATE
 our $VERSION = '0.43'; # VERSION
 
 use 5.010001;
 use strict;
 use warnings;
 
 our $Enable_Decoration = 1;
 our $Enable_Cleansing  = 0;
 
 # text formats are special. since they are more oriented towards human instead
 # of machine, we remove envelope when status is 2xx, so users only see content.
 
 # XXX color theme?
 
 my $format_text = sub {
     my ($format, $res) = @_;
 
     my $stack_trace_printed;
 
     my $print_err = sub {
         require Color::ANSI::Util;
         require Term::Detect::Software;
 
         my $use_color = $ENV{COLOR} // 1;
         my $terminfo = Term::Detect::Software::detect_terminal_cached();
         $use_color = 0 if !$terminfo->{color_depth};
         my $colorize = sub {
             my ($color, $str) = @_;
             if ($use_color) {
                 if (ref($color) eq 'ARRAY') {
                     (defined($color->[0]) ?
                          Color::ANSI::Util::ansifg($color->[0]):"").
                                (defined($color->[1]) ?
                                     Color::ANSI::Util::ansibg($color->[1]):"").
                                           $str . "\e[0m";
                 } else {
                     Color::ANSI::Util::ansifg($color) . $str . "\e[0m";
                 }
             } else {
                 $str;
             }
         };
 
         my $res = shift;
         my $out = $colorize->("cc0000", "ERROR $res->[0]") .
             ($res->[1] ? ": $res->[1]" : "");
         $out =~ s/\n+\z//;
         my $clog; $clog = $res->[3]{logs}[0]
             if $res->[3] && $res->[3]{logs};
         if ($clog->{file} && $clog->{line}) {
             $out .= " (at ".$colorize->('3399cc', $clog->{file}).
                 " line ".$colorize->('3399cc', $clog->{line}).")";
         }
         $out .= "\n";
         if ($clog->{stack_trace} && $INC{"Carp/Always.pm"} &&
                 !$stack_trace_printed) {
             require Data::Dump::OneLine;
             my $i;
             for my $c (@{ $clog->{stack_trace} }) {
                 next unless $i++; # skip first entry
                 my $args;
                 if (!$c->[4]) {
                     $args = "()";
                 } elsif (!ref($c->[4])) {
                     $args = "(...)";
                 } else {
                     # periutil 0.37+ stores call arguments in [4]
 
                     # XXX a flag to let user choose which
 
                     # dump version
                     #$args = Data::Dump::OneLine::dump1(@{ $c->[4] });
                     #$args = "($args)" if @{$c->[4]} < 2;
 
                     # stringify version
                     $args = Data::Dump::OneLine::dump1(
                         map {defined($_) ? "$_":$_} @{ $c->[4] });
                     $args = "($args)" if @{$c->[4]} == 1;
                 }
                 $out .= "    $c->[3]${args} called at $c->[1] line $c->[2]\n";
             }
             $stack_trace_printed++;
         }
         $out;
     };
 
     if (!defined($res->[2])) {
         my $out = $res->[0] =~ /\A(?:2..|304)\z/ ? "" : $print_err->($res);
         my $max = 30;
         my $i = 0;
         my $prev = $res;
         while (1) {
             if ($i > $max) {
                 $out .= "  Previous error list too deep, stopping here\n";
                 last;
             }
             last unless $prev = $prev->[3]{prev};
             last unless ref($prev) eq 'ARRAY';
             $out .= "  " . $print_err->($prev);
             $i++;
         }
         return $out;
     }
     my ($r, $opts);
     if ($res->[0] =~ /\A2../) {
         $r = $res->[2];
         my $rfo = $res->[3]{format_options} // {};
         if ($rfo->{$format}) {
             $opts = $rfo->{$format};
         } elsif ($rfo->{any}) {
             $opts = $rfo->{any};
         }
     } else {
         $r = $res;
     }
     $opts //= {};
     if ($format eq 'text') {
         return Data::Format::Pretty::format_pretty(
             $r, {%$opts, module=>'Console'});
     }
     if ($format eq 'text-simple') {
         return Data::Format::Pretty::format_pretty(
             $r, {%$opts, module=>'SimpleText'});
     }
     if ($format eq 'text-pretty') {
         return Data::Format::Pretty::format_pretty(
             $r, {%$opts, module=>'Text'});
     }
 };
 
 our %Formats = (
     # YAML::Tiny::Color currently does not support circular refs
     yaml          => ['YAML', 'text/yaml', {circular=>0}],
     json          => ['CompactJSON', 'application/json', {circular=>0}],
     'json-pretty' => ['JSON', 'application/json', {circular=>0}],
     text          => [$format_text, 'text/plain', {circular=>0}],
     'text-simple' => [$format_text, 'text/plain', {circular=>0}],
     'text-pretty' => [$format_text, 'text/plain', {circular=>0}],
     'perl'        => ['Perl', 'text/x-perl', {circular=>1}],
     #'php'         => ['PHP', 'application/x-httpd-php', {circular=>0}],
     'phpserialization' => ['PHPSerialization', 'application/vnd.php.serialized', {circular=>0}],
     'ruby'        => ['Ruby', 'application/x-ruby', {circular=>1}],
 );
 
 sub format {
     require Data::Format::Pretty;
 
     my ($res, $format, $is_naked) = @_;
 
     my $fmtinfo = $Formats{$format} or return undef;
     my $formatter = $fmtinfo->[0];
 
     state $cleanser;
     if ($Enable_Cleansing && !$fmtinfo->[2]{circular}) {
         # currently we only have one type of cleansing, oriented towards JSON
         if (!$cleanser) {
             require Data::Clean::JSON;
             $cleanser = Data::Clean::JSON->get_cleanser;
         }
         $res = $cleanser->clone_and_clean($res);
     }
 
     my $deco = $Enable_Decoration;
 
     if (ref($formatter) eq 'CODE') {
         return $formatter->($format, $res);
     } else {
         my %o;
         $o{color} = 0 if !$deco && $format =~ /json|yaml|perl/;
         my $data = $is_naked ? $res->[2] : $res;
         return Data::Format::Pretty::format_pretty(
             $data, {%o, module=>$formatter});
     }
 }
 
 1;
 # ABSTRACT: Format envelope result
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Perinci::Result::Format - Format envelope result
 
 =head1 VERSION
 
 This document describes version 0.43 of Perinci::Result::Format (from Perl distribution Perinci-Result-Format), released on 2015-10-20.
 
 =head1 SYNOPSIS
 
 =head1 DESCRIPTION
 
 This module formats enveloped result to YAML, JSON, etc. It uses
 L<Data::Format::Pretty> for the backend. It is used by other Perinci modules
 like L<Perinci::CmdLine> and L<Perinci::Access::HTTP::Server>.
 
 The default supported formats are:
 
 =over 4
 
 =item * json
 
 Using Data::Format::Pretty::CompactJSON.
 
 =item * json-pretty
 
 Using Data::Format::Pretty::JSON.
 
 =item * text-simple
 
 Using Data::Format::Pretty::SimpleText.
 
 =item * text-pretty
 
 Using Data::Format::Pretty::Text.
 
 =item * text
 
 Using Data::Format::Pretty::Console.
 
 =item * yaml
 
 Using Data::Format::Pretty::YAML.
 
 =item * perl
 
 Using Data::Format::Pretty::Perl.
 
 =item * phpserialization
 
 Using Data::Format::Pretty::PHPSerialization.
 
 =item * ruby
 
 Using Data::Format::Pretty::Ruby.
 
 =back
 
 =for Pod::Coverage .*
 
 =head1 VARIABLES
 
 =head1 %Perinci::Result::Format::Formats => HASH
 
 Contains a mapping between format names and Data::Format::Pretty::* module
 names + MIME type.
 
 =head1 $Enable_Decoration => BOOL (default: 1)
 
 Decorations include color or other markup, which might make a data structure
 like JSON or YAML string become invalid JSON/YAML. This should be turned off if
 one wants to send the formatting over network.
 
 =head1 $Enable_Cleansing => BOOL (default: 0)
 
 If enabled, cleansing will be done to data to help make sure that data does not
 contain item that cannot be handled by formatter. for example, JSON format
 cannot handle circular references or complex types other than hash/array.
 
 =head1 FUNCTIONS
 
 None is currently exported/exportable.
 
 =head1 format($res, $format[ , $is_naked=0 ]) => STR
 
 Format enveloped result C<$res> with format named C<$format>.
 
 Result metadata (C<< $res->[3] >>) is also checked for key named
 C<format_options>. The value should be a hash like this C<< { FORMAT_NAME =>
 OPTS, ... } >>. FORMAT_NAME can be C<any> to mean any format. This way, function
 results can specify the details of formatting. An example enveloped result:
 
  [200, "OK", ["foo", "bar", "baz"], {
      format_options => {
          "text"        => {list_max_columns=>1},
          "text-pretty" => {list_max_columns=>1},
      }
  }]
 
 The above result specifies that if it is displayed using C<text> or
 C<text-pretty> format, it should be displayed in one columns instead of
 multicolumns.
 
 =head1 RESULT METADATA
 
 =over
 
 =item * property: format_options => HASH
 
 =back
 
 =head1 FAQ
 
 =head2 How to list supported formats?
 
 Simply:
 
  my @supported_formats = keys %Perinci::Result::Format::Formats;
 
 =head2 How to add support for new formats?
 
 First make sure that Data::Format::Pretty::<FORMAT> module is available for your
 format. Look on CPAN. If it's not, i't also not hard to create one.
 
 Then, add your format to %Perinci::Result::Format::Formats hash:
 
  use Perinci::Result::Format;
 
  # this means format named 'xml' will be handled by Data::Format::Pretty::XML
  $Perinci::Result::Format::Formats{xml} = ['XML', 'text/xml'];
 
 =head1 SEE ALSO
 
 L<Data::Format::Pretty>
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Perinci-Result-Format>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Perinci-Result-Format>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Perinci-Result-Format>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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
### Perinci/Result/Format/Lite.pm ###
 package Perinci::Result::Format::Lite;
 
 our $DATE = '2015-09-30'; # DATE
 our $VERSION = '0.06'; # VERSION
 
 use 5.010001;
 #IFUNBUILT
 use strict;
 use warnings;
 #END IFUNBUILT
 
 use List::Util qw(first);
 
 require Exporter;
 our @ISA = qw(Exporter);
 our @EXPORT_OK = qw(format);
 
 # copy-pasted from List::MoreUtils::PP
 sub firstidx (&@) {
     my $f = shift;
     foreach my $i ( 0 .. $#_ )
         {
             local *_ = \$_[$i];
             return $i if $f->();
         }
     return -1;
 }
 
 sub _json {
     state $json = do {
         if    (eval { require JSON::XS; 1 })   { JSON::XS->new->canonical(1)->allow_nonref }
         elsif (eval { require JSON::Tiny::Subclassable; 1 }) { JSON::Tiny::Subclassable->new }
         elsif (eval { require JSON::PP; 1 })   { JSON::PP->new->canonical(1)->allow_nonref }
         else { die "Can't find any JSON module" }
     };
     $json;
 };
 
 sub __cleanse {
     state $cleanser = do {
         eval { require Data::Clean::JSON; 1 };
         if ($@) {
             undef;
         } else {
             Data::Clean::JSON->get_cleanser;
         }
     };
     if ($cleanser) {
         $cleanser->clean_in_place($_[0]);
     } else {
         $_[0];
     }
 }
 
 sub __gen_table {
     my ($data, $header_row, $resmeta, $is_pretty) = @_;
 
     $resmeta //= {};
 
     my @columns;
     if ($header_row) {
         @columns = @{$data->[0]};
     } else {
         @columns = map {"col$_"} 0..@{$data->[0]}-1;
     }
 
     my $column_orders; # e.g. [col2, col1, col3, ...]
   SET_COLUMN_ORDERS: {
 
         # find column orders from 'table_column_orders' in result metadata (or
         # from env)
         my $tcos;
         if ($ENV{FORMAT_PRETTY_TABLE_COLUMN_ORDERS}) {
             $tcos = _json->encode($ENV{FORMAT_PRETTY_TABLE_COLUMN_ORDERS});
         } elsif (my $rfos = ($resmeta->{'cmdline.format_options'} //
                                  $resmeta->{format_options})) {
             my $rfo = $rfos->{'text-pretty'} // $rfos->{text} // $rfos->{any};
             if ($rfo) {
                 $tcos = $rfo->{table_column_orders};
             }
         }
         if ($tcos) {
             # find an entry in tcos that @columns contains all the columns of
           COLS:
             for my $cols (@$tcos) {
                 for my $col (@$cols) {
                     next COLS unless first {$_ eq $col} @columns;
                 }
                 $column_orders = $cols;
                 last SET_COLUMN_ORDERS;
             }
         }
 
         # find column orders from table spec
         $column_orders = $resmeta->{'table.fields'};
     }
 
     # reorder each row according to requested column order
     if ($column_orders) {
         # 0->2, 1->0, ... (map column position from unordered to ordered)
         my @map0 = sort {
             my $idx_a = firstidx(sub {$_ eq $a->[1]},
                                                   @$column_orders) // 9999;
             my $idx_b = firstidx(sub {$_ eq $b->[1]},
                                                   @$column_orders) // 9999;
             $idx_a <=> $idx_b || $a->[1] cmp $b->[1];
         } map {[$_, $columns[$_]]} 0..@columns-1;
         #use DD; dd \@map0;
         my @map;
         for (0..@map0-1) {
             $map[$_] = $map0[$_][0];
         }
         #use DD; dd \@map;
         my $newdata = [];
         for my $row (@$data) {
             my @newrow;
             for (0..@map-1) { $newrow[$_] = $row->[$map[$_]] }
             push @$newdata, \@newrow;
         }
         $data = $newdata;
     }
 
     if ($is_pretty) {
         require Text::Table::Tiny;
         Text::Table::Tiny::table(rows=>$data, header_row=>$header_row) . "\n";
     } else {
         no warnings 'uninitialized';
         shift @$data if $header_row;
         join("", map {join("\t", @$_)."\n"} @$data);
     }
 }
 
 sub format {
     my ($res, $format, $is_naked, $cleanse) = @_;
 
     if ($format =~ /\Atext(-simple|-pretty)?\z/) {
         my $is_pretty = $format eq 'text-pretty' ? 1 :
             $format eq 'text-simple' ? 0 : (-t STDOUT);
         no warnings 'uninitialized';
         if ($res->[0] !~ /^(2|304)/) {
             my $fres = "ERROR $res->[0]: $res->[1]";
             if (my $prev = $res->[3]{prev}) {
                 $fres .= " ($prev->[0]: $prev->[1])";
             }
             return "$fres\n";
         } elsif ($res->[3] && $res->[3]{"x.hint.result_binary"}) {
             return $res->[2];
         } else {
             require Data::Check::Structure;
             my $data = $res->[2];
             my $max = 5;
             if (!ref($data)) {
                 $data //= "";
                 $data .= "\n" unless !length($data) || $data =~ /\n\z/;
                 return $data;
             } elsif (ref($data) eq 'ARRAY' && !@$data) {
                 return "";
             } elsif (Data::Check::Structure::is_aos($data, {max=>$max})) {
                 return join("", map {"$_\n"} @$data);
             } elsif (Data::Check::Structure::is_aoaos($data, {max=>$max})) {
                 return __gen_table($data, 0, $res->[3], $is_pretty);
             } elsif (Data::Check::Structure::is_hos($data, {max=>$max})) {
                 $data = [map {[$_, $data->{$_}]} sort keys %$data];
                 unshift @$data, ["key", "value"];
                 return __gen_table($data, 1, $res->[3], $is_pretty);
             } elsif (Data::Check::Structure::is_aohos($data, {max=>$max})) {
                 # collect all mentioned fields
                 my %fieldnames;
                 for my $row (@$data) {
                     $fieldnames{$_}++ for keys %$row;
                 }
                 my @fieldnames = sort keys %fieldnames;
                 my $newdata = [];
                 for my $row (@$data) {
                     push @$newdata, [map {$row->{$_}} @fieldnames];
                 }
                 unshift @$newdata, \@fieldnames;
                 return __gen_table($newdata, 1, $res->[3], $is_pretty);
             } else {
                 $format = 'json-pretty';
             }
         }
     }
 
     $res = $res->[2] if $is_naked;
 
     warn "Unknown format '$format', fallback to json-pretty"
         unless $format =~ /\Ajson(-pretty)?\z/;
     __cleanse($res) if ($cleanse//1);
     if ($format eq 'json') {
         return _json->encode($res) . "\n";
     } else {
         _json->pretty(1);
         return _json->encode($res);
     }
 }
 
 1;
 # ABSTRACT: Format enveloped result
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Perinci::Result::Format::Lite - Format enveloped result
 
 =head1 VERSION
 
 This document describes version 0.06 of Perinci::Result::Format::Lite (from Perl distribution Perinci-Result-Format-Lite), released on 2015-09-30.
 
 =head1 SYNOPSIS
 
 =head1 DESCRIPTION
 
 =for Pod::Coverage ^(firstidx)$
 
 =head1 FUNCTIONS
 
 =head2 format($res, $format[ , $is_naked=0, $cleanse=1 ]) => str
 
 =head1 ENVIRONMENT
 
 =head2 FORMAT_PRETTY_TABLE_COLUMN_ORDERS => array (json)
 
 Set the default of C<table_column_orders> in C<format_options> in result
 metadata, similar to what's implemented in L<Perinci::Result::Format> and
 L<Data::Format::Pretty::Console>.
 
 =head1 SEE ALSO
 
 L<Perinci::Result::Format>, a more heavyweight version of this module.
 
 L<Perinci::CmdLine::Lite> uses this module to format enveloped result.
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Perinci-Result-Format-Lite>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Perinci-Result-Format-Lite>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Perinci-Result-Format-Lite>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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
### Perinci/Sub/CoerceArgs.pm ###
 package Perinci::Sub::CoerceArgs;
 
 our $DATE = '2015-09-30'; # DATE
 our $VERSION = '0.12'; # VERSION
 
 use 5.010001;
 use strict;
 use warnings;
 #use Log::Any '$log';
 
 use Scalar::Util qw(blessed looks_like_number);
 
 use Exporter;
 our @ISA = qw(Exporter);
 our @EXPORT_OK = qw(
                        coerce_args
                );
 
 our %SPEC;
 
 # a cheap Module::Load
 #sub _require_class {
 #    my $class = shift;
 #    (my $class_pm = $class) =~ s!::!/!g; $class_pm .= ".pm";
 #    require $class_pm;
 #}
 
 sub _coerce_to_datetime {
     my ($args, $arg_name) = @_;
 
     my $val = $args->{$arg_name};
 
     if ($val =~ /\A\d{8,}\z/) {
         require DateTime;
         $args->{$arg_name} = DateTime->from_epoch(
             epoch => $val,
             time_zone => $ENV{TZ} // "UTC",
         );
         return [200];
     } elsif ($val =~ m!\A
                        (\d{4})[/-](\d{1,2})[/-](\d{1,2})
                        (?:[ Tt](\d{1,2}):(\d{1,2}):(\d{1,2}))?
                        \z!x) {
         require DateTime;
         $args->{$arg_name} = DateTime->new(
             year => $1, month => $2, day => $3,
             hour => $4 // 0,
             minute => $4 // 0,
             second => $4 // 0,
             time_zone => $ENV{TZ} // "UTC",
         );
         return [200];
     } elsif (blessed($val)) {
         if ($val->isa("DateTime")) {
             # no-op
             return [200];
         } elsif ($val->isa("Time::Moment")) {
             require DateTime;
             my $tz = sprintf("%s%04d",
                              $val->offset < 0 ? "-":"+",
                              abs($val->offset/60*100));
             $args->{$arg_name} = DateTime->from_epoch(
                 epoch => $val->epoch,
                 time_zone => $tz,
             );
             return [200];
         }
     }
 
     return [400, "Can't coerce '$arg_name' to DateTime object: " .
                 "'$args->{$arg_name}'"];
 }
 
 sub _coerce_to_time_moment {
     my ($args, $arg_name) = @_;
 
     my $val = $args->{$arg_name};
 
     # XXX just use Time::Moment's from_string()?
     if ($val =~ /\A\d{8,}\z/) {
         require Time::Moment;
         $args->{$arg_name} = Time::Moment->from_epoch($val);
         return [200];
     } elsif ($val =~ m!\A
                        (\d{4})[/-](\d{1,2})[/-](\d{1,2})
                        (?:[ Tt](\d{1,2}):(\d{1,2}):(\d{1,2}))?
                        \z!x) {
         # XXX parse time zone offset
         require Time::Moment;
         $args->{$arg_name} = Time::Moment->new(
             year => $1, month => $2, day => $3,
             hour => $4 // 0,
             minute => $4 // 0,
             second => $4 // 0,
         );
         return [200];
     } elsif (blessed($val)) {
         if ($val->isa("Time::Moment")) {
             # no-op
             return [200];
         } elsif ($val->isa("DateTime")) {
             require Time::Moment;
             $args->{$arg_name} = Time::Moment->from_object($val);
             return [200];
         }
     }
 
     return [400, "Can't coerce '$arg_name' to Time::Moment object: " .
                 "'$args->{$arg_name}'"];
 }
 
 sub _coerce_to_epoch {
     my ($args, $arg_name) = @_;
 
     my $val = $args->{$arg_name};
 
     if (looks_like_number($val)) {
         # no-op
         return [200];
     } elsif ($val =~ m!\A
                        (\d{4})[/-](\d{1,2})[/-](\d{1,2})
                        (?:[ Tt](\d{1,2}):(\d{1,2}):(\d{1,2}))?
                        \z!x) {
         require DateTime;
         $args->{$arg_name} = DateTime->new(
             year => $1, month => $2, day => $3,
             hour => $4 // 0,
             minute => $4 // 0,
             second => $4 // 0,
             time_zone => $ENV{TZ} // "UTC",
         )->epoch;
         return [200];
     } elsif (blessed($val)) {
         if ($val->isa("DateTime")) {
             $args->{$arg_name} = $val->epoch;
             return [200];
         } elsif ($val->isa("Time::Moment")) {
             $args->{$arg_name} = $val->epoch;
             return [200];
         }
     }
 
     return [400, "Can't coerce epoch " .
                 "'$arg_name' from '$args->{$arg_name}'"];
 }
 
 sub _coerce_to_datetime_duration {
     my ($args, $arg_name) = @_;
 
     my $val = $args->{$arg_name};
 
     my $d;
 
     if ($val =~ /\A\+?\d+(?:\.\d*)?\z/) {
         require DateTime::Duration;
         my $days = int($val/86400);
         my $secs = $val - $days*86400;
         $args->{$arg_name} = DateTime::Duration->new(
             days    => $days,
             seconds => $secs,
         );
         return [200];
     } elsif ($val =~ /\AP
                  (?:([0-9]+(?:\.[0-9]+)?)Y)?
                  (?:([0-9]+(?:\.[0-9]+)?)M)?
                  (?:([0-9]+(?:\.[0-9]+)?)W)?
                  (?:([0-9]+(?:\.[0-9]+)?)D)?
                  (?: T
                      (?:([0-9]+(?:\.[0-9]+)?)H)?
                      (?:([0-9]+(?:\.[0-9]+)?)M)?
                      (?:([0-9]+(?:\.[0-9]+)?)S)?
                  )?\z/x) {
         require DateTime::Duration;
         $args->{$arg_name} = DateTime::Duration->new(
             years   => $1 || 0,
             months  => $2 || 0,
             weeks   => $3 || 0,
             days    => $4 || 0,
             hours   => $5 || 0,
             minutes => $6 || 0,
             seconds => $7 || 0,
         );
         return [200];
     } elsif (blessed($val)) {
         if ($val->isa("DateTime::Duration")) {
             # no-op
             return [200];
         }
     } elsif (eval { require Time::Duration::Parse::AsHash; $d = Time::Duration::Parse::AsHash::parse_duration($val) } && !$@) {
         require DateTime::Duration;
         $args->{$arg_name} = DateTime::Duration->new(
             years   => $d->{years}   || 0,
             months  => $d->{months}  || 0,
             weeks   => $d->{weeks}   || 0,
             days    => $d->{days}    || 0,
             hours   => $d->{hours}   || 0,
             minutes => $d->{minutes} || 0,
             seconds => $d->{seconds} || 0,
         );
         return [200];
     }
 
     return [400, "Can't coerce '$arg_name' to DateTime::Duration object: " .
                 "'$args->{$arg_name}'"];
 }
 
 sub _coerce_to_secs {
     my ($args, $arg_name) = @_;
 
     my $val = $args->{$arg_name};
 
     my $d;
 
     if ($val =~ /\A\+?\d+(?:\.\d*)?\z/) {
         # no-op
         return [200];
     } elsif ($val =~ /\AP
                  (?:([0-9]+(?:\.[0-9]+)?)Y)?
                  (?:([0-9]+(?:\.[0-9]+)?)M)?
                  (?:([0-9]+(?:\.[0-9]+)?)W)?
                  (?:([0-9]+(?:\.[0-9]+)?)D)?
                  (?: T
                      (?:([0-9]+(?:\.[0-9]+)?)H)?
                      (?:([0-9]+(?:\.[0-9]+)?)M)?
                      (?:([0-9]+(?:\.[0-9]+)?)S)?
                  )?\z/x) {
         $args->{$arg_name} =
             (($1//0)*365 + ($2 // 0)*30 + ($3 // 0)*7 + ($4 // 0)) * 86400 +
             ($5 // 0)*3600 + ($6 // 0)*60 + ($7 // 0);
         return [200];
     } elsif (blessed($val)) {
         if ($val->isa("DateTime::Duration")) {
             my ($y, $mon, $d, $min, $s) = $val->in_units(
                 "years", "months", "days", "minutes", "seconds");
             $args->{$arg_name} =
                 ($y*365 + $mon*30 + $d) * 86400 +
                 $min*60 + $s;
             return [200];
         }
     } elsif (eval { require Time::Duration::Parse::AsHash; $d = Time::Duration::Parse::AsHash::parse_duration($val) } && !$@) {
         $args->{$arg_name} =
             ($d->{years}   // 0) * 365*86400 +
             ($d->{months}  // 0) *  30*86400 +
             ($d->{weeks}   // 0) *   7*86400 +
             ($d->{days}    // 0) *     86400 +
             ($d->{hours}   // 0) *      3600 +
             ($d->{minutes} // 0) *        60 +
             ($d->{seconds} // 0);
         return [200];
     }
 
     return [400, "Can't coerce '$arg_name' to seconds: " .
                 "'$args->{$arg_name}'"];
 }
 
 $SPEC{coerce_args} = {
     v           => 1.1,
     summary     => 'Coerce arguments',
     description => <<'_',
 
 This routine can be used when function arguments are retrieved from strings,
 like from command-line arguments in CLI application (see
 `Perinci::CmdLine::Lite` or `Perinci::CmdLine::Classic`) or from web form
 variables in web application (see `Borang`). For convenience, object or complex
 data structure can be converted from string (e.g. `DateTime` object from strings
 like `2015-03-27` or epoch integer). And filters can be applied to
 clean/preprocess the string (e.g. remove leading/trailing blanks) beforehand.
 
 _
     args => {
         meta => {
             summary => 'Rinci function metadata',
             schema  => 'hash*',
             req     => 1,
         },
         meta_is_normalized => {
             schema => 'bool*',
         },
         args => {
             summary => 'Reference to hash which store the arguments',
             schema  => 'hash*',
         },
     },
 };
 sub coerce_args {
     my %fargs = @_;
 
     my $meta = $fargs{meta} or return [400, "Please specify meta"];
     unless ($fargs{meta_is_normalized}) {
         require Perinci::Sub::Normalize;
         $meta = Perinci::Sub::Normalize::normalize_function_metadata($meta);
     }
     my $args = $fargs{args};
 
     for my $arg_name (keys %$args) {
         my $val = $args->{$arg_name};
         next unless defined($val);
         my $arg_spec = $meta->{args}{$arg_name};
         next unless $arg_spec;
 
         if (my $filters = $arg_spec->{filters}) {
             for my $filter (@$filters) {
                 if (ref($filter) eq 'CODE') {
                     $val = $filter->($val);
                 } elsif ($filter eq 'trim') {
                     $val =~ s/\A\s+//s;
                     $val =~ s/\s+\z//s;
                 } elsif ($filter eq 'ltrim') {
                     $val =~ s/\s+\z//s;
                 } elsif ($filter eq 'rtrim') {
                     $val =~ s/\A\s+//s;
                 } else {
                     return [400, "Unknown filter '$filter' ".
                                 "for argument '$arg_name'"];
                 }
             }
             $args->{$arg_name} = $val if @$filters;
         }
 
         if (my $schema = $arg_spec->{schema}) {
             my $coerce_to = $arg_spec->{'x.perl.coerce_to'} // '';
             if ($schema->[0] eq 'obj') {
                 my $class = $schema->[1]{isa} // '';
                 # convert DateTime object from epoch/some formatted string
                 if ($class eq 'DateTime') {
                     my $coerce_res = _coerce_to_datetime($args, $arg_name);
                     return $coerce_res unless $coerce_res->[0] == 200;
                 } elsif ($class eq 'DateTime::Duration') {
                     my $coerce_res = _coerce_to_datetime_duration($args, $arg_name);
                     return $coerce_res unless $coerce_res->[0] == 200;
                 } elsif ($class eq 'Time::Moment') {
                     my $coerce_res = _coerce_to_time_moment($args, $arg_name);
                     return $coerce_res unless $coerce_res->[0] == 200;
                 }
             } elsif ($schema->[0] eq 'date') {
                 if ($coerce_to eq 'DateTime') {
                     my $coerce_res = _coerce_to_datetime($args, $arg_name);
                     return $coerce_res unless $coerce_res->[0] == 200;
                 } elsif ($coerce_to eq 'Time::Moment') {
                     my $coerce_res = _coerce_to_time_moment($args, $arg_name);
                     return $coerce_res unless $coerce_res->[0] == 200;
                 } elsif ($coerce_to eq 'int(epoch)') {
                     my $coerce_res = _coerce_to_epoch($args, $arg_name);
                     return $coerce_res unless $coerce_res->[0] == 200;
                 }
             } elsif ($schema->[0] eq 'duration') {
                 if ($coerce_to eq 'DateTime::Duration') {
                     my $coerce_res = _coerce_to_datetime_duration($args, $arg_name);
                     return $coerce_res unless $coerce_res->[0] == 200;
                 } elsif ($coerce_to eq 'int(secs)') {
                     my $coerce_res = _coerce_to_secs($args, $arg_name);
                     return $coerce_res unless $coerce_res->[0] == 200;
                 }
             }
         } # has schema
     }
 
     [200, "OK", $args];
 }
 
 1;
 # ABSTRACT: Coerce arguments
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Perinci::Sub::CoerceArgs - Coerce arguments
 
 =head1 VERSION
 
 This document describes version 0.12 of Perinci::Sub::CoerceArgs (from Perl distribution Perinci-Sub-CoerceArgs), released on 2015-09-30.
 
 =head1 SYNOPSIS
 
  use Perinci::Sub::CoerceArgs qw(coerce_args);
 
  my $res = coerce_args(meta=>$meta, args=>$args, ...);
 
 =head1 DESCRIPTION
 
 I expect this to be a temporary solution until L<Data::Sah> or
 L<Perinci::Sub::Wrapper> has this functionality.
 
 =head1 FUNCTIONS
 
 
 =head2 coerce_args(%args) -> [status, msg, result, meta]
 
 Coerce arguments.
 
 This routine can be used when function arguments are retrieved from strings,
 like from command-line arguments in CLI application (see
 C<Perinci::CmdLine::Lite> or C<Perinci::CmdLine::Classic>) or from web form
 variables in web application (see C<Borang>). For convenience, object or complex
 data structure can be converted from string (e.g. C<DateTime> object from strings
 like C<2015-03-27> or epoch integer). And filters can be applied to
 clean/preprocess the string (e.g. remove leading/trailing blanks) beforehand.
 
 This function is not exportable.
 
 Arguments ('*' denotes required arguments):
 
 =over 4
 
 =item * B<args> => I<hash>
 
 Reference to hash which store the arguments.
 
 =item * B<meta>* => I<hash>
 
 Rinci function metadata.
 
 =item * B<meta_is_normalized> => I<bool>
 
 =back
 
 Returns an enveloped result (an array).
 
 First element (status) is an integer containing HTTP status code
 (200 means OK, 4xx caller error, 5xx function error). Second element
 (msg) is a string containing error message, or 'OK' if status is
 200. Third element (result) is optional, the actual result. Fourth
 element (meta) is called result metadata and is optional, a hash
 that contains extra information.
 
 Return value:  (any)
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Perinci-Sub-CoerceArgs>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Perinci-Sub-CoerceArgs>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Perinci-Sub-CoerceArgs>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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
### Perinci/Sub/Complete.pm ###
 package Perinci::Sub::Complete;
 
 our $DATE = '2015-09-09'; # DATE
 our $VERSION = '0.82'; # VERSION
 
 use 5.010001;
 use strict;
 use warnings;
 use Log::Any::IfLOG '$log';
 
 use Complete::Util qw(hashify_answer complete_array_elem combine_answers);
 use Complete::Setting;
 use Perinci::Sub::Util qw(gen_modified_sub);
 
 require Exporter;
 our @ISA       = qw(Exporter);
 our @EXPORT_OK = qw(
                        complete_from_schema
                        complete_arg_val
                        complete_arg_elem
                        complete_cli_arg
                );
 our %SPEC;
 
 $SPEC{':package'} = {
     v => 1.1,
     summary => 'Complete command-line argument using Rinci metadata',
 };
 
 my %common_args_riap = (
     riap_client => {
         summary => 'Optional, to perform complete_arg_val to the server',
         schema  => 'obj*',
         description => <<'_',
 
 When the argument spec in the Rinci metadata contains `completion` key, this
 means there is custom completion code for that argument. However, if retrieved
 from a remote server, sometimes the `completion` key no longer contains the code
 (it has been cleansed into a string). Moreover, the completion code needs to run
 on the server.
 
 If supplied this argument and te `riap_server_url` argument, the function will
 try to request to the server (via Riap request `complete_arg_val`). Otherwise,
 the function will just give up/decline completing.
 
 _
         },
     riap_server_url => {
         summary => 'Optional, to perform complete_arg_val to the server',
         schema  => 'str*',
         description => <<'_',
 
 See the `riap_client` argument.
 
 _
     },
     riap_uri => {
         summary => 'Optional, to perform complete_arg_val to the server',
         schema  => 'str*',
         description => <<'_',
 
 See the `riap_client` argument.
 
 _
     },
 );
 
 $SPEC{complete_from_schema} = {
     v => 1.1,
     summary => 'Complete a value from schema',
     description => <<'_',
 
 Employ some heuristics to complete a value from Sah schema. For example, if
 schema is `[str => in => [qw/new open resolved rejected/]]`, then we can
 complete from the `in` clause. Or for something like `[int => between => [1,
 20]]` we can complete using values from 1 to 20.
 
 _
     args => {
         schema => {
             summary => 'Must be normalized',
             req => 1,
         },
         word => {
             schema => [str => default => ''],
             req => 1,
         },
         ci => {
             schema => 'bool',
         },
     },
 };
 sub complete_from_schema {
     my %args = @_;
     my $sch  = $args{schema}; # must be normalized
     my $word = $args{word} // "";
     my $ci   = $args{ci} // $Complete::Setting::OPT_CI;
 
     my $fres;
     $log->tracef("[comp][periscomp] entering complete_from_schema, word=<%s>, schema=%s", $word, $sch);
 
     my ($type, $cs) = @{$sch};
 
     my $static;
     my $words;
     eval {
         if ($cs->{is} && !ref($cs->{is})) {
             $log->tracef("[comp][periscomp] adding completion from 'is' clause");
             push @$words, $cs->{is};
             $static++;
             return; # from eval. there should not be any other value
         }
         if ($cs->{in}) {
             $log->tracef("[comp][periscomp] adding completion from 'in' clause");
             push @$words, grep {!ref($_)} @{ $cs->{in} };
             $static++;
             return; # from eval. there should not be any other value
         }
         if ($type eq 'any') {
             # because currently Data::Sah::Normalize doesn't recursively
             # normalize schemas in 'of' clauses, etc.
             require Data::Sah::Normalize;
             if ($cs->{of} && @{ $cs->{of} }) {
                 $fres = combine_answers(
                     grep { defined } map {
                         complete_from_schema(
                             schema=>Data::Sah::Normalize::normalize_schema($_),
                             word => $word,
                             ci => $ci,
                         )
                     } @{ $cs->{of} }
                 );
                 goto RETURN_RES; # directly return result
             }
         }
         if ($type eq 'bool') {
             $log->tracef("[comp][periscomp] adding completion from possible values of bool");
             push @$words, 0, 1;
             $static++;
             return; # from eval
         }
         if ($type eq 'int') {
             my $limit = 100;
             if ($cs->{between} &&
                     $cs->{between}[0] - $cs->{between}[0] <= $limit) {
                 $log->tracef("[comp][periscomp] adding completion from 'between' clause");
                 push @$words, $cs->{between}[0] .. $cs->{between}[1];
                 $static++;
             } elsif ($cs->{xbetween} &&
                          $cs->{xbetween}[0] - $cs->{xbetween}[0] <= $limit) {
                 $log->tracef("[comp][periscomp] adding completion from 'xbetween' clause");
                 push @$words, $cs->{xbetween}[0]+1 .. $cs->{xbetween}[1]-1;
                 $static++;
             } elsif (defined($cs->{min}) && defined($cs->{max}) &&
                          $cs->{max}-$cs->{min} <= $limit) {
                 $log->tracef("[comp][periscomp] adding completion from 'min' & 'max' clauses");
                 push @$words, $cs->{min} .. $cs->{max};
                 $static++;
             } elsif (defined($cs->{min}) && defined($cs->{xmax}) &&
                          $cs->{xmax}-$cs->{min} <= $limit) {
                 $log->tracef("[comp][periscomp] adding completion from 'min' & 'xmax' clauses");
                 push @$words, $cs->{min} .. $cs->{xmax}-1;
                 $static++;
             } elsif (defined($cs->{xmin}) && defined($cs->{max}) &&
                          $cs->{max}-$cs->{xmin} <= $limit) {
                 $log->tracef("[comp][periscomp] adding completion from 'xmin' & 'max' clauses");
                 push @$words, $cs->{xmin}+1 .. $cs->{max};
                 $static++;
             } elsif (defined($cs->{xmin}) && defined($cs->{xmax}) &&
                          $cs->{xmax}-$cs->{xmin} <= $limit) {
                 $log->tracef("[comp][periscomp] adding completion from 'xmin' & 'xmax' clauses");
                 push @$words, $cs->{xmin}+1 .. $cs->{xmax}-1;
                 $static++;
             } elsif (length($word) && $word !~ /\A-?\d*\z/) {
                 $log->tracef("[comp][periscomp] word not an int");
                 $words = [];
             } else {
                 # do a digit by digit completion
                 $words = [];
                 for my $sign ("", "-") {
                     for ("", 0..9) {
                         my $i = $sign . $word . $_;
                         next unless length $i;
                         next unless $i =~ /\A-?\d+\z/;
                         next if $i eq '-0';
                         next if $i =~ /\A-?0\d/;
                         next if $cs->{between} &&
                             ($i < $cs->{between}[0] ||
                                  $i > $cs->{between}[1]);
                         next if $cs->{xbetween} &&
                             ($i <= $cs->{xbetween}[0] ||
                                  $i >= $cs->{xbetween}[1]);
                         next if defined($cs->{min} ) && $i <  $cs->{min};
                         next if defined($cs->{xmin}) && $i <= $cs->{xmin};
                         next if defined($cs->{max} ) && $i >  $cs->{max};
                         next if defined($cs->{xmin}) && $i >= $cs->{xmax};
                         push @$words, $i;
                     }
                 }
                 $words = [sort @$words];
             }
             return; # from eval
         }
         if ($type eq 'float') {
             if (length($word) && $word !~ /\A-?\d*(\.\d*)?\z/) {
                 $log->tracef("[comp][periscomp] word not a float");
                 $words = [];
             } else {
                 $words = [];
                 for my $sig ("", "-") {
                     for ("", 0..9,
                          ".0",".1",".2",".3",".4",".5",".6",".7",".8",".9") {
                         my $f = $sig . $word . $_;
                         next unless length $f;
                         next unless $f =~ /\A-?\d+(\.\d+)?\z/;
                         next if $f eq '-0';
                         next if $f =~ /\A-?0\d\z/;
                         next if $cs->{between} &&
                             ($f < $cs->{between}[0] ||
                                  $f > $cs->{between}[1]);
                         next if $cs->{xbetween} &&
                             ($f <= $cs->{xbetween}[0] ||
                                  $f >= $cs->{xbetween}[1]);
                         next if defined($cs->{min} ) && $f <  $cs->{min};
                         next if defined($cs->{xmin}) && $f <= $cs->{xmin};
                         next if defined($cs->{max} ) && $f >  $cs->{max};
                         next if defined($cs->{xmin}) && $f >= $cs->{xmax};
                         push @$words, $f;
                     }
                 }
             }
             return; # from eval
         }
     }; # eval
 
     $log->tracef("[periscomp] complete_from_schema died: %s", $@) if $@;
 
     goto RETURN_RES unless $words;
     $fres = hashify_answer(
         complete_array_elem(array=>$words, word=>$word, ci=>$ci),
         {static=>$static && $word eq '' ? 1:0},
     );
 
   RETURN_RES:
     $log->tracef("[comp][periscomp] leaving complete_from_schema, result=%s", $fres);
     $fres;
 }
 
 $SPEC{complete_arg_val} = {
     v => 1.1,
     summary => 'Given argument name and function metadata, complete value',
     description => <<'_',
 
 Will attempt to complete using the completion routine specified in the argument
 specification (the `completion` property, or in the case of `complete_arg_elem`
 function, the `element_completion` property), or if that is not specified, from
 argument's schema using `complete_from_schema`.
 
 Completion routine will get `%args`, with the following keys:
 
 * `word` (str, the word to be completed)
 * `ci` (bool, whether string matching should be case-insensitive)
 * `arg` (str, the argument name which value is currently being completed)
 * `index (int, only for the `complete_arg_elem` function, the index in the
    argument array that is currently being completed, starts from 0)
 * `args` (hash, the argument hash to the function, so far)
 
 as well as extra keys from `extras` (but these won't overwrite the above
 standard keys).
 
 Completion routine should return a completion answer structure (described in
 `Complete`) which is either a hash or an array. The simplest form of answer is
 just to return an array of strings. Completion routine can also return undef to
 express declination.
 
 _
     args => {
         meta => {
             summary => 'Rinci function metadata, must be normalized',
             schema => 'hash*',
             req => 1,
         },
         arg => {
             summary => 'Argument name',
             schema => 'str*',
             req => 1,
         },
         word => {
             summary => 'Word to be completed',
             schema => ['str*', default => ''],
         },
         ci => {
             summary => 'Whether to be case-insensitive',
             schema => ['bool*'],
         },
         args => {
             summary => 'Collected arguments so far, '.
                 'will be passed to completion routines',
             schema  => 'hash',
         },
         extras => {
             summary => 'Add extra arguments to completion routine',
             schema  => 'hash',
             description => <<'_',
 
 The keys from this `extras` hash will be merged into the final `%args` passed to
 completion routines. Note that standard keys like `word`, `cword`, `ci`, and so
 on as described in the function description will not be overwritten by this.
 
 _
         },
 
         %common_args_riap,
     },
     result_naked => 1,
     result => {
         schema => 'array', # XXX of => str*
     },
 };
 sub complete_arg_val {
     my %args = @_;
 
     $log->tracef("[comp][periscomp] entering complete_arg_val, arg=<%s>", $args{arg});
     my $fres;
 
     my $extras = $args{extras} // {};
 
     my $meta = $args{meta} or do {
         $log->tracef("[comp][periscomp] meta is not supplied, declining");
         goto RETURN_RES;
     };
     my $arg  = $args{arg} or do {
         $log->tracef("[comp][periscomp] arg is not supplied, declining");
         goto RETURN_RES;
     };
     my $ci   = $args{ci} // $Complete::Setting::OPT_CI;
     my $word = $args{word} // '';
 
     # XXX reject if meta's v is not 1.1
 
     my $args_prop = $meta->{args} // {};
     my $arg_spec = $args_prop->{$arg} or do {
         $log->tracef("[comp][periscomp] arg '$arg' is not specified in meta, declining");
         goto RETURN_RES;
     };
 
     my $static;
     eval { # completion sub can die, etc.
 
         my $comp;
       GET_COMP_ROUTINE:
         {
             $comp = $arg_spec->{completion};
             if ($comp) {
                 $log->tracef("[comp][periscomp] using arg completion routine from 'completion' property");
                 last GET_COMP_ROUTINE;
             }
             my $xcomp = $arg_spec->{'x.completion'};
             if ($xcomp) {
                 require Module::Path::More;
                 my $mod = "Perinci::Sub::XCompletion::$xcomp->[0]";
                 if (Module::Path::More::module_path(module=>$mod)) {
                     $log->tracef("[comp][periscomp] loading module %s ...", $mod);
                     my $mod_pm = $mod; $mod_pm =~ s!::!/!g; $mod_pm .= ".pm";
                     require $mod_pm;
                     my $fref = \&{"$mod\::gen_completion"};
                     $comp = $fref->(%{ $xcomp->[1] });
                 }
                 if ($comp) {
                     $log->tracef("[comp][periscomp] using arg completion routine from 'x.completion' attribute");
                     last GET_COMP_ROUTINE;
                 }
             }
             my $ent = $arg_spec->{'x.schema.entity'};
             if ($ent) {
                 require Module::Path::More;
                 my $mod = "Perinci::Sub::ArgEntity::$ent";
                 if (Module::Path::More::module_path(module=>$mod)) {
                     $log->tracef("[comp][periscomp] loading module %s ...", $mod);
                     my $mod_pm = $mod; $mod_pm =~ s!::!/!g; $mod_pm .= ".pm";
                     require $mod_pm;
                     if (defined &{"$mod\::complete_arg_val"}) {
                         $log->tracef("[comp][periscomp] using arg completion routine from complete_arg_val() from %s", $mod);
                         $comp = \&{"$mod\::complete_arg_val"};
                         last GET_COMP_ROUTINE;
                     }
                 }
             }
         } # GET_COMP_ROUTINE
 
         if ($comp) {
             if (ref($comp) eq 'CODE') {
                 $log->tracef("[comp][periscomp] invoking arg completion routine");
                 $fres = $comp->(
                     %$extras,
                     word=>$word, ci=>$ci, arg=>$arg, args=>$args{args});
                 return; # from eval
             } elsif (ref($comp) eq 'ARRAY') {
                 # this is deprecated but will be supported for some time
                 $log->tracef("[comp][periscomp] using array specified in arg completion routine: %s", $comp);
                 $fres = complete_array_elem(
                     array=>$comp, word=>$word, ci=>$ci);
                 $static++;
                 return; # from eval
             }
 
             $log->tracef("[comp][periscomp] arg spec's 'completion' property is not a coderef or arrayref");
             if ($args{riap_client} && $args{riap_server_url}) {
                 $log->tracef("[comp][periscomp] trying to perform complete_arg_val request to Riap server");
                 my $res = $args{riap_client}->request(
                     complete_arg_val => $args{riap_server_url},
                     {(uri=>$args{riap_uri}) x !!defined($args{riap_uri}),
                      arg=>$arg, word=>$word, ci=>$ci},
                 );
                 if ($res->[0] != 200) {
                     $log->tracef("[comp][periscomp] Riap request failed (%s), declining", $res);
                     return; # from eval
                 }
                 $fres = $res->[2];
                 return; # from eval
             }
 
             $log->tracef("[comp][periscomp] declining");
             return; # from eval
         }
 
         my $sch = $arg_spec->{schema};
         unless ($sch) {
             $log->tracef("[comp][periscomp] arg spec does not specify schema, declining");
             return; # from eval
         };
 
         # XXX normalize schema if not normalized
 
         $fres = complete_from_schema(schema=>$sch, word=>$word, ci=>$ci);
     };
     $log->debug("[comp][periscomp] completion died: $@") if $@;
     unless ($fres) {
         $log->tracef("[comp][periscomp] no completion from metadata possible, declining");
         goto RETURN_RES;
     }
 
     $fres = hashify_answer($fres);
     $fres->{static} //= $static && $word eq '' ? 1:0;
   RETURN_RES:
     $log->tracef("[comp][periscomp] leaving complete_arg_val, result=%s", $fres);
     $fres;
 }
 
 gen_modified_sub(
     output_name  => 'complete_arg_elem',
     install_sub  => 0,
     base_name    => 'complete_arg_val',
     summary      => 'Given argument name and function metadata, '.
         'complete array element',
     add_args     => {
         index => {
             summary => 'Index of element to complete',
             schema  => [int => min => 0],
         },
     },
 );
 sub complete_arg_elem {
     require Data::Sah::Normalize;
 
     my %args = @_;
 
     my $fres;
 
     $log->tracef("[comp][periscomp] entering complete_arg_elem, arg=<%s>, index=<%d>",
                  $args{arg}, $args{index});
 
     my $extras = $args{extras} // {};
 
     my $ourextras = {arg=>$args{arg}, args=>$args{args}};
 
     my $meta = $args{meta} or do {
         $log->tracef("[comp][periscomp] meta is not supplied, declining");
         goto RETURN_RES;
     };
     my $arg  = $args{arg} or do {
         $log->tracef("[comp][periscomp] arg is not supplied, declining");
         goto RETURN_RES;
     };
     defined(my $index = $args{index}) or do {
         $log->tracef("[comp][periscomp] index is not supplied, declining");
         goto RETURN_RES;
     };
     my $ci   = $args{ci} // $Complete::Setting::OPT_CI;
     my $word = $args{word} // '';
 
     # XXX reject if meta's v is not 1.1
 
     my $args_prop = $meta->{args} // {};
     my $arg_spec = $args_prop->{$arg} or do {
         $log->tracef("[comp][periscomp] arg '$arg' is not specified in meta, declining");
         goto RETURN_RES;
     };
 
     my $static;
     eval { # completion sub can die, etc.
 
         my $elcomp;
       GET_ELCOMP_ROUTINE:
         {
             $elcomp = $arg_spec->{element_completion};
             if ($elcomp) {
                 $log->tracef("[comp][periscomp] using arg element completion routine from 'element_completion' property");
                 last GET_ELCOMP_ROUTINE;
             }
             my $xelcomp = $arg_spec->{'x.element_completion'};
             if ($xelcomp) {
                require Module::Path::More;
                 my $mod = "Perinci::Sub::XCompletion::$xelcomp->[0]";
                 if (Module::Path::More::module_path(module=>$mod)) {
                     $log->tracef("[comp][periscomp] loading module %s ...", $mod);
                     my $mod_pm = $mod; $mod_pm =~ s!::!/!g; $mod_pm .= ".pm";
                     require $mod_pm;
                     my $fref = \&{"$mod\::gen_completion"};
                     $elcomp = $fref->(%{ $xelcomp->[1] });
                 }
                 if ($elcomp) {
                     $log->tracef("[comp][periscomp] using arg element completion routine from 'x.element_completion' attribute");
                     last GET_ELCOMP_ROUTINE;
                 }
             }
             my $ent = $arg_spec->{'x.schema.element_entity'};
             if ($ent) {
                 require Module::Path::More;
                 my $mod = "Perinci::Sub::ArgEntity::$ent";
                 if (Module::Path::More::module_path(module=>$mod)) {
                     $log->tracef("[comp][periscomp] loading module %s ...", $mod);
                     my $mod_pm = $mod; $mod_pm =~ s!::!/!g; $mod_pm .= ".pm";
                     require $mod_pm;
                     if (defined &{"$mod\::complete_arg_val"}) {
                         $log->tracef("[comp][periscomp] using arg element completion routine from complete_arg_val() from %s", $mod);
                         $elcomp = \&{"$mod\::complete_arg_val"};
                         last GET_ELCOMP_ROUTINE;
                     }
                 }
             }
         } # GET_ELCOMP_ROUTINE
 
         $ourextras->{index} = $index;
         if ($elcomp) {
             if (ref($elcomp) eq 'CODE') {
                 $log->tracef("[comp][periscomp] invoking arg element completion routine");
                 $fres = $elcomp->(
                     %$extras,
                     %$ourextras,
                     word=>$word, ci=>$ci);
                 return; # from eval
             } elsif (ref($elcomp) eq 'ARRAY') {
                 $log->tracef("[comp][periscomp] using array specified in arg element completion routine: %s", $elcomp);
                 $fres = complete_array_elem(
                     array=>$elcomp, word=>$word, ci=>$ci);
                 $static = $word eq '';
             }
 
             $log->tracef("[comp][periscomp] arg spec's 'element_completion' property is not a coderef or ".
                              "arrayref");
             if ($args{riap_client} && $args{riap_server_url}) {
                 $log->tracef("[comp][periscomp] trying to perform complete_arg_elem request to Riap server");
                 my $res = $args{riap_client}->request(
                     complete_arg_elem => $args{riap_server_url},
                     {(uri=>$args{riap_uri}) x !!defined($args{riap_uri}),
                      arg=>$arg, args=>$args{args}, word=>$word, ci=>$ci,
                      index=>$index},
                 );
                 if ($res->[0] != 200) {
                     $log->tracef("[comp][periscomp] Riap request failed (%s), declining", $res);
                     return; # from eval
                 }
                 $fres = $res->[2];
                 return; # from eval
             }
 
             $log->tracef("[comp][periscomp] declining");
             return; # from eval
         }
 
         my $sch = $arg_spec->{schema};
         unless ($sch) {
             $log->tracef("[comp][periscomp] arg spec does not specify schema, declining");
             return; # from eval
         };
 
         # XXX normalize if not normalized
 
         my ($type, $cs) = @{ $sch };
         if ($type ne 'array') {
             $log->tracef("[comp][periscomp] can't complete element for non-array");
             return; # from eval
         }
 
         unless ($cs->{of}) {
             $log->tracef("[comp][periscomp] schema does not specify 'of' clause, declining");
             return; # from eval
         }
 
         # normalize subschema because normalize_schema (as of 0.01) currently
         # does not do it yet
         my $elsch = Data::Sah::Normalize::normalize_schema($cs->{of});
 
         $fres = complete_from_schema(schema=>$elsch, word=>$word, ci=>$ci);
     };
     $log->debug("[comp][periscomp] completion died: $@") if $@;
     unless ($fres) {
         $log->tracef("[comp][periscomp] no completion from metadata possible, declining");
         goto RETURN_RES;
     }
 
     $fres = hashify_answer($fres);
     $fres->{static} //= $static && $word eq '' ? 1:0;
   RETURN_RES:
     $log->tracef("[comp][periscomp] leaving complete_arg_elem, result=%s", $fres);
     $fres;
 }
 
 $SPEC{complete_cli_arg} = {
     v => 1.1,
     summary => 'Complete command-line argument using Rinci function metadata',
     description => <<'_',
 
 This routine uses `Perinci::Sub::GetArgs::Argv` to generate `Getopt::Long`
 specification from arguments list in Rinci function metadata and common options.
 Then, it will use `Complete::Getopt::Long` to complete option names, option
 values, as well as arguments.
 
 _
     args => {
         meta => {
             summary => 'Rinci function metadata',
             schema => 'hash*',
             req => 1,
         },
         words => {
             summary => 'Command-line arguments',
             schema => ['array*' => {of=>'str*'}],
             req => 1,
         },
         cword => {
             summary => 'On which argument cursor is located (zero-based)',
             schema => 'int*',
             req => 1,
         },
         completion => {
             summary => 'Supply custom completion routine',
             description => <<'_',
 
 If supplied, instead of the default completion routine, this code will be called
 instead. Will receive all arguments that `Complete::Getopt::Long` will pass, and
 additionally:
 
 * `arg` (str, the name of function argument)
 * `args` (hash, the function arguments formed so far)
 * `index` (int, if completing argument element value)
 
 _
             schema => 'code*',
         },
         per_arg_json => {
             summary => 'Will be passed to Perinci::Sub::GetArgs::Argv',
             schema  => 'bool',
         },
         per_arg_yaml => {
             summary => 'Will be passed to Perinci::Sub::GetArgs::Argv',
             schema  => 'bool',
         },
         common_opts => {
             summary => 'Common options',
             description => <<'_',
 
 A hash where the values are hashes containing these keys: `getopt` (Getopt::Long
 option specification), `handler` (Getopt::Long handler). Will be passed to
 `get_args_from_argv()`. Example:
 
     {
         help => {
             getopt  => 'help|h|?',
             handler => sub { ... },
             summary => 'Display help and exit',
         },
         version => {
             getopt  => 'version|v',
             handler => sub { ... },
             summary => 'Display version and exit',
         },
     }
 
 _
             schema => ['hash*'],
         },
         extras => {
             summary => 'Add extra arguments to completion routine',
             schema  => 'hash',
             description => <<'_',
 
 The keys from this `extras` hash will be merged into the final `%args` passed to
 completion routines. Note that standard keys like `word`, `cword`, `ci`, and so
 on as described in the function description will not be overwritten by this.
 
 _
         },
         func_arg_starts_at => {
             schema  => 'int*',
             default => 0,
             description => <<'_',
 
 This is a (temporary?) workaround for Perinci::CmdLine. In an application with
 subcommands (e.g. `cmd --verbose subcmd arg0 arg1 ...`), then `words` will still
 contain the subcommand name. Positional function arguments then start at 1 not
 0. This option allows offsetting function arguments.
 
 _
         },
         %common_args_riap,
     },
     result_naked => 1,
     result => {
         schema => 'hash*',
         description => <<'_',
 
 You can use `format_completion` function in `Complete::Bash` module to format
 the result of this function for bash.
 
 _
     },
 };
 sub complete_cli_arg {
     require Complete::Getopt::Long;
     require Perinci::Sub::GetArgs::Argv;
 
     my %args   = @_;
     my $meta   = $args{meta} or die "Please specify meta";
     my $words  = $args{words} or die "Please specify words";
     my $cword  = $args{cword}; defined($cword) or die "Please specify cword";
     my $copts  = $args{common_opts} // {};
     my $comp   = $args{completion};
     my $extras = {
         %{ $args{extras} // {} },
         words => $args{words},
         cword => $args{cword},
     };
 
     my $fname = __PACKAGE__ . "::complete_cli_arg"; # XXX use __SUB__
     my $fres;
 
     my $word   = $words->[$cword];
     my $args_prop = $meta->{args} // {};
 
     $log->tracef('[comp][periscomp] entering %s(), words=%s, cword=%d, word=<%s>',
                  $fname, $words, $cword, $word);
 
     my $genres = Perinci::Sub::GetArgs::Argv::gen_getopt_long_spec_from_meta(
         meta         => $meta,
         common_opts  => $copts,
         per_arg_json => $args{per_arg_json},
         per_arg_yaml => $args{per_arg_yaml},
         ignore_converted_code => 1,
     );
     die "Can't generate getopt spec from meta: $genres->[0] - $genres->[1]"
         unless $genres->[0] == 200;
     my $gospec = $genres->[2];
     my $specmeta = $genres->[3]{'func.specmeta'};
 
     my $gares = Perinci::Sub::GetArgs::Argv::get_args_from_argv(
         argv   => [@$words],
         meta   => $meta,
         strict => 0,
     );
 
     my $copts_by_ospec = {};
     for (keys %$copts) { $copts_by_ospec->{$copts->{$_}{getopt}}=$copts->{$_} }
 
     my $compgl_comp = sub {
         $log->tracef("[comp][periscomp] entering completion routine (that we supply to Complete::Getopt::Long)");
         my %cargs = @_;
         my $type  = $cargs{type};
         my $ospec = $cargs{ospec} // '';
         my $word  = $cargs{word};
         my $ci    = $cargs{ci} // $Complete::Setting::OPT_CI;
 
         my $fres;
 
         my %rargs = (
             riap_server_url => $args{riap_server_url},
             riap_uri        => $args{riap_uri},
             riap_client     => $args{riap_client},
         );
 
         if (my $sm = $specmeta->{$ospec}) {
             $cargs{type} = 'optval';
             if ($sm->{arg}) {
                 $log->tracef("[comp][periscomp] completing option value for a known function argument, arg=<%s>, ospec=<%s>", $sm->{arg}, $ospec);
                 $cargs{arg} = $sm->{arg};
                 my $arg_spec = $args_prop->{$sm->{arg}} or goto RETURN_RES;
                 if ($comp) {
                     $log->tracef("[comp][periscomp] invoking routine supplied from 'completion' argument");
                     my $compres;
                     eval { $compres = $comp->(%cargs) };
                     $log->debug("[comp][periscomp] completion died: $@") if $@;
                     $log->tracef("[comp][periscomp] result from 'completion' routine: %s", $compres);
                     if ($compres) {
                         $fres = $compres;
                         goto RETURN_RES;
                     }
                 }
                 if ($ospec =~ /\@$/) {
                     $fres = complete_arg_elem(
                         meta=>$meta, arg=>$sm->{arg}, args=>$gares->[2],
                         word=>$word, index=>$cargs{nth}, # XXX correct index
                         extras=>$extras, %rargs);
                     goto RETURN_RES;
                 } else {
                     $fres = complete_arg_val(
                         meta=>$meta, arg=>$sm->{arg}, args=>$gares->[2],
                         word=>$word, extras=>$extras, %rargs);
                     goto RETURN_RES;
                 }
             } else {
                 $log->tracef("[comp][periscomp] completing option value for a common option, ospec=<%s>", $ospec);
                 $cargs{arg}  = undef;
                 my $codata = $copts_by_ospec->{$ospec};
                 if ($comp) {
                     $log->tracef("[comp][periscomp] invoking routine supplied from 'completion' argument");
                     my $res;
                     eval { $res = $comp->(%cargs) };
                     $log->debug("[comp][periscomp] completion died: $@") if $@;
                     if ($res) {
                         $fres = $res;
                         goto RETURN_RES;
                     }
                 }
                 if ($codata->{completion}) {
                     $cargs{arg}  = undef;
                     $log->tracef("[comp][periscomp] completing with common option's 'completion' property");
                     my $res;
                     eval { $res = $codata->{completion}->(%cargs) };
                     $log->debug("[comp][periscomp] completion died: $@") if $@;
                     if ($res) {
                         $fres = $res;
                         goto RETURN_RES;
                     }
                 }
                 if ($codata->{schema}) {
                     require Data::Sah::Normalize;
                     my $nsch = Data::Sah::Normalize::normalize_schema(
                         $codata->{schema});
                     $log->tracef("[comp][periscomp] completing with common option's schema");
                     $fres = complete_from_schema(
                         schema => $nsch, word=>$word, ci=>$ci);
                     goto RETURN_RES;
                 }
                 goto RETURN_RES;
             }
         } elsif ($type eq 'arg') {
             $log->tracef("[comp][periscomp] completing argument #%d", $cargs{argpos});
             $cargs{type} = 'arg';
 
             my $pos = $cargs{argpos};
             my $fasa = $args{func_arg_starts_at} // 0;
 
             # find if there is a non-greedy argument with the exact position
             for my $an (keys %$args_prop) {
                 my $arg_spec = $args_prop->{$an};
                 next unless !$arg_spec->{greedy} &&
                     defined($arg_spec->{pos}) && $arg_spec->{pos} == $pos - $fasa;
                 $log->tracef("[comp][periscomp] this argument position is for non-greedy function argument <%s>", $an);
                 $cargs{arg} = $an;
                 if ($comp) {
                     $log->tracef("[comp][periscomp] invoking routine supplied from 'completion' argument");
                     my $res;
                     eval { $res = $comp->(%cargs) };
                     $log->debug("[comp][periscomp] completion died: $@") if $@;
                     if ($res) {
                         $fres = $res;
                         goto RETURN_RES;
                     }
                 }
                 $fres = complete_arg_val(
                     meta=>$meta, arg=>$an, args=>$gares->[2],
                     word=>$word, extras=>$extras, %rargs);
                 goto RETURN_RES;
             }
 
             # find if there is a greedy argument which takes elements at that
             # position
             for my $an (sort {
                 ($args_prop->{$b}{pos} // 9999) <=> ($args_prop->{$a}{pos} // 9999)
             } keys %$args_prop) {
                 my $arg_spec = $args_prop->{$an};
                 next unless $arg_spec->{greedy} &&
                     defined($arg_spec->{pos}) && $arg_spec->{pos} <= $pos - $fasa;
                 my $index = $pos - $fasa - $arg_spec->{pos};
                 $cargs{arg} = $an;
                 $cargs{index} = $index;
                 $log->tracef("[comp][periscomp] this position is for greedy function argument <%s>'s element[%d]", $an, $index);
                 if ($comp) {
                     $log->tracef("[comp][periscomp] invoking routine supplied from 'completion' argument");
                     my $res;
                     eval { $res = $comp->(%cargs) };
                     $log->debug("[comp][periscomp] completion died: $@") if $@;
                     if ($res) {
                         $fres = $res;
                         goto RETURN_RES;
                     }
                 }
                 $fres = complete_arg_elem(
                     meta=>$meta, arg=>$an, args=>$gares->[2],
                     word=>$word, index=>$index, extras=>$extras, %rargs);
                 goto RETURN_RES;
             }
 
             $log->tracef("[comp][periscomp] there is no matching function argument at this position");
             if ($comp) {
                 $log->tracef("[comp][periscomp] invoking routine supplied from 'completion' argument");
                 my $res;
                 eval { $res = $comp->(%cargs) };
                 $log->debug("[comp][periscomp] completion died: $@") if $@;
                 if ($res) {
                     $fres = $res;
                     goto RETURN_RES;
                 }
             }
             goto RETURN_RES;
         } else {
             $log->tracef("[comp][periscomp] completing option value for an unknown/ambiguous option, declining ...");
             # decline because there's nothing in Rinci metadata that can aid us
             goto RETURN_RES;
         }
       RETURN_RES:
         $log->tracef("[comp][periscomp] leaving completion routine (that we supply to Complete::Getopt::Long)");
         $fres;
     }; # completion routine
 
     $fres = Complete::Getopt::Long::complete_cli_arg(
         getopt_spec => $gospec,
         words       => $words,
         cword       => $cword,
         completion  => $compgl_comp,
         extras      => $extras,
     );
 
   RETURN_RES:
     $log->tracef('[comp][periscomp] leaving %s(), result=%s',
                  $fname, $fres);
     $fres;
 }
 
 1;
 # ABSTRACT: Complete command-line argument using Rinci metadata
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Perinci::Sub::Complete - Complete command-line argument using Rinci metadata
 
 =head1 VERSION
 
 This document describes version 0.82 of Perinci::Sub::Complete (from Perl distribution Perinci-Sub-Complete), released on 2015-09-09.
 
 =head1 SYNOPSIS
 
 See L<Perinci::CmdLine> or L<Perinci::CmdLine::Lite> or L<App::riap> which use
 this module.
 
 =head1 DESCRIPTION
 
 =head1 FUNCTIONS
 
 
 =head2 complete_arg_elem(%args) -> array
 
 Given argument name and function metadata, complete array element.
 
 Will attempt to complete using the completion routine specified in the argument
 specification (the C<completion> property, or in the case of C<complete_arg_elem>
 function, the C<element_completion> property), or if that is not specified, from
 argument's schema using C<complete_from_schema>.
 
 Completion routine will get C<%args>, with the following keys:
 
 =over
 
 =item * C<word> (str, the word to be completed)
 
 =item * C<ci> (bool, whether string matching should be case-insensitive)
 
 =item * C<arg> (str, the argument name which value is currently being completed)
 
 =item * C<index (int, only for the>complete_arg_elem` function, the index in the
 argument array that is currently being completed, starts from 0)
 
 =item * C<args> (hash, the argument hash to the function, so far)
 
 =back
 
 as well as extra keys from C<extras> (but these won't overwrite the above
 standard keys).
 
 Completion routine should return a completion answer structure (described in
 C<Complete>) which is either a hash or an array. The simplest form of answer is
 just to return an array of strings. Completion routine can also return undef to
 express declination.
 
 Arguments ('*' denotes required arguments):
 
 =over 4
 
 =item * B<arg>* => I<str>
 
 Argument name.
 
 =item * B<args> => I<hash>
 
 Collected arguments so far, will be passed to completion routines.
 
 =item * B<ci> => I<bool>
 
 Whether to be case-insensitive.
 
 =item * B<extras> => I<hash>
 
 Add extra arguments to completion routine.
 
 The keys from this C<extras> hash will be merged into the final C<%args> passed to
 completion routines. Note that standard keys like C<word>, C<cword>, C<ci>, and so
 on as described in the function description will not be overwritten by this.
 
 =item * B<index> => I<int>
 
 Index of element to complete.
 
 =item * B<meta>* => I<hash>
 
 Rinci function metadata, must be normalized.
 
 =item * B<riap_client> => I<obj>
 
 Optional, to perform complete_arg_val to the server.
 
 When the argument spec in the Rinci metadata contains C<completion> key, this
 means there is custom completion code for that argument. However, if retrieved
 from a remote server, sometimes the C<completion> key no longer contains the code
 (it has been cleansed into a string). Moreover, the completion code needs to run
 on the server.
 
 If supplied this argument and te C<riap_server_url> argument, the function will
 try to request to the server (via Riap request C<complete_arg_val>). Otherwise,
 the function will just give up/decline completing.
 
 =item * B<riap_server_url> => I<str>
 
 Optional, to perform complete_arg_val to the server.
 
 See the C<riap_client> argument.
 
 =item * B<riap_uri> => I<str>
 
 Optional, to perform complete_arg_val to the server.
 
 See the C<riap_client> argument.
 
 =item * B<word> => I<str> (default: "")
 
 Word to be completed.
 
 =back
 
 Return value:  (array)
 
 
 =head2 complete_arg_val(%args) -> array
 
 Given argument name and function metadata, complete value.
 
 Will attempt to complete using the completion routine specified in the argument
 specification (the C<completion> property, or in the case of C<complete_arg_elem>
 function, the C<element_completion> property), or if that is not specified, from
 argument's schema using C<complete_from_schema>.
 
 Completion routine will get C<%args>, with the following keys:
 
 =over
 
 =item * C<word> (str, the word to be completed)
 
 =item * C<ci> (bool, whether string matching should be case-insensitive)
 
 =item * C<arg> (str, the argument name which value is currently being completed)
 
 =item * C<index (int, only for the>complete_arg_elem` function, the index in the
 argument array that is currently being completed, starts from 0)
 
 =item * C<args> (hash, the argument hash to the function, so far)
 
 =back
 
 as well as extra keys from C<extras> (but these won't overwrite the above
 standard keys).
 
 Completion routine should return a completion answer structure (described in
 C<Complete>) which is either a hash or an array. The simplest form of answer is
 just to return an array of strings. Completion routine can also return undef to
 express declination.
 
 Arguments ('*' denotes required arguments):
 
 =over 4
 
 =item * B<arg>* => I<str>
 
 Argument name.
 
 =item * B<args> => I<hash>
 
 Collected arguments so far, will be passed to completion routines.
 
 =item * B<ci> => I<bool>
 
 Whether to be case-insensitive.
 
 =item * B<extras> => I<hash>
 
 Add extra arguments to completion routine.
 
 The keys from this C<extras> hash will be merged into the final C<%args> passed to
 completion routines. Note that standard keys like C<word>, C<cword>, C<ci>, and so
 on as described in the function description will not be overwritten by this.
 
 =item * B<meta>* => I<hash>
 
 Rinci function metadata, must be normalized.
 
 =item * B<riap_client> => I<obj>
 
 Optional, to perform complete_arg_val to the server.
 
 When the argument spec in the Rinci metadata contains C<completion> key, this
 means there is custom completion code for that argument. However, if retrieved
 from a remote server, sometimes the C<completion> key no longer contains the code
 (it has been cleansed into a string). Moreover, the completion code needs to run
 on the server.
 
 If supplied this argument and te C<riap_server_url> argument, the function will
 try to request to the server (via Riap request C<complete_arg_val>). Otherwise,
 the function will just give up/decline completing.
 
 =item * B<riap_server_url> => I<str>
 
 Optional, to perform complete_arg_val to the server.
 
 See the C<riap_client> argument.
 
 =item * B<riap_uri> => I<str>
 
 Optional, to perform complete_arg_val to the server.
 
 See the C<riap_client> argument.
 
 =item * B<word> => I<str> (default: "")
 
 Word to be completed.
 
 =back
 
 Return value:  (array)
 
 
 =head2 complete_cli_arg(%args) -> hash
 
 Complete command-line argument using Rinci function metadata.
 
 This routine uses C<Perinci::Sub::GetArgs::Argv> to generate C<Getopt::Long>
 specification from arguments list in Rinci function metadata and common options.
 Then, it will use C<Complete::Getopt::Long> to complete option names, option
 values, as well as arguments.
 
 Arguments ('*' denotes required arguments):
 
 =over 4
 
 =item * B<common_opts> => I<hash>
 
 Common options.
 
 A hash where the values are hashes containing these keys: C<getopt> (Getopt::Long
 option specification), C<handler> (Getopt::Long handler). Will be passed to
 C<get_args_from_argv()>. Example:
 
  {
      help => {
          getopt  => 'help|h|?',
          handler => sub { ... },
          summary => 'Display help and exit',
      },
      version => {
          getopt  => 'version|v',
          handler => sub { ... },
          summary => 'Display version and exit',
      },
  }
 
 =item * B<completion> => I<code>
 
 Supply custom completion routine.
 
 If supplied, instead of the default completion routine, this code will be called
 instead. Will receive all arguments that C<Complete::Getopt::Long> will pass, and
 additionally:
 
 =over
 
 =item * C<arg> (str, the name of function argument)
 
 =item * C<args> (hash, the function arguments formed so far)
 
 =item * C<index> (int, if completing argument element value)
 
 =back
 
 =item * B<cword>* => I<int>
 
 On which argument cursor is located (zero-based).
 
 =item * B<extras> => I<hash>
 
 Add extra arguments to completion routine.
 
 The keys from this C<extras> hash will be merged into the final C<%args> passed to
 completion routines. Note that standard keys like C<word>, C<cword>, C<ci>, and so
 on as described in the function description will not be overwritten by this.
 
 =item * B<func_arg_starts_at> => I<int> (default: 0)
 
 This is a (temporary?) workaround for Perinci::CmdLine. In an application with
 subcommands (e.g. C<cmd --verbose subcmd arg0 arg1 ...>), then C<words> will still
 contain the subcommand name. Positional function arguments then start at 1 not
 0. This option allows offsetting function arguments.
 
 =item * B<meta>* => I<hash>
 
 Rinci function metadata.
 
 =item * B<per_arg_json> => I<bool>
 
 Will be passed to Perinci::Sub::GetArgs::Argv.
 
 =item * B<per_arg_yaml> => I<bool>
 
 Will be passed to Perinci::Sub::GetArgs::Argv.
 
 =item * B<riap_client> => I<obj>
 
 Optional, to perform complete_arg_val to the server.
 
 When the argument spec in the Rinci metadata contains C<completion> key, this
 means there is custom completion code for that argument. However, if retrieved
 from a remote server, sometimes the C<completion> key no longer contains the code
 (it has been cleansed into a string). Moreover, the completion code needs to run
 on the server.
 
 If supplied this argument and te C<riap_server_url> argument, the function will
 try to request to the server (via Riap request C<complete_arg_val>). Otherwise,
 the function will just give up/decline completing.
 
 =item * B<riap_server_url> => I<str>
 
 Optional, to perform complete_arg_val to the server.
 
 See the C<riap_client> argument.
 
 =item * B<riap_uri> => I<str>
 
 Optional, to perform complete_arg_val to the server.
 
 See the C<riap_client> argument.
 
 =item * B<words>* => I<array[str]>
 
 Command-line arguments.
 
 =back
 
 Return value:  (hash)
 
 
 You can use C<format_completion> function in C<Complete::Bash> module to format
 the result of this function for bash.
 
 
 =head2 complete_from_schema(%args) -> [status, msg, result, meta]
 
 Complete a value from schema.
 
 Employ some heuristics to complete a value from Sah schema. For example, if
 schema is C<< [str =E<gt> in =E<gt> [qw/new open resolved rejected/]] >>, then we can
 complete from the C<in> clause. Or for something like C<< [int =E<gt> between =E<gt> [1,
 20]] >> we can complete using values from 1 to 20.
 
 Arguments ('*' denotes required arguments):
 
 =over 4
 
 =item * B<ci> => I<bool>
 
 =item * B<schema>* => I<any>
 
 Must be normalized.
 
 =item * B<word>* => I<str> (default: "")
 
 =back
 
 Returns an enveloped result (an array).
 
 First element (status) is an integer containing HTTP status code
 (200 means OK, 4xx caller error, 5xx function error). Second element
 (msg) is a string containing error message, or 'OK' if status is
 200. Third element (result) is optional, the actual result. Fourth
 element (meta) is called result metadata and is optional, a hash
 that contains extra information.
 
 Return value:  (any)
 
 =for Pod::Coverage ^(.+)$
 
 =head1 SEE ALSO
 
 L<Complete>, L<Complete::Getopt::Long>
 
 L<Perinci::CmdLine>, L<Perinci::CmdLine::Lite>, L<App::riap>
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Perinci-Sub-Complete>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Perinci-Sub-Complete>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Perinci-Sub-Complete>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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
### Perinci/Sub/ConvertArgs/Argv.pm ###
 package Perinci::Sub::ConvertArgs::Argv;
 
 our $DATE = '2015-09-03'; # DATE
 our $VERSION = '0.05'; # VERSION
 
 use 5.010001;
 use strict;
 use warnings;
 
 use Exporter;
 our @ISA = qw(Exporter);
 our @EXPORT_OK = qw(convert_args_to_argv);
 
 our %SPEC;
 
 sub _json {
     require JSON;
     state $json = JSON->new->allow_nonref;
     $json->encode($_[0]);
 }
 
 sub _encode {
     ref($_[0]) ? _json($_[0]) : $_[0];
 }
 
 $SPEC{convert_args_to_argv} = {
     v => 1.1,
     summary => 'Convert hash arguments to command-line options (and arguments)',
     description => <<'_',
 
 Convert hash arguments to command-line arguments. This is the reverse of
 `Perinci::Sub::GetArgs::Argv::get_args_from_argv`.
 
 Note: currently the function expects schemas in metadata to be normalized
 already.
 
 _
     args => {
         args => {req=>1, schema=>'hash*', pos=>0},
         meta => {req=>0, schema=>'hash*', pos=>1},
         use_pos => {
             summary => 'Whether to use positional arguments',
             schema  => 'bool',
             description => <<'_',
 
 For example, given this metadata:
 
     {
         v => 1.1,
         args => {
           arg1 => {pos=>0, req=>1},
           arg2 => {pos=>1},
           arg3 => {},
         },
     }
 
 then under `use_pos=0` the hash `{arg1=>1, arg2=>2, arg3=>'a b'}` will be
 converted to `['--arg1', 1, '--arg2', 2, '--arg3', 'a b']`. Meanwhile if
 `use_pos=1` the same hash will be converted to `[1, 2, '--arg3', 'a b']`.
 
 _
         },
     },
 };
 sub convert_args_to_argv {
     my %fargs = @_;
 
     my $iargs = $fargs{args} or return [400, "Please specify args"];
     my $meta  = $fargs{meta} // {v=>1.1};
     my $args_prop = $meta->{args} // {};
 
     my $v = $meta->{v} // 1.0;
     return [412, "Sorry, only metadata version 1.1 is supported (yours: $v)"]
         unless $v == 1.1;
 
     my @argv;
     my %iargs = %$iargs; # copy 'coz we will delete them one by one as we fill
 
     if ($fargs{use_pos}) {
         for (sort {$args_prop->{$a}{pos} <=> $args_prop->{$b}{pos}}
                  grep {defined $args_prop->{$_}{pos}} keys %iargs) {
             $argv[ $args_prop->{$_}{pos} ] = _encode($iargs{$_});
             delete $iargs{$_};
         }
     }
 
     for (sort keys %iargs) {
         my $is_bool = $args_prop->{$_}{schema} &&
             $args_prop->{$_}{schema}[0] eq 'bool';
         my $opt = $_; $opt =~ s/_/-/g;
         my $dashopt = length($opt) > 1 ? "--$opt" : "-$opt";
         if ($is_bool) {
             if ($iargs{$_}) {
                 push @argv, $dashopt;
             } else {
                 push @argv, "--no$opt";
             }
         } else {
             if (ref $iargs{$_}) {
                 push @argv, "$dashopt-json", _encode($iargs{$_});
             } else {
                 push @argv, $dashopt, "$iargs{$_}";
             }
         }
     }
     [200, "OK", \@argv];
 }
 
 1;
 # ABSTRACT: Convert hash arguments to command-line options (and arguments)
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Perinci::Sub::ConvertArgs::Argv - Convert hash arguments to command-line options (and arguments)
 
 =head1 VERSION
 
 This document describes version 0.05 of Perinci::Sub::ConvertArgs::Argv (from Perl distribution Perinci-Sub-ConvertArgs-Argv), released on 2015-09-03.
 
 =head1 SYNOPSIS
 
  use Perinci::Sub::ConvertArgs::Argv qw(convert_args_to_argv);
 
  my $res = convert_args_to_argv(args=>\%args, meta=>$meta, ...);
 
 =head1 SEE ALSO
 
 L<Perinci::CmdLine>, which uses this module for presenting command-line
 examples.
 
 L<Perinci::Sub::GetArgs::Argv> which does the reverse: converting command-line
 arguments to hash.
 
 =head1 FUNCTIONS
 
 
 =head2 convert_args_to_argv(%args) -> [status, msg, result, meta]
 
 Convert hash arguments to command-line options (and arguments).
 
 Convert hash arguments to command-line arguments. This is the reverse of
 C<Perinci::Sub::GetArgs::Argv::get_args_from_argv>.
 
 Note: currently the function expects schemas in metadata to be normalized
 already.
 
 Arguments ('*' denotes required arguments):
 
 =over 4
 
 =item * B<args>* => I<hash>
 
 =item * B<meta> => I<hash>
 
 =item * B<use_pos> => I<bool>
 
 Whether to use positional arguments.
 
 For example, given this metadata:
 
  {
      v => 1.1,
      args => {
        arg1 => {pos=>0, req=>1},
        arg2 => {pos=>1},
        arg3 => {},
      },
  }
 
 then under C<use_pos=0> the hash C<< {arg1=E<gt>1, arg2=E<gt>2, arg3=E<gt>'a b'} >> will be
 converted to C<['--arg1', 1, '--arg2', 2, '--arg3', 'a b']>. Meanwhile if
 C<use_pos=1> the same hash will be converted to C<[1, 2, '--arg3', 'a b']>.
 
 =back
 
 Returns an enveloped result (an array).
 
 First element (status) is an integer containing HTTP status code
 (200 means OK, 4xx caller error, 5xx function error). Second element
 (msg) is a string containing error message, or 'OK' if status is
 200. Third element (result) is optional, the actual result. Fourth
 element (meta) is called result metadata and is optional, a hash
 that contains extra information.
 
 Return value:  (any)
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Perinci-Sub-ConvertArgs-Argv>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Perinci-Sub-ConvertArgs-Argv>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Perinci-Sub-ConvertArgs-Argv>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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
### Perinci/Sub/ConvertArgs/Array.pm ###
 package Perinci::Sub::ConvertArgs::Array;
 
 our $DATE = '2015-09-03'; # DATE
 our $VERSION = '0.07'; # VERSION
 
 use 5.010001;
 use strict;
 use warnings;
 
 use Exporter;
 our @ISA = qw(Exporter);
 our @EXPORT_OK = qw(convert_args_to_array);
 
 our %SPEC;
 
 $SPEC{convert_args_to_array} = {
     v => 1.1,
     summary => 'Convert hash arguments to array',
     description => <<'_',
 
 Using information in 'args' property (particularly the 'pos' and 'greedy' of
 each argument spec), convert hash arguments to array.
 
 Example:
 
     my $meta = {
         v => 1.1,
         summary => 'Multiply 2 numbers (a & b)',
         args => {
             a => ['num*' => {arg_pos=>0}],
             b => ['num*' => {arg_pos=>1}],
         }
     }
 
 then 'convert_args_to_array(args=>{a=>2, b=>3}, meta=>$meta)' will produce:
 
     [200, "OK", [2, 3]]
 
 _
     args => {
         args => {req=>1, schema=>'hash*', pos=>0},
         meta => {req=>1, schema=>'hash*', pos=>1},
     },
 };
 sub convert_args_to_array {
     my %input_args   = @_;
     my $args         = $input_args{args} or return [400, "Please specify args"];
     my $meta         = $input_args{meta} or return [400, "Please specify meta"];
     my $args_prop    = $meta->{args} // {};
 
     my $v = $meta->{v} // 1.0;
     return [412, "Sorry, only metadata version 1.1 is supported (yours: $v)"]
         unless $v == 1.1;
 
     #$log->tracef("-> convert_args_to_array(), args=%s", $args);
 
     my @array;
 
     while (my ($k, $v) = each %$args) {
         my $as = $args_prop->{$k};
         return [412, "Argument $k: Not specified in args property"] unless $as;
         my $pos = $as->{pos};
         return [412, "Argument $k: No pos specified in arg spec"]
             unless defined $pos;
         if ($as->{greedy}) {
             $v = [$v] if ref($v) ne 'ARRAY';
             # splice can't work if $pos is beyond array's length
             for (@array .. $pos-1) {
                 $array[$_] = undef;
             }
             splice @array, $pos, 0, @$v;
         } else {
             $array[$pos] = $v;
         }
     }
     [200, "OK", \@array];
 }
 
 1;
 # ABSTRACT: Convert hash arguments to array
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Perinci::Sub::ConvertArgs::Array - Convert hash arguments to array
 
 =head1 VERSION
 
 This document describes version 0.07 of Perinci::Sub::ConvertArgs::Array (from Perl distribution Perinci-Sub-ConvertArgs-Array), released on 2015-09-03.
 
 =head1 SYNOPSIS
 
  use Perinci::Sub::ConvertArgs::Array qw(convert_args_to_array);
 
  my $res = convert_args_to_array(args=>\%args, meta=>$meta, ...);
 
 =head1 DESCRIPTION
 
 This module provides convert_args_to_array() (and
 gencode_convert_args_to_array(), upcoming). This module is used by, among
 others, L<Perinci::Sub::Wrapper>.
 
 =head1 FUNCTIONS
 
 
 =head2 convert_args_to_array(%args) -> [status, msg, result, meta]
 
 Convert hash arguments to array.
 
 Using information in 'args' property (particularly the 'pos' and 'greedy' of
 each argument spec), convert hash arguments to array.
 
 Example:
 
  my $meta = {
      v => 1.1,
      summary => 'Multiply 2 numbers (a & b)',
      args => {
          a => ['num*' => {arg_pos=>0}],
          b => ['num*' => {arg_pos=>1}],
      }
  }
 
 then 'convert_args_to_array(args=>{a=>2, b=>3}, meta=>$meta)' will produce:
 
  [200, "OK", [2, 3]]
 
 Arguments ('*' denotes required arguments):
 
 =over 4
 
 =item * B<args>* => I<hash>
 
 =item * B<meta>* => I<hash>
 
 =back
 
 Returns an enveloped result (an array).
 
 First element (status) is an integer containing HTTP status code
 (200 means OK, 4xx caller error, 5xx function error). Second element
 (msg) is a string containing error message, or 'OK' if status is
 200. Third element (result) is optional, the actual result. Fourth
 element (meta) is called result metadata and is optional, a hash
 that contains extra information.
 
 Return value:  (any)
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Perinci-Sub-ConvertArgs-Array>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Perinci-Sub-ConvertArgs-Array>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Perinci-Sub-ConvertArgs-Array>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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
### Perinci/Sub/DepChecker.pm ###
 package Perinci::Sub::DepChecker;
 
 use 5.010001;
 use strict;
 use warnings;
 use experimental 'smartmatch';
 #use Log::Any '$log';
 
 require Exporter;
 our @ISA = qw(Exporter);
 our @EXPORT_OK = qw(
                        check_deps
                        dep_satisfy_rel
                        list_mentioned_dep_clauses
                );
 
 our $VERSION = '0.11'; # VERSION
 our $DATE = '2015-09-03'; # DATE
 
 my $pa;
 
 sub check_deps {
     my ($val) = @_;
     #say "D:check: ", dump($val);
     for my $dname (keys %$val) {
         my $dval = $val->{$dname};
         unless (defined &{"checkdep_$dname"}) {
             # give a chance to load from a module first
             eval { require "Perinci/Sub/Dep/$dname.pm" };
             return "Unknown dependency type: $dname"
                 unless defined &{"checkdep_$dname"};
         }
         my $check = \&{"checkdep_$dname"};
         my $res = $check->($dval);
         if ($res) {
             $res = "$dname: $res";
             return $res;
         }
     }
     "";
 }
 
 sub checkdep_all {
     my ($val) = @_;
     #say "D:check_all: ", dump($val);
     for (@$val) {
         my $res = check_deps($_);
         return "Some dependencies not met: $res" if $res;
     }
     "";
 }
 
 sub checkdep_any {
     my ($val) = @_;
     my $nfail = 0;
     for (@$val) {
         return "" unless check_deps($_);
         $nfail++;
     }
     $nfail ? "None of the dependencies are met" : "";
 }
 
 sub checkdep_none {
     my ($val) = @_;
     for (@$val) {
         my $res = check_deps($_);
         return "A dependency is met when it shouldn't: $res" unless $res;
     }
     "";
 }
 
 sub checkdep_env {
     my ($cval) = @_;
     $ENV{$cval} ? "" : "Environment variable $cval not set/true";
 }
 
 sub checkdep_code {
     my ($cval) = @_;
     $cval->() ? "" : "code doesn't return true value";
 }
 
 sub checkdep_prog {
     my ($cval) = @_;
 
     if ($cval =~ m!/!) {
         return "Program $cval not executable" unless (-x $cval);
     } else {
         require File::Which;
         return "Program $cval not found in PATH (".
             join(":", File::Spec->path).")"
                 unless File::Which::which($cval);
     }
     "";
 }
 
 sub riap_client {
     return $pa if $pa;
     require Perinci::Access;
     $pa = Perinci::Access->new;
     $pa;
 }
 
 sub checkdep_pkg {
     my ($cval) = @_;
     my $res = riap_client->request(info => $cval);
     $res->[0] == 200 or return "Can't perform 'info' Riap request on '$cval': ".
         "$res->[0] $res->[1]";
     $res->[2]{type} eq 'package' or return "$cval is not a Riap package";
     "";
 }
 
 sub checkdep_func {
     my ($cval) = @_;
     my $res = riap_client->request(info => $cval);
     $res->[0] == 200 or return "Can't perform 'info' Riap request on '$cval': ".
         "$res->[0] $res->[1]";
     $res->[2]{type} eq 'function' or return "$cval is not a Riap function";
     "";
 }
 
 # for backward-compatibility
 sub checkdep_exec { checkdep_prog(@_) }
 
 # we check this dep by checking arguments, so we'll let something like
 # Perinci::Sub::Wrapper to do it
 sub checkdep_tmp_dir { "" }
 
 # we check this dep by checking arguments, so we'll let something like
 # Perinci::Sub::Wrapper to do it
 sub checkdep_trash_dir { "" }
 
 # we check this dep by checking arguments, so we'll let something like
 # Perinci::Sub::Wrapper to do it
 sub checkdep_undo_trash_dir { "" }
 
 sub _all_elems_is {
     my ($ary, $el) = @_;
     (grep {$_ eq $el} @$ary) && !(grep {$_ ne $el} @$ary);
 }
 
 sub _all_nonblank_elems_is {
     my ($ary, $el) = @_;
     (grep {$_ eq $el} @$ary) && !(grep {$_ && $_ ne $el} @$ary);
 }
 
 sub dep_satisfy_rel {
     my ($wanted, $deps) = @_;
     #$log->tracef("=> dep_satisfy_rel(%s, %s)", $wanted, $deps);
 
     my $res;
     for my $dname (keys %$deps) {
         my $dval = $deps->{$dname};
 
         if ($dname eq 'all') {
             my @r = map { dep_satisfy_rel($wanted, $_) } @$dval;
             #$log->tracef("all: %s", \@r);
             next unless @r;
             return "impossible" if "impossible" ~~ @r;
             return "impossible" if "must" ~~ @r && "must not" ~~ @r;
             return "must"       if "must" ~~ @r;
             return "must not"   if "must not" ~~ @r;
             return "might"      if _all_nonblank_elems_is(\@r, "might");
         } elsif ($dname eq 'any') {
             my @r = map { dep_satisfy_rel($wanted, $_) } @$dval;
             #$log->tracef("any: %s", \@r);
             next unless @r;
             return "impossible" if "impossible" ~~ @r;
             return "must"       if _all_elems_is(\@r, "must");
             return "must not"   if _all_elems_is(\@r, "must not");
             next                if _all_elems_is(\@r, "");
             return "might";
         } elsif ($dname eq 'none') {
             my @r = map { dep_satisfy_rel($wanted, $_) } @$dval;
             #$log->tracef("none: %s", \@r);
             next unless @r;
             return "impossible" if "impossible" ~~ @r;
             return "impossible" if "must" ~~ @r && "must not" ~~ @r;
             return "must not"   if "must" ~~ @r;
             return "must"       if "must not" ~~ @r;
             return "might"      if _all_nonblank_elems_is(\@r, "might");
         } else {
             return "must" if $dname eq $wanted;
         }
     }
     "";
 }
 
 sub list_mentioned_dep_clauses {
     my ($deps, $res) = @_;
     $res //= [];
     for my $dname (keys %$deps) {
         my $dval = $deps->{$dname};
         push @$res, $dname unless $dname ~~ @$res;
         if ($dname =~ /\A(?:all|any|none)\z/) {
             list_mentioned_dep_clauses($_, $res) for @$dval;
         }
     }
     $res;
 }
 
 1;
 # ABSTRACT: Check dependencies from 'deps' property
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Perinci::Sub::DepChecker - Check dependencies from 'deps' property
 
 =head1 VERSION
 
 This document describes version 0.11 of Perinci::Sub::DepChecker (from Perl distribution Perinci-Sub-DepChecker), released on 2015-09-03.
 
 =head1 SYNOPSIS
 
  use Perinci::Spec::DepChecker qw(check_deps dep_satisfy_rel list_mentioned_dep_clauses);
 
  my $err = check_deps($meta->{deps});
  print "Dependencies not met: $err" if $err;
 
  print "We need to prepare foo"
      if dep_satisfy_rel('foo', $meta->{deps}) =~ /^(?:must|might)$/;
 
 =head1 DESCRIPTION
 
 The 'deps' spec clause adds information about subroutine dependencies. This
 module performs check on it.
 
 This module is currently mainly used by L<Perinci::Sub::Wrapper>.
 
 =for Pod::Coverage ^(checkdep_.*|riap_client)$
 
 =head1 FUNCTIONS
 
 None is exported by default, but every function is exportable.
 
 =head2 check_deps($deps) => ERRSTR
 
 Check dependencies. Will in turn call various C<checkdep_NAME()> subroutines.
 Return empty string if all dependencies are met, or a string containing an error
 message stating a dependency error.
 
 Example:
 
  my $err = check_deps({env=>'DEBUG'});
 
 Will check environment variable C<DEBUG>. If true, will return an empty string.
 Otherwise will set $err with something like C<Environment variable DEBUG not
 set/true>.
 
 Another example:
 
  my $err = check_deps({ all=>[{env=>"A"}, {env=>"B", prog=>"bc"}] });
 
 The above will check environment variables C<A>, C<B>, as well as program C<bc>.
 All dependencies must be met (because we use the C<and> metaclause).
 
 To support a custom dependency named C<NAME>, just define C<checkdep_NAME>
 subroutine in L<Perinci::Sub::DepChecker> package which accepts a value and
 should return an empty string on success or an error message string.
 
 =head2 dep_satisfy_rel($name, $deps) => STR
 
 Check dep satisfication relationship, i.e. whether dependency named C<$name>
 must be satisfied in C<$deps>. Due to B<all>, B<any>, and B<none> clauses, this
 needs to be checked recursively and might yield an inconclusive answer
 ("maybe").
 
 Return "must" if C<$name> definitely must be satisfied in C<$deps>, "must not"
 if definitely not, "" if need not be satisfied (dep clause does not exist in
 deps), "impossible" if condition is impossible to be satisfied (due to
 conflicts), "might" if dep might need to be satisfied (but might also not).
 
 Examples:
 
  dep_satisfy_rel('env', {env=>"A"})              # => "must"
  dep_satisfy_rel('a', {all=>[{a=>1}, {b=>1}]})   # => "must"
  dep_satisfy_rel('a', {b=>2})                    # => ""
  dep_satisfy_rel('a', {none=>[{a=>1}, {b=>1}]})  # => "must not"
  dep_satisfy_rel('c', {none=>[{a=>1}, {b=>1}]})  # => ""
  dep_satisfy_rel('a', {any=>[{a=>1}, {b=>1}]})   # => "might"
  dep_satisfy_rel('a', {all=>[{a=>1},
                              {none=>[{a=>1}]}]}) # => "impossible"
 
 This function is useful if we want to prepare something that "must" or "might"
 be needed, or want to avoid preparing something that "must not" be present.
 
 =head2 list_mentioned_dep_clauses($deps) => ARRAYREF
 
 List all dep clauses mentioned in $deps. The returned array is I<not> sorted
 alphabetically, so you will have to do it yourself if you need it sorted.
 
 Example:
 
  list_mentioned_dep_clauses({any=>[{a=>1}, {b=>1}]}) # => [qw/any a b/]
 
 =head1 SEE ALSO
 
 L<Perinci>
 
 'deps' section in L<Rinci::function>
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Perinci-Sub-DepChecker>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Perinci-Sub-DepChecker>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Perinci-Sub-DepChecker>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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
### Perinci/Sub/GetArgs/Argv.pm ###
 package Perinci::Sub::GetArgs::Argv;
 
 our $DATE = '2015-08-19'; # DATE
 our $VERSION = '0.69'; # VERSION
 
 use 5.010001;
 use strict;
 use warnings;
 #use Log::Any '$log';
 
 use Data::Sah::Normalize qw(normalize_schema);
 use Getopt::Long::Negate::EN qw(negations_for_option);
 use Getopt::Long::Util qw(parse_getopt_long_opt_spec);
 use List::Util qw(first);
 use Perinci::Sub::GetArgs::Array qw(get_args_from_array);
 use Perinci::Sub::Util qw(err);
 
 use Exporter;
 our @ISA = qw(Exporter);
 our @EXPORT_OK = qw(
                        gen_getopt_long_spec_from_meta
                        get_args_from_argv
                );
 
 our %SPEC;
 
 $SPEC{':package'} = {
     v => 1.1,
     summary => 'Get subroutine arguments from command line arguments (@ARGV)',
 };
 
 my $re_simple_scalar = qr/^(str|num|int|float|bool|buf|re|date|duration)$/;
 
 # retun ($success?, $errmsg, $res)
 sub _parse_json {
     my $str = shift;
 
     state $json = do {
         require JSON::PP;
         JSON::PP->new->allow_nonref;
     };
 
     # to rid of those JSON::PP::Boolean objects which currently choke
     # Data::Sah-generated validator code. in the future Data::Sah can be
     # modified to handle those, or we use a fork of JSON::PP which doesn't
     # produce those in the first place (probably only when performance is
     # critical).
     state $cleanser = do {
         if (eval { require Data::Clean::FromJSON; 1 }) {
             Data::Clean::FromJSON->get_cleanser;
         } else {
             undef;
         }
     };
 
     my $res;
     eval { $res = $json->decode($str); $cleanser->clean_in_place($res) if $cleanser };
     my $e = $@;
     return (!$e, $e, $res);
 }
 
 sub _parse_yaml {
     no warnings 'once';
 
     state $yaml_xs_available = do {
         if (eval { require YAML::XS; 1 }) {
             1;
         } else {
             require YAML::Old;
             0;
         }
     };
 
     my $str = shift;
 
     #local $YAML::Syck::ImplicitTyping = 1;
     my $res;
     eval {
         if ($yaml_xs_available) {
             $res = YAML::XS::Load($str);
         } else {
             # YAML::Old is too strict, it requires "--- " header and newline
             # ending
             $str = "--- $str" unless $str =~ /\A--- /;
             $str .= "\n" unless $str =~ /\n\z/;
             $res = YAML::Old::Load($str);
         }
     };
     my $e = $@;
     return (!$e, $e, $res);
 }
 
 sub _arg2opt {
     my $opt = shift;
     $opt =~ s/[^A-Za-z0-9-]+/-/g; # foo.bar_baz becomes --foo-bar-baz
     $opt;
 }
 
 # return one or more triplets of Getopt::Long option spec, its parsed structure,
 # and extra stuffs. we do this to avoid having to call
 # parse_getopt_long_opt_spec().
 sub _opt2ospec {
     my ($opt, $schema, $arg_spec) = @_;
     my $type = $schema->[0];
     my $cs   = $schema->[1];
     my $is_array_of_simple_scalar = $type eq 'array' &&
         $cs->{of} && $cs->{of}[0] =~ $re_simple_scalar;
     if ($is_array_of_simple_scalar && $arg_spec && $arg_spec->{'x.name.is_plural'}) {
         if ($arg_spec->{'x.name.singular'}) {
             $opt = $arg_spec->{'x.name.singular'};
         } else {
             require Lingua::EN::PluralToSingular;
             $opt = Lingua::EN::PluralToSingular::to_singular($opt);
         }
     }
     if ($type eq 'bool') {
         if (length($opt) == 1 || $cs->{is}) {
             # single-letter option like -b doesn't get --nob.
             # [bool=>{is=>1}] also means it's a flag and should not get
             # --nofoo.
             return ($opt, {opts=>[$opt]});
         } else {
             my @res;
             my @negs = negations_for_option($opt);
             push @res, $opt, {opts=>[$opt]}, {is_neg=>0, neg_opts=>\@negs};
             for (@negs) {
                 push @res, $_, {opts=>[$_]}, {is_neg=>1, pos_opts=>[$opt]};
             }
             return @res;
         }
     } elsif ($type eq 'buf') {
         return (
             "$opt=s", {opts=>[$opt], desttype=>"", type=>"s"}, undef,
             "$opt-base64=s", {opts=>["$opt-base64"], desttype=>"", type=>"s"}, {is_base64=>1},
         );
     } else {
         my $t = ($type eq 'int' ? 'i' : $type eq 'float' ? 'f' :
                      $is_array_of_simple_scalar ? 's@' : 's');
         return ("$opt=$t", {opts=>[$opt], desttype=>"", type=>$t});
     }
 }
 
 sub _args2opts {
     my %args = @_;
 
     my $argprefix        = $args{argprefix};
     my $parent_args      = $args{parent_args};
     my $meta             = $args{meta};
     my $seen_opts        = $args{seen_opts};
     my $seen_common_opts = $args{seen_common_opts};
     my $seen_func_opts   = $args{seen_func_opts};
     my $rargs            = $args{rargs};
     my $go_spec          = $args{go_spec};
     my $specmeta         = $args{specmeta};
 
     my $args_prop = $meta->{args} // {};
 
     for my $arg (keys %$args_prop) {
         my $fqarg    = "$argprefix$arg";
         my $arg_spec = $args_prop->{$arg};
         my $sch      = $arg_spec->{schema} // ['any', {}];
         my $type     = $sch->[0] // '';
         my $cs       = $sch->[1] // {};
 
         # XXX normalization of 'of' clause should've been handled by sah itself
         if ($type eq 'array' && $cs->{of}) {
             $cs->{of} = normalize_schema($cs->{of});
         }
         my $opt = _arg2opt($fqarg);
         if ($seen_opts->{$opt}) {
             my $i = 1;
             my $opt2;
             while (1) {
                 $opt2 = "$opt-arg" . ($i > 1 ? $i : '');
                 last unless $seen_opts->{$opt2};
                 $i++;
             }
             $opt = $opt2;
         }
 
         my $is_simple_scalar = $type =~ $re_simple_scalar;
         my $is_array_of_simple_scalar = $type eq 'array' &&
             $cs->{of} && $cs->{of}[0] =~ $re_simple_scalar;
 
         my $stash = {};
 
         # why we use coderefs here? due to Getopt::Long's behavior. when
         # @ARGV=qw() and go_spec is ('foo=s' => \$opts{foo}) then %opts will
         # become (foo=>undef). but if go_spec is ('foo=s' => sub { $opts{foo} =
         # $_[1] }) then %opts will become (), which is what we prefer, so we can
         # later differentiate "unspecified" (exists($opts{foo}) == false) and
         # "specified as undef" (exists($opts{foo}) == true but
         # defined($opts{foo}) == false).
 
         my $handler = sub {
             my ($val, $val_set);
 
             # how many times have been called for this argument?
             my $num_called = ++$stash->{called}{$arg};
 
             # hashify rargs till the end of the handler scope if it happens to
             # be an array (this is the case when we want to fill values using
             # element_meta).
             my $rargs = do {
                 if (ref($rargs) eq 'ARRAY') {
                     $rargs->[$num_called-1] //= {};
                     $rargs->[$num_called-1];
                 } else {
                     $rargs;
                 }
             };
 
             if ($is_array_of_simple_scalar) {
                 $rargs->{$arg} //= [];
                 $val_set = 1; $val = $_[1];
                 push @{ $rargs->{$arg} }, $val;
             } elsif ($is_simple_scalar) {
                 $val_set = 1; $val = $_[1];
                 $rargs->{$arg} = $val;
             } else {
                 {
                     my ($success, $e, $decoded);
                     ($success, $e, $decoded) = _parse_json($_[1]);
                     if ($success) {
                         $val_set = 1; $val = $decoded;
                         $rargs->{$arg} = $val;
                         last;
                     }
                     ($success, $e, $decoded) = _parse_yaml($_[1]);
                     if ($success) {
                         $val_set = 1; $val = $decoded;
                         $rargs->{$arg} = $val;
                         last;
                     }
                     die "Invalid YAML/JSON in arg '$fqarg'";
                 }
             }
             if ($val_set && $arg_spec->{cmdline_on_getopt}) {
                 $arg_spec->{cmdline_on_getopt}->(
                     arg=>$arg, fqarg=>$fqarg, value=>$val, args=>$rargs,
                     opt=>$opt,
                 );
             }
         }; # handler
 
         my @triplets = _opt2ospec($opt, $sch, $arg_spec);
         my $aliases_processed;
         while (my ($ospec, $parsed, $extra) = splice @triplets, 0, 3) {
             $extra //= {};
             if ($extra->{is_neg}) {
                 $go_spec->{$ospec} = sub { $handler->($_[0], 0) };
             } elsif (defined $extra->{is_neg}) {
                 $go_spec->{$ospec} = sub { $handler->($_[0], 1) };
             } elsif ($extra->{is_base64}) {
                 $go_spec->{$ospec} = sub {
                     require MIME::Base64;
                     my $decoded = MIME::Base64::decode($_[1]);
                     $handler->($_[0], $decoded);
                 };
             } else {
                 $go_spec->{$ospec} = $handler;
             }
 
             $specmeta->{$ospec} = {arg=>$arg, fqarg=>$fqarg, parsed=>$parsed, %$extra};
             for (@{ $parsed->{opts} }) {
                 $seen_opts->{$_}++; $seen_func_opts->{$_} = $fqarg;
             }
 
             if ($parent_args->{per_arg_json} && $type !~ $re_simple_scalar) {
                 my $jopt = "$opt-json";
                 if ($seen_opts->{$jopt}) {
                     warn "Clash of option: $jopt, not added";
                 } else {
                     my $jospec = "$jopt=s";
                     my $parsed = {type=>"s", opts=>[$jopt]};
                     $go_spec->{$jospec} = sub {
                         my ($success, $e, $decoded);
                         ($success, $e, $decoded) = _parse_json($_[1]);
                         if ($success) {
                             $rargs->{$arg} = $decoded;
                         } else {
                             die "Invalid JSON in option --$jopt: $_[1]: $e";
                         }
                     };
                     $specmeta->{$jospec} = {arg=>$arg, fqarg=>$fqarg, is_json=>1, parsed=>$parsed, %$extra};
                     $seen_opts->{$jopt}++; $seen_func_opts->{$jopt} = $fqarg;
                 }
             }
             if ($parent_args->{per_arg_yaml} && $type !~ $re_simple_scalar) {
                 my $yopt = "$opt-yaml";
                 if ($seen_opts->{$yopt}) {
                     warn "Clash of option: $yopt, not added";
                 } else {
                     my $yospec = "$yopt=s";
                     my $parsed = {type=>"s", opts=>[$yopt]};
                     $go_spec->{$yospec} = sub {
                         my ($success, $e, $decoded);
                         ($success, $e, $decoded) = _parse_yaml($_[1]);
                         if ($success) {
                             $rargs->{$arg} = $decoded;
                         } else {
                             die "Invalid YAML in option --$yopt: $_[1]: $e";
                         }
                     };
                     $specmeta->{$yospec} = {arg=>$arg, fqarg=>$fqarg, is_yaml=>1, parsed=>$parsed, %$extra};
                     $seen_opts->{$yopt}++; $seen_func_opts->{$yopt} = $fqarg;
                 }
             }
 
             # parse argv_aliases
             if ($arg_spec->{cmdline_aliases} && !$aliases_processed++) {
                 for my $al (keys %{$arg_spec->{cmdline_aliases}}) {
                     my $alspec = $arg_spec->{cmdline_aliases}{$al};
                     my $alsch = $alspec->{schema} //
                         $alspec->{is_flag} ? [bool=>{req=>1,is=>1}] : $sch;
                     my $altype = $alsch->[0];
                     my $alopt = _arg2opt("$argprefix$al");
                     if ($seen_opts->{$alopt}) {
                         warn "Clash of cmdline_alias option $al";
                         next;
                     }
                     my $alcode = $alspec->{code};
                     my $alospec;
                     my $parsed;
                     if ($alcode && $alsch->[0] eq 'bool') {
                         # bool --alias doesn't get --noalias if has code
                         $alospec = $alopt; # instead of "$alopt!"
                         $parsed = {opts=>[$alopt]};
                     } else {
                         ($alospec, $parsed) = _opt2ospec($alopt, $alsch);
                     }
 
                     if ($alcode) {
                         if ($alcode eq 'CODE') {
                             if ($parent_args->{ignore_converted_code}) {
                                 $alcode = sub {};
                             } else {
                                 return [
                                     501,
                                     join("",
                                          "Code in cmdline_aliases for arg $fqarg ",
                                          "got converted into string, probably ",
                                          "because of JSON/YAML transport"),
                                 ];
                             }
                         }
                         # alias handler
                         $go_spec->{$alospec} = sub {
 
                             # do the same like in arg handler
                             my $num_called = ++$stash->{called}{$arg};
                             my $rargs = do {
                                 if (ref($rargs) eq 'ARRAY') {
                                     $rargs->[$num_called-1] //= {};
                                     $rargs->[$num_called-1];
                                 } else {
                                     $rargs;
                                 }
                             };
 
                             $alcode->($rargs, $_[1]);
                         };
                     } else {
                         $go_spec->{$alospec} = $handler;
                     }
                     $specmeta->{$alospec} = {
                         alias     => $al,
                         is_alias  => 1,
                         alias_for => $ospec,
                         arg       => $arg,
                         fqarg     => $fqarg,
                         is_code   => $alcode ? 1:0,
                         parsed    => $parsed,
                         %$extra,
                     };
                     push @{$specmeta->{$ospec}{($alcode ? '':'non').'code_aliases'}},
                         $alospec;
                     $seen_opts->{$alopt}++; $seen_func_opts->{$alopt} = $fqarg;
                 }
             } # cmdline_aliases
 
             # submetadata
             if ($arg_spec->{meta}) {
                 $rargs->{$arg} = {};
                 my $res = _args2opts(
                     %args,
                     argprefix => "$argprefix$arg\::",
                     meta      => $arg_spec->{meta},
                     rargs     => $rargs->{$arg},
                 );
                 return $res if $res;
             }
 
             # element submetadata
             if ($arg_spec->{element_meta}) {
                 $rargs->{$arg} = [];
                 my $res = _args2opts(
                     %args,
                     argprefix => "$argprefix$arg\::",
                     meta      => $arg_spec->{element_meta},
                     rargs     => $rargs->{$arg},
                 );
                 return $res if $res;
             }
         } # for ospec triplet
 
     } # for arg
 
     undef;
 }
 
 $SPEC{gen_getopt_long_spec_from_meta} = {
     v           => 1.1,
     summary     => 'Generate Getopt::Long spec from Rinci function metadata',
     description => <<'_',
 
 This routine will produce a `Getopt::Long` specification from Rinci function
 metadata, as well as some more data structure in the result metadata to help
 producing a command-line help/usage message.
 
 Function arguments will be mapped to command-line options with the same name,
 with non-alphanumeric characters changed to `-` (`-` is preferred over `_`
 because it lets user avoid pressing Shift on popular keyboards). For example:
 `file_size` becomes `file-size`, `file_size.max` becomes `file-size-max`. If
 function argument option name clashes with command-line option or another
 existing option, it will be renamed to `NAME-arg` (or `NAME-arg2` and so on).
 For example: `help` will become `help-arg` (if `common_opts` contains `help`,
 that is).
 
 Each command-line alias (`cmdline_aliases` property) in the argument
 specification will also be added as command-line option, except if it clashes
 with an existing option, in which case this function will warn and skip adding
 the alias. For more information about `cmdline_aliases`, see `Rinci::function`.
 
 For arguments with type of `bool`, Getopt::Long will by default also
 automatically recognize `--noNAME` or `--no-NAME` in addition to `--name`. So
 this function will also check those names for clashes.
 
 For arguments with type array of simple scalar, `--NAME` can be specified more
 than once to append to the array.
 
 If `per_arg_json` setting is active, and argument's schema is not a "required
 simple scalar" (e.g. an array, or a nullable string), then `--NAME-json` will
 also be added to let users input undef (through `--NAME-json null`) or a
 non-scalar value (e.g. `--NAME-json '[1,2,3]'`). If this name conflicts with
 another existing option, a warning will be displayed and the option will not be
 added.
 
 If `per_arg_yaml` setting is active, and argument's schema is not a "required
 simple scalar" (e.g. an array, or a nullable string), then `--NAME-yaml` will
 also be added to let users input undef (through `--NAME-yaml '~'`) or a
 non-scalar value (e.g. `--NAME-yaml '[foo, bar]'`). If this name conflicts with
 another existing option, a warning will be displayed and the option will not be
 added. YAML can express a larger set of values, e.g. binary data, circular
 references, etc.
 
 Will produce a hash (Getopt::Long spec), with `func.specmeta`, `func.opts`,
 `func.common_opts`, `func.func_opts` that contain extra information
 (`func.specmeta` is a hash of getopt spec name and a hash of extra information
 while `func.*opts` lists all used option names).
 
 _
     args => {
         meta => {
             summary => 'Rinci function metadata',
             schema  => 'hash*',
             req     => 1,
         },
         meta_is_normalized => {
             schema => 'bool*',
         },
         args => {
             summary => 'Reference to hash which will store the result',
             schema  => 'hash*',
         },
         common_opts => {
             summary => 'Common options',
             description => <<'_',
 
 A hash where the values are hashes containing these keys: `getopt` (Getopt::Long
 option specification), `handler` (Getopt::Long handler). Will be passed to
 `get_args_from_argv()`. Example:
 
     {
         help => {
             getopt  => 'help|h|?',
             handler => sub { ... },
             summary => 'Display help and exit',
         },
         version => {
             getopt  => 'version|v',
             handler => sub { ... },
             summary => 'Display version and exit',
         },
     }
 
 _
             schema => ['hash*'],
         },
         per_arg_json => {
             summary => 'Whether to add --NAME-json for non-simple arguments',
             schema  => 'bool',
             default => 0,
             description => <<'_',
 
 Will also interpret command-line arguments as JSON if assigned to function
 arguments, if arguments' schema is not simple scalar.
 
 _
         },
         per_arg_yaml => {
             summary => 'Whether to add --NAME-yaml for non-simple arguments',
             schema  => 'bool',
             default => 0,
             description => <<'_',
 
 Will also interpret command-line arguments as YAML if assigned to function
 arguments, if arguments' schema is not simple scalar.
 
 _
         },
         ignore_converted_code => {
             summary => 'Whether to ignore coderefs converted to string',
             schema => 'bool',
             default => 0,
             description => <<'_',
 
 Across network through JSON encoding, coderef in metadata (e.g. in
 `cmdline_aliases` property) usually gets converted to string `CODE`. In some
 cases, like for tab completion, this is pretty harmless so you can turn this
 option on. For example, in the case of `cmdline_aliases`, the effect is just
 that command-line aliases code are not getting executed, but this is usually
 okay.
 
 _
         },
     },
 };
 sub gen_getopt_long_spec_from_meta {
     my %fargs = @_;
 
     my $meta       = $fargs{meta} or return [400, "Please specify meta"];
     unless ($fargs{meta_is_normalized}) {
         require Perinci::Sub::Normalize;
         $meta = Perinci::Sub::Normalize::normalize_function_metadata($meta);
     }
     my $co           = $fargs{common_opts} // {};
     my $per_arg_yaml = $fargs{per_arg_yaml} // 0;
     my $per_arg_json = $fargs{per_arg_json} // 0;
     my $ignore_converted_code = $fargs{ignore_converted_code};
     my $rargs        = $fargs{args} // {};
 
     my %go_spec;
     my %specmeta; # key = option spec, val = hash of extra info
     my %seen_opts;
     my %seen_common_opts;
     my %seen_func_opts;
 
     for my $k (keys %$co) {
         my $v = $co->{$k};
         my $ospec   = $v->{getopt};
         my $handler = $v->{handler};
         my $res = parse_getopt_long_opt_spec($ospec)
             or return [400, "Can't parse common opt spec '$ospec'"];
         $go_spec{$ospec} = $handler;
         $specmeta{$ospec} = {common_opt=>$k, arg=>undef, parsed=>$res};
         for (@{ $res->{opts} }) {
             return [412, "Clash of common opt '$_'"] if $seen_opts{$_};
             $seen_opts{$_}++; $seen_common_opts{$_} = $ospec;
             if ($res->{is_neg}) {
                 $seen_opts{"no$_"}++ ; $seen_common_opts{"no$_"}  = $ospec;
                 $seen_opts{"no-$_"}++; $seen_common_opts{"no-$_"} = $ospec;
             }
         }
     }
 
     my $res = _args2opts(
         argprefix        => "",
         parent_args      => \%fargs,
         meta             => $meta,
         seen_opts        => \%seen_opts,
         seen_common_opts => \%seen_common_opts,
         seen_func_opts   => \%seen_func_opts,
         rargs            => $rargs,
         go_spec          => \%go_spec,
         specmeta         => \%specmeta,
     );
     return $res if $res;
 
     my $opts        = [sort(map {length($_)>1 ? "--$_":"-$_"} keys %seen_opts)];
     my $common_opts = [sort(map {length($_)>1 ? "--$_":"-$_"} keys %seen_common_opts)];
     my $func_opts   = [sort(map {length($_)>1 ? "--$_":"-$_"} keys %seen_func_opts)];
     my $opts_by_common = {};
     for my $k (keys %$co) {
         my $v = $co->{$k};
         my $ospec = $v->{getopt};
         my @opts;
         for (keys %seen_common_opts) {
             next unless $seen_common_opts{$_} eq $ospec;
             push @opts, (length($_)>1 ? "--$_":"-$_");
         }
         $opts_by_common->{$ospec} = [sort @opts];
     }
 
     my $opts_by_arg = {};
     for (keys %seen_func_opts) {
         my $fqarg = $seen_func_opts{$_};
         push @{ $opts_by_arg->{$fqarg} }, length($_)>1 ? "--$_":"-$_";
     }
     for (keys %$opts_by_arg) {
         $opts_by_arg->{$_} = [sort @{ $opts_by_arg->{$_} }];
     }
 
     [200, "OK", \%go_spec,
      {
          "func.specmeta"       => \%specmeta,
          "func.opts"           => $opts,
          "func.common_opts"    => $common_opts,
          "func.func_opts"      => $func_opts,
          "func.opts_by_arg"    => $opts_by_arg,
          "func.opts_by_common" => $opts_by_common,
      }];
 }
 
 $SPEC{get_args_from_argv} = {
     v => 1.1,
     summary => 'Get subroutine arguments (%args) from command-line arguments '.
         '(@ARGV)',
     description => <<'_',
 
 Using information in Rinci function metadata's `args` property, parse command
 line arguments `@argv` into hash `%args`, suitable for passing into subroutines.
 
 Currently uses Getopt::Long's GetOptions to do the parsing.
 
 As with GetOptions, this function modifies its `argv` argument, so you might
 want to copy the original `argv` first (or pass a copy instead) if you want to
 preserve the original.
 
 See also: gen_getopt_long_spec_from_meta() which is the routine that generates
 the specification.
 
 _
     args => {
         argv => {
             schema => ['array*' => {
                 of => 'str*',
             }],
             description => 'If not specified, defaults to @ARGV',
         },
         args => {
             summary => 'Specify input args, with some arguments preset',
             schema  => ['hash'],
         },
         meta => {
             schema => ['hash*' => {}],
             req => 1,
         },
         meta_is_normalized => {
             summary => 'Can be set to 1 if your metadata is normalized, '.
                 'to avoid duplicate effort',
             schema => 'bool',
             default => 0,
         },
         strict => {
             schema => ['bool' => {default=>1}],
             summary => 'Strict mode',
             description => <<'_',
 
 If set to 0, will still return parsed argv even if there are parsing errors
 (reported by Getopt::Long). If set to 1 (the default), will die upon error.
 
 Normally you would want to use strict mode, for more error checking. Setting off
 strict is used by, for example, Perinci::Sub::Complete during completion where
 the command-line might still be incomplete.
 
 Should probably be named `ignore_errors`. :-)
 
 _
         },
         per_arg_yaml => {
             schema => ['bool' => {default=>0}],
             summary => 'Whether to recognize --ARGNAME-yaml',
             description => <<'_',
 
 This is useful for example if you want to specify a value which is not
 expressible from the command-line, like 'undef'.
 
     % script.pl --name-yaml '~'
 
 See also: per_arg_json. You should enable just one instead of turning on both.
 
 _
         },
         per_arg_json => {
             schema => ['bool' => {default=>0}],
             summary => 'Whether to recognize --ARGNAME-json',
             description => <<'_',
 
 This is useful for example if you want to specify a value which is not
 expressible from the command-line, like 'undef'.
 
     % script.pl --name-json 'null'
 
 But every other string will need to be quoted:
 
     % script.pl --name-json '"foo"'
 
 See also: per_arg_yaml. You should enable just one instead of turning on both.
 
 _
         },
         common_opts => {
             summary => 'Common options',
             description => <<'_',
 
 A hash where the values are hashes containing these keys: `getopt` (Getopt::Long
 option specification), `handler` (Getopt::Long handler). Will be passed to
 `get_args_from_argv()`. Example:
 
     {
         help => {
             getopt  => 'help|h|?',
             handler => sub { ... },
             summary => 'Display help and exit',
         },
         version => {
             getopt  => 'version|v',
             handler => sub { ... },
             summary => 'Display version and exit',
         },
     }
 
 _
             schema => ['hash*'],
         },
         allow_extra_elems => {
             schema => ['bool' => {default=>0}],
             summary => 'Allow extra/unassigned elements in argv',
             description => <<'_',
 
 If set to 1, then if there are array elements unassigned to one of the
 arguments, instead of generating an error, this function will just ignore them.
 
 This option will be passed to Perinci::Sub::GetArgs::Array's allow_extra_elems.
 
 _
         },
         on_missing_required_args => {
             schema => 'code',
             summary => 'Execute code when there is missing required args',
             description => <<'_',
 
 This can be used to give a chance to supply argument value from other sources if
 not specified by command-line options. Perinci::CmdLine, for example, uses this
 hook to supply value from STDIN or file contents (if argument has `cmdline_src`
 specification key set).
 
 This hook will be called for each missing argument. It will be supplied hash
 arguments: (arg => $the_missing_argument_name, args =>
 $the_resulting_args_so_far, spec => $the_arg_spec).
 
 The hook can return true if it succeeds in making the missing situation
 resolved. In this case, this function will not report the argument as missing.
 
 _
         },
         ignore_converted_code => {
             summary => 'Whether to ignore coderefs converted to string',
             schema => 'bool',
             default => 0,
             description => <<'_',
 
 Across network through JSON encoding, coderef in metadata (e.g. in
 `cmdline_aliases` property) usually gets converted to string `CODE`. In some
 cases, like for tab completion, this is harmless so you can turn this option on.
 
 _
         },
     },
     result => {
         description => <<'_',
 
 Error codes:
 
 * 400 - Error in Getopt::Long option specification, e.g. in common_opts.
 
 * 500 - failure in GetOptions, meaning argv is not valid according to metadata
   specification (only if 'strict' mode is enabled).
 
 * 501 - coderef in cmdline_aliases got converted into a string, probably because
   the metadata was transported (e.g. through Riap::HTTP/Riap::Simple).
 
 _
     },
 };
 sub get_args_from_argv {
     require Getopt::Long;
 
     my %fargs = @_;
     my $argv       = $fargs{argv} // \@ARGV;
     my $meta       = $fargs{meta} or return [400, "Please specify meta"];
     unless ($fargs{meta_is_normalized}) {
         require Perinci::Sub::Normalize;
         $meta = Perinci::Sub::Normalize::normalize_function_metadata($meta);
     }
     my $strict            = $fargs{strict} // 1;
     my $common_opts       = $fargs{common_opts} // {};
     my $per_arg_yaml      = $fargs{per_arg_yaml} // 0;
     my $per_arg_json      = $fargs{per_arg_json} // 0;
     my $allow_extra_elems = $fargs{allow_extra_elems} // 0;
     my $on_missing        = $fargs{on_missing_required_args};
     my $ignore_converted_code = $fargs{ignore_converted_code};
     #$log->tracef("-> get_args_from_argv(), argv=%s", $argv);
 
     # to store the resulting args
     my $rargs = $fargs{args} // {};
 
     # 1. first we generate Getopt::Long spec
     my $genres = gen_getopt_long_spec_from_meta(
         meta => $meta, meta_is_normalized => 1,
         args => $rargs,
         common_opts  => $common_opts,
         per_arg_json => $per_arg_json,
         per_arg_yaml => $per_arg_yaml,
         ignore_converted_code => $ignore_converted_code,
     );
     return err($genres->[0], "Can't generate Getopt::Long spec", $genres)
         if $genres->[0] != 200;
     my $go_spec = $genres->[2];
 
     # 2. then we run GetOptions to fill $rargs from command-line opts
     #$log->tracef("GetOptions spec: %s", \@go_spec);
     {
         local $SIG{__WARN__} = sub{} if !$strict;
         my $old_go_conf = Getopt::Long::Configure(
             $strict ? "no_pass_through" : "pass_through",
             "no_ignore_case", "permute", "bundling", "no_getopt_compat");
         my $res = Getopt::Long::GetOptionsFromArray($argv, %$go_spec);
         Getopt::Long::Configure($old_go_conf);
         unless ($res) {
             return [500, "GetOptions failed"] if $strict;
         }
     }
 
     # 3. then we try to fill $rargs from remaining command-line arguments (for
     # args which have 'pos' spec specified)
 
     my $args_prop = $meta->{args};
 
     if (@$argv) {
         my $res = get_args_from_array(
             array=>$argv, meta => $meta,
             meta_is_normalized => 1,
             allow_extra_elems => $allow_extra_elems,
         );
         if ($res->[0] != 200 && $strict) {
             return err(500, "Get args from array failed", $res);
         } elsif ($strict && $res->[0] != 200) {
             return err("Can't get args from argv", $res);
         } elsif ($res->[0] == 200) {
             my $pos_args = $res->[2];
             for my $name (keys %$pos_args) {
                 my $arg_spec = $args_prop->{$name};
                 my $val      = $pos_args->{$name};
                 if (exists $rargs->{$name}) {
                     return [400, "You specified option --$name but also ".
                                 "argument #".$arg_spec->{pos}] if $strict;
                 }
                 my $type = $arg_spec->{schema}[0];
                 my $cs   = $arg_spec->{schema}[1];
                 my $is_simple_scalar = $type =~ $re_simple_scalar;
                 my $is_array_of_simple_scalar = $type eq 'array' &&
                     $cs->{of} && $cs->{of}[0] =~ $re_simple_scalar;
 
                 if ($arg_spec->{greedy} && ref($val) eq 'ARRAY' &&
                         !$is_array_of_simple_scalar) {
                     my $i = 0;
                     for (@$val) {
                       TRY_PARSING_AS_JSON_YAML:
                         {
                             my ($success, $e, $decoded);
                             if ($per_arg_json) {
                                 ($success, $e, $decoded) = _parse_json($_);
                                 if ($success) {
                                     $_ = $decoded;
                                     last TRY_PARSING_AS_JSON_YAML;
                                 } else {
                                     warn "Failed trying to parse argv #$i as JSON: $e";
                                 }
                             }
                             if ($per_arg_yaml) {
                                 ($success, $e, $decoded) = _parse_yaml($_);
                                 if ($success) {
                                     $_ = $decoded;
                                     last TRY_PARSING_AS_JSON_YAML;
                                 } else {
                                     warn "Failed trying to parse argv #$i as YAML: $e";
                                 }
                             }
                         }
                         $i++;
                     }
                 }
                 if (!$arg_spec->{greedy} && !$is_simple_scalar) {
                   TRY_PARSING_AS_JSON_YAML:
                     {
                         my ($success, $e, $decoded);
                         if ($per_arg_json) {
                             ($success, $e, $decoded) = _parse_json($val);
                             if ($success) {
                                 $val = $decoded;
                                 last TRY_PARSING_AS_JSON_YAML;
                             } else {
                                 warn "Failed trying to parse argv #$arg_spec->{pos} as JSON: $e";
                             }
                         }
                         if ($per_arg_yaml) {
                             ($success, $e, $decoded) = _parse_yaml($val);
                             if ($success) {
                                 $val = $decoded;
                                 last TRY_PARSING_AS_JSON_YAML;
                             } else {
                                 warn "Failed trying to parse argv #$arg_spec->{pos} as YAML: $e";
                             }
                         }
                     }
                 }
                 $rargs->{$name} = $val;
                 # we still call cmdline_on_getopt for this
                 if ($arg_spec->{cmdline_on_getopt}) {
                     if ($arg_spec->{greedy}) {
                         $arg_spec->{cmdline_on_getopt}->(
                             arg=>$name, fqarg=>$name, value=>$_, args=>$rargs,
                             opt=>undef, # this marks that value is retrieved from cmdline arg
                         ) for @$val;
                     } else {
                         $arg_spec->{cmdline_on_getopt}->(
                             arg=>$name, fqarg=>$name, value=>$val, args=>$rargs,
                             opt=>undef, # this marks that value is retrieved from cmdline arg
                         );
                     }
                 }
             }
         }
     }
 
     # 4. check missing required args
 
     my %missing_args;
     for my $arg (keys %$args_prop) {
         my $arg_spec = $args_prop->{$arg};
         if (!exists($rargs->{$arg})) {
             next unless $arg_spec->{req};
             # give a chance to hook to set missing arg
             if ($on_missing) {
                 next if $on_missing->(arg=>$arg, args=>$rargs, spec=>$arg_spec);
             }
             next if exists $rargs->{$arg};
             $missing_args{$arg} = 1;
         }
     }
 
     # 5. check 'deps', currently we only support 'arg' dep type
     {
         last unless $strict;
 
         for my $arg (keys %$args_prop) {
             my $arg_spec = $args_prop->{$arg};
             next unless exists $rargs->{$arg};
             next unless $arg_spec->{deps};
             my $dep_arg = $arg_spec->{deps}{arg};
             next unless $dep_arg;
             return [400, "You specify '$arg', but don't specify '$dep_arg' ".
                         "(upon which '$arg' depends)"]
                 unless exists $rargs->{$dep_arg};
         }
     }
 
     #$log->tracef("<- get_args_from_argv(), args=%s, remaining argv=%s",
     #             $rargs, $argv);
     [200, "OK", $rargs, {
         "func.missing_args" => [sort keys %missing_args],
         "func.gen_getopt_long_spec_result" => $genres,
     }];
 }
 
 1;
 # ABSTRACT: Get subroutine arguments from command line arguments (@ARGV)
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Perinci::Sub::GetArgs::Argv - Get subroutine arguments from command line arguments (@ARGV)
 
 =head1 VERSION
 
 This document describes version 0.69 of Perinci::Sub::GetArgs::Argv (from Perl distribution Perinci-Sub-GetArgs-Argv), released on 2015-08-19.
 
 =head1 SYNOPSIS
 
  use Perinci::Sub::GetArgs::Argv;
 
  my $res = get_args_from_argv(argv=>\@ARGV, meta=>$meta, ...);
 
 =head1 DESCRIPTION
 
 This module provides C<get_args_from_argv()>, which parses command line
 arguments (C<@ARGV>) into subroutine arguments (C<%args>). This module is used
 by L<Perinci::CmdLine>. For explanation on how command-line options are
 processed, see Perinci::CmdLine's documentation.
 
 =head1 FUNCTIONS
 
 
 =head2 gen_getopt_long_spec_from_meta(%args) -> [status, msg, result, meta]
 
 {en_US Generate Getopt::Long spec from Rinci function metadata}.
 
 {en_US 
 This routine will produce a C<Getopt::Long> specification from Rinci function
 metadata, as well as some more data structure in the result metadata to help
 producing a command-line help/usage message.
 
 Function arguments will be mapped to command-line options with the same name,
 with non-alphanumeric characters changed to C<-> (C<-> is preferred over C<_>
 because it lets user avoid pressing Shift on popular keyboards). For example:
 C<file_size> becomes C<file-size>, C<file_size.max> becomes C<file-size-max>. If
 function argument option name clashes with command-line option or another
 existing option, it will be renamed to C<NAME-arg> (or C<NAME-arg2> and so on).
 For example: C<help> will become C<help-arg> (if C<common_opts> contains C<help>,
 that is).
 
 Each command-line alias (C<cmdline_aliases> property) in the argument
 specification will also be added as command-line option, except if it clashes
 with an existing option, in which case this function will warn and skip adding
 the alias. For more information about C<cmdline_aliases>, see C<Rinci::function>.
 
 For arguments with type of C<bool>, Getopt::Long will by default also
 automatically recognize C<--noNAME> or C<--no-NAME> in addition to C<--name>. So
 this function will also check those names for clashes.
 
 For arguments with type array of simple scalar, C<--NAME> can be specified more
 than once to append to the array.
 
 If C<per_arg_json> setting is active, and argument's schema is not a "required
 simple scalar" (e.g. an array, or a nullable string), then C<--NAME-json> will
 also be added to let users input undef (through C<--NAME-json null>) or a
 non-scalar value (e.g. C<--NAME-json '[1,2,3]'>). If this name conflicts with
 another existing option, a warning will be displayed and the option will not be
 added.
 
 If C<per_arg_yaml> setting is active, and argument's schema is not a "required
 simple scalar" (e.g. an array, or a nullable string), then C<--NAME-yaml> will
 also be added to let users input undef (through C<--NAME-yaml '~'>) or a
 non-scalar value (e.g. C<--NAME-yaml '[foo, bar]'>). If this name conflicts with
 another existing option, a warning will be displayed and the option will not be
 added. YAML can express a larger set of values, e.g. binary data, circular
 references, etc.
 
 Will produce a hash (Getopt::Long spec), with C<func.specmeta>, C<func.opts>,
 C<func.common_opts>, C<func.func_opts> that contain extra information
 (C<func.specmeta> is a hash of getopt spec name and a hash of extra information
 while C<func.*opts> lists all used option names).
 }
 
 Arguments ('*' denotes required arguments):
 
 =over 4
 
 =item * B<args> => I<hash>
 
 {en_US Reference to hash which will store the result}.
 
 =item * B<common_opts> => I<hash>
 
 {en_US Common options}.
 
 {en_US 
 A hash where the values are hashes containing these keys: C<getopt> (Getopt::Long
 option specification), C<handler> (Getopt::Long handler). Will be passed to
 C<get_args_from_argv()>. Example:
 
  {
      help => {
          getopt  => 'help|h|?',
          handler => sub { ... },
          summary => 'Display help and exit',
      },
      version => {
          getopt  => 'version|v',
          handler => sub { ... },
          summary => 'Display version and exit',
      },
  }
 
 }
 
 =item * B<ignore_converted_code> => I<bool> (default: 0)
 
 {en_US Whether to ignore coderefs converted to string}.
 
 {en_US 
 Across network through JSON encoding, coderef in metadata (e.g. in
 C<cmdline_aliases> property) usually gets converted to string C<CODE>. In some
 cases, like for tab completion, this is pretty harmless so you can turn this
 option on. For example, in the case of C<cmdline_aliases>, the effect is just
 that command-line aliases code are not getting executed, but this is usually
 okay.
 }
 
 =item * B<meta>* => I<hash>
 
 {en_US Rinci function metadata}.
 
 =item * B<meta_is_normalized> => I<bool>
 
 =item * B<per_arg_json> => I<bool> (default: 0)
 
 {en_US Whether to add --NAME-json for non-simple arguments}.
 
 {en_US 
 Will also interpret command-line arguments as JSON if assigned to function
 arguments, if arguments' schema is not simple scalar.
 }
 
 =item * B<per_arg_yaml> => I<bool> (default: 0)
 
 {en_US Whether to add --NAME-yaml for non-simple arguments}.
 
 {en_US 
 Will also interpret command-line arguments as YAML if assigned to function
 arguments, if arguments' schema is not simple scalar.
 }
 
 =back
 
 Returns an enveloped result (an array).
 
 First element (status) is an integer containing HTTP status code
 (200 means OK, 4xx caller error, 5xx function error). Second element
 (msg) is a string containing error message, or 'OK' if status is
 200. Third element (result) is optional, the actual result. Fourth
 element (meta) is called result metadata and is optional, a hash
 that contains extra information.
 
 Return value:  (any)
 
 
 =head2 get_args_from_argv(%args) -> [status, msg, result, meta]
 
 {en_US Get subroutine arguments (%args) from command-line arguments (@ARGV)}.
 
 {en_US 
 Using information in Rinci function metadata's C<args> property, parse command
 line arguments C<@argv> into hash C<%args>, suitable for passing into subroutines.
 
 Currently uses Getopt::Long's GetOptions to do the parsing.
 
 As with GetOptions, this function modifies its C<argv> argument, so you might
 want to copy the original C<argv> first (or pass a copy instead) if you want to
 preserve the original.
 
 See also: gen_getopt_long_spec_from_meta() which is the routine that generates
 the specification.
 }
 
 Arguments ('*' denotes required arguments):
 
 =over 4
 
 =item * B<allow_extra_elems> => I<bool> (default: 0)
 
 {en_US Allow extra/unassigned elements in argv}.
 
 {en_US 
 If set to 1, then if there are array elements unassigned to one of the
 arguments, instead of generating an error, this function will just ignore them.
 
 This option will be passed to Perinci::Sub::GetArgs::Array's allow_extra_elems.
 }
 
 =item * B<args> => I<hash>
 
 {en_US Specify input args, with some arguments preset}.
 
 =item * B<argv> => I<array[str]>
 
 {en_US If not specified, defaults to @ARGV}
 
 =item * B<common_opts> => I<hash>
 
 {en_US Common options}.
 
 {en_US 
 A hash where the values are hashes containing these keys: C<getopt> (Getopt::Long
 option specification), C<handler> (Getopt::Long handler). Will be passed to
 C<get_args_from_argv()>. Example:
 
  {
      help => {
          getopt  => 'help|h|?',
          handler => sub { ... },
          summary => 'Display help and exit',
      },
      version => {
          getopt  => 'version|v',
          handler => sub { ... },
          summary => 'Display version and exit',
      },
  }
 
 }
 
 =item * B<ignore_converted_code> => I<bool> (default: 0)
 
 {en_US Whether to ignore coderefs converted to string}.
 
 {en_US 
 Across network through JSON encoding, coderef in metadata (e.g. in
 C<cmdline_aliases> property) usually gets converted to string C<CODE>. In some
 cases, like for tab completion, this is harmless so you can turn this option on.
 }
 
 =item * B<meta>* => I<hash>
 
 =item * B<meta_is_normalized> => I<bool> (default: 0)
 
 {en_US Can be set to 1 if your metadata is normalized, to avoid duplicate effort}.
 
 =item * B<on_missing_required_args> => I<code>
 
 {en_US Execute code when there is missing required args}.
 
 {en_US 
 This can be used to give a chance to supply argument value from other sources if
 not specified by command-line options. Perinci::CmdLine, for example, uses this
 hook to supply value from STDIN or file contents (if argument has C<cmdline_src>
 specification key set).
 
 This hook will be called for each missing argument. It will be supplied hash
 arguments: (arg => $the_missing_argument_name, args =>
 $the_resulting_args_so_far, spec => $the_arg_spec).
 
 The hook can return true if it succeeds in making the missing situation
 resolved. In this case, this function will not report the argument as missing.
 }
 
 =item * B<per_arg_json> => I<bool> (default: 0)
 
 {en_US Whether to recognize --ARGNAME-json}.
 
 {en_US 
 This is useful for example if you want to specify a value which is not
 expressible from the command-line, like 'undef'.
 
  % script.pl --name-json 'null'
 
 But every other string will need to be quoted:
 
  % script.pl --name-json '"foo"'
 
 See also: per_arg_yaml. You should enable just one instead of turning on both.
 }
 
 =item * B<per_arg_yaml> => I<bool> (default: 0)
 
 {en_US Whether to recognize --ARGNAME-yaml}.
 
 {en_US 
 This is useful for example if you want to specify a value which is not
 expressible from the command-line, like 'undef'.
 
  % script.pl --name-yaml '~'
 
 See also: per_arg_json. You should enable just one instead of turning on both.
 }
 
 =item * B<strict> => I<bool> (default: 1)
 
 {en_US Strict mode}.
 
 {en_US 
 If set to 0, will still return parsed argv even if there are parsing errors
 (reported by Getopt::Long). If set to 1 (the default), will die upon error.
 
 Normally you would want to use strict mode, for more error checking. Setting off
 strict is used by, for example, Perinci::Sub::Complete during completion where
 the command-line might still be incomplete.
 
 Should probably be named C<ignore_errors>. :-)
 }
 
 =back
 
 Returns an enveloped result (an array).
 
 First element (status) is an integer containing HTTP status code
 (200 means OK, 4xx caller error, 5xx function error). Second element
 (msg) is a string containing error message, or 'OK' if status is
 200. Third element (result) is optional, the actual result. Fourth
 element (meta) is called result metadata and is optional, a hash
 that contains extra information.
 
 Return value:  (any)
 
 
 {en_US 
 Error codes:
 
 =over
 
 =item * 400 - Error in Getopt::Long option specification, e.g. in common_opts.
 
 =item * 500 - failure in GetOptions, meaning argv is not valid according to metadata
 specification (only if 'strict' mode is enabled).
 
 =item * 501 - coderef in cmdline_aliases got converted into a string, probably because
 the metadata was transported (e.g. through Riap::HTTP/Riap::Simple).
 }
 
 =back
 
 =head1 FAQ
 
 =head1 SEE ALSO
 
 L<Perinci>
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Perinci-Sub-GetArgs-Argv>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Perinci-Sub-GetArgs-Argv>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Perinci-Sub-GetArgs-Argv>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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
### Perinci/Sub/GetArgs/Array.pm ###
 package Perinci::Sub::GetArgs::Array;
 
 our $DATE = '2015-09-04'; # DATE
 our $VERSION = '0.15'; # VERSION
 
 use 5.010001;
 use strict;
 use warnings;
 #use Log::Any '$log';
 
 use Exporter;
 our @ISA = qw(Exporter);
 our @EXPORT_OK = qw(get_args_from_array);
 
 our %SPEC;
 
 $SPEC{':package'} = {
     v => 1.1,
 };
 
 $SPEC{get_args_from_array} = {
     v => 1.1,
     summary => 'Get subroutine arguments (%args) from array',
     description => <<'_',
 
 Using information in metadata's `args` property (particularly the `pos` and
 `greedy` arg type clauses), extract arguments from an array into a hash
 `\%args`, suitable for passing into subs.
 
 Example:
 
     my $meta = {
         v => 1.1,
         summary => 'Multiply 2 numbers (a & b)',
         args => {
             a => {schema=>'num*', pos=>0},
             b => {schema=>'num*', pos=>1},
         }
     }
 
 then `get_args_from_array(array=>[2, 3], meta=>$meta)` will produce:
 
     [200, "OK", {a=>2, b=>3}]
 
 _
     args => {
         array => {
             schema => ['array*' => {}],
             req => 1,
             description => <<'_',
 
 NOTE: array will be modified/emptied (elements will be taken from the array as
 they are put into the resulting args). Copy your array first if you want to
 preserve its content.
 
 _
         },
         meta => {
             schema => ['hash*' => {}],
             req => 1,
         },
         meta_is_normalized => {
             summary => 'Can be set to 1 if your metadata is normalized, '.
                 'to avoid duplicate effort',
             schema => 'bool',
             default => 0,
         },
         allow_extra_elems => {
             schema => ['bool' => {default=>0}],
             summary => 'Allow extra/unassigned elements in array',
             description => <<'_',
 
 If set to 1, then if there are array elements unassigned to one of the arguments
 (due to missing `pos`, for example), instead of generating an error, the
 function will just ignore them.
 
 _
         },
     },
 };
 sub get_args_from_array {
     my %fargs = @_;
     my $ary  = $fargs{array} or return [400, "Please specify array"];
     my $meta = $fargs{meta} or return [400, "Please specify meta"];
     unless ($fargs{meta_is_normalized}) {
         require Perinci::Sub::Normalize;
         $meta = Perinci::Sub::Normalize::normalize_function_metadata(
             $meta);
     }
     my $allow_extra_elems = $fargs{allow_extra_elems} // 0;
 
     my $rargs = {};
 
     my $args_p = $meta->{args} // {};
     for my $i (reverse 0..@$ary-1) {
         #$log->tracef("i=$i");
         while (my ($a, $as) = each %$args_p) {
             my $o = $as->{pos};
             if (defined($o) && $o == $i) {
                 if ($as->{greedy}) {
                     my $type = $as->{schema}[0];
                     my @elems = splice(@$ary, $i);
                     if ($type eq 'array') {
                         $rargs->{$a} = \@elems;
                     } else {
                         $rargs->{$a} = join " ", @elems;
                     }
                     #$log->tracef("assign %s to arg->{$a}", $rargs->{$a});
                 } else {
                     $rargs->{$a} = splice(@$ary, $i, 1);
                     #$log->tracef("assign %s to arg->{$a}", $rargs->{$a});
                 }
             }
         }
     }
 
     return [400, "There are extra, unassigned elements in array: [".
                 join(", ", @$ary)."]"] if @$ary && !$allow_extra_elems;
 
     [200, "OK", $rargs];
 }
 
 1;
 # ABSTRACT: Get subroutine arguments (%args) from array
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Perinci::Sub::GetArgs::Array - Get subroutine arguments (%args) from array
 
 =head1 VERSION
 
 This document describes version 0.15 of Perinci::Sub::GetArgs::Array (from Perl distribution Perinci-Sub-GetArgs-Array), released on 2015-09-04.
 
 =head1 SYNOPSIS
 
  use Perinci::Sub::GetArgs::Array;
 
  my $res = get_args_from_array(array=>\@ary, meta=>$meta, ...);
 
 =head1 DESCRIPTION
 
 This module provides get_args_from_array(). This module is used by, among
 others, L<Perinci::Sub::GetArgs::Argv>.
 
 =head1 FUNCTIONS
 
 
 =head2 get_args_from_array(%args) -> [status, msg, result, meta]
 
 Get subroutine arguments (%args) from array.
 
 Using information in metadata's C<args> property (particularly the C<pos> and
 C<greedy> arg type clauses), extract arguments from an array into a hash
 C<\%args>, suitable for passing into subs.
 
 Example:
 
  my $meta = {
      v => 1.1,
      summary => 'Multiply 2 numbers (a & b)',
      args => {
          a => {schema=>'num*', pos=>0},
          b => {schema=>'num*', pos=>1},
      }
  }
 
 then C<< get_args_from_array(array=E<gt>[2, 3], meta=E<gt>$meta) >> will produce:
 
  [200, "OK", {a=>2, b=>3}]
 
 Arguments ('*' denotes required arguments):
 
 =over 4
 
 =item * B<allow_extra_elems> => I<bool> (default: 0)
 
 Allow extra/unassigned elements in array.
 
 If set to 1, then if there are array elements unassigned to one of the arguments
 (due to missing C<pos>, for example), instead of generating an error, the
 function will just ignore them.
 
 =item * B<array>* => I<array>
 
 NOTE: array will be modified/emptied (elements will be taken from the array as
 they are put into the resulting args). Copy your array first if you want to
 preserve its content.
 
 =item * B<meta>* => I<hash>
 
 =item * B<meta_is_normalized> => I<bool> (default: 0)
 
 Can be set to 1 if your metadata is normalized, to avoid duplicate effort.
 
 =back
 
 Returns an enveloped result (an array).
 
 First element (status) is an integer containing HTTP status code
 (200 means OK, 4xx caller error, 5xx function error). Second element
 (msg) is a string containing error message, or 'OK' if status is
 200. Third element (result) is optional, the actual result. Fourth
 element (meta) is called result metadata and is optional, a hash
 that contains extra information.
 
 Return value:  (any)
 
 =head1 SEE ALSO
 
 L<Perinci>
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Perinci-Sub-GetArgs-Array>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Perinci-Sub-GetArgs-Array>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Perinci-Sub-GetArgs-Array>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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
### Perinci/Sub/Normalize.pm ###
 package Perinci::Sub::Normalize;
 
 our $DATE = '2015-09-30'; # DATE
 our $VERSION = '0.13'; # VERSION
 
 use 5.010001;
 use strict;
 use warnings;
 
 require Exporter;
 our @ISA = qw(Exporter);
 our @EXPORT_OK = qw(
                        normalize_function_metadata
                );
 
 use Sah::Schema::Rinci;
 my $sch = $Sah::Schema::Rinci::SCHEMAS{rinci_function}
     or die "BUG: Rinci schema structure changed (1)";
 my $sch_proplist = $sch->[1]{_prop}
     or die "BUG: Rinci schema structure changed (2)";
 
 sub _normalize{
     my ($meta, $ver, $opts, $proplist, $nmeta, $prefix, $modprefix) = @_;
 
     my $opt_aup = $opts->{allow_unknown_properties};
     my $opt_nss = $opts->{normalize_sah_schemas};
     my $opt_rip = $opts->{remove_internal_properties};
 
     if (defined $ver) {
         defined($meta->{v}) && $meta->{v} eq $ver
             or die "$prefix: Metadata version must be $ver";
     }
 
   KEY:
     for my $k (keys %$meta) {
         die "Invalid prop/attr syntax '$k', must be word/dotted-word only"
             unless $k =~ /\A(\w+)(?:\.(\w+(?:\.\w+)*))?(?:\((\w+)\))?\z/;
 
         my ($prop, $attr);
         if (defined $3) {
             $prop = $1;
             $attr = defined($2) ? "$2.alt.lang.$3" : "alt.lang.$3";
         } else {
             $prop = $1;
             $attr = $2;
         }
 
         my $nk = "$prop" . (defined($attr) ? ".$attr" : "");
 
         # strip property/attr started with _
         if ($prop =~ /\A_/ || defined($attr) && $attr =~ /\A_|\._/) {
             unless ($opt_rip) {
                 $nmeta->{$nk} = $meta->{$k};
             }
             next KEY;
         }
 
         my $prop_proplist = $proplist->{$prop};
 
         # try to load module that declare new props first
         if (!$opt_aup && !$prop_proplist) {
             $modprefix //= $prefix;
             my $mod = "Perinci/Sub/Property$modprefix/$prop.pm";
             eval { require $mod };
             # hide technical error message from require()
             if ($@) {
                 die "Unknown property '$prefix/$prop' (and couldn't ".
                     "load property module '$mod'): $@" if $@;
             }
             $prop_proplist = $proplist->{$prop};
         }
         die "Unknown property '$prefix/$prop'"
             unless $opt_aup || $prop_proplist;
 
         if ($prop_proplist && $prop_proplist->{_prop}) {
             die "Property '$prefix/$prop' must be a hash"
                 unless ref($meta->{$k}) eq 'HASH';
             $nmeta->{$nk} = {};
             _normalize(
                 $meta->{$k},
                 $prop_proplist->{_ver},
                 $opts,
                 $prop_proplist->{_prop},
                 $nmeta->{$nk},
                 "$prefix/$prop",
             );
         } elsif ($prop_proplist && $prop_proplist->{_elem_prop}) {
             die "Property '$prefix/$prop' must be an array"
                 unless ref($meta->{$k}) eq 'ARRAY';
             $nmeta->{$nk} = [];
             my $i = 0;
             for (@{ $meta->{$k} }) {
                 my $href = {};
                 if (ref($_) eq 'HASH') {
                     _normalize(
                         $_,
                         $prop_proplist->{_ver},
                         $opts,
                         $prop_proplist->{_elem_prop},
                         $href,
                         "$prefix/$prop/$i",
                     );
                     push @{ $nmeta->{$nk} }, $href;
                 } else {
                     push @{ $nmeta->{$nk} }, $_;
                 }
                 $i++;
             }
         } elsif ($prop_proplist && $prop_proplist->{_value_prop}) {
             die "Property '$prefix/$prop' must be a hash"
                 unless ref($meta->{$k}) eq 'HASH';
             $nmeta->{$nk} = {};
             for (keys %{ $meta->{$k} }) {
                 $nmeta->{$nk}{$_} = {};
                 die "Property '$prefix/$prop/$_' must be a hash"
                     unless ref($meta->{$k}{$_}) eq 'HASH';
                 _normalize(
                     $meta->{$k}{$_},
                     $prop_proplist->{_ver},
                     $opts,
                     $prop_proplist->{_value_prop},
                     $nmeta->{$nk}{$_},
                     "$prefix/$prop/$_",
                     ($prop eq 'args' ? "$prefix/arg" : undef),
                 );
             }
         } else {
             if ($k eq 'schema' && $opt_nss) { # XXX currently hardcoded
                 require Data::Sah::Normalize;
                 $nmeta->{$nk} = Data::Sah::Normalize::normalize_schema(
                     $meta->{$k});
             } else {
                 $nmeta->{$nk} = $meta->{$k};
             }
         }
     }
 
     $nmeta;
 }
 
 sub normalize_function_metadata($;$) {
     my ($meta, $opts) = @_;
 
     $opts //= {};
 
     $opts->{allow_unknown_properties}    //= 0;
     $opts->{normalize_sah_schemas}       //= 1;
     $opts->{remove_internal_properties}  //= 0;
 
     _normalize($meta, 1.1, $opts, $sch_proplist, {}, '');
 }
 
 1;
 # ABSTRACT: Normalize Rinci function metadata
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Perinci::Sub::Normalize - Normalize Rinci function metadata
 
 =head1 VERSION
 
 This document describes version 0.13 of Perinci::Sub::Normalize (from Perl distribution Perinci-Sub-Normalize), released on 2015-09-30.
 
 =head1 SYNOPSIS
 
  use Perinci::Sub::Normalize qw(normalize_function_metadata);
 
  my $nmeta = normalize_function_metadata($meta);
 
 =head1 FUNCTIONS
 
 =head2 normalize_function_metadata($meta[ , \%opts ]) => HASH
 
 Normalize and check L<Rinci> function metadata C<$meta>. Return normalized
 metadata, which is a shallow copy of C<$meta>. Die on error.
 
 Available options:
 
 =over
 
 =item * allow_unknown_properties => BOOL (default: 0)
 
 If set to true, will die if there are unknown properties.
 
 =item * normalize_sah_schemas => BOOL (default: 1)
 
 By default, L<Sah> schemas e.g. in C<result/schema> or C<args/*/schema> property
 is normalized using L<Data::Sah>'s C<normalize_schema>. Set this to 0 if you
 don't want this.
 
 =item * remove_internal_properties => BOOL (default: 0)
 
 If set to 1, all properties and attributes starting with underscore (C<_>) with
 will be stripped. According to L<DefHash> specification, they are ignored and
 usually contain notes/comments/extra information.
 
 =back
 
 =head1 SEE ALSO
 
 L<Rinci::function>
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Perinci-Sub-Normalize>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Perinci-Sub-Normalize>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Perinci-Sub-Normalize>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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
### Perinci/Sub/To/CLIDocData.pm ###
 package Perinci::Sub::To::CLIDocData;
 
 our $DATE = '2015-09-23'; # DATE
 our $VERSION = '0.23'; # VERSION
 
 use 5.010001;
 use strict;
 use warnings;
 
 use Perinci::Object;
 use Perinci::Sub::Util qw(err);
 
 our %SPEC;
 
 require Exporter;
 our @ISA = qw(Exporter);
 our @EXPORT_OK = qw(gen_cli_doc_data_from_meta);
 
 sub _has_cats {
     for my $spec (@{ $_[0] }) {
         for (@{ $spec->{tags} // [] }) {
             my $tag_name = ref($_) ? $_->{name} : $_;
             if ($tag_name =~ /^category:/) {
                 return 1;
             }
         }
     }
     0;
 }
 
 sub _add_category_from_spec {
     my ($cats_spec, $thing, $spec, $noun, $has_cats) = @_;
     my @cats;
     for (@{ $spec->{tags} // [] }) {
         my $tag_name = ref($_) ? $_->{name} : $_;
         if ($tag_name =~ /^category:(.+)/) {
             my $cat = ucfirst($1);
             $cat =~ s/-/ /g;
             $cat .= " " . $noun;
             push @cats, [$cat, 50]; # name, ordering
         }
     }
     if (!@cats) {
         @cats = [$has_cats ? "Other $noun" : ucfirst($noun), 99]; # XXX translatable?
     }
 
     # old, will be removed someday
     $thing->{category} = $cats[0][0];
     # new/current
     $thing->{categories} = [map {$_->[0]} @cats];
 
     $cats_spec->{$_->[0]}{order} //= $_->[1] for @cats;
 }
 
 sub _add_default_from_arg_spec {
     my ($opt, $arg_spec) = @_;
     if (exists $arg_spec->{default}) {
         $opt->{default} = $arg_spec->{default};
     } elsif ($arg_spec->{schema} && exists($arg_spec->{schema}[1]{default})) {
         $opt->{default} = $arg_spec->{schema}[1]{default};
     }
 }
 
 sub _dash_prefix {
     length($_[0]) > 1 ? "--$_[0]" : "-$_[0]";
 }
 
 sub _fmt_opt {
     my $spec = shift;
     my @ospecs = @_;
     my @res;
     my $i = 0;
     for my $ospec (@ospecs) {
         my $j = 0;
         my $parsed = $ospec->{parsed};
         for (@{ $parsed->{opts} }) {
             my $opt = _dash_prefix($_);
             if ($i==0 && $j==0) {
                 if ($parsed->{type}) {
                     if ($spec->{'x.schema.entity'}) {
                         $opt .= "=".$spec->{'x.schema.entity'};
                     } elsif ($spec->{'x.schema.element_entity'}) {
                         $opt .= "=".$spec->{'x.schema.element_entity'};
                     } else {
                         $opt .= "=$parsed->{type}";
                     }
                 }
                 # mark required option with a '*'
                 $opt .= "*" if $spec->{req} && !$ospec->{is_base64} &&
                     !$ospec->{is_json} && !$ospec->{is_yaml};
             }
             push @res, $opt;
             $j++;
         }
         $i++;
     }
     join ", ", @res;
 }
 
 $SPEC{gen_cli_doc_data_from_meta} = {
     v => 1.1,
     summary => 'From Rinci function metadata, generate structure convenient '.
         'for producing CLI documentation (help/usage/POD)',
     description => <<'_',
 
 This function calls `Perinci::Sub::GetArgs::Argv`'s
 `gen_getopt_long_spec_from_meta()` (or receive its result as an argument, if
 passed, to avoid calling the function twice) and post-processes it: produce
 command usage line, format the options, include information from metadata, group
 the options by category. It also selects examples in the `examples` property
 which are applicable to CLI environment and format them.
 
 The resulting data structure is convenient to use when one wants to produce a
 documentation for CLI program (including help/usage message and POD).
 
 _
     args => {
         meta => {
             schema => 'hash*', # XXX rifunc
             req => 1,
             pos => 0,
         },
         meta_is_normalized => {
             schema => 'bool*',
         },
         common_opts => {
             summary => 'Will be passed to gen_getopt_long_spec_from_meta()',
             schema  => 'hash*',
         },
         ggls_res => {
             summary => 'Full result from gen_getopt_long_spec_from_meta()',
             schema  => 'array*', # XXX envres
             description => <<'_',
 
 If you already call `Perinci::Sub::GetArgs::Argv`'s
 `gen_getopt_long_spec_from_meta()`, you can pass the _full_ enveloped result
 here, to avoid calculating twice. What will be useful for the function is the
 extra result in result metadata (`func.*` keys in `$res->[3]` hash).
 
 _
         },
         per_arg_json => {
             schema => 'bool',
             summary => 'Pass per_arg_json=1 to Perinci::Sub::GetArgs::Argv',
         },
         per_arg_yaml => {
             schema => 'bool',
             summary => 'Pass per_arg_json=1 to Perinci::Sub::GetArgs::Argv',
         },
         lang => {
             schema => 'str*',
         },
     },
     result => {
         schema => 'hash*',
     },
 };
 sub gen_cli_doc_data_from_meta {
     require Getopt::Long::Negate::EN;
 
     my %args = @_;
 
     my $lang = $args{lang};
     my $meta = $args{meta} or return [400, 'Please specify meta'];
     my $common_opts = $args{common_opts};
     unless ($args{meta_is_normalized}) {
         require Perinci::Sub::Normalize;
         $meta = Perinci::Sub::Normalize::normalize_function_metadata($meta);
     }
     my $ggls_res = $args{ggls_res} // do {
         require Perinci::Sub::GetArgs::Argv;
         Perinci::Sub::GetArgs::Argv::gen_getopt_long_spec_from_meta(
             meta=>$meta, meta_is_normalized=>1, common_opts=>$common_opts,
             per_arg_json => $args{per_arg_json},
             per_arg_yaml => $args{per_arg_yaml},
         );
     };
     $ggls_res->[0] == 200 or return $ggls_res;
 
     my $args_prop = $meta->{args} // {};
     my $clidocdata = {
         option_categories => {},
         example_categories => {},
     };
 
     # generate usage line
     {
         my @args;
         my %args_prop = %$args_prop; # copy because we want to iterate & delete
         my $max_pos = -1;
         for (values %args_prop) {
             $max_pos = $_->{pos}
                 if defined($_->{pos}) && $_->{pos} > $max_pos;
         }
         my $pos = 0;
         while ($pos <= $max_pos) {
             my ($arg, $arg_spec);
             for (keys %args_prop) {
                 $arg_spec = $args_prop{$_};
                 if (defined($arg_spec->{pos}) && $arg_spec->{pos}==$pos) {
                     $arg = $_;
                     last;
                 }
             }
             $pos++;
             next unless defined($arg);
             if ($arg_spec->{req}) {
                 push @args, "<$arg>";
             } else {
                 push @args, "[$arg]";
             }
             $args[-1] .= "..." if $arg_spec->{greedy};
             delete $args_prop{$arg};
         }
         unshift @args, "[options]" if keys(%args_prop) || keys(%$common_opts); # XXX translatable?
         $clidocdata->{usage_line} = "[[prog]]".
             (@args ? " ".join(" ", @args) : "");
     }
 
     # generate list of options
     my %opts;
     {
         my $ospecs = $ggls_res->[3]{'func.specmeta'};
         # separate groupable aliases because they will be merged with the
         # argument options
         my (@k, @k_aliases);
       OSPEC1:
         for (sort keys %$ospecs) {
             my $ospec = $ospecs->{$_};
             {
                 last unless $ospec->{is_alias};
                 next if $ospec->{is_code};
                 my $arg_spec = $args_prop->{$ospec->{arg}};
                 my $alias_spec = $arg_spec->{cmdline_aliases}{$ospec->{alias}};
                 next if $alias_spec->{summary};
                 push @k_aliases, $_;
                 next OSPEC1;
             }
             push @k, $_;
         }
 
         my %negs; # key=arg, only show one negation form for each arg option
 
       OSPEC2:
         while (@k) {
             my $k = shift @k;
             my $ospec = $ospecs->{$k};
             my $opt;
             my $optkey;
 
             if ($ospec->{is_alias} || defined($ospec->{arg})) {
                 my $arg_spec;
                 my $alias_spec;
 
                 if ($ospec->{is_alias}) {
                     # non-groupable alias
 
                     $arg_spec = $args_prop->{ $ospec->{arg} };
                     $alias_spec = $arg_spec->{cmdline_aliases}{$ospec->{alias}};
                     my $rimeta = rimeta($alias_spec);
                     $optkey = _fmt_opt($arg_spec, $ospec);
                     $opt = {
                         opt_parsed => $ospec->{parsed},
                         orig_opt => $k,
                         is_alias => 1,
                         alias_for => $ospec->{alias_for},
                         summary => $rimeta->langprop({lang=>$lang}, 'summary') //
                             "Alias for "._dash_prefix($ospec->{parsed}{opts}[0]),
                         description =>
                             $rimeta->langprop({lang=>$lang}, 'description'),
                     };
                 } else {
                     # an option for argument
 
                     $arg_spec = $args_prop->{$ospec->{arg}};
                     my $rimeta = rimeta($arg_spec);
                     $opt = {
                         opt_parsed => $ospec->{parsed},
                         orig_opt => $k,
                     };
 
                     # for bool, only display either the positive (e.g. --bool)
                     # or the negative (e.g. --nobool) depending on the default
                     if (defined($ospec->{is_neg})) {
                         my $default = $arg_spec->{default} //
                             $arg_spec->{schema}[1]{default};
                         next OSPEC2 if  $default && !$ospec->{is_neg};
                         next OSPEC2 if !$default &&  $ospec->{is_neg};
                         if ($ospec->{is_neg}) {
                             next OSPEC2 if $negs{$ospec->{arg}}++;
                         }
                     }
 
                     if ($ospec->{is_neg}) {
                         # for negative option, use negative summary instead of
                         # regular (positive sentence) summary
                         $opt->{summary} =
                             $rimeta->langprop({lang=>$lang}, 'summary.alt.bool.not');
                     } elsif (defined $ospec->{is_neg}) {
                         # for boolean option which we show the positive, show
                         # the positive summary if available
                         $opt->{summary} =
                             $rimeta->langprop({lang=>$lang}, 'summary.alt.bool.yes') //
                                 $rimeta->langprop({lang=>$lang}, 'summary');
                     } elsif (($ospec->{parsed}{type}//'') eq 's@') {
                         # for array of string that can be specified via multiple
                         # --opt, show singular version of summary if available.
                         # otherwise show regular summary.
                         $opt->{summary} =
                             $rimeta->langprop({lang=>$lang}, 'summary.alt.plurality.singular') //
                                 $rimeta->langprop({lang=>$lang}, 'summary');
                     } else {
                         $opt->{summary} =
                             $rimeta->langprop({lang=>$lang}, 'summary');
                     }
                     $opt->{description} =
                         $rimeta->langprop({lang=>$lang}, 'description');
 
                     # find aliases that can be grouped together with this option
                     my @aliases;
                     my $j = $#k_aliases;
                     while ($j >= 0) {
                         my $aospec = $ospecs->{ $k_aliases[$j] };
                         {
                             last unless $aospec->{arg} eq $ospec->{arg};
                             push @aliases, $aospec;
                             splice @k_aliases, $j, 1;
                         }
                         $j--;
                     }
 
                     $optkey = _fmt_opt($arg_spec, $ospec, @aliases);
                 }
 
                 $opt->{arg_spec} = $arg_spec;
                 $opt->{alias_spec} = $alias_spec if $alias_spec;
 
                 # include keys from func.specmeta
                 for (qw/arg fqarg is_base64 is_json is_yaml/) {
                     $opt->{$_} = $ospec->{$_} if defined $ospec->{$_};
                 }
 
                 # include keys from arg_spec
                 for (qw/req pos greedy is_password links tags/) {
                     $opt->{$_} = $arg_spec->{$_} if defined $arg_spec->{$_};
                 }
 
                 _add_category_from_spec($clidocdata->{option_categories},
                                         $opt, $arg_spec, "options", 1);
                 _add_default_from_arg_spec($opt, $arg_spec);
 
             } else {
                 # option from common_opts
 
                 my $spec = $common_opts->{$ospec->{common_opt}};
 
                 # for bool, only display either the positive (e.g. --bool)
                 # or the negative (e.g. --nobool) depending on the default
                 my $show_neg = $ospec->{parsed}{is_neg} && $spec->{default};
 
                 local $ospec->{parsed}{opts} = do {
                     # XXX check if it's single-letter, get first
                     # non-single-letter
                     my @opts = Getopt::Long::Negate::EN::negations_for_option(
                         $ospec->{parsed}{opts}[0]);
                     [ $opts[0] ];
                 } if $show_neg;
 
                 $optkey = _fmt_opt($spec, $ospec);
                 my $rimeta = rimeta($spec);
                 $opt = {
                     opt_parsed => $ospec->{parsed},
                     orig_opt => $k,
                     common_opt => $ospec->{common_opt},
                     common_opt_spec => $spec,
                     summary => $show_neg ?
                         $rimeta->langprop({lang=>$lang}, 'summary.alt.bool.not') :
                             $rimeta->langprop({lang=>$lang}, 'summary'),
                     (schema => $spec->{schema}) x !!$spec->{schema},
                     ('x.schema.entity' => $spec->{'x.schema.entity'}) x !!$spec->{'x.schema.entity'},
                     ('x.schema.element_entity' => $spec->{'x.schema.element_entity'}) x !!$spec->{'x.schema.element_entity'},
                     description =>
                         $rimeta->langprop({lang=>$lang}, 'description'),
                     (default => $spec->{default}) x !!(exists($spec->{default}) && !$show_neg),
                 };
 
                 _add_category_from_spec($clidocdata->{option_categories},
                                         $opt, $spec, "options", 1);
 
             }
 
             $opts{$optkey} = $opt;
         }
 
         # link ungrouped alias to its main opt
       OPT1:
         for my $k (keys %opts) {
             my $opt = $opts{$k};
             next unless $opt->{is_alias} || $opt->{is_base64} ||
                 $opt->{is_json} || $opt->{is_yaml};
             for my $k2 (keys %opts) {
                 my $arg_opt = $opts{$k2};
                 next if $arg_opt->{is_alias} || $arg_opt->{is_base64} ||
                     $arg_opt->{is_json} || $arg_opt->{is_yaml};
                 next unless defined($arg_opt->{arg}) &&
                     $arg_opt->{arg} eq $opt->{arg};
                 $opt->{main_opt} = $k2;
                 next OPT1;
             }
         }
 
     }
     $clidocdata->{opts} = \%opts;
 
     # filter and format examples
     my @examples;
     {
         my $examples = $meta->{examples} // [];
         my $has_cats = _has_cats($examples);
 
         for my $eg (@$examples) {
             my $rimeta = rimeta($eg);
             my $argv;
             my $cmdline;
             if (defined($eg->{src})) {
                 # we only show shell command examples
                 if ($eg->{src_plang} =~ /^(sh|bash)$/) {
                     $cmdline = $eg->{src};
                 } else {
                     next;
                 }
             } else {
                 require String::ShellQuote;
                 if ($eg->{argv}) {
                     $argv = $eg->{argv};
                 } else {
                     require Perinci::Sub::ConvertArgs::Argv;
                     my $res = Perinci::Sub::ConvertArgs::Argv::convert_args_to_argv(
                         args => $eg->{args}, meta => $meta);
                     return err($res, 500, "Can't convert args to argv")
                         unless $res->[0] == 200;
                     $argv = $res->[2];
                 }
                 $cmdline = "[[prog]]";
                 for my $arg (@$argv) {
                     my $qarg = String::ShellQuote::shell_quote($arg);
                     $cmdline .= " $qarg"; # XXX markup with color?
                 }
             }
             my $egdata = {
                 cmdline      => $cmdline,
                 summary      => $rimeta->langprop({lang=>$lang}, 'summary'),
                 description  => $rimeta->langprop({lang=>$lang}, 'description'),
                 example_spec => $eg,
             };
             # XXX show result from $eg
             _add_category_from_spec($clidocdata->{example_categories},
                                     $egdata, $eg, "examples", $has_cats);
             push @examples, $egdata;
         }
     }
     $clidocdata->{examples} = \@examples;
 
     [200, "OK", $clidocdata];
 }
 
 1;
 # ABSTRACT: From Rinci function metadata, generate structure convenient for producing CLI documentation (help/usage/POD)
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Perinci::Sub::To::CLIDocData - From Rinci function metadata, generate structure convenient for producing CLI documentation (help/usage/POD)
 
 =head1 VERSION
 
 This document describes version 0.23 of Perinci::Sub::To::CLIDocData (from Perl distribution Perinci-Sub-To-CLIDocData), released on 2015-09-23.
 
 =head1 SYNOPSIS
 
  use Perinci::Sub::To::CLIDocData qw(gen_cli_doc_data_from_meta);
  my $clidocdata = gen_cli_doc_data_from_meta(meta => $meta);
 
 Sample function metadata (C<$meta>):
 
  {
    args => {
      bool1 => {
                 cmdline_aliases => { z => { summary => "This is summary for option `-z`" } },
                 schema => "bool",
                 summary => "Another bool option",
                 tags => ["category:cat1"],
               },
      flag1 => {
                 cmdline_aliases => { f => {} },
                 schema => ["bool", "is", 1],
                 tags => ["category:cat1"],
               },
      str1  => {
                 pos => 0,
                 req => 1,
                 schema => "str*",
                 summary => "A required option as well as positional argument",
               },
    },
    examples => [
      {
        argv    => ["a value", "--bool1"],
        summary => "Summary for an example",
        test    => 0,
      },
    ],
    summary => "Function summary",
    v => 1.1,
  }
 
 Sample result:
 
  do {
    my $a = [
      200,
      "OK",
      {
        example_categories => { Examples => { order => 99 } },
        examples => [
          {
            categories   => ["Examples"],
            category     => "Examples",
            cmdline      => "[[prog]] 'a value' --bool1",
            description  => undef,
            example_spec => {
                              argv    => ["a value", "--bool1"],
                              summary => "Summary for an example",
                              test    => 0,
                            },
            summary      => "Summary for an example",
          },
        ],
        option_categories => {
          "Cat1 options"  => { order => 50 },
          "Other options" => { order => 99 },
        },
        opts => {
          "--bool1" => {
            arg         => "bool1",
            arg_spec    => {
                             cmdline_aliases => { z => { summary => "This is summary for option `-z`" } },
                             schema => ["bool", {}, {}],
                             summary => "Another bool option",
                             tags => ["category:cat1"],
                           },
            categories  => ["Cat1 options"],
            category    => "Cat1 options",
            description => undef,
            fqarg       => "bool1",
            opt_parsed  => { opts => ["bool1"] },
            orig_opt    => "bool1",
            summary     => "Another bool option",
            tags        => 'fix',
          },
          "--flag1, -f" => {
            arg         => "flag1",
            arg_spec    => {
                             cmdline_aliases => { f => {} },
                             schema => ["bool", { is => 1 }, {}],
                             tags => ["category:cat1"],
                           },
            categories  => ["Cat1 options"],
            category    => "Cat1 options",
            description => undef,
            fqarg       => "flag1",
            opt_parsed  => { opts => ["flag1"] },
            orig_opt    => "flag1",
            summary     => undef,
            tags        => 'fix',
          },
          "--str1=s*" => {
            arg => "str1",
            arg_spec => {
              pos => 0,
              req => 1,
              schema => ["str", { req => 1 }, {}],
              summary => "A required option as well as positional argument",
            },
            categories => ["Other options"],
            category => "Other options",
            description => undef,
            fqarg => "str1",
            opt_parsed => { desttype => "", opts => ["str1"], type => "s" },
            orig_opt => "str1=s",
            pos => 0,
            req => 1,
            summary => "A required option as well as positional argument",
          },
          "-z" => {
            alias_for   => "bool1",
            alias_spec  => 'fix',
            arg         => "bool1",
            arg_spec    => 'fix',
            categories  => ["Cat1 options"],
            category    => "Cat1 options",
            description => undef,
            fqarg       => "bool1",
            is_alias    => 1,
            main_opt    => "--bool1",
            opt_parsed  => { opts => ["z"] },
            orig_opt    => "z",
            summary     => "This is summary for option `-z`",
            tags        => 'fix',
          },
        },
        usage_line => "[[prog]] [options] <str1>",
      },
    ];
    $a->[2]{opts}{"--bool1"}{tags} = $a->[2]{opts}{"--bool1"}{arg_spec}{tags};
    $a->[2]{opts}{"--flag1, -f"}{tags} = $a->[2]{opts}{"--flag1, -f"}{arg_spec}{tags};
    $a->[2]{opts}{"-z"}{alias_spec} = $a->[2]{opts}{"--bool1"}{arg_spec}{cmdline_aliases}{z};
    $a->[2]{opts}{"-z"}{arg_spec} = $a->[2]{opts}{"--bool1"}{arg_spec};
    $a->[2]{opts}{"-z"}{tags} = $a->[2]{opts}{"--bool1"}{arg_spec}{tags};
    $a;
  }
 
 For a more complete sample, see function metadata for C<demo_cli_opts> in
 L<Perinci::Examples::CLI>.
 
 =head1 SEE ALSO
 
 L<Perinci::CmdLine>, L<Perinci::CmdLine::Lite>
 
 L<Pod::Weaver::Plugin::Rinci>
 
 =head1 FUNCTIONS
 
 
 =head2 gen_cli_doc_data_from_meta(%args) -> [status, msg, result, meta]
 
 From Rinci function metadata, generate structure convenient for producing CLI documentation (help/usage/POD).
 
 This function calls C<Perinci::Sub::GetArgs::Argv>'s
 C<gen_getopt_long_spec_from_meta()> (or receive its result as an argument, if
 passed, to avoid calling the function twice) and post-processes it: produce
 command usage line, format the options, include information from metadata, group
 the options by category. It also selects examples in the C<examples> property
 which are applicable to CLI environment and format them.
 
 The resulting data structure is convenient to use when one wants to produce a
 documentation for CLI program (including help/usage message and POD).
 
 Arguments ('*' denotes required arguments):
 
 =over 4
 
 =item * B<common_opts> => I<hash>
 
 Will be passed to gen_getopt_long_spec_from_meta().
 
 =item * B<ggls_res> => I<array>
 
 Full result from gen_getopt_long_spec_from_meta().
 
 If you already call C<Perinci::Sub::GetArgs::Argv>'s
 C<gen_getopt_long_spec_from_meta()>, you can pass the I<full> enveloped result
 here, to avoid calculating twice. What will be useful for the function is the
 extra result in result metadata (C<func.*> keys in C<< $res-E<gt>[3] >> hash).
 
 =item * B<lang> => I<str>
 
 =item * B<meta>* => I<hash>
 
 =item * B<meta_is_normalized> => I<bool>
 
 =item * B<per_arg_json> => I<bool>
 
 Pass per_arg_json=1 to Perinci::Sub::GetArgs::Argv.
 
 =item * B<per_arg_yaml> => I<bool>
 
 Pass per_arg_json=1 to Perinci::Sub::GetArgs::Argv.
 
 =back
 
 Returns an enveloped result (an array).
 
 First element (status) is an integer containing HTTP status code
 (200 means OK, 4xx caller error, 5xx function error). Second element
 (msg) is a string containing error message, or 'OK' if status is
 200. Third element (result) is optional, the actual result. Fourth
 element (meta) is called result metadata and is optional, a hash
 that contains extra information.
 
 Return value:  (hash)
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Perinci-Sub-To-CLIDocData>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Perinci-Sub-To-CLIOptSpec>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Perinci-Sub-To-CLIDocData>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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
### Perinci/Sub/Util.pm ###
 package Perinci::Sub::Util;
 
 our $DATE = '2015-09-04'; # DATE
 our $VERSION = '0.42'; # VERSION
 
 use 5.010001;
 use strict;
 use warnings;
 
 require Exporter;
 our @ISA = qw(Exporter);
 our @EXPORT_OK = qw(
                        err
                        caller
                        gen_modified_sub
                        warn_err
                        die_err
                );
 
 our %SPEC;
 
 $SPEC{':package'} = {
     v => 1.1,
     summary => 'Helper when writing functions',
 };
 
 our $STACK_TRACE;
 our @_c; # to store temporary celler() result
 our $_i; # temporary variable
 sub err {
     require Scalar::Util;
 
     # get information about caller
     my @caller = CORE::caller(1);
     if (!@caller) {
         # probably called from command-line (-e)
         @caller = ("main", "-e", 1, "program");
     }
 
     my ($status, $msg, $meta, $prev);
 
     for (@_) {
         my $ref = ref($_);
         if ($ref eq 'ARRAY') { $prev = $_ }
         elsif ($ref eq 'HASH') { $meta = $_ }
         elsif (!$ref) {
             if (Scalar::Util::looks_like_number($_)) {
                 $status = $_;
             } else {
                 $msg = $_;
             }
         }
     }
 
     $status //= 500;
     $msg  //= "$caller[3] failed";
     $meta //= {};
     $meta->{prev} //= $prev if $prev;
 
     # put information on who produced this error and where/when
     if (!$meta->{logs}) {
 
         # should we produce a stack trace?
         my $stack_trace;
         {
             no warnings;
             # we use Carp::Always as a sign that user wants stack traces
             last unless $STACK_TRACE // $INC{"Carp/Always.pm"};
             # stack trace is already there in previous result's log
             last if $prev && ref($prev->[3]) eq 'HASH' &&
                 ref($prev->[3]{logs}) eq 'ARRAY' &&
                     ref($prev->[3]{logs}[0]) eq 'HASH' &&
                         $prev->[3]{logs}[0]{stack_trace};
             $stack_trace = [];
             $_i = 1;
             while (1) {
                 {
                     package DB;
                     @_c = CORE::caller($_i);
                     if (@_c) {
                         $_c[4] = [@DB::args];
                     }
                 }
                 last unless @_c;
                 push @$stack_trace, [@_c];
                 $_i++;
             }
         }
         push @{ $meta->{logs} }, {
             type    => 'create',
             time    => time(),
             package => $caller[0],
             file    => $caller[1],
             line    => $caller[2],
             func    => $caller[3],
             ( stack_trace => $stack_trace ) x !!$stack_trace,
         };
     }
 
     #die;
     [$status, $msg, undef, $meta];
 }
 
 sub caller {
     my $n0 = shift;
     my $n  = $n0 // 0;
 
     my $pkg = $Perinci::Sub::Wrapper::default_wrapped_package //
         'Perinci::Sub::Wrapped';
 
     my @r;
     my $i =  0;
     my $j = -1;
     while ($i <= $n+1) { # +1 for this sub itself
         $j++;
         @r = CORE::caller($j);
         last unless @r;
         if ($r[0] eq $pkg && $r[1] =~ /^\(eval /) {
             next;
         }
         $i++;
     }
 
     return unless @r;
     return defined($n0) ? @r : $r[0];
 }
 
 $SPEC{gen_modified_sub} = {
     v => 1.1,
     summary => 'Generate modified metadata (and subroutine) based on another',
     description => <<'_',
 
 Often you'll want to create another sub (and its metadata) based on another, but
 with some modifications, e.g. add/remove/rename some arguments, change summary,
 add/remove some properties, and so on.
 
 Instead of cloning the Rinci metadata and modify it manually yourself, this
 routine provides some shortcuts.
 
 You can specify base sub/metadata using `base_name` (string, subroutine name,
 either qualified or not) or `base_code` (coderef) + `base_meta` (hash).
 
 _
     args => {
         base_name => {
             summary => 'Subroutine name (either qualified or not)',
             schema => 'str*',
             description => <<'_',
 
 If not qualified with package name, will be searched in the caller's package.
 Rinci metadata will be searched in `%SPEC` package variable.
 
 Alternatively, you can also specify `base_code` and `base_meta`.
 
 _
         },
         base_code => {
             summary => 'Base subroutine code',
             schema  => 'code*',
             description => <<'_',
 
 If you specify this, you'll also need to specify `base_meta`.
 
 Alternatively, you can specify `base_name` instead, to let this routine search
 the base subroutine from existing Perl package.
 
 _
         },
         base_meta => {
             summary => 'Base Rinci metadata',
             schema  => 'hash*', # XXX defhash/rifunc
         },
         output_name => {
             summary => 'Where to install the modified sub',
             schema  => 'str*',
             description => <<'_',
 
 Subroutine will be put in the specified name. If the name is not qualified with
 package name, will use caller's package. If no `output_code` is specified, the
 base subroutine reference will be assigned here.
 
 Note that this argument is optional.
 
 _
         },
         output_code => {
             summary => 'Code for the modified sub',
             schema  => 'code*',
             description => <<'_',
 
 If not specified will use `base_code` (which will then be required).
 
 _
         },
         summary => {
             summary => 'Summary for the mod subroutine',
             schema  => 'str*',
         },
         description => {
             summary => 'Description for the mod subroutine',
             schema  => 'str*',
         },
         remove_args => {
             summary => 'List of arguments to remove',
             schema  => 'array*',
         },
         add_args => {
             summary => 'Arguments to add',
             schema  => 'hash*',
         },
         replace_args => {
             summary => 'Arguments to add',
             schema  => 'hash*',
         },
         rename_args => {
             summary => 'Arguments to rename',
             schema  => 'hash*',
         },
         modify_args => {
             summary => 'Arguments to modify',
             description => <<'_',
 
 For each argument you can specify a coderef. The coderef will receive the
 argument ($arg_spec) and is expected to modify the argument specification.
 
 _
             schema  => 'hash*',
         },
         modify_meta => {
             summary => 'Specify code to modify metadata',
             schema  => 'code*',
             description => <<'_',
 
 Code will be called with arguments ($meta) where $meta is the cloned Rinci
 metadata.
 
 _
         },
         install_sub => {
             schema  => 'bool',
             default => 1,
         },
     },
     result => {
         schema => ['hash*' => {
             keys => {
                 code => ['code*'],
                 meta => ['hash*'], # XXX defhash/risub
             },
         }],
     },
 };
 sub gen_modified_sub {
     require Function::Fallback::CoreOrPP;
 
     my %args = @_;
 
     # get base code/meta
     my ($base_code, $base_meta);
     if ($args{base_name}) {
         my ($pkg, $leaf);
         if ($args{base_name} =~ /(.+)::(.+)/) {
             ($pkg, $leaf) = ($1, $2);
         } else {
             $pkg  = CORE::caller();
             $leaf = $args{base_name};
         }
         no strict 'refs';
         $base_code = \&{"$pkg\::$leaf"};
         $base_meta = ${"$pkg\::SPEC"}{$leaf};
         die "Can't find Rinci metadata for $pkg\::$leaf" unless $base_meta;
     } elsif ($args{base_meta}) {
         $base_meta = $args{base_meta};
         $base_code = $args{base_code}
             or die "Please specify base_code";
     } else {
         die "Please specify base_name or base_code+base_meta";
     }
 
     my $output_meta = Function::Fallback::CoreOrPP::clone($base_meta);
     my $output_code = $args{output_code} // $base_code;
 
     # modify metadata
     for (qw/summary description/) {
         $output_meta->{$_} = $args{$_} if $args{$_};
     }
     if ($args{remove_args}) {
         delete $output_meta->{args}{$_} for @{ $args{remove_args} };
     }
     if ($args{add_args}) {
         for my $k (keys %{ $args{add_args} }) {
             my $v = $args{add_args}{$k};
             die "Can't add arg '$k' in mod sub: already exists"
                 if $output_meta->{args}{$k};
             $output_meta->{args}{$k} = $v;
         }
     }
     if ($args{replace_args}) {
         for my $k (keys %{ $args{replace_args} }) {
             my $v = $args{replace_args}{$k};
             die "Can't replace arg '$k' in mod sub: doesn't exist"
                 unless $output_meta->{args}{$k};
             $output_meta->{args}{$k} = $v;
         }
     }
     if ($args{rename_args}) {
         for my $old (keys %{ $args{rename_args} }) {
             my $new = $args{rename_args}{$old};
             my $as = $output_meta->{args}{$old};
             die "Can't rename arg '$old' in mod sub: doesn't exist" unless $as;
             die "Can't rename arg '$old'->'$new' in mod sub: ".
                 "new name already exist" if $output_meta->{args}{$new};
             $output_meta->{args}{$new} = $as;
             delete $output_meta->{args}{$old};
         }
     }
     if ($args{modify_args}) {
         for (keys %{ $args{modify_args} }) {
             $args{modify_args}{$_}->($output_meta->{args}{$_});
         }
     }
     if ($args{modify_meta}) {
         $args{modify_meta}->($output_meta);
     }
 
     # install
     if ($args{output_name}) {
         my ($pkg, $leaf);
         if ($args{output_name} =~ /(.+)::(.+)/) {
             ($pkg, $leaf) = ($1, $2);
         } else {
             $pkg  = CORE::caller();
             $leaf = $args{output_name};
         }
         no strict 'refs';
         no warnings 'redefine';
         *{"$pkg\::$leaf"}       = $output_code if $args{install_sub} // 1;
         ${"$pkg\::SPEC"}{$leaf} = $output_meta;
     }
 
     [200, "OK", {code=>$output_code, meta=>$output_meta}];
 }
 
 # TODO: for simpler cases (e.g. only remove some arguments, or preset some
 # arguments), create more convenient helper, e.g.
 #
 # gen_curried_sub('list_users', {is_suspended=>1}, ?'list_suspended_users'); # equivalent to remove args => ['is_suspended'] and create a wrapper that calls list_users with is_suspended=>1
 
 sub warn_err {
     require Carp;
 
     my $res = err(@_);
     Carp::carp("ERROR $res->[0]: $res->[1]");
 }
 
 sub die_err {
     require Carp;
 
     my $res = err(@_);
     Carp::croak("ERROR $res->[0]: $res->[1]");
 }
 
 1;
 # ABSTRACT: Helper when writing functions
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Perinci::Sub::Util - Helper when writing functions
 
 =head1 VERSION
 
 This document describes version 0.42 of Perinci::Sub::Util (from Perl distribution Perinci-Sub-Util), released on 2015-09-04.
 
 =head1 SYNOPSIS
 
 Example for err() and caller():
 
  use Perinci::Sub::Util qw(err caller);
 
  sub foo {
      my %args = @_;
      my $res;
 
      my $caller = caller();
 
      $res = bar(...);
      return err($err, 500, "Can't foo") if $res->[0] != 200;
 
      [200, "OK"];
  }
 
 Example for gen_modified_sub():
 
  use Perinci::Sub::Util qw(gen_modified_sub);
 
  $SPEC{list_users} = {
      v => 1.1,
      args => {
          search => {},
          is_suspended => {},
      },
  };
  sub list_users { ... }
 
  gen_modified_sub(
      output_name => 'list_suspended_users',
      base_name   => 'list_users',
      remove_args => ['is_suspended'],
      output_code => sub {
          list_users(@_, is_suspended=>1);
      },
  );
 
 Example for die_err() and warn_err():
 
  use Perinci::Sub::Util qw(warn_err die_err);
  warn_err(403, "Forbidden");
  die_err(403, "Forbidden");
 
 =head1 FAQ
 
 =head2 What if I want to put result ($res->[2]) into my result with err()?
 
 You can do something like this:
 
  my $err = err(...) if ERROR_CONDITION;
  $err->[2] = SOME_RESULT;
  return $err;
 
 =head1 SEE ALSO
 
 L<Perinci>
 
 =head1 FUNCTIONS
 
 
 =head2 gen_modified_sub(%args) -> [status, msg, result, meta]
 
 Generate modified metadata (and subroutine) based on another.
 
 Often you'll want to create another sub (and its metadata) based on another, but
 with some modifications, e.g. add/remove/rename some arguments, change summary,
 add/remove some properties, and so on.
 
 Instead of cloning the Rinci metadata and modify it manually yourself, this
 routine provides some shortcuts.
 
 You can specify base sub/metadata using C<base_name> (string, subroutine name,
 either qualified or not) or C<base_code> (coderef) + C<base_meta> (hash).
 
 Arguments ('*' denotes required arguments):
 
 =over 4
 
 =item * B<add_args> => I<hash>
 
 Arguments to add.
 
 =item * B<base_code> => I<code>
 
 Base subroutine code.
 
 If you specify this, you'll also need to specify C<base_meta>.
 
 Alternatively, you can specify C<base_name> instead, to let this routine search
 the base subroutine from existing Perl package.
 
 =item * B<base_meta> => I<hash>
 
 Base Rinci metadata.
 
 =item * B<base_name> => I<str>
 
 Subroutine name (either qualified or not).
 
 If not qualified with package name, will be searched in the caller's package.
 Rinci metadata will be searched in C<%SPEC> package variable.
 
 Alternatively, you can also specify C<base_code> and C<base_meta>.
 
 =item * B<description> => I<str>
 
 Description for the mod subroutine.
 
 =item * B<install_sub> => I<bool> (default: 1)
 
 =item * B<modify_args> => I<hash>
 
 Arguments to modify.
 
 For each argument you can specify a coderef. The coderef will receive the
 argument ($arg_spec) and is expected to modify the argument specification.
 
 =item * B<modify_meta> => I<code>
 
 Specify code to modify metadata.
 
 Code will be called with arguments ($meta) where $meta is the cloned Rinci
 metadata.
 
 =item * B<output_code> => I<code>
 
 Code for the modified sub.
 
 If not specified will use C<base_code> (which will then be required).
 
 =item * B<output_name> => I<str>
 
 Where to install the modified sub.
 
 Subroutine will be put in the specified name. If the name is not qualified with
 package name, will use caller's package. If no C<output_code> is specified, the
 base subroutine reference will be assigned here.
 
 Note that this argument is optional.
 
 =item * B<remove_args> => I<array>
 
 List of arguments to remove.
 
 =item * B<rename_args> => I<hash>
 
 Arguments to rename.
 
 =item * B<replace_args> => I<hash>
 
 Arguments to add.
 
 =item * B<summary> => I<str>
 
 Summary for the mod subroutine.
 
 =back
 
 Returns an enveloped result (an array).
 
 First element (status) is an integer containing HTTP status code
 (200 means OK, 4xx caller error, 5xx function error). Second element
 (msg) is a string containing error message, or 'OK' if status is
 200. Third element (result) is optional, the actual result. Fourth
 element (meta) is called result metadata and is optional, a hash
 that contains extra information.
 
 Return value:  (hash)
 
 =head2 caller([ $n ])
 
 Just like Perl's builtin caller(), except that this one will ignore wrapper code
 in the call stack. You should use this if your code is potentially wrapped. See
 L<Perinci::Sub::Wrapper> for more details.
 
 =head2 err(...) => ARRAY
 
 Experimental.
 
 Generate an enveloped error response (see L<Rinci::function>). Can accept
 arguments in an unordered fashion, by utilizing the fact that status codes are
 always integers, messages are strings, result metadata are hashes, and previous
 error responses are arrays. Error responses also seldom contain actual result.
 Status code defaults to 500, status message will default to "FUNC failed". This
 function will also fill the information in the C<logs> result metadata.
 
 Examples:
 
  err();    # => [500, "FUNC failed", undef, {...}];
  err(404); # => [404, "FUNC failed", undef, {...}];
  err(404, "Not found"); # => [404, "Not found", ...]
  err("Not found", 404); # => [404, "Not found", ...]; # order doesn't matter
  err([404, "Prev error"]); # => [500, "FUNC failed", undef,
                            #     {logs=>[...], prev=>[404, "Prev error"]}]
 
 Will put C<stack_trace> in logs only if C<Carp::Always> module is loaded.
 
 =head2 warn_err(...)
 
 This is a shortcut for:
 
  $res = err(...);
  warn "ERROR $res->[0]: $res->[1]";
 
 =head2 die_err(...)
 
 This is a shortcut for:
 
  $res = err(...);
  die "ERROR $res->[0]: $res->[1]";
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Perinci-Sub-Util>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Perinci-Sub-Util>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Perinci-Sub-Util>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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
### Perinci/Sub/Util/ResObj.pm ###
 package Perinci::Sub::Util::ResObj;
 
 our $DATE = '2015-09-04'; # DATE
 our $VERSION = '0.42'; # VERSION
 
 use Carp;
 use overload
     q("") => sub {
         my $res = shift; "ERROR $err->[0]: $err->[1]\n" . Carp::longmess();
     };
 
 1;
 # ABSTRACT: An object that represents enveloped response suitable for die()-ing
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Perinci::Sub::Util::ResObj - An object that represents enveloped response suitable for die()-ing
 
 =head1 VERSION
 
 This document describes version 0.42 of Perinci::Sub::Util::ResObj (from Perl distribution Perinci-Sub-Util), released on 2015-09-04.
 
 =head1 SYNOPSIS
 
 Currently unused. See L<Perinci::Sub::Util>'s C<warn_err> and C<die_err>
 instead.
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Perinci-Sub-Util>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Perinci-Sub-Util>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Perinci-Sub-Util>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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
### Perinci/Sub/Util/Sort.pm ###
 package Perinci::Sub::Util::Sort;
 
 our $DATE = '2015-09-04'; # DATE
 our $VERSION = '0.42'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 
 require Exporter;
 our @ISA = qw(Exporter);
 our @EXPORT_OK = qw(
                        sort_args
                );
 
 our %SPEC;
 
 sub sort_args {
     my $args = shift;
     sort {
         (($args->{$a}{pos} // 9999) <=> ($args->{$b}{pos} // 9999)) ||
             $a cmp $b
         } keys %$args;
 }
 
 1;
 # ABSTRACT: Sort routines
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Perinci::Sub::Util::Sort - Sort routines
 
 =head1 VERSION
 
 This document describes version 0.42 of Perinci::Sub::Util::Sort (from Perl distribution Perinci-Sub-Util), released on 2015-09-04.
 
 =head1 SYNOPSIS
 
  use Perinci::Sub::Util::Sort qw(sort_args);
 
  my $meta = {
      v => 1.1,
      args => {
          a1 => { pos=>0 },
          a2 => { pos=>1 },
          opt1 => {},
          opt2 => {},
      },
  };
  my @args = sort_args($meta->{args}); # ('a1','a2','opt1','opt2')
 
 =head1 FUNCTIONS
 
 =head2 sort_args(\%args) => LIST
 
 Sort argument in args property by pos, then by name.
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Perinci-Sub-Util>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Perinci-Sub-Util>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Perinci-Sub-Util>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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
### Perinci/Sub/Wrapper.pm ###
 package Perinci::Sub::Wrapper;
 
 our $DATE = '2015-09-04'; # DATE
 our $VERSION = '0.79'; # VERSION
 
 use 5.010001;
 use strict;
 use warnings;
 use experimental 'smartmatch';
 use Log::Any::IfLOG '$log';
 
 use Function::Fallback::CoreOrPP qw(clone);
 use Perinci::Sub::Normalize qw(normalize_function_metadata);
 use Perinci::Sub::Util qw(err);
 
 use Exporter qw(import);
 our @EXPORT_OK = qw(wrap_sub);
 
 our $Log_Wrapper_Code = $ENV{LOG_PERINCI_WRAPPER_CODE} // 0;
 
 our %SPEC;
 
 $SPEC{':package'} = {
     v => 1.1,
     summary => 'A multi-purpose subroutine wrapping framework',
 };
 
 # "protocol version" (v). whenever there's a significant change in the basic
 # structure of the wrapper, which potentially cause some/a lot of property
 # handlers to stop working, we increase this. property handler must always state
 # which version it follows in its meta. if unspecified, it's assumed to be 1.
 our $protocol_version = 2;
 
 sub new {
     my ($class) = @_;
     bless {}, $class;
 }
 
 sub __squote {
     require Data::Dumper;
     my $res = Data::Dumper->new([shift])->
         Purity(1)->Terse(1)->Deepcopy(1)->Indent(0)->Dump;
     chomp $res;
     $res;
 }
 
 sub _check_module {
     my ($self, $mod) = @_;
 
     if ($self->{_args}{core}) {
         if ($mod =~ /\A(experimental|Scalar::Numeric::Util|Scalar::Util::Numeric::PP)\z/) {
             die "BUG: Requested non-core module '$mod' while wrap arg core=1";
         } elsif ($mod =~ /\A(warnings|List::Util)\z/) {
             # core modules
         } else {
             die "BUG: Haven't noted whether module '$mod' is core/non-core";
         }
     }
 
     if ($self->{_args}{pp}) {
         if ($mod =~ /\A(List::Util|Scalar::Numeric::Util)\z/) {
             die "BUG: Requested XS module '$mod' while wrap arg pp=1";
         } elsif ($mod =~ /\A(experimental|warnings|Scalar::Util::Numeric::PP)\z/) {
             # pp modules
         } else {
             die "BUG: Haven't noted whether module '$mod' is pure-perl/XS";
         }
     }
 
     if ($self->{_args}{core_or_pp}) {
         if ($mod =~ /\A(Scalar::Numeric::Util)\z/) {
             die "BUG: Requested non-core XS module '$mod' while wrap arg core_or_pp=1";
         } elsif ($mod =~ /\A(experimental|warnings|List::Util|Scalar::Util::Numeric::PP)\z/) {
             # core or pp modules
         } else {
             die "BUG: Haven't noted whether module '$mod' is non-core xs or not";
         }
     }
 }
 
 sub _add_module {
     my ($self, $mod) = @_;
     unless ($mod ~~ $self->{_modules}) {
         local $self->{_cur_section};
         $self->select_section('before_sub_require_modules');
         if ($mod =~ /(-?)(.+?)\s+(.+)/) {
             $self->_check_module($2);
             if ($1) {
                 $self->push_lines("no $2 $3;");
             } else {
                 $self->push_lines("use $2 $3;");
             }
         } else {
             $self->_check_module($mod);
             $self->push_lines("require $mod;");
         }
         push @{ $self->{_modules} }, $mod;
     }
 }
 
 sub _add_modules {
     my ($self, $mods) = @_;
     for my $mod (sort keys %$mods) {
         my $modspec = $mods->{$mod};
         if ($modspec->[1]) {
             if ($modspec->[0] eq 'no') {
                 $self->_add_module("-$mod ".join(" ", @{ $modspec->[1] }));
             } else {
                 $self->_add_module( "$mod ".join(" ", @{ $modspec->[1] }));
             }
         } else {
             $self->_add_module($mod);
         }
     }
 }
 
 sub _add_var {
     my ($self, $var, $value) = @_;
     unless (exists $self->{_vars}{$var}) {
         local $self->{_cur_section};
         $self->select_section('declare_vars');
         $self->push_lines("my \$$var = ".__squote($value).";");
         $self->{_vars}{$var} = $value;
     }
 }
 
 sub _known_sections {
 
     # order=>N regulates the order of code. embed=>1 means the code is for embed
     # mode only and should not be included in dynamic wrapper code.
 
     state $val = {
         before_sub_require_modules => {order=>1},
 
         # reserved by wrapper for setting Perl package and declaring 'sub {'
         OPEN_SUB => {order=>4},
 
         # reserved to say 'my %args = @_;' or 'my @args = @_;' etc
         ACCEPT_ARGS => {order=>5},
 
         # reserved to get args values if converted from array/arrayref
         ACCEPT_ARGS2 => {order=>6},
 
         declare_vars => {order=>7},
 
         # for handlers to put stuffs right before eval. for example, 'timeout'
         # uses this to set ALRM signal handler.
         before_eval => {order=>10},
 
         # reserved by wrapper for generating 'eval {'
         OPEN_EVAL => {order=>20},
 
         # used e.g. to load modules used by validation
         before_call_before_arg_validation => {order=>31},
 
         before_call_arg_validation => {order=>32},
 
         # used e.g. by dependency checking
         before_call_after_arg_validation => {order=>33},
 
         # feed arguments to sub
         before_call_feed_args => {order=>48},
 
         # for handlers that *must* do stuffs right before call
         before_call_right_before_call => {order=>49},
 
         # reserved by the wrapper for calling the sub
         CALL => {order=>50},
 
         # for handlers that *must* do stuffs right after call
         after_call_right_after_call => {order=>51},
 
         # reserved by the wrapper for adding/stripping result envelope, this
         # happens before result validation
         AFTER_CALL_ADD_OR_STRIP_RESULT_ENVELOPE => {order=>52},
 
         # used e.g. to load modules used by validation
         after_call_before_res_validation => {order=>61},
 
         after_call_res_validation => {order=>62},
 
         after_call_after_res_validation => {order=>63},
 
         # reserved by wrapper to put eval end '}' and capturing result in
         # $_w_res and $@ in $eval_err
         CLOSE_EVAL => {order=>70},
 
         # for handlers to put checks against $eval_err
         after_eval => {order=>80},
 
         # reserved for returning final result '$_w_res'
         BEFORE_CLOSE_SUB => {order=>99},
 
         # reserved for sub closing '}' line
         CLOSE_SUB => {order=>100},
     };
     $val;
 }
 
 sub section_empty {
     my ($self, $section) = @_;
     !$self->{_codes}{$section};
 }
 
 sub _needs_eval {
     my ($self) = @_;
     !($self->section_empty('before_eval') &&
           $self->section_empty('after_eval'));
 }
 
 # whether we need to store call result to a variable ($_w_res)
 sub _needs_store_res {
     my ($self) = @_;
     return 1 if $self->{_args}{validate_result};
     return 1 if $self->_needs_eval;
     my $ks = $self->_known_sections;
     for (grep {/^after_call/} keys %$ks) {
         return 1 unless $self->section_empty($_);
     }
     0;
 }
 
 sub _check_known_section {
     my ($self, $section) = @_;
     my $ks = $self->_known_sections;
     $ks->{$section} or die "BUG: Unknown code section '$section'";
 }
 
 sub _err {
     my ($self, $c_status, $c_msg) = @_;
     if ($self->{_meta}{result_naked}) {
         $self->push_lines(
             "warn 'ERROR ' . ($c_status) . ': '. ($c_msg);",
             'return undef;',
         );
     } else {
         $self->push_lines("return [$c_status, $c_msg];");
     }
 }
 
 sub _errif {
     my ($self, $c_status, $c_msg, $c_cond) = @_;
     $self->push_lines("if ($c_cond) {");
     $self->indent;
     $self->_err($c_status, $c_msg);
     $self->unindent;
     $self->push_lines('}');
 }
 
 sub select_section {
     my ($self, $section) = @_;
     $self->_check_known_section($section);
     $self->{_cur_section} = $section;
     $self;
 }
 
 sub indent {
     my ($self) = @_;
     my $section = $self->{_cur_section};
     $self->{_codes}{$section} //= undef;
     $self->{_levels}{$section}++;
     $self;
 }
 
 sub unindent {
     my ($self) = @_;
     my $section = $self->{_cur_section};
     $self->{_codes}{$section} //= undef;
     $self->{_levels}{$section}--;
     $self;
 }
 
 sub get_indent_level {
     my ($self) = @_;
     my $section = $self->{_cur_section};
     $self->{_levels}{$section} // 0;
 }
 
 # line can be code or comment. code should not contain string literals that
 # cross lines (i.e. contain literal newlines) because push_lines() might add
 # comment at the end of each line.
 
 sub push_lines {
     my ($self, @lines) = @_;
     my $section = $self->{_cur_section};
 
     unless (exists $self->{_codes}{$section}) {
         unshift @lines, "# * section: $section";
         # don't give blank line for the top-most section (order=>0)
         unshift @lines, "" if $self->_known_sections->{$section}{order};
         $self->{_codes}{$section} = [];
         $self->{_levels}{$section} = 0;
     }
 
     @lines = map {[$self->{_levels}{$section}, $_]} @lines;
     if ($self->{_args}{debug}) {
         for my $l (@lines) {
             $l->[2] =
                 $self->{_cur_handler} ?
                     "$self->{_cur_handler} prio=".$self->{_cur_handler_meta}{prio}
                         : "";
         }
     }
     push @{$self->{_codes}{$section}}, @lines;
     $self;
 }
 
 sub _join_codes {
     my ($self, $crit, $prev_section_level) = @_;
     my @lines;
     my $ks = $self->_known_sections;
     $prev_section_level //= 0;
     my $i = 0;
     for my $s (sort {$ks->{$a}{order} <=> $ks->{$b}{order}}
                    keys %$ks) {
         next if $self->section_empty($s);
         next unless $crit->(section => $s);
         $i++;
         for my $l (@{ $self->{_codes}{$s} }) {
             $l->[0] += $prev_section_level;
             die "BUG: Negative indent level in line $i (section $s): '$l->[1]'"
                 if $l->[0] < 0;
             my $s = ($self->{_args}{indent} x $l->[0]) . $l->[1];
             if (defined $l->[2]) {
                 my $num_ws = 80 - length($s);
                 $num_ws = 1 if $num_ws < 1;
                 $s .= (" " x $num_ws) . "## $l->[2]";
             }
             push @lines, $s;
         }
         $prev_section_level += $self->{_levels}{$s};
     }
     [join("\n", @lines), $prev_section_level];
 }
 
 sub _format_dyn_wrapper_code {
     my ($self) = @_;
     my $ks = $self->_known_sections;
     $self->_join_codes(
         sub {
             my %args = @_;
             my $section = $args{section};
             !$ks->{$section}{embed};
         })->[0];
 }
 
 # for embedded, we need to produce three sections which will be inserted in
 # different places, demonstrated below:
 #
 #   $SPEC{foo} = {
 #       ...
 #   };
 #   sub foo {
 #       my %args = @_;
 #       # do stuffs
 #   }
 #
 # becomes:
 #
 #   #PRESUB1: require modules (inserted before sub declaration)
 #   require Data::Dumper;
 #   require Scalar::Util;
 #
 #   $SPEC{foo} = {
 #       ...
 #   };
 #   #PRESUB2: modify metadata piece-by-piece (inserted before sub declaration &
 #   #after $SPEC{foo}). we're avoiding dumping the new modified metadata because
 #   #metadata might contain coderefs which is sometimes problematic when dumping
 #   {
 #       my $meta = $SPEC{foo};
 #       $meta->{v} = 1.1;
 #       $meta->{result_naked} = 0;
 #   }
 #
 #   sub foo {
 #       my %args = @_;
 #       #PREAMBLE: before call sections (inserted after accept args), e.g.
 #       #validate arguments, convert argument type, setup eval block
 #       #...
 #
 #       # do stuffs
 #
 #       #POSTAMBLE: after call sections (inserted before sub end), e.g.
 #       #validate result, close eval block and do retry/etc.
 #       #...
 #   }
 sub _format_embed_wrapper_code {
     my ($self) = @_;
 
     my $res = {};
     my $ks = $self->_known_sections;
     my $j;
 
     $j = $self->_join_codes(
         sub {
             my %args = @_;
             my $section = $args{section};
             $section =~ /\A(before_sub_require_modules)\z/;
         });
     $res->{presub1} = $j->[0];
 
     # no longer needed/produce, code to modify metadata
     $res->{presub2} = '';
 
     $j = $self->_join_codes(
         sub {
             my %args = @_;
             my $section = $args{section};
             my $order = $ks->{$section}{order};
             return 1 if $order > $ks->{ACCEPT_ARGS}{order} &&
                 $order < $ks->{CALL}{order};
             0;
         }, 1);
     $res->{preamble} = $j->[0];
 
     $j = $self->_join_codes(
         sub {
             my %args = @_;
             my $section = $args{section};
             my $order = $ks->{$section}{order};
             return 1 if $order > $ks->{CALL}{order} &&
                 $order < $ks->{CLOSE_SUB}{order};
             0;
         }, $j->[1]);
     $res->{postamble} = $j->[0];
 
     $res;
 }
 
 sub handlemeta_v { {} }
 sub handlemeta_name { {} }
 sub handlemeta_summary { {} }
 sub handlemeta_description { {} }
 sub handlemeta_tags { {} }
 sub handlemeta_default_lang { {} }
 sub handlemeta_links { {} }
 sub handlemeta_text_markup { {} }
 sub handlemeta_is_func { {} }
 sub handlemeta_is_meth { {} }
 sub handlemeta_is_class_meth { {} }
 sub handlemeta_examples { {} }
 
 # after args
 sub handlemeta_features { {v=>2, prio=>15} }
 sub handle_features {
     my ($self, %args) = @_;
 
     my $meta = $self->{_meta};
     my $v = $meta->{features} // {};
 
     $self->select_section('before_call_before_arg_validation');
 
     if ($v->{tx} && $v->{tx}{req}) {
         $self->push_lines('', '# check required transaction');
         $self->_errif(412, '"Must run with transaction (pass -tx_manager)"',
                       '!$args{-tx_manager}');
     }
 }
 
 # run before args
 sub handlemeta_args_as { {v=>2, prio=>1, convert=>1} }
 sub handle_args_as {
     my ($self, %args) = @_;
 
     my $value  = $args{value};
     my $new    = $args{new};
     my $meta   = $self->{_meta};
     my $args_p = $meta->{args} // {};
     my $opt_va = $self->{_args}{validate_args};
 
     # We support conversion of arguments between hash/hashref/array/arrayref. To
     # make it simple, currently the algorithm is as follow: we first form the
     # %args hash. If args_as is already 'hash', we just do 'my %args = @_'.
     # Otherwise, we convert from the other forms.
     #
     # We then validate each argument in %args (code generated in 'args'
     # handler).
     #
     # Finally, unless original args_as is 'hash' we convert to the final form
     # that the wrapped sub expects.
     #
     # This setup is optimal when both the sub and generated wrapper accept
     # 'hash', but suboptimal for other cases (especially positional ones, as
     # they have to undergo a round-trip to hash even when both accept 'array').
     # This will be rectified in the future.
 
     my $v = $new // $value;
 
     $self->select_section('ACCEPT_ARGS');
     if ($v eq 'hash') {
          $self->push_lines(q{die 'BUG: Odd number of hash elements supplied' if @_ % 2;})
              if $opt_va;
          $self->push_lines('my %args = @_;');
     } elsif ($v eq 'hashref') {
         $self->push_lines(q{die 'BUG: $_[0] needs to be hashref' if @_ && ref($_[0]) ne "HASH";})
             if $opt_va;
         $self->push_lines('my %args = %{$_[0] // {}};');
     } elsif ($v =~ /\Aarray(ref)?\z/) {
         my $ref = $1 ? 1:0;
         if ($ref) {
             $self->push_lines(q{die 'BUG: $_[0] needs to be arrayref' if @_ && ref($_[0]) ne "ARRAY";})
                 if $opt_va;
         }
         $self->push_lines('my %args;');
         $self->select_section('ACCEPT_ARGS2');
         for my $a (sort keys %$args_p) {
             my $as = $args_p->{$a};
             my $line = '$args{'.__squote($a).'} = ';
             defined($as->{pos}) or die "Error in args property for arg '$a': ".
                 "no pos defined";
             my $pos = int($as->{pos} + 0);
             $pos >= 0 or die "Error in args property for arg '$a': ".
                 "negative value in pos";
             if ($as->{greedy}) {
                 if ($ref) {
                     $line .= '[splice @{$_[0]}, '.$pos.'] if @{$_[0]} > '.$pos;
                 } else {
                     $line .= '[splice @_, '.$pos.'] if @_ > '.$pos;
                 }
             } else {
                 if ($ref) {
                     $line .= '$_[0]['.$pos.'] if @{$_[0]} > '.$pos;
                 } else {
                     $line .= '$_['.$pos.'] if @_ > '.$pos;
                 }
             }
             $self->push_lines("$line;");
         }
     } else {
         die "Unknown args_as value '$v'";
     }
 
     $self->select_section('ACCEPT_ARGS');
     if ($value eq 'hashref') {
         $self->push_lines('my $args;');
     } elsif ($value eq 'array') {
         $self->push_lines('my @args;');
     } elsif ($value eq 'arrayref') {
         $self->push_lines('my $args;');
     }
 
     my $tok;
     $self->select_section('before_call_feed_args');
     $v = $value;
     if ($v eq 'hash') {
         $tok = '%args';
     } elsif ($v eq 'hashref') {
         $tok = '$args';
         $self->push_lines($tok.' = \%args;'); # XXX should we set each arg instead?
     } elsif ($v =~ /\Aarray(ref)?\z/) {
         my $ref = $1 ? 1:0;
         $tok = ($ref ? '$':'@') . 'args';
         for my $a (sort {$args_p->{$a}{pos} <=> $args_p->{$b}{pos}}
                        keys %$args_p) {
             my $as = $args_p->{$a};
             my $t = '$args{'.__squote($a).'}';
             my $line;
             defined($as->{pos}) or die "Error in args property for arg '$a': ".
                 "no pos defined";
             my $pos = int($as->{pos} + 0);
             $pos >= 0 or die "Error in args property for arg '$a': ".
                 "negative value in pos";
             if ($as->{greedy}) {
                 $line = 'splice @args, '.$pos.', scalar(@args)-1, @{'.$t.'}';
             } else {
                 $line = '$args'.($ref ? '->':'').'['.$pos."] = $t if exists $t";
             }
             $self->push_lines("$line;");
         }
     } else {
         die "Unknown args_as value '$v'";
     }
     $self->{_args_token} = $tok;
 }
 
 sub _sah {
     require Data::Sah;
 
     my $self = shift;
     state $sah = Data::Sah->new;
     $sah;
 }
 
 sub _plc {
     my $self = shift;
     state $plc = do {
         my $plc = $self->_sah->get_compiler("perl");
         $plc->comment_style('shell2'); # to make all comment uses ## instead of #
         $plc;
     };
 }
 
 sub _handle_args {
     my ($self, %args) = @_;
 
     my $v = $args{v} // $self->{_meta}{args};
     return unless $v;
 
     my $opt_sin = $self->{_args}{_schema_is_normalized};
     my $opt_va  = $self->{_args}{validate_args};
 
     my $prefix = $args{prefix} // '';
     my $argsterm = $args{argsterm} // '%args';
 
     if ($opt_va) {
         $self->_add_module("experimental 'smartmatch'");
         $self->select_section('before_call_arg_validation');
         $self->push_lines('', '# check args') if $prefix eq '';
         $self->push_lines("for (sort keys $argsterm) {");
         $self->indent;
         $self->_errif(400, q["Invalid argument name (please use letters/numbers/underscores only)'].$prefix.q[$_'"],
                       '!/\A(-?)\w+(\.\w+)*\z/o');
         $self->_errif(400, q["Unknown argument '].$prefix.q[$_'"],
                       '!($1 || $_ ~~ '.__squote([sort keys %$v]).')');
         $self->unindent;
         $self->push_lines('}');
     }
 
     for my $argname (sort keys %$v) {
         my $argspec = $v->{$argname};
 
         my $argterm = $argsterm;
         if ($argterm =~ /^%\{\s*(.+)\s*\}/) {
             $argterm = $1 . "->{'$argname'}";
         } elsif ($argterm =~ s/^%/\$/) {
             $argterm .= "{'$argname'}";
         } else {
             $argterm .= "->{'$argname'}";
         }
 
         my $has_default_prop = exists($argspec->{default});
         my $sch = $argspec->{schema};
 
         if ($sch) {
             my $has_sch_default  = ref($sch) eq 'ARRAY' &&
                 exists($sch->[1]{default}) ? 1:0;
             if ($opt_va) {
 
                 $self->push_lines("if (exists($argterm)) {");
                 $self->indent;
 
                 if ($argspec->{stream}) {
                     $self->_errif(
                         400,
                         qq["Argument '$prefix$argname' (stream) fails validation: must be coderef"],
                         "!(ref($argterm) eq 'CODE')",
                     );
                     $self->push_lines('{ ## introduce scope because we want to declare a generic variable $i');
                     $self->indent;
                     $self->push_lines(
                         'my $i = -1;',
                         "my \$origsub = $argterm;",
                         '# arg coderef wrapper for validation',
                         "$argterm = sub {",
                     );
                     $self->indent;
                     $self->push_lines(
                         '$i++;',
                         "my \$rec = \$origsub->();",
                         'return undef unless defined $rec;',
                     );
                 }
 
                 my $dn = $argname; $dn =~ s/\W+/_/g;
                 my $cd = $self->_plc->compile(
                     data_name            => $dn,
                     data_term            => $argspec->{stream} ? '$rec' : $argterm,
                     schema               => $sch,
                     schema_is_normalized => $opt_sin,
                     return_type          => 'str',
                     indent_level         => $self->get_indent_level + 1,
                     core                 => $self->{_args}{core},
                     core_or_pp           => $self->{_args}{core_or_pp},
                     pp                   => $self->{_args}{pp},
                     %{ $self->{_args}{_extra_sah_compiler_args} // {}},
                 );
                 $self->_add_modules($cd->{module_statements});
                 for (@{ $cd->{modules} }) { $self->_add_module($_) unless $cd->{module_statements}{$_} }
                 $self->_add_var($_, $cd->{vars}{$_})
                     for sort keys %{ $cd->{vars} };
                 $cd->{result} =~ s/\A\s+//;
                 $self->push_lines(
                     "my \$err_$dn;",
                     "$cd->{result};",
                 );
                 if ($argspec->{stream}) {
                     $self->push_lines(
                         'if ('."\$err_$dn".') { die "Record #$i of streaming argument '."'$prefix$argname'".' fails validation: '."\$err_$dn".'" }',
                         '$rec;',
                     );
                 } else {
                     $self->_errif(
                         400, qq["Argument '$prefix$argname' fails validation: \$err_$dn"],
                         "\$err_$dn");
                 }
                 if ($argspec->{meta}) {
                     $self->push_lines("# check subargs of $prefix$argname");
                     $self->_handle_args(
                             %args,
                             v => $argspec->{meta}{args},
                             prefix => ($prefix ? "$prefix/" : "") . "$argname/",
                             argsterm => '%{'.$argterm.'}',
                         );
                 }
                 if ($argspec->{element_meta}) {
                     $self->push_lines("# check element subargs of $prefix$argname");
                     my $indexterm = "$prefix$argname";
                     $indexterm =~ s/\W+/_/g;
                     $indexterm = '$i_' . $indexterm;
                     $self->push_lines('for my '.$indexterm.' (0..$#{ '.$argterm.' }) {');
                     $self->indent;
                     $self->_errif(
                         400, qq("Argument '$prefix$argname\[).qq($indexterm]' fails validation: must be hash"),
                         "ref($argterm\->[$indexterm]) ne 'HASH'");
                     $self->_handle_args(
                         %args,
                         v => $argspec->{element_meta}{args},
                         prefix => ($prefix ? "$prefix/" : "") . "$argname\[$indexterm]/",
                         argsterm => '%{'.$argterm.'->['.$indexterm.']}',
                     );
                     $self->unindent;
                     $self->push_lines('}');
                 }
                 $self->unindent;
                 if ($argspec->{stream}) {
                     $self->push_lines('}; ## arg coderef wrapper');
                     $self->unindent;
                     $self->push_lines('} ## close scope');
                     $self->unindent;
                 }
                 if ($has_default_prop) {
                     $self->push_lines(
                         '} else {',
                         "    $argterm //= ".__squote($argspec->{default}).";");
                 } elsif ($has_sch_default) {
                     $self->push_lines(
                         '} else {',
                         "    $argterm //= ".__squote($sch->[1]{default}).";");
                 }
                 $self->push_lines("} ## if exists arg $prefix$argname");
             } # if opt_va
 
         } elsif ($has_default_prop) {
             # doesn't have schema but have 'default' property, we still need to
             # set default here
             $self->push_lines("$argterm = ".__squote($argspec->{default}).
                                   " if !exists($argterm);");
         }
         if ($argspec->{req} && $opt_va) {
             $self->_errif(
                 400, qq["Missing required argument: $argname"],
                 "!exists($argterm)");
         }
     } # for arg
 }
 
 sub handlemeta_args { {v=>2, prio=>10} }
 sub handle_args {
     my ($self, %args) = @_;
     $self->_handle_args(%args);
 }
 
 # after args
 sub handlemeta_args_rels { {v=>2, prio=>11} }
 sub handle_args_rels {
     my ($self, %args) = @_;
 
     my $v = $args{v} // $self->{_meta}{args_rels};
     return unless $v;
 
     my $argsterm = $args{argsterm} // '%args';
 
     $self->select_section('before_call_arg_validation');
     $self->push_lines('', '# check args_rels');
 
     my $dn = "args_rels";
     my $hc = $self->_sah->get_compiler("human");
     my $cd_h = $hc->init_cd;
     $cd_h->{args}{lang} //= $cd_h->{default_lang};
 
     my $cd = $self->_plc->compile(
         data_name            => $dn,
         data_term            => "\\$argsterm",
         schema               => ['hash', $v],
         return_type          => 'str',
         indent_level         => $self->get_indent_level + 1,
         human_hash_values    => {
             field  => $hc->_xlt($cd_h, "argument"),
             fields => $hc->_xlt($cd_h, "arguments"),
         },
         core                 => $self->{_args}{core},
         core_or_pp           => $self->{_args}{core_or_pp},
         pp                   => $self->{_args}{pp},
     );
     $self->_add_modules($cd->{module_statements});
     for (@{ $cd->{modules} }) { $self->_add_module($_) unless $cd->{module_statements}{$_} }
     $self->_add_var($_, $cd->{vars}{$_}) for sort keys %{ $cd->{vars} };
     $cd->{result} =~ s/\A\s+//;
     $self->push_lines(
         "my \$err_$dn;",
         "$cd->{result};",
     );
     $self->_errif(
         400, qq["\$err_$dn"],
         "\$err_$dn");
 }
 
 sub handlemeta_result { {v=>2, prio=>50} }
 sub handle_result {
     require Data::Sah;
 
     my ($self, %args) = @_;
 
     my $meta = $self->{_meta};
     my $v = $meta->{result};
     return unless $v;
 
     my $opt_sin = $self->{_args}{_schema_is_normalized};
     my $opt_vr  = $self->{_args}{validate_result};
 
     my %schemas_by_status; # key = status, value = schema
 
     # collect and check handlers
     my %handler_args;
     my %handler_metas;
     for my $k0 (keys %$v) {
         my $k = $k0;
         $k =~ s/\..+//;
         next if $k =~ /\A_/;
 
         # check builtin result spec key
         next if $k =~ /\A(
                            summary|description|tags|default_lang|
                            schema|statuses|stream|
                            x
                        )\z/x;
         # try a property module first
         require "Perinci/Sub/Property/result/$k.pm";
         my $meth = "handlemeta_result__$k";
         unless ($self->can($meth)) {
             die "No handler for property result/$k0 ($meth)";
         }
         my $hm = $self->$meth;
         $hm->{v} //= 1;
         next unless defined $hm->{prio};
         die "Please update property handler result/$k which is still at v=$hm->{v} ".
             "(needs v=$protocol_version)"
                 unless $hm->{v} == $protocol_version;
         my $ha = {
             prio=>$hm->{prio}, value=>$v->{$k0}, property=>$k0,
             meth=>"handle_result__$k",
         };
         $handler_args{$k} = $ha;
         $handler_metas{$k} = $hm;
     }
 
     # call all the handlers in order
     for my $k (sort {$handler_args{$a}{prio} <=> $handler_args{$b}{prio}}
                    keys %handler_args) {
         my $ha = $handler_args{$k};
         my $meth = $ha->{meth};
         local $self->{_cur_handler}      = $meth;
         local $self->{_cur_handler_meta} = $handler_metas{$k};
         local $self->{_cur_handler_args} = $ha;
         $self->$meth(args=>\%args, meta=>$meta, %$ha);
     }
 
     # validate result
     my @modules;
     if ($v->{schema} && $opt_vr) {
         $schemas_by_status{200} = $v->{schema};
     }
     if ($v->{statuses} && $opt_vr) {
         for my $s (keys %{$v->{statuses}}) {
             my $sv = $v->{statuses}{$s};
             if ($sv->{schema}) {
                 $schemas_by_status{$s} = $sv->{schema};
             }
         }
     }
 
     my $sub_name = $self->{_args}{sub_name};
 
     if ($opt_vr) {
         $self->select_section('after_call_res_validation');
         $self->push_lines(
             'my $_w_res2 = $_w_res->[2];',
             'my $_w_res_is_stream = $_w_res->[3]{stream} // ' . ($v->{stream} ? 1:0) . ';',
         );
         $self->_errif(
             500,
             q["Stream result must be coderef"],
             '$_w_res_is_stream && ref($_w_res2) ne "CODE"',
         );
         for my $s (sort keys %schemas_by_status) {
             my $sch = $schemas_by_status{$s};
             $self->push_lines("if (\$_w_res->[0] == $s) {");
             $self->indent;
             $self->push_lines('if (!$_w_res_is_stream) {');
             $self->indent;
 
             my $cd = $self->_plc->compile(
                 data_name            => '_w_res2',
                 # err_res can clash on arg named 'res'
                 err_term             => '$_w_err2_res',
                 schema               => $sch,
                 schema_is_normalized => $opt_sin,
                 return_type          => 'str',
                 indent_level         => $self->get_indent_level + 1,
                 core                 => $self->{_args}{core},
                 core_or_pp           => $self->{_args}{core_or_pp},
                 pp                   => $self->{_args}{pp},
                 %{ $self->{_args}{_extra_sah_compiler_args} // {}},
             );
             $self->_add_modules($cd->{module_statements});
             for (@{ $cd->{modules} }) { $self->_add_module($_) unless $cd->{module_statements}{$_} }
             $self->_add_var($_, $cd->{vars}{$_})
                 for sort keys %{ $cd->{vars} };
             $self->push_lines("my \$_w_err2_res;");
             $cd->{result} =~ s/\A\s+//;
             $self->push_lines("$cd->{result};");
             $self->_errif(
                 500,
                 qq["BUG: Result from sub $sub_name fails validation: ].
                     qq[\$_w_err2_res"],
                 "\$_w_err2_res");
             $self->unindent;
             $self->push_lines("} else {"); # stream
             $self->indent;
             $self->push_lines(
                 'my $i = -1;',
                 '# wrap result coderef for validation',
                 '$_w_res->[2] = sub {',
             );
             $self->indent;
             $self->push_lines(
                 '$i++;',
                 'my $rec = $_w_res2->();',
                 'return undef unless defined $rec;',
             );
             # generate schema code once again, this time for when stream
             $cd = $self->_plc->compile(
                 data_name            => 'rec',
                 # err_res can clash on arg named 'res'
                 err_term             => '$rec_err',
                 schema               => $sch,
                 schema_is_normalized => $opt_sin,
                 return_type          => 'str',
                 indent_level         => $self->get_indent_level + 1,
                 core                 => $self->{_args}{core},
                 core_or_pp           => $self->{_args}{core_or_pp},
                 pp                   => $self->{_args}{pp},
                 %{ $self->{_args}{_extra_sah_compiler_args} // {}},
             );
             $self->push_lines('my $rec_err;');
             $cd->{result} =~ s/\A\s+//;
             $self->push_lines("$cd->{result};");
             $self->push_lines('if ($rec_err) { die "BUG: Result stream record #$i fail validation: $rec_err" }');
             $self->push_lines('$rec;');
             $self->unindent;
             $self->push_lines('}; ## result coderef wrapper');
             $self->unindent;
             $self->push_lines("} ## if stream");
             $self->unindent;
             $self->push_lines("} ## if status=$s");
         } # for schemas_by_status
     }
 }
 
 sub handlemeta_result_naked { {v=>2, prio=>99, convert=>1} }
 sub handle_result_naked {
     my ($self, %args) = @_;
 
     my $old = $args{value};
     my $v   = $args{new} // $old;
 
     return if !!$v == !!$old;
 
     $self->select_section('AFTER_CALL_ADD_OR_STRIP_RESULT_ENVELOPE');
     if ($v) {
         $self->push_lines(
             '', '# strip result envelope',
             '$_w_res = $_w_res->[2];',
         );
     } else {
         $self->push_lines(
             '', '# add result envelope',
             '$_w_res = [200, "OK", $_w_res];',
         );
     }
 }
 
 sub handlemeta_deps { {v=>2, prio=>0.5} }
 sub handle_deps {
     my ($self, %args) = @_;
     my $value = $args{value};
     my $meta  = $self->{_meta};
     my $v     = $self->{_args}{meta_name};
     $self->select_section('before_call_after_arg_validation');
     $self->push_lines('', '# check dependencies');
     $self->_add_module("Perinci::Sub::DepChecker");
     #$self->push_lines('use Data::Dump; dd '.$v.';');
     $self->push_lines('my $_w_deps_res = Perinci::Sub::DepChecker::check_deps('.
                           $v.'->{deps});');
     $self->_errif(412, '"Deps failed: $_w_deps_res"', '$_w_deps_res');
 
     # we handle some deps our own
     if ($value->{tmp_dir}) {
         $self->_errif(412, '"Dep failed: please specify -tmp_dir"',
                       '!$args{-tmp_dir}');
     }
     if ($value->{trash_dir}) {
         $self->_errif(412, '"Dep failed: please specify -trash_dir"',
                       '!$args{-trash_dir}');
     }
     if ($value->{undo_trash_dir}) {
         $self->_errif(412, '"Dep failed: please specify -undo_trash_dir"',
                       '!($args{-undo_trash_dir} || $args{-tx_manager} || '.
                           '$args{-undo_action} && $args{-undo_action}=~/\A(?:undo|redo)\z/)');
     }
 }
 
 sub handlemeta_x { {} }
 sub handlemeta_entity_v { {} }
 sub handlemeta_entity_date { {} }
 
 sub _reset_work_data {
     my ($self, %args) = @_;
 
     # to make it stand out more, all work/state data is prefixed with
     # underscore.
 
     $self->{_cur_section}      = undef;
     $self->{_cur_handler}      = undef;
     $self->{_cur_handler_args} = undef;
     $self->{_cur_handler_meta} = undef;
     $self->{_levels}           = {};
     $self->{_codes}            = {};
     $self->{_modules}          = []; # modules loaded by wrapper sub
     $self->{$_} = $args{$_} for keys %args;
 }
 
 sub wrap {
     require Scalar::Util;
 
     my ($self, %args) = @_;
 
     my $wrap_log_prop = "x.perinci.sub.wrapper.logs";
 
     # required arguments
     my $sub      = $args{sub};
     my $sub_name = $args{sub_name};
     $sub || $sub_name or return [400, "Please specify sub or sub_name"];
     $args{meta} or return [400, "Please specify meta"];
     my $meta_name = $args{meta_name};
     # we clone the meta because we'll replace stuffs
     my $meta     = clone($args{meta});
     my $wrap_logs = $meta->{$wrap_log_prop} // [];
 
     # currently internal args, not exposed/documented
     $args{_compiled_package}           //= 'Perinci::Sub::Wrapped';
     my $comppkg  = $args{_compiled_package};
     $args{_schema_is_normalized}       //=
         $wrap_logs->[-1] && $wrap_logs->[-1]{normalize_schema} ? 1 : 0;
     $args{_embed}                      //= 0;
     $args{_extra_sah_compiler_args}    //= undef;
 
     # defaults for arguments
     $args{indent}                      //= " " x 4;
     $args{convert}                     //= {};
     $args{compile}                     //= 1;
     $args{log}                         //= 1;
     $args{validate_args}               //= 0
         # function might want to disable validate_args by default, e.g. if
         # source code has been processed with
         # Dist::Zilla::Plugin::Rinci::Validate
         if $meta->{'x.perinci.sub.wrapper.disable_validate_args'};
     $args{validate_args}               //= 0
         # by default do not validate args again if previous wrapper(s) have
         # already done it
         if (grep {$_->{validate_args}} @$wrap_logs);
     $args{validate_args}               //= 1;
     $args{validate_result}             //= 0
         # function might want to disable validate_result by default, e.g. if
         # source code has been processed with
         # Dist::Zilla::Plugin::Rinci::Validate
         if $meta->{'x.perinci.sub.wrapper.disable_validate_result'};
     $args{validate_result}             //= 0
         # by default do not validate result again if previous wrapper(s) have
         # already done it
         if (grep {$_->{validate_result}} @$wrap_logs);
     $args{validate_result}             //= 1;
     $args{core}                        //= $ENV{PERINCI_WRAPPER_CORE};
     $args{core_or_pp}                  //= $ENV{PERINCI_WRAPPER_CORE_OR_PP};
     $args{pp}                          //= $ENV{PERINCI_WRAPPER_PP};
 
     my $sub_ref_name;
     # if sub_name is not provided, create a unique name for it. it is needed by
     # the wrapper-generated code (e.g. printing error messages)
     if (!$sub_name || $sub) {
         my $n = $comppkg . "::sub".Scalar::Util::refaddr($sub);
         no strict 'refs'; no warnings; ${$n} = $sub;
         use experimental 'smartmatch';
         if (!$sub_name) {
             $args{sub_name} = $sub_name = '$' . $n;
         }
         $sub_ref_name = '$' . $n;
     }
     # if meta name is not provided, we store the meta somewhere, it is needed by
     # the wrapper-generated code (e.g. deps clause).
     if (!$meta_name) {
         my $n = $comppkg . "::meta".Scalar::Util::refaddr($meta);
         no strict 'refs'; no warnings; ${$n} = $meta;
         use experimental 'smartmatch';
         $args{meta_name} = $meta_name = '$' . $n;
     }
 
     # shallow copy
     my $opt_cvt = { %{ $args{convert} } };
     my $opt_sin = $args{_schema_is_normalized};
 
     $meta = normalize_function_metadata($meta)
         unless $opt_sin;
 
     $self->_reset_work_data(_args=>\%args, _meta=>$meta);
 
     # add properties from convert, if not yet mentioned in meta
     for (keys %$opt_cvt) {
         $meta->{$_} = undef unless exists $meta->{$_};
     }
 
     # mark in the metadata that we have done the wrapping, so future wrapping
     # can avoid needless duplicated functionality (like validating args twice).
     # note that handler can log their mark too.
     {
         my @wrap_log = @{ $meta->{$wrap_log_prop} // [] };
         push @wrap_log, {
             validate_args     => $args{validate_args},
             validate_result   => $args{validate_result},
             normalize_schema  => !$opt_sin,
         };
         if ($args{log}) {
             $meta->{$wrap_log_prop} = \@wrap_log;
         }
     }
 
     # start iterating over properties
 
     $self->select_section('OPEN_SUB');
     $self->push_lines(
         "package $comppkg;", 'sub {');
     $self->indent;
 
     $meta->{args_as} //= "hash";
 
     if ($meta->{args_as} =~ /hash/) {
         $self->select_section('before_call_after_arg_validation');
         # tell function it's being wrapped, currently disabled
         #$self->push_lines('$args{-wrapped} = 1;');
     }
 
     my %props = map {$_=>1} keys %$meta;
     $props{$_} = 1 for keys %$opt_cvt;
 
     # collect and check handlers
     my %handler_args;
     my %handler_metas;
     for my $k0 (keys %props) {
         my $k = $k0;
         $k =~ s/\..+//;
         next if $k =~ /\A_/;
         next if $handler_args{$k};
         #if ($k ~~ $self->{_args}{skip}) {
         #    $log->tracef("Skipped property %s (mentioned in skip)", $k);
         #    next;
         #}
         return [500, "Invalid property name $k"] unless $k =~ /\A\w+\z/;
         my $meth = "handlemeta_$k";
         unless ($self->can($meth)) {
             # try a property module first
             require "Perinci/Sub/Property/$k.pm";
             unless ($self->can($meth)) {
                 return [500, "No handler for property $k0 ($meth)"];
             }
         }
         my $hm = $self->$meth;
         $hm->{v} //= 1;
         next unless defined $hm->{prio};
         die "Please update property handler $k which is still at v=$hm->{v} ".
             "(needs v=$protocol_version)"
                 unless $hm->{v} == $protocol_version;
         my $ha = {
             prio=>$hm->{prio}, value=>$meta->{$k0}, property=>$k0,
             meth=>"handle_$k",
         };
         if (exists $opt_cvt->{$k0}) {
             return [501, "Property '$k0' does not support conversion"]
                 unless $hm->{convert};
             $ha->{new}   = $opt_cvt->{$k0};
             $meta->{$k0} = $opt_cvt->{$k0};
         }
         $handler_args{$k}  = $ha;
         $handler_metas{$k} = $hm;
     }
 
     # call all the handlers in order
     for my $k (sort {$handler_args{$a}{prio} <=> $handler_args{$b}{prio}}
                    keys %handler_args) {
         my $ha = $handler_args{$k};
         my $meth = $ha->{meth};
         local $self->{_cur_handler}      = $meth;
         local $self->{_cur_handler_meta} = $handler_metas{$k};
         local $self->{_cur_handler_args} = $ha;
         $self->$meth(args=>\%args, meta=>$meta, %$ha);
     }
 
     my $needs_store_res = $self->_needs_store_res;
     if ($needs_store_res) {
         $self->_add_var('_w_res');
     }
 
     $self->select_section('CALL');
     my $sn = $sub_ref_name // $sub_name;
     $self->push_lines(
         ($needs_store_res ? '$_w_res = ' : "") .
         $sn. ($sn =~ /^\$/ ? "->" : "").
             "(".$self->{_args_token}.");");
     if ($args{validate_result}) {
         $self->select_section('after_call_before_res_validation');
         unless ($meta->{result_naked}) {
             $self->push_lines(
                 '',
                 '# check that sub produces enveloped result',
                 'unless (ref($_w_res) eq "ARRAY" && $_w_res->[0]) {',
             );
             $self->indent;
             if ($log->is_trace) {
                 $self->_add_module('Data::Dumper');
                 $self->push_lines(
                     'local $Data::Dumper::Purity   = 1;',
                     'local $Data::Dumper::Terse    = 1;',
                     'local $Data::Dumper::Indent   = 0;',
                 );
                 $self->_err(500,
                             qq['BUG: Sub $sub_name does not produce envelope: '.].
                                 qq[Data::Dumper::Dumper(\$_w_res)]);
             } else {
                 $self->_err(500,
                             qq['BUG: Sub $sub_name does not produce envelope']);
             }
             $self->unindent;
             $self->push_lines('}');
         }
     }
 
     my $use_eval = $self->_needs_eval;
     if ($use_eval) {
         $self->select_section('CLOSE_EVAL');
         $self->push_lines('return $_w_res;');
         $self->unindent;
         $self->_add_var('_w_eval_err');
         $self->push_lines(
             '};',
             '$_w_eval_err = $@;');
 
         # _needs_eval will automatically be enabled here, due after_eval being
         # filled
         $self->select_section('after_eval');
         $self->push_lines('warn $_w_eval_err if $_w_eval_err;');
         $self->_errif(500, '"Function died: $_w_eval_err"', '$_w_eval_err');
 
         $self->select_section('OPEN_EVAL');
         $self->push_lines('eval {');
         $self->indent;
     }
 
     # return sub result
     $self->select_section('BEFORE_CLOSE_SUB');
     $self->push_lines('return $_w_res;') if $needs_store_res;
     $self->select_section('CLOSE_SUB');
     $self->unindent;
     $self->push_lines('}'); # wrapper sub
 
     # return wrap result
     my $result = {
         sub_name     => $sub_name,
         sub_ref_name => $sub_ref_name,
         meta         => $meta,
         meta_name    => $meta_name,
         use_eval     => $use_eval,
     };
     if ($args{embed}) {
         $result->{source} = $self->_format_embed_wrapper_code;
     } else {
         my $source = $self->_format_dyn_wrapper_code;
         if ($Log_Wrapper_Code && $log->is_trace) {
             require String::LineNumber;
             $log->tracef("wrapper code:\n%s",
                          $ENV{LINENUM} // 1 ?
                              String::LineNumber::linenum($source) :
                                    $source);
         }
         $result->{source} = $source;
         if ($args{compile}) {
             my $wrapped = eval $source;
             die "BUG: Wrapper code can't be compiled: $@" if $@ || !$wrapped;
             $result->{sub}  = $wrapped;
         }
     }
 
     [200, "OK", $result];
 }
 
 $SPEC{wrap_sub} = {
     v => 1.1,
     summary => 'Wrap subroutine to do various things, '.
         'like enforcing Rinci properties',
     result => {
         summary => 'The wrapped subroutine along with its new metadata',
         description => <<'_',
 
 Aside from wrapping the subroutine, the wrapper will also create a new metadata
 for the subroutine. The new metadata is a clone of the original, with some
 properties changed, e.g. schema in `args` and `result` normalized, some values
 changed according to the `convert` argument, some defaults set, etc.
 
 The new metadata will also contain (or append) the wrapping log located in the
 `x.perinci.sub.wrapper.logs` attribute. The wrapping log marks that the wrapper
 has added some functionality (like validating arguments or result) so that
 future nested wrapper can choose to avoid duplicating the same functionality.
 
 _
         schema=>['hash*'=>{keys=>{
             sub=>'code*',
             source=>['any*' => of => ['str*', ['hash*' => each_value=>'str*']]],
             meta=>'hash*',
         }}],
     },
     args => {
         sub => {
             schema => 'str*',
             summary => 'The code to be wrapped',
             description => <<'_',
 
 At least one of `sub` or `sub_name` must be specified.
 
 _
         },
         sub_name => {
             schema => 'str*',
             summary => 'The name of the subroutine, '.
                 'e.g. func or Foo::func (qualified)',
             description => <<'_',
 
 At least one of `sub` or `sub_name` must be specified.
 
 _
         },
         meta => {
             schema => 'hash*',
             summary => 'The function metadata',
             req => 1,
         },
         meta_name => {
             schema => 'str*',
             summary => 'Where to find the metadata, e.g. "$SPEC{foo}"',
             description => <<'_',
 
 Some wrapper code (e.g. handler for `dep` property) needs to refer to the
 function metadata. If not provided, the wrapper will store the function metadata
 in a unique variable (e.g. `$Perinci::Sub::Wrapped::meta34127816`).
 
 _
         },
         convert => {
             schema => 'hash*',
             summary => 'Properties to convert to new value',
             description => <<'_',
 
 Not all properties can be converted, but these are a partial list of those that
 can: v (usually do not need to be specified when converting from 1.0 to 1.1,
 will be done automatically), args_as, result_naked, default_lang.
 
 _
         },
         compile => {
             schema => ['bool' => {default=>1}],
             summary => 'Whether to compile the generated wrapper',
             description => <<'_',
 
 Can be set to 0 to not actually wrap but just return the generated wrapper
 source code.
 
 _
         },
         compile => {
             schema => ['bool' => {default=>1}],
             summary => 'Whether to compile the generated wrapper',
             description => <<'_',
 
 Can be set to 0 to not actually wrap but just return the generated wrapper
 source code.
 
 _
         },
         debug => {
             schema => [bool => {default=>0}],
             summary => 'Generate code with debugging',
             description => <<'_',
 
 If turned on, will produce various debugging in the generated code. Currently
 what this does:
 
 * add more comments (e.g. for each property handler)
 
 _
         },
         validate_args => {
             schema => ['bool'],
             summary => 'Whether wrapper should validate arguments',
             description => <<'_',
 
 If set to true, will validate arguments. Validation error will cause status 400
 to be returned. The default is to enable this unless previous wrapper(s) have
 already done this.
 
 _
         },
         validate_result => {
             schema => ['bool'],
             summary => 'Whether wrapper should validate arguments',
             description => <<'_',
 
 If set to true, will validate sub's result. Validation error will cause wrapper
 to return status 500 instead of sub's result. The default is to enable this
 unless previous wrapper(s) have already done this.
 
 _
         },
         core => {
             summary => 'If set to true, will avoid the use of non-core modules',
             schema => 'bool',
         },
         core_or_pp => {
             summary => 'If set to true, will avoid the use of non-core XS modules',
             schema => 'bool',
             description => <<'_',
 
 In other words, will stick to core or pure-perl modules only.
 
 _
         },
         pp => {
             summary => 'If set to true, will avoid the use of XS modules',
             schema => 'bool',
         },
     },
 };
 sub wrap_sub {
     __PACKAGE__->new->wrap(@_);
 }
 
 1;
 # ABSTRACT: A multi-purpose subroutine wrapping framework
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Perinci::Sub::Wrapper - A multi-purpose subroutine wrapping framework
 
 =head1 VERSION
 
 This document describes version 0.79 of Perinci::Sub::Wrapper (from Perl distribution Perinci-Sub-Wrapper), released on 2015-09-04.
 
 =head1 SYNOPSIS
 
 For dynamic usage:
 
  use Perinci::Sub::Wrapper qw(wrap_sub);
  my $res = wrap_sub(sub_name => "mysub", meta=>{...});
  my ($wrapped_sub, $meta) = ($res->[2]{sub}, $res->[2]{meta});
  $wrapped_sub->(); # call the wrapped function
 
 =head1 DESCRIPTION
 
 Perinci::Sub::Wrapper (PSW for short) is an extensible subroutine wrapping
 framework. It generates code to do stuffs before calling your subroutine, like
 validate arguments, convert arguments from positional/array to named/hash or
 vice versa, etc; as well as generate code to do stuffs after calling your
 subroutine, like retry calling for a number of times if subroutine returns a
 non-success status, check subroutine result against a schema, etc). Some other
 things it can do: apply a timeout, currying, and so on.
 
 PSW differs from other function composition or decoration system like Python
 decorators (or its Perl equivalent L<Python::Decorator>) in a couple of ways:
 
 =over
 
 =item * Single wrapper
 
 Instead of multiple/nested wrapping for implementing different features, PSW
 is designed to generate a single large wrapper around your code, i.e.:
 
  sub _wrapper_for_your_sub {
      ...
      # do various stuffs before calling:
 
      # e.g. start timer
      # e.g. convert, prefill, validate arguments
      my @args = ...;
      ...
      your_sub(@args);
      ...
      # do various stuffs after calling
      ...
      # e.g. report times
      # e.g. perform retry
      # e.g. convert or envelope results
 
      # return result
  }
 
 Multiple functionalities will be added and combined in this single wrapper
 subroutine in the appropriate location. This is done to reduce function call
 overhead or depth of nested call levels. And also to make it easier to embed the
 wrapping code to your source code (see L<Dist::Zilla::Plugin::Rinci::Wrap>).
 
 Of course, you can still wrap multiple times if wanted.
 
 =item * Rinci
 
 The wrapper code is built according to the L<Rinci> metadata you provide. Rinci
 allows you to specify various things for your function, e.g. list of arguments
 including the expected data type of each argument and whether an argument is
 required or optional. PSW can then be used to generate the necessary code to
 enforce this specification, e.g. generate validator for the function arguments.
 
 Since Rinci specification is extensible, you can describe additional stuffs for
 your function and write a PSW plugin to generate the necessary code to implement
 your specification. An example is C<timeout> to specify execution time limit,
 implemented by L<Perinci::Sub::Property::timeout> which generates code to call
 function inside an C<eval()> block and use C<alarm()> to limit the execution.
 Another example is C<retry> property, implemented by
 L<Perinci::Sub::Property::retry> which generates code to call function inside a
 simple retry loop.
 
 =back
 
 Normally you do not use PSW directly in your applications. You might want to
 check out L<Perinci::Access::Perl> and L<Perinci::Exporter> on examples of
 wrapping function dynamically (during runtime), or
 L<Dist::Zilla::Plugin::Rinci::Wrap> on an example of embedding the generated
 wrapping code to source code during build.
 
 =head1 FUNCTIONS
 
 
 =head2 wrap_sub(%args) -> [status, msg, result, meta]
 
 Wrap subroutine to do various things, like enforcing Rinci properties.
 
 Arguments ('*' denotes required arguments):
 
 =over 4
 
 =item * B<compile> => I<bool> (default: 1)
 
 Whether to compile the generated wrapper.
 
 Can be set to 0 to not actually wrap but just return the generated wrapper
 source code.
 
 =item * B<convert> => I<hash>
 
 Properties to convert to new value.
 
 Not all properties can be converted, but these are a partial list of those that
 can: v (usually do not need to be specified when converting from 1.0 to 1.1,
 will be done automatically), args_as, result_naked, default_lang.
 
 =item * B<core> => I<bool>
 
 If set to true, will avoid the use of non-core modules.
 
 =item * B<core_or_pp> => I<bool>
 
 If set to true, will avoid the use of non-core XS modules.
 
 In other words, will stick to core or pure-perl modules only.
 
 =item * B<debug> => I<bool> (default: 0)
 
 Generate code with debugging.
 
 If turned on, will produce various debugging in the generated code. Currently
 what this does:
 
 =over
 
 =item * add more comments (e.g. for each property handler)
 
 =back
 
 =item * B<meta>* => I<hash>
 
 The function metadata.
 
 =item * B<meta_name> => I<str>
 
 Where to find the metadata, e.g. "$SPEC{foo}".
 
 Some wrapper code (e.g. handler for C<dep> property) needs to refer to the
 function metadata. If not provided, the wrapper will store the function metadata
 in a unique variable (e.g. C<$Perinci::Sub::Wrapped::meta34127816>).
 
 =item * B<pp> => I<bool>
 
 If set to true, will avoid the use of XS modules.
 
 =item * B<sub> => I<str>
 
 The code to be wrapped.
 
 At least one of C<sub> or C<sub_name> must be specified.
 
 =item * B<sub_name> => I<str>
 
 The name of the subroutine, e.g. func or Foo::func (qualified).
 
 At least one of C<sub> or C<sub_name> must be specified.
 
 =item * B<validate_args> => I<bool>
 
 Whether wrapper should validate arguments.
 
 If set to true, will validate arguments. Validation error will cause status 400
 to be returned. The default is to enable this unless previous wrapper(s) have
 already done this.
 
 =item * B<validate_result> => I<bool>
 
 Whether wrapper should validate arguments.
 
 If set to true, will validate sub's result. Validation error will cause wrapper
 to return status 500 instead of sub's result. The default is to enable this
 unless previous wrapper(s) have already done this.
 
 =back
 
 Returns an enveloped result (an array).
 
 First element (status) is an integer containing HTTP status code
 (200 means OK, 4xx caller error, 5xx function error). Second element
 (msg) is a string containing error message, or 'OK' if status is
 200. Third element (result) is optional, the actual result. Fourth
 element (meta) is called result metadata and is optional, a hash
 that contains extra information.
 
 Return value: The wrapped subroutine along with its new metadata (hash)
 
 
 Aside from wrapping the subroutine, the wrapper will also create a new metadata
 for the subroutine. The new metadata is a clone of the original, with some
 properties changed, e.g. schema in C<args> and C<result> normalized, some values
 changed according to the C<convert> argument, some defaults set, etc.
 
 The new metadata will also contain (or append) the wrapping log located in the
 C<x.perinci.sub.wrapper.logs> attribute. The wrapping log marks that the wrapper
 has added some functionality (like validating arguments or result) so that
 future nested wrapper can choose to avoid duplicating the same functionality.
 
 =for Pod::Coverage ^(new|handle(meta)?_.+|wrap|add_.+|section_empty|indent|unindent|get_indent_level|select_section|push_lines)$
 
 =head1 EXTENDING
 
 The framework is simple and extensible. Please delve directly into the source
 code for now. Some notes:
 
 The internal uses OO.
 
 The main wrapper building mechanism is in the C<wrap()> method.
 
 For each Rinci property, it will call C<handle_NAME()> wrapper handler method.
 The C<handlemeta_NAME()> methods are called first, to determine order of
 processing. You can supply these methods either by subclassing the class or,
 more simply, monkeypatching the method in the C<Perinci::Sub::Wrapper> package.
 
 The wrapper handler method will be called with a hash argument, containing these
 keys: B<value> (property value), B<new> (this key will exist if C<convert>
 argument of C<wrap()> exists, to convert a property to a new value).
 
 For properties that have name in the form of C<NAME1.NAME2.NAME3> (i.e., dotted)
 only the first part of the name will be used (i.e., C<handle_NAME1()>).
 
 =head1 VARIABLES
 
 =head2 $Log_Wrapper_Code (BOOL)
 
 Whether to log wrapper result. Default is from environment variable
 LOG_PERINCI_WRAPPER_CODE, or false. Logging is done with L<Log::Any> at trace
 level.
 
 =head1 METHODS
 
 The OO interface is only used internally or when you want to extend the wrapper.
 
 =head1 ENVIRONMENT
 
 =head2 LOG_PERINCI_WRAPPER_CODE (bool)
 
 If set to 1, will log the generated wrapper code. This value is used to set
 C<$Log_Wrapper_Code> if it is not already set.
 
 =head2 PERINCI_WRAPPER_CORE => bool
 
 Set default for wrap argument C<core>.
 
 =head2 PERINCI_WRAPPER_CORE_OR_PP => bool
 
 Set default for wrap argument C<core_or_pp>.
 
 =head2 PERINCI_WRAPPER_PP => bool
 
 Set default for wrap argument C<pp>.
 
 =head1 RINCI FUNCTION METADATA
 
 =head2 x.perinci.sub.wrapper.disable_validate_args => bool
 
 Can be set to 1 to set C<validate_args> to 0 by default. This is used e.g. if
 you already embed/insert code to validate arguments by other means and do not
 want to repeat validating arguments. E.g. used if you use
 L<Dist::Zilla::Plugin::Rinci::Validate>.
 
 =head2 x.perinci.sub.wrapper.disable_validate_result => bool
 
 Can be set to 1 to set C<validate_result> to 0 by default. This is used e.g. if
 you already embed/insert code to validate result by other means and do not want
 to repeat validating result. E.g. used if you use
 L<Dist::Zilla::Plugin::Rinci::Validate>.
 
 =head2 x.perinci.sub.wrapper.logs => array
 
 Generated/added by this module to the function metadata for every wrapping done.
 Used to avoid adding repeated code, e.g. to validate result or arguments.
 
 =head1 PERFORMANCE NOTES
 
 The following numbers are produced on an Intel Core i5-2400 3.1GHz desktop using
 PSW v0.51 and Perl v5.18.2. Operating system is Debian sid (64bit).
 
 For perspective, empty subroutine (C<< sub {} >>) as well as C<< sub { [200,
 "OK"] } >> can be called around 5.3 mil/sec.
 
 Wrapping this subroutine C<< sub { [200, "OK"] } >> and this simple metadata C<<
 {v=>1.1} >> using default options yields call performance for C<< $sub->() >> of
 about 0.9 mil/sec. With C<< validate_args=>0 >> and C<< validate_result=>0 >>,
 it's 1.5 mil/sec.
 
 As more (and more complex) arguments are introduced and validated, overhead will
 increase. The significant portion of the overhead is in argument validation. For
 example, this metadata C<< {v=>1.1, args=>{a=>{schema=>"int"}}} >> yields 0.5
 mil/sec.
 
 =head1 FAQ
 
 =head2 General
 
 =over
 
 =item * What is a function wrapper?
 
 A wrapper function calls the target function but with additional behaviors. The
 goal is similar to function composition or decorator system like in Python (or
 its Perl equivalent L<Python::Decorator>) where you use a higher-order function
 which accepts another function and modifies it.
 
 It is used to add various functionalities, e.g.: cache/memoization, singleton,
 adding benchmarking/timing around function call, logging, argument validation
 (parameter checking), checking pre/post-condition, authentication/authorization
 checking, etc. The Python folks use decorators quite a bit; see discussions on
 the Internet on those.
 
 =item * How is PSW different from Python::Decorator?
 
 PSW uses dynamic code generation (it generates Perl code on the fly). It also
 creates a single large wrapper instead of nested wrappers. It builds wrapper
 code according to L<Rinci> specification.
 
 =item * Why use code generation?
 
 Mainly because L<Data::Sah>, which is the module used to do argument validation,
 also uses code generation. Data::Sah allows us to do data validation at full
 Perl speed, which can be one or two orders of magnitude faster than
 "interpreter" modules like L<Data::FormValidator>.
 
 =item * Why use a single large wrapper?
 
 This is just a design approach. It can impose some restriction for wrapper code
 authors, since everything needs to be put in a single subroutine, but has nice
 properties like less stack trace depth and less function call overhead.
 
 =back
 
 =head2 Debugging
 
 =over
 
 =item * How to display the wrapper code being generated?
 
 If environment variable L<LOG_PERINCI_WRAPPER_CODE> or package variable
 $Log_Perinci_Wrapper_Code is set to true, generated wrapper source code is
 logged at trace level using L<Log::Any>. It can be displayed, for example, using
 L<Log::Any::App>:
 
  % LOG=1 LOG_PERINCI_WRAPPER_CODE=1 TRACE=1 \
    perl -MLog::Any::App -MPerinci::Sub::Wrapper=wrap_sub \
    -e 'wrap_sub(sub=>sub{}, meta=>{v=>1.1, args=>{a=>{schema=>"int"}}});'
 
 Note that L<Data::Sah> (the module used to generate validator code) observes
 C<LOG_SAH_VALIDATOR_CODE>, but during wrapping this environment flag is
 currently disabled by this module, so you need to set
 L<LOG_PERINCI_WRAPPER_CODE> instead.
 
 =back
 
 =head2 caller() doesn't work from inside my wrapped code!
 
 Wrapping adds at least one or two levels of calls: one for the wrapper
 subroutine itself, the other is for the eval trap when necessary.
 
 This poses a problem if you need to call caller() from within your wrapped code;
 it will also be off by at least one or two.
 
 The solution is for your function to use the caller() replacement, provided by
 L<Perinci::Sub::Util>. Or use embedded mode, where the wrapper code won't add
 extra subroutine calls.
 
 =head1 SEE ALSO
 
 L<Perinci>, L<Rinci>
 
 L<Python::Decorator>
 
 L<Dist::Zilla::Plugin::Rinci::Wrap>
 
 L<Dist::Zilla::Plugin::Rinci::Validate>
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Perinci-Sub-Wrapper>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Perinci-Sub-Wrapper>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Perinci-Sub-Wrapper>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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
### Proc/PID/File.pm ###
 #
 #   Proc::PID::File - pidfile manager
 #   Copyright (C) 2001-2003 Erick Calder
 #
 #   This program is free software; you can redistribute it and/or modify
 #   it under the terms of the GNU General Public License as published by
 #   the Free Software Foundation; either version 2 of the License, or
 #   (at your option) any later version.
 #
 #   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 the
 #   GNU General Public License for more details.
 #
 #   You should have received a copy of the GNU General Public License
 #   along with this program; if not, write to the Free Software
 #   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 #
 
 package Proc::PID::File;
 
 =head1 NAME
 
 Proc::PID::File - a module to manage process id files
 
 =head1 SYNOPSIS
 
   use Proc::PID::File;
   die "Already running!" if Proc::PID::File->running();
 
 Process that spawn child processes may want to protect
 each separately by using multiple I<pidfiles>.
 
   my $child1 = Proc::PID::File->new(name => "lock.1");
   my $child2 = Proc::PID::File->new(name => "lock.2");
 
 which may be checked like this:
 
   <do-something> if $child1->alive();
 
 and should be released manually:
 
   $child1->release();
 
 =head1 DESCRIPTION
 
 This Perl module is useful for writers of daemons and other processes that need to tell whether they are already running, in order to prevent multiple process instances.  The module accomplishes this via *nix-style I<pidfiles>, which are files that store a process identifier.
 
 The module provides two interfaces: 1) a simple call, and
 2) an object-oriented interface
 
 =cut
 
 require Exporter;
 @ISA = qw(Exporter);
 
 use strict;
 use vars qw($VERSION $RPM_Requires);
 use Fcntl qw(:DEFAULT :flock);
 
 $VERSION = "1.27";
 $RPM_Requires = "procps";
 
 my $RUNDIR = "/var/run";
 my ($ME) = $0 =~ m|([^/]+)$|;
 my $self;
 
 # -- Simple Interface --------------------------------------------------------
 
 =head1 Simple Interface
 
 The simple interface consists of a call as indicated in the first example
 of the B<Synopsis> section above.  This approach avoids causing race
 conditions whereby one instance of a daemon could read the I<pidfile>
 after a previous instance has read it but before it has had a chance
 to write to it.
 
 =head2 running [hash[-ref]]
 
 The parameter signature for this function is identical to that of the
 I<-E<gt>new()> method described below in the B<OO Interface> section of this document. The method's return value is the same as that of I<-E<gt>alive()>.
 
 =cut
 
 sub running {
     $self = shift->new(@_);
 
 	local *FH;
 	my $pid = $self->read(*FH);
 
 	if ($pid && $pid != $$ && kill(0, $pid)) {
         $self->debug("running: $pid");
 	    close FH;
         return $self->verify($pid) ? $pid : 0;
         }
 
 	$self->write(*FH);
 	return 0;
     }
 
 # -- Object oriented Interface -----------------------------------------------
 
 =head1 OO Interface
 
 The following methods are provided:
 
 =head2 new [hash[-ref]]
 
 This method is used to create an instance object.  It automatically calls the I<-E<gt>file()> method described below and receives the same paramters.  For a listing of valid keys in this hash please refer to the aforementioned method documentation below.
 
 In addition to the above, the following constitute valid keys:
 
 =over
 
 =item I<verify> = 1 | string
 
 This parameter implements the second solution outlined in the WARNING section
 of this document and is used to verify that an existing I<pidfile> correctly
 represents a live process other than the current.  If set to a string, it will
 be interpreted as a I<regular expression> and used to search within the name
 of the running process.  Alternatively, a 1 may be passed: For Linux/FreeBSD,
 this indicates that the value of I<$0> will be used (stripped of its full
 path); for Cygwin, I<$^X> (stripped of path and extension) will be used.
 
 If the parameter is not passed, no verification will take place.  Please
 note that verification will only work for the operating systems
 listed below and that the OS will be auto-sensed.  See also DEPENDENCIES
 section below.
 
 Supported platforms: Linux, FreeBSD, Cygwin
 
 =item I<debug>
 
 Any non-zero value turns debugging output on.  Additionally, if a string
 is passed containing the character B<M>, the module name will be prefixed
 to the debugging output.
 
 =back
 
 =cut
 
 sub new {
 	my $class = shift;
 	my $self = bless({}, $class);
 	%$self = &args;
 	$self->file();	# init file path
 	$self->{debug} ||= "";
 	return $self;
 	}
 
 =head2 file [hash[-ref]]
 
 Use this method to set the path of the I<pidfile>.  The method receives an optional hash (or hash reference) with the keys listed below, from which it makes a path of the format: F<$dir/$name.pid>.
 
 =over
 
 =item I<dir>
 
 Specifies the directory to place the pid file.  If left unspecified,
 defaults to F</var/run>.
 
 =item I<name>
 
 Indicates the name of the current process.  When not specified, defaults
 to I<basename($0)>.
 
 =back
 
 =cut
 
 sub file {
 	my $self = shift;
 	%$self = (%$self, &args);
 	$self->{dir} ||= $RUNDIR;
 	$self->{name} ||= $ME;
 	$self->{path} = sprintf("%s/%s.pid", $self->{dir}, $self->{name});
 	}
 
 =head2 alive
 
 Returns true when the process is already running.  Please note that this
 call must be made *after* daemonisation i.e. subsequent to the call to
 fork(). If the B<verify> flag was set during the instance creation, the
 process id is verified, alternatively the flag may be passed directly
 to this method.
 
 =cut
 
 sub alive {
 	my $self = shift;
 
 	my %args = &args;
 	$self->{verify} = $args{verify} if $args{verify};
 
 	my $pid = $self->read() || "";
 	$self->debug("alive(): $pid");
 
 	if ($pid && $pid != $$ && kill(0, $pid)) {
         return $self->verify($pid) ? $pid : 0;
         }
 
 	return 0;
 	}
 
 =head2 touch
 
 Causes for the current process id to be written to the I<pidfile>.
 
 =cut
 
 sub touch {
 	shift->write();
 	}
 
 =head2 release
 
 This method is used to delete the I<pidfile> and is automatically called by DESTROY method.  It should thus be unnecessary to call it directly.
 
 =cut
 
 sub release {
 	my $self = shift;
 	$self->debug("release()");
 	unlink($self->{path}) || warn $!;
 	}
 
 =head2 locktime [hash[-ref]]
 
 This method returns the I<mtime> of the I<pidfile>.
 
 =cut
 
 sub locktime {
     my $self = shift;
     return (stat($self->{path}))[10];
 	}
 
 # -- support functionality ---------------------------------------------------
 
 sub verify {
     my ($self, $pid) = @_;
     return 1 unless $self->{verify};
 
 	my $ret = 0;
     $self->debug("verify(): OS = $^O");
     if ($^O =~ /linux|freebsd|cygwin/i) {
         my $me = $self->{verify};
 		if (!$me || $me eq "1") {
 			$me = $ME;
 			if ($^O eq "cygwin") {
 				$^X =~ m|([^/]+)$|;
 				($me = $1) =~ s/\.exe$//;
 				}
 			}
 		my $cols = delete($ENV{'COLUMNS'}); # prevents `ps` from wrapping
         my @ps = split m|$/|, qx/ps -fp $pid/
             || die "ps utility not available: $!";
         s/^\s+// for @ps;   # leading spaces confuse us
 
 		$ENV{'COLUMNS'} = $cols if defined($cols);
         no warnings;    # hate that deprecated @_ thing
         my $n = split(/\s+/, $ps[0]);
         @ps = split /\s+/, $ps[1], $n;
         $ret = $ps[$n - 1] =~ /\Q$me\E/;;
         }
 
 	$self->debug(" - ret: [$ret]");
 	$ret;
     }
 
 # Returns the process id currently stored in the file set.  If the method
 # is passed a file handle, it will return the value, leaving the file handle
 # locked.  This is useful for atomic operations where the caller needs to
 # write to the file after the read without allowing other dirty writes.
 # 
 # Please note, when passing a file handle, caller is responsible for
 # closing it. Also, file handles must be passed by reference!
 
 sub read {
 	my ($self, $fh) = @_;
 
 	sysopen $fh, $self->{path}, O_RDWR|O_CREAT
 		|| die qq/Cannot open pid file "$self->{path}": $!\n/;
 	flock($fh, LOCK_EX | LOCK_NB)
         || die qq/pid "$self->{path}" already locked: $!\n/;
 	my ($pid) = <$fh> =~ /^(\d+)/;
 	close $fh if @_ == 1;
 
 	$self->debug("read(\"$self->{path}\") = " . ($pid || ""));
 	return $pid;
 	}
 
 # Causes for the current process id to be written to the selected
 # file.  If a file handle it passed, the method assumes it has already
 # been opened, otherwise it opens its own. Please note that file
 # handles must be passed by reference!
 
 sub write {
 	my ($self, $fh) = @_;
 
 	$self->debug("write($$)");
 	if (@_ == 1) {
 		sysopen $fh, $self->{path}, O_RDWR|O_CREAT
 			|| die qq/Cannot open pid file "$self->{path}": $!\n/;
 		flock($fh, LOCK_EX | LOCK_NB)
         	|| die qq/pid "$self->{path}" already locked: $!\n/;
 		}
 	sysseek  $fh, 0, 0;
 	truncate $fh, 0;
 	syswrite $fh, "$$\n", length("$$\n");
 	close $fh || die qq/Cannot write pid file "$self->{path}": $!\n/;
 	}
 
 sub args {
 	!defined($_[0]) ? () : ref($_[0]) ? %{$_[0]} : @_;
 	}
 
 sub debug {
 	my $self = shift;
 	my $msg = shift || $_;
 
 	$msg = "> Proc::PID::File - $msg"
 		if $self->{debug} =~ /M/;	# prefix with module name
 	print $msg
 		if $self->{debug};
 	}
 
 sub DESTROY {
 	my $self = shift;
 
     if (exists($INC{'threads.pm'})) {
         return if threads->tid() != 0;
     	}
     
 	my $pid = $self->read();
 	$self->release()
         if $self->{path} && $pid && $pid == $$;
 	}
 
 1;
 
 __END__
 
 # -- documentation -----------------------------------------------------------
 
 =head1 AUTHOR
 
 Erick Calder <ecalder@cpan.org>
 
 =head1 ACKNOWLEDGEMENTS
 
 1k thx to Steven Haryanto <steven@haryan.to> whose package (Proc::RID_File) inspired this implementation.
 
 Our gratitude also to Alan Ferrency <alan@pair.com> for fingering the boot-up problem and suggesting possible solutions.
 
 =head1 DEPENDENCIES
 
 For Linux, FreeBSD and Cygwin, support of the I<verify> option requires
 availability of the B<ps> utility.  For Linux/FreeBSD This is typically
 found in the B<procps> package. Cygwin users need to run version 1.5.20
 or later for this to work.
 
 =head1 WARNING
 
 This module may prevent daemons from starting at system boot time.  The problem occurs because the process id written to the I<pidfile> by an instance of the daemon may coincidentally be reused by another process after a system restart, thus making the daemon think it's already running.
 
 Some ideas on how to fix this problem are catalogued below, but unfortunately, no platform-independent solutions have yet been gleaned.
 
 =over
 
 =item - leaving the I<pidfile> open for the duration of the daemon's life
 
 =item - checking a C<ps> to make sure the pid is what one expects (current implementation)
 
 =item - looking at /proc/$PID/stat for a process name
 
 =item - check mtime of the pidfile versus uptime; don't trust old pidfiles
 
 =item - try to get the script to nuke its pidfile when it exits (this is vulnerable to hardware resets and hard reboots)
 
 =item - try to nuke the pidfile at boot time before the script runs; this solution suffers from a race condition wherein two instances read the I<pidfile> before one manages to lock it, thus allowing two instances to run simultaneously.
 
 =back
 
 =head1 SUPPORT
 
 For help and thank you notes, e-mail the author directly.  To report a bug, submit a patch or add to our wishlist please visit the CPAN bug manager at: F<http://rt.cpan.org>
 
 =head1 AVAILABILITY
 
 The latest version of the tarball, RPM and SRPM may always be found at: F<http://perl.arix.com/>  Additionally the module is available from CPAN.
 
 =head1 LICENCE
 
 This utility is free and distributed under GPL, the Gnu Public License.  A copy of this license was included in a file called LICENSE. If for some reason, this file was not included, please see F<http://www.gnu.org/licenses/> to obtain a copy of this license.
 
 $Id: File.pm,v 1.16 2004-04-08 02:27:25 ekkis Exp $
### Progress/Any.pm ###
 package Progress::Any;
 
 our $DATE = '2015-01-27'; # DATE
 our $VERSION = '0.20'; # VERSION
 
 use 5.010001;
 use strict;
 use warnings;
 
 use Time::Duration qw();
 use Time::HiRes qw(time);
 
 sub import {
     my ($self, @args) = @_;
     my $caller = caller();
     for (@args) {
         if ($_ eq '$progress') {
             my $progress = $self->get_indicator(task => '');
             {
                 no strict 'refs';
                 my $v = "$caller\::progress";
                 *$v = \$progress;
             }
         } else {
             die "Unknown import argument: $_";
         }
     }
 }
 
 # store Progress::Any objects for each task
 our %indicators;  # key = task name
 
 # store output objects
 our %outputs;     # key = task name, value = [$outputobj, ...]
 
 # store settings/data for each object
 our %output_data; # key = "$output_object", value = {key=>val, ...}
 
 # internal attributes:
 # - _elapsed (float*) = accumulated elapsed time so far
 # - _start_time (float) = when is the last time the indicator state is changed
 #     from 'stopped' to 'started'. when indicator is changed from 'started' to
 #     'stopped', this will be set to undef.
 # - _remaining = used to store user's estimation of remaining time. will be
 #     unset after each update().
 
 # return 1 if created, 0 if already created/initialized
 sub _init_indicator {
     my ($class, $task) = @_;
 
     #say "D: _init_indicator($task)";
 
     # prevent double initialization
     return $indicators{$task} if $indicators{$task};
 
     my $progress = bless({
         task        => $task,
         title       => $task,
         target      => 0,
         pos         => 0,
         state       => 'stopped',
 
         _remaining          => undef,
         _set_remaining_time => undef,
         _elapsed            => 0,
         _start_time         => 0,
     }, $class);
     $indicators{$task} = $progress;
 
     # if we create an indicator named a.b.c, we must also create a.b, a, and ''.
     if ($task =~ s/\.?\w+\z//) {
         $class->_init_indicator($task);
     }
 
     $progress;
 }
 
 sub get_indicator {
     my ($class, %args) = @_;
 
     my %oargs = %args;
 
     my $task   = delete($args{task});
     if (!defined($task)) {
         my @caller = caller(0);
         #say "D:caller=".join(",",map{$_//""} @caller);
         $task = $caller[0] eq '(eval)' ? 'main' : $caller[0];
         $task =~ s/::/./g;
         $task =~ s/[^.\w]+/_/g;
     }
     die "Invalid task syntax '$task', please only use dotted words"
         unless $task =~ /\A(?:\w+(\.\w+)*)?\z/;
 
     my %uargs;
 
     my $p = $class->_init_indicator($task);
     for my $an (qw/title target pos remaining state/) {
         if (exists $args{$an}) {
             $uargs{$an} = delete($args{$an});
         }
     }
     die "Unknown argument(s) to get_indicator(): ".join(", ", keys(%args))
         if keys(%args);
     $p->_update(%uargs) if keys %uargs;
 
     $p;
 }
 
 my %attrs = (
     title     => {is => 'rw'},
     target    => {is => 'rw'},
     pos       => {is => 'rw'},
     state     => {is => 'rw'},
 );
 
 # create attribute methods
 for my $an (keys %attrs) {
     next if $attrs{$an}{manual};
     my $code;
     if ($attrs{$an}{is} eq 'rw') {
         $code = sub {
             my $self = shift;
             if (@_) {
                 $self->_update($an => shift);
             }
             $self->{$an};
         };
     } else {
         $code = sub {
             my $self = shift;
             die "Can't set value, $an is an ro attribute" if @_;
             $self->{$an};
         };
     }
     no strict 'refs';
     *{$an} = $code;
 }
 
 sub elapsed {
     my $self = shift;
 
     if ($self->{state} eq 'started') {
         return $self->{_elapsed} + (time()-$self->{_start_time});
     } else {
         return $self->{_elapsed};
     }
 }
 
 sub total_pos {
     my $self = shift;
 
     my $t = $self->{task};
 
     my $res = $self->{pos};
     for (keys %indicators) {
         if ($t eq '') {
             next if $_ eq '';
         } else {
             next unless index($_, "$t.") == 0;
         }
         $res += $indicators{$_}{pos};
     }
     $res;
 }
 
 sub total_target {
     my $self = shift;
 
     my $t = $self->{task};
 
     my $res = $self->{target};
     return undef unless defined($res);
 
     for (keys %indicators) {
         if ($t eq '') {
             next if $_ eq '';
         } else {
             next unless index($_, "$t.") == 0;
         }
         return undef unless defined $indicators{$_}{target};
         $res += $indicators{$_}{target};
     }
     $res;
 }
 
 sub percent_complete {
     my $self = shift;
 
     my $total_pos    = $self->total_pos;
     my $total_target = $self->total_target;
 
     return undef unless defined($total_target);
     if ($total_target == 0) {
         if ($self->{state} eq 'finished') {
             return 100;
         } else {
             return 0;
         }
     } else {
         return $total_pos / $total_target * 100;
     }
 }
 
 sub remaining {
     my $self = shift;
 
     if (defined $self->{_remaining}) {
         if ($self->{state} eq 'started') {
             my $r = $self->{_remaining}-(time()-$self->{_set_remaining_time});
             return $r > 0 ? $r : 0;
         } else {
             return $self->{_remaining};
         }
     } else {
         if (defined $self->{target}) {
             if ($self->{pos} == 0) {
                 return 0;
             } else {
                 return ($self->{target} - $self->{pos})/$self->{pos} *
                     $self->elapsed;
             }
         } else {
             return undef;
         }
     }
 }
 
 sub total_remaining {
     my $self = shift;
 
     my $t = $self->{task};
 
     my $res = $self->remaining;
     return undef unless defined $res;
 
     for (keys %indicators) {
         if ($t eq '') {
             next if $_ eq '';
         } else {
             next unless index($_, "$t.") == 0;
         }
         my $res2 = $indicators{$_}->remaining;
         return undef unless defined $res2;
         $res += $res2;
     }
     $res;
 }
 
 # the routine to use to update rw attributes, does validation and checks to make
 # sure things are consistent.
 sub _update {
     my ($self, %args) = @_;
 
     # no need to check for unknown arg in %args, it's an internal method anyway
 
     my $now = time();
 
     my $task = $self->{task};
     #use Data::Dump; print "D: _update($task) "; dd \%args;
 
   SET_TITLE:
     {
         last unless exists $args{title};
         my $val = $args{title};
         die "Invalid value for title, must be defined"
             unless defined($val);
         $self->{title} = $val;
     }
 
   SET_TARGET:
     {
         last unless exists $args{target};
         my $val = $args{target};
         die "Invalid value for target, must be a positive number or undef"
             unless !defined($val) || $val >= 0;
         # ensure that pos does not exceed target
         if (defined($val) && $self->{pos} > $val) {
             $self->{pos} = $val;
         }
         $self->{target} = $val;
         undef $self->{_remaining};
     }
 
   SET_POS:
     {
         last unless exists $args{pos};
         my $val = $args{pos};
         die "Invalid value for pos, must be a positive number"
             unless defined($val) && $val >= 0;
         # ensure that pos does not exceed target
         if (defined($self->{target}) && $val > $self->{target}) {
             $val = $self->{target};
         }
         $self->{pos} = $val;
         undef $self->{_remaining};
     }
 
   SET_REMAINING:
     {
         last unless exists $args{remaining};
         my $val = $args{remaining};
         die "Invalid value for remaining, must be a positive number"
             unless defined($val) && $val >= 0;
         $self->{_remaining} = $val;
         $self->{_set_remaining_time} = $now;
     }
 
   SET_STATE:
     {
         last unless exists $args{state};
         my $old = $self->{state};
         my $val = $args{state} // 'started';
         die "Invalid value for state, must be stopped/started/finished"
             unless $val =~ /\A(?:stopped|started|finished)\z/;
         last if $old eq $val;
         if ($val eq 'started') {
             $self->{_start_time} = $now;
 
             # automatically start parents
             my @parents;
             {
                 my $t = $task;
                 while (1) {
                     last unless $t =~ s/\.\w+\z//;
                     push @parents, $t;
                 }
                 push @parents, '';
             }
             for my $t (@parents) {
                 my $p = $indicators{$t};
                 if ($p->{state} ne 'started') {
                     $p->{state}       = 'started';
                     $p->{_start_time} = $now;
                 }
             }
         } else {
             $self->{_elapsed} += $now - $self->{_start_time};
             if ($val eq 'finished') {
                 die "BUG: Can't finish task '$task', pos is still < target"
                     if defined($self->{target}) &&
                         $self->{pos} < $self->{target};
                 $self->{_remaining} = 0;
                 $self->{_set_remaining_time} = $now;
             }
         }
         $self->{state} = $val;
     }
 
   DONE:
     #use Data::Dump; print "after update: "; dd $self;
     return;
 }
 
 sub _should_update_output {
     my ($self, $output, $now) = @_;
 
     my $key = "$output";
     $output_data{$key} //= {};
     my $odata = $output_data{$key};
     if (!defined($odata->{mtime})) {
         # output has never been updated, update
         return 1;
     } elsif ($self->{state} eq 'finished') {
         # finishing, update the output to show finished state
         return 1;
     } elsif ($odata->{force_update}) {
         # force update
         delete $odata->{force_update};
         return 1;
     # } elsif ($args->{prio} eq 'low') {
         # perhaps provide something like this? a low-priority or minor update so
         # we don't have to update the outputs?
     } else {
         # normal update, update if not too frequent
         if (!defined($odata->{freq})) {
             # negative number means seconds, positive means pos delta. only
             # update if that number of seconds, or that difference in pos has
             # been passed.
             $odata->{freq} = -0.5;
         }
         if ($odata->{freq} < 0) {
             return 1 if $now >= $odata->{mtime} - $odata->{freq};
         } else {
             return 1 if abs($self->{pos} - $odata->{pos}) >= $odata->{freq};
         }
         return 0;
     }
 }
 
 sub update {
     my ($self, %args) = @_;
 
     my $pos   = delete($args{pos}) // $self->{pos} + 1;
     my $state = delete($args{state}) // 'started';
     $self->_update(pos => $pos, state => $state);
 
     my $message  = delete($args{message});
     my $level    = delete($args{level});
     die "Unknown argument(s) to update(): ".join(", ", keys(%args))
         if keys(%args);
 
     my $now = time();
 
     # find output(s) and call it
     {
         my $task = $self->{task};
         while (1) {
             if ($outputs{$task}) {
                 for my $output (@{ $outputs{$task} }) {
                     next unless $self->_should_update_output($output, $now);
                     if (ref($message) eq 'CODE') {
                         $message = $message->();
                     }
                     $output->update(
                         indicator => $indicators{$task},
                         message   => $message,
                         level     => $level,
                         time      => $now,
                     );
                     my $key = "$output";
                     $output_data{$key}{mtime} = $now;
                     $output_data{$key}{pos}   = $pos;
                 }
             }
             last unless $task =~ s/\.?\w+\z//;
         }
     }
 }
 
 sub start {
     my $self = shift;
     $self->_update(state => 'started');
 }
 
 sub stop {
     my $self = shift;
     $self->_update(state => 'stopped');
 }
 
 sub finish {
     my ($self, %args) = @_;
     $self->update(pos=>$self->{target}, state=>'finished', %args);
 }
 
 # - currently used letters: emnPpRrTt%
 # - currently used by Output::TermProgressBarColor: bB
 # - letters that can be used later: s (state)
 sub fill_template {
     my ($self, $template, %args) = @_;
 
     # TODO: some caching so "%e%e" produces two identical numbers
 
     state $re = qr{( # all=1
                        %
                        ( #width=2
                            -?\d+ )?
                        ( #dot=3
                            \.?)
                        ( #prec=4
                            \d+)?
                        ( #conv=5
                            [emnPpRrTt%])
                    )}x;
 
     state $sub = sub {
         my %args = @_;
 
         my ($all, $width, $dot, $prec, $conv) = ($1, $2, $3, $4, $5);
 
         my $p = $args{indicator};
 
         my ($fmt, $sconv, $data);
         if ($conv eq 'n') {
             $data = $p->{task};
         } elsif ($conv eq 't') {
             $data = $p->{title};
         } elsif ($conv eq '%') {
             $data = '%';
         } elsif ($conv eq 'm') {
             $data = $args{message} // '';
         } elsif ($conv eq 'p') {
             my $val = $p->percent_complete;
             $width //= 3;
             if (defined $val) {
                 $data = $val;
                 $prec //= 0;
                 $sconv = "f";
             } else {
                 $data = '?';
             }
         } elsif ($conv eq 'P') {
             $data = $p->total_pos;
             $prec //= 0;
             $sconv = "f";
         } elsif ($conv eq 'T') {
             my $val = $p->total_target;
             if (defined $val) {
                 $data = $val;
                 $prec //= 0;
                 $sconv = "f";
             } else {
                 $data = '?';
             }
         } elsif ($conv eq 'e') {
             my $val = $p->elapsed;
             $val = 1 if $val < 1; # TMP, prevent duration() return "just now"
             $data = Time::Duration::concise(Time::Duration::duration($val));
             $width //= -8;
         } elsif ($conv eq 'r') {
             my $val = $p->total_remaining;
             if (defined $val) {
                 $val = 1 if $val < 1; # TMP, prevent duration() return "just now
                 $data = Time::Duration::concise(Time::Duration::duration($val));
             } else {
                 $data = '?';
             }
             $width //= -8;
         } elsif ($conv eq 'R') {
             my $val = $p->total_remaining;
             if (defined $val) {
                 $val = 1 if $val < 1; # TMP, prevent duration() return "just now
                 $data = Time::Duration::concise(Time::Duration::duration($val)).
                     " left"; # XXX i18n
             } else {
                 $val = $p->elapsed;
                 $val = 1 if $val < 1; # TMP, prevent duration() return "just now
                 $data = Time::Duration::concise(Time::Duration::duration($val)).
                     " elapsed"; # XXX i18n
             }
             $width //= -(8 + 1 + 7);
         } else {
             # return as-is
             $fmt = '%s';
             $data = $all;
         }
 
         # sprintf format
         $sconv //= 's';
         $dot = "." if $sconv eq 'f';
         $fmt //= join("", grep {defined} ("%", $width, $dot, $prec, $sconv));
 
         #say "D:fmt=$fmt";
         sprintf $fmt, $data;
 
     };
     $template =~ s{$re}{$sub->(%args, indicator=>$self)}egox;
 
     $template;
 }
 
 1;
 # ABSTRACT: Record progress to any output
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Progress::Any - Record progress to any output
 
 =head1 VERSION
 
 This document describes version 0.20 of Progress::Any (from Perl distribution Progress-Any), released on 2015-01-27.
 
 =head1 SYNOPSIS
 
 =head2 First example, simple usage in a script
 
  use Progress::Any '$progress';
  use Progress::Any::Output 'TermProgressBarColor';
 
  $progress->target(10);
  for (1..10) {
      $progress->update(message => "Doing item $_");
      sleep 1;
  }
 
 Sample output:
 
  % ./script.pl
   60% [Doing item 6====           ]3s left
 
 =head2 Second example, usage in module as well as script
 
 In your module:
 
  package MyApp;
  use Progress::Any;
 
  sub download {
      my @urls = @_;
      return unless @urls;
      my $progress = Progress::Any->get_indicator(
          task => "download", pos=>0, target=>~~@urls);
      for my $url (@urls) {
          # download the $url ...
          $progress->update(message => "Downloaded $url");
      }
      $progress->finish;
  }
 
 In your application:
 
  use MyApp;
  use Progress::Any::Output;
  Progress::Any::Output->set('TermProgressBarColor');
 
  MyApp::download("url1", "url2", "url3", "url4", "url5");
 
 sample output, in succession:
 
  % ./script.pl
   20% [====== Downloaded url1           ]0m00s Left
   40% [=======Downloaded url2           ]0m01s Left
   60% [=======Downloaded url3           ]0m01s Left
   80% [=======Downloaded url4==         ]0m00s Left
 
 (At 100%, the output automatically cleans up the progress bar).
 
 =head3 Another example, demonstrating multiple indicators and the LogAny output:
 
  use Progress::Any;
  use Progress::Any::Output;
  use Log::Any::App;
 
  Progress::Any::Output->set('LogAny', template => '[%-8t] [%P/%2T] %m');
  my $pdl = Progress::Any->get_indicator(task => 'download');
  my $pcp = Progress::Any->get_indicator(task => 'copy');
 
  $pdl->pos(10);
  $pdl->target(10);
  $pdl->update(message => "downloading A");
  $pcp->update(message => "copying A");
  $pdl->update(message => "downloading B");
  $pcp->update(message => "copying B");
 
 will show something like:
 
  [download] [1/10] downloading A
  [copy    ] [1/ ?] copying A
  [download] [2/10] downloading B
  [copy    ] [2/ ?] copying B
 
 =head2 Example of using with Perinci::CmdLine
 
 If you use L<Perinci::CmdLine>, you can mark your function as expecting a
 Progress::Any object and it will be supplied to you in a special argument
 C<-progress>:
 
  use File::chdir;
  use Perinci::CmdLine;
  $SPEC{check_dir} = {
      v => 1.1,
      args => {
          dir => {summary=>"Path to check", schema=>"str*", req=>1, pos=>0},
      },
      features => {progress=>1},
  };
  sub check_dir {
      my %args = @_;
      my $progress = $args{-progress};
      my $dir = $args{dir};
      (-d $dir) or return [412, "No such dir: $dir"];
      local $CWD = $dir;
      opendir my($dh), $dir;
      my @ent = readdir($dh);
      $progress->pos(0);
      $progress->target(~~@ent);
      for (@ent) {
          # do the check ...
          $progress->update(message => $_);
          sleep 1;
      }
      $progress->finish;
      [200];
  }
  Perinci::CmdLine->new(url => '/main/check_dir')->run;
 
 =head1 DESCRIPTION
 
 C<Progress::Any> is an interface for applications that want to display progress
 to users. It decouples progress updating and output, rather similar to how
 L<Log::Any> decouples log producers and consumers (output). The API is also
 rather similar to Log::Any, except I<Adapter> is called I<Output> and
 I<category> is called I<task>.
 
 Progress::Any records position/target and calculates elapsed time, estimated
 remaining time, and percentage of completion. One or more output modules
 (Progress::Any::Output::*) display this information.
 
 In your modules, you typically only need to use Progress::Any, get one or more
 indicators, set target and update it during work. In your application, you use
 Progress::Any::Output and set/add one or more outputs to display the progress.
 By setting output only in the application and not in modules, you separate the
 formatting/display concern from the logic.
 
 Screenshots:
 
 =head1 STATUS
 
 API might still change, will be stabilized in 1.0.
 
 =begin HTML
 
 <p><img src="http://blogs.perl.org/users/perlancar/progany-tpc-sample.jpg" /><br />Using TermProgressBarColor output
 
 <p><img src="http://blogs.perl.org/users/perlancar/progany-dn-sample.jpg" /><br />Using DesktopNotify output
 
 =end HTML
 
 The list of features:
 
 =over 4
 
 =item * multiple progress indicators
 
 You can use different indicator for each task/subtask.
 
 =item * customizable output
 
 Output is handled by one of C<Progress::Any::Output::*> modules. Currently
 available outputs: C<Null> (no output), C<TermMessage> (display as simple
 message on terminal), C<TermProgressBarColor> (display as color progress bar on
 terminal), C<LogAny> (log using L<Log::Any>), C<Callback> (call a subroutine).
 Other possible output ideas: IM/Twitter/SMS, GUI, web/AJAX, remote/RPC (over
 L<Riap> for example, so that L<Perinci::CmdLine>-based command-line clients can
 display progress update from remote functions).
 
 =item * multiple outputs
 
 One or more outputs can be used to display one or more indicators.
 
 =item * hierarchical progress
 
 A task can be divided into subtasks. If a subtask is updated, its parent task
 (and its parent, and so on) are also updated proportionally.
 
 =item * message
 
 Aside from setting a number/percentage, allow including a message when updating
 indicator.
 
 =item * undefined target
 
 Target can be undefined, so a bar output might not show any bar (or show them,
 but without percentage indicator), but can still show messages.
 
 =item * retargetting
 
 Target can be changed in the middle of things.
 
 =back
 
 =head1 EXPORTS
 
 =head2 $progress => OBJ
 
 The root indicator. Equivalent to:
 
  Progress::Any->get_indicator(task => '')
 
 =head1 ATTRIBUTES
 
 Below are the attributes of an indicator/task:
 
 =head2 task => STR* (default: from caller's package, or C<main>)
 
 Task name. If not specified will be set to caller's package (C<::> will be
 replaced with C<.>), e.g. if you are calling this method from
 C<Foo::Bar::baz()>, then task will be set to C<Foo.Bar>. If caller is code
 inside eval, C<main> will be used instead.
 
 =head2 title => STR* (default: task name)
 
 Specify task title. Task title is a longer description for a task and can
 contain spaces and other characters. It is displayed in some outputs, as well as
 using C<%t> in C<fill_template()>. For example, for a task called C<copy>, its
 title might be C<Copying files to remote server>.
 
 =head2 target => POSNUM (default: 0)
 
 The total number of items to finish. Can be set to undef to mean that we don't
 know (yet) how many items there are to finish (in which case, we cannot estimate
 percent of completion and remaining time).
 
 =head2 pos => POSNUM* (default: 0)
 
 The number of items that are already done. It cannot be larger than C<target>,
 if C<target> is defined. If C<target> is set to a value smaller than C<pos> or
 C<pos> is set to a value larger than C<target>, C<pos> will be changed to be
 C<target>.
 
 =head2 state => STR (default: C<stopped>)
 
 State of task/indicator. Either: C<stopped>, C<started>, or C<finished>.
 Initially it will be set to C<stopped>, which means elapsed time won't be
 running and will stay at 0. C<update()> will set the state to C<started> to get
 elapsed time to run. At the end of task, you can call C<finish()> (or
 alternatively set C<state> to C<finished>) to stop the elapsed time again.
 
 The difference between C<stopped> and C<finished> is: when C<target> and C<pos>
 are both at 0, percent completed is assumed to be 0% when state is C<stopped>,
 but 100% when state is C<finished>.
 
 =head1 METHODS
 
 =head2 Progress::Any->get_indicator(%args) => OBJ
 
 Get a progress indicator for a certain task. C<%args> contain attribute values,
 at least C<task> must be specified.
 
 Note that this module maintains a list of indicator singleton objects for each
 task (in C<%indicators> package variable), so subsequent C<get_indicator()> for
 the same task will return the same object.
 
 =head2 $progress->update(%args)
 
 Update indicator. Will also, usually, update associated output(s) if necessary.
 
 Arguments:
 
 =over 4
 
 =item * pos => NUM
 
 Set the new position. If unspecified, defaults to current position + 1. If pos
 is larger than target, outputs will generally still show 100%. Note that
 fractions are allowed.
 
 =item * message => str|code
 
 Set a message to be displayed when updating indicator.
 
 Aside from a string, you can also pass a coderef here. It can be used to delay
 costly calculation. The message will only be calculated when actually sent to
 output.
 
 =item * level => NUM
 
 EXPERIMENTAL, NOT YET IMPLEMENTED BY MOST OUTPUTS. Setting the importance level
 of this update. Default is C<normal> (or C<low> for fractional update), but can
 be set to C<high> or C<low>. Output can choose to ignore updates lower than a
 certain level.
 
 =item * state => STR
 
 Can be set to C<finished> to finish a task.
 
 =back
 
 =head2 $progress->finish(%args)
 
 Equivalent to:
 
  $progress->update(
      ( pos => $progress->target ) x !!defined($progress->target),
      state => 'finished',
      %args,
  );
 
 =head2 $progress->start()
 
 Set state to C<started>.
 
 =head2 $progress->stop()
 
 Set state to C<stopped>.
 
 =head2 $progress->elapsed() => FLOAT
 
 Get elapsed time. Just like a stop-watch, when state is C<started> elapsed time
 will run and when state is C<stopped>, it will freeze.
 
 =head2 $progress->remaining() => undef|FLOAT
 
 Give estimated remaining time until task is finished, which will depend on how
 fast the C<update()> is called, i.e. how fast C<pos> is approaching C<target>.
 Will be undef if C<target> is undef.
 
 =head2 $progress->total_remaining() => undef|FLOAT
 
 Give estimated remaining time added by all its subtasks' remaining. Return undef
 if any one of those time is undef.
 
 =head2 $progress->total_pos() => FLOAT
 
 Total of indicator's pos and all of its subtasks'.
 
 =head2 $progress->total_target() => undef|FLOAT
 
 Total of indicator's target and all of its subtasks'. Return undef if any one of
 those is undef.
 
 =head2 $progress->percent_complete() => undef|FLOAT
 
 Give percentage of completion, calculated using C<< total_pos / total_target *
 100 >>. Undef if total_target is undef.
 
 =head2 $progress->fill_template($template)
 
 Fill template with values, like in C<sprintf()>. Usually used by output modules.
 Available templates:
 
 =over
 
 =item * C<%(width)n>
 
 Task name (the value of the C<task> attribute). C<width> is optional, an
 integer, like in C<sprintf()>, can be negative to mean left-justify instead of
 right.
 
 =item * C<%(width)t>
 
 Task title (the value of the C<title> attribute).
 
 =item * C<%(width)e>
 
 Elapsed time (the result from the C<elapsed()> method). Currently using
 L<Time::Duration> concise format, e.g. 10s, 1m40s, 16m40s, 1d4h, and so on.
 Format might be configurable and localizable in the future. Default width is -8.
 Examples:
 
  2m30s
  10s
 
 =item * C<%(width)r>
 
 Estimated remaining time (the result of the C<total_remaining()> method).
 Currently using L<Time::Duration> concise format, e.g. 10s, 1m40s, 16m40s, 1d4h,
 and so on. Will show C<?> if unknown. Format might be configurable and
 localizable in the future. Default width is -8. Examples:
 
  1m40s
  5s
 
 =item * C<%(width)R>
 
 Estimated remaining time I<or> elapsed time, if estimated remaining time is not
 calculatable (e.g. when target is undefined). Format might be configurable and
 localizable in the future. Default width is -(8+1+7). Examples:
 
  30s left
  1m40s elapsed
 
 =item * C<%(width).(prec)p>
 
 Percentage of completion (the result of the C<percent_complete()> method).
 C<width> and C<precision> are optional, like C<%f> in Perl's C<sprintf()>,
 default is C<%3.0p>. If percentage is unknown (due to target being undef), will
 show C<?>.
 
 =item * C<%(width)P>
 
 Current position (the result of the C<total_pos()> method).
 
 =item * C<%(width)T>
 
 Target (the result of the C<total_target()> method). If undefined, will show
 C<?>.
 
 =item * C<%m>
 
 Message (the C<update()> parameter). If message is unspecified, will show empty
 string.
 
 =item * C<%%>
 
 A literal C<%> sign.
 
 =back
 
 =head1 FAQ
 
 =head1 SEE ALSO
 
 Other progress modules on CPAN: L<Term::ProgressBar>,
 L<Term::ProgressBar::Simple>, L<Time::Progress>, among others.
 
 Output modules: C<Progress::Any::Output::*>
 
 See examples on how Progress::Any is used by other modules: L<Perinci::CmdLine>
 (supplying progress object to functions), L<Git::Bunch> (using progress object).
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Progress-Any>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Progress-Any>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Progress-Any>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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
### Progress/Any/Output.pm ###
 package Progress::Any::Output;
 
 our $DATE = '2015-01-27'; # DATE
 our $VERSION = '0.20'; # VERSION
 
 use 5.010001;
 use strict;
 use warnings;
 
 require Progress::Any;
 
 sub import {
     my $self = shift;
     __PACKAGE__->set(@_) if @_;
 }
 
 sub _set_or_add {
     my $class = shift;
     my $which = shift;
 
     my $opts;
     if (@_ && ref($_[0]) eq 'HASH') {
         $opts = shift;
     } else {
         $opts = {};
     }
 
     my $output = shift or die "Please specify output name";
     $output =~ /\A(?:\w+(::\w+)*)?\z/ or die "Invalid output syntax '$output'";
 
     my $task = $opts->{task} // "";
 
     my $outputo;
     unless (ref $outputo) {
         my $outputpm = $output; $outputpm =~ s!::!/!g; $outputpm .= ".pm";
         require "Progress/Any/Output/$outputpm";
         no strict 'refs';
         $outputo = "Progress::Any::Output::$output"->new(@_);
     }
 
     if ($which eq 'set') {
         $Progress::Any::outputs{$task} = [$outputo];
     } else {
         $Progress::Any::outputs{$task} //= [];
         push @{ $Progress::Any::outputs{$task} }, $outputo;
     }
 
     $outputo;
 }
 
 sub set {
     my $class = shift;
     $class->_set_or_add('set', @_);
 }
 
 sub add {
     my $class = shift;
     $class->_set_or_add('add', @_);
 }
 
 1;
 # ABSTRACT: Assign output to progress indicators
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Progress::Any::Output - Assign output to progress indicators
 
 =head1 VERSION
 
 This document describes version 0.20 of Progress::Any::Output (from Perl distribution Progress-Any), released on 2015-01-27.
 
 =head1 SYNOPSIS
 
 In your application:
 
  use Progress::Any::Output;
  Progress::Any::Output->set('TermProgressBarColor');
 
 or:
 
  use Progress::Any::Output 'TermProgressBarColor';
 
 To give parameters to output:
 
  use Progress::Any::Output;
  Progress::Any::Output->set('TermProgressBarColor', width=>50, ...);
 
 or:
 
  use Progress::Any::Output 'TermProgressBarColor', width=>50, ...;
 
 To assign output to a certain (sub)task:
 
  use Progress::Any::Output;
  Progress::Any::Output->set({task=>'main.download'}, 'TermMessage');
 
 To add additional output, use C<add()> instead of C<set()>.
 
 =head1 DESCRIPTION
 
 See L<Progress::Any> for overview.
 
 =head1 METHODS
 
 =head2 Progress::Any::Output->set([ \%opts ], $output[, @args]) => obj
 
 Set (or replace) output. Will load and instantiate
 C<Progress::Any::Output::$output>. To only set output for a certain (sub)task,
 set C<%opts> to C<< { task => $task } >>. C<@args> will be passed to output
 module's constructor.
 
 Return the instantiated object.
 
 If C<$output> is an object (a reference, really), it will be used as-is.
 
 =head2 Progress::Any::Output->add([ \%opts ], $output[, @args])
 
 Like set(), but will add output instead of replace existing one(s).
 
 =head1 SEE ALSO
 
 L<Progress::Any>
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Progress-Any>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Progress-Any>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Progress-Any>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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
### Progress/Any/Output/Null.pm ###
 package Progress::Any::Output::Null;
 
 use 5.010;
 use strict;
 use warnings;
 
 our $VERSION = '0.20'; # VERSION
 
 sub new {
     my ($class, %args) = @_;
     bless \%args, $class;
 }
 
 sub update {
     1;
 }
 
 1;
 # ABSTRACT: Null output
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Progress::Any::Output::Null - Null output
 
 =head1 VERSION
 
 This document describes version 0.20 of Progress::Any::Output::Null (from Perl distribution Progress-Any), released on 2015-01-27.
 
 =for Pod::Coverage ^(new|update)$
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Progress-Any>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Progress-Any>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Progress-Any>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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
### Progress/Any/Output/TermProgressBarColor.pm ###
 package Progress::Any::Output::TermProgressBarColor;
 
 our $DATE = '2015-08-29'; # DATE
 our $VERSION = '0.21'; # VERSION
 
 use 5.010001;
 use strict;
 use warnings;
 
 use Color::ANSI::Util qw(ansifg ansibg);
 require Win32::Console::ANSI if $^O =~ /Win/;
 
 $|++;
 
 # patch handle
 my ($ph1, $ph2);
 
 sub _patch {
     my $out = shift;
 
     return if $ph1;
     require Monkey::Patch::Action;
     $ph1 = Monkey::Patch::Action::patch_package(
         'Log::Any::Adapter::Screen', 'hook_before_log', 'replace',
         sub {
             $out->cleanup;
             $Progress::Any::output_data{"$out"}{force_update} = 1;
         }
     ) if defined &{"Log::Any::Adapter::Screen::hook_before_log"};
     $ph2 = Monkey::Patch::Action::patch_package(
         'Log::Any::Adapter::Screen', 'hook_after_log', 'replace',
         sub {
             my ($self, $msg) = @_;
             print { $self->{_fh} } "\n" unless $msg =~ /\R\z/;
             $out->keep_delay_showing if $out->{show_delay};
         }
     ) if defined &{"Log::Any::Adapter::Screen::hook_after_log"};
 }
 
 sub _unpatch {
     undef $ph1;
     undef $ph2;
 }
 
 sub new {
     my ($class, %args0) = @_;
 
     my %args;
 
     $args{width} = delete($args0{width});
     if (!defined($args{width})) {
         my ($cols, $rows);
         if ($ENV{COLUMNS}) {
             $cols = $ENV{COLUMNS};
         } elsif (eval { require Term::Size; 1 }) {
             ($cols, $rows) = Term::Size::chars();
         } else {
             $cols = 80;
         }
         # on windows if we print at rightmost column, cursor will move to the
         # next line, so we try to avoid that
         $args{width} = $^O =~ /Win/ ? $cols-1 : $cols;
     }
 
     $args{fh} = delete($args0{fh});
     $args{fh} //= \*STDOUT;
 
     $args{show_delay} = delete($args0{show_delay});
 
     $args{wide} = delete($args0{wide});
 
     keys(%args0) and die "Unknown output parameter(s): ".
         join(", ", keys(%args0));
 
     $args{_last_hide_time} = time();
 
     require Text::ANSI::NonWideUtil;
     if ($args{wide}) {
         require Text::ANSI::WideUtil;
     }
 
     my $self = bless \%args, $class;
     $self->_patch;
     $self;
 }
 
 sub update {
     my ($self, %args) = @_;
 
     my $now = time();
 
     # if there is show_delay, don't display until we've surpassed it
     if (defined $self->{show_delay}) {
         return if $now - $self->{show_delay} < $self->{_last_hide_time};
     }
 
     # "erase" previous display
     my $ll = $self->{_lastlen};
     if (defined $self->{_lastlen}) {
         print { $self->{fh} } "\b" x $self->{_lastlen};
         undef $self->{_lastlen};
     }
 
     my $p = $args{indicator};
     my $tottgt = $p->total_target;
     my $totpos = $p->total_pos;
     my $is_complete = $p->{state} eq 'finished' ||
         defined($tottgt) && $tottgt > 0 && $totpos == $tottgt;
     if ($is_complete) {
         if ($ll) {
             my $fh = $self->{fh};
             print $fh " " x $ll, "\b" x $ll;
             $self->{_last_hide_time} = $now;
         }
         return;
     }
 
     # XXX follow 'template'
     my $bar;
     my $bar_pct = $p->fill_template("%p%% ", %args);
 
     my $bar_eta = $p->fill_template("%R", %args);
 
     my $bar_bar = "";
     my $bwidth = $self->{width} - length($bar_pct) - length($bar_eta) - 2;
     if ($bwidth > 0) {
         if ($tottgt) {
             my $bfilled = int($totpos / $tottgt * $bwidth);
             $bfilled = $bwidth if $bfilled > $bwidth;
             $bar_bar = ("=" x $bfilled) . (" " x ($bwidth-$bfilled));
 
             my $message = $args{message};
         } else {
             # display 15% width of bar just moving right
             my $bfilled = int(0.15 * $bwidth);
             $bfilled = 1 if $bfilled < 1;
             $self->{_x}++;
             if ($self->{_x} > $bwidth-$bfilled) {
                 $self->{_x} = 0;
             }
             $bar_bar = (" " x $self->{_x}) . ("=" x $bfilled) .
                 (" " x ($bwidth-$self->{_x}-$bfilled));
         }
 
         my $msg = $args{message};
         if (defined $msg) {
             if ($msg =~ m!</elspan!) {
                 require String::Elide::Parts;
                 $msg = String::Elide::Parts::elide($msg, $bwidth);
             }
             my $mwidth;
             if ($self->{wide}) {
                 $msg = Text::ANSI::WideUtil::ta_mbtrunc($msg, $bwidth);
                 $mwidth = Text::ANSI::WideUtil::ta_mbswidth($msg);
             } else {
                 $msg = Text::ANSI::NonWideUtil::ta_trunc($msg, $bwidth);
                 $mwidth = Text::ANSI::NonWideUtil::ta_length($msg);
             }
             $bar_bar = ansifg("808080") . $msg . ansifg("ff8000") .
                 substr($bar_bar, $mwidth);
         }
 
         $bar_bar = ansifg("ff8000") . $bar_bar;
     }
 
     $bar = join(
         "",
         ansifg("ffff00"), $bar_pct,
         "[$bar_bar]",
         ansifg("ffff00"), $bar_eta,
         "\e[0m",
     );
     print { $self->{fh} } $bar;
 
     $self->{_lastlen} = Text::ANSI::NonWideUtil::ta_length($bar);
 }
 
 sub cleanup {
     my ($self) = @_;
 
     # sometimes (e.g. when a subtask's target is undefined) we don't get
     # state=finished at the end. but we need to cleanup anyway at the end of
     # app, so this method is provided and will be called by e.g.
     # Perinci::CmdLine
 
     my $ll = $self->{_lastlen};
     return unless $ll;
     print { $self->{fh} } "\b" x $ll, " " x $ll, "\b" x $ll;
 }
 
 sub keep_delay_showing {
     my $self = shift;
 
     $self->{_last_hide_time} = time();
 }
 
 sub DESTROY {
     my $self = shift;
     $self->_unpatch;
 }
 
 1;
 # ABSTRACT: Output progress to terminal as color bar
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Progress::Any::Output::TermProgressBarColor - Output progress to terminal as color bar
 
 =head1 VERSION
 
 This document describes version 0.21 of Progress::Any::Output::TermProgressBarColor (from Perl distribution Progress-Any-Output-TermProgressBarColor), released on 2015-08-29.
 
 =head1 SYNOPSIS
 
  use Progress::Any::Output;
 
  # use default options
  Progress::Any::Output->set('TermProgressBarColor');
 
  # set options
  Progress::Any::Output->set('TermProgressBarColor',
                             width=>50, fh=>\*STDERR, show_delay=>5);
 
 =head1 DESCRIPTION
 
 B<THIS IS AN EARLY RELEASE, SOME THINGS ARE NOT YET IMPLEMENTED E.G. TEMPLATE,
 STYLES, COLOR THEMES>.
 
 Sample screenshots:
 
 =for Pod::Coverage ^(update|cleanup)$
 
 =for HTML <img src="http://blogs.perl.org/users/perlancar/progany-tpc-sample.jpg" />
 
 This output displays progress indicators as colored progress bar on terminal. It
 produces output similar to that produced by L<Term::ProgressBar>, except that it
 uses the L<Progress::Any> framework and has additional features:
 
 =over
 
 =item * colors and color themes
 
 =item * template and styles
 
 =item * displaying message text in addition to bar/percentage number
 
 =item * wide character support
 
 =back
 
 XXX option to cleanup when complete or not (like in Term::ProgressBar) and
 should default to 1.
 
 =head1 METHODS
 
 =head2 new(%args) => OBJ
 
 Instantiate. Usually called through C<<
 Progress::Any::Output->set("TermProgressBarColor", %args) >>.
 
 Known arguments:
 
 =over
 
 =item * wide => bool
 
 If set to 1, enable wide character support (requires L<Text::ANSI::WideUtil>.
 
 =item * width => INT
 
 Width of progress bar. The default is to detect terminal width and use the whole
 width.
 
 =item * color_theme => STR
 
 Not yet implemented.
 
 Choose color theme. To see what color themes are available, use
 C<list_color_themes()>.
 
 =item * style => STR
 
 Not yet implemented.
 
 Choose style. To see what styles are available, use C<list_styles()>. Styles
 determine the characters used for drawing the bar, alignment, etc.
 
 =item * template => STR (default: '%p [%B]%e')
 
 Not yet implemented.
 
 See B<fill_template> in Progress::Any's documentation. Aside from template
 strings supported by Progress::Any, this output recognizes these additional
 strings: C<%b> to display the progress bar (using the rest of the available
 width), C<%B> to display the progress bar as well as the message inside it.
 
 =item * fh => handle (default: \*STDOUT)
 
 Instead of the default STDOUT, you can direct the output to another filehandle.
 
 =item * show_delay => int
 
 If set, will delay showing the progress bar until the specified number of
 seconds. This can be used to create, e.g. a CLI application that is relatively
 not chatty but will display progress after several seconds of seeming inactivity
 to indicate users that the process is still going on.
 
 =back
 
 =head2 keep_delay_showing()
 
 Can be called to reset the timer that counts down to show progress bar when
 C<show_delay> is defined. For example, if C<show_delay> is 5 seconds and two
 seconds have passed, it should've been 3 seconds before progress bar is shown in
 the next C<update()>. However, if you call this method, it will be 5 seconds
 again before showing.
 
 =head1 ENVIRONMENT
 
 =head2 COLOR => BOOL
 
 Can be used to force or disable color.
 
 =head2 COLOR_DEPTH => INT
 
 Can be used to override color depth detection. See L<Color::ANSI::Util>.
 
 =head2 COLUMNS => INT
 
 Can be used to override terminal width detection.
 
 =head1 SEE ALSO
 
 L<Progress::Any>
 
 L<Term::ProgressBar>
 
 Ruby library: ruby-progressbar, L<https://github.com/jfelchner/ruby-progressbar>
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Progress-Any-Output-TermProgressBarColor>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Progress-Any-Output-TermProgressBarColor>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Progress-Any-Output-TermProgressBarColor>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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
### Regexp/Stringify.pm ###
 package Regexp::Stringify;
 
 our $DATE = '2015-09-04'; # DATE
 our $VERSION = '0.04'; # VERSION
 
 use 5.010001;
 use strict;
 use warnings;
 
 use re qw(regexp_pattern);
 use Version::Util qw(version_ge);
 
 use Exporter;
 our @ISA = qw(Exporter);
 our @EXPORT_OK = qw(stringify_regexp);
 
 our %SPEC;
 
 $SPEC{stringify_regexp} = {
     v => 1.1,
     summary => 'Stringify a Regexp object',
     description => <<'_',
 
 This routine is an alternative to Perl's default stringification of Regexp
 object (i.e.:`"$re"`) and has some features/options, e.g.: producing regexp
 string that is compatible with certain perl versions.
 
 If given a string (or other non-Regexp object), will return it as-is.
 
 _
     args => {
         regexp => {
             schema => 're*',
             req => 1,
             pos => 0,
         },
         plver => {
             summary => 'Target perl version',
             schema => 'str*',
             description => <<'_',
 
 Try to produce a regexp object compatible with a certain perl version (should at
 least be >= 5.10).
 
 For example, in perl 5.14 regex stringification changes, e.g. `qr/hlagh/i` would
 previously be stringified as `(?i-xsm:hlagh)`, but now it's stringified as
 `(?^i:hlagh)`. If you set `plver` to 5.10 or 5.12, then this routine will
 still produce the former. It will also ignore regexp modifiers that are
 introduced in newer perls.
 
 Note that not all regexp objects are translatable to older perls, e.g. if they
 contain constructs not known to older perls like `(^...)` before perl 5.14.
 
 _
         },
         with_qr => {
             schema  => 'bool',
             description => <<'_',
 
 If you set this to 1, then `qr/a/i` will be stringified as `'qr/a/i'` instead as
 `'(^i:a)'`. The resulting string can then be eval-ed to recreate the Regexp
 object.
 
 _
         },
     },
     result_naked => 1,
     result => {
         schema => 'str*',
     },
 };
 sub stringify_regexp {
     my %args = @_;
 
     my $re = $args{regexp};
     return $re unless ref($re) eq 'Regexp';
     my $plver = $args{plver} // $^V;
 
     my ($pat, $mod) = regexp_pattern($re);
 
     my $ge_5140 = version_ge($plver, 5.014);
     unless ($ge_5140) {
         $mod =~ s/[adlu]//g;
     }
 
     if ($args{with_qr}) {
         return "qr($pat)$mod";
     } else {
         if ($ge_5140) {
             return "(^$mod:$pat)";
         } else {
             return "(?:(?$mod-)$pat)";
         }
     }
 }
 
 1;
 # ABSTRACT: Stringify a Regexp object
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Regexp::Stringify - Stringify a Regexp object
 
 =head1 VERSION
 
 This document describes version 0.04 of Regexp::Stringify (from Perl distribution Regexp-Stringify), released on 2015-09-04.
 
 =head1 SYNOPSIS
 
 Assuming this runs on Perl 5.14 or newer.
 
  use Regexp::Stringify qw(stringify_regexp);
  $str = stringify_regexp(regexp=>qr/a/i);                       # '(^i:a)'
  $str = stringify_regexp(regexp=>qr/a/i, with_qr=>1);           # 'qr(a)i'
  $str = stringify_regexp(regexp=>qr/a/i, plver=>5.010);         # '(?:(?i-)a)'
  $str = stringify_regexp(regexp=>qr/a/ui, plver=>5.010);        # '(?:(?i-)a)'
 
 =head1 FUNCTIONS
 
 
 =head2 stringify_regexp(%args) -> str
 
 Stringify a Regexp object.
 
 This routine is an alternative to Perl's default stringification of Regexp
 object (i.e.:C<"$re">) and has some features/options, e.g.: producing regexp
 string that is compatible with certain perl versions.
 
 If given a string (or other non-Regexp object), will return it as-is.
 
 Arguments ('*' denotes required arguments):
 
 =over 4
 
 =item * B<plver> => I<str>
 
 Target perl version.
 
 Try to produce a regexp object compatible with a certain perl version (should at
 least be >= 5.10).
 
 For example, in perl 5.14 regex stringification changes, e.g. C<qr/hlagh/i> would
 previously be stringified as C<(?i-xsm:hlagh)>, but now it's stringified as
 C<(?^i:hlagh)>. If you set C<plver> to 5.10 or 5.12, then this routine will
 still produce the former. It will also ignore regexp modifiers that are
 introduced in newer perls.
 
 Note that not all regexp objects are translatable to older perls, e.g. if they
 contain constructs not known to older perls like C<(^...)> before perl 5.14.
 
 =item * B<regexp>* => I<re>
 
 =item * B<with_qr> => I<bool>
 
 If you set this to 1, then C<qr/a/i> will be stringified as C<'qr/a/i'> instead as
 C<'(^i:a)'>. The resulting string can then be eval-ed to recreate the Regexp
 object.
 
 =back
 
 Return value:  (str)
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Regexp-Stringify>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Regexp-Stringify>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Regexp-Stringify>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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
### Rinci.pm ###
 package Rinci;
 
 our $VERSION = '1.1.78'; # VERSION
 
 1;
 # ABSTRACT: Language-neutral metadata for your code
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Rinci - Language-neutral metadata for your code
 
 =head1 VERSION
 
 This document describes version 1.1.78 of Rinci (from Perl distribution Rinci), released on 2015-09-03.
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Rinci>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Rinci>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Rinci>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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
### Role/Tiny.pm ###
 package Role::Tiny;
 
 sub _getglob { \*{$_[0]} }
 sub _getstash { \%{"$_[0]::"} }
 
 use strict;
 use warnings;
 
 our $VERSION = '2.000001';
 $VERSION = eval $VERSION;
 
 our %INFO;
 our %APPLIED_TO;
 our %COMPOSED;
 our %COMPOSITE_INFO;
 our @ON_ROLE_CREATE;
 
 # Module state workaround totally stolen from Zefram's Module::Runtime.
 
 BEGIN {
   *_WORK_AROUND_BROKEN_MODULE_STATE = "$]" < 5.009 ? sub(){1} : sub(){0};
   *_MRO_MODULE = "$]" < 5.010 ? sub(){"MRO/Compat.pm"} : sub(){"mro.pm"};
 }
 
 sub Role::Tiny::__GUARD__::DESTROY {
   delete $INC{$_[0]->[0]} if @{$_[0]};
 }
 
 sub _load_module {
   (my $proto = $_[0]) =~ s/::/\//g;
   $proto .= '.pm';
   return 1 if $INC{$proto};
   # can't just ->can('can') because a sub-package Foo::Bar::Baz
   # creates a 'Baz::' key in Foo::Bar's symbol table
   return 1 if grep !/::$/, keys %{_getstash($_[0])||{}};
   my $guard = _WORK_AROUND_BROKEN_MODULE_STATE
     && bless([ $proto ], 'Role::Tiny::__GUARD__');
   require $proto;
   pop @$guard if _WORK_AROUND_BROKEN_MODULE_STATE;
   return 1;
 }
 
 sub import {
   my $target = caller;
   my $me = shift;
   strict->import;
   warnings->import;
   return if $me->is_role($target); # already exported into this package
   $INFO{$target}{is_role} = 1;
   # get symbol table reference
   my $stash = _getstash($target);
   # install before/after/around subs
   foreach my $type (qw(before after around)) {
     *{_getglob "${target}::${type}"} = sub {
       require Class::Method::Modifiers;
       push @{$INFO{$target}{modifiers}||=[]}, [ $type => @_ ];
       return;
     };
   }
   *{_getglob "${target}::requires"} = sub {
     push @{$INFO{$target}{requires}||=[]}, @_;
     return;
   };
   *{_getglob "${target}::with"} = sub {
     $me->apply_roles_to_package($target, @_);
     return;
   };
   # grab all *non-constant* (stash slot is not a scalarref) subs present
   # in the symbol table and store their refaddrs (no need to forcibly
   # inflate constant subs into real subs) with a map to the coderefs in
   # case of copying or re-use
   my @not_methods = (map { *$_{CODE}||() } grep !ref($_), values %$stash);
   @{$INFO{$target}{not_methods}={}}{@not_methods} = @not_methods;
   # a role does itself
   $APPLIED_TO{$target} = { $target => undef };
   $_->($target) for @ON_ROLE_CREATE;
 }
 
 sub role_application_steps {
   qw(_install_methods _check_requires _install_modifiers _copy_applied_list);
 }
 
 sub apply_single_role_to_package {
   my ($me, $to, $role) = @_;
 
   _load_module($role);
 
   die "This is apply_role_to_package" if ref($to);
   die "${role} is not a Role::Tiny" unless $me->is_role($role);
 
   foreach my $step ($me->role_application_steps) {
     $me->$step($to, $role);
   }
 }
 
 sub _copy_applied_list {
   my ($me, $to, $role) = @_;
   # copy our role list into the target's
   @{$APPLIED_TO{$to}||={}}{keys %{$APPLIED_TO{$role}}} = ();
 }
 
 sub apply_roles_to_object {
   my ($me, $object, @roles) = @_;
   die "No roles supplied!" unless @roles;
   my $class = ref($object);
   # on perl < 5.8.9, magic isn't copied to all ref copies. bless the parameter
   # directly, so at least the variable passed to us will get any magic applied
   bless($_[1], $me->create_class_with_roles($class, @roles));
 }
 
 my $role_suffix = 'A000';
 sub _composite_name {
   my ($me, $superclass, @roles) = @_;
 
   my $new_name = join(
     '__WITH__', $superclass, my $compose_name = join '__AND__', @roles
   );
 
   if (length($new_name) > 252) {
     $new_name = $COMPOSED{abbrev}{$new_name} ||= do {
       my $abbrev = substr $new_name, 0, 250 - length $role_suffix;
       $abbrev =~ s/(?<!:):$//;
       $abbrev.'__'.$role_suffix++;
     };
   }
   return wantarray ? ($new_name, $compose_name) : $new_name;
 }
 
 sub create_class_with_roles {
   my ($me, $superclass, @roles) = @_;
 
   die "No roles supplied!" unless @roles;
 
   _load_module($superclass);
   {
     my %seen;
     $seen{$_}++ for @roles;
     if (my @dupes = grep $seen{$_} > 1, @roles) {
       die "Duplicated roles: ".join(', ', @dupes);
     }
   }
 
   my ($new_name, $compose_name) = $me->_composite_name($superclass, @roles);
 
   return $new_name if $COMPOSED{class}{$new_name};
 
   foreach my $role (@roles) {
     _load_module($role);
     die "${role} is not a Role::Tiny" unless $me->is_role($role);
   }
 
   require(_MRO_MODULE);
 
   my $composite_info = $me->_composite_info_for(@roles);
   my %conflicts = %{$composite_info->{conflicts}};
   if (keys %conflicts) {
     my $fail =
       join "\n",
         map {
           "Method name conflict for '$_' between roles "
           ."'".join(' and ', sort values %{$conflicts{$_}})."'"
           .", cannot apply these simultaneously to an object."
         } keys %conflicts;
     die $fail;
   }
 
   my @composable = map $me->_composable_package_for($_), reverse @roles;
 
   # some methods may not exist in the role, but get generated by
   # _composable_package_for (Moose accessors via Moo).  filter out anything
   # provided by the composable packages, excluding the subs we generated to
   # make modifiers work.
   my @requires = grep {
     my $method = $_;
     !grep $_->can($method) && !$COMPOSED{role}{$_}{modifiers_only}{$method},
       @composable
   } @{$composite_info->{requires}};
 
   $me->_check_requires(
     $superclass, $compose_name, \@requires
   );
 
   *{_getglob("${new_name}::ISA")} = [ @composable, $superclass ];
 
   @{$APPLIED_TO{$new_name}||={}}{
     map keys %{$APPLIED_TO{$_}}, @roles
   } = ();
 
   $COMPOSED{class}{$new_name} = 1;
   return $new_name;
 }
 
 # preserved for compat, and apply_roles_to_package calls it to allow an
 # updated Role::Tiny to use a non-updated Moo::Role
 
 sub apply_role_to_package { shift->apply_single_role_to_package(@_) }
 
 sub apply_roles_to_package {
   my ($me, $to, @roles) = @_;
 
   return $me->apply_role_to_package($to, $roles[0]) if @roles == 1;
 
   my %conflicts = %{$me->_composite_info_for(@roles)->{conflicts}};
   my @have = grep $to->can($_), keys %conflicts;
   delete @conflicts{@have};
 
   if (keys %conflicts) {
     my $fail =
       join "\n",
         map {
           "Due to a method name conflict between roles "
           ."'".join(' and ', sort values %{$conflicts{$_}})."'"
           .", the method '$_' must be implemented by '${to}'"
         } keys %conflicts;
     die $fail;
   }
 
   # conflicting methods are supposed to be treated as required by the
   # composed role. we don't have an actual composed role, but because
   # we know the target class already provides them, we can instead
   # pretend that the roles don't do for the duration of application.
   my @role_methods = map $me->_concrete_methods_of($_), @roles;
   # separate loops, since local ..., delete ... for ...; creates a scope
   local @{$_}{@have} for @role_methods;
   delete @{$_}{@have} for @role_methods;
 
   # the if guard here is essential since otherwise we accidentally create
   # a $INFO for something that isn't a Role::Tiny (or Moo::Role) because
   # autovivification hates us and wants us to die()
   if ($INFO{$to}) {
     delete $INFO{$to}{methods}; # reset since we're about to add methods
   }
 
   # backcompat: allow subclasses to use apply_single_role_to_package
   # to apply changes.  set a local var so ours does nothing.
   our %BACKCOMPAT_HACK;
   if($me ne __PACKAGE__
       and exists $BACKCOMPAT_HACK{$me} ? $BACKCOMPAT_HACK{$me} :
       $BACKCOMPAT_HACK{$me} =
         $me->can('role_application_steps')
           == \&role_application_steps
         && $me->can('apply_single_role_to_package')
           != \&apply_single_role_to_package
   ) {
     foreach my $role (@roles) {
       $me->apply_single_role_to_package($to, $role);
     }
   }
   else {
     foreach my $step ($me->role_application_steps) {
       foreach my $role (@roles) {
         $me->$step($to, $role);
       }
     }
   }
   $APPLIED_TO{$to}{join('|',@roles)} = 1;
 }
 
 sub _composite_info_for {
   my ($me, @roles) = @_;
   $COMPOSITE_INFO{join('|', sort @roles)} ||= do {
     foreach my $role (@roles) {
       _load_module($role);
     }
     my %methods;
     foreach my $role (@roles) {
       my $this_methods = $me->_concrete_methods_of($role);
       $methods{$_}{$this_methods->{$_}} = $role for keys %$this_methods;
     }
     my %requires;
     @requires{map @{$INFO{$_}{requires}||[]}, @roles} = ();
     delete $requires{$_} for keys %methods;
     delete $methods{$_} for grep keys(%{$methods{$_}}) == 1, keys %methods;
     +{ conflicts => \%methods, requires => [keys %requires] }
   };
 }
 
 sub _composable_package_for {
   my ($me, $role) = @_;
   my $composed_name = 'Role::Tiny::_COMPOSABLE::'.$role;
   return $composed_name if $COMPOSED{role}{$composed_name};
   $me->_install_methods($composed_name, $role);
   my $base_name = $composed_name.'::_BASE';
   # force stash to exist so ->can doesn't complain
   _getstash($base_name);
   # Not using _getglob, since setting @ISA via the typeglob breaks
   # inheritance on 5.10.0 if the stash has previously been accessed an
   # then a method called on the class (in that order!), which
   # ->_install_methods (with the help of ->_install_does) ends up doing.
   { no strict 'refs'; @{"${composed_name}::ISA"} = ( $base_name ); }
   my $modifiers = $INFO{$role}{modifiers}||[];
   my @mod_base;
   my @modifiers = grep !$composed_name->can($_),
     do { my %h; @h{map @{$_}[1..$#$_-1], @$modifiers} = (); keys %h };
   foreach my $modified (@modifiers) {
     push @mod_base, "sub ${modified} { shift->next::method(\@_) }";
   }
   my $e;
   {
     local $@;
     eval(my $code = join "\n", "package ${base_name};", @mod_base);
     $e = "Evaling failed: $@\nTrying to eval:\n${code}" if $@;
   }
   die $e if $e;
   $me->_install_modifiers($composed_name, $role);
   $COMPOSED{role}{$composed_name} = {
     modifiers_only => { map { $_ => 1 } @modifiers },
   };
   return $composed_name;
 }
 
 sub _check_requires {
   my ($me, $to, $name, $requires) = @_;
   return unless my @requires = @{$requires||$INFO{$name}{requires}||[]};
   if (my @requires_fail = grep !$to->can($_), @requires) {
     # role -> role, add to requires, role -> class, error out
     if (my $to_info = $INFO{$to}) {
       push @{$to_info->{requires}||=[]}, @requires_fail;
     } else {
       die "Can't apply ${name} to ${to} - missing ".join(', ', @requires_fail);
     }
   }
 }
 
 sub _concrete_methods_of {
   my ($me, $role) = @_;
   my $info = $INFO{$role};
   # grab role symbol table
   my $stash = _getstash($role);
   # reverse so our keys become the values (captured coderefs) in case
   # they got copied or re-used since
   my $not_methods = { reverse %{$info->{not_methods}||{}} };
   $info->{methods} ||= +{
     # grab all code entries that aren't in the not_methods list
     map {
       my $code = *{$stash->{$_}}{CODE};
       ( ! $code or exists $not_methods->{$code} ) ? () : ($_ => $code)
     } grep !ref($stash->{$_}), keys %$stash
   };
 }
 
 sub methods_provided_by {
   my ($me, $role) = @_;
   die "${role} is not a Role::Tiny" unless $me->is_role($role);
   (keys %{$me->_concrete_methods_of($role)}, @{$INFO{$role}->{requires}||[]});
 }
 
 sub _install_methods {
   my ($me, $to, $role) = @_;
 
   my $info = $INFO{$role};
 
   my $methods = $me->_concrete_methods_of($role);
 
   # grab target symbol table
   my $stash = _getstash($to);
 
   # determine already extant methods of target
   my %has_methods;
   @has_methods{grep
     +(ref($stash->{$_}) || *{$stash->{$_}}{CODE}),
     keys %$stash
   } = ();
 
   foreach my $i (grep !exists $has_methods{$_}, keys %$methods) {
     no warnings 'once';
     my $glob = _getglob "${to}::${i}";
     *$glob = $methods->{$i};
 
     # overloads using method names have the method stored in the scalar slot
     # and &overload::nil in the code slot.
     next
       unless $i =~ /^\(/
         && ((defined &overload::nil && $methods->{$i} == \&overload::nil)
             || (defined &overload::_nil && $methods->{$i} == \&overload::_nil));
 
     my $overload = ${ *{_getglob "${role}::${i}"}{SCALAR} };
     next
       unless defined $overload;
 
     *$glob = \$overload;
   }
 
   $me->_install_does($to);
 }
 
 sub _install_modifiers {
   my ($me, $to, $name) = @_;
   return unless my $modifiers = $INFO{$name}{modifiers};
   if (my $info = $INFO{$to}) {
     push @{$info->{modifiers}}, @{$modifiers||[]};
   } else {
     foreach my $modifier (@{$modifiers||[]}) {
       $me->_install_single_modifier($to, @$modifier);
     }
   }
 }
 
 my $vcheck_error;
 
 sub _install_single_modifier {
   my ($me, @args) = @_;
   defined($vcheck_error) or $vcheck_error = do {
     local $@;
     eval { Class::Method::Modifiers->VERSION(1.05); 1 }
       ? 0
       : $@
   };
   $vcheck_error and die $vcheck_error;
   Class::Method::Modifiers::install_modifier(@args);
 }
 
 my $FALLBACK = sub { 0 };
 sub _install_does {
   my ($me, $to) = @_;
 
   # only add does() method to classes
   return if $me->is_role($to);
 
   my $does = $me->can('does_role');
   # add does() only if they don't have one
   *{_getglob "${to}::does"} = $does unless $to->can('does');
 
   return
     if $to->can('DOES') and $to->can('DOES') != (UNIVERSAL->can('DOES') || 0);
 
   my $existing = $to->can('DOES') || $to->can('isa') || $FALLBACK;
   my $new_sub = sub {
     my ($proto, $role) = @_;
     $proto->$does($role) or $proto->$existing($role);
   };
   no warnings 'redefine';
   return *{_getglob "${to}::DOES"} = $new_sub;
 }
 
 sub does_role {
   my ($proto, $role) = @_;
   require(_MRO_MODULE);
   foreach my $class (@{mro::get_linear_isa(ref($proto)||$proto)}) {
     return 1 if exists $APPLIED_TO{$class}{$role};
   }
   return 0;
 }
 
 sub is_role {
   my ($me, $role) = @_;
   return !!($INFO{$role} && $INFO{$role}{is_role});
 }
 
 1;
 __END__
 
 =encoding utf-8
 
 =head1 NAME
 
 Role::Tiny - Roles. Like a nouvelle cuisine portion size slice of Moose.
 
 =head1 SYNOPSIS
 
  package Some::Role;
 
  use Role::Tiny;
 
  sub foo { ... }
 
  sub bar { ... }
 
  around baz => sub { ... }
 
  1;
 
 else where
 
  package Some::Class;
 
  use Role::Tiny::With;
 
  # bar gets imported, but not foo
  with 'Some::Role';
 
  sub foo { ... }
 
  # baz is wrapped in the around modifier by Class::Method::Modifiers
  sub baz { ... }
 
  1;
 
 If you wanted attributes as well, look at L<Moo::Role>.
 
 =head1 DESCRIPTION
 
 C<Role::Tiny> is a minimalist role composition tool.
 
 =head1 ROLE COMPOSITION
 
 Role composition can be thought of as much more clever and meaningful multiple
 inheritance.  The basics of this implementation of roles is:
 
 =over 2
 
 =item *
 
 If a method is already defined on a class, that method will not be composed in
 from the role.
 
 =item *
 
 If a method that the role L</requires> to be implemented is not implemented,
 role application will fail loudly.
 
 =back
 
 Unlike L<Class::C3>, where the B<last> class inherited from "wins," role
 composition is the other way around, where the class wins. If multiple roles
 are applied in a single call (single with statement), then if any of their
 provided methods clash, an exception is raised unless the class provides
 a method since this conflict indicates a potential problem.
 
 =head1 IMPORTED SUBROUTINES
 
 =head2 requires
 
  requires qw(foo bar);
 
 Declares a list of methods that must be defined to compose role.
 
 =head2 with
 
  with 'Some::Role1';
 
  with 'Some::Role1', 'Some::Role2';
 
 Composes another role into the current role (or class via L<Role::Tiny::With>).
 
 If you have conflicts and want to resolve them in favour of Some::Role1 you
 can instead write:
 
  with 'Some::Role1';
  with 'Some::Role2';
 
 If you have conflicts and want to resolve different conflicts in favour of
 different roles, please refactor your codebase.
 
 =head2 before
 
  before foo => sub { ... };
 
 See L<< Class::Method::Modifiers/before method(s) => sub { ... } >> for full
 documentation.
 
 Note that since you are not required to use method modifiers,
 L<Class::Method::Modifiers> is lazily loaded and we do not declare it as
 a dependency. If your L<Role::Tiny> role uses modifiers you must depend on
 both L<Class::Method::Modifiers> and L<Role::Tiny>.
 
 =head2 around
 
  around foo => sub { ... };
 
 See L<< Class::Method::Modifiers/around method(s) => sub { ... } >> for full
 documentation.
 
 Note that since you are not required to use method modifiers,
 L<Class::Method::Modifiers> is lazily loaded and we do not declare it as
 a dependency. If your L<Role::Tiny> role uses modifiers you must depend on
 both L<Class::Method::Modifiers> and L<Role::Tiny>.
 
 =head2 after
 
  after foo => sub { ... };
 
 See L<< Class::Method::Modifiers/after method(s) => sub { ... } >> for full
 documentation.
 
 Note that since you are not required to use method modifiers,
 L<Class::Method::Modifiers> is lazily loaded and we do not declare it as
 a dependency. If your L<Role::Tiny> role uses modifiers you must depend on
 both L<Class::Method::Modifiers> and L<Role::Tiny>.
 
 =head2 Strict and Warnings
 
 In addition to importing subroutines, using C<Role::Tiny> applies L<strict> and
 L<warnings> to the caller.
 
 =head1 SUBROUTINES
 
 =head2 does_role
 
  if (Role::Tiny::does_role($foo, 'Some::Role')) {
    ...
  }
 
 Returns true if class has been composed with role.
 
 This subroutine is also installed as ->does on any class a Role::Tiny is
 composed into unless that class already has an ->does method, so
 
   if ($foo->does('Some::Role')) {
     ...
   }
 
 will work for classes but to test a role, one must use ::does_role directly.
 
 Additionally, Role::Tiny will override the standard Perl C<DOES> method
 for your class. However, if C<any> class in your class' inheritance
 hierarchy provides C<DOES>, then Role::Tiny will not override it.
 
 =head1 METHODS
 
 =head2 apply_roles_to_package
 
  Role::Tiny->apply_roles_to_package(
    'Some::Package', 'Some::Role', 'Some::Other::Role'
  );
 
 Composes role with package.  See also L<Role::Tiny::With>.
 
 =head2 apply_roles_to_object
 
  Role::Tiny->apply_roles_to_object($foo, qw(Some::Role1 Some::Role2));
 
 Composes roles in order into object directly.  Object is reblessed into the
 resulting class.
 
 =head2 create_class_with_roles
 
  Role::Tiny->create_class_with_roles('Some::Base', qw(Some::Role1 Some::Role2));
 
 Creates a new class based on base, with the roles composed into it in order.
 New class is returned.
 
 =head2 is_role
 
  Role::Tiny->is_role('Some::Role1')
 
 Returns true if the given package is a role.
 
 =head1 CAVEATS
 
 =over 4
 
 =item * On perl 5.8.8 and earlier, applying a role to an object won't apply any
 overloads from the role to all copies of the object.
 
 =back
 
 =head1 SEE ALSO
 
 L<Role::Tiny> is the attribute-less subset of L<Moo::Role>; L<Moo::Role> is
 a meta-protocol-less subset of the king of role systems, L<Moose::Role>.
 
 Ovid's L<Role::Basic> provides roles with a similar scope, but without method
 modifiers, and having some extra usage restrictions.
 
 =head1 AUTHOR
 
 mst - Matt S. Trout (cpan:MSTROUT) <mst@shadowcat.co.uk>
 
 =head1 CONTRIBUTORS
 
 dg - David Leadbeater (cpan:DGL) <dgl@dgl.cx>
 
 frew - Arthur Axel "fREW" Schmidt (cpan:FREW) <frioux@gmail.com>
 
 hobbs - Andrew Rodland (cpan:ARODLAND) <arodland@cpan.org>
 
 jnap - John Napiorkowski (cpan:JJNAPIORK) <jjn1056@yahoo.com>
 
 ribasushi - Peter Rabbitson (cpan:RIBASUSHI) <ribasushi@cpan.org>
 
 chip - Chip Salzenberg (cpan:CHIPS) <chip@pobox.com>
 
 ajgb - Alex J. G. Burzyński (cpan:AJGB) <ajgb@cpan.org>
 
 doy - Jesse Luehrs (cpan:DOY) <doy at tozt dot net>
 
 perigrin - Chris Prather (cpan:PERIGRIN) <chris@prather.org>
 
 Mithaldu - Christian Walde (cpan:MITHALDU) <walde.christian@googlemail.com>
 
 ilmari - Dagfinn Ilmari Mannsåker (cpan:ILMARI) <ilmari@ilmari.org>
 
 tobyink - Toby Inkster (cpan:TOBYINK) <tobyink@cpan.org>
 
 haarg - Graham Knop (cpan:HAARG) <haarg@haarg.org>
 
 =head1 COPYRIGHT
 
 Copyright (c) 2010-2012 the Role::Tiny L</AUTHOR> and L</CONTRIBUTORS>
 as listed above.
 
 =head1 LICENSE
 
 This library is free software and may be distributed under the same terms
 as perl itself.
 
 =cut
### Role/Tiny/With.pm ###
 package Role::Tiny::With;
 
 use strict;
 use warnings;
 
 our $VERSION = '2.000001';
 $VERSION = eval $VERSION;
 
 use Role::Tiny ();
 
 use Exporter 'import';
 our @EXPORT = qw( with );
 
 sub with {
     my $target = caller;
     Role::Tiny->apply_roles_to_package($target, @_)
 }
 
 1;
 
 =head1 NAME
 
 Role::Tiny::With - Neat interface for consumers of Role::Tiny roles
 
 =head1 SYNOPSIS
 
  package Some::Class;
 
  use Role::Tiny::With;
 
  with 'Some::Role';
 
  # The role is now mixed in
 
 =head1 DESCRIPTION
 
 C<Role::Tiny> is a minimalist role composition tool.  C<Role::Tiny::With>
 provides a C<with> function to compose such roles.
 
 =head1 AUTHORS
 
 See L<Role::Tiny> for authors.
 
 =head1 COPYRIGHT AND LICENSE
 
 See L<Role::Tiny> for the copyright and license.
 
 =cut
 
 
### Sah/Schema/Rinci.pm ###
 package Sah::Schema::Rinci;
 
 our $DATE = '2015-09-03'; # DATE
 our $VERSION = '1.1.78'; # VERSION
 
 use 5.010001;
 use strict;
 use warnings;
 
 our %SCHEMAS;
 
 my %dh_props = (
     v => {},
     defhash_v => {},
     name => {},
     caption => {},
     summary => {},
     description => {},
     tags => {},
     default_lang => {},
     x => {},
 );
 
 $SCHEMAS{rinci} = [hash => {
     # tmp
     _ver => 1.1, # this has the effect of version checking
     _prop => {
         %dh_props,
 
         entity_v => {},
         entity_date => {},
         links => {
             _elem_prop => {
                 %dh_props,
 
                 url => {},
             },
         },
     },
 }];
 
 $SCHEMAS{rinci_function} = [hash => {
     # tmp
     _ver => 1.1,
     _prop => {
         %dh_props,
 
         # from common rinci metadata
         entity_v => {},
         entity_date => {},
         links => {},
 
         is_func => {},
         is_meth => {},
         is_class_meth => {},
         args => {
             _value_prop => {
                 %dh_props,
 
                 # common rinci metadata
                 links => {},
 
                 schema => {},
                 filters => {},
                 default => {},
                 req => {},
                 pos => {},
                 greedy => {},
                 partial => {},
                 stream => {},
                 is_password => {},
                 cmdline_aliases => {
                     _value_prop => {
                         summary => {},
                         description => {},
                         schema => {},
                         code => {},
                         is_flag => {},
                     },
                 },
                 cmdline_on_getopt => {},
                 cmdline_prompt => {},
                 completion => {},
                 element_completion => {},
                 cmdline_src => {},
                 meta => 'fix',
                 element_meta => 'fix',
                 deps => {
                     _keys => {
                         arg => {},
                         all => {},
                         any => {},
                         none => {},
                     },
                 },
             },
         },
         args_as => {},
         args_rels => {},
         result => {
             _prop => {
                 %dh_props,
 
                 schema => {},
                 statuses => {
                     _value_prop => {
                         # from defhash
                         summary => {},
                         description => {},
                         schema => {},
                     },
                 },
                 partial => {},
                 stream => {},
             },
         },
         result_naked => {},
         examples => {
             _elem_prop => {
                 %dh_props,
 
                 args => {},
                 argv => {},
                 src => {},
                 src_plang => {},
                 status => {},
                 result => {},
                 test => {},
             },
         },
         features => {
             _keys => {
                 reverse => {},
                 tx => {},
                 dry_run => {},
                 pure => {},
                 immutable => {},
                 idempotent => {},
                 check_arg => {},
             },
         },
         deps => {
             _keys => {
                 all => {},
                 any => {},
                 none => {},
                 env => {},
                 prog => {},
                 pkg => {},
                 func => {},
                 code => {},
                 tmp_dir => {},
                 trash_dir => {},
             },
         },
     },
 }];
 $SCHEMAS{rinci_function}[1]{_prop}{args}{_value_prop}{meta} =
     $SCHEMAS{rinci_function}[1];
 $SCHEMAS{rinci_function}[1]{_prop}{args}{_value_prop}{element_meta} =
     $SCHEMAS{rinci_function}[1];
 
 # rinci_package
 # rinci_variable
 
 $SCHEMAS{rinci_resmeta} = [hash => {
     # tmp
     _ver => 1.1,
     _prop => {
         %dh_props,
 
         perm_err => {},
         func => {}, # XXX func.*
         cmdline => {}, # XXX cmdline.*
         logs => {},
         prev => {},
         results => {},
         part_start => {},
         part_len => {},
         len => {},
         stream => {},
     },
 }];
 
 # list of known special arguments: -dry_run, -action, -tx_action,
 # -res_part_start, -res_part_len, -arg_part_start, -arg_part_len
 
 1;
 # ABSTRACT: Sah schemas for Rinci metadata
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Sah::Schema::Rinci - Sah schemas for Rinci metadata
 
 =head1 VERSION
 
 This document describes version 1.1.78 of Sah::Schema::Rinci (from Perl distribution Rinci), released on 2015-09-03.
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Rinci>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Rinci>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Rinci>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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
### Scalar/Util/Numeric/PP.pm ###
 package Scalar::Util::Numeric::PP;
 
 our $DATE = '2015-06-16'; # DATE
 our $VERSION = '0.03'; # VERSION
 
 use 5.010001;
 use strict;
 use warnings;
 
 require Exporter;
 our @ISA       = qw(Exporter);
 our @EXPORT_OK = qw(
                        isint
                        isnum
                        isnan
                        isinf
                        isneg
                        isfloat
                );
 
 sub isint {
     local $_ = shift;
     return 0 unless defined;
     return 1 if /\A[+-]?(?:0|[1-9][0-9]*)\z/;
     0;
 }
 
 sub isnan($) {
     local $_ = shift;
     return 0 unless defined;
     return 1 if /\A\s*[+-]?nan\s*\z/i;
     0;
 }
 
 sub isinf($) {
     local $_ = shift;
     return 0 unless defined;
     return 1 if /\A\s*[+-]?inf(?:inity)?\s*\z/i;
     0;
 }
 
 sub isneg($) {
     local $_ = shift;
     return 0 unless defined;
     return 1 if /\A\s*-/;
     0;
 }
 
 sub isnum($) {
     local $_ = shift;
     return 0 unless defined;
     return 1 if isint($_);
     return 1 if isfloat($_);
     0;
 }
 
 sub isfloat($) {
     local $_ = shift;
     return 0 unless defined;
     return 1 if /\A[+-]?
                  (?: (?:0|[1-9][0-9]*)(\.[0-9]+)? | (\.[0-9]+) )
                  ([eE][+-]?[0-9]+)?\z/x && $1 || $2 || $3;
     return 1 if isnan($_) || isinf($_);
     0;
 }
 
 1;
 # ABSTRACT: Pure-perl drop-in replacement/approximation of Scalar::Util::Numeric
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Scalar::Util::Numeric::PP - Pure-perl drop-in replacement/approximation of Scalar::Util::Numeric
 
 =head1 VERSION
 
 This document describes version 0.03 of Scalar::Util::Numeric::PP (from Perl distribution Scalar-Util-Numeric-PP), released on 2015-06-16.
 
 =head1 SYNOPSIS
 
 =head1 DESCRIPTION
 
 This module is written mainly for the convenience of L<Data::Sah>, as a drop-in
 pure-perl replacement for the XS module L<Scalar::Util::Numeric>, in the case
 when Data::Sah needs to generate code that uses PP modules instead of XS ones.
 
 Not all functions from Scalar::Util::Numeric have been provided.
 
 =head1 FUNCTIONS
 
 =head2 isint
 
 =head2 isfloat
 
 =head2 isnum
 
 =head2 isneg
 
 =head2 isinf
 
 =head2 isnan
 
 =head1 SEE ALSO
 
 L<Data::Sah>
 
 L<Scalar::Util::Numeric>
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Scalar-Util-Numeric-PP>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Scalar-Util-Numeric-PP>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Scalar-Util-Numeric-PP>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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
### String/Elide/Parts.pm ###
 package String::Elide::Parts;
 
 our $DATE = '2015-01-23'; # DATE
 our $VERSION = '0.01'; # VERSION
 
 use 5.010001;
 use strict;
 use warnings;
 
 use Exporter;
 our @ISA = qw(Exporter);
 our @EXPORT_OK = qw(elide);
 
 sub _elide_part {
     my ($str, $len, $marker, $truncate) = @_;
 
     my $len_marker = length($marker);
     if ($len <= $len_marker) {
         return substr($marker, 0, $len);
     }
 
     if ($truncate eq 'left') {
         return $marker . substr($str, length($str) - $len+$len_marker);
     } elsif ($truncate eq 'middle') {
         my $left  = substr($str, 0,
                            ($len-$len_marker)/2);
         my $right = substr($str,
                            length($str) - ($len-$len_marker-length($left)));
         return $left . $marker . $right;
     } elsif ($truncate eq 'ends') {
         if ($len <= 2*$len_marker) {
             return substr($marker . $marker, 0, $len);
         }
         return $marker . substr($str, (length($str)-$len)/2 + $len_marker,
                                 $len-2*$len_marker) . $marker;
     } else { # right
         return substr($str, 0, $len-$len_marker) . $marker;
     }
 }
 
 sub elide {
     my ($str, $len, $opts) = @_;
 
     $opts //= {};
     my $truncate  = $opts->{truncate} // 'right';
     my $marker = $opts->{marker} // '..';
 
     # split into parts by priority
     my @parts;
     my @parts_attrs;
     my $parts_len = 0;
     while ($str =~ m#<elspan([^>]*)>(.*?)</elspan>|(.*?)(?=<elspan)|(.*)#g) {
         if (defined $1) {
             next unless length $2;
             push @parts, $2;
             push @parts_attrs, $1;
         } elsif (defined $3) {
             next unless length $3;
             push @parts, $3;
             push @parts_attrs, undef;
         } elsif (defined $4) {
             next unless length $4;
             push @parts, $4;
             push @parts_attrs, undef;
         }
     }
     return "" unless @parts && $len > 0;
     for my $i (0..@parts-1) {
         $parts_len += length($parts[$i]);
         if (defined $parts_attrs[$i]) {
             my $attrs = {};
             $attrs->{truncate} = $1 // $2
                 if $parts_attrs[$i] =~ /\btruncate=(?:"([^"]*)"|(\S+))/;
             $attrs->{prio} = $1 // $2
                 if $parts_attrs[$i] =~ /\bprio(?:rity)?=(?:"([^"]*)"|(\S+))/;
             $parts_attrs[$i] = $attrs;
         } else {
             $parts_attrs[$i] = {prio=>1};
         }
     }
 
     #use DD; dd \@parts; dd \@parts_attrs;
 
     # used to flip and flop between eliding left and right end, used when
     # truncate is 'ends'
     my $flip = 0;
 
     # elide and truncate part by part until str is short enough
   PART:
     while (1) {
         if ($parts_len <= $len) {
             return join("", @parts);
         }
 
         # collect part indexes that have the largest priority
         my @indexes;
         my $highest_prio;
         for (@parts_attrs) {
             $highest_prio = $_->{prio} if !defined($highest_prio) ||
                 $highest_prio < $_->{prio};
         }
         for my $i (0..@parts_attrs-1) {
             push @indexes, $i if $parts_attrs[$i]{prio} == $highest_prio;
         }
 
         # pick which part (index) to elide
         my $index;
         if ($truncate eq 'left') {
             $index = $indexes[0];
         } elsif ($truncate eq 'middle') {
             $index = $indexes[@indexes/2];
         } elsif ($truncate eq 'ends') {
             $index = $flip++ % 2 ? $indexes[0] : $indexes[-1];
         } else { # right
             $index = $indexes[-1];
         }
 
         my $part_len = length($parts[$index]);
         if ($parts_len - $part_len >= $len) {
             # we need to fully eliminate this part then search for another part
             #say "D:eliminating part (prio=$highest_prio): <$parts[$index]>";
             $parts_len -= $part_len;
             splice @parts, $index, 1;
             splice @parts_attrs, $index, 1;
             next PART;
         }
 
         # we just need to elide this part and return the result
         #say "D:eliding part (prio=$highest_prio): <$parts[$index]>";
         $parts[$index] = _elide_part(
             $parts[$index],
             $part_len - ($parts_len-$len),
             $marker,
             $parts_attrs[$index]{truncate} // $truncate,
         );
         return join("", @parts);
 
     } # while 1
 }
 
 1;
 # ABSTRACT: Elide a string with multiple parts of different priorities
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 String::Elide::Parts - Elide a string with multiple parts of different priorities
 
 =head1 VERSION
 
 This document describes version 0.01 of String::Elide::Parts (from Perl distribution String-Elide-Parts), released on 2015-01-23.
 
 =head1 SYNOPSIS
 
  use String::Elide qw(elide);
 
  # single string with no parts
 
  my $text = "this is your brain";
  elide($text, 16);                       # -> "this is your ..."
  elide($text, 16, {truncate=>"left"});   # -> "...is your brain"
  elide($text, 16, {truncate=>"middle"}); # -> "this is... brain"
  elide($text, 16, {truncate=>"ends"});   # -> "... is your b..."
 
  elide($text, 16, {marker=>"--"});       # -> "this is your b--"
  elide($text, 16, {marker=>"--"});       # -> "this is your b--"
 
  # multipart strings: we want to elide URL first, then the Downloading text,
  # then the speed
 
  $text = "<elspan prio=2>Downloading</elspan> <elspan prio=3 truncate=middle>http://www.example.com/somefile</elspan> 320.0k/5.5M";
  elide($text, 56); # -> "Downloading http://www.example.com/somefile 320.0k/5.5M"
  elide($text, 55); # -> "Downloading http://www.example.com/somefile 320.0k/5.5M"
  elide($text, 50); # -> "Downloading http://www.e..com/somefile 320.0k/5.5M"
  elide($text, 45); # -> "Downloading http://ww..m/somefile 320.0k/5.5M"
  elide($text, 40); # -> "Downloading http://..omefile 320.0k/5.5M"
  elide($text, 35); # -> "Downloading http..efile 320.0k/5.5M"
  elide($text, 30); # -> "Downloading ht..le 320.0k/5.5M"
  elide($text, 25); # -> "Downloading . 320.0k/5.5M"
  elide($text, 24); # -> "Downloading  320.0k/5.5M"
  elide($text, 23); # -> "Download..  320.0k/5.5M"
  elide($text, 20); # -> "Downl..  320.0k/5.5M"
  elide($text, 15); # -> "..  320.0k/5.5M"
  elide($text, 13); # -> "  320.0k/5.5M"
  elide($text, 12); # -> "  320.0k/5.."
 
 =head1 DESCRIPTION
 
 String::Elide is similar to other string eliding modules, with one main
 difference: it accepts string marked with parts of different priorities. The
 goal is to retain more important information as much as possible when length is
 reduced.
 
 =head1 FUNCTIONS
 
 =head2 elide($str, $len[, \%opts]) => str
 
 Elide a string if length exceeds C<$len>.
 
 String can be marked with C<< <elspan prio=N truncate=T>...</elspan> >> so there
 can be multiple parts with different priorities and truncate direction. The
 default priority is 1. You can mark less important strings with higher priority
 to let it be elided first.
 
 Known options:
 
 =over
 
 =item * marker => str (default: '..')
 
 =item * truncate => 'left'|'middle'|'middle'|'ends' (default: 'right')
 
 =back
 
 =head1 SEE ALSO
 
 =head2 Similar elide modules
 
 L<Text::Elide> is simple, does not have many options, and elides at word
 boundaries.
 
 L<String::Truncate> has similar interface like String::Elide and has some
 options.
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/String-Elide-Parts>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-String-Elide-Parts>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=String-Elide-Parts>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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
### String/Indent.pm ###
 package String::Indent;
 
 our $DATE = '2015-03-06'; # DATE
 our $VERSION = '0.03'; # VERSION
 
 use 5.010001;
 use strict;
 use warnings;
 
 use Exporter;
 our @ISA = qw(Exporter);
 our @EXPORT_OK = qw(
                        indent
                );
 
 sub indent {
     my ($indent, $str, $opts) = @_;
     $opts //= {};
 
     my $ibl = $opts->{indent_blank_lines} // 1;
     my $fli = $opts->{first_line_indent} // $indent;
     my $sli = $opts->{subsequent_lines_indent} // $indent;
     #say "D:ibl=<$ibl>, fli=<$fli>, sli=<$sli>";
 
     my $i = 0;
     $str =~ s/^([^\r\n]?)/$i++; !$ibl && !$1 ? "$1" : $i==1 ? "$fli$1" : "$sli$1"/egm;
     $str;
 }
 
 1;
 # ABSTRACT: String indenting routines
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 String::Indent - String indenting routines
 
 =head1 VERSION
 
 This document describes version 0.03 of String::Indent (from Perl distribution String-Indent), released on 2015-03-06.
 
 =head1 FUNCTIONS
 
 =head2 indent($indent, $str, \%opts) => STR
 
 Indent every line in $str with $indent. Example:
 
  indent('  ', "one\ntwo\nthree") # "  one\n  two\n  three"
 
 %opts is optional. Known options:
 
 =over 4
 
 =item * indent_blank_lines => bool (default: 1)
 
 If set to false, does not indent blank lines (i.e., lines containing only zero
 or more whitespaces).
 
 =item * first_line_indent => str
 
 If set, then the first line will be set to this instead of the normal indent.
 
 =item * subsequent_lines_indent => str
 
 If set, then all lines but the first line will be set to this instead of the
 normal indent.
 
 =back
 
 =head1 SEE ALSO
 
 L<Indent::String>, L<String::Nudge>
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/String-Indent>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-String-Indent>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=String-Indent>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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
### String/LineNumber.pm ###
 package String::LineNumber;
 
 our $DATE = '2014-12-10'; # DATE
 our $VERSION = '0.01'; # VERSION
 
 use 5.010001;
 use strict;
 use warnings;
 
 use Exporter;
 our @ISA = qw(Exporter);
 our @EXPORT_OK = qw(
                        linenum
                );
 
 sub linenum {
     my ($str, $opts) = @_;
     $opts //= {};
     $opts->{width}      //= 4;
     $opts->{zeropad}    //= 0;
     $opts->{skip_empty} //= 1;
 
     my $i = 0;
     $str =~ s/^(([\t ]*\S)?.*)/
         sprintf(join("",
                      "%",
                      ($opts->{zeropad} && !($opts->{skip_empty}
                                                 && !defined($2)) ? "0" : ""),
                      $opts->{width}, "s",
                      "|%s"),
                 ++$i && $opts->{skip_empty} && !defined($2) ? "" : $i,
                 $1)/meg;
 
     $str;
 }
 
 1;
 # ABSTRACT: Give line number to each line of string
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 String::LineNumber - Give line number to each line of string
 
 =head1 VERSION
 
 This document describes version 0.01 of String::LineNumber (from Perl distribution String-LineNumber), released on 2014-12-10.
 
 =head1 FUNCTIONS
 
 =head2 linenum($str, \%opts) => STR
 
 Add line numbers. For example:
 
      1|line1
      2|line2
       |
      4|line4
 
 Known options:
 
 =over 4
 
 =item * width => INT (default: 4)
 
 =item * zeropad => BOOL (default: 0)
 
 If turned on, will output something like:
 
   0001|line1
   0002|line2
       |
   0004|line4
 
 =item * skip_empty => BOOL (default: 1)
 
 If set to false, keep printing line number even if line is empty:
 
      1|line1
      2|line2
      3|
      4|line4
 
 =back
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/String-LineNumber>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-String-LineNumber>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=String-LineNumber>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2014 by perlancar@cpan.org.
 
 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
### String/PerlQuote.pm ###
 package String::PerlQuote;
 
 our $DATE = '2014-12-10'; # DATE
 our $VERSION = '0.01'; # VERSION
 
 use 5.010001;
 use strict;
 use warnings;
 
 use Exporter;
 our @ISA = qw(Exporter);
 our @EXPORT_OK = qw(
                        single_quote
                        double_quote
                );
 
 # BEGIN COPY PASTE FROM Data::Dump
 my %esc = (
     "\a" => "\\a",
     "\b" => "\\b",
     "\t" => "\\t",
     "\n" => "\\n",
     "\f" => "\\f",
     "\r" => "\\r",
     "\e" => "\\e",
 );
 
 # put a string value in double quotes
 sub double_quote {
   local($_) = $_[0];
   # If there are many '"' we might want to use qq() instead
   s/([\\\"\@\$])/\\$1/g;
   return qq("$_") unless /[^\040-\176]/;  # fast exit
 
   s/([\a\b\t\n\f\r\e])/$esc{$1}/g;
 
   # no need for 3 digits in escape for these
   s/([\0-\037])(?!\d)/sprintf('\\%o',ord($1))/eg;
 
   s/([\0-\037\177-\377])/sprintf('\\x%02X',ord($1))/eg;
   s/([^\040-\176])/sprintf('\\x{%X}',ord($1))/eg;
 
   return qq("$_");
 }
 # END COPY PASTE FROM Data::Dump
 
 sub single_quote {
   local($_) = $_[0];
   s/([\\'])/\\$1/g;
   return qq('$_');
 }
 1;
 # ABSTRACT: Quote a string like Perl does
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 String::PerlQuote - Quote a string like Perl does
 
 =head1 VERSION
 
 This document describes version 0.01 of String::PerlQuote (from Perl distribution String-PerlQuote), released on 2014-12-10.
 
 =head1 FUNCTIONS
 
 =head2 double_quote($str) => STR
 
 Quote or encode C<$str> to the Perl double quote (C<">) literal representation
 of the string. Example:
 
  say double_quote("a");        # => "a"     (with the quotes)
  say double_quote("a\n");      # => "a\n"
  say double_quote('"');        # => "\""
  say double_quote('$foo');     # => "\$foo"
 
 This code is taken from C<quote()> in L<Data::Dump>. Maybe I didn't look more
 closely, but I couldn't a module that provides a function to do something like
 this. L<String::Escape>, for example, provides C<qqbackslash> but it does not
 escape C<$>.
 
 =head2 single_quote($str) => STR
 
 Like C<double_quote> but will produce a Perl single quote literal representation
 instead of the double quote ones. In single quotes, only literal backslash C<\>
 and single quote character C<'> are escaped, the rest are displayed as-is, so
 the result might span multiple lines or contain other non-printable characters.
 
  say single_quote("Mom's");    # => 'Mom\'s' (with the quotes)
  say single_quote("a\\");      # => 'a\\"
  say single_quote('"');        # => '"'
  say single_quote("\$foo");    # => '$foo'
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/String-PerlQuote>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-String-PerlQuote>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=String-PerlQuote>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2014 by perlancar@cpan.org.
 
 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
### String/ShellQuote.pm ###
 # $Id: ShellQuote.pm,v 1.11 2010-06-11 20:08:57 roderick Exp $
 #
 # Copyright (c) 1997 Roderick Schertler.  All rights reserved.  This
 # program is free software; you can redistribute it and/or modify it
 # under the same terms as Perl itself.
 
 =head1 NAME
 
 String::ShellQuote - quote strings for passing through the shell
 
 =head1 SYNOPSIS
 
     $string = shell_quote @list;
     $string = shell_quote_best_effort @list;
     $string = shell_comment_quote $string;
 
 =head1 DESCRIPTION
 
 This module contains some functions which are useful for quoting strings
 which are going to pass through the shell or a shell-like object.
 
 =over
 
 =cut
 
 package String::ShellQuote;
 
 use strict;
 use vars qw($VERSION @ISA @EXPORT);
 
 require Exporter;
 
 $VERSION	= '1.04';
 @ISA		= qw(Exporter);
 @EXPORT		= qw(shell_quote shell_quote_best_effort shell_comment_quote);
 
 sub croak {
     require Carp;
     goto &Carp::croak;
 }
 
 sub _shell_quote_backend {
     my @in = @_;
     my @err = ();
 
     if (0) {
 	require RS::Handy;
 	print RS::Handy::data_dump(\@in);
     }
 
     return \@err, '' unless @in;
 
     my $ret = '';
     my $saw_non_equal = 0;
     foreach (@in) {
 	if (!defined $_ or $_ eq '') {
 	    $_ = "''";
 	    next;
 	}
 
 	if (s/\x00//g) {
 	    push @err, "No way to quote string containing null (\\000) bytes";
 	}
 
     	my $escape = 0;
 
 	# = needs quoting when it's the first element (or part of a
 	# series of such elements), as in command position it's a
 	# program-local environment setting
 
 	if (/=/) {
 	    if (!$saw_non_equal) {
 	    	$escape = 1;
 	    }
 	}
 	else {
 	    $saw_non_equal = 1;
 	}
 
 	if (m|[^\w!%+,\-./:=@^]|) {
 	    $escape = 1;
 	}
 
 	if ($escape
 		|| (!$saw_non_equal && /=/)) {
 
 	    # ' -> '\''
     	    s/'/'\\''/g;
 
 	    # make multiple ' in a row look simpler
 	    # '\'''\'''\'' -> '"'''"'
     	    s|((?:'\\''){2,})|q{'"} . (q{'} x (length($1) / 4)) . q{"'}|ge;
 
 	    $_ = "'$_'";
 	    s/^''//;
 	    s/''$//;
 	}
     }
     continue {
 	$ret .= "$_ ";
     }
 
     chop $ret;
     return \@err, $ret;
 }
 
 =item B<shell_quote> [I<string>]...
 
 B<shell_quote> quotes strings so they can be passed through the shell.
 Each I<string> is quoted so that the shell will pass it along as a
 single argument and without further interpretation.  If no I<string>s
 are given an empty string is returned.
 
 If any I<string> can't be safely quoted B<shell_quote> will B<croak>.
 
 =cut
 
 sub shell_quote {
     my ($rerr, $s) = _shell_quote_backend @_;
 
     if (@$rerr) {
     	my %seen;
     	@$rerr = grep { !$seen{$_}++ } @$rerr;
 	my $s = join '', map { "shell_quote(): $_\n" } @$rerr;
 	chomp $s;
 	croak $s;
     }
     return $s;
 }
 
 =item B<shell_quote_best_effort> [I<string>]...
 
 This is like B<shell_quote>, excpet if the string can't be safely quoted
 it does the best it can and returns the result, instead of dying.
 
 =cut
 
 sub shell_quote_best_effort {
     my ($rerr, $s) = _shell_quote_backend @_;
 
     return $s;
 }
 
 =item B<shell_comment_quote> [I<string>]
 
 B<shell_comment_quote> quotes the I<string> so that it can safely be
 included in a shell-style comment (the current algorithm is that a sharp
 character is placed after any newlines in the string).
 
 This routine might be changed to accept multiple I<string> arguments
 in the future.  I haven't done this yet because I'm not sure if the
 I<string>s should be joined with blanks ($") or nothing ($,).  Cast
 your vote today!  Be sure to justify your answer.
 
 =cut
 
 sub shell_comment_quote {
     return '' unless @_;
     unless (@_ == 1) {
 	croak "Too many arguments to shell_comment_quote "
 	    	    . "(got " . @_ . " expected 1)";
     }
     local $_ = shift;
     s/\n/\n#/g;
     return $_;
 }
 
 1;
 
 __END__
 
 =back
 
 =head1 EXAMPLES
 
     $cmd = 'fuser 2>/dev/null ' . shell_quote @files;
     @pids = split ' ', `$cmd`;
 
     print CFG "# Configured by: ",
 		shell_comment_quote($ENV{LOGNAME}), "\n";
 
 =head1 BUGS
 
 Only Bourne shell quoting is supported.  I'd like to add other shells
 (particularly cmd.exe), but I'm not familiar with them.  It would be a
 big help if somebody supplied the details.
 
 =head1 AUTHOR
 
 Roderick Schertler <F<roderick@argon.org>>
 
 =head1 SEE ALSO
 
 perl(1).
 
 =cut
### String/Trim/More.pm ###
 package String::Trim::More;
 
 our $DATE = '2014-12-10'; # DATE
 our $VERSION = '0.02'; # VERSION
 
 use 5.010001;
 use strict;
 use warnings;
 
 use Exporter;
 our @ISA = qw(Exporter);
 our @EXPORT_OK = qw(
                        ltrim
                        rtrim
                        trim
                        ltrim_lines
                        rtrim_lines
                        trim_lines
                        trim_blank_lines
 
                        ellipsis
                );
 
 sub ltrim {
     my $str = shift;
     $str =~ s/\A\s+//s;
     $str;
 }
 
 sub rtrim {
     my $str = shift;
     $str =~ s/\s+\z//s;
     $str;
 }
 
 sub trim {
     my $str = shift;
     $str =~ s/\A\s+//s;
     $str =~ s/\s+\z//s;
     $str;
 }
 
 sub ltrim_lines {
     my $str = shift;
     $str =~ s/^[ \t]+//mg; # XXX other unicode non-newline spaces
     $str;
 }
 
 sub rtrim_lines {
     my $str = shift;
     $str =~ s/[ \t]+$//mg;
     $str;
 }
 
 sub trim_lines {
     my $str = shift;
     $str =~ s/^[ \t]+//mg;
     $str =~ s/[ \t]+$//mg;
     $str;
 }
 
 sub trim_blank_lines {
     local $_ = shift;
     return $_ unless defined;
     s/\A(?:\n\s*)+//;
     s/(?:\n\s*){2,}\z/\n/;
     $_;
 }
 
 sub ellipsis {
     my ($str, $maxlen, $ellipsis) = @_;
     $maxlen   //= 80;
     $ellipsis //= "...";
 
     if (length($str) <= $maxlen) {
         return $str;
     } else {
         return substr($str, 0, $maxlen-length($ellipsis)) . $ellipsis;
     }
 }
 
 1;
 # ABSTRACT: Various string trimming utilities
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 String::Trim::More - Various string trimming utilities
 
 =head1 VERSION
 
 This document describes version 0.02 of String::Trim::More (from Perl distribution String-Trim-More), released on 2014-12-10.
 
 =head1 DESCRIPTION
 
 This is an alternative to L<String::Trim> (and similar modules, see L</"SEE
 ALSO">). Instead of a single C<trim> function, this module provides several from
 which you can choose on, depending on your needs.
 
 =head1 FUNCTIONS
 
 =head2 ltrim($str) => STR
 
 Trim whitespaces (including newlines) at the beginning of string. Equivalent to:
 
  $str =~ s/\A\s+//s;
 
 =head2 ltrim_lines($str) => STR
 
 Trim whitespaces (not including newlines) at the beginning of each line of
 string. Equivalent to:
 
  $str =~ s/^\s+//mg;
 
 =head2 rtrim($str) => STR
 
 Trim whitespaces (including newlines) at the end of string. Equivalent to:
 
  $str =~ s/[ \t]+\z//s;
 
 =head2 rtrim_lines($str) => STR
 
 Trim whitespaces (not including newlines) at the end of each line of
 string. Equivalent to:
 
  $str =~ s/[ \t]+$//mg;
 
 =head2 trim($str) => STR
 
 ltrim + rtrim.
 
 =head2 trim_lines($str) => STR
 
 ltrim_lines + rtrim_lines.
 
 =head2 trim_blank_lines($str) => STR
 
 Trim blank lines at the beginning and the end. Won't trim blank lines in the
 middle. Blank lines include lines with only whitespaces in them.
 
 =head2 ellipsis($str[, $maxlen, $ellipsis]) => STR
 
 Return $str unmodified if $str's length is less than $maxlen (default 80).
 Otherwise cut $str to ($maxlen - length($ellipsis)) and append $ellipsis
 (default '...') at the end.
 
 =head1 SEE ALSO
 
 L<String::Trim>, L<Text::Trim>, L<String::Strip>, L<String::Util>.
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/String-Trim-More>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-String-Trim-More>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=String-Trim-More>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2014 by perlancar@cpan.org.
 
 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
### String/Wildcard/Bash.pm ###
 package String::Wildcard::Bash;
 
 use 5.010001;
 use strict;
 use warnings;
 
 our $VERSION = '0.03'; # VERSION
 
 use Exporter;
 our @ISA = qw(Exporter);
 our @EXPORT_OK = qw(
                        $RE_WILDCARD_BASH
                        contains_wildcard
                        convert_wildcard_to_sql
                );
 
 # note: order is important here, brace encloses the other
 our $RE_WILDCARD_BASH =
     qr(
           # non-escaped brace expression, with at least one comma
           (?P<brace>
               (?<!\\)(?:\\\\)*\{
               (?:           \\\\ | \\\{ | \\\} | [^\\\{\}] )*
               (?:, (?:  \\\\ | \\\{ | \\\} | [^\\\{\}] )* )+
               (?<!\\)(?:\\\\)*\}
           )
       |
           # non-escaped brace expression, to catch * or ? or [...] inside so
           # they don't go to below pattern, because bash doesn't consider them
           # wildcards, e.g. '/{et?,us*}' expands to '/etc /usr', but '/{et?}'
           # doesn't expand at all to /etc.
           (?P<braceno>
               (?<!\\)(?:\\\\)*\{
               (?:           \\\\ | \\\{ | \\\} | [^\\\{\}] )*
               (?<!\\)(?:\\\\)*\}
           )
       |
           (?P<class>
               # non-empty, non-escaped character class
               (?<!\\)(?:\\\\)*\[
               (?:  \\\\ | \\\[ | \\\] | [^\\\[\]] )+
               (?<!\\)(?:\\\\)*\]
           )
       |
           (?P<joker>
               # non-escaped * and ?
               (?<!\\)(?:\\\\)*[*?]
           )
       |
           (?P<sql_wc>
               # non-escaped % and ?
               (?<!\\)(?:\\\\)*[%_]
           )
       )ox;
 
 sub contains_wildcard {
     my $str = shift;
 
     while ($str =~ /$RE_WILDCARD_BASH/go) {
         my %m = %+;
         return 1 if $m{brace} || $m{class} || $m{joker};
     }
     0;
 }
 
 sub convert_wildcard_to_sql {
     my $str = shift;
 
     $str =~ s/$RE_WILDCARD_BASH/
         if ($+{joker}) {
             if ($+{joker} eq '*') {
                 "%";
             } else {
                 "_";
             }
         } elsif ($+{sql_wc}) {
             "\\$+{sql_wc}";
         } else {
             $&;
         }
     /eg;
 
     $str;
 }
 
 1;
 # ABSTRACT: Bash wildcard string routines
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 String::Wildcard::Bash - Bash wildcard string routines
 
 =head1 VERSION
 
 This document describes version 0.03 of String::Wildcard::Bash (from Perl distribution String-Wildcard-Bash), released on 2015-09-10.
 
 =head1 SYNOPSIS
 
     use String::Wildcard::Bash qw(
         $RE_WILDCARD_BASH
         contains_wildcard
         convert_wildcard_to_sql
     );
 
     say 1 if contains_wildcard(""));      # -> 0
     say 1 if contains_wildcard("ab*"));   # -> 1
     say 1 if contains_wildcard("ab\\*")); # -> 0
 
     say convert_wildcard_to_sql("foo*");  # -> "foo%"
 
 =head1 DESCRIPTION
 
 =for Pod::Coverage ^(qqquote)$
 
 =head1 FUNCTIONS
 
 =head2 contains_wildcard($str) => bool
 
 Return true if C<$str> contains wildcard pattern. Wildcard patterns include C<*>
 (meaning zero or more characters), C<?> (exactly one character), C<[...]>
 (character class), C<{...,}> (brace expansion). Can handle escaped/backslash
 (e.g. C<foo\*> does not contain wildcard, it's C<foo> followed by a literal
 asterisk C<*>).
 
 Aside from wildcard, bash does other types of expansions/substitutions too, but
 these are not considered wildcard. These include tilde expansion (e.g. C<~>
 becomes C</home/alice>), parameter and variable expansion (e.g. C<$0> and
 C<$HOME>), arithmetic expression (e.g. C<$[1+2]>), history (C<!>), and so on.
 
 Although this module has 'Bash' in its name, this set of wildcards should be
 applicable to other Unix shells. Haven't checked completely though.
 
 =head2 convert_wildcard_to_sql($str) => str
 
 Convert bash wildcard to SQL. This includes:
 
 =over
 
 =item * converting unescaped C<*> to C<%>
 
 =item * converting unescaped C<?> to C<_>
 
 =item * escaping unescaped <%>
 
 =item * escaping unescaped C<_>
 
 =back
 
 Unsupported constructs currently will be passed as-is.
 
 =head1 SEE ALSO
 
 L<Regexp::Wildcards> to convert a string with wildcard pattern to equivalent
 regexp pattern. Can handle Unix wildcards as well as SQL and DOS/Win32. As of
 this writing (v1.05), it does not handle character class (C<[...]>) and
 interprets brace expansion differently than bash.
 
 Other C<String::Wildcard::*> modules.
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/String-Wildcard-Bash>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-String-Wildcard-Bash>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=String-Wildcard-Bash>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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
### Sub/Defer.pm ###
 package Sub::Defer;
 
 use Moo::_strictures;
 use Exporter qw(import);
 use Moo::_Utils qw(_getglob _install_coderef);
 use Scalar::Util qw(weaken);
 
 our $VERSION = '2.000002';
 $VERSION = eval $VERSION;
 
 our @EXPORT = qw(defer_sub undefer_sub undefer_all);
 our @EXPORT_OK = qw(undefer_package);
 
 our %DEFERRED;
 
 sub undefer_sub {
   my ($deferred) = @_;
   my ($target, $maker, $undeferred_ref) = @{
     $DEFERRED{$deferred}||return $deferred
   };
   return ${$undeferred_ref}
     if ${$undeferred_ref};
   ${$undeferred_ref} = my $made = $maker->();
 
   # make sure the method slot has not changed since deferral time
   if (defined($target) && $deferred eq *{_getglob($target)}{CODE}||'') {
     no warnings 'redefine';
 
     # I believe $maker already evals with the right package/name, so that
     # _install_coderef calls are not necessary --ribasushi
     *{_getglob($target)} = $made;
   }
   $DEFERRED{$made} = $DEFERRED{$deferred};
   weaken $DEFERRED{$made}
     unless $target;
 
   return $made;
 }
 
 sub undefer_all {
   undefer_sub($_) for keys %DEFERRED;
   return;
 }
 
 sub undefer_package {
   my $package = shift;
   my @subs = grep { $DEFERRED{$_}[0] =~ /^${package}::[^:]+$/ } keys %DEFERRED;
   undefer_sub($_) for @subs;
   return;
 }
 
 sub defer_info {
   my ($deferred) = @_;
   my $info = $DEFERRED{$deferred||''} or return undef;
   [ @$info ];
 }
 
 sub defer_sub {
   my ($target, $maker) = @_;
   my $undeferred;
   my $deferred_info;
   my $deferred = sub {
     $undeferred ||= undefer_sub($deferred_info->[3]);
     goto &$undeferred;
   };
   $deferred_info = [ $target, $maker, \$undeferred, $deferred ];
   weaken($deferred_info->[3]);
   weaken($DEFERRED{$deferred} = $deferred_info);
   _install_coderef($target => $deferred) if defined $target;
   return $deferred;
 }
 
 sub CLONE {
   %DEFERRED = map { defined $_ && $_->[3] ? ($_->[3] => $_) : () } values %DEFERRED;
   foreach my $info (values %DEFERRED) {
     weaken($info)
       unless $info->[0] && ${$info->[2]};
   }
 }
 
 1;
 __END__
 
 =head1 NAME
 
 Sub::Defer - defer generation of subroutines until they are first called
 
 =head1 SYNOPSIS
 
  use Sub::Defer;
 
  my $deferred = defer_sub 'Logger::time_since_first_log' => sub {
     my $t = time;
     sub { time - $t };
  };
 
   Logger->time_since_first_log; # returns 0 and replaces itself
   Logger->time_since_first_log; # returns time - $t
 
 =head1 DESCRIPTION
 
 These subroutines provide the user with a convenient way to defer creation of
 subroutines and methods until they are first called.
 
 =head1 SUBROUTINES
 
 =head2 defer_sub
 
  my $coderef = defer_sub $name => sub { ... };
 
 This subroutine returns a coderef that encapsulates the provided sub - when
 it is first called, the provided sub is called and is -itself- expected to
 return a subroutine which will be goto'ed to on subsequent calls.
 
 If a name is provided, this also installs the sub as that name - and when
 the subroutine is undeferred will re-install the final version for speed.
 
 Exported by default.
 
 =head2 undefer_sub
 
  my $coderef = undefer_sub \&Foo::name;
 
 If the passed coderef has been L<deferred|/defer_sub> this will "undefer" it.
 If the passed coderef has not been deferred, this will just return it.
 
 If this is confusing, take a look at the example in the L</SYNOPSIS>.
 
 Exported by default.
 
 =head2 undefer_all
 
  undefer_all();
 
 This will undefer all defered subs in one go.  This can be very useful in a
 forking environment where child processes would each have to undefer the same
 subs.  By calling this just before you start forking children you can undefer
 all currently deferred subs in the parent so that the children do not have to
 do it.  Note this may bake the behavior of some subs that were intended to
 calculate their behavior later, so it shouldn't be used midway through a
 module load or class definition.
 
 Exported by default.
 
 =head2 undefer_package
 
   undefer_package($package);
 
 This undefers all defered subs in a package.
 
 Not exported by default.
 
 =head1 SUPPORT
 
 See L<Moo> for support and contact information.
 
 =head1 AUTHORS
 
 See L<Moo> for authors.
 
 =head1 COPYRIGHT AND LICENSE
 
 See L<Moo> for the copyright and license.
 
 =cut
### Sub/Delete.pm ###
 use 5.008003;
 
 package Sub::Delete;
 
 $VERSION = '1.00002';
 @EXPORT = delete_sub;
 
use Exporter 5.57 'import';
 use constant point0 => 0+$] eq 5.01;
 
 # This sub must come before any lexical vars.
 sub strict_eval($) {
  local %^H if point0;
  local *@;
  use#
   strict 'vars';
  local $SIG{__WARN__} = sub {};
  eval shift
 }
 
 my %sigils = qw( SCALAR $  ARRAY @  HASH % );
 
 sub delete_sub {
 	my $sub = shift;
 	my($stashname, $key) = $sub =~ /(.*::)((?:(?!::).)*)\z/s
 		? ($1,$2) : (caller()."::", $sub);
 	exists +(my $stash = \%$stashname)->{$key} or return;
 	ref $stash->{$key} eq 'SCALAR' and  # perl5.10 constant
 		delete $stash->{$key}, return;
 	my $globname = "$stashname$key"; 
 	my $glob = *$globname; # autovivify the glob in case future perl
 	defined *$glob{CODE} or return;  # versions add new funny stuff
 	my $check_importedness
 	 = $stashname =~ /^(?:(?!\d)\w*(?:::\w*)*)\z/
 	   && $key    =~ /^(?!\d)\w+\z/;
 	my %imported_slots;
 	my $package;
 	if($check_importedness) {
 		$package = substr $stashname, 0, -2;
 		for (qw "SCALAR ARRAY HASH") {
 			defined *$glob{$_} or next;
 			$imported_slots{$_} = strict_eval
 			  "package $package; 0 && $sigils{$_}$key; 1"
 		}
 	}
         delete $stash->{$key};
 	keys %imported_slots == 1 and exists $imported_slots{SCALAR}
 	 and !$imported_slots{SCALAR} and Internals'SvREFCNT $$glob =>== 1
 	 and !defined *$glob{IO} and !defined *$glob{FORMAT}
 	 and return; # empty glob
 	my $newglob = \*$globname;
 	local *alias = *$newglob;
 	defined *$glob{$_} and (
 	 !$check_importedness || $imported_slots{$_}
 	  ? *$newglob
 	  : *alias
 	) = *$glob{$_}
 		for qw "SCALAR ARRAY HASH";
 	defined *$glob{$_} and *$newglob = *$glob{$_}
 		for qw "IO FORMAT";
 	return # nothing;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 Sub::Delete - Perl module enabling one to delete subroutines
 
 =head1 VERSION
 
 1.00002
 
 =head1 SYNOPSIS
 
     use Sub::Delete;
     sub foo {}
     delete_sub 'foo';
     eval 'foo();1' or die; # dies
 
 =head1 DESCRIPTION
 
 This module provides one function, C<delete_sub>, that deletes the
 subroutine whose name is passed to it. (To load the module without
 importing the function, write S<C<use Sub::Delete();>>.)
 
 This does more than simply undefine
 the subroutine in the manner of C<undef &foo>, which leaves a stub that
 can trigger AUTOLOAD (and, consequently, won't work for deleting methods).
 The subroutine is completely obliterated from the
 symbol table (though there may be
 references to it elsewhere, including in compiled code).
 
 =head1 PREREQUISITES
 
 This module requires L<perl> 5.8.3 or higher.
 
 =head1 LIMITATIONS
 
 If you take a reference to a glob containing a subroutine, and then delete
 the subroutine with C<delete_sub>, you will find that the glob you 
 referenced still has a subroutine in it. This is because C<delete_sub>
 removes a glob, replaces it with another, and then copies the contents of
 the old glob into the new one, except for the C<CODE> slot. (This is nearly
 impossible to fix without breaking constant::lexical.)
 
 =head1 BUGS
 
 If you find any bugs, please report them to the author via e-mail.
 
 =head1 AUTHOR & COPYRIGHT
 
 Copyright (C) 2008-10 Father Chrysostomos (sprout at, um, cpan dot org)
 
 This program is free software; you may redistribute or modify it (or both)
 under the same terms as perl.
 
 =head1 SEE ALSO
 
 L<perltodo>, which has C<delete &sub> listed as a possible future feature
 
 L<Symbol::Glob> and L<Symbol::Util>, both of which predate this module (but
 I only discovered them recently), and which allow one to delete any
 arbitrary slot from a glob. Neither of them takes perl 5.10 constants
 into account, however. They also both differ from this module, in that a
 subroutine referenced in compiled code can no longer be called if deleted
 from its glob. The entire glob must be replaced (which this module does).
 
 =cut
### Sub/Exporter/Progressive.pm ###
 package Sub::Exporter::Progressive;
 
 use strict;
 use warnings;
 
 our $VERSION = '0.001011';
 
 use Carp ();
 use List::Util ();
 
 sub import {
    my ($self, @args) = @_;
 
    my $inner_target = caller;
    my $export_data = sub_export_options($inner_target, @args);
 
    my $full_exporter;
    no strict 'refs';
    @{"${inner_target}::EXPORT_OK"} = @{$export_data->{exports}};
    @{"${inner_target}::EXPORT"} = @{$export_data->{defaults}};
    %{"${inner_target}::EXPORT_TAGS"} = %{$export_data->{tags}};
    *{"${inner_target}::import"} = sub {
       use strict;
       my ($self, @args) = @_;
 
       if (List::Util::first { ref || !m/ \A [:-]? \w+ \z /xm } @args) {
          Carp::croak 'your usage of Sub::Exporter::Progressive requires Sub::Exporter to be installed'
             unless eval { require Sub::Exporter };
          $full_exporter ||= Sub::Exporter::build_exporter($export_data->{original});
 
          goto $full_exporter;
       } elsif (defined(my $num = List::Util::first { !ref and m/^\d/ } @args)) {
          die "cannot export symbols with a leading digit: '$num'";
       } else {
          require Exporter;
          s/ \A - /:/xm for @args;
          @_ = ($self, @args);
          goto \&Exporter::import;
       }
    };
    return;
 }
 
 my $too_complicated = <<'DEATH';
 You are using Sub::Exporter::Progressive, but the features your program uses from
 Sub::Exporter cannot be implemented without Sub::Exporter, so you might as well
 just use vanilla Sub::Exporter
 DEATH
 
 sub sub_export_options {
    my ($inner_target, $setup, $options) = @_;
 
    my @exports;
    my @defaults;
    my %tags;
 
    if ($setup eq '-setup') {
       my %options = %$options;
 
       OPTIONS:
       for my $opt (keys %options) {
          if ($opt eq 'exports') {
 
             Carp::croak $too_complicated if ref $options{exports} ne 'ARRAY';
             @exports = @{$options{exports}};
             Carp::croak $too_complicated if List::Util::first { ref } @exports;
 
          } elsif ($opt eq 'groups') {
             %tags = %{$options{groups}};
             for my $tagset (values %tags) {
                Carp::croak $too_complicated if List::Util::first { / \A - (?! all \b ) /x || ref } @{$tagset};
             }
             @defaults = @{$tags{default} || [] };
          } else {
             Carp::croak $too_complicated;
          }
       }
       @{$_} = map { / \A  [:-] all \z /x ? @exports : $_ } @{$_} for \@defaults, values %tags;
       $tags{all} ||= [ @exports ];
       my %exports = map { $_ => 1 } @exports;
       my @errors = grep { not $exports{$_} } @defaults;
       Carp::croak join(', ', @errors) . " is not exported by the $inner_target module\n" if @errors;
    }
 
    return {
       exports => \@exports,
       defaults => \@defaults,
       original => $options,
       tags => \%tags,
    };
 }
 
 1;
 
 =encoding utf8
 
 =head1 NAME
 
 Sub::Exporter::Progressive - Only use Sub::Exporter if you need it
 
 =head1 SYNOPSIS
 
  package Syntax::Keyword::Gather;
 
  use Sub::Exporter::Progressive -setup => {
    exports => [qw( break gather gathered take )],
    groups => {
      default => [qw( break gather gathered take )],
    },
  };
 
  # elsewhere
 
  # uses Exporter for speed
  use Syntax::Keyword::Gather;
 
  # somewhere else
 
  # uses Sub::Exporter for features
  use Syntax::Keyword::Gather 'gather', take => { -as => 'grab' };
 
 =head1 DESCRIPTION
 
 L<Sub::Exporter> is an incredibly powerful module, but with that power comes
 great responsibility, er- as well as some runtime penalties.  This module
 is a C<Sub::Exporter> wrapper that will let your users just use L<Exporter>
 if all they are doing is picking exports, but use C<Sub::Exporter> if your
 users try to use C<Sub::Exporter>'s more advanced features, like
 renaming exports, if they try to use them.
 
 Note that this module will export C<@EXPORT>, C<@EXPORT_OK> and
 C<%EXPORT_TAGS> package variables for C<Exporter> to work.  Additionally, if
 your package uses advanced C<Sub::Exporter> features like currying, this module
 will only ever use C<Sub::Exporter>, so you might as well use it directly.
 
 =head1 AUTHOR
 
 frew - Arthur Axel Schmidt (cpan:FREW) <frioux+cpan@gmail.com>
 
 =head1 CONTRIBUTORS
 
 ilmari - Dagfinn Ilmari Mannsåker (cpan:ILMARI) <ilmari@ilmari.org>
 
 mst - Matt S. Trout (cpan:MSTROUT) <mst@shadowcat.co.uk>
 
 leont - Leon Timmermans (cpan:LEONT) <leont@cpan.org>
 
 =head1 COPYRIGHT
 
 Copyright (c) 2012 the Sub::Exporter::Progressive L</AUTHOR> and
 L</CONTRIBUTORS> as listed above.
 
 =head1 LICENSE
 
 This library is free software and may be distributed under the same terms
 as perl itself.
 
 =cut
### Sub/Install.pm ###
 use strict;
 use warnings;
 package Sub::Install;
 # ABSTRACT: install subroutines into packages easily
 $Sub::Install::VERSION = '0.928';
 use Carp;
 use Scalar::Util ();
 
 #pod =head1 SYNOPSIS
 #pod
 #pod   use Sub::Install;
 #pod
 #pod   Sub::Install::install_sub({
 #pod     code => sub { ... },
 #pod     into => $package,
 #pod     as   => $subname
 #pod   });
 #pod
 #pod =head1 DESCRIPTION
 #pod
 #pod This module makes it easy to install subroutines into packages without the
 #pod unsightly mess of C<no strict> or typeglobs lying about where just anyone can
 #pod see them.
 #pod
 #pod =func install_sub
 #pod
 #pod   Sub::Install::install_sub({
 #pod    code => \&subroutine,
 #pod    into => "Finance::Shady",
 #pod    as   => 'launder',
 #pod   });
 #pod
 #pod This routine installs a given code reference into a package as a normal
 #pod subroutine.  The above is equivalent to:
 #pod
 #pod   no strict 'refs';
 #pod   *{"Finance::Shady" . '::' . "launder"} = \&subroutine;
 #pod
 #pod If C<into> is not given, the sub is installed into the calling package.
 #pod
 #pod If C<code> is not a code reference, it is looked for as an existing sub in the
 #pod package named in the C<from> parameter.  If C<from> is not given, it will look
 #pod in the calling package.
 #pod
 #pod If C<as> is not given, and if C<code> is a name, C<as> will default to C<code>.
 #pod If C<as> is not given, but if C<code> is a code ref, Sub::Install will try to
 #pod find the name of the given code ref and use that as C<as>.
 #pod
 #pod That means that this code:
 #pod
 #pod   Sub::Install::install_sub({
 #pod     code => 'twitch',
 #pod     from => 'Person::InPain',
 #pod     into => 'Person::Teenager',
 #pod     as   => 'dance',
 #pod   });
 #pod
 #pod is the same as:
 #pod
 #pod   package Person::Teenager;
 #pod
 #pod   Sub::Install::install_sub({
 #pod     code => Person::InPain->can('twitch'),
 #pod     as   => 'dance',
 #pod   });
 #pod
 #pod =func reinstall_sub
 #pod
 #pod This routine behaves exactly like C<L</install_sub>>, but does not emit a
 #pod warning if warnings are on and the destination is already defined.
 #pod
 #pod =cut
 
 sub _name_of_code {
   my ($code) = @_;
   require B;
   my $name = B::svref_2object($code)->GV->NAME;
   return $name unless $name =~ /\A__ANON__/;
   return;
 }
 
 # See also Params::Util, to which this code was donated.
 sub _CODELIKE {
   (Scalar::Util::reftype($_[0])||'') eq 'CODE'
   || Scalar::Util::blessed($_[0])
   && (overload::Method($_[0],'&{}') ? $_[0] : undef);
 }
 
 # do the heavy lifting
 sub _build_public_installer {
   my ($installer) = @_;
 
   sub {
     my ($arg) = @_;
     my ($calling_pkg) = caller(0);
 
     # I'd rather use ||= but I'm whoring for Devel::Cover.
     for (qw(into from)) { $arg->{$_} = $calling_pkg unless $arg->{$_} }
 
     # This is the only absolutely required argument, in many cases.
     Carp::croak "named argument 'code' is not optional" unless $arg->{code};
 
     if (_CODELIKE($arg->{code})) {
       $arg->{as} ||= _name_of_code($arg->{code});
     } else {
       Carp::croak
         "couldn't find subroutine named $arg->{code} in package $arg->{from}"
         unless my $code = $arg->{from}->can($arg->{code});
 
       $arg->{as}   = $arg->{code} unless $arg->{as};
       $arg->{code} = $code;
     }
 
     Carp::croak "couldn't determine name under which to install subroutine"
       unless $arg->{as};
 
     $installer->(@$arg{qw(into as code) });
   }
 }
 
 # do the ugly work
 
 my $_misc_warn_re;
 my $_redef_warn_re;
 BEGIN {
   $_misc_warn_re = qr/
     Prototype\ mismatch:\ sub\ .+?  |
     Constant subroutine .+? redefined
   /x;
   $_redef_warn_re = qr/Subroutine\ .+?\ redefined/x;
 }
 
 my $eow_re;
 BEGIN { $eow_re = qr/ at .+? line \d+\.\Z/ };
 
 sub _do_with_warn {
   my ($arg) = @_;
   my $code = delete $arg->{code};
   my $wants_code = sub {
     my $code = shift;
     sub {
       my $warn = $SIG{__WARN__} ? $SIG{__WARN__} : sub { warn @_ }; ## no critic
       local $SIG{__WARN__} = sub {
         my ($error) = @_;
         for (@{ $arg->{suppress} }) {
             return if $error =~ $_;
         }
         for (@{ $arg->{croak} }) {
           if (my ($base_error) = $error =~ /\A($_) $eow_re/x) {
             Carp::croak $base_error;
           }
         }
         for (@{ $arg->{carp} }) {
           if (my ($base_error) = $error =~ /\A($_) $eow_re/x) {
             return $warn->(Carp::shortmess $base_error);
           }
         }
         ($arg->{default} || $warn)->($error);
       };
       $code->(@_);
     };
   };
   return $wants_code->($code) if $code;
   return $wants_code;
 }
 
 sub _installer {
   sub {
     my ($pkg, $name, $code) = @_;
     no strict 'refs'; ## no critic ProhibitNoStrict
     *{"$pkg\::$name"} = $code;
     return $code;
   }
 }
 
 BEGIN {
   *_ignore_warnings = _do_with_warn({
     carp => [ $_misc_warn_re, $_redef_warn_re ]
   });
 
   *install_sub = _build_public_installer(_ignore_warnings(_installer));
 
   *_carp_warnings =  _do_with_warn({
     carp     => [ $_misc_warn_re ],
     suppress => [ $_redef_warn_re ],
   });
 
   *reinstall_sub = _build_public_installer(_carp_warnings(_installer));
 
   *_install_fatal = _do_with_warn({
     code     => _installer,
     croak    => [ $_redef_warn_re ],
   });
 }
 
 #pod =func install_installers
 #pod
 #pod This routine is provided to allow Sub::Install compatibility with
 #pod Sub::Installer.  It installs C<install_sub> and C<reinstall_sub> methods into
 #pod the package named by its argument.
 #pod
 #pod  Sub::Install::install_installers('Code::Builder'); # just for us, please
 #pod  Code::Builder->install_sub({ name => $code_ref });
 #pod
 #pod  Sub::Install::install_installers('UNIVERSAL'); # feeling lucky, punk?
 #pod  Anything::At::All->install_sub({ name => $code_ref });
 #pod
 #pod The installed installers are similar, but not identical, to those provided by
 #pod Sub::Installer.  They accept a single hash as an argument.  The key/value pairs
 #pod are used as the C<as> and C<code> parameters to the C<install_sub> routine
 #pod detailed above.  The package name on which the method is called is used as the
 #pod C<into> parameter.
 #pod
 #pod Unlike Sub::Installer's C<install_sub> will not eval strings into code, but
 #pod will look for named code in the calling package.
 #pod
 #pod =cut
 
 sub install_installers {
   my ($into) = @_;
 
   for my $method (qw(install_sub reinstall_sub)) {
     my $code = sub {
       my ($package, $subs) = @_;
       my ($caller) = caller(0);
       my $return;
       for (my ($name, $sub) = %$subs) {
         $return = Sub::Install->can($method)->({
           code => $sub,
           from => $caller,
           into => $package,
           as   => $name
         });
       }
       return $return;
     };
     install_sub({ code => $code, into => $into, as => $method });
   }
 }
 
 #pod =head1 EXPORTS
 #pod
 #pod Sub::Install exports C<install_sub> and C<reinstall_sub> only if they are
 #pod requested.
 #pod
 #pod =head2 exporter
 #pod
 #pod Sub::Install has a never-exported subroutine called C<exporter>, which is used
 #pod to implement its C<import> routine.  It takes a hashref of named arguments,
 #pod only one of which is currently recognize: C<exports>.  This must be an arrayref
 #pod of subroutines to offer for export.
 #pod
 #pod This routine is mainly for Sub::Install's own consumption.  Instead, consider
 #pod L<Sub::Exporter>.
 #pod
 #pod =cut
 
 sub exporter {
   my ($arg) = @_;
 
   my %is_exported = map { $_ => undef } @{ $arg->{exports} };
 
   sub {
     my $class = shift;
     my $target = caller;
     for (@_) {
       Carp::croak "'$_' is not exported by $class" if !exists $is_exported{$_};
       install_sub({ code => $_, from => $class, into => $target });
     }
   }
 }
 
 BEGIN { *import = exporter({ exports => [ qw(install_sub reinstall_sub) ] }); }
 
 #pod =head1 SEE ALSO
 #pod
 #pod =over
 #pod
 #pod =item L<Sub::Installer>
 #pod
 #pod This module is (obviously) a reaction to Damian Conway's Sub::Installer, which
 #pod does the same thing, but does it by getting its greasy fingers all over
 #pod UNIVERSAL.  I was really happy about the idea of making the installation of
 #pod coderefs less ugly, but I couldn't bring myself to replace the ugliness of
 #pod typeglobs and loosened strictures with the ugliness of UNIVERSAL methods.
 #pod
 #pod =item L<Sub::Exporter>
 #pod
 #pod This is a complete Exporter.pm replacement, built atop Sub::Install.
 #pod
 #pod =back
 #pod
 #pod =head1 EXTRA CREDITS
 #pod
 #pod Several of the tests are adapted from tests that shipped with Damian Conway's
 #pod Sub-Installer distribution.
 #pod
 #pod =cut
 
 1;
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Sub::Install - install subroutines into packages easily
 
 =head1 VERSION
 
 version 0.928
 
 =head1 SYNOPSIS
 
   use Sub::Install;
 
   Sub::Install::install_sub({
     code => sub { ... },
     into => $package,
     as   => $subname
   });
 
 =head1 DESCRIPTION
 
 This module makes it easy to install subroutines into packages without the
 unsightly mess of C<no strict> or typeglobs lying about where just anyone can
 see them.
 
 =head1 FUNCTIONS
 
 =head2 install_sub
 
   Sub::Install::install_sub({
    code => \&subroutine,
    into => "Finance::Shady",
    as   => 'launder',
   });
 
 This routine installs a given code reference into a package as a normal
 subroutine.  The above is equivalent to:
 
   no strict 'refs';
   *{"Finance::Shady" . '::' . "launder"} = \&subroutine;
 
 If C<into> is not given, the sub is installed into the calling package.
 
 If C<code> is not a code reference, it is looked for as an existing sub in the
 package named in the C<from> parameter.  If C<from> is not given, it will look
 in the calling package.
 
 If C<as> is not given, and if C<code> is a name, C<as> will default to C<code>.
 If C<as> is not given, but if C<code> is a code ref, Sub::Install will try to
 find the name of the given code ref and use that as C<as>.
 
 That means that this code:
 
   Sub::Install::install_sub({
     code => 'twitch',
     from => 'Person::InPain',
     into => 'Person::Teenager',
     as   => 'dance',
   });
 
 is the same as:
 
   package Person::Teenager;
 
   Sub::Install::install_sub({
     code => Person::InPain->can('twitch'),
     as   => 'dance',
   });
 
 =head2 reinstall_sub
 
 This routine behaves exactly like C<L</install_sub>>, but does not emit a
 warning if warnings are on and the destination is already defined.
 
 =head2 install_installers
 
 This routine is provided to allow Sub::Install compatibility with
 Sub::Installer.  It installs C<install_sub> and C<reinstall_sub> methods into
 the package named by its argument.
 
  Sub::Install::install_installers('Code::Builder'); # just for us, please
  Code::Builder->install_sub({ name => $code_ref });
 
  Sub::Install::install_installers('UNIVERSAL'); # feeling lucky, punk?
  Anything::At::All->install_sub({ name => $code_ref });
 
 The installed installers are similar, but not identical, to those provided by
 Sub::Installer.  They accept a single hash as an argument.  The key/value pairs
 are used as the C<as> and C<code> parameters to the C<install_sub> routine
 detailed above.  The package name on which the method is called is used as the
 C<into> parameter.
 
 Unlike Sub::Installer's C<install_sub> will not eval strings into code, but
 will look for named code in the calling package.
 
 =head1 EXPORTS
 
 Sub::Install exports C<install_sub> and C<reinstall_sub> only if they are
 requested.
 
 =head2 exporter
 
 Sub::Install has a never-exported subroutine called C<exporter>, which is used
 to implement its C<import> routine.  It takes a hashref of named arguments,
 only one of which is currently recognize: C<exports>.  This must be an arrayref
 of subroutines to offer for export.
 
 This routine is mainly for Sub::Install's own consumption.  Instead, consider
 L<Sub::Exporter>.
 
 =head1 SEE ALSO
 
 =over
 
 =item L<Sub::Installer>
 
 This module is (obviously) a reaction to Damian Conway's Sub::Installer, which
 does the same thing, but does it by getting its greasy fingers all over
 UNIVERSAL.  I was really happy about the idea of making the installation of
 coderefs less ugly, but I couldn't bring myself to replace the ugliness of
 typeglobs and loosened strictures with the ugliness of UNIVERSAL methods.
 
 =item L<Sub::Exporter>
 
 This is a complete Exporter.pm replacement, built atop Sub::Install.
 
 =back
 
 =head1 EXTRA CREDITS
 
 Several of the tests are adapted from tests that shipped with Damian Conway's
 Sub-Installer distribution.
 
 =head1 AUTHOR
 
 Ricardo SIGNES <rjbs@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2005 by 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
### Sub/Quote.pm ###
 package Sub::Quote;
 
 sub _clean_eval { eval $_[0] }
 
 use Moo::_strictures;
 
 use Sub::Defer qw(defer_sub);
 use Scalar::Util qw(weaken);
 use Exporter qw(import);
 use B ();
 BEGIN {
   *_HAVE_PERLSTRING = defined &B::perlstring ? sub(){1} : sub(){0};
 }
 
 our $VERSION = '2.000002';
 $VERSION = eval $VERSION;
 
 our @EXPORT = qw(quote_sub unquote_sub quoted_from_sub qsub);
 our @EXPORT_OK = qw(quotify capture_unroll inlinify);
 
 our %QUOTED;
 
 sub quotify {
   ! defined $_[0]     ? 'undef()'
   : _HAVE_PERLSTRING  ? B::perlstring($_[0])
   : qq["\Q$_[0]\E"];
 }
 
 sub capture_unroll {
   my ($from, $captures, $indent) = @_;
   join(
     '',
     map {
       /^([\@\%\$])/
         or die "capture key should start with \@, \% or \$: $_";
       (' ' x $indent).qq{my ${_} = ${1}{${from}->{${\quotify $_}}};\n};
     } keys %$captures
   );
 }
 
 sub inlinify {
   my ($code, $args, $extra, $local) = @_;
   my $do = 'do { '.($extra||'');
   if ($code =~ s/^(\s*package\s+([a-zA-Z0-9:]+);)//) {
     $do .= $1;
   }
   if ($code =~ s{
     \A((?:\#\ BEGIN\ quote_sub\ PRELUDE\n.*?\#\ END\ quote_sub\ PRELUDE\n)?\s*)
     (^\s*) my \s* \(([^)]+)\) \s* = \s* \@_;
   }{}xms) {
     my ($pre, $indent, $code_args) = ($1, $2, $3);
     $do .= $pre;
     if ($code_args ne $args) {
       $do .= $indent . 'my ('.$code_args.') = ('.$args.'); ';
     }
   }
   elsif ($local || $args ne '@_') {
     $do .= ($local ? 'local ' : '').'@_ = ('.$args.'); ';
   }
   $do.$code.' }';
 }
 
 sub quote_sub {
   # HOLY DWIMMERY, BATMAN!
   # $name => $code => \%captures => \%options
   # $name => $code => \%captures
   # $name => $code
   # $code => \%captures => \%options
   # $code
   my $options =
     (ref($_[-1]) eq 'HASH' and ref($_[-2]) eq 'HASH')
       ? pop
       : {};
   my $captures = ref($_[-1]) eq 'HASH' ? pop : undef;
   undef($captures) if $captures && !keys %$captures;
   my $code = pop;
   my $name = $_[0];
   my ($package, $hints, $bitmask, $hintshash) = (caller(0))[0,8,9,10];
   my $context
     ="# BEGIN quote_sub PRELUDE\n"
     ."package $package;\n"
     ."BEGIN {\n"
     ."  \$^H = ".quotify($hints).";\n"
     ."  \${^WARNING_BITS} = ".quotify($bitmask).";\n"
     ."  \%^H = (\n"
     . join('', map
      "    ".quotify($_)." => ".quotify($hintshash->{$_}).",",
       keys %$hintshash)
     ."  );\n"
     ."}\n"
     ."# END quote_sub PRELUDE\n";
   $code = "$context$code";
   my $quoted_info;
   my $unquoted;
   my $deferred = defer_sub +($options->{no_install} ? undef : $name) => sub {
     $unquoted if 0;
     unquote_sub($quoted_info->[4]);
   };
   $quoted_info = [ $name, $code, $captures, \$unquoted, $deferred ];
   weaken($quoted_info->[3]);
   weaken($quoted_info->[4]);
   weaken($QUOTED{$deferred} = $quoted_info);
   return $deferred;
 }
 
 sub quoted_from_sub {
   my ($sub) = @_;
   my $quoted_info = $QUOTED{$sub||''} or return undef;
   my ($name, $code, $captured, $unquoted, $deferred) = @{$quoted_info};
   $unquoted &&= $$unquoted;
   if (($deferred && $deferred eq $sub)
       || ($unquoted && $unquoted eq $sub)) {
     return [ $name, $code, $captured, $unquoted, $deferred ];
   }
   return undef;
 }
 
 sub unquote_sub {
   my ($sub) = @_;
   my $quoted = $QUOTED{$sub} or return undef;
   my $unquoted = $quoted->[3];
   unless ($unquoted && $$unquoted) {
     my ($name, $code, $captures) = @$quoted;
 
     my $make_sub = "{\n";
 
     my %captures = $captures ? %$captures : ();
     $captures{'$_UNQUOTED'} = \$unquoted;
     $captures{'$_QUOTED'} = \$quoted;
     $make_sub .= capture_unroll("\$_[1]", \%captures, 2);
 
     $make_sub .= (
       $name
           # disable the 'variable $x will not stay shared' warning since
           # we're not letting it escape from this scope anyway so there's
           # nothing trying to share it
         ? "  no warnings 'closure';\n  sub ${name} {\n"
         : "  \$\$_UNQUOTED = sub {\n"
     );
     $make_sub .= "  \$_QUOTED if 0;\n";
     $make_sub .= "  \$_UNQUOTED if 0;\n";
     $make_sub .= $code;
     $make_sub .= "  }".($name ? '' : ';')."\n";
     if ($name) {
       $make_sub .= "  \$\$_UNQUOTED = \\&${name}\n";
     }
     $make_sub .= "}\n1;\n";
     $ENV{SUB_QUOTE_DEBUG} && warn $make_sub;
     {
       no strict 'refs';
       local *{$name} if $name;
       my ($success, $e);
       {
         local $@;
         $success = _clean_eval($make_sub, \%captures);
         $e = $@;
       }
       unless ($success) {
         die "Eval went very, very wrong:\n\n${make_sub}\n\n$e";
       }
       weaken($QUOTED{$$unquoted} = $quoted);
     }
   }
   $$unquoted;
 }
 
 sub qsub ($) {
   goto &quote_sub;
 }
 
 sub CLONE {
   %QUOTED = map { defined $_ ? (
     $_->[3] && ${$_->[3]} ? (${ $_->[3] } => $_) : (),
     $_->[4] ? ($_->[4] => $_) : (),
   ) : () } values %QUOTED;
   weaken($_) for values %QUOTED;
 }
 
 1;
 __END__
 
 =head1 NAME
 
 Sub::Quote - efficient generation of subroutines via string eval
 
 =head1 SYNOPSIS
 
  package Silly;
 
  use Sub::Quote qw(quote_sub unquote_sub quoted_from_sub);
 
  quote_sub 'Silly::kitty', q{ print "meow" };
 
  quote_sub 'Silly::doggy', q{ print "woof" };
 
  my $sound = 0;
 
  quote_sub 'Silly::dagron',
    q{ print ++$sound % 2 ? 'burninate' : 'roar' },
    { '$sound' => \$sound };
 
 And elsewhere:
 
  Silly->kitty;  # meow
  Silly->doggy;  # woof
  Silly->dagron; # burninate
  Silly->dagron; # roar
  Silly->dagron; # burninate
 
 =head1 DESCRIPTION
 
 This package provides performant ways to generate subroutines from strings.
 
 =head1 SUBROUTINES
 
 =head2 quote_sub
 
  my $coderef = quote_sub 'Foo::bar', q{ print $x++ . "\n" }, { '$x' => \0 };
 
 Arguments: ?$name, $code, ?\%captures, ?\%options
 
 C<$name> is the subroutine where the coderef will be installed.
 
 C<$code> is a string that will be turned into code.
 
 C<\%captures> is a hashref of variables that will be made available to the
 code.  The keys should be the full name of the variable to be made available,
 including the sigil.  The values should be references to the values.  The
 variables will contain copies of the values.  See the L</SYNOPSIS>'s
 C<Silly::dagron> for an example using captures.
 
 =head3 options
 
 =over 2
 
 =item * no_install
 
 B<Boolean>.  Set this option to not install the generated coderef into the
 passed subroutine name on undefer.
 
 =back
 
 =head2 unquote_sub
 
  my $coderef = unquote_sub $sub;
 
 Forcibly replace subroutine with actual code.
 
 If $sub is not a quoted sub, this is a no-op.
 
 =head2 quoted_from_sub
 
  my $data = quoted_from_sub $sub;
 
  my ($name, $code, $captures, $compiled_sub) = @$data;
 
 Returns original arguments to quote_sub, plus the compiled version if this
 sub has already been unquoted.
 
 Note that $sub can be either the original quoted version or the compiled
 version for convenience.
 
 =head2 inlinify
 
  my $prelude = capture_unroll '$captures', {
    '$x' => 1,
    '$y' => 2,
  }, 4;
 
  my $inlined_code = inlinify q{
    my ($x, $y) = @_;
 
    print $x + $y . "\n";
  }, '$x, $y', $prelude;
 
 Takes a string of code, a string of arguments, a string of code which acts as a
 "prelude", and a B<Boolean> representing whether or not to localize the
 arguments.
 
 =head2 quotify
 
  my $quoted_value = quotify $value;
 
 Quotes a single (non-reference) scalar value for use in a code string.  Numbers
 aren't treated specially and will be quoted as strings, but undef will quoted as
 C<undef()>.
 
 =head2 capture_unroll
 
  my $prelude = capture_unroll '$captures', {
    '$x' => 1,
    '$y' => 2,
  }, 4;
 
 Arguments: $from, \%captures, $indent
 
 Generates a snippet of code which is suitable to be used as a prelude for
 L</inlinify>.  C<$from> is a string will be used as a hashref in the resulting
 code.  The keys of C<%captures> are the names of the variables and the values
 are ignored.  C<$indent> is the number of spaces to indent the result by.
 
 =head2 qsub
 
  my $hash = {
   coderef => qsub q{ print "hello"; },
   other   => 5,
  };
 
 Arguments: $code
 
 Works exactly like L</quote_sub>, but includes a prototype to only accept a
 single parameter.  This makes it easier to include in hash structures or lists.
 
 =head1 CAVEATS
 
 Much of this is just string-based code-generation, and as a result, a few
 caveats apply.
 
 =head2 return
 
 Calling C<return> from a quote_sub'ed sub will not likely do what you intend.
 Instead of returning from the code you defined in C<quote_sub>, it will return
 from the overall function it is composited into.
 
 So when you pass in:
 
    quote_sub q{  return 1 if $condition; $morecode }
 
 It might turn up in the intended context as follows:
 
   sub foo {
 
     <important code a>
     do {
       return 1 if $condition;
       $morecode
     };
     <important code b>
 
   }
 
 Which will obviously return from foo, when all you meant to do was return from
 the code context in quote_sub and proceed with running important code b.
 
 =head2 pragmas
 
 C<Sub::Quote> preserves the environment of the code creating the
 quoted subs.  This includes the package, strict, warnings, and any
 other lexical pragmas.  This is done by prefixing the code with a
 block that sets up a matching environment.  When inlining C<Sub::Quote>
 subs, care should be taken that user pragmas won't effect the rest
 of the code.
 
 =head1 SUPPORT
 
 See L<Moo> for support and contact information.
 
 =head1 AUTHORS
 
 See L<Moo> for authors.
 
 =head1 COPYRIGHT AND LICENSE
 
 See L<Moo> for the copyright and license.
 
 =cut
### Sys/Syslog.pm ###
 package Sys::Syslog;
 use strict;
 use warnings;
 use warnings::register;
 use Carp;
 use Exporter        qw< import >;
 use File::Basename;
 use POSIX           qw< strftime setlocale LC_TIME >;
 use Socket          qw< :all >;
 require 5.005;
 
 
 {   no strict 'vars';
     $VERSION = '0.33';
 
     %EXPORT_TAGS = (
         standard => [qw(openlog syslog closelog setlogmask)],
         extended => [qw(setlogsock)],
         macros => [
             # levels
             qw(
                 LOG_ALERT LOG_CRIT LOG_DEBUG LOG_EMERG LOG_ERR 
                 LOG_INFO LOG_NOTICE LOG_WARNING
             ), 
 
             # standard facilities
             qw(
                 LOG_AUTH LOG_AUTHPRIV LOG_CRON LOG_DAEMON LOG_FTP LOG_KERN
                 LOG_LOCAL0 LOG_LOCAL1 LOG_LOCAL2 LOG_LOCAL3 LOG_LOCAL4
                 LOG_LOCAL5 LOG_LOCAL6 LOG_LOCAL7 LOG_LPR LOG_MAIL LOG_NEWS
                 LOG_SYSLOG LOG_USER LOG_UUCP
             ),
             # Mac OS X specific facilities
             qw( LOG_INSTALL LOG_LAUNCHD LOG_NETINFO LOG_RAS LOG_REMOTEAUTH ),
             # modern BSD specific facilities
             qw( LOG_CONSOLE LOG_NTP LOG_SECURITY ),
             # IRIX specific facilities
             qw( LOG_AUDIT LOG_LFMT ),
 
             # options
             qw(
                 LOG_CONS LOG_PID LOG_NDELAY LOG_NOWAIT LOG_ODELAY LOG_PERROR 
             ), 
 
             # others macros
             qw(
                 LOG_FACMASK LOG_NFACILITIES LOG_PRIMASK 
                 LOG_MASK LOG_UPTO
             ), 
         ],
     );
 
     @EXPORT = (
         @{$EXPORT_TAGS{standard}}, 
     );
 
     @EXPORT_OK = (
         @{$EXPORT_TAGS{extended}}, 
         @{$EXPORT_TAGS{macros}}, 
     );
 
     eval {
         require XSLoader;
         XSLoader::load('Sys::Syslog', $VERSION);
         1
     } or do {
         require DynaLoader;
         push @ISA, 'DynaLoader';
         bootstrap Sys::Syslog $VERSION;
     };
 }
 
 
 # 
 # Public variables
 # 
 use vars qw($host);             # host to send syslog messages to (see notes at end)
 
 #
 # Prototypes
 #
 sub silent_eval (&);
 
 # 
 # Global variables
 # 
 use vars qw($facility);
 my $connected       = 0;        # flag to indicate if we're connected or not
 my $syslog_send;                # coderef of the function used to send messages
 my $syslog_path     = undef;    # syslog path for "stream" and "unix" mechanisms
 my $syslog_xobj     = undef;    # if defined, holds the external object used to send messages
 my $transmit_ok     = 0;        # flag to indicate if the last message was transmitted
 my $sock_port       = undef;    # socket port
 my $sock_timeout    = 0;        # socket timeout, see below
 my $current_proto   = undef;    # current mechanism used to transmit messages
 my $ident           = '';       # identifiant prepended to each message
 $facility           = '';       # current facility
 my $maskpri         = LOG_UPTO(&LOG_DEBUG);     # current log mask
 
 my %options = (
     ndelay  => 0, 
     noeol   => 0,
     nofatal => 0, 
     nonul   => 0,
     nowait  => 0, 
     perror  => 0, 
     pid     => 0, 
 );
 
 # Default is now to first use the native mechanism, so Perl programs 
 # behave like other normal Unix programs, then try other mechanisms.
 my @connectMethods = qw(native tcp udp unix pipe stream console);
 if ($^O eq "freebsd" or $^O eq "linux") {
     @connectMethods = grep { $_ ne 'udp' } @connectMethods;
 }
 
 # And on Win32 systems, we try to use the native mechanism for this 
 # platform, the events logger, available through Win32::EventLog.
 EVENTLOG: {
     my $is_Win32 = $^O =~ /Win32/i;
 
     if (can_load("Sys::Syslog::Win32", $is_Win32)) {
         unshift @connectMethods, 'eventlog';
     }
 }
 
 my @defaultMethods = @connectMethods;
 my @fallbackMethods = ();
 
 # The timeout in connection_ok() was pushed up to 0.25 sec in 
 # Sys::Syslog v0.19 in order to address a heisenbug on MacOSX:
 # http://london.pm.org/pipermail/london.pm/Week-of-Mon-20061211/005961.html
 # 
 # However, this also had the effect of slowing this test for 
 # all other operating systems, which apparently impacted some 
 # users (cf. CPAN-RT #34753). So, in order to make everybody 
 # happy, the timeout is now zero by default on all systems 
 # except on OSX where it is set to 250 msec, and can be set 
 # with the infamous setlogsock() function.
 #
 # Update 2011-08: this issue is also been seen on multiprocessor
 # Debian GNU/kFreeBSD systems. See http://bugs.debian.org/627821
 # and https://rt.cpan.org/Ticket/Display.html?id=69997
 # Also, lowering the delay to 1 ms, which should be enough.
 
 $sock_timeout = 0.001 if $^O =~ /darwin|gnukfreebsd/;
 
 
 # Perl 5.6.0's warnings.pm doesn't have warnings::warnif()
 if (not defined &warnings::warnif) {
     *warnings::warnif = sub {
         goto &warnings::warn if warnings::enabled(__PACKAGE__)
     }
 }
 
 # coderef for a nicer handling of errors
 my $err_sub = $options{nofatal} ? \&warnings::warnif : \&croak;
 
 
 sub AUTOLOAD {
     # This AUTOLOAD is used to 'autoload' constants from the constant()
     # XS function.
     no strict 'vars';
     my $constname;
     ($constname = $AUTOLOAD) =~ s/.*:://;
     croak "Sys::Syslog::constant() not defined" if $constname eq 'constant';
     my ($error, $val) = constant($constname);
     croak $error if $error;
     no strict 'refs';
     *$AUTOLOAD = sub { $val };
     goto &$AUTOLOAD;
 }
 
 
 sub openlog {
     ($ident, my $logopt, $facility) = @_;
 
     # default values
     $ident    ||= basename($0) || getlogin() || getpwuid($<) || 'syslog';
     $logopt   ||= '';
     $facility ||= LOG_USER();
 
     for my $opt (split /\b/, $logopt) {
         $options{$opt} = 1 if exists $options{$opt}
     }
 
     $err_sub = delete $options{nofatal} ? \&warnings::warnif : \&croak;
     return 1 unless $options{ndelay};
     connect_log();
 } 
 
 sub closelog {
     disconnect_log() if $connected;
     $options{$_} = 0 for keys %options;
     $facility = $ident = "";
     $connected = 0;
     return 1
 } 
 
 sub setlogmask {
     my $oldmask = $maskpri;
     $maskpri = shift unless $_[0] == 0;
     $oldmask;
 }
 
 
 my %mechanism = (
     console => {
         check   => sub { 1 },
     },
     eventlog => {
         check   => sub { return can_load("Win32::EventLog") },
         err_msg => "no Win32 API available",
     },
     inet => {
         check   => sub { 1 },
     },
     native => {
         check   => sub { 1 },
     },
     pipe => {
         check   => sub {
             ($syslog_path) = grep { defined && length && -p && -w _ }
                                 $syslog_path, &_PATH_LOG, "/dev/log";
             return $syslog_path ? 1 : 0
         },
         err_msg => "path not available",
     },
     stream => {
         check   => sub {
             if (not defined $syslog_path) {
                 my @try = qw(/dev/log /dev/conslog);
                 unshift @try, &_PATH_LOG  if length &_PATH_LOG;
                 ($syslog_path) = grep { -w } @try;
             }
             return defined $syslog_path && -w $syslog_path
         },
         err_msg => "could not find any writable device",
     },
     tcp => {
         check   => sub {
             return 1 if defined $sock_port;
 
             if (getservbyname('syslog', 'tcp') || getservbyname('syslogng', 'tcp')) {
                 $host = $syslog_path;
                 return 1
             }
             else {
                 return
             }
         },
         err_msg => "TCP service unavailable",
     },
     udp => {
         check   => sub {
             return 1 if defined $sock_port;
 
             if (getservbyname('syslog', 'udp')) {
                 $host = $syslog_path;
                 return 1
             }
             else {
                 return
             }
         },
         err_msg => "UDP service unavailable",
     },
     unix => {
         check   => sub {
             my @try = ($syslog_path, &_PATH_LOG);
             ($syslog_path) = grep { defined && length && -w } @try;
             return defined $syslog_path && -w $syslog_path
         },
         err_msg => "path not available",
     },
 );
  
 sub setlogsock {
     my %opt;
 
     # handle arguments
     # - old API: setlogsock($sock_type, $sock_path, $sock_timeout)
     # - new API: setlogsock(\%options)
     croak "setlogsock(): Invalid number of arguments"
         unless @_ >= 1 and @_ <= 3;
 
     if (my $ref = ref $_[0]) {
         if ($ref eq "HASH") {
             %opt = %{ $_[0] };
             croak "setlogsock(): No argument given" unless keys %opt;
         }
         elsif ($ref eq "ARRAY") {
             @opt{qw< type path timeout >} = @_;
         }
         else {
             croak "setlogsock(): Unexpected \L$ref\E reference"
         }
     }
     else {
         @opt{qw< type path timeout >} = @_;
     }
 
     # check socket type, remove invalid ones
     my $diag_invalid_type = "setlogsock(): Invalid type%s; must be one of "
                           . join ", ", map { "'$_'" } sort keys %mechanism;
     croak sprintf $diag_invalid_type, "" unless defined $opt{type};
     my @sock_types = ref $opt{type} eq "ARRAY" ? @{$opt{type}} : ($opt{type});
     my @tmp;
 
     for my $sock_type (@sock_types) {
         carp sprintf $diag_invalid_type, " '$sock_type'" and next
             unless exists $mechanism{$sock_type};
         push @tmp, "tcp", "udp" and next  if $sock_type eq "inet";
         push @tmp, $sock_type;
     }
 
     @sock_types = @tmp;
 
     # set global options
     $syslog_path  = $opt{path}    if defined $opt{path};
     $host         = $opt{host}    if defined $opt{host};
     $sock_timeout = $opt{timeout} if defined $opt{timeout};
     $sock_port    = $opt{port}    if defined $opt{port};
 
     disconnect_log() if $connected;
     $transmit_ok = 0;
     @fallbackMethods = ();
     @connectMethods = ();
     my $found = 0;
 
     # check each given mechanism and test if it can be used on the current system
     for my $sock_type (@sock_types) {
         if ( $mechanism{$sock_type}{check}->() ) {
             push @connectMethods, $sock_type;
             $found = 1;
         }
         else {
             warnings::warnif("setlogsock(): type='$sock_type': "
                            . $mechanism{$sock_type}{err_msg});
         }
     }
 
     # if no mechanism worked from the given ones, use the default ones
     @connectMethods = @defaultMethods unless @connectMethods;
 
     return $found;
 }
 
 sub syslog {
     my ($priority, $mask, @args) = @_;
     my ($message, $buf);
     my (@words, $num, $numpri, $numfac, $sum);
     my $failed = undef;
     my $fail_time = undef;
     my $error = $!;
 
     # if $ident is undefined, it means openlog() wasn't previously called
     # so do it now in order to have sensible defaults
     openlog() unless $ident;
 
     local $facility = $facility;    # may need to change temporarily.
 
     croak "syslog: expecting argument \$priority" unless defined $priority;
     croak "syslog: expecting argument \$format"   unless defined $mask;
 
     if ($priority =~ /^\d+$/) {
         $numpri = LOG_PRI($priority);
         $numfac = LOG_FAC($priority) << 3;
     }
     elsif ($priority =~ /^\w+/) {
         # Allow "level" or "level|facility".
         @words = split /\W+/, $priority, 2;
 
         undef $numpri;
         undef $numfac;
 
         for my $word (@words) {
             next if length $word == 0;
 
             # Translate word to number.
             $num = xlate($word);
 
             if ($num < 0) {
                 croak "syslog: invalid level/facility: $word"
             }
             elsif ($num <= LOG_PRIMASK() and $word ne "kern") {
                 croak "syslog: too many levels given: $word"
                     if defined $numpri;
                 $numpri = $num;
             }
             else {
                 croak "syslog: too many facilities given: $word"
                     if defined $numfac;
                 $facility = $word if $word =~ /^[A-Za-z]/;
                 $numfac = $num;
             }
         }
     }
     else {
         croak "syslog: invalid level/facility: $priority"
     }
 
     croak "syslog: level must be given" unless defined $numpri;
 
     # don't log if priority is below mask level
     return 0 unless LOG_MASK($numpri) & $maskpri;
 
     if (not defined $numfac) {  # Facility not specified in this call.
 	$facility = 'user' unless $facility;
 	$numfac = xlate($facility);
     }
 
     connect_log() unless $connected;
 
     if ($mask =~ /%m/) {
         # escape percent signs for sprintf()
         $error =~ s/%/%%/g if @args;
         # replace %m with $error, if preceded by an even number of percent signs
         $mask =~ s/(?<!%)((?:%%)*)%m/$1$error/g;
     }
 
     $mask .= "\n" unless $mask =~ /\n$/;
     $message = @args ? sprintf($mask, @args) : $mask;
 
     if ($current_proto eq 'native') {
         $buf = $message;
     }
     elsif ($current_proto eq 'eventlog') {
         $buf = $message;
     }
     else {
         my $whoami = $ident;
         $whoami .= "[$$]" if $options{pid};
 
         $sum = $numpri + $numfac;
         my $oldlocale = setlocale(LC_TIME);
         setlocale(LC_TIME, 'C');
         my $timestamp = strftime "%b %d %H:%M:%S", localtime;
         setlocale(LC_TIME, $oldlocale);
 
         # construct the stream that will be transmitted
         $buf = "<$sum>$timestamp $whoami: $message";
 
         # add (or not) a newline
         $buf .= "\n" if !$options{noeol} and rindex($buf, "\n") == -1;
 
         # add (or not) a NUL character
         $buf .= "\0" if !$options{nonul};
     }
 
     # handle PERROR option
     # "native" mechanism already handles it by itself
     if ($options{perror} and $current_proto ne 'native') {
         my $whoami = $ident;
         $whoami .= "[$$]" if $options{pid};
         print STDERR "$whoami: $message\n";
     }
 
     # it's possible that we'll get an error from sending
     # (e.g. if method is UDP and there is no UDP listener,
     # then we'll get ECONNREFUSED on the send). So what we
     # want to do at this point is to fallback onto a different
     # connection method.
     while (scalar @fallbackMethods || $syslog_send) {
 	if ($failed && (time - $fail_time) > 60) {
 	    # it's been a while... maybe things have been fixed
 	    @fallbackMethods = ();
 	    disconnect_log();
 	    $transmit_ok = 0; # make it look like a fresh attempt
 	    connect_log();
         }
 
 	if ($connected && !connection_ok()) {
 	    # Something was OK, but has now broken. Remember coz we'll
 	    # want to go back to what used to be OK.
 	    $failed = $current_proto unless $failed;
 	    $fail_time = time;
 	    disconnect_log();
 	}
 
 	connect_log() unless $connected;
 	$failed = undef if ($current_proto && $failed && $current_proto eq $failed);
 
 	if ($syslog_send) {
             if ($syslog_send->($buf, $numpri, $numfac)) {
 		$transmit_ok++;
 		return 1;
 	    }
 	    # typically doesn't happen, since errors are rare from write().
 	    disconnect_log();
 	}
     }
     # could not send, could not fallback onto a working
     # connection method. Lose.
     return 0;
 }
 
 sub _syslog_send_console {
     my ($buf) = @_;
 
     # The console print is a method which could block
     # so we do it in a child process and always return success
     # to the caller.
     if (my $pid = fork) {
 
 	if ($options{nowait}) {
 	    return 1;
 	} else {
 	    if (waitpid($pid, 0) >= 0) {
 	    	return ($? >> 8);
 	    } else {
 		# it's possible that the caller has other
 		# plans for SIGCHLD, so let's not interfere
 		return 1;
 	    }
 	}
     } else {
         if (open(CONS, ">/dev/console")) {
 	    my $ret = print CONS $buf . "\r";  # XXX: should this be \x0A ?
 	    POSIX::_exit($ret) if defined $pid;
 	    close CONS;
 	}
 
 	POSIX::_exit(0) if defined $pid;
     }
 }
 
 sub _syslog_send_stream {
     my ($buf) = @_;
     # XXX: this only works if the OS stream implementation makes a write 
     # look like a putmsg() with simple header. For instance it works on 
     # Solaris 8 but not Solaris 7.
     # To be correct, it should use a STREAMS API, but perl doesn't have one.
     return syswrite(SYSLOG, $buf, length($buf));
 }
 
 sub _syslog_send_pipe {
     my ($buf) = @_;
     return print SYSLOG $buf;
 }
 
 sub _syslog_send_socket {
     my ($buf) = @_;
     return syswrite(SYSLOG, $buf, length($buf));
     #return send(SYSLOG, $buf, 0);
 }
 
 sub _syslog_send_native {
     my ($buf, $numpri, $numfac) = @_;
     syslog_xs($numpri|$numfac, $buf);
     return 1;
 }
 
 
 # xlate()
 # -----
 # private function to translate names to numeric values
 # 
 sub xlate {
     my ($name) = @_;
 
     return $name+0 if $name =~ /^\s*\d+\s*$/;
     $name = uc $name;
     $name = "LOG_$name" unless $name =~ /^LOG_/;
 
     # ExtUtils::Constant 0.20 introduced a new way to implement
     # constants, called ProxySubs.  When it was used to generate
     # the C code, the constant() function no longer returns the 
     # correct value.  Therefore, we first try a direct call to 
     # constant(), and if the value is an error we try to call the 
     # constant by its full name. 
     my $value = constant($name);
 
     if (index($value, "not a valid") >= 0) {
         $name = "Sys::Syslog::$name";
         $value = eval { no strict "refs"; &$name };
         $value = $@ unless defined $value;
     }
 
     $value = -1 if index($value, "not a valid") >= 0;
 
     return defined $value ? $value : -1;
 }
 
 
 # connect_log()
 # -----------
 # This function acts as a kind of front-end: it tries to connect to 
 # a syslog service using the selected methods, trying each one in the 
 # selected order. 
 # 
 sub connect_log {
     @fallbackMethods = @connectMethods unless scalar @fallbackMethods;
 
     if ($transmit_ok && $current_proto) {
         # Retry what we were on, because it has worked in the past.
 	unshift(@fallbackMethods, $current_proto);
     }
 
     $connected = 0;
     my @errs = ();
     my $proto = undef;
 
     while ($proto = shift @fallbackMethods) {
 	no strict 'refs';
 	my $fn = "connect_$proto";
 	$connected = &$fn(\@errs) if defined &$fn;
 	last if $connected;
     }
 
     $transmit_ok = 0;
     if ($connected) {
 	$current_proto = $proto;
         my ($old) = select(SYSLOG); $| = 1; select($old);
     } else {
 	@fallbackMethods = ();
         $err_sub->(join "\n\t- ", "no connection to syslog available", @errs);
         return undef;
     }
 }
 
 sub connect_tcp {
     my ($errs) = @_;
 
     my $proto = getprotobyname('tcp');
     if (!defined $proto) {
 	push @$errs, "getprotobyname failed for tcp";
 	return 0;
     }
 
     my $port = $sock_port || getservbyname('syslog', 'tcp');
     $port = getservbyname('syslogng', 'tcp') unless defined $port;
     if (!defined $port) {
 	push @$errs, "getservbyname failed for syslog/tcp and syslogng/tcp";
 	return 0;
     }
 
     my $addr;
     if (defined $host) {
         $addr = inet_aton($host);
         if (!$addr) {
 	    push @$errs, "can't lookup $host";
 	    return 0;
 	}
     } else {
         $addr = INADDR_LOOPBACK;
     }
     $addr = sockaddr_in($port, $addr);
 
     if (!socket(SYSLOG, AF_INET, SOCK_STREAM, $proto)) {
 	push @$errs, "tcp socket: $!";
 	return 0;
     }
 
     setsockopt(SYSLOG, SOL_SOCKET, SO_KEEPALIVE, 1);
     if (silent_eval { IPPROTO_TCP() }) {
         # These constants don't exist in 5.005. They were added in 1999
         setsockopt(SYSLOG, IPPROTO_TCP(), TCP_NODELAY(), 1);
     }
     if (!connect(SYSLOG, $addr)) {
 	push @$errs, "tcp connect: $!";
 	return 0;
     }
 
     $syslog_send = \&_syslog_send_socket;
 
     return 1;
 }
 
 sub connect_udp {
     my ($errs) = @_;
 
     my $proto = getprotobyname('udp');
     if (!defined $proto) {
 	push @$errs, "getprotobyname failed for udp";
 	return 0;
     }
 
     my $port = $sock_port || getservbyname('syslog', 'udp');
     if (!defined $port) {
 	push @$errs, "getservbyname failed for syslog/udp";
 	return 0;
     }
 
     my $addr;
     if (defined $host) {
         $addr = inet_aton($host);
         if (!$addr) {
 	    push @$errs, "can't lookup $host";
 	    return 0;
 	}
     } else {
         $addr = INADDR_LOOPBACK;
     }
     $addr = sockaddr_in($port, $addr);
 
     if (!socket(SYSLOG, AF_INET, SOCK_DGRAM, $proto)) {
 	push @$errs, "udp socket: $!";
 	return 0;
     }
     if (!connect(SYSLOG, $addr)) {
 	push @$errs, "udp connect: $!";
 	return 0;
     }
 
     # We want to check that the UDP connect worked. However the only
     # way to do that is to send a message and see if an ICMP is returned
     _syslog_send_socket("");
     if (!connection_ok()) {
 	push @$errs, "udp connect: nobody listening";
 	return 0;
     }
 
     $syslog_send = \&_syslog_send_socket;
 
     return 1;
 }
 
 sub connect_stream {
     my ($errs) = @_;
     # might want syslog_path to be variable based on syslog.h (if only
     # it were in there!)
     $syslog_path = '/dev/conslog' unless defined $syslog_path; 
 
     if (!-w $syslog_path) {
 	push @$errs, "stream $syslog_path is not writable";
 	return 0;
     }
 
     require Fcntl;
 
     if (!sysopen(SYSLOG, $syslog_path, Fcntl::O_WRONLY(), 0400)) {
 	push @$errs, "stream can't open $syslog_path: $!";
 	return 0;
     }
 
     $syslog_send = \&_syslog_send_stream;
 
     return 1;
 }
 
 sub connect_pipe {
     my ($errs) = @_;
 
     $syslog_path ||= &_PATH_LOG || "/dev/log";
 
     if (not -w $syslog_path) {
         push @$errs, "$syslog_path is not writable";
         return 0;
     }
 
     if (not open(SYSLOG, ">$syslog_path")) {
         push @$errs, "can't write to $syslog_path: $!";
         return 0;
     }
 
     $syslog_send = \&_syslog_send_pipe;
 
     return 1;
 }
 
 sub connect_unix {
     my ($errs) = @_;
 
     $syslog_path ||= _PATH_LOG() if length _PATH_LOG();
 
     if (not defined $syslog_path) {
         push @$errs, "_PATH_LOG not available in syslog.h and no user-supplied socket path";
 	return 0;
     }
 
     if (not (-S $syslog_path or -c _)) {
         push @$errs, "$syslog_path is not a socket";
 	return 0;
     }
 
     my $addr = sockaddr_un($syslog_path);
     if (!$addr) {
 	push @$errs, "can't locate $syslog_path";
 	return 0;
     }
     if (!socket(SYSLOG, AF_UNIX, SOCK_STREAM, 0)) {
         push @$errs, "unix stream socket: $!";
 	return 0;
     }
 
     if (!connect(SYSLOG, $addr)) {
         if (!socket(SYSLOG, AF_UNIX, SOCK_DGRAM, 0)) {
 	    push @$errs, "unix dgram socket: $!";
 	    return 0;
 	}
         if (!connect(SYSLOG, $addr)) {
 	    push @$errs, "unix dgram connect: $!";
 	    return 0;
 	}
     }
 
     $syslog_send = \&_syslog_send_socket;
 
     return 1;
 }
 
 sub connect_native {
     my ($errs) = @_;
     my $logopt = 0;
 
     # reconstruct the numeric equivalent of the options
     for my $opt (keys %options) {
         $logopt += xlate($opt) if $options{$opt}
     }
 
     openlog_xs($ident, $logopt, xlate($facility));
     $syslog_send = \&_syslog_send_native;
 
     return 1;
 }
 
 sub connect_eventlog {
     my ($errs) = @_;
 
     $syslog_xobj = Sys::Syslog::Win32::_install();
     $syslog_send = \&Sys::Syslog::Win32::_syslog_send;
 
     return 1;
 }
 
 sub connect_console {
     my ($errs) = @_;
     if (!-w '/dev/console') {
 	push @$errs, "console is not writable";
 	return 0;
     }
     $syslog_send = \&_syslog_send_console;
     return 1;
 }
 
 # To test if the connection is still good, we need to check if any
 # errors are present on the connection. The errors will not be raised
 # by a write. Instead, sockets are made readable and the next read
 # would cause the error to be returned. Unfortunately the syslog 
 # 'protocol' never provides anything for us to read. But with 
 # judicious use of select(), we can see if it would be readable...
 sub connection_ok {
     return 1 if defined $current_proto and (
         $current_proto eq 'native' or $current_proto eq 'console'
         or $current_proto eq 'eventlog'
     );
 
     my $rin = '';
     vec($rin, fileno(SYSLOG), 1) = 1;
     my $ret = select $rin, undef, $rin, $sock_timeout;
     return ($ret ? 0 : 1);
 }
 
 sub disconnect_log {
     $connected = 0;
     $syslog_send = undef;
 
     if (defined $current_proto and $current_proto eq 'native') {
         closelog_xs();
         unshift @fallbackMethods, $current_proto;
         $current_proto = undef;
         return 1;
     }
     elsif (defined $current_proto and $current_proto eq 'eventlog') {
         $syslog_xobj->Close();
         unshift @fallbackMethods, $current_proto;
         $current_proto = undef;
         return 1;
     }
 
     return close SYSLOG;
 }
 
 
 #
 # Wrappers around eval() that makes sure that nobody, and I say NOBODY, 
 # ever knows that I wanted to test if something was here or not. 
 # It is needed because some applications are trying to be too smart,
 # do it wrong, and it ends up in EPIC FAIL. 
 # Yes I'm speaking of YOU, SpamAssassin.
 #
 sub silent_eval (&) {
     local($SIG{__DIE__}, $SIG{__WARN__}, $@);
     return eval { $_[0]->() }
 }
 
 sub can_load {
     my ($module, $verbose) = @_;
     local($SIG{__DIE__}, $SIG{__WARN__}, $@);
     my $loaded = eval "use $module; 1";
     warn $@ if not $loaded and $verbose;
     return $loaded
 }
 
 
 "Eighth Rule: read the documentation."
 
 __END__
 
 =head1 NAME
 
 Sys::Syslog - Perl interface to the UNIX syslog(3) calls
 
 =head1 VERSION
 
 This is the documentation of version 0.33
 
 =head1 SYNOPSIS
 
     use Sys::Syslog;                        # all except setlogsock()
     use Sys::Syslog qw(:standard :macros);  # standard functions & macros
 
     openlog($ident, $logopt, $facility);    # don't forget this
     syslog($priority, $format, @args);
     $oldmask = setlogmask($mask_priority);
     closelog();
 
 
 =head1 DESCRIPTION
 
 C<Sys::Syslog> is an interface to the UNIX C<syslog(3)> program.
 Call C<syslog()> with a string priority and a list of C<printf()> args
 just like C<syslog(3)>.
 
 
 =head1 EXPORTS
 
 C<Sys::Syslog> exports the following C<Exporter> tags: 
 
 =over 4
 
 =item *
 
 C<:standard> exports the standard C<syslog(3)> functions: 
 
     openlog closelog setlogmask syslog
 
 =item *
 
 C<:extended> exports the Perl specific functions for C<syslog(3)>: 
 
     setlogsock
 
 =item *
 
 C<:macros> exports the symbols corresponding to most of your C<syslog(3)> 
 macros and the C<LOG_UPTO()> and C<LOG_MASK()> functions. 
 See L<"CONSTANTS"> for the supported constants and their meaning. 
 
 =back
 
 By default, C<Sys::Syslog> exports the symbols from the C<:standard> tag. 
 
 
 =head1 FUNCTIONS
 
 =over 4
 
 =item B<openlog($ident, $logopt, $facility)>
 
 Opens the syslog.
 C<$ident> is prepended to every message.  C<$logopt> contains zero or
 more of the options detailed below.  C<$facility> specifies the part 
 of the system to report about, for example C<LOG_USER> or C<LOG_LOCAL0>:
 see L<"Facilities"> for a list of well-known facilities, and your 
 C<syslog(3)> documentation for the facilities available in your system. 
 Check L<"SEE ALSO"> for useful links. Facility can be given as a string 
 or a numeric macro. 
 
 This function will croak if it can't connect to the syslog daemon.
 
 Note that C<openlog()> now takes three arguments, just like C<openlog(3)>.
 
 B<You should use C<openlog()> before calling C<syslog()>.>
 
 B<Options>
 
 =over 4
 
 =item *
 
 C<cons> - This option is ignored, since the failover mechanism will drop 
 down to the console automatically if all other media fail.
 
 =item *
 
 C<ndelay> - Open the connection immediately (normally, the connection is
 opened when the first message is logged).
 
 =item *
 
 C<noeol> - When set to true, no end of line character (C<\n>) will be
 appended to the message. This can be useful for some buggy syslog daemons.
 
 =item *
 
 C<nofatal> - When set to true, C<openlog()> and C<syslog()> will only 
 emit warnings instead of dying if the connection to the syslog can't 
 be established. 
 
 =item *
 
 C<nonul> - When set to true, no C<NUL> character (C<\0>) will be
 appended to the message. This can be useful for some buggy syslog daemons.
 
 =item *
 
 C<nowait> - Don't wait for child processes that may have been created 
 while logging the message.  (The GNU C library does not create a child
 process, so this option has no effect on Linux.)
 
 =item *
 
 C<perror> - Write the message to standard error output as well to the
 system log (added in C<Sys::Syslog> 0.22).
 
 =item *
 
 C<pid> - Include PID with each message.
 
 =back
 
 B<Examples>
 
 Open the syslog with options C<ndelay> and C<pid>, and with facility C<LOCAL0>: 
 
     openlog($name, "ndelay,pid", "local0");
 
 Same thing, but this time using the macro corresponding to C<LOCAL0>: 
 
     openlog($name, "ndelay,pid", LOG_LOCAL0);
 
 
 =item B<syslog($priority, $message)>
 
 =item B<syslog($priority, $format, @args)>
 
 If C<$priority> permits, logs C<$message> or C<sprintf($format, @args)>
 with the addition that C<%m> in $message or C<$format> is replaced with
 C<"$!"> (the latest error message). 
 
 C<$priority> can specify a level, or a level and a facility.  Levels and 
 facilities can be given as strings or as macros.  When using the C<eventlog>
 mechanism, priorities C<DEBUG> and C<INFO> are mapped to event type 
 C<informational>, C<NOTICE> and C<WARNING> to C<warning> and C<ERR> to 
 C<EMERG> to C<error>.
 
 If you didn't use C<openlog()> before using C<syslog()>, C<syslog()> will 
 try to guess the C<$ident> by extracting the shortest prefix of 
 C<$format> that ends in a C<":">.
 
 B<Examples>
 
     # informational level
     syslog("info", $message);
     syslog(LOG_INFO, $message);
 
     # information level, Local0 facility
     syslog("info|local0", $message);
     syslog(LOG_INFO|LOG_LOCAL0, $message);
 
 =over 4
 
 =item B<Note>
 
 C<Sys::Syslog> version v0.07 and older passed the C<$message> as the 
 formatting string to C<sprintf()> even when no formatting arguments
 were provided.  If the code calling C<syslog()> might execute with 
 older versions of this module, make sure to call the function as
 C<syslog($priority, "%s", $message)> instead of C<syslog($priority,
 $message)>.  This protects against hostile formatting sequences that
 might show up if $message contains tainted data.
 
 =back
 
 
 =item B<setlogmask($mask_priority)>
 
 Sets the log mask for the current process to C<$mask_priority> and 
 returns the old mask.  If the mask argument is 0, the current log mask 
 is not modified.  See L<"Levels"> for the list of available levels. 
 You can use the C<LOG_UPTO()> function to allow all levels up to a 
 given priority (but it only accept the numeric macros as arguments).
 
 B<Examples>
 
 Only log errors: 
 
     setlogmask( LOG_MASK(LOG_ERR) );
 
 Log everything except informational messages: 
 
     setlogmask( ~(LOG_MASK(LOG_INFO)) );
 
 Log critical messages, errors and warnings: 
 
     setlogmask( LOG_MASK(LOG_CRIT)
               | LOG_MASK(LOG_ERR)
               | LOG_MASK(LOG_WARNING) );
 
 Log all messages up to debug: 
 
     setlogmask( LOG_UPTO(LOG_DEBUG) );
 
 
 =item B<setlogsock()>
 
 Sets the socket type and options to be used for the next call to C<openlog()>
 or C<syslog()>.  Returns true on success, C<undef> on failure.
 
 Being Perl-specific, this function has evolved along time.  It can currently
 be called as follow:
 
 =over
 
 =item *
 
 C<setlogsock($sock_type)>
 
 =item *
 
 C<setlogsock($sock_type, $stream_location)> (added in Perl 5.004_02)
 
 =item *
 
 C<setlogsock($sock_type, $stream_location, $sock_timeout)> (added in
 C<Sys::Syslog> 0.25)
 
 =item *
 
 C<setlogsock(\%options)> (added in C<Sys::Syslog> 0.28)
 
 =back
 
 The available options are:
 
 =over
 
 =item *
 
 C<type> - equivalent to C<$sock_type>, selects the socket type (or
 "mechanism").  An array reference can be passed to specify several
 mechanisms to try, in the given order.
 
 =item *
 
 C<path> - equivalent to C<$stream_location>, sets the stream location.
 Defaults to standard Unix location, or C<_PATH_LOG>.
 
 =item *
 
 C<timeout> - equivalent to C<$sock_timeout>, sets the socket timeout
 in seconds.  Defaults to 0 on all systems except S<Mac OS X> where it
 is set to 0.25 sec.
 
 =item *
 
 C<host> - sets the hostname to send the messages to.  Defaults to 
 the local host.
 
 =item *
 
 C<port> - sets the TCP or UDP port to connect to.  Defaults to the
 first standard syslog port available on the system.
 
 =back
 
 
 The available mechanisms are: 
 
 =over
 
 =item *
 
 C<"native"> - use the native C functions from your C<syslog(3)> library
 (added in C<Sys::Syslog> 0.15).
 
 =item *
 
 C<"eventlog"> - send messages to the Win32 events logger (Win32 only; 
 added in C<Sys::Syslog> 0.19).
 
 =item *
 
 C<"tcp"> - connect to a TCP socket, on the C<syslog/tcp> or C<syslogng/tcp> 
 service.  See also the C<host>, C<port> and C<timeout> options.
 
 =item *
 
 C<"udp"> - connect to a UDP socket, on the C<syslog/udp> service.
 See also the C<host>, C<port> and C<timeout> options.
 
 =item *
 
 C<"inet"> - connect to an INET socket, either TCP or UDP, tried in that 
 order.  See also the C<host>, C<port> and C<timeout> options.
 
 =item *
 
 C<"unix"> - connect to a UNIX domain socket (in some systems a character 
 special device).  The name of that socket is given by the C<path> option
 or, if omitted, the value returned by the C<_PATH_LOG> macro (if your
 system defines it), F</dev/log> or F</dev/conslog>, whichever is writable.
 
 =item *
 
 C<"stream"> - connect to the stream indicated by the C<path> option, or,
 if omitted, the value returned by the C<_PATH_LOG> macro (if your system
 defines it), F</dev/log> or F</dev/conslog>, whichever is writable.  For
 example Solaris and IRIX system may prefer C<"stream"> instead of C<"unix">. 
 
 =item *
 
 C<"pipe"> - connect to the named pipe indicated by the C<path> option,
 or, if omitted, to the value returned by the C<_PATH_LOG> macro (if your
 system defines it), or F</dev/log> (added in C<Sys::Syslog> 0.21).
 HP-UX is a system which uses such a named pipe.
 
 =item *
 
 C<"console"> - send messages directly to the console, as for the C<"cons"> 
 option of C<openlog()>.
 
 =back
 
 The default is to try C<native>, C<tcp>, C<udp>, C<unix>, C<pipe>, C<stream>, 
 C<console>.
 Under systems with the Win32 API, C<eventlog> will be added as the first 
 mechanism to try if C<Win32::EventLog> is available.
 
 Giving an invalid value for C<$sock_type> will C<croak>.
 
 B<Examples>
 
 Select the UDP socket mechanism:
 
     setlogsock("udp");
 
 Send messages using the TCP socket mechanism on a custom port:
 
     setlogsock({ type => "tcp", port => 2486 });
 
 Send messages to a remote host using the TCP socket mechanism:
 
     setlogsock({ type => "tcp", host => $loghost });
 
 Try the native, UDP socket then UNIX domain socket mechanisms: 
 
     setlogsock(["native", "udp", "unix"]);
 
 =over
 
 =item B<Note>
 
 Now that the "native" mechanism is supported by C<Sys::Syslog> and selected 
 by default, the use of the C<setlogsock()> function is discouraged because 
 other mechanisms are less portable across operating systems.  Authors of 
 modules and programs that use this function, especially its cargo-cult form 
 C<setlogsock("unix")>, are advised to remove any occurrence of it unless they 
 specifically want to use a given mechanism (like TCP or UDP to connect to 
 a remote host).
 
 =back
 
 =item B<closelog()>
 
 Closes the log file and returns true on success.
 
 =back
 
 
 =head1 THE RULES OF SYS::SYSLOG
 
 I<The First Rule of Sys::Syslog is:>
 You do not call C<setlogsock>.
 
 I<The Second Rule of Sys::Syslog is:>
 You B<do not> call C<setlogsock>.
 
 I<The Third Rule of Sys::Syslog is:>
 The program crashes, C<die>s, calls C<closelog>, the log is over.
 
 I<The Fourth Rule of Sys::Syslog is:>
 One facility, one priority.
 
 I<The Fifth Rule of Sys::Syslog is:>
 One log at a time.
 
 I<The Sixth Rule of Sys::Syslog is:>
 No C<syslog> before C<openlog>.
 
 I<The Seventh Rule of Sys::Syslog is:>
 Logs will go on as long as they have to. 
 
 I<The Eighth, and Final Rule of Sys::Syslog is:>
 If this is your first use of Sys::Syslog, you must read the doc.
 
 
 =head1 EXAMPLES
 
 An example:
 
     openlog($program, 'cons,pid', 'user');
     syslog('info', '%s', 'this is another test');
     syslog('mail|warning', 'this is a better test: %d', time);
     closelog();
 
     syslog('debug', 'this is the last test');
 
 Another example:
 
     openlog("$program $$", 'ndelay', 'user');
     syslog('notice', 'fooprogram: this is really done');
 
 Example of use of C<%m>:
 
     $! = 55;
     syslog('info', 'problem was %m');   # %m == $! in syslog(3)
 
 Log to UDP port on C<$remotehost> instead of logging locally:
 
     setlogsock("udp", $remotehost);
     openlog($program, 'ndelay', 'user');
     syslog('info', 'something happened over here');
 
 
 =head1 CONSTANTS
 
 =head2 Facilities
 
 =over 4
 
 =item *
 
 C<LOG_AUDIT> - audit daemon (IRIX); falls back to C<LOG_AUTH>
 
 =item *
 
 C<LOG_AUTH> - security/authorization messages
 
 =item *
 
 C<LOG_AUTHPRIV> - security/authorization messages (private)
 
 =item *
 
 C<LOG_CONSOLE> - C</dev/console> output (FreeBSD); falls back to C<LOG_USER>
 
 =item *
 
 C<LOG_CRON> - clock daemons (B<cron> and B<at>)
 
 =item *
 
 C<LOG_DAEMON> - system daemons without separate facility value
 
 =item *
 
 C<LOG_FTP> - FTP daemon
 
 =item *
 
 C<LOG_KERN> - kernel messages
 
 =item *
 
 C<LOG_INSTALL> - installer subsystem (Mac OS X); falls back to C<LOG_USER>
 
 =item *
 
 C<LOG_LAUNCHD> - launchd - general bootstrap daemon (Mac OS X);
 falls back to C<LOG_DAEMON>
 
 =item *
 
 C<LOG_LFMT> - logalert facility; falls back to C<LOG_USER>
 
 =item *
 
 C<LOG_LOCAL0> through C<LOG_LOCAL7> - reserved for local use
 
 =item *
 
 C<LOG_LPR> - line printer subsystem
 
 =item *
 
 C<LOG_MAIL> - mail subsystem
 
 =item *
 
 C<LOG_NETINFO> - NetInfo subsystem (Mac OS X); falls back to C<LOG_DAEMON>
 
 =item *
 
 C<LOG_NEWS> - USENET news subsystem
 
 =item *
 
 C<LOG_NTP> - NTP subsystem (FreeBSD, NetBSD); falls back to C<LOG_DAEMON>
 
 =item *
 
 C<LOG_RAS> - Remote Access Service (VPN / PPP) (Mac OS X);
 falls back to C<LOG_AUTH>
 
 =item *
 
 C<LOG_REMOTEAUTH> - remote authentication/authorization (Mac OS X);
 falls back to C<LOG_AUTH>
 
 =item *
 
 C<LOG_SECURITY> - security subsystems (firewalling, etc.) (FreeBSD);
 falls back to C<LOG_AUTH>
 
 =item *
 
 C<LOG_SYSLOG> - messages generated internally by B<syslogd>
 
 =item *
 
 C<LOG_USER> (default) - generic user-level messages
 
 =item *
 
 C<LOG_UUCP> - UUCP subsystem
 
 =back
 
 
 =head2 Levels
 
 =over 4
 
 =item *
 
 C<LOG_EMERG> - system is unusable
 
 =item *
 
 C<LOG_ALERT> - action must be taken immediately
 
 =item *
 
 C<LOG_CRIT> - critical conditions
 
 =item *
 
 C<LOG_ERR> - error conditions
 
 =item *
 
 C<LOG_WARNING> - warning conditions
 
 =item *
 
 C<LOG_NOTICE> - normal, but significant, condition
 
 =item *
 
 C<LOG_INFO> - informational message
 
 =item *
 
 C<LOG_DEBUG> - debug-level message
 
 =back
 
 
 =head1 DIAGNOSTICS
 
 =over
 
 =item C<Invalid argument passed to setlogsock>
 
 B<(F)> You gave C<setlogsock()> an invalid value for C<$sock_type>. 
 
 =item C<eventlog passed to setlogsock, but no Win32 API available>
 
 B<(W)> You asked C<setlogsock()> to use the Win32 event logger but the 
 operating system running the program isn't Win32 or does not provides Win32
 compatible facilities.
 
 =item C<no connection to syslog available>
 
 B<(F)> C<syslog()> failed to connect to the specified socket.
 
 =item C<stream passed to setlogsock, but %s is not writable>
 
 B<(W)> You asked C<setlogsock()> to use a stream socket, but the given 
 path is not writable. 
 
 =item C<stream passed to setlogsock, but could not find any device>
 
 B<(W)> You asked C<setlogsock()> to use a stream socket, but didn't 
 provide a path, and C<Sys::Syslog> was unable to find an appropriate one.
 
 =item C<tcp passed to setlogsock, but tcp service unavailable>
 
 B<(W)> You asked C<setlogsock()> to use a TCP socket, but the service 
 is not available on the system. 
 
 =item C<syslog: expecting argument %s>
 
 B<(F)> You forgot to give C<syslog()> the indicated argument.
 
 =item C<syslog: invalid level/facility: %s>
 
 B<(F)> You specified an invalid level or facility.
 
 =item C<syslog: too many levels given: %s>
 
 B<(F)> You specified too many levels. 
 
 =item C<syslog: too many facilities given: %s>
 
 B<(F)> You specified too many facilities. 
 
 =item C<syslog: level must be given>
 
 B<(F)> You forgot to specify a level.
 
 =item C<udp passed to setlogsock, but udp service unavailable>
 
 B<(W)> You asked C<setlogsock()> to use a UDP socket, but the service 
 is not available on the system. 
 
 =item C<unix passed to setlogsock, but path not available>
 
 B<(W)> You asked C<setlogsock()> to use a UNIX socket, but C<Sys::Syslog> 
 was unable to find an appropriate an appropriate device.
 
 =back
 
 
 =head1 HISTORY
 
 C<Sys::Syslog> is a core module, part of the standard Perl distribution
 since 1990.  At this time, modules as we know them didn't exist, the
 Perl library was a collection of F<.pl> files, and the one for sending
 syslog messages with was simply F<lib/syslog.pl>, included with Perl 3.0.
 It was converted as a module with Perl 5.0, but had a version number
 only starting with Perl 5.6.  Here is a small table with the matching
 Perl and C<Sys::Syslog> versions.
 
     Sys::Syslog     Perl
     -----------     ----
        undef        5.0.0 ~ 5.5.4
        0.01         5.6.*
        0.03         5.8.0
        0.04         5.8.1, 5.8.2, 5.8.3
        0.05         5.8.4, 5.8.5, 5.8.6
        0.06         5.8.7
        0.13         5.8.8
        0.22         5.10.0
        0.27         5.8.9, 5.10.1 ~ 5.14.2
        0.29         5.16.0, 5.16.1
 
 
 =head1 SEE ALSO
 
 =head2 Other modules
 
 L<Log::Log4perl> - Perl implementation of the Log4j API
 
 L<Log::Dispatch> - Dispatches messages to one or more outputs
 
 L<Log::Report> - Report a problem, with exceptions and language support
 
 =head2 Manual Pages
 
 L<syslog(3)>
 
 SUSv3 issue 6, IEEE Std 1003.1, 2004 edition, 
 L<http://www.opengroup.org/onlinepubs/000095399/basedefs/syslog.h.html>
 
 GNU C Library documentation on syslog, 
 L<http://www.gnu.org/software/libc/manual/html_node/Syslog.html>
 
 Solaris 10 documentation on syslog, 
 L<http://docs.sun.com/app/docs/doc/816-5168/syslog-3c?a=view>
 
 Mac OS X documentation on syslog,
 L<http://developer.apple.com/documentation/Darwin/Reference/ManPages/man3/syslog.3.html>
 
 IRIX 6.5 documentation on syslog,
 L<http://techpubs.sgi.com/library/tpl/cgi-bin/getdoc.cgi?coll=0650&db=man&fname=3c+syslog>
 
 AIX 5L 5.3 documentation on syslog, 
 L<http://publib.boulder.ibm.com/infocenter/pseries/v5r3/index.jsp?topic=/com.ibm.aix.basetechref/doc/basetrf2/syslog.htm>
 
 HP-UX 11i documentation on syslog, 
 L<http://docs.hp.com/en/B2355-60130/syslog.3C.html>
 
 Tru64 5.1 documentation on syslog, 
 L<http://h30097.www3.hp.com/docs/base_doc/DOCUMENTATION/V51_HTML/MAN/MAN3/0193____.HTM>
 
 Stratus VOS 15.1, 
 L<http://stratadoc.stratus.com/vos/15.1.1/r502-01/wwhelp/wwhimpl/js/html/wwhelp.htm?context=r502-01&file=ch5r502-01bi.html>
 
 =head2 RFCs
 
 I<RFC 3164 - The BSD syslog Protocol>, L<http://www.faqs.org/rfcs/rfc3164.html>
 -- Please note that this is an informational RFC, and therefore does not 
 specify a standard of any kind.
 
 I<RFC 3195 - Reliable Delivery for syslog>, L<http://www.faqs.org/rfcs/rfc3195.html>
 
 =head2 Articles
 
 I<Syslogging with Perl>, L<http://lexington.pm.org/meetings/022001.html>
 
 =head2 Event Log
 
 Windows Event Log,
 L<http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wes/wes/windows_event_log.asp>
 
 
 =head1 AUTHORS & ACKNOWLEDGEMENTS
 
 Tom Christiansen E<lt>F<tchrist (at) perl.com>E<gt> and Larry Wall
 E<lt>F<larry (at) wall.org>E<gt>.
 
 UNIX domain sockets added by Sean Robinson
 E<lt>F<robinson_s (at) sc.maricopa.edu>E<gt> with support from Tim Bunce 
 E<lt>F<Tim.Bunce (at) ig.co.uk>E<gt> and the C<perl5-porters> mailing list.
 
 Dependency on F<syslog.ph> replaced with XS code by Tom Hughes
 E<lt>F<tom (at) compton.nu>E<gt>.
 
 Code for C<constant()>s regenerated by Nicholas Clark E<lt>F<nick (at) ccl4.org>E<gt>.
 
 Failover to different communication modes by Nick Williams
 E<lt>F<Nick.Williams (at) morganstanley.com>E<gt>.
 
 Extracted from core distribution for publishing on the CPAN by 
 SE<eacute>bastien Aperghis-Tramoni E<lt>sebastien (at) aperghis.netE<gt>.
 
 XS code for using native C functions borrowed from C<L<Unix::Syslog>>, 
 written by Marcus Harnisch E<lt>F<marcus.harnisch (at) gmx.net>E<gt>.
 
 Yves Orton suggested and helped for making C<Sys::Syslog> use the native 
 event logger under Win32 systems.
 
 Jerry D. Hedden and Reini Urban provided greatly appreciated help to 
 debug and polish C<Sys::Syslog> under Cygwin.
 
 
 =head1 BUGS
 
 Please report any bugs or feature requests to
 C<bug-sys-syslog (at) rt.cpan.org>, or through the web interface at
 L<http://rt.cpan.org/Public/Dist/Display.html?Name=Sys-Syslog>.
 I will be notified, and then you'll automatically be notified of progress on
 your bug as I make changes.
 
 
 =head1 SUPPORT
 
 You can find documentation for this module with the perldoc command.
 
     perldoc Sys::Syslog
 
 You can also look for information at:
 
 =over 4
 
 =item * AnnoCPAN: Annotated CPAN documentation
 
 L<http://annocpan.org/dist/Sys-Syslog>
 
 =item * CPAN Ratings
 
 L<http://cpanratings.perl.org/d/Sys-Syslog>
 
 =item * RT: CPAN's request tracker
 
 L<http://rt.cpan.org/Dist/Display.html?Queue=Sys-Syslog>
 
 =item * Search CPAN
 
 L<http://search.cpan.org/dist/Sys-Syslog/>
 
 =item * MetaCPAN
 
 L<https://metacpan.org/module/Sys::Syslog>
 
 =item * Perl Documentation
 
 L<http://perldoc.perl.org/Sys/Syslog.html>
 
 =back
 
 
 =head1 COPYRIGHT
 
 Copyright (C) 1990-2012 by Larry Wall and others.
 
 
 =head1 LICENSE
 
 This program is free software; you can redistribute it and/or modify it
 under the same terms as Perl itself.
 
 =cut
 
 =begin comment
 
 Notes for the future maintainer (even if it's still me..)
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
 Using Google Code Search, I search who on Earth was relying on $host being 
 public. It found 5 hits: 
 
 * First was inside Indigo Star Perl2exe documentation. Just an old version 
 of Sys::Syslog. 
 
 
 * One real hit was inside DalWeathDB, a weather related program. It simply 
 does a 
 
     $Sys::Syslog::host = '127.0.0.1';
 
 - L<http://www.gallistel.net/nparker/weather/code/>
 
 
 * Two hits were in TPC, a fax server thingy. It does a 
 
     $Sys::Syslog::host = $TPC::LOGHOST;
 
 but also has this strange piece of code:
 
     # work around perl5.003 bug
     sub Sys::Syslog::hostname {}
 
 I don't know what bug the author referred to.
 
 - L<http://www.tpc.int/>
 - L<ftp://ftp-usa.tpc.int/pub/tpc/server/UNIX/>
 
 
 * Last hit was in Filefix, which seems to be a FIDOnet mail program (!).
 This one does not use $host, but has the following piece of code:
 
     sub Sys::Syslog::hostname
     {
         use Sys::Hostname;
         return hostname;
     }
 
 I guess this was a more elaborate form of the previous bit, maybe because 
 of a bug in Sys::Syslog back then?
 
 - L<ftp://ftp.kiae.su/pub/unix/fido/>
 
 
 Links
 -----
 Linux Fast-STREAMS
 - L<http://www.openss7.org/streams.html>
 
 II12021: SYSLOGD HOWTO TCPIPINFO (z/OS, OS/390, MVS)
 - L<http://www-1.ibm.com/support/docview.wss?uid=isg1II12021>
 
 Getting the most out of the Event Viewer
 - L<http://www.codeproject.com/dotnet/evtvwr.asp?print=true>
 
 Log events to the Windows NT Event Log with JNI
 - L<http://www.javaworld.com/javaworld/jw-09-2001/jw-0928-ntmessages.html>
 
 =end comment
 
### Term/ANSIColor.pm ###
 # Term::ANSIColor -- Color screen output using ANSI escape sequences.
 #
 # Copyright 1996, 1997, 1998, 2000, 2001, 2002, 2005, 2006, 2008, 2009, 2010,
 #     2011, 2012, 2013, 2014 Russ Allbery <rra@cpan.org>
 # Copyright 1996 Zenin
 # Copyright 2012 Kurt Starsinic <kstarsinic@gmail.com>
 #
 # This program is free software; you may redistribute it and/or modify it
 # under the same terms as Perl itself.
 #
 # PUSH/POP support submitted 2007 by openmethods.com voice solutions
 #
 # Ah, September, when the sysadmins turn colors and fall off the trees....
 #                               -- Dave Van Domelen
 
 ##############################################################################
 # Modules and declarations
 ##############################################################################
 
 package Term::ANSIColor;
 
 use 5.006;
 use strict;
 use warnings;
 
 use Carp qw(croak);
 use Exporter ();
 
 # use Exporter plus @ISA instead of use base for 5.6 compatibility.
 ## no critic (ClassHierarchies::ProhibitExplicitISA)
 
 # Declare variables that should be set in BEGIN for robustness.
 ## no critic (Modules::ProhibitAutomaticExportation)
 our (@EXPORT, @EXPORT_OK, %EXPORT_TAGS, @ISA, $VERSION);
 
 # We use autoloading, which sets this variable to the name of the called sub.
 our $AUTOLOAD;
 
 # Set $VERSION and everything export-related in a BEGIN block for robustness
 # against circular module loading (not that we load any modules, but
 # consistency is good).
 BEGIN {
     $VERSION = '4.03';
 
     # All of the basic supported constants, used in %EXPORT_TAGS.
     my @colorlist = qw(
       CLEAR           RESET             BOLD            DARK
       FAINT           ITALIC            UNDERLINE       UNDERSCORE
       BLINK           REVERSE           CONCEALED
 
       BLACK           RED               GREEN           YELLOW
       BLUE            MAGENTA           CYAN            WHITE
       ON_BLACK        ON_RED            ON_GREEN        ON_YELLOW
       ON_BLUE         ON_MAGENTA        ON_CYAN         ON_WHITE
 
       BRIGHT_BLACK    BRIGHT_RED        BRIGHT_GREEN    BRIGHT_YELLOW
       BRIGHT_BLUE     BRIGHT_MAGENTA    BRIGHT_CYAN     BRIGHT_WHITE
       ON_BRIGHT_BLACK ON_BRIGHT_RED     ON_BRIGHT_GREEN ON_BRIGHT_YELLOW
       ON_BRIGHT_BLUE  ON_BRIGHT_MAGENTA ON_BRIGHT_CYAN  ON_BRIGHT_WHITE
     );
 
     # 256-color constants, used in %EXPORT_TAGS.
     my @colorlist256 = (
         (map { ("ANSI$_", "ON_ANSI$_") } 0 .. 15),
         (map { ("GREY$_", "ON_GREY$_") } 0 .. 23),
     );
     for my $r (0 .. 5) {
         for my $g (0 .. 5) {
             push(@colorlist256, map { ("RGB$r$g$_", "ON_RGB$r$g$_") } 0 .. 5);
         }
     }
 
     # Exported symbol configuration.
     @ISA         = qw(Exporter);
     @EXPORT      = qw(color colored);
     @EXPORT_OK   = qw(uncolor colorstrip colorvalid coloralias);
     %EXPORT_TAGS = (
         constants    => \@colorlist,
         constants256 => \@colorlist256,
         pushpop      => [@colorlist, qw(PUSHCOLOR POPCOLOR LOCALCOLOR)],
     );
     Exporter::export_ok_tags('pushpop', 'constants256');
 }
 
 ##############################################################################
 # Package variables
 ##############################################################################
 
 # If this is set, any color changes will implicitly push the current color
 # onto the stack and then pop it at the end of the constant sequence, just as
 # if LOCALCOLOR were used.
 our $AUTOLOCAL;
 
 # Caller sets this to force a reset at the end of each constant sequence.
 our $AUTORESET;
 
 # Caller sets this to force colors to be reset at the end of each line.
 our $EACHLINE;
 
 ##############################################################################
 # Internal data structures
 ##############################################################################
 
 # This module does quite a bit of initialization at the time it is first
 # loaded, primarily to set up the package-global %ATTRIBUTES hash.  The
 # entries for 256-color names are easier to handle programmatically, and
 # custom colors are also imported from the environment if any are set.
 
 # All basic supported attributes, including aliases.
 #<<<
 our %ATTRIBUTES = (
     'clear'          => 0,
     'reset'          => 0,
     'bold'           => 1,
     'dark'           => 2,
     'faint'          => 2,
     'italic'         => 3,
     'underline'      => 4,
     'underscore'     => 4,
     'blink'          => 5,
     'reverse'        => 7,
     'concealed'      => 8,
 
     'black'          => 30,   'on_black'          => 40,
     'red'            => 31,   'on_red'            => 41,
     'green'          => 32,   'on_green'          => 42,
     'yellow'         => 33,   'on_yellow'         => 43,
     'blue'           => 34,   'on_blue'           => 44,
     'magenta'        => 35,   'on_magenta'        => 45,
     'cyan'           => 36,   'on_cyan'           => 46,
     'white'          => 37,   'on_white'          => 47,
 
     'bright_black'   => 90,   'on_bright_black'   => 100,
     'bright_red'     => 91,   'on_bright_red'     => 101,
     'bright_green'   => 92,   'on_bright_green'   => 102,
     'bright_yellow'  => 93,   'on_bright_yellow'  => 103,
     'bright_blue'    => 94,   'on_bright_blue'    => 104,
     'bright_magenta' => 95,   'on_bright_magenta' => 105,
     'bright_cyan'    => 96,   'on_bright_cyan'    => 106,
     'bright_white'   => 97,   'on_bright_white'   => 107,
 );
 #>>>
 
 # Generating the 256-color codes involves a lot of codes and offsets that are
 # not helped by turning them into constants.
 
 # The first 16 256-color codes are duplicates of the 16 ANSI colors,
 # included for completeness.
 for my $code (0 .. 15) {
     $ATTRIBUTES{"ansi$code"}    = "38;5;$code";
     $ATTRIBUTES{"on_ansi$code"} = "48;5;$code";
 }
 
 # 256-color RGB colors.  Red, green, and blue can each be values 0 through 5,
 # and the resulting 216 colors start with color 16.
 for my $r (0 .. 5) {
     for my $g (0 .. 5) {
         for my $b (0 .. 5) {
             my $code = 16 + (6 * 6 * $r) + (6 * $g) + $b;
             $ATTRIBUTES{"rgb$r$g$b"}    = "38;5;$code";
             $ATTRIBUTES{"on_rgb$r$g$b"} = "48;5;$code";
         }
     }
 }
 
 # The last 256-color codes are 24 shades of grey.
 for my $n (0 .. 23) {
     my $code = $n + 232;
     $ATTRIBUTES{"grey$n"}    = "38;5;$code";
     $ATTRIBUTES{"on_grey$n"} = "48;5;$code";
 }
 
 # Reverse lookup.  Alphabetically first name for a sequence is preferred.
 our %ATTRIBUTES_R;
 for my $attr (reverse sort keys %ATTRIBUTES) {
     $ATTRIBUTES_R{ $ATTRIBUTES{$attr} } = $attr;
 }
 
 # Import any custom colors set in the environment.
 our %ALIASES;
 if (exists $ENV{ANSI_COLORS_ALIASES}) {
     my $spec = $ENV{ANSI_COLORS_ALIASES};
     $spec =~ s{\s+}{}xmsg;
 
     # Error reporting here is an interesting question.  Use warn rather than
     # carp because carp would report the line of the use or require, which
     # doesn't help anyone understand what's going on, whereas seeing this code
     # will be more helpful.
     ## no critic (ErrorHandling::RequireCarping)
     for my $definition (split m{,}xms, $spec) {
         my ($new, $old) = split m{=}xms, $definition, 2;
         if (!$new || !$old) {
             warn qq{Bad color mapping "$definition"};
         } else {
             my $result = eval { coloralias($new, $old) };
             if (!$result) {
                 my $error = $@;
                 $error =~ s{ [ ] at [ ] .* }{}xms;
                 warn qq{$error in "$definition"};
             }
         }
     }
 }
 
 # Stores the current color stack maintained by PUSHCOLOR and POPCOLOR.  This
 # is global and therefore not threadsafe.
 our @COLORSTACK;
 
 ##############################################################################
 # Implementation (constant form)
 ##############################################################################
 
 # Time to have fun!  We now want to define the constant subs, which are named
 # the same as the attributes above but in all caps.  Each constant sub needs
 # to act differently depending on whether $AUTORESET is set.  Without
 # autoreset:
 #
 #     BLUE "text\n"  ==>  "\e[34mtext\n"
 #
 # If $AUTORESET is set, we should instead get:
 #
 #     BLUE "text\n"  ==>  "\e[34mtext\n\e[0m"
 #
 # The sub also needs to handle the case where it has no arguments correctly.
 # Maintaining all of this as separate subs would be a major nightmare, as well
 # as duplicate the %ATTRIBUTES hash, so instead we define an AUTOLOAD sub to
 # define the constant subs on demand.  To do that, we check the name of the
 # called sub against the list of attributes, and if it's an all-caps version
 # of one of them, we define the sub on the fly and then run it.
 #
 # If the environment variable ANSI_COLORS_DISABLED is set to a true value,
 # just return the arguments without adding any escape sequences.  This is to
 # make it easier to write scripts that also work on systems without any ANSI
 # support, like Windows consoles.
 #
 ## no critic (ClassHierarchies::ProhibitAutoloading)
 ## no critic (Subroutines::RequireArgUnpacking)
 sub AUTOLOAD {
     my ($sub, $attr) = $AUTOLOAD =~ m{ \A ([\w:]*::([[:upper:]\d_]+)) \z }xms;
 
     # Check if we were called with something that doesn't look like an
     # attribute.
     if (!($attr && defined($ATTRIBUTES{ lc $attr }))) {
         croak("undefined subroutine &$AUTOLOAD called");
     }
 
     # If colors are disabled, just return the input.  Do this without
     # installing a sub for (marginal, unbenchmarked) speed.
     if ($ENV{ANSI_COLORS_DISABLED}) {
         return join(q{}, @_);
     }
 
     # We've untainted the name of the sub.
     $AUTOLOAD = $sub;
 
     # Figure out the ANSI string to set the desired attribute.
     my $escape = "\e[" . $ATTRIBUTES{ lc $attr } . 'm';
 
     # Save the current value of $@.  We can't just use local since we want to
     # restore it before dispatching to the newly-created sub.  (The caller may
     # be colorizing output that includes $@.)
     my $eval_err = $@;
 
     # Generate the constant sub, which should still recognize some of our
     # package variables.  Use string eval to avoid a dependency on
     # Sub::Install, even though it makes it somewhat less readable.
     ## no critic (BuiltinFunctions::ProhibitStringyEval)
     ## no critic (ValuesAndExpressions::ProhibitImplicitNewlines)
     my $eval_result = eval qq{
         sub $AUTOLOAD {
             if (\$ENV{ANSI_COLORS_DISABLED}) {
                 return join(q{}, \@_);
             } elsif (\$AUTOLOCAL && \@_) {
                 return PUSHCOLOR('$escape') . join(q{}, \@_) . POPCOLOR;
             } elsif (\$AUTORESET && \@_) {
                 return '$escape' . join(q{}, \@_) . "\e[0m";
             } else {
                 return '$escape' . join(q{}, \@_);
             }
         }
         1;
     };
 
     # Failure is an internal error, not a problem with the caller.
     ## no critic (ErrorHandling::RequireCarping)
     if (!$eval_result) {
         die "failed to generate constant $attr: $@";
     }
 
     # Restore $@.
     ## no critic (Variables::RequireLocalizedPunctuationVars)
     $@ = $eval_err;
 
     # Dispatch to the newly-created sub.
     ## no critic (References::ProhibitDoubleSigils)
     goto &$AUTOLOAD;
 }
 ## use critic (Subroutines::RequireArgUnpacking)
 
 # Append a new color to the top of the color stack and return the top of
 # the stack.
 #
 # $text - Any text we're applying colors to, with color escapes prepended
 #
 # Returns: The text passed in
 sub PUSHCOLOR {
     my (@text) = @_;
     my $text = join(q{}, @text);
 
     # Extract any number of color-setting escape sequences from the start of
     # the string.
     my ($color) = $text =~ m{ \A ( (?:\e\[ [\d;]+ m)+ ) }xms;
 
     # If we already have a stack, append these escapes to the set from the top
     # of the stack.  This way, each position in the stack stores the complete
     # enabled colors for that stage, at the cost of some potential
     # inefficiency.
     if (@COLORSTACK) {
         $color = $COLORSTACK[-1] . $color;
     }
 
     # Push the color onto the stack.
     push(@COLORSTACK, $color);
     return $text;
 }
 
 # Pop the color stack and return the new top of the stack (or reset, if
 # the stack is empty).
 #
 # @text - Any text we're applying colors to
 #
 # Returns: The concatenation of @text prepended with the new stack color
 sub POPCOLOR {
     my (@text) = @_;
     pop(@COLORSTACK);
     if (@COLORSTACK) {
         return $COLORSTACK[-1] . join(q{}, @text);
     } else {
         return RESET(@text);
     }
 }
 
 # Surround arguments with a push and a pop.  The effect will be to reset the
 # colors to whatever was on the color stack before this sequence of colors was
 # applied.
 #
 # @text - Any text we're applying colors to
 #
 # Returns: The concatenation of the text and the proper color reset sequence.
 sub LOCALCOLOR {
     my (@text) = @_;
     return PUSHCOLOR(join(q{}, @text)) . POPCOLOR();
 }
 
 ##############################################################################
 # Implementation (attribute string form)
 ##############################################################################
 
 # Return the escape code for a given set of color attributes.
 #
 # @codes - A list of possibly space-separated color attributes
 #
 # Returns: The escape sequence setting those color attributes
 #          undef if no escape sequences were given
 #  Throws: Text exception for any invalid attribute
 sub color {
     my (@codes) = @_;
     @codes = map { split } @codes;
 
     # Return the empty string if colors are disabled.
     if ($ENV{ANSI_COLORS_DISABLED}) {
         return q{};
     }
 
     # Build the attribute string from semicolon-separated numbers.
     my $attribute = q{};
     for my $code (@codes) {
         $code = lc($code);
         if (defined($ATTRIBUTES{$code})) {
             $attribute .= $ATTRIBUTES{$code} . q{;};
         } elsif (defined($ALIASES{$code})) {
             $attribute .= $ALIASES{$code} . q{;};
         } else {
             croak("Invalid attribute name $code");
         }
     }
 
     # We added one too many semicolons for simplicity.  Remove the last one.
     chop($attribute);
 
     # Return undef if there were no attributes.
     return ($attribute ne q{}) ? "\e[${attribute}m" : undef;
 }
 
 # Return a list of named color attributes for a given set of escape codes.
 # Escape sequences can be given with or without enclosing "\e[" and "m".  The
 # empty escape sequence '' or "\e[m" gives an empty list of attrs.
 #
 # There is one special case.  256-color codes start with 38 or 48, followed by
 # a 5 and then the 256-color code.
 #
 # @escapes - A list of escape sequences or escape sequence numbers
 #
 # Returns: An array of attribute names corresponding to those sequences
 #  Throws: Text exceptions on invalid escape sequences or unknown colors
 sub uncolor {
     my (@escapes) = @_;
     my (@nums, @result);
 
     # Walk the list of escapes and build a list of attribute numbers.
     for my $escape (@escapes) {
         $escape =~ s{ \A \e\[ }{}xms;
         $escape =~ s{ m \z }   {}xms;
         my ($attrs) = $escape =~ m{ \A ((?:\d+;)* \d*) \z }xms;
         if (!defined($attrs)) {
             croak("Bad escape sequence $escape");
         }
 
         # Pull off 256-color codes (38;5;n or 48;5;n) as a unit.
         push(@nums, $attrs =~ m{ ( 0*[34]8;0*5;\d+ | \d+ ) (?: ; | \z ) }xmsg);
     }
 
     # Now, walk the list of numbers and convert them to attribute names.
     # Strip leading zeroes from any of the numbers.  (xterm, at least, allows
     # leading zeroes to be added to any number in an escape sequence.)
     for my $num (@nums) {
         $num =~ s{ ( \A | ; ) 0+ (\d) }{$1$2}xmsg;
         my $name = $ATTRIBUTES_R{$num};
         if (!defined($name)) {
             croak("No name for escape sequence $num");
         }
         push(@result, $name);
     }
 
     # Return the attribute names.
     return @result;
 }
 
 # Given a string and a set of attributes, returns the string surrounded by
 # escape codes to set those attributes and then clear them at the end of the
 # string.  The attributes can be given either as an array ref as the first
 # argument or as a list as the second and subsequent arguments.
 #
 # If $EACHLINE is set, insert a reset before each occurrence of the string
 # $EACHLINE and the starting attribute code after the string $EACHLINE, so
 # that no attribute crosses line delimiters (this is often desirable if the
 # output is to be piped to a pager or some other program).
 #
 # $first - An anonymous array of attributes or the text to color
 # @rest  - The text to color or the list of attributes
 #
 # Returns: The text, concatenated if necessary, surrounded by escapes to set
 #          the desired colors and reset them afterwards
 #  Throws: Text exception on invalid attributes
 sub colored {
     my ($first, @rest) = @_;
     my ($string, @codes);
     if (ref($first) && ref($first) eq 'ARRAY') {
         @codes = @{$first};
         $string = join(q{}, @rest);
     } else {
         $string = $first;
         @codes  = @rest;
     }
 
     # Return the string unmolested if colors are disabled.
     if ($ENV{ANSI_COLORS_DISABLED}) {
         return $string;
     }
 
     # Find the attribute string for our colors.
     my $attr = color(@codes);
 
     # If $EACHLINE is defined, split the string on line boundaries, suppress
     # empty segments, and then colorize each of the line sections.
     if (defined($EACHLINE)) {
         my @text = map { ($_ ne $EACHLINE) ? $attr . $_ . "\e[0m" : $_ }
           grep { length($_) > 0 }
           split(m{ (\Q$EACHLINE\E) }xms, $string);
         return join(q{}, @text);
     } else {
         return $attr . $string . "\e[0m";
     }
 }
 
 # Define a new color alias, or return the value of an existing alias.
 #
 # $alias - The color alias to define
 # $color - The standard color the alias will correspond to (optional)
 #
 # Returns: The standard color value of the alias
 #          undef if one argument was given and the alias was not recognized
 #  Throws: Text exceptions for invalid alias names, attempts to use a
 #          standard color name as an alias, or an unknown standard color name
 sub coloralias {
     my ($alias, $color) = @_;
     if (!defined($color)) {
         if (!exists $ALIASES{$alias}) {
             return;
         } else {
             return $ATTRIBUTES_R{ $ALIASES{$alias} };
         }
     }
     if ($alias !~ m{ \A [\w._-]+ \z }xms) {
         croak(qq{Invalid alias name "$alias"});
     } elsif ($ATTRIBUTES{$alias}) {
         croak(qq{Cannot alias standard color "$alias"});
     } elsif (!exists $ATTRIBUTES{$color}) {
         croak(qq{Invalid attribute name "$color"});
     }
     $ALIASES{$alias} = $ATTRIBUTES{$color};
     return $color;
 }
 
 # Given a string, strip the ANSI color codes out of that string and return the
 # result.  This removes only ANSI color codes, not movement codes and other
 # escape sequences.
 #
 # @string - The list of strings to sanitize
 #
 # Returns: (array)  The strings stripped of ANSI color escape sequences
 #          (scalar) The same, concatenated
 sub colorstrip {
     my (@string) = @_;
     for my $string (@string) {
         $string =~ s{ \e\[ [\d;]* m }{}xmsg;
     }
     return wantarray ? @string : join(q{}, @string);
 }
 
 # Given a list of color attributes (arguments for color, for instance), return
 # true if they're all valid or false if any of them are invalid.
 #
 # @codes - A list of color attributes, possibly space-separated
 #
 # Returns: True if all the attributes are valid, false otherwise.
 sub colorvalid {
     my (@codes) = @_;
     @codes = map { split(q{ }, lc($_)) } @codes;
     for my $code (@codes) {
         if (!defined($ATTRIBUTES{$code}) && !defined($ALIASES{$code})) {
             return;
         }
     }
     return 1;
 }
 
 ##############################################################################
 # Module return value and documentation
 ##############################################################################
 
 # Ensure we evaluate to true.
 1;
 __END__
 
 =head1 NAME
 
 Term::ANSIColor - Color screen output using ANSI escape sequences
 
 =for stopwords
 cyan colorize namespace runtime TMTOWTDI cmd.exe cmd.exe. 4nt.exe. 4nt.exe
 command.com NT ESC Delvare SSH OpenSSH aixterm ECMA-048 Fraktur overlining
 Zenin reimplemented Allbery PUSHCOLOR POPCOLOR LOCALCOLOR openmethods.com
 openmethods.com. grey ATTR urxvt mistyped prepending Bareword filehandle
 Cygwin Starsinic aterm rxvt CPAN RGB Solarized Whitespace alphanumerics
 undef
 
 =head1 SYNOPSIS
 
     use Term::ANSIColor;
     print color('bold blue');
     print "This text is bold blue.\n";
     print color('reset');
     print "This text is normal.\n";
     print colored("Yellow on magenta.", 'yellow on_magenta'), "\n";
     print "This text is normal.\n";
     print colored(['yellow on_magenta'], 'Yellow on magenta.', "\n");
     print colored(['red on_bright_yellow'], 'Red on bright yellow.', "\n");
     print colored(['bright_red on_black'], 'Bright red on black.', "\n");
     print "\n";
 
     # Map escape sequences back to color names.
     use Term::ANSIColor 1.04 qw(uncolor);
     my $names = uncolor('01;31');
     print join(q{ }, @{$names}), "\n";
 
     # Strip all color escape sequences.
     use Term::ANSIColor 2.01 qw(colorstrip);
     print colorstrip("\e[1mThis is bold\e[0m"), "\n";
 
     # Determine whether a color is valid.
     use Term::ANSIColor 2.02 qw(colorvalid);
     my $valid = colorvalid('blue bold', 'on_magenta');
     print "Color string is ", $valid ? "valid\n" : "invalid\n";
 
     # Create new aliases for colors.
     use Term::ANSIColor 4.00 qw(coloralias);
     coloralias('alert', 'red');
     print "Alert is ", coloralias('alert'), "\n";
     print colored("This is in red.", 'alert'), "\n";
 
     use Term::ANSIColor qw(:constants);
     print BOLD, BLUE, "This text is in bold blue.\n", RESET;
 
     use Term::ANSIColor qw(:constants);
     {
         local $Term::ANSIColor::AUTORESET = 1;
         print BOLD BLUE "This text is in bold blue.\n";
         print "This text is normal.\n";
     }
 
     use Term::ANSIColor 2.00 qw(:pushpop);
     print PUSHCOLOR RED ON_GREEN "This text is red on green.\n";
     print PUSHCOLOR BRIGHT_BLUE "This text is bright blue on green.\n";
     print RESET BRIGHT_BLUE "This text is just bright blue.\n";
     print POPCOLOR "Back to red on green.\n";
     print LOCALCOLOR GREEN ON_BLUE "This text is green on blue.\n";
     print "This text is red on green.\n";
     {
         local $Term::ANSIColor::AUTOLOCAL = 1;
         print ON_BLUE "This text is red on blue.\n";
         print "This text is red on green.\n";
     }
     print POPCOLOR "Back to whatever we started as.\n";
 
 =head1 DESCRIPTION
 
 This module has two interfaces, one through color() and colored() and the
 other through constants.  It also offers the utility functions uncolor(),
 colorstrip(), colorvalid(), and coloralias(), which have to be explicitly
 imported to be used (see L</SYNOPSIS>).
 
 See L</COMPATIBILITY> for the versions of Term::ANSIColor that introduced
 particular features and the versions of Perl that included them.
 
 =head2 Supported Colors
 
 Terminal emulators that support color divide into two types: ones that
 support only eight colors, ones that support sixteen, and ones that
 support 256.  This module provides the ANSI escape codes all of them.
 These colors are referred to as ANSI colors 0 through 7 (normal), 8
 through 15 (16-color), and 16 through 255 (256-color).
 
 Unfortunately, interpretation of colors 0 through 7 often depends on
 whether the emulator supports eight colors or sixteen colors.  Emulators
 that only support eight colors (such as the Linux console) will display
 colors 0 through 7 with normal brightness and ignore colors 8 through 15,
 treating them the same as white.  Emulators that support 16 colors, such
 as gnome-terminal, normally display colors 0 through 7 as dim or darker
 versions and colors 8 through 15 as normal brightness.  On such emulators,
 the "normal" white (color 7) usually is shown as pale grey, requiring
 bright white (15) to be used to get a real white color.  Bright black
 usually is a dark grey color, although some terminals display it as pure
 black.  Some sixteen-color terminal emulators also treat normal yellow
 (color 3) as orange or brown, and bright yellow (color 11) as yellow.
 
 Following the normal convention of sixteen-color emulators, this module
 provides a pair of attributes for each color.  For every normal color (0
 through 7), the corresponding bright color (8 through 15) is obtained by
 prepending the string C<bright_> to the normal color name.  For example,
 C<red> is color 1 and C<bright_red> is color 9.  The same applies for
 background colors: C<on_red> is the normal color and C<on_bright_red> is
 the bright color.  Capitalize these strings for the constant interface.
 
 For 256-color emulators, this module additionally provides C<ansi0>
 through C<ansi15>, which are the same as colors 0 through 15 in
 sixteen-color emulators but use the 256-color escape syntax, C<grey0>
 through C<grey23> ranging from nearly black to nearly white, and a set of
 RGB colors.  The RGB colors are of the form C<rgbI<RGB>> where I<R>, I<G>,
 and I<B> are numbers from 0 to 5 giving the intensity of red, green, and
 blue.  C<on_> variants of all of these colors are also provided.  These
 colors may be ignored completely on non-256-color terminals or may be
 misinterpreted and produce random behavior.  Additional attributes such as
 blink, italic, or bold may not work with the 256-color palette.
 
 There is unfortunately no way to know whether the current emulator
 supports more than eight colors, which makes the choice of colors
 difficult.  The most conservative choice is to use only the regular
 colors, which are at least displayed on all emulators.  However, they will
 appear dark in sixteen-color terminal emulators, including most common
 emulators in UNIX X environments.  If you know the display is one of those
 emulators, you may wish to use the bright variants instead.  Even better,
 offer the user a way to configure the colors for a given application to
 fit their terminal emulator.
 
 =head2 Function Interface
 
 The function interface uses attribute strings to describe the colors and
 text attributes to assign to text.  The recognized non-color attributes
 are clear, reset, bold, dark, faint, italic, underline, underscore, blink,
 reverse, and concealed.  Clear and reset (reset to default attributes),
 dark and faint (dim and saturated), and underline and underscore are
 equivalent, so use whichever is the most intuitive to you.
 
 Note that not all attributes are supported by all terminal types, and some
 terminals may not support any of these sequences.  Dark and faint, italic,
 blink, and concealed in particular are frequently not implemented.
 
 The recognized normal foreground color attributes (colors 0 to 7) are:
 
   black  red  green  yellow  blue  magenta  cyan  white
 
 The corresponding bright foreground color attributes (colors 8 to 15) are:
 
   bright_black  bright_red      bright_green  bright_yellow
   bright_blue   bright_magenta  bright_cyan   bright_white
 
 The recognized normal background color attributes (colors 0 to 7) are:
 
   on_black  on_red      on_green  on yellow
   on_blue   on_magenta  on_cyan   on_white
 
 The recognized bright background color attributes (colors 8 to 15) are:
 
   on_bright_black  on_bright_red      on_bright_green  on_bright_yellow
   on_bright_blue   on_bright_magenta  on_bright_cyan   on_bright_white
 
 For 256-color terminals, the recognized foreground colors are:
 
   ansi0 .. ansi15
   grey0 .. grey23
 
 plus C<rgbI<RGB>> for I<R>, I<G>, and I<B> values from 0 to 5, such as
 C<rgb000> or C<rgb515>.  Similarly, the recognized background colors are:
 
   on_ansi0 .. on_ansi15
   on_grey0 .. on_grey23
 
 plus C<on_rgbI<RGB>> for I<R>, I<G>, and I<B> values from 0 to 5.
 
 For any of the above listed attributes, case is not significant.
 
 Attributes, once set, last until they are unset (by printing the attribute
 C<clear> or C<reset>).  Be careful to do this, or otherwise your attribute
 will last after your script is done running, and people get very annoyed
 at having their prompt and typing changed to weird colors.
 
 =over 4
 
 =item color(ATTR[, ATTR ...])
 
 color() takes any number of strings as arguments and considers them to be
 space-separated lists of attributes.  It then forms and returns the escape
 sequence to set those attributes.  It doesn't print it out, just returns
 it, so you'll have to print it yourself if you want to.  This is so that
 you can save it as a string, pass it to something else, send it to a file
 handle, or do anything else with it that you might care to.  color()
 throws an exception if given an invalid attribute.
 
 =item colored(STRING, ATTR[, ATTR ...])
 
 =item colored(ATTR-REF, STRING[, STRING...])
 
 As an aid in resetting colors, colored() takes a scalar as the first
 argument and any number of attribute strings as the second argument and
 returns the scalar wrapped in escape codes so that the attributes will be
 set as requested before the string and reset to normal after the string.
 Alternately, you can pass a reference to an array as the first argument,
 and then the contents of that array will be taken as attributes and color
 codes and the remainder of the arguments as text to colorize.
 
 Normally, colored() just puts attribute codes at the beginning and end of
 the string, but if you set $Term::ANSIColor::EACHLINE to some string, that
 string will be considered the line delimiter and the attribute will be set
 at the beginning of each line of the passed string and reset at the end of
 each line.  This is often desirable if the output contains newlines and
 you're using background colors, since a background color that persists
 across a newline is often interpreted by the terminal as providing the
 default background color for the next line.  Programs like pagers can also
 be confused by attributes that span lines.  Normally you'll want to set
 $Term::ANSIColor::EACHLINE to C<"\n"> to use this feature.
 
 =item uncolor(ESCAPE)
 
 uncolor() performs the opposite translation as color(), turning escape
 sequences into a list of strings corresponding to the attributes being set
 by those sequences.
 
 =item colorstrip(STRING[, STRING ...])
 
 colorstrip() removes all color escape sequences from the provided strings,
 returning the modified strings separately in array context or joined
 together in scalar context.  Its arguments are not modified.
 
 =item colorvalid(ATTR[, ATTR ...])
 
 colorvalid() takes attribute strings the same as color() and returns true
 if all attributes are known and false otherwise.
 
 =item coloralias(ALIAS[, ATTR])
 
 If ATTR is specified, coloralias() sets up an alias of ALIAS for the
 standard color ATTR.  From that point forward, ALIAS can be passed into
 color(), colored(), and colorvalid() and will have the same meaning as
 ATTR.  One possible use of this facility is to give more meaningful names
 to the 256-color RGB colors.  Only alphanumerics, C<.>, C<_>, and C<-> are
 allowed in alias names.
 
 If ATTR is not specified, coloralias() returns the standard color name to
 which ALIAS is aliased, if any, or undef if ALIAS does not exist.
 
 This is the same facility used by the ANSI_COLORS_ALIASES environment
 variable (see L</ENVIRONMENT> below) but can be used at runtime, not just
 when the module is loaded.
 
 Later invocations of coloralias() with the same ALIAS will override
 earlier aliases.  There is no way to remove an alias.
 
 Aliases have no effect on the return value of uncolor().
 
 B<WARNING>: Aliases are global and affect all callers in the same process.
 There is no way to set an alias limited to a particular block of code or a
 particular object.
 
 =back
 
 =head2 Constant Interface
 
 Alternately, if you import C<:constants>, you can use the following
 constants directly:
 
   CLEAR           RESET             BOLD            DARK
   FAINT           ITALIC            UNDERLINE       UNDERSCORE
   BLINK           REVERSE           CONCEALED
 
   BLACK           RED               GREEN           YELLOW
   BLUE            MAGENTA           CYAN            WHITE
   BRIGHT_BLACK    BRIGHT_RED        BRIGHT_GREEN    BRIGHT_YELLOW
   BRIGHT_BLUE     BRIGHT_MAGENTA    BRIGHT_CYAN     BRIGHT_WHITE
 
   ON_BLACK        ON_RED            ON_GREEN        ON_YELLOW
   ON_BLUE         ON_MAGENTA        ON_CYAN         ON_WHITE
   ON_BRIGHT_BLACK ON_BRIGHT_RED     ON_BRIGHT_GREEN ON_BRIGHT_YELLOW
   ON_BRIGHT_BLUE  ON_BRIGHT_MAGENTA ON_BRIGHT_CYAN  ON_BRIGHT_WHITE
 
 These are the same as color('attribute') and can be used if you prefer
 typing:
 
     print BOLD BLUE ON_WHITE "Text", RESET, "\n";
 
 to
 
     print colored ("Text", 'bold blue on_white'), "\n";
 
 (Note that the newline is kept separate to avoid confusing the terminal as
 described above since a background color is being used.)
 
 If you import C<:constants256>, you can use the following constants
 directly:
 
   ANSI0 .. ANSI15
   GREY0 .. GREY23
 
   RGBXYZ (for X, Y, and Z values from 0 to 5, like RGB000 or RGB515)
 
   ON_ANSI0 .. ON_ANSI15
   ON_GREY0 .. ON_GREY23
 
   ON_RGBXYZ (for X, Y, and Z values from 0 to 5)
 
 Note that C<:constants256> does not include the other constants, so if you
 want to mix both, you need to include C<:constants> as well.  You may want
 to explicitly import at least C<RESET>, as in:
 
     use Term::ANSIColor 4.00 qw(RESET :constants256);
 
 When using the constants, if you don't want to have to remember to add the
 C<, RESET> at the end of each print line, you can set
 $Term::ANSIColor::AUTORESET to a true value.  Then, the display mode will
 automatically be reset if there is no comma after the constant.  In other
 words, with that variable set:
 
     print BOLD BLUE "Text\n";
 
 will reset the display mode afterward, whereas:
 
     print BOLD, BLUE, "Text\n";
 
 will not.  If you are using background colors, you will probably want to
 either use say() (in newer versions of Perl) or print the newline with a
 separate print statement to avoid confusing the terminal.
 
 If $Term::ANSIColor::AUTOLOCAL is set (see below), it takes precedence
 over $Term::ANSIColor::AUTORESET, and the latter is ignored.
 
 The subroutine interface has the advantage over the constants interface in
 that only two subroutines are exported into your namespace, versus
 thirty-eight in the constants interface.  On the flip side, the constants
 interface has the advantage of better compile time error checking, since
 misspelled names of colors or attributes in calls to color() and colored()
 won't be caught until runtime whereas misspelled names of constants will
 be caught at compile time.  So, pollute your namespace with almost two
 dozen subroutines that you may not even use that often, or risk a silly
 bug by mistyping an attribute.  Your choice, TMTOWTDI after all.
 
 =head2 The Color Stack
 
 You can import C<:pushpop> and maintain a stack of colors using PUSHCOLOR,
 POPCOLOR, and LOCALCOLOR.  PUSHCOLOR takes the attribute string that
 starts its argument and pushes it onto a stack of attributes.  POPCOLOR
 removes the top of the stack and restores the previous attributes set by
 the argument of a prior PUSHCOLOR.  LOCALCOLOR surrounds its argument in a
 PUSHCOLOR and POPCOLOR so that the color resets afterward.
 
 If $Term::ANSIColor::AUTOLOCAL is set, each sequence of color constants
 will be implicitly preceded by LOCALCOLOR.  In other words, the following:
 
     {
         local $Term::ANSIColor::AUTOLOCAL = 1;
         print BLUE "Text\n";
     }
 
 is equivalent to:
 
     print LOCALCOLOR BLUE "Text\n";
 
 If $Term::ANSIColor::AUTOLOCAL is set, it takes precedence over
 $Term::ANSIColor::AUTORESET, and the latter is ignored.
 
 When using PUSHCOLOR, POPCOLOR, and LOCALCOLOR, it's particularly
 important to not put commas between the constants.
 
     print PUSHCOLOR BLUE "Text\n";
 
 will correctly push BLUE onto the top of the stack.
 
     print PUSHCOLOR, BLUE, "Text\n";    # wrong!
 
 will not, and a subsequent pop won't restore the correct attributes.
 PUSHCOLOR pushes the attributes set by its argument, which is normally a
 string of color constants.  It can't ask the terminal what the current
 attributes are.
 
 =head1 DIAGNOSTICS
 
 =over 4
 
 =item Bad color mapping %s
 
 (W) The specified color mapping from ANSI_COLORS_ALIASES is not valid and
 could not be parsed.  It was ignored.
 
 =item Bad escape sequence %s
 
 (F) You passed an invalid ANSI escape sequence to uncolor().
 
 =item Bareword "%s" not allowed while "strict subs" in use
 
 (F) You probably mistyped a constant color name such as:
 
     $Foobar = FOOBAR . "This line should be blue\n";
 
 or:
 
     @Foobar = FOOBAR, "This line should be blue\n";
 
 This will only show up under use strict (another good reason to run under
 use strict).
 
 =item Cannot alias standard color %s
 
 (F) The alias name passed to coloralias() matches a standard color name.
 Standard color names cannot be aliased.
 
 =item Cannot alias standard color %s in %s
 
 (W) The same, but in ANSI_COLORS_ALIASES.  The color mapping was ignored.
 
 =item Invalid alias name %s
 
 (F) You passed an invalid alias name to coloralias().  Alias names must
 consist only of alphanumerics, C<.>, C<->, and C<_>.
 
 =item Invalid alias name %s in %s
 
 (W) You specified an invalid alias name on the left hand of the equal sign
 in a color mapping in ANSI_COLORS_ALIASES.  The color mapping was ignored.
 
 =item Invalid attribute name %s
 
 (F) You passed an invalid attribute name to color(), colored(), or
 coloralias().
 
 =item Invalid attribute name %s in %s
 
 (W) You specified an invalid attribute name on the right hand of the equal
 sign in a color mapping in ANSI_COLORS_ALIASES.  The color mapping was
 ignored.
 
 =item Name "%s" used only once: possible typo
 
 (W) You probably mistyped a constant color name such as:
 
     print FOOBAR "This text is color FOOBAR\n";
 
 It's probably better to always use commas after constant names in order to
 force the next error.
 
 =item No comma allowed after filehandle
 
 (F) You probably mistyped a constant color name such as:
 
     print FOOBAR, "This text is color FOOBAR\n";
 
 Generating this fatal compile error is one of the main advantages of using
 the constants interface, since you'll immediately know if you mistype a
 color name.
 
 =item No name for escape sequence %s
 
 (F) The ANSI escape sequence passed to uncolor() contains escapes which
 aren't recognized and can't be translated to names.
 
 =back
 
 =head1 ENVIRONMENT
 
 =over 4
 
 =item ANSI_COLORS_ALIASES
 
 This environment variable allows the user to specify custom color aliases
 that will be understood by color(), colored(), and colorvalid().  None of
 the other functions will be affected, and no new color constants will be
 created.  The custom colors are aliases for existing color names; no new
 escape sequences can be introduced.  Only alphanumerics, C<.>, C<_>, and
 C<-> are allowed in alias names.
 
 The format is:
 
     ANSI_COLORS_ALIASES='newcolor1=oldcolor1,newcolor2=oldcolor2'
 
 Whitespace is ignored.
 
 For example the L<Solarized|http://ethanschoonover.com/solarized> colors
 can be mapped with:
 
     ANSI_COLORS_ALIASES='\
         base00=bright_yellow, on_base00=on_bright_yellow,\
         base01=bright_green,  on_base01=on_bright_green, \
         base02=black,         on_base02=on_black,        \
         base03=bright_black,  on_base03=on_bright_black, \
         base0=bright_blue,    on_base0=on_bright_blue,   \
         base1=bright_cyan,    on_base1=on_bright_cyan,   \
         base2=white,          on_base2=on_white,         \
         base3=bright_white,   on_base3=on_bright_white,  \
         orange=bright_red,    on_orange=on_bright_red,   \
         violet=bright_magenta,on_violet=on_bright_magenta'
 
 This environment variable is read and applied when the Term::ANSIColor
 module is loaded and is then subsequently ignored.  Changes to
 ANSI_COLORS_ALIASES after the module is loaded will have no effect.  See
 coloralias() for an equivalent facility that can be used at runtime.
 
 =item ANSI_COLORS_DISABLED
 
 If this environment variable is set to a true value, all of the functions
 defined by this module (color(), colored(), and all of the constants not
 previously used in the program) will not output any escape sequences and
 instead will just return the empty string or pass through the original
 text as appropriate.  This is intended to support easy use of scripts
 using this module on platforms that don't support ANSI escape sequences.
 
 =back
 
 =head1 COMPATIBILITY
 
 Term::ANSIColor was first included with Perl in Perl 5.6.0.
 
 The uncolor() function and support for ANSI_COLORS_DISABLED were added in
 Term::ANSIColor 1.04, included in Perl 5.8.0.
 
 Support for dark was added in Term::ANSIColor 1.08, included in Perl
 5.8.4.
 
 The color stack, including the C<:pushpop> import tag, PUSHCOLOR,
 POPCOLOR, LOCALCOLOR, and the $Term::ANSIColor::AUTOLOCAL variable, was
 added in Term::ANSIColor 2.00, included in Perl 5.10.1.
 
 colorstrip() was added in Term::ANSIColor 2.01 and colorvalid() was added
 in Term::ANSIColor 2.02, both included in Perl 5.11.0.
 
 Support for colors 8 through 15 (the C<bright_> variants) was added in
 Term::ANSIColor 3.00, included in Perl 5.13.3.
 
 Support for italic was added in Term::ANSIColor 3.02, included in Perl
 5.17.1.
 
 Support for colors 16 through 256 (the C<ansi>, C<rgb>, and C<grey>
 colors), the C<:constants256> import tag, the coloralias() function, and
 support for the ANSI_COLORS_ALIASES environment variable were added in
 Term::ANSIColor 4.00, included in Perl 5.17.8.
 
 $Term::ANSIColor::AUTOLOCAL was changed to take precedence over
 $Term::ANSIColor::AUTORESET, rather than the other way around, in
 Term::ANSIColor 4.00, included in Perl 5.17.8.
 
 =head1 RESTRICTIONS
 
 It would be nice if one could leave off the commas around the constants
 entirely and just say:
 
     print BOLD BLUE ON_WHITE "Text\n" RESET;
 
 but the syntax of Perl doesn't allow this.  You need a comma after the
 string.  (Of course, you may consider it a bug that commas between all the
 constants aren't required, in which case you may feel free to insert
 commas unless you're using $Term::ANSIColor::AUTORESET or
 PUSHCOLOR/POPCOLOR.)
 
 For easier debugging, you may prefer to always use the commas when not
 setting $Term::ANSIColor::AUTORESET or PUSHCOLOR/POPCOLOR so that you'll
 get a fatal compile error rather than a warning.
 
 It's not possible to use this module to embed formatting and color
 attributes using Perl formats.  They replace the escape character with a
 space (as documented in L<perlform(1)>), resulting in garbled output from
 the unrecognized attribute.  Even if there were a way around that problem,
 the format doesn't know that the non-printing escape sequence is
 zero-length and would incorrectly format the output.  For formatted output
 using color or other attributes, either use sprintf() instead or use
 formline() and then add the color or other attributes after formatting and
 before output.
 
 =head1 NOTES
 
 The codes generated by this module are standard terminal control codes,
 complying with ECMA-048 and ISO 6429 (generally referred to as "ANSI
 color" for the color codes).  The non-color control codes (bold, dark,
 italic, underline, and reverse) are part of the earlier ANSI X3.64
 standard for control sequences for video terminals and peripherals.
 
 Note that not all displays are ISO 6429-compliant, or even X3.64-compliant
 (or are even attempting to be so).  This module will not work as expected
 on displays that do not honor these escape sequences, such as cmd.exe,
 4nt.exe, and command.com under either Windows NT or Windows 2000.  They
 may just be ignored, or they may display as an ESC character followed by
 some apparent garbage.
 
 Jean Delvare provided the following table of different common terminal
 emulators and their support for the various attributes and others have
 helped me flesh it out:
 
               clear    bold     faint   under    blink   reverse  conceal
  ------------------------------------------------------------------------
  xterm         yes      yes      no      yes      yes      yes      yes
  linux         yes      yes      yes    bold      yes      yes      no
  rxvt          yes      yes      no      yes  bold/black   yes      no
  dtterm        yes      yes      yes     yes    reverse    yes      yes
  teraterm      yes    reverse    no      yes    rev/red    yes      no
  aixterm      kinda   normal     no      yes      no       yes      yes
  PuTTY         yes     color     no      yes      no       yes      no
  Windows       yes      no       no      no       no       yes      no
  Cygwin SSH    yes      yes      no     color    color    color     yes
  Terminal.app  yes      yes      no      yes      yes      yes      yes
 
 Windows is Windows telnet, Cygwin SSH is the OpenSSH implementation under
 Cygwin on Windows NT, and Mac Terminal is the Terminal application in Mac
 OS X.  Where the entry is other than yes or no, that emulator displays the
 given attribute as something else instead.  Note that on an aixterm, clear
 doesn't reset colors; you have to explicitly set the colors back to what
 you want.  More entries in this table are welcome.
 
 Support for code 3 (italic) is rare and therefore not mentioned in that
 table.  It is not believed to be fully supported by any of the terminals
 listed, although it's displayed as green in the Linux console, but it is
 reportedly supported by urxvt.
 
 Note that codes 6 (rapid blink) and 9 (strike-through) are specified in
 ANSI X3.64 and ECMA-048 but are not commonly supported by most displays
 and emulators and therefore aren't supported by this module at the present
 time.  ECMA-048 also specifies a large number of other attributes,
 including a sequence of attributes for font changes, Fraktur characters,
 double-underlining, framing, circling, and overlining.  As none of these
 attributes are widely supported or useful, they also aren't currently
 supported by this module.
 
 Most modern X terminal emulators support 256 colors.  Known to not support
 those colors are aterm, rxvt, Terminal.app, and TTY/VC.
 
 =head1 AUTHORS
 
 Original idea (using constants) by Zenin, reimplemented using subs by Russ
 Allbery <rra@cpan.org>, and then combined with the original idea by
 Russ with input from Zenin.  256-color support is based on work by Kurt
 Starsinic.  Russ Allbery now maintains this module.
 
 PUSHCOLOR, POPCOLOR, and LOCALCOLOR were contributed by openmethods.com
 voice solutions.
 
 =head1 COPYRIGHT AND LICENSE
 
 Copyright 1996 Zenin.  Copyright 1996, 1997, 1998, 2000, 2001, 2002, 2005,
 2006, 2008, 2009, 2010, 2011, 2012, 2013, 2014 Russ Allbery
 <rra@cpan.org>.  Copyright 2012 Kurt Starsinic <kstarsinic@gmail.com>.
 This program is free software; you may redistribute it and/or modify it
 under the same terms as Perl itself.
 
 =head1 SEE ALSO
 
 The CPAN module L<Term::ExtendedColor> provides a different and more
 comprehensive interface for 256-color emulators that may be more
 convenient.  The CPAN module L<Win32::Console::ANSI> provides ANSI color
 (and other escape sequence) support in the Win32 Console environment.
 
 ECMA-048 is available on-line (at least at the time of this writing) at
 L<http://www.ecma-international.org/publications/standards/Ecma-048.htm>.
 
 ISO 6429 is available from ISO for a charge; the author of this module
 does not own a copy of it.  Since the source material for ISO 6429 was
 ECMA-048 and the latter is available for free, there seems little reason
 to obtain the ISO standard.
 
 The 256-color control sequences are documented at
 L<http://invisible-island.net/xterm/ctlseqs/ctlseqs.html> (search for
 256-color).
 
 The current version of this module is always available from its web site
 at L<http://www.eyrie.org/~eagle/software/ansicolor/>.  It is also part of
 the Perl core distribution as of 5.6.0.
 
 =cut
### Term/App/Role/Attrs.pm ###
 package Term::App::Role::Attrs;
 
 our $DATE = '2014-12-10'; # DATE
 our $VERSION = '0.01'; # VERSION
 
 use 5.010001;
 use Moo::Role;
 
 my $dt_cache;
 sub detect_terminal {
     my $self = shift;
 
     if (!$dt_cache) {
         require Term::Detect::Software;
         $dt_cache = Term::Detect::Software::detect_terminal_cached();
         #use Data::Dump; dd $dt_cache;
     }
     $dt_cache;
 }
 
 my $termw_cache;
 my $termh_cache;
 sub _term_size {
     my $self = shift;
 
     if (defined $termw_cache) {
         return ($termw_cache, $termh_cache);
     }
 
     ($termw_cache, $termh_cache) = (0, 0);
     if (eval { require Term::Size; 1 }) {
         ($termw_cache, $termh_cache) = Term::Size::chars();
     }
     ($termw_cache, $termh_cache);
 }
 
 # return undef if fail to parse
 sub __parse_color_depth {
     my $val = shift;
     if ($val =~ /\A\d+\z/) {
         return $val;
     } elsif ($val =~ /\A(\d+)[ _-]?(?:bit|b)\z/) {
         return 2**$val;
     } else {
         # IDEA: parse 'high color', 'true color'?
         return undef;
     }
 }
 
 has interactive => (
     is      => 'rw',
     lazy    => 1,
     default => sub {
         my $self = shift;
         if (defined $ENV{INTERACTIVE}) {
             $self->{_term_attrs_debug_info}{interactive_from} =
                 'INTERACTIVE env';
             return $ENV{INTERACTIVE};
         } else {
             $self->{_term_attrs_debug_info}{interactive_from} =
                 '-t STDOUT';
             return (-t STDOUT);
         }
     },
 );
 
 has use_color => (
     is      => 'rw',
     lazy    => 1,
     default => sub {
         my $self = shift;
         if (defined $ENV{COLOR}) {
             $self->{_term_attrs_debug_info}{use_color_from} =
                 'COLOR env';
             return $ENV{COLOR};
         } elsif (defined $ENV{COLOR_DEPTH}) {
             $self->{_term_attrs_debug_info}{use_color_from} =
                 'COLOR_DEPTH env';
             my $val = __parse_color_depth($ENV{COLOR_DEPTH}) //
                 $ENV{COLOR_DEPTH};
             return $val ? 1:0;
         } else {
             $self->{_term_attrs_debug_info}{use_color_from} =
                 'interactive + color_deth';
             return $self->interactive && $self->color_depth > 0;
         }
     },
     trigger => sub {
         my ($self, $val) = @_;
         return if !defined($val) || $val =~ /\A(|1|0)\z/;
         my $pval = __parse_color_depth($val);
         $self->{color_depth} = $pval if defined $pval;
     },
 );
 
 has color_depth => (
     is      => 'rw',
     lazy    => 1,
     default => sub {
         my $self = shift;
         my $pval;
         if (defined($ENV{COLOR_DEPTH}) &&
                 defined($pval = __parse_color_depth($ENV{COLOR_DEPTH}))) {
             $self->{_term_attrs_debug_info}{color_depth_from} =
                 'COLOR_DEPTH env';
             return $pval;
         } elsif (defined($ENV{COLOR}) && $ENV{COLOR} !~ /^(|0|1)$/ &&
                      defined($pval = __parse_color_depth($ENV{COLOR}))) {
                 $self->{_term_attrs_debug_info}{color_depth_from} =
                     'COLOR env';
             return $pval;
         } elsif (defined(my $cd = $self->detect_terminal->{color_depth})) {
             $self->{_term_attrs_debug_info}{color_depth_from} =
                 'detect_terminal';
             return $cd;
         } else {
             $self->{_term_attrs_debug_info}{color_depth_from} =
                 'hardcoded default';
             return 16;
         }
     },
     trigger => sub {
         my ($self, $val) = @_;
         if (defined(my $pval = __parse_color_depth($val))) {
             $self->{color_depth} = $val = $pval;
         }
         if ($val) {
             $self->{use_color} = 1;
         } else {
             $self->{use_color} = 0;
         }
     },
 );
 
 has use_box_chars => (
     is      => 'rw',
     lazy    => 1,
     default => sub {
         my $self = shift;
         if (defined $ENV{BOX_CHARS}) {
             $self->{_term_attrs_debug_info}{use_box_chars_from} =
                 'BOX_CHARS env';
             return $ENV{BOX_CHARS};
         } elsif (!$self->interactive) {
             # most pager including 'less -R' does not support interpreting
             # boxchar escape codes.
             $self->{_term_attrs_debug_info}{use_box_chars_from} =
                 '(not) interactive';
             return 0;
         } elsif (defined(my $bc = $self->detect_terminal->{box_chars})) {
             $self->{_term_attrs_debug_info}{use_box_chars_from} =
                 'detect_terminal';
             return $bc;
         } else {
             $self->{_term_attrs_debug_info}{use_box_chars_from} =
                 'hardcoded default';
             return 0;
         }
     },
 );
 
 has use_utf8 => (
     is      => 'rw',
     lazy    => 1,
     default => sub {
         my $self = shift;
         if (defined $ENV{UTF8}) {
             $self->{_term_attrs_debug_info}{use_utf8_from} =
                 'UTF8 env';
             return $ENV{UTF8};
         } elsif (defined(my $termuni = $self->detect_terminal->{unicode})) {
             $self->{_term_attrs_debug_info}{use_utf8_from} =
                 'detect_terminal + LANG/LANGUAGE env must include "utf8"';
             return $termuni &&
                 (($ENV{LANG} || $ENV{LANGUAGE} || "") =~ /utf-?8/i ? 1:0);
         } else {
             $self->{_term_attrs_debug_info}{use_utf8_from} =
                 'hardcoded default';
             return 0;
         }
     },
 );
 
 has _term_attrs_debug_info => (is => 'rw', default=>sub{ {} });
 
 has term_width => (
     is      => 'rw',
     lazy    => 1,
     default => sub {
         my $self = shift;
         if ($ENV{COLUMNS}) {
             $self->{_term_attrs_debug_info}{term_width_from} = 'COLUMNS env';
             return $ENV{COLUMNS};
         }
         my ($termw, undef) = $self->_term_size;
         if ($termw) {
             $self->{_term_attrs_debug_info}{term_width_from} = 'term_size';
         } else {
             # sane default, on windows printing to rightmost column causes
             # cursor to move to the next line.
             $self->{_term_attrs_debug_info}{term_width_from} =
                 'hardcoded default';
             $termw = $^O =~ /Win/ ? 79 : 80;
         }
         $termw;
     },
 );
 
 has term_height => (
     is      => 'rw',
     lazy    => 1,
     default => sub {
         my $self = shift;
         if ($ENV{LINES}) {
             $self->{_term_attrs_debug_info}{term_height_from} = 'LINES env';
             return $ENV{LINES};
         }
         my (undef, $termh) = $self->_term_size;
         if ($termh) {
             $self->{_term_attrs_debug_info}{term_height_from} = 'term_size';
         } else {
             $self->{_term_attrs_debug_info}{term_height_from} = 'default';
             # sane default
             $termh = 25;
         }
         $termh;
     },
 );
 
 1;
 #ABSTRACT: Role for terminal-related attributes
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Term::App::Role::Attrs - Role for terminal-related attributes
 
 =head1 VERSION
 
 This document describes version 0.01 of Term::App::Role::Attrs (from Perl distribution Term-App-Roles), released on 2014-12-10.
 
 =head1 DESCRIPTION
 
 This role gives several options to turn on/off terminal-oriented features like
 whether to use UTF8 characters, whether to use colors, and color depth. Defaults
 are set from environment variables or by detecting terminal
 software/capabilities.
 
 =head1 ATTRIBUTES
 
 =head2 use_utf8 => BOOL (default: from env, or detected from terminal)
 
 The default is retrieved from environment: if C<UTF8> is set, it is used.
 Otherwise, the default is on if terminal emulator software supports Unicode
 I<and> language (LANG/LANGUAGE) setting has /utf-?8/i in it.
 
 =head2 use_box_chars => BOOL (default: from env, or detected from OS)
 
 Default is 0 for Windows.
 
 =head2 interactive => BOOL (default: from env, or detected from terminal)
 
 =head2 use_color => BOOL (default: from env, or detected from terminal)
 
 For convenience, this attribute is "linked" with C<color_depth>. Setting
 C<use_color> will also set C<color_depth> when the value is not ''/1/0 and
 matches color depth pattern. For example, setting C<use_color> to 256 or '8bit'
 will also set C<color_depth> to 256.
 
 =head2 color_depth => INT (or STR, default: from env, or detected from terminal)
 
 Get/set color depth. When setting, you can use string like '8 bit' or '24b' and
 it will be converted to 256 (2**8) or 16777216 (2**24).
 
 For convenience, this attribute is "linked" with C<use_color>. Setting
 C<color_depth> to non-zero value will enable C<use_color>, while setting it to 0
 will disable C<use_color>.
 
 =head2 term_width => INT (default: from env, or detected from terminal)
 
 =head2 term_height => INT (default: from env, or detected from terminal)
 
 =head1 METHODS
 
 =head2 detect_terminal() => HASH
 
 Call L<Term::Detect::Software>'s C<detect_terminal_cached>.
 
 =head1 ENVIRONMENT
 
 =over
 
 =item * UTF8 => BOOL
 
 Can be used to set C<use_utf8>.
 
 =item * INTERACTIVE => BOOL
 
 Can be used to set C<interactive>.
 
 =item * COLOR => BOOL (or INT or STR)
 
 Can be used to set C<use_color>. Can also be used to set C<color_depth> (if
 C<COLOR_DEPTH> is not defined).
 
 =item * COLOR_DEPTH => INT (or STR)
 
 Can be used to set C<color_depth>. Can also be used to enable/disable
 C<use_color>.
 
 =item * BOX_CHARS => BOOL
 
 Can be used to set C<use_box_chars>.
 
 =item * COLUMNS => INT
 
 Can be used to set C<term_width>.
 
 =item * LINES => INT
 
 Can be used to set C<term_height>.
 
 =back
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Term-App-Roles>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Term-App-Roles>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Term-App-Roles>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2014 by perlancar@cpan.org.
 
 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
### Term/App/Roles.pm ###
 package Term::App::Roles;
 
 our $DATE = '2014-12-10'; # DATE
 our $VERSION = '0.01'; # VERSION
 
 1;
 #ABSTRACT: Collection of roles for terminal-based application
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Term::App::Roles - Collection of roles for terminal-based application
 
 =head1 VERSION
 
 This document describes version 0.01 of Term::App::Roles (from Perl distribution Term-App-Roles), released on 2014-12-10.
 
 =head1 DESCRIPTION
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Term-App-Roles>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Term-App-Roles>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Term-App-Roles>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2014 by perlancar@cpan.org.
 
 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
### Term/Detect/Software.pm ###
 package Term::Detect::Software;
 
 our $DATE = '2015-01-03'; # DATE
 our $VERSION = '0.21'; # VERSION
 
 use 5.010001;
 use strict;
 use warnings;
 use experimental 'smartmatch';
 #use Log::Any '$log';
 
 require Exporter;
 our @ISA       = qw(Exporter);
 our @EXPORT_OK = qw(detect_terminal detect_terminal_cached);
 
 my $dt_cache;
 sub detect_terminal_cached {
     if (!$dt_cache) {
         $dt_cache = detect_terminal(@_);
     }
     $dt_cache;
 }
 
 sub detect_terminal {
     my @dbg;
     my $info = {_debug_info=>\@dbg};
 
   DETECT:
     {
         unless (defined $ENV{TERM}) {
             push @dbg, "skip: TERM env undefined";
             $info->{emulator_engine}   = '';
             $info->{emulator_software} = '';
             last DETECT;
         }
 
         if ($ENV{KONSOLE_DBUS_SERVICE} || $ENV{KONSOLE_DBUS_SESSION}) {
             push @dbg, "detect: konsole via KONSOLE_DBUS_{SERVICE,SESSION} env";
             $info->{emulator_engine} = 'konsole';
             $info->{color_depth}     = 2**24;
             $info->{default_bgcolor} = '000000';
             $info->{unicode}         = 1;
             $info->{box_chars}       = 1;
             last DETECT;
         }
 
         if ($ENV{XTERM_VERSION}) {
             push @dbg, "detect: xterm via XTERM_VERSION env";
             $info->{emulator_engine} = 'xterm';
             $info->{color_depth}     = 256;
             $info->{default_bgcolor} = 'ffffff';
             $info->{unicode}         = 0;
             $info->{box_chars}       = 1;
             last DETECT;
         }
 
         # cygwin terminal
         if ($ENV{TERM} eq 'xterm' && ($ENV{OSTYPE} // '') eq 'cygwin') {
             push @dbg, "detect: xterm via TERM env (cygwin)";
             $info->{emulator_engine} = 'cygwin';
             $info->{color_depth}     = 16;
             $info->{default_bgcolor} = '000000';
             $info->{unicode}         = 0; # CONFIRM?
             $info->{box_chars}       = 1;
             last DETECT;
         }
 
         if ($ENV{TERM} eq 'linux') {
             push @dbg, "detect: linux via TERM env";
             # Linux virtual console
             $info->{emulator_engine} = 'linux';
             $info->{color_depth}     = 16;
             $info->{default_bgcolor} = '000000';
             # actually it can show a few Unicode characters like single borders
             $info->{unicode}         = 0;
             $info->{box_chars}       = 0;
             last DETECT;
         }
 
         my $gnome_terminal_terms = [qw/gnome-terminal guake xfce4-terminal
                                        mlterm lxterminal/];
 
         my $set_gnome_terminal_term = sub {
             $info->{emulator_software} = $_[0];
             $info->{emulator_engine}   = 'gnome-terminal';
 
             # xfce4-terminal only shows 16 color, despite being
             # gnome-terminal-based?
             $info->{color_depth}       = $_[0] =~ /xfce4/ ? 16 : 256;
 
             $info->{unicode}           = 1;
             if ($_[0] ~~ [qw/mlterm/]) {
                 $info->{default_bgcolor} = 'ffffff';
             } else {
                 $info->{default_bgcolor} = '000000';
             }
             $info->{box_chars} = 1;
         };
 
         if (($ENV{COLORTERM} // '') ~~ $gnome_terminal_terms) {
             push @dbg, "detect: gnome-terminal via COLORTERM";
             $set_gnome_terminal_term->($ENV{COLORTERM});
             last DETECT;
         }
 
         # Windows command prompt
         if ($ENV{TERM} eq 'dumb' && $ENV{windir}) {
             push @dbg, "detect: windows via TERM & windir env";
             $info->{emulator_software} = 'windows';
             $info->{emulator_engine}   = 'windows';
             $info->{color_depth}       = 16;
             $info->{unicode}           = 0;
             $info->{default_bgcolor}   = '000000';
             $info->{box_chars}         = 0;
             last DETECT;
         }
 
         # run under CGI or something like that
         if ($ENV{TERM} eq 'dumb') {
             push @dbg, "detect: dumb via TERM env";
             $info->{emulator_software} = 'dumb';
             $info->{emulator_engine}   = 'dumb';
             $info->{color_depth}       = 0;
             # XXX how to determine unicode support?
             $info->{default_bgcolor}   = '000000';
             $info->{box_chars}         = 0;
             last DETECT;
         }
 
         {
             last if $^O =~ /Win/;
 
             require Proc::Find::Parents;
             my $ppids = Proc::Find::Parents::get_parent_processes();
             unless (defined $ppids) {
                 push @dbg, "skip: get_parent_processes returns undef";
                 last;
             }
 
             # [0] is shell
             my $proc = @$ppids >= 1 ? $ppids->[1]{name} : '';
             #say "D:proc=$proc";
             if ($proc ~~ $gnome_terminal_terms) {
                 push @dbg, "detect: gnome-terminal via procname ($proc)";
                 $set_gnome_terminal_term->($proc);
                 last DETECT;
             } elsif ($proc ~~ [qw/rxvt mrxvt/]) {
                 push @dbg, "detect: rxvt via procname ($proc)";
                 $info->{emulator_software} = $proc;
                 $info->{emulator_engine}   = 'rxvt';
                 $info->{color_depth}       = 16;
                 $info->{unicode}           = 0;
                 $info->{default_bgcolor}   = 'd6d2d0';
                 $info->{box_chars}         = 1;
                 last DETECT;
             } elsif ($proc ~~ [qw/pterm/]) {
                 push @dbg, "detect: pterm via procname ($proc)";
                 $info->{emulator_software} = $proc;
                 $info->{emulator_engine}   = 'putty';
                 $info->{color_depth}       = 256;
                 $info->{unicode}           = 0;
                 $info->{default_bgcolor}   = '000000';
                 last DETECT;
             } elsif ($proc ~~ [qw/xvt/]) {
                 push @dbg, "detect: xvt via procname ($proc)";
                 $info->{emulator_software} = $proc;
                 $info->{emulator_engine}   = 'xvt';
                 $info->{color_depth}       = 0; # only support bold
                 $info->{unicode}           = 0;
                 $info->{default_bgcolor}   = 'd6d2d0';
                 last DETECT;
             }
         }
 
         # generic
         {
             unless (exists $info->{color_depth}) {
                 if ($ENV{TERM} =~ /256color/) {
                     push @dbg, "detect color_depth: 256 via TERM env";
                     $info->{color_depth} = 256;
                 } else {
                     require File::Which;
                     if (File::Which::which("tput")) {
                         my $res = `tput colors` + 0;
                         push @dbg, "detect color_depth: $res via tput";
                         $info->{color_depth} = $res;
                     }
                 }
             }
 
             $info->{emulator_software} //= '(generic)';
             $info->{emulator_engine} //= '(generic)';
             $info->{unicode} //= 0;
             $info->{color_depth} //= 0;
             $info->{box_chars} //= 0;
             $info->{default_bgcolor} //= '000000';
         }
 
     } # DETECT
 
     # some additional detections
 
     # we're running under emacs, it doesn't support box chars
     if ($ENV{INSIDE_EMACS}) {
         $info->{inside_emacs} = 1;
         $info->{box_chars} = 0;
     }
 
     $info;
 }
 
 1;
 # ABSTRACT: Detect terminal (emulator) software and its capabilities
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Term::Detect::Software - Detect terminal (emulator) software and its capabilities
 
 =head1 VERSION
 
 This document describes version 0.21 of Term::Detect::Software (from Perl distribution Term-Detect-Software), released on 2015-01-03.
 
 =head1 SYNOPSIS
 
  use Term::Detect::Software qw(detect_terminal detect_terminal_cached);
  my $res = detect_terminal();
  die "Not running under terminal!" unless $res->{emulator_engine};
  say "Emulator engine: ", $res->{emulator_engine};
  say "Emulator software: ", $res->{emulator_software};
  say "Unicode support? ", $res->{unicode} ? "yes":"no";
  say "Boxchars support? ", $res->{box_chars} ? "yes":"no";
  say "Color depth: ", $res->{color_depth};
  say "Inside emacs? ", $res->{inside_emacs} ? "yes":"no";
 
 =head1 DESCRIPTION
 
 This module uses several heuristics to find out what terminal (emulator)
 software the current process is running in, and its capabilities/settings. This
 module complements other modules such as L<Term::Terminfo> and
 L<Term::Encoding>.
 
 =head1 FUNCTIONS
 
 =head2 detect_terminal() => HASHREF
 
 Return a hashref containing information about running terminal (emulator)
 software and its capabilities/settings.
 
 Detection method is tried from the easiest/cheapest (e.g. checking environment
 variables) or by looking at known process names in the process tree. Terminal
 capabilities is determined using heuristics.
 
 Currently Konsole and Konsole-based terminals (like Yakuake) can be detected
 through existence of environment variables C<KONSOLE_DBUS_SERVICE> or
 C<KONSOLE_DBUS_SESSION>. xterm is detected through C<XTERM_VERSION>. XFCE's
 Terminal is detected using C<COLORTERM>. The other software are detected via
 known process names.
 
 Terminal capabilities and settings are currently determined via heuristics.
 Probing terminal configuration files might be performed in the future.
 
 Result:
 
 =over
 
 =item * emulator_engine => STR
 
 Possible values: C<konsole>, C<xterm>, C<gnome-terminal>, C<rxvt>, C<pterm>
 (PuTTY), C<xvt>, C<windows> (CMD.EXE), C<cygwin>, or empty string (if not
 detected running under terminal).
 
 =item * emulator_software => STR
 
 Either: C<xfce4-terminal>, C<guake>, C<gnome-terminal>, C<mlterm>,
 C<lxterminal>, C<rxvt>, C<mrxvt>, C<putty>, C<xvt>, C<windows> (CMD.EXE), or
 empty string (if not detected running under terminal).
 
 w=item * color_depth => INT
 
 Either 0 (does not support ANSI color codes), 16, 256, or 16777216 (2**24).
 
 =item * default_bgcolor => STR (6-hexdigit RGB)
 
 For example, any xterm is assumed to have white background (ffffff) by default,
 while Konsole is assumed to have black (000000). Better heuristics will be done
 in the future.
 
 =item * unicode => BOOL
 
 Whether terminal software supports Unicode/wide characters. Note that you should
 also check encoding, e.g. using L<Term::Encoding>.
 
 =item * box_chars => BOOL
 
 Whether terminal supports box-drawing characters.
 
 =back
 
 =head2 detect_terminal_cached([$flag]) => ANY
 
 Just like C<detect_terminal()> but will cache the result. Can be used by
 applications or modules to avoid repeating detection process.
 
 =head1 FAQ
 
 =head2 What is this module for? Why not Term::Terminfo or Term::Encoding?
 
 This module is first written for L<Text::ANSITable> so that the module can
 provide good defaults when displaying formatted and colored tables, especially
 on popular terminal emulation software like Konsole (KDE's default terminal),
 gnome-terminal (GNOME's default), Terminal (XFCE's default), xterm, rxvt.
 
 The module works by trying to figure out the terminal emulation software because
 the information provided by L<Term::Terminfo> and L<Term::Encoding> are
 sometimes not specific enough. For example, Term::Encoding can return L<utf-8>
 when running under rxvt, but since the software currently lacks Unicode support
 we shouldn't display Unicode characters. Another example is color depth:
 Term::Terminfo currently doesn't recognize Konsole's 24bit color support and
 only gives C<max_colors> 256.
 
 =head1 SEE ALSO
 
 L<Term::Terminfo>
 
 L<Term::Encoding>
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Term-Detect-Software>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Term-Detect-Software>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Term-Detect-Software>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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
### Test/Config/IOD/Common.pm ###
 package Test::Config::IOD::Common;
 
 our $DATE = '2015-09-08'; # DATE
 our $VERSION = '0.19'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 
 use Module::Load;
 use Test::More 0.98;
 
 our $CLASS = "Config::IOD::Reader";
 
 sub test_common_iod {
 
     load $CLASS;
 
     subtest "opt: default_section" => sub {
         test_read_iod(
             args  => {default_section=>'bawaan'},
             input => <<'_',
 a=1
 _
             result => {bawaan=>{a=>1}},
         );
     };
 
     subtest "opt: allow_directives" => sub {
         test_read_iod(
             args  => {allow_directives=>['merge']},
             input => <<'_',
 ;!noop
 _
             dies  => 1,
         );
         test_read_iod(
             args  => {allow_directives=>['noop']},
             input => <<'_',
 ;!noop
 _
             result => {},
         );
     };
 
     subtest "opt: disallow_directives" => sub {
         test_read_iod(
             args  => {disallow_directives=>['noop']},
             input => <<'_',
 ;!noop
 _
             dies  => 1,
         );
         test_read_iod(
             args  => {disallow_directives=>['merge']},
             input => <<'_',
 ;!noop
 _
             result => {},
         );
     };
 
     subtest "opt: allow_directives + disallow_directives" => sub {
         test_read_iod(
             args  => {
                 allow_directives    => ['noop'],
                 disallow_directives => ['noop'],
             },
             input => <<'_',
 ;!noop
 _
             dies  => 1,
         );
     };
 
     subtest "opt: enable_quoting=0" => sub {
         test_read_iod(
             args  => {enable_quoting=>0},
             input => <<'_',
 name="1\n2"
 _
             result => {GLOBAL=>{name=>'"1\\n2"'}},
         );
     };
 
     subtest "opt: enable_bracket=0" => sub {
         test_read_iod(
             args  => {enable_bracket=>0},
             input => <<'_',
 name=[1,2,3]
 _
             result => {GLOBAL=>{name=>'[1,2,3]'}},
         );
     };
 
     subtest "opt: enable_brace=0" => sub {
         test_read_iod(
             args  => {enable_brace=>0},
             input => <<'_',
 name={"a":1}
 _
             result => {GLOBAL=>{name=>'{"a":1}'}},
         );
     };
 
     subtest "opt: enable_encoding=0" => sub {
         test_read_iod(
             args  => {enable_encoding=>0},
             input => <<'_',
 name=!hex 5e5e
 _
             result => {GLOBAL=>{name=>'!hex 5e5e'}},
         );
     };
 
     subtest "opt: allow_encodings" => sub {
         test_read_iod(
             args  => {allow_encodings=>['hex']},
             input => <<'_',
 name=!json "1\n2"
 _
             dies => 1,
         );
         test_read_iod(
             args  => {allow_encodings=>['json']},
             input => <<'_',
 name=!json "1\n2"
 name2=!j "3\n4"
 _
             result => {GLOBAL=>{name=>"1\n2", name2=>"3\n4"}},
         );
     };
 
     subtest "opt: disallow_encodings" => sub {
         test_read_iod(
             args  => {disallow_encodings=>['json']},
             input => <<'_',
 name=!json "1\n2"
 _
             dies => 1,
         );
         test_read_iod(
             args  => {disallow_encodings=>['json']},
             input => <<'_',
 name=!j "1\n2"
 _
             dies => 1,
         );
         test_read_iod(
             args  => {disallow_encodings=>['hex']},
             input => <<'_',
 name=!json "1\n2"
 _
             result => {GLOBAL=>{name=>"1\n2"}},
         );
     };
 
     subtest "opt: allow_encodings + disallow_encodings" => sub {
         test_read_iod(
             args  => {
                 allow_encodings   =>['json'],
                 disallow_encodings=>['json'],
             },
             input => <<'_',
 name=!json "1\n2"
 _
             dies => 1,
         );
     };
 
     subtest "opt: allow_bang_only=0" => sub {
         test_read_iod(
             args  => {allow_bang_only=>0},
             input => <<'_',
 a=1
 !noop
 _
             dies => 1,
         );
     };
 
     subtest "opt: allow_duplicate_key=0" => sub {
         test_read_iod(
             args  => {allow_duplicate_key=>0},
             input => <<'_',
 a=1
 a=2
 _
             dies => 1,
         );
     };
 
     subtest "opt: ignore_unknown_directive=1" => sub {
         test_read_iod(
             args  => {ignore_unknown_directive=>1},
             input => <<'_',
 ;!foo bar
 _
             result => {},
         );
     };
 
     # temporarily placed here
     subtest "expr" => sub {
         test_read_iod(
             name  => "must be enabled first",
             args  => {},
             input => <<'_',
 a=!e 1+1
 _
             dies => 1,
         );
         test_read_iod(
             name  => "must be valid",
             args  => {enable_expr=>1},
             input => <<'_',
 a=!e 1+
 _
             dies => 1,
         );
         test_read_iod(
             args  => {enable_expr=>1},
             input => <<'_',
 a=!e 1+1
 [sect]
 b=!e val("GLOBAL.a")*3
 c=!e val("b") x 3
 _
             result => {GLOBAL=>{a=>2}, sect=>{b=>6, c=>666}},
         );
     };
 }
 
 sub test_read_iod {
     my %args = @_;
 
     my $parser_args = $args{args};
     my $test_name = $args{name} //
         "{". join(", ",
                   (map {"$_=$parser_args->{$_}"}
                        sort keys %$parser_args),
               ) . "}";
     subtest $test_name => sub {
 
         my $parser = $CLASS->new(%$parser_args);
 
         my $res;
         eval {
             if ($CLASS eq 'Config::IOD') {
                 $res = $parser->read_string($args{input})->dump;
             } else {
                 $res = $parser->read_string($args{input});
             }
         };
         my $err = $@;
         if ($args{dies}) {
             ok($err, "dies") or diag explain $res;
             return;
         } else {
             ok(!$err, "doesn't die")
                 or do { diag explain "err=$err"; return };
             is_deeply($res, $args{result}, 'result')
                 or diag explain $res;
         }
     };
 }
 
 1;
 # ABSTRACT: Common tests for Config::IOD and Config::IOD::Reader
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Test::Config::IOD::Common - Common tests for Config::IOD and Config::IOD::Reader
 
 =head1 VERSION
 
 This document describes version 0.19 of Test::Config::IOD::Common (from Perl distribution Config-IOD-Reader), released on 2015-09-08.
 
 =for Pod::Coverage .+
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Config-IOD-Reader>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Config-IOD-Reader>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Config-IOD-Reader>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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
### Test/Data/Sah.pm ###
 package Test::Data::Sah;
 
 our $DATE = '2015-10-18'; # DATE
 our $VERSION = '0.74'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 
 use Data::Dump qw(dump);
 use Data::Sah qw(gen_validator);
 use Test::More 0.98;
 
 use Exporter qw(import);
 our @EXPORT_OK = qw(test_sah_cases);
 
 # XXX support js & human testing too
 sub test_sah_cases {
     my $tests = shift;
     my $opts  = shift // {};
 
     my $sah = Data::Sah->new;
     my $plc = $sah->get_compiler('perl');
 
     my $gvopts = $opts->{gen_validator_opts} // {};
     my $rt = $gvopts->{return_type} // 'bool';
 
     for my $test (@$tests) {
         my $v = gen_validator($test->{schema}, $gvopts);
         my $res = $v->($test->{input});
         my $name = $test->{name} //
             "data " . dump($test->{input}) . " should".
                 ($test->{valid} ? " pass" : " not pass"). " schema " .
                     dump($test->{schema});
         my $testres;
         if ($test->{valid}) {
             if ($rt eq 'bool') {
                 $testres = ok($res, $name);
             } elsif ($rt eq 'str') {
                 $testres = is($res, "", $name) or diag explain $res;
             } elsif ($rt eq 'full') {
                 $testres = is(~~keys(%{$res->{errors}}), 0, $name) or diag explain $res;
             }
         } else {
             if ($rt eq 'bool') {
                 $testres = ok(!$res, $name);
             } elsif ($rt eq 'str') {
                 $testres = isnt($res, "", $name) or diag explain $res;
             } elsif ($rt eq 'full') {
                 $testres = isnt(~~keys(%{$res->{errors}}), 0, $name) or diag explain $res;
             }
         }
         next if $testres;
 
         # when test fails, show the validator generated code to help debugging
         my $cd = $plc->compile(schema => $test->{schema});
         diag "schema compilation result:\n----begin generated code----\n",
             explain($cd->{result}), "\n----end generated code----\n",
                 "that code should return ", ($test->{valid} ? "true":"false"),
                     " when fed \$data=", dump($test->{input}),
                         " but instead returns ", dump($res);
 
         # also show the result for return_type=full
         my $vfull = gen_validator($test->{schema}, {return_type=>"full"});
         diag "\nvalidator result (full):\n----begin result----\n",
             explain($vfull->($test->{input})), "----end result----";
     }
 }
 
 1;
 # ABSTRACT: Test routines for Data::Sah
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Test::Data::Sah - Test routines for Data::Sah
 
 =head1 VERSION
 
 This document describes version 0.74 of Test::Data::Sah (from Perl distribution Data-Sah), released on 2015-10-18.
 
 =head1 FUNCTIONS
 
 =head2 test_sah_cases(\@tests)
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Data-Sah>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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
### Test/Perinci/Sub/Wrapper.pm ###
 package Test::Perinci::Sub::Wrapper;
 
 our $DATE = '2015-09-04'; # DATE
 our $VERSION = '0.79'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 
 use Function::Fallback::CoreOrPP qw(clone);
 #use List::Util qw(shuffle);
 use Perinci::Sub::Wrapper qw(wrap_sub);
 use Test::More 0.96;
 
 our @ISA = qw(Exporter);
 our @EXPORT_OK = qw(test_wrap);
 
 sub test_wrap {
     my %test_args = @_;
     $test_args{wrap_args} or die "BUG: wrap_args not defined";
     my $test_name = $test_args{name} or die "BUG: test_name not defined";
 
     for my $wrapper_type (qw/dynamic embed/) {
         next if $wrapper_type eq 'dynamic' && $test_args{skip_dynamic};
         next if $wrapper_type eq 'embed'   && $test_args{skip_embed};
         subtest "$test_name ($wrapper_type)" => sub {
 
             if ($test_args{pretest}) {
                 $test_args{pretest}->();
             }
 
             my $wrap_args = clone($test_args{wrap_args});
             die "BUG: embed must not be specified in wrap_args, test_wrap() ".
                 "will always test dynamic (embed=0) *and* embed mode"
                     if exists $wrap_args->{embed};
             if ($wrapper_type eq 'embed') {
                 $wrap_args->{embed} = 1;
                 #diag explain $wrap_args->{meta};
             } else {
                 $wrap_args->{embed} = 0;
             }
 
             my $wrap_res;
             eval { $wrap_res = wrap_sub(%$wrap_args) };
             my $wrap_eval_err = $@;
             if ($test_args{wrap_dies}) {
                 ok($wrap_eval_err, "wrap dies");
                 return;
             } else {
                 ok(!$wrap_eval_err, "wrap doesn't die") or do {
                     diag $wrap_eval_err;
                     return;
                 };
             }
 
             if (defined $test_args{wrap_status}) {
                 is(ref($wrap_res), 'ARRAY', 'wrap res is array');
                 is($wrap_res->[0], $test_args{wrap_status},
                    "wrap status is $test_args{wrap_status}")
                     or diag "wrap res: ", explain($wrap_res);
             }
 
             return unless $wrap_res->[0] == 200;
 
             my $sub;
             if ($wrapper_type eq 'embed') {
                 my $src = $wrap_res->[2]{source};
                 my $meta = $wrap_res->[2]{meta};
                 my $args_as = $meta->{args_as};
                 my $orig_args_as = $wrap_args->{meta}{args_as} // 'hash';
                 my $sub_name = $wrap_res->[2]{sub_name};
                 my $eval_src = join(
                     "\n",
                     $src->{presub1},
                     $src->{presub2},
                     'sub {',
                     '    my %args;',
                     ('    my @args;') x !!($orig_args_as eq 'array' || $args_as eq 'array'),
                     ('    my $args;') x !!($orig_args_as =~ /ref/ || $args_as =~ /ref/),
                     '    '.
                         ($args_as eq 'hash' ? '%args = @_;' :
                              $args_as eq 'hashref' ? '$args = $_[0] // {}; %args = %$args;' :
                                  $args_as eq 'array' ? '@args = @_;' :
                                      '$args = $_[0] // [];'),
                     $src->{preamble},
                     ($src->{postamble} ? '    $_w_res = do {' : ''),
                     $sub_name. ($sub_name =~ /\A\$/ ? '->':'').'('.
                         ($orig_args_as eq 'hash' ? '%args' :
                              $orig_args_as eq 'hashref' ? '$args' :
                                  $orig_args_as eq 'array' ? '@args' :
                                      '$args').');',
                     ($src->{postamble} ? '}; # do' : ''),
                     $src->{postamble},
                     '}; # sub',
                 );
                 $sub = eval $eval_src;
                 my $eval_err = $@;
                 ok(!$eval_err, "embed code compiles ok") or do {
                     diag "eval err: ", $eval_err;
                     diag "eval source: ", $eval_src;
                     return;
                 };
                 diag "eval source: ", $eval_src
                     if $ENV{LOG_PERINCI_WRAPPER_CODE};
             } else {
 
                 # check that we don't generate comment after code (unless it
                 # uses '##' instead of '#'), because this makes cutting comments
                 # easier. XXX this is using a simple regex and misses some.
                 for my $line (split /^/, $wrap_res->[2]{source}) {
                     if ($line =~ /(.*?)\s+#\s+(.*)/) {
                         my ($before, $after) = ($1, $2);
                         next unless $before =~ /\S/;
                         ok 0; diag "Source code contains comment line after some code '$line' (if you do this, you must use ## instead of # to help ease removing comment lines (e.g. in Dist::Zilla::Plugin::Rinci::Wrap))";
                     }
                 }
 
                 $sub = $wrap_res->[2]{sub};
             }
 
             # testing a single sub call
             my $call_argsr = $test_args{call_argsr};
             my $call_res;
             if ($call_argsr) {
                 eval { $call_res = $sub->(@$call_argsr) };
                 my $call_eval_err = $@;
                 if ($test_args{call_dies}) {
                     ok($call_eval_err, "call dies");
                     if ($test_args{call_die_message}) {
                         like($call_eval_err, $test_args{call_die_message},
                              "call die message");
                     }
                     return;
                 } else {
                     ok(!$call_eval_err, "call doesn't die")
                         or diag $call_eval_err;
                 }
 
                 if (defined $test_args{call_status}) {
                     is(ref($call_res), 'ARRAY', 'call res is array')
                         or diag "call res = ", explain($call_res);
                     is($call_res->[0], $test_args{call_status},
                        "call status is $test_args{call_status}")
                         or diag "call res = ", explain($call_res);
                 }
 
                 if (exists $test_args{call_res}) {
                     is_deeply($call_res, $test_args{call_res},
                               "call res")
                         or diag explain $call_res;
                 }
 
                 if (exists $test_args{call_actual_res}) {
                     is_deeply($call_res->[2], $test_args{call_actual_res},
                               "call actual res")
                         or diag explain $call_res->[2];
                 }
 
                 if (exists $test_args{call_actual_res_re}) {
                     like($call_res->[2], $test_args{call_actual_res_re},
                          "call actual res");
                 }
             }
 
             # testing multiple sub calls
             if ($test_args{calls}) {
                 my $i = 0;
                 for my $call (@{$test_args{calls}}) {
                     $i++;
                     subtest "call #$i: ".($call->{name} // "") => sub {
                         my $res;
                         eval { $res = $sub->(@{$call->{argsr}}) };
                         my $eval_err = $@;
                         if ($call->{dies}) {
                             ok($eval_err, "dies");
                             if ($call->{die_message}) {
                                 like($eval_err, $call->{die_message},
                                      "die message");
                             }
                             return;
                         } else {
                             ok(!$eval_err, "doesn't die")
                                 or diag $eval_err;
                         }
 
                         if (defined $call->{status}) {
                             is(ref($res), 'ARRAY', 'res is array')
                                 or diag "res = ", explain($res);
                             is($res->[0], $call->{status},
                                "status is $call->{status}")
                                 or diag "res = ", explain($res);
                         }
 
                         if (exists $call->{res}) {
                             is_deeply($res, $call->{res}, "res")
                                 or diag explain $res;
                         }
 
                         if (exists $call->{actual_res}) {
                             is_deeply($res->[2], $call->{actual_res}, "actual res")
                                 or diag explain $res->[2];
                         }
 
                         if (exists $call->{actual_res_re}) {
                             like($res->[2], $call->{actual_res_re},
                                  "actual res re");
                         }
                     }; # subtest call #$i
                 }
             } # if calls
 
             if ($test_args{posttest}) {
                 $test_args{posttest}->($wrap_res, $call_res, $sub);
             }
 
             done_testing();
 
         }; # subtest
     } # for $wrapper_type
 }
 
 1;
 # ABSTRACT: Provide test_wrap() to test wrapper
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Test::Perinci::Sub::Wrapper - Provide test_wrap() to test wrapper
 
 =head1 VERSION
 
 This document describes version 0.79 of Test::Perinci::Sub::Wrapper (from Perl distribution Perinci-Sub-Wrapper), released on 2015-09-04.
 
 =for Pod::Coverage test_wrap
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Perinci-Sub-Wrapper>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Perinci-Sub-Wrapper>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Perinci-Sub-Wrapper>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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
### Test/SharedFork.pm ###
 package Test::SharedFork;
 use strict;
 use warnings;
 use base 'Test::Builder::Module';
 our $VERSION = '0.34';
 use Test::Builder 0.32; # 0.32 or later is needed
 use Test::SharedFork::Scalar;
 use Test::SharedFork::Array;
 use Test::SharedFork::Store;
 use Config;
 use 5.008000;
 
 {
     package #
         Test::SharedFork::Contextual;
 
     sub call {
         my $code = shift;
         my $wantarray = [caller(1)]->[5];
         if ($wantarray) {
             my @result = $code->();
             bless {result => \@result, wantarray => $wantarray}, __PACKAGE__;
         } elsif (defined $wantarray) {
             my $result = $code->();
             bless {result => $result, wantarray => $wantarray}, __PACKAGE__;
         } else {
             { ; $code->(); } # void context
             bless {wantarray => $wantarray}, __PACKAGE__;
         }
     }
 
     sub result {
         my $self = shift;
         if ($self->{wantarray}) {
             return @{ $self->{result} };
         } elsif (defined $self->{wantarray}) {
             return $self->{result};
         } else {
             return;
         }
     }
 }
 
 my $STORE;
 
 sub _mangle_builder {
     my $builder = shift;
 
     if( $] >= 5.008001 && $Config{useithreads} && $INC{'threads.pm'} ) {
         die "# Current version of Test::SharedFork does not supports ithreads.";
     }
 
     if ($builder->can("coordinate_forks")) {
         # Use Test::Builder's implementation.
         $builder->new->coordinate_forks(1);
     } elsif($INC{'Test/Stream/Sync.pm'}) {
         require Test::Stream::IPC;
         Test::Stream::IPC->import('poll');
         Test::Stream::IPC->enable_polling if Test::Stream::IPC->can('enable_polling');
         my $stack = $builder->{Stack};
         return if $stack->top->ipc;
         my ($driver) = Test::Stream::IPC->drivers;
         my $ipc = $driver->new();
         for my $hub (@$stack) {
             $hub->set_ipc($ipc);
             $ipc->add_hub($hub->hid);
         }
     } else {
         # older Test::Builder
         $STORE = Test::SharedFork::Store->new(
             cb => sub {
                 my $store = shift;
                 tie $builder->{Curr_Test}, 'Test::SharedFork::Scalar',
                     $store, 'Curr_Test';
                 tie $builder->{Is_Passing}, 'Test::SharedFork::Scalar',
                     $store, 'Is_Passing';
                 tie @{ $builder->{Test_Results} },
                     'Test::SharedFork::Array', $store, 'Test_Results';
             },
             init => +{
                 Test_Results => $builder->{Test_Results},
                 Curr_Test    => $builder->{Curr_Test},
                 Is_Passing   => 1,
             },
         );
 
         # make methods atomic.
         no strict 'refs';
         no warnings 'redefine';
         no warnings 'uninitialized';
         for my $name (qw/ok skip todo_skip current_test is_passing/) {
             my $orig = *{"Test::Builder::${name}"}{CODE};
             *{"Test::Builder::${name}"} = sub {
                 local $Test::Builder::Level = $Test::Builder::Level + 1;
                 local $Test::Builder::BLevel = $Test::Builder::BLevel + 1;
                 my $lock = $STORE->get_lock(); # RAII
                 $orig->(@_);
             };
         };
     }
 }
 
 BEGIN {
     my $builder = __PACKAGE__->builder;
     _mangle_builder($builder);
 }
 
 {
     # backward compatibility method
     sub parent { }
     sub child  { }
     sub fork   { fork() }
 }
 
 1;
 __END__
 
 =for stopwords slkjfd yappo konbuizm
 
 =head1 NAME
 
 Test::SharedFork - fork test
 
 =head1 SYNOPSIS
 
     use Test::More tests => 200;
     use Test::SharedFork;
 
     my $pid = fork();
     if ($pid == 0) {
         # child
         ok 1, "child $_" for 1..100;
     } elsif ($pid) {
         # parent
         ok 1, "parent $_" for 1..100;
         waitpid($pid, 0);
     } else {
         die $!;
     }
 
 =head1 DESCRIPTION
 
 Test::SharedFork is utility module for Test::Builder.
 
 This module makes L<fork(2)> safety in your test case.
 
 This module merges test count with parent process & child process.
 
 =head1 LIMITATIONS
 
 This version of the Test::SharedFork does not support ithreads, because L<threads::shared> conflicts with L<Storable>.
 
 =head1 AUTHOR
 
 Tokuhiro Matsuno E<lt>tokuhirom  slkjfd gmail.comE<gt>
 
 yappo
 
 =head1 THANKS TO
 
 kazuhooku
 
 konbuizm
 
 =head1 SEE ALSO
 
 L<Test::TCP>, L<Test::Fork>, L<Test::MultiFork>
 
 =head1 LICENSE
 
 This library is free software; you can redistribute it and/or modify
 it under the same terms as Perl itself.
 
 =cut
### Test/SharedFork/Array.pm ###
 package Test::SharedFork::Array;
 use strict;
 use warnings;
 use base 'Tie::Array';
 use Storable ();
 
 # create new tied array
 sub TIEARRAY {
     my ($class, $share, $key) = @_;
     die "missing key" unless $key;
     my $self = bless { share => $share, key => $key }, $class;
     $self;
 }
 
 
 sub _get {
     my $self = shift;
     my $lock = $self->{share}->get_lock();
     return $self->{share}->get($self->{key});
 }
 sub FETCH {
     my ($self, $index) = @_;
     $self->_get()->[$index];
 }
 sub FETCHSIZE {
     my $self = shift;
     my $ary = $self->_get();
     scalar @$ary;
 }
 
 sub STORESIZE {
     my ($self, $size) = @_;
     my $lock = $self->{share}->get_lock();
     my $ary  = $self->_get();
     $#$ary   = $size - 1;
 }
 
 sub STORE {
     my ($self, $index, $val) = @_;
 
     my $lock = $self->{share}->get_lock();
 
     my $share = $self->{share};
     my $cur = $share->get($self->{key});
     $cur->[$index] = $val;
     $share->set($self->{key} => $cur);
 }
 
 1;
### Test/SharedFork/Scalar.pm ###
 package Test::SharedFork::Scalar;
 use strict;
 use warnings;
 use base 'Tie::Scalar';
 
 # create new tied scalar
 sub TIESCALAR {
     my ($class, $share, $key) = @_;
     die "missing key" unless $key;
     bless { share => $share, key => $key }, $class;
 }
 
 sub FETCH {
     my $self = shift;
     my $lock = $self->{share}->get_lock();
     $self->{share}->get($self->{key});
 }
 
 sub STORE {
     my ($self, $val) = @_;
     my $share = $self->{share};
     my $lock = $self->{share}->get_lock();
     $share->set($self->{key} => $val);
 }
 
 1;
### Test/SharedFork/Store.pm ###
 package Test::SharedFork::Store;
 use strict;
 use warnings;
 use Storable ();
 use Fcntl ':seek', ':DEFAULT', ':flock';
 use File::Temp ();
 use IO::Handle;
 
 sub new {
     my $class = shift;
     my %args = @_;
     my $filename = File::Temp::tmpnam();
 
     my $init = Storable::dclone($args{init} || +{});
 
     my $self = bless {
         callback_on_open => $args{cb},
         filename         => $filename,
         lock             => 0,
         pid              => $$,
         ppid             => $$,
     }, $class;
     $self->open();
 
     # initialize
     Storable::nstore_fd($init, $self->{fh}) or die "Cannot write initialize data to $filename";
 
     return $self;
 }
 
 sub open {
     my $self = shift;
     if (my $cb = $self->{callback_on_open}) {
         $cb->($self);
     }
     sysopen my $fh, $self->{filename}, O_RDWR|O_CREAT or die $!;
     $fh->autoflush(1);
     $self->{fh} = $fh;
 }
 
 sub close {
     my $self = shift;
     close $self->{fh};
     undef $self->{fh};
 }
 
 sub get {
     my ($self, $key) = @_;
     $self->_reopen_if_needed;
     seek $self->{fh}, 0, SEEK_SET or die $!;
     Storable::fd_retrieve($self->{fh})->{$key};
 }
 
 sub set {
     my ($self, $key, $val) = @_;
 
     $self->_reopen_if_needed;
 
     seek $self->{fh}, 0, SEEK_SET or die $!;
     my $dat = Storable::fd_retrieve($self->{fh});
     $dat->{$key} = $val;
 
     truncate $self->{fh}, 0;
     seek $self->{fh}, 0, SEEK_SET or die $!;
     Storable::nstore_fd($dat => $self->{fh}) or die "Cannot store data to $self->{filename}";
 }
 
 sub get_lock {
     my ($self, ) = @_;
     Test::SharedFork::Store::Locker->new($self);
 }
 
 sub _reopen_if_needed {
     my $self = shift;
     if ($self->{pid} != $$) { # forked, and I'm just a child.
         $self->{pid} = $$;
         if ($self->{lock} > 0) { # unlock! I'm not owner!
             flock $self->{fh}, LOCK_UN or die $!;
             $self->{lock} = 0;
         }
         $self->close();
         $self->open();
     }
 }
 
 sub DESTROY {
     my $self = shift;
     if ($self->{ppid} eq $$) { # cleanup method only run on original process.
         unlink $self->{filename};
     }
 }
 
 package # hide from pause
     Test::SharedFork::Store::Locker;
 
 use Fcntl ':flock';
 
 sub new {
     my ($class, $store) = @_;
 
     $store->_reopen_if_needed;
 
     if ($store->{lock}++ == 0) {
         flock $store->{fh}, LOCK_EX or die $!;
     }
 
     bless { store => $store }, $class;
 }
 
 sub DESTROY {
     my ($self) = @_;
 
     $self->{store}->{lock}--;
     if ($self->{store}->{lock} == 0) {
         flock $self->{store}->{fh}, LOCK_UN or die $!;
     }
 }
 
 1;
### Text/ANSI/BaseUtil.pm ###
 package Text::ANSI::BaseUtil;
 
 our $DATE = '2015-08-20'; # DATE
 our $VERSION = '0.21'; # VERSION
 
 use 5.010001;
 use strict;
 use warnings;
 
 use List::Util qw(min max);
 
 our $re       = qr/\e\[[0-9;]+m/s;
 our $re_mult  = qr/(?:\e\[[0-9;]+m)+/s;
 
 sub ta_detect {
     my $text = shift;
     $text =~ $re ? 1:0;
 }
 
 sub ta_length {
     my $text = shift;
     length(ta_strip($text));
 }
 
 sub _ta_length_height {
     my ($is_mb, $text) = @_;
     my $num_lines = 0;
     my @lens;
     for my $e (split /(\r?\n)/, ta_strip($text)) {
         if ($e =~ /\n/) {
             $num_lines++;
             next;
         }
         $num_lines = 1 if $num_lines == 0;
         push @lens, $is_mb ? Text::WideChar::Util::mbswidth($e) : length($e);
     }
     [max(@lens) // 0, $num_lines];
 }
 
 sub ta_length_height {
     _ta_length_height(0, @_);
 }
 
 sub ta_mbswidth_height {
     _ta_length_height(1, @_);
 }
 
 sub ta_strip {
     my $text = shift;
     $text =~ s/$re//go;
     $text;
 }
 
 sub ta_extract_codes {
     my $text = shift;
     my $res = "";
     $res .= $1 while $text =~ /($re_mult)/go;
     $res;
 }
 
 sub ta_split_codes {
     my $text = shift;
     return split(/($re_mult)/o, $text);
 }
 
 sub ta_split_codes_single {
     my $text = shift;
     return split(/($re)/o, $text);
 }
 
 # same like _ta_mbswidth, but without handling multiline text
 sub _ta_mbswidth0 {
     my $text = shift;
     Text::WideChar::Util::mbswidth(ta_strip($text));
 }
 
 sub ta_mbswidth {
     my $text = shift;
     ta_mbswidth_height($text)->[0];
 }
 
 sub _ta_wrap {
     my ($is_mb, $text, $width, $opts) = @_;
     $width //= 80;
     $opts  //= {};
 
     # basically similar to Text::WideChar::Util's algorithm. we adjust for
     # dealing with ANSI codes by splitting codes first (to easily do color
     # resets/replays), then grouping into words and paras, then doing wrapping.
 
     my $_re1 = $is_mb ?
         qr/($Text::WideChar::Util::re_cjk+)|(\S+)|(\s+)/ :
         qr/()(\S+)|(\s+)/;
 
     my $_re2 = $is_mb ?
         qr/($Text::WideChar::Util::re_cjk_class+)|
            ($Text::WideChar::Util::re_cjk_negclass+)/x : undef;
 
     my @termst; # store term type, 's' (spaces), 'w' (word), 'c' (cjk word) or
                 # 'p' (parabreak)
     my @terms;  # store the text (w/ codes); for ws, only store the codes
     my @pterms; # store the plaintext ver, but only for ws to check parabreak
     my @termsw; # store width of each term, only for non-ws
     my @termsc; # store color replay code
     {
         my @ch = ta_split_codes_single($text);
         my $crcode = ""; # code for color replay to be put at the start of line
         my $term      = '';
         my $pterm     = '';
         my $prev_type = '';
         while (my ($pt, $c) = splice(@ch, 0, 2)) {
             #use Data::Dump; print "D:chunk: "; dd [$pt, $c];
 
             # split into (CJK and non-CJK) words and spaces.
 
             my @s; # (WORD1, TYPE, ...) where type is 's' for space, 'c' for
                    # CJK word, or 'w' for non-CJK word
             while ($pt =~ /$_re1/g) {
                 if ($is_mb && $1) {
                     push @s, $1, 'c';
                 } elsif ($3) {
                     push @s, $3, 's';
                 } else {
                     if ($is_mb) {
                         my $pt2 = $2;
                         while ($pt2 =~ /$_re2/g) {
                             if ($1) {
                                 push @s, $1, 'c';
                             } else {
                                 push @s, $2, 'w';
                             }
                         }
                     } else {
                         push @s, $2, 'w';
                     }
                 }
             }
 
             #use Data::Dump; say "D:s=",Data::Dump::dump(\@s);
 
             my $only_code = 1 if !@s;
             while (1) {
                 my ($s, $s_type) = splice @s, 0, 2;
                 $s_type //= '';
                 last unless $only_code || defined($s);
                 # empty text, only code
                 if ($only_code) {
                     $s = "";
                     $term .= $c if defined $c;
                 }
                 #say "D:s=[$s]  prev_type=$prev_type \@ch=",~~@ch,"  \@s=",~~@s;
 
                 if ($s_type && $s_type ne 's') {
                     if ($prev_type eq 's') {
                         #say "D:found word, completed previous ws [$term]";
                         push @termst, 's';
                         push @terms , $term;
                         push @pterms, $pterm;
                         push @termsw, undef;
                         push @termsc, $crcode;
                         # start new word
                         $pterm = ''; $term = '';
                     } elsif ($prev_type && $prev_type ne $s_type) {
                         #say "D:found a ".($s_type eq 'c' ? 'CJK':'non-CJK')." word, completed previous ".($prev_type eq 'c' ? 'CJK':'non-CJK')." word [$term]";
                         push @termst, $prev_type;
                         push @terms , $term;
                         push @pterms, $pterm;
                         push @termsw, $is_mb ? Text::WideChar::Util::mbswidth($pterm):length($pterm);
                         push @termsc, $crcode;
                         # start new word
                         $pterm = ''; $term = '';
                     }
                     $pterm .= $s;
                     $term  .= $s; $term .= $c if defined($c) && !@s;
                     if (!@s && !@ch) {
                         #say "D:complete word because this is the last token";
                         push @termst, $s_type;
                         push @terms , $term;
                         push @pterms, "";
                         push @termsw, $is_mb ? Text::WideChar::Util::mbswidth($pterm):length($pterm);
                         push @termsc, $crcode;
                     }
                 } elsif (length($s)) {
                     if ($prev_type ne 's') {
                         #say "D:found ws, completed previous word [$term]";
                         push @termst, $prev_type;
                         push @terms , $term;
                         push @pterms, "";
                         push @termsw, $is_mb ? Text::WideChar::Util::mbswidth($pterm):length($pterm);
                         push @termsc, $crcode;
                         # start new ws
                         $pterm = ''; $term = '';
                     }
                     $pterm .= $s;
                     $term  .= $c if defined($c) && !@s;
                     if (!@s && !@ch) {
                         #say "D:complete ws because this is the last token";
                         push @termst, 's';
                         push @terms , $term;
                         push @pterms, $pterm;
                         push @termsw, undef;
                         push @termsc, $crcode;
                     }
                 }
                 $prev_type = $s_type;
 
                 if (!@s) {
                     if (defined($c) && $c =~ /m\z/) {
                         if ($c eq "\e[0m") {
                             #say "D:found color reset, emptying crcode";
                             $crcode = "";
                         } elsif ($c =~ /m\z/) {
                             #say "D:adding to crcode";
                             $crcode .= $c;
                         }
                     }
                     last if $only_code;
                 }
 
             } # splice @s
         } # splice @ch
     }
 
     # mark parabreaks
     {
         my $i = 0;
         while ($i < @pterms) {
             if ($termst[$i] eq 's') {
                 if ($pterms[$i] =~ /[ \t]*(\n(?:[ \t]*\n)+)([ \t]*)/) {
                     #say "D:found parabreak";
                     $pterms[$i] = $1;
                     $termst[$i] = 'p';
                     if ($i < @pterms-1) {
                         # stick color code to the beginning of next para
                         $terms [$i+1] = $terms[$i] . $terms [$i+1];
                         $terms [$i] = "";
                     }
                     if (length $2) {
                         #say "D:found space after parabreak, splitting";
                         splice @termst, $i+1, 0, "s";
                         splice @terms , $i+1, 0, "";
                         splice @pterms, $i+1, 0, $2;
                         splice @termsw, $i+1, 0, undef;
                         splice @termsc, $i+1, 0, $termsc[$i];
                         $i += 2;
                         next;
                     }
                 }
             }
             $i++;
         }
     }
 
     #use Data::Dump::Color; my @d; for (0..$#terms) { push @d, {type=>$termst[$_], term=>$terms[$_], pterm=>$pterms[$_], termc=>$termsc[$_], termw=>$termsw[$_], } } dd \@d;
     #return;
 
     #use Data::Dump; say "D:termst=".Data::Dump::dump(\@termst);
     #use Data::Dump; say "D:terms =".Data::Dump::dump(\@terms);
     #use Data::Dump; say "D:pterms=".Data::Dump::dump(\@pterms);
     #use Data::Dump; say "D:termsw=".Data::Dump::dump(\@termsw);
     #use Data::Dump; say "D:termsc=".Data::Dump::dump(\@termsc);
 
     my ($maxww, $minww);
 
     # now we perform wrapping
 
     my @res;
     {
         my $tw = $opts->{tab_width} // 8;
         die "Please specify a positive tab width" unless $tw > 0;
         my $optfli  = $opts->{flindent};
         my $optfliw = Text::WideChar::Util::_get_indent_width($is_mb, $optfli, $tw) if defined $optfli;
         my $optsli  = $opts->{slindent};
         my $optsliw = Text::WideChar::Util::_get_indent_width($is_mb, $optsli, $tw) if defined $optsli;
         my $pad = $opts->{pad};
         my $x = 0;
         my $y = 0;
         my ($fli, $sli, $fliw, $sliw);
         my $is_parastart = 1;
         my $line_has_word = 0;
         my ($termt, $prev_t);
       TERM:
         for my $i (0..$#terms) {
             $prev_t = $termt if $i;
             $termt = $termst[$i];
             my $term  = $terms[$i];
             my $pterm = $pterms[$i];
             my $termw = $termsw[$i];
             my $crcode = $i > 0 ? $termsc[$i-1] : "";
             #say "D:term=[", ($termt eq 'w' ? $term : $pterm), "] ($termt)";
 
             # end of paragraph
             if ($termt eq 'p') {
                 my $numnl = 0;
                 $numnl++ while $pterm =~ /\n/g;
                 for (1..$numnl) {
                     push @res, "\e[0m" if $crcode && $_ == 1;
                     push @res, " " x ($width-$x) if $pad;
                     push @res, "\n";
                     $x = 0;
                     $y++;
                 }
                 $line_has_word = 0;
                 $x = 0;
                 $is_parastart = 1;
                 next TERM;
             }
 
             if ($is_parastart) {
                 # this is the start of paragraph, determine indents
                 if (defined $optfli) {
                     $fli  = $optfli;
                     $fliw = $optfliw;
                 } else {
                     if ($termt eq 's') {
                         $fli  = $pterm;
                         $fliw = Text::WideChar::Util::_get_indent_width($is_mb, $fli, $tw);
                     } else {
                         $fli  = "";
                         $fliw = 0;
                     }
                     #say "D:deduced fli from text [$fli] ($fliw)";
                     my $j = $i;
                     $sli = undef;
                     while ($j < @terms && $termst[$j] ne 'p') {
                         if ($termst[$j] eq 's') {
                             if ($pterms[$j] =~ /\n([ \t]+)/) {
                                 $sli  = $1;
                                 $sliw = Text::WideChar::Util::_get_indent_width($is_mb, $sli, $tw);
                                 last;
                             }
                         }
                         $j++;
                     }
                     if (!defined($sli)) {
                         $sli  = "";
                         $sliw = 0;
                     }
                     #say "D:deduced sli from text [$sli] ($sliw)";
                     die "Subsequent indent must be less than width" if $sliw >= $width;
                 }
 
                 #say "D:inserting the fli [$fli] ($fliw)";
                 push @res, $fli;
                 $x += $fliw;
             } # parastart
 
             $is_parastart = 0;
 
             if ($termt eq 's') {
                 # just print the codes
                 push @res, $term;
 
                 # maintain terminating newline
                 if ($pterm =~ /\n/ && $i == $#terms) {
                     push @res, "\e[0m" if $crcode;
                     push @res, " " x ($width-$x) if $pad;
                     push @res, "\n";
                     $line_has_word = 0;
                 }
             }
 
             if ($termt ne 's') {
                 # we need to chop long words
                 my @words;
                 my @wordsw;
                 my @wordst; # c if cjk, w if not
                 my @wordswsb; # whether there are ws before the word
                 my $j = 0;
                 my $c = ""; # see below for explanation
                 while (1) {
                     $j++;
                     # most words shouldn't be that long. and we don't need to
                     # truncate long CJK word first here because it will get
                     # truncated later.
                     if ($termw <= $width-$sliw || $termt eq 'c') {
                         push @words   , $c . $term;
                         push @wordsw  , $termw;
                         push @wordst  , $termt;
                         push @wordswsb, ($prev_t && $prev_t eq 's')?1:0;
                         last;
                     }
                     #use Data::Dump; print "D:truncating long word "; dd $term;
                     my $res = $is_mb ? ta_mbtrunc($term, $width-$sliw, 1) :
                         ta_trunc($term, $width-$sliw, 1);
 
                     my ($tword, $twordw);
                     if ($j == 1) {
                         $tword  = $res->[0];
                         $twordw = $res->[1];
                     } else {
                         # since ta_{,mb}trunc() adds the codes until the end of
                         # the word, to avoid messing colors, for the second word
                         # and so on we need to replay colors by prefixing with:
                         # \e[0m (reset) + $crcode + (all the codes from the
                         # start of the long word up until the truncated
                         # position, stored in $c).
                         #
                         # there might be faster way, but it is expected that
                         # long words are not that common.
                         $tword  = ($crcode ? "\e[0m" . $crcode : "") .
                             $c . $res->[0];
                         $twordw = $res->[1];
                     }
                     $c .= ta_extract_codes(substr($term, 0, $res->[2]));
                     #use Data::Dump; print "D:truncated word is "; dd $tword;
 
                     push @words   , $tword;
                     push @wordsw  , $twordw;
                     push @wordst  , $termt;
                     push @wordswsb, $j == 1 ? (($prev_t && $prev_t eq 's')?1:0) : 0;
                     $term  = substr($term, $res->[2]);
                     $termw = $is_mb ? _ta_mbswidth0($term) : ta_length($term);
                 }
 
                 #use Data::Dump; print "D:words="; dd \@words; print "D:wordsw="; dd \@wordsw; print "D:wordswsb="; dd \@wordswsb;
 
                 # the core of the wrapping algo
                 for my $word (@words) {
                     my $wordw = shift @wordsw;
                     my $wordt = shift @wordst;
                     my $ws_before = shift @wordswsb;
                     #say "D:x=$x word=$word wordw=$wordw wordt=$wordt ws_before=$ws_before line_has_word=$line_has_word width=$width";
 
                     $maxww = $wordw if !defined($maxww) || $maxww < $wordw;
                     $minww = $wordw if !defined($minww) || $minww > $wordw;
 
                     if ($x + ($line_has_word ? 1:0) + $wordw <= $width) {
                         if ($line_has_word && $ws_before) {
                             push @res, " ";
                             $x++;
                         }
                         push @res, $word;
                         $x += $wordw;
                     } else {
                         # line break
                         while (1) {
                             if ($wordt eq 'c') {
                                 # a CJK word can be line-broken
                                 my $res;
                                 if ($ws_before) {
                                     $res = ta_mbtrunc($word, $width-$x-1, 1);
                                     push @res, " ", $res->[0];
                                 } else {
                                     $res = ta_mbtrunc($word, $width-$x, 1);
                                     push @res, $res->[0];
                                 }
                                 #say "D:truncated CJK word: $word (".length($word)."), ".($width-$x)." -> $res->[0] (".length($res->[0]).") & $res->[1], remaining=$res->[3] (".length($res->[3]).")";
                                 $word = $res->[3];
                                 $wordw = _ta_mbswidth0($res->[3]);
                             } else {
                                 push @res, "\e[0m" if $crcode;
                             }
                             push @res, " " x ($width-$x) if $pad;
                             push @res, "\n";
                             $y++;
                             push @res, $crcode;
                             push @res, $sli;
 
                             if ($sliw + $wordw <= $width) {
                                 push @res, $word;
                                 $x = $sliw + $wordw;
                                 last;
                             } else {
                                 # word still too long, break again
                                 $x = $sliw;
                             }
                         }
                     }
                     $line_has_word++;
                 }
 
             }
         } # for term
         push @res, " " x ($width-$x) if $line_has_word && $pad;
     }
 
     if ($opts->{return_stats}) {
         return [join("", @res), {
             max_word_width => $maxww,
             min_word_width => $minww,
         }];
     } else {
         return join("", @res);
     }
 }
 
 sub ta_wrap {
     _ta_wrap(0, @_);
 }
 
 sub ta_mbwrap {
     _ta_wrap(1, @_);
 }
 
 sub _ta_pad {
     my ($is_mb, $text, $width, $which, $padchar, $is_trunc) = @_;
     if ($which) {
         $which = substr($which, 0, 1);
     } else {
         $which = "r";
     }
     $padchar //= " ";
 
     my $w = $is_mb ? _ta_mbswidth0($text) : ta_length($text);
     if ($is_trunc && $w > $width) {
         my $res = $is_mb ?
             ta_mbtrunc($text, $width, 1) : ta_trunc($text, $width, 1);
         $text = $res->[0] . ($padchar x ($width-$res->[1]));
     } else {
         if ($which eq 'l') {
             $text = ($padchar x ($width-$w)) . $text;
         } elsif ($which eq 'c') {
             my $n = int(($width-$w)/2);
             $text = ($padchar x $n) . $text . ($padchar x ($width-$w-$n));
         } else {
             $text .= ($padchar x ($width-$w));
         }
     }
     $text;
 }
 
 sub ta_pad {
     _ta_pad(0, @_);
 }
 
 sub ta_mbpad {
     _ta_pad(1, @_);
 }
 
 sub _ta_trunc {
     my ($is_mb, $text, $width, $return_extra) = @_;
 
     # return_extra (undocumented): if set to 1, will return [truncated_text,
     # visual width, length(chars) up to truncation point, rest of the text not
     # included]
 
     my $w = $is_mb ? _ta_mbswidth0($text) : ta_length($text);
     if ($w <= $width) {
         return $return_extra ? [$text, $w, length($text), ''] : $text;
     }
     my @p = ta_split_codes_single($text);
     my $res = '';
     my $append = 1; # whether we should add more text
     my $code4rest = '';
     my $rest = '';
     $w = 0;
     my $c = 0;
     #use Data::Dump; dd \@p;
     while (my ($t, $ansi) = splice @p, 0, 2) {
         #say "D: t=<$t>, \@p=", ~~@p, ", code4rest=<$code4rest>, rest=<$rest>";
         if ($append) {
             my $tw = $is_mb ? Text::WideChar::Util::mbswidth($t) : length($t);
             #say "D: tw=$tw";
             if ($w+$tw <= $width) {
                 $res .= $t;
                 $w += $tw;
                 $c += length($t);
                 $append = 0 if $w == $width;
                 #say "D:end1" unless $append;
             } else {
                 my $tres = $is_mb ?
                     Text::WideChar::Util::mbtrunc($t, $width-$w, 1) :
                       [substr($t, 0, $width-$w), $width-$w, $width-$w];
                 #use Data::Dump; dd $tres;
                 $res .= $tres->[0];
                 $w += $tres->[1];
                 $c += $tres->[2];
                 $rest = substr($t, $tres->[2]);
                 $append = 0;
                 #say "D:end2";
             }
         } else {
             $rest .= $t;
         }
         if (defined $ansi) {
             if ($append) {
                 if ($ansi eq "\e[0m") {
                     #say "D:found color reset, resetting code4rest";
                     $c = length($ansi);
                     $code4rest = $ansi;
                 } else {
                     $c += length($ansi);
                     $code4rest .= $ansi;
                 }
                 $res .= $ansi;
             } else {
                 $res .= $ansi;
                 $rest .= $ansi;
             }
         }
     }
 
     # ta_trunc/ta_mbtrunc currently adds unpruned color codes at the end of
     # truncated string. pruned meaning strings of color codes right before reset
     # code is removed, e.g. \e[1m\e[30m...\e[0m becomes \e[0m. you might want to
     # prune the result of trunc using _ta_prune_codes.
 
     if ($return_extra) {
         return [$res, $w, $c, $code4rest . $rest];
     } else {
         return $res;
     }
 }
 
 sub _ta_prune_codes {
     my $text = shift;
     $text =~ s/($re_mult)\e\[0m/\e\[0m/g;
     $text;
 }
 
 sub ta_trunc {
     _ta_trunc(0, @_);
 }
 
 sub ta_mbtrunc {
     _ta_trunc(1, @_);
 }
 
 sub _ta_highlight {
     my ($is_all, $text, $needle, $color) = @_;
 
     # break into chunks
     my (@chptext, @chcode, @chsavedc); # chunk plain texts, codes, saved codes
     my $sc = "";
     my $plaintext = "";
     my @ch = ta_split_codes_single($text);
     while (my ($pt, $c) = splice(@ch, 0, 2)) {
         push @chptext , $pt;
         push @chcode  , $c;
         push @chsavedc, $sc;
         $plaintext .= $pt;
         if (defined($c) && $c =~ /m\z/) {
             if ($c eq "\e[0m") {
                 $sc = "";
             } elsif ($c =~ /m\z/) {
                 $sc .= $c;
             }
         }
     }
     #use Data::Dump; print "\@chptext: "; dd \@chptext; print "\@chcode: "; dd \@chcode; print "\@chsavedc: "; dd \@chsavedc;
 
     # gather a list of needles to highlight, with their positions
     my (@needle, @npos);
     if (ref($needle) eq 'Regexp') {
         my @m = $plaintext =~ /$needle/g;
         return $text unless @m;
         my $pos = 0;
         while ($pos < length($plaintext)) {
             my @pt;
             for (@m) {
                 my $p = index($plaintext, $_, $pos);
                 push @pt, [$p, $_] if $p >= 0;
             }
             last unless @pt;
             my $pmin = $pt[0][0];
             my $t = $pt[0][1];
             for (@pt) {
                 if ($pmin > $_->[0] ||
                         $pmin==$_->[0] && length($t) < length($_->[1])) {
                     $pmin = $_->[0];
                     $t = $_->[1];
                 }
             }
             push @needle, $t;
             push @npos  , $pmin;
             last unless $is_all;
             $pos = $pmin + length($t);
         }
     } else {
         my $pos = 0;
         while (1) {
             #say "D:finding '$needle' in '$plaintext' from pos '$pos'";
             my $p = index($plaintext, $needle, $pos);
             last if $p < 0;
             push @needle, $needle;
             push @npos  , $p;
             last unless $is_all;
             $pos = $p + length($needle);
             last if $pos >= length($plaintext);
         }
         return $text unless @needle;
     }
     #use Data::Dump; print "\@needle: "; dd \@needle; print "\@npos: "; dd \@npos;
 
     my @res;
     my $found = 1;
     my $pos = 0;
     my $i = 0;
     my $curneed = shift @needle;
     my $npos    = shift @npos;
   CHUNK:
     while (1) {
         last if $i >= @chptext;
         my $pos2  = $pos+length($chptext[$i])-1;
         my $npos2 = $npos+length($curneed)-1;
         #say "D: chunk=[$chptext[$i]], npos=$npos, npos2=$npos2, pos=$pos, pos2=$pos2";
         if ($pos > $npos2 || $pos2 < $npos || !$found) {
             #say "D:inserting chunk: [$chptext[$i]]";
             # no need to highlight
             push @res, $chptext[$i];
             push @res, $chcode[$i] if defined $chcode[$i];
             goto L1;
         }
 
         # there is chunk text at the left of needle?
         if ($pos < $npos) {
             my $pre = substr($chptext[$i], 0, $npos-$pos);
             #say "D:inserting pre=[$pre]";
             push @res, $pre;
         }
 
         my $npart = substr($curneed,
                            max(0, $pos-$npos),
                            min($pos2, $npos2)-max($pos, $npos)+1);
         if (length($npart)) {
             #say "D:inserting npart=[$npart]";
             push @res, $color, $npart;
             push @res, "\e[0m";
             #use Data::Dump; dd [$chsaved[$i], $chcode[$i]];
             push @res, $chsavedc[$i];
         }
 
         # is there chunk text at the right of needle?
         if ($npos2 <= $pos2) {
             #say "D:We have run past current needle [$curneed]";
             my $post = substr($chptext[$i], $npos2-$pos+1);
 
             if (@needle) {
                 $curneed = shift @needle;
                 $npos    = shift @npos;
                 #say "D:Finding the next needle ($curneed) at pos $npos";
                 $pos     = $npos2+1;
                 $chptext[$i] = $post;
                 $found = 1;
                 redo CHUNK;
             } else {
                 # we're done finding needle
                 $found = 0;
             }
 
             if (!$found) {
                 #say "D:inserting post=[$post]";
                 push @res, $post;
                 push @res, $chcode[$i] if defined $chcode[$i];
             }
         }
 
       L1:
         $pos = $pos2+1;
         $i++;
     }
 
     join "", @res;
 }
 
 sub ta_highlight {
     _ta_highlight(0, @_);
 }
 
 sub ta_highlight_all {
     _ta_highlight(1, @_);
 }
 
 sub ta_add_color_resets {
     my (@text) = @_;
 
     my @res;
     my $i = 0;
     my $savedc = "";
     for my $text (@text) {
         $i++;
         my $newt = $i > 1 && !$savedc ? "\e[0m" : $savedc;
 
         # break into chunks
         my @ch = ta_split_codes_single($text);
         while (my ($t, $c) = splice(@ch, 0, 2)) {
             $newt .= $t;
             if (defined($c) && $c =~ /m\z/) {
                 $newt .= $c;
                 if ($c eq "\e[0m") {
                     $savedc = "";
                 } elsif ($c =~ /m\z/) {
                     $savedc .= $c;
                 }
             }
         }
 
         $newt .= "\e[0m" if $savedc && $i < @text;
         push @res, $newt;
     }
 
     @res;
 }
 
 sub _ta_substr {
     my $is_mb = shift;
     my $str   = shift;
     my $pos   = shift;
     my $len   = shift;
 
     my $res1 = _ta_trunc($is_mb, $str, $pos, 1);
     my $res2 = _ta_trunc($is_mb, $res1->[3], $len, 1);
 
     if (@_) {
         # left + replacement + right
         return _ta_prune_codes($res1->[0] . $_[0] . $res2->[3]);
     } else {
         return _ta_prune_codes($res2->[0]);
     }
 }
 
 sub ta_substr {
     _ta_substr(0, @_);
 }
 
 sub ta_mbsubstr {
     _ta_substr(1, @_);
 }
 
 
 1;
 # ABSTRACT: Base for Text::ANSI::{Util,NonWideUtil,WideUtil}
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Text::ANSI::BaseUtil - Base for Text::ANSI::{Util,NonWideUtil,WideUtil}
 
 =head1 VERSION
 
 This document describes version 0.21 of Text::ANSI::BaseUtil (from Perl distribution Text-ANSI-Util), released on 2015-08-20.
 
 =for Pod::Coverage .+
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Text-ANSI-Util>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Text-ANSI-Util>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Text-ANSI-Util>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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
### Text/ANSI/NonWideUtil.pm ###
 package Text::ANSI::NonWideUtil;
 
 our $DATE = '2015-08-20'; # DATE
 our $VERSION = '0.21'; # VERSION
 
 use 5.010001;
 use strict 'subs', 'vars';
 use warnings;
 
 require Exporter;
 our @ISA       = qw(Exporter);
 our @EXPORT_OK = qw(
                        ta_add_color_resets
                        ta_detect
                        ta_extract_codes
                        ta_highlight
                        ta_highlight_all
                        ta_length
                        ta_length_height
                        ta_pad
                        ta_split_codes
                        ta_split_codes_single
                        ta_strip
                        ta_substr
                        ta_trunc
                        ta_wrap
                );
 
 use Text::ANSI::BaseUtil ();
 
 our $re = $Text::ANSI::BaseUtil::re;
 *{$_} = \&{"Text::ANSI::BaseUtil::$_"} for @EXPORT_OK;
 
 1;
 # ABSTRACT: Routines for text containing ANSI color codes (non-wide functions only)
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Text::ANSI::NonWideUtil - Routines for text containing ANSI color codes (non-wide functions only)
 
 =head1 VERSION
 
 This document describes version 0.21 of Text::ANSI::NonWideUtil (from Perl distribution Text-ANSI-Util), released on 2015-08-20.
 
 =head1 DESCRIPTION
 
 This module provides routines for dealing with text that contains ANSI color
 codes, e.g. for determining its length/width (excluding the color codes),
 stripping the color codes, extracting the color codes, and so on.
 
 There is also a wide variant: L<Text::ANSI::WideUtil>. The difference is that
 ::WideUtil can handle wide (full-width) Unicode characters, while ::NonWideUtil
 can also handle normal/halfwidth/ASCII characters.
 
 =head1 FUNCTIONS
 
 =head2 ta_detect($text) => BOOL
 
 Return true if C<$text> contains ANSI color codes, false otherwise.
 
 =head2 ta_length($text) => INT
 
 Count the number of characters in $text, while ignoring ANSI color codes.
 Equivalent to C<< length(ta_strip($text)) >>. See also: ta_mbswidth().
 
 =head2 ta_length_height($text) => [INT, INT]
 
 Like ta_length(), but also gives height (number of lines). For example, C<<
 ta_length_height("foobar\nb\n") >> gives [6, 3].
 
 =head2 ta_strip($text) => STR
 
 Strip ANSI color codes from C<$text>, returning the stripped text.
 
 =head2 ta_extract_codes($text) => STR
 
 This is the opposite of C<ta_strip()>, return only the ANSI codes in C<$text>.
 
 =head2 ta_split_codes($text) => LIST
 
 Split C<$text> to a list containing alternating ANSI color codes and text. ANSI
 color codes are always on the second element, fourth, and so on. Example:
 
  ta_split_codes("");              # => ()
  ta_split_codes("a");             # => ("a")
  ta_split_codes("a\e[31m");       # => ("a", "\e[31m")
  ta_split_codes("\e[31ma");       # => ("", "\e[31m", "a")
  ta_split_codes("\e[31ma\e[0m");  # => ("", "\e[31m", "a", "\e[0m")
  ta_split_codes("\e[31ma\e[0mb"); # => ("", "\e[31m", "a", "\e[0m", "b")
  ta_split_codes("\e[31m\e[0mb");  # => ("", "\e[31m\e[0m", "b")
 
 so you can do something like:
 
  my @parts = ta_split_codes($text);
  while (my ($text, $ansicode) = splice(@parts, 0, 2)) {
      ...
  }
 
 =head2 ta_split_codes_single($text) => LIST
 
 Like C<ta_split_codes()> but each ANSI color code is split separately, instead
 of grouped together. This routine is currently used internally e.g. for
 C<ta_mbwrap()> and C<ta_highlight()> to trace color reset/replay codes.
 
 =head2 ta_wrap($text, $width, \%opts) => STR
 
 Like L<Text::WideChar::Util>'s wrap() except handles ANSI color codes. Perform
 color reset at the end of each line and a color replay at the start of
 subsequent line so the text is safe for combining in a multicolumn/tabular
 layout.
 
 Options:
 
 =over
 
 =item * flindent => STR
 
 First line indent. See Text::WideChar::Util for more details.
 
 =item * slindent => STR
 
 First line indent. See Text::WideChar::Util for more details.
 
 =item * tab_width => INT (default: 8)
 
 First line indent. See Text::WideChar::Util for more details.
 
 =item * pad => BOOL (default: 0)
 
 If set to true, will pad each line to C<$width>. This is convenient if you need
 the lines padded, saves calls to ta_pad().
 
 =item * return_stats => BOOL (default: 0)
 
 If set to true, then instead of returning the wrapped string, function will
 return C<< [$wrapped, $stats] >> where C<$stats> is a hash containing some
 information like C<max_word_width>, C<min_word_width>.
 
 =back
 
 Performance: ~500/s on my Core i5 1.7GHz laptop for a ~1KB of text (with zero to
 moderate amount of color codes). As a comparison, Text::WideChar::Util's wrap()
 can do about 2000/s.
 
 =head2 ta_add_color_resets(@text) => LIST
 
 Make sure that a color reset command (add C<\e[0m>) to the end of each element
 and a replay of all the color codes from the previous element, from the last
 color reset) to the start of the next element, and so on. Return the new list.
 
 This makes each element safe to be combined with other array of text into a
 single line, e.g. in a multicolumn/tabular layout. An example:
 
 Without color resets:
 
  my @col1 = split /\n/, "\e[31mred\nmerah\e[0m";
  my @col2 = split /\n/, "\e[32mgreen\e[1m\nhijau tebal\e[0m";
 
  printf "%s | %s\n", $col1[0], $col2[0];
  printf "%s | %s\n", $col1[1], $col2[1];
 
 the printed output:
 
  \e[31mred | \e[32mgreen
  merah\e[0m | \e[1mhijau tebal\e[0m
 
 The C<merah> text on the second line will become green because of the effect of
 the last color command printed (C<\e[32m>). However, with ta_add_color_resets():
 
  my @col1 = ta_add_color_resets(split /\n/, "\e[31mred\nmerah\e[0m");
  my @col2 = ta_add_color_resets(split /\n/, "\e[32mgreen\e[1m\nhijau tebal\e[0m");
 
  printf "%s | %s\n", $col1[0], $col2[0];
  printf "%s | %s\n", $col1[1], $col2[1];
 
 the printed output (C<< <...> >>) marks the code added by ta_add_color_resets():
 
  \e[31mred<\e[0m> | \e[32mgreen\e[1m<\e[0m>
  <\e[31m>merah\e[0m | <\e[32m\e[1m>hijau tebal\e[0m
 
 All the cells are printed with the intended colors.
 
 =head2 ta_pad($text, $width[, $which[, $padchar[, $truncate]]]) => STR
 
 Return C<$text> padded with C<$padchar> to C<$width> columns. C<$which> is
 either "r" or "right" for padding on the right (the default if not specified),
 "l" or "left" for padding on the right, or "c" or "center" or "centre" for
 left+right padding to center the text.
 
 C<$padchar> is whitespace if not specified. It should be string having the width
 of 1 column.
 
 Does *not* handle multiline text; you can split text by C</\r?\n/> yourself.
 
 =head2 ta_trunc($text, $width) => STR
 
 Truncate C<$text> to C<$width> columns while still including all the ANSI color
 codes. This ensures that truncated text still reset colors, etc.
 
 Does *not* handle multiline text; you can split text by C</\r?\n/> yourself.
 
 =head2 ta_highlight($text, $needle, $color) => STR
 
 Highlight the first occurence of C<$needle> in C<$text> with <$color>, taking
 care not to mess up existing colors.
 
 C<$needle> can be a string or a Regexp object.
 
 Implementation note: to not mess up colors, we save up all color codes from the
 last reset (C<\e[0m>) before inserting the highlight color + highlight text.
 Then we issue C<\e[0m> and the saved up color code to return back to the color
 state before the highlight is inserted. This is the same technique as described
 in ta_add_color_resets().
 
 =head2 ta_highlight_all($text, $needle, $color) => STR
 
 Like ta_highlight(), but highlight all occurences instead of only the first.
 
 =head2 ta_substr($text, $pos, $len[ , $replacement ]) => STR
 
 A bit like Perl's C<substr()>. If C<$replacement> is not specified, will return
 the substring. If C<$replacement> is specified, will return $text with the
 substring replaced by C<$replacement>.
 
 =head1 SEE ALSO
 
 L<Text::ANSI::WideUtil>
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Text-ANSI-Util>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Text-ANSI-Util>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Text-ANSI-Util>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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
### Text/ANSI/Util.pm ###
 package Text::ANSI::Util;
 
 our $DATE = '2015-08-20'; # DATE
 our $VERSION = '0.21'; # VERSION
 
 use 5.010001;
 use strict 'subs', 'vars';
 use warnings;
 
 BEGIN {
     eval {
         require Text::WideChar::Util;
         Text::WideChar::Util->import(qw(mbswidth mbtrunc));
     };
     warn if $@;
 }
 
 require Exporter;
 our @ISA       = qw(Exporter);
 our @EXPORT_OK = qw(
                        ta_add_color_resets
                        ta_detect
                        ta_extract_codes
                        ta_highlight
                        ta_highlight_all
                        ta_length
                        ta_length_height
                        ta_mbpad
                        ta_mbsubstr
                        ta_mbswidth
                        ta_mbswidth_height
                        ta_mbtrunc
                        ta_mbwrap
                        ta_pad
                        ta_split_codes
                        ta_split_codes_single
                        ta_strip
                        ta_substr
                        ta_trunc
                        ta_wrap
                );
 
 use Text::ANSI::BaseUtil ();
 
 our $re = $Text::ANSI::BaseUtil::re;
 *{$_} = \&{"Text::ANSI::BaseUtil::$_"} for @EXPORT_OK;
 
 1;
 # ABSTRACT: (DEPRECATED) Routines for text containing ANSI color codes
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Text::ANSI::Util - (DEPRECATED) Routines for text containing ANSI color codes
 
 =head1 VERSION
 
 This document describes version 0.21 of Text::ANSI::Util (from Perl distribution Text-ANSI-Util), released on 2015-08-20.
 
 =head1 SYNOPSIS
 
  use Text::ANSI::Util qw(
      ta_add_color_resets
      ta_detect ta_highlight ta_highlight_all ta_length ta_mbpad ta_mbsubstr ta_mbswidth
      ta_mbswidth_height ta_mbwrap ta_pad ta_split_codes ta_split_codes_single
      ta_strip ta_wrap ta_substr);
 
  # detect whether text has ANSI color codes?
  say ta_detect("red");       # => false
  say ta_detect("\e[31mred"); # => true
 
  # calculate length of text (excluding the ANSI color codes)
  say ta_length("red");       # => 3
  say ta_length("\e[31mred"); # => 3
 
  # calculate visual width of text if printed on terminal (can handle Unicode
  # wide characters and exclude the ANSI color codes)
  say ta_mbswidth("\e[31mred");  # => 3
  say ta_mbswidth("\e[31m红色"); # => 4
 
  # ditto, but also return the number of lines
  say ta_mbswidth_height("\e[31mred\n红色"); # => [4, 2]
 
  # strip ANSI color codes
  say ta_strip("\e[31mred"); # => "red"
 
  # split codes (ANSI color codes are always on the even positions)
  my @parts = ta_split_codes("\e[31mred"); # => ("", "\e[31m", "red")
 
  # wrap text to a certain column width, handle ANSI color codes
  say ta_wrap("....", 40);
 
  # ditto, but handle wide characters
  say ta_mbwrap(...);
 
  # pad (left, right, center) text to a certain width
  say ta_pad("foo", 10);                          # => "foo       "
  say ta_pad("foo", 10, "left");                  # => "       foo"
  say ta_pad("foo\nbarbaz\n", 10, "center", "."); # => "...foo....\n..barbaz..\n"
 
  # ditto, but handle wide characters
  say ta_mbpad(...);
 
  # truncate text to a certain width while still passing ANSI color codes
  use Term::ANSIColor;
  my $text = color("red")."red text".color("reset"); # => "\e[31mred text\e[0m"
  say ta_trunc($text, 5);                            # => "\e[31mred t\e[0m"
 
  # ditto, but handle wide characters
  say ta_mbtrunc(...);
 
  # highlight the first occurence of some string within text
  say ta_highlight("some text", "ome", "\e[7m\e[31m");
 
  # ditto, but highlight all occurrences
  say ta_highlight_all(...);
 
  # get substring
  my $substr = ta_substr("...", $pos, $len);
  # ditto but with wide character support
  my $substr = ta_mbsubstr("...", $pos, $len);
 
  # return text but with substring replaced with replacement
  say ta_substr("...", $pos, $len, $replacement);
  # ditto but with wide character support
  say ta_mbsubstr("...", $pos, $len, $replacement);
 
 =head1 DESCRIPTION
 
 B<DEPRECATION NOTICE:> To keep dependencies stay slim, since 0.17 this module
 has been split into L<Text::ANSI::NonWideUtil> (for routines dealing with just
 ASCII characters, which does not depend on Unicode/wide-char libraries) and
 L<Text::ANSI::WideUtil> (for routines supporting Unicode/wide characters). It is
 advised that you use either one of the two, depending on your needs. This module
 might be removed in the future.
 
 This module provides routines for dealing with text containing ANSI color codes
 (Select Graphic Rendition/SGR/C<\e[...m> codes).
 
 Current caveats:
 
 =over
 
 =item * Other ANSI codes (non-color codes) are ignored
 
 These are codes like for altering cursor positions, etc.
 
 =item * Single-character CSI (control sequence introducer) currently ignored
 
 Only C<ESC+[> (two-character CSI) is currently parsed.
 
 BTW, in ASCII terminals, single-character CSI is C<0x9b>. In UTF-8 terminals, it
 is C<0xc2, 0x9b> (2 bytes).
 
 =item * Private-mode- and trailing-intermediate character currently not parsed
 
 =item * Only color reset code \e[0m is recognized
 
 For simplicity, currently multiple SGR parameters inside a single ANSI color
 code is not parsed. This means that color reset code like C<\e[1;0m> or
 C<\e[31;47;0m> is not recognized, only C<\e[0m> is. I believe this should not be
 a problem with most real-world text out there.
 
 =back
 
 =head1 FUNCTIONS
 
 =for BEGIN_BLOCK: pod_nonwide_functions
 
 =head2 ta_detect($text) => BOOL
 
 Return true if C<$text> contains ANSI color codes, false otherwise.
 
 =head2 ta_length($text) => INT
 
 Count the number of characters in $text, while ignoring ANSI color codes.
 Equivalent to C<< length(ta_strip($text)) >>. See also: ta_mbswidth().
 
 =head2 ta_length_height($text) => [INT, INT]
 
 Like ta_length(), but also gives height (number of lines). For example, C<<
 ta_length_height("foobar\nb\n") >> gives [6, 3].
 
 =head2 ta_strip($text) => STR
 
 Strip ANSI color codes from C<$text>, returning the stripped text.
 
 =head2 ta_extract_codes($text) => STR
 
 This is the opposite of C<ta_strip()>, return only the ANSI codes in C<$text>.
 
 =head2 ta_split_codes($text) => LIST
 
 Split C<$text> to a list containing alternating ANSI color codes and text. ANSI
 color codes are always on the second element, fourth, and so on. Example:
 
  ta_split_codes("");              # => ()
  ta_split_codes("a");             # => ("a")
  ta_split_codes("a\e[31m");       # => ("a", "\e[31m")
  ta_split_codes("\e[31ma");       # => ("", "\e[31m", "a")
  ta_split_codes("\e[31ma\e[0m");  # => ("", "\e[31m", "a", "\e[0m")
  ta_split_codes("\e[31ma\e[0mb"); # => ("", "\e[31m", "a", "\e[0m", "b")
  ta_split_codes("\e[31m\e[0mb");  # => ("", "\e[31m\e[0m", "b")
 
 so you can do something like:
 
  my @parts = ta_split_codes($text);
  while (my ($text, $ansicode) = splice(@parts, 0, 2)) {
      ...
  }
 
 =head2 ta_split_codes_single($text) => LIST
 
 Like C<ta_split_codes()> but each ANSI color code is split separately, instead
 of grouped together. This routine is currently used internally e.g. for
 C<ta_mbwrap()> and C<ta_highlight()> to trace color reset/replay codes.
 
 =head2 ta_wrap($text, $width, \%opts) => STR
 
 Like L<Text::WideChar::Util>'s wrap() except handles ANSI color codes. Perform
 color reset at the end of each line and a color replay at the start of
 subsequent line so the text is safe for combining in a multicolumn/tabular
 layout.
 
 Options:
 
 =over
 
 =item * flindent => STR
 
 First line indent. See Text::WideChar::Util for more details.
 
 =item * slindent => STR
 
 First line indent. See Text::WideChar::Util for more details.
 
 =item * tab_width => INT (default: 8)
 
 First line indent. See Text::WideChar::Util for more details.
 
 =item * pad => BOOL (default: 0)
 
 If set to true, will pad each line to C<$width>. This is convenient if you need
 the lines padded, saves calls to ta_pad().
 
 =item * return_stats => BOOL (default: 0)
 
 If set to true, then instead of returning the wrapped string, function will
 return C<< [$wrapped, $stats] >> where C<$stats> is a hash containing some
 information like C<max_word_width>, C<min_word_width>.
 
 =back
 
 Performance: ~500/s on my Core i5 1.7GHz laptop for a ~1KB of text (with zero to
 moderate amount of color codes). As a comparison, Text::WideChar::Util's wrap()
 can do about 2000/s.
 
 =head2 ta_add_color_resets(@text) => LIST
 
 Make sure that a color reset command (add C<\e[0m>) to the end of each element
 and a replay of all the color codes from the previous element, from the last
 color reset) to the start of the next element, and so on. Return the new list.
 
 This makes each element safe to be combined with other array of text into a
 single line, e.g. in a multicolumn/tabular layout. An example:
 
 Without color resets:
 
  my @col1 = split /\n/, "\e[31mred\nmerah\e[0m";
  my @col2 = split /\n/, "\e[32mgreen\e[1m\nhijau tebal\e[0m";
 
  printf "%s | %s\n", $col1[0], $col2[0];
  printf "%s | %s\n", $col1[1], $col2[1];
 
 the printed output:
 
  \e[31mred | \e[32mgreen
  merah\e[0m | \e[1mhijau tebal\e[0m
 
 The C<merah> text on the second line will become green because of the effect of
 the last color command printed (C<\e[32m>). However, with ta_add_color_resets():
 
  my @col1 = ta_add_color_resets(split /\n/, "\e[31mred\nmerah\e[0m");
  my @col2 = ta_add_color_resets(split /\n/, "\e[32mgreen\e[1m\nhijau tebal\e[0m");
 
  printf "%s | %s\n", $col1[0], $col2[0];
  printf "%s | %s\n", $col1[1], $col2[1];
 
 the printed output (C<< <...> >>) marks the code added by ta_add_color_resets():
 
  \e[31mred<\e[0m> | \e[32mgreen\e[1m<\e[0m>
  <\e[31m>merah\e[0m | <\e[32m\e[1m>hijau tebal\e[0m
 
 All the cells are printed with the intended colors.
 
 =head2 ta_pad($text, $width[, $which[, $padchar[, $truncate]]]) => STR
 
 Return C<$text> padded with C<$padchar> to C<$width> columns. C<$which> is
 either "r" or "right" for padding on the right (the default if not specified),
 "l" or "left" for padding on the right, or "c" or "center" or "centre" for
 left+right padding to center the text.
 
 C<$padchar> is whitespace if not specified. It should be string having the width
 of 1 column.
 
 Does *not* handle multiline text; you can split text by C</\r?\n/> yourself.
 
 =head2 ta_trunc($text, $width) => STR
 
 Truncate C<$text> to C<$width> columns while still including all the ANSI color
 codes. This ensures that truncated text still reset colors, etc.
 
 Does *not* handle multiline text; you can split text by C</\r?\n/> yourself.
 
 =head2 ta_highlight($text, $needle, $color) => STR
 
 Highlight the first occurence of C<$needle> in C<$text> with <$color>, taking
 care not to mess up existing colors.
 
 C<$needle> can be a string or a Regexp object.
 
 Implementation note: to not mess up colors, we save up all color codes from the
 last reset (C<\e[0m>) before inserting the highlight color + highlight text.
 Then we issue C<\e[0m> and the saved up color code to return back to the color
 state before the highlight is inserted. This is the same technique as described
 in ta_add_color_resets().
 
 =head2 ta_highlight_all($text, $needle, $color) => STR
 
 Like ta_highlight(), but highlight all occurences instead of only the first.
 
 =head2 ta_substr($text, $pos, $len[ , $replacement ]) => STR
 
 A bit like Perl's C<substr()>. If C<$replacement> is not specified, will return
 the substring. If C<$replacement> is specified, will return $text with the
 substring replaced by C<$replacement>.
 
 =for END_BLOCK: pod_nonwide_functions
 
 =for BEGIN_BLOCK: pod_wide_functions
 
 =head2 ta_mbpad($text, $width[, $which[, $padchar[, $truncate]]]) => STR
 
 Like ta_pad() but it uses ta_mbswidth() instead of ta_length(), so it can handle
 wide characters.
 
 =head2 ta_mbtrunc($text, $width) => STR
 
 Like ta_trunc() but it uses ta_mbswidth() instead of ta_length(), so it can
 handle wide characters.
 
 =head2 ta_mbswidth($text) => INT
 
 Return visual width of C<$text> (in number of columns) if printed on terminal.
 Equivalent to C<< Text::WideChar::Util::mbswidth(ta_strip($text)) >>. This
 function can be used e.g. in making sure that your text aligns vertically when
 output to the terminal in tabular/table format.
 
 Note that C<ta_mbswidth()> handles multiline text correctly, e.g.: C<<
 ta_mbswidth("foo\nbarbaz") >> gives 6 instead of 3-1+8 = 8. It splits the input
 text first against C<< /\r?\n/ >>.
 
 =head2 ta_mbswidth_height($text) => [INT, INT]
 
 Like C<ta_mbswidth()>, but also gives height (number of lines). For example, C<<
 ta_mbswidth_height("西爪哇\nb\n") >> gives [6, 3].
 
 =head2 ta_mbwrap($text, $width, \%opts) => STR
 
 Like ta_wrap(), but it uses ta_mbswidth() instead of ta_length(), so it can
 handle wide characters.
 
 Performance: ~300/s on my Core i5 1.7GHz laptop for a ~1KB of text (with zero to
 moderate amount of color codes). As a comparison, Text::WideChar::Util's
 mbwrap() can do about 650/s.
 
 =head2 ta_mbsubstr($text, $pos, $len[ , $replacement ]) => STR
 
 Like ta_substr(), but handles wide characters.
 
 =for END_BLOCK: pod_wide_functions
 
 =head1 FAQ
 
 =head2 How do I truncate string based on number of characters?
 
 You can simply use ta_trunc() even on text containing wide characters.
 ta_trunc() uses Perl's length() which works on a per-character basis.
 
 =head2 How do I highlight a string case-insensitively?
 
 You can currently use a regex for the C<$needle> and use the C<i> modifier.
 Example:
 
  use Term::ANSIColor;
  ta_highlight($text, qr/\b(foo)\b/i, color("bold red"));
 
 =head1 SEE ALSO
 
 L<Term::ANSIColor>
 
 L<Text::ANSITable> uses this module. In fact, this module was first created
 specifically for Text::ANSITable.
 
 http://en.wikipedia.org/wiki/ANSI_escape_code
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Text-ANSI-Util>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Text-ANSI-Util>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Text-ANSI-Util>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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
### Text/ANSITable.pm ###
 package Text::ANSITable;
 
 our $DATE = '2015-10-21'; # DATE
 our $VERSION = '0.43'; # VERSION
 
 use 5.010001;
 use Carp;
 use Log::Any::IfLOG '$log';
 use Moo;
 use experimental 'smartmatch';
 
 #use List::Util qw(first);
 use Scalar::Util 'looks_like_number';
 use Text::ANSI::Util qw(ta_mbswidth_height ta_mbpad ta_add_color_resets
                         ta_mbwrap);
 
 my $ATTRS = [qw(
 
                   use_color color_depth use_box_chars use_utf8 columns rows
                   column_filter row_filter show_row_separator show_header
                   show_header cell_width cell_height cell_pad cell_lpad
                   cell_rpad cell_vpad cell_tpad cell_bpad cell_fgcolor
                   cell_bgcolor cell_align cell_valign header_align header_valign
                   header_vpad header_tpad header_bpad header_fgcolor
                   header_bgcolor color_theme_args border_style_args
 
           )];
 my $STYLES = $ATTRS;
 my $COLUMN_STYLES = [qw(
 
                           type width align valign pad lpad rpad formats fgcolor
                           bgcolor wrap
 
                   )];
 my $ROW_STYLES = [qw(
 
                        height align valign vpad tpad bpad fgcolor bgcolor
 
                )];
 my $CELL_STYLES = [qw(
 
                         align valign formats fgcolor bgcolor
 
                 )];
 
 has columns => (
     is      => 'rw',
     default => sub { [] },
     trigger => sub {
         my $self = shift;
         $self->{_columns_set}++;
     },
 );
 has rows => (
     is      => 'rw',
     default => sub { [] },
     trigger => sub {
         my ($self, $rows) = @_;
         $self->_set_default_cols($rows->[0]);
     },
 );
 has column_filter => (
     is => 'rw',
 );
 has column_wrap => (
     is => 'rw',
 );
 has row_filter => (
     is => 'rw',
 );
 has _row_separators => ( # [index after which sep should be drawn, ...] sorted
     is      => 'rw',
     default => sub { [] },
 );
 has show_row_separator => (
     is      => 'rw',
     default => sub { 2 },
 );
 has show_header => (
     is      => 'rw',
     default => sub { 1 },
 );
 
 has _column_styles => ( # store per-column styles
     is      => 'rw',
     default => sub { [] },
 );
 has _row_styles => ( # store per-row styles
     is      => 'rw',
     default => sub { [] },
 );
 has _cell_styles => ( # store per-cell styles
     is      => 'rw',
     default => sub { [] },
 );
 
 # each element of _cond_*styles is a two-element [$cond, ], where $cond is code
 # (str|coderef) and the second element is a hashref containing styles.
 
 has _cond_column_styles => ( # store conditional column styles
     is      => 'rw',
     default => sub { [] },
 );
 has _cond_row_styles => ( # store conditional row styles
     is      => 'rw',
     default => sub { [] },
 );
 has _cond_cell_styles => ( # store conditional cell styles
     is      => 'rw',
     default => sub { [] },
 );
 
 has cell_width => (
     is      => 'rw',
 );
 has cell_height => (
     is      => 'rw',
 );
 has cell_pad => (
     is      => 'rw',
     default => sub { 1 },
 );
 has cell_lpad => (
     is      => 'rw',
 );
 has cell_rpad => (
     is      => 'rw',
 );
 has cell_vpad => (
     is      => 'rw',
     default => sub { 0 },
 );
 has cell_tpad => (
     is      => 'rw',
 );
 has cell_bpad => (
     is      => 'rw',
 );
 has cell_fgcolor => (
     is => 'rw',
 );
 has cell_bgcolor => (
     is => 'rw',
 );
 has cell_align => (
     is => 'rw',
 );
 has cell_valign => (
     is => 'rw',
 );
 
 has header_align => (
     is      => 'rw',
 );
 has header_valign => (
     is      => 'rw',
 );
 has header_vpad => (
     is      => 'rw',
 );
 has header_tpad => (
     is      => 'rw',
 );
 has header_bpad => (
     is      => 'rw',
 );
 has header_fgcolor => (
     is      => 'rw',
 );
 has header_bgcolor => (
     is      => 'rw',
 );
 
 with 'Border::Style::Role';
 with 'Color::Theme::Role::ANSI';
 with 'Term::App::Role::Attrs';
 
 sub BUILD {
     my ($self, $args) = @_;
 
     if ($ENV{ANSITABLE_STYLE_SETS}) {
         require JSON;
         my $sets = JSON::decode_json($ENV{ANSITABLE_STYLE_SETS});
         croak "ANSITABLE_STYLE_SETS must be an array"
             unless ref($sets) eq 'ARRAY';
         for my $set (@$sets) {
             if (ref($set) eq 'ARRAY') {
                 $self->apply_style_set($set->[0], $set->[1]);
             } else {
                 $self->apply_style_set($set);
             }
         }
     }
 
     if ($ENV{ANSITABLE_STYLE}) {
         require JSON;
         my $s = JSON::decode_json($ENV{ANSITABLE_STYLE});
         for my $k (keys %$s) {
             my $v = $s->{$k};
             croak "Unknown table style '$k' in ANSITABLE_STYLE environment, ".
                 "please use one of [".join(", ", @$STYLES)."]"
                     unless $k ~~ $STYLES;
             $self->{$k} = $v;
         }
     }
 
     # set "pseudo"-attributes, they are not declared using 'has' so Moo doesn't
     # set them and we need to set them manually
     if ($args->{border_style}) { $self->border_style($args->{border_style}) }
     if ($args->{color_theme}) { $self->color_theme($args->{color_theme}) }
 
     # pick a default border style
     unless ($self->{border_style}) {
         my $bs;
 
         my $use_utf8 = $self->use_utf8;
 
         # even though Term::Detect::Software decides that linux virtual console
         # does not support unicode, it actually can display some uni characters
         # like single borders, so we use it as the default here instead of
         # singleo_ascii (linux vc doesn't seem to support box_chars).
         my $emu_eng  = $self->detect_terminal->{emulator_engine} // '';
         my $linux_vc = $emu_eng eq 'linux' && !defined($ENV{UTF8});
         if ($linux_vc) {
             $use_utf8 = 1;
             $bs = 'Default::singleo_utf8';
         }
         # use statement modifier style to avoid block and make local work
         local $self->{use_utf8} = 1 if $linux_vc;
 
         # we only default to utf8 border if user has set something like
         # binmode(STDOUT, ":utf8") to avoid 'Wide character in print' warning.
         unless (defined $ENV{UTF8}) {
             require PerlIO;
             my @layers = PerlIO::get_layers(STDOUT);
             $use_utf8 = 0 unless 'utf8' ~~ @layers;
         }
 
         if (defined $ENV{ANSITABLE_BORDER_STYLE}) {
             $bs = $ENV{ANSITABLE_BORDER_STYLE};
         } elsif ($use_utf8) {
             $bs //= 'Default::bricko';
         } elsif ($self->use_box_chars) {
             $bs = 'Default::singleo_boxchar';
         } else {
             $bs = 'Default::singleo_ascii';
         }
 
         $self->border_style($bs);
     }
 
     # pick a default color theme
     unless ($self->{color_theme}) {
         my $ct;
         if (defined $ENV{ANSITABLE_COLOR_THEME}) {
             $ct = $ENV{ANSITABLE_COLOR_THEME};
         } elsif ($self->use_color) {
             my $bg = $self->detect_terminal->{default_bgcolor} // '';
             if ($self->color_depth >= 2**24) {
                 $ct = 'Default::default_gradation' .
                     ($bg eq 'ffffff' ? '_whitebg' : '');
             } else {
                 $ct = 'Default::default_nogradation' .
                     ($bg eq 'ffffff' ? '_whitebg' : '');;
             }
         } else {
             $ct = 'Default::no_color';
         }
         $self->color_theme($ct);
     }
 }
 
 sub _set_default_cols {
     my ($self, $row) = @_;
     return if $self->{_columns_set}++;
     $self->columns([map {"col$_"} 0..@$row-1]) if $row;
 }
 
 sub add_row {
     my ($self, $row, $styles) = @_;
     croak "Row must be arrayref" unless ref($row) eq 'ARRAY';
     push @{ $self->{rows} }, $row;
     $self->_set_default_cols($row) unless $self->{_columns_set}++;
     if ($styles) {
         my $i = @{ $self->{rows} }-1;
         for my $s (keys %$styles) {
             $self->set_row_style($i, $s, $styles->{$s});
         }
     }
     $self;
 }
 
 sub add_row_separator {
     my ($self) = @_;
     my $idx = ~~@{$self->{rows}}-1;
     # ignore duplicate separators
     push @{ $self->{_row_separators} }, $idx
         unless @{ $self->{_row_separators} } &&
             $self->{_row_separators}[-1] == $idx;
     $self;
 }
 
 sub add_rows {
     my ($self, $rows, $styles) = @_;
     croak "Rows must be arrayref" unless ref($rows) eq 'ARRAY';
     $self->add_row($_, $styles) for @$rows;
     $self;
 }
 
 sub _colnum {
     my $self = shift;
     my $colname = shift;
 
     return $colname if looks_like_number($colname);
     my $cols = $self->{columns};
     for my $i (0..@$cols-1) {
         return $i if $cols->[$i] eq $colname;
     }
     croak "Unknown column name '$colname'";
 }
 
 sub get_cell {
     my ($self, $row_num, $col) = @_;
 
     $col = $self->_colnum($col);
 
     $self->{rows}[$row_num][$col];
 }
 
 sub set_cell {
     my ($self, $row_num, $col, $val) = @_;
 
     $col = $self->_colnum($col);
 
     my $oldval = $self->{rows}[$row_num][$col];
     $self->{rows}[$row_num][$col] = $val;
     $oldval;
 }
 
 sub get_column_style {
     my ($self, $col, $style) = @_;
 
     $col = $self->_colnum($col);
     $self->{_column_styles}[$col]{$style};
 }
 
 sub set_column_style {
     my $self = shift;
     my $col  = shift;
 
     $col = $self->_colnum($col);
 
     my %sets = ref($_[0]) eq 'HASH' ? %{$_[0]} : @_;
 
     for my $style (keys %sets) {
         my $val = $sets{$style};
         croak "Unknown per-column style '$style', please use one of [".
             join(", ", @$COLUMN_STYLES) . "]" unless $style ~~ $COLUMN_STYLES;
         $self->{_column_styles}[$col]{$style} = $val;
     }
 }
 
 sub get_cond_column_styles {
     my $self = shift;
     $self->{_cond_column_styles};
 }
 
 #sub set_cond_column_style {
 #    my ($self, $styles) = @_;
 #    $self->{_cond_column_styles} = $styles;
 #}
 
 sub add_cond_column_style {
     my $self = shift;
     my $cond = shift;
     if (ref($cond) ne 'CODE') {
         croak "cond must be a coderef";
     }
 
     my $styles;
     if (ref($_[0]) eq 'HASH') {
         $styles = shift;
     } else {
         $styles = { @_ };
     }
 
     for my $style (keys %$styles) {
         croak "Unknown per-column style '$style', please use one of [".
             join(", ", @$COLUMN_STYLES) . "]" unless $style ~~ $COLUMN_STYLES;
     }
 
     push @{ $self->{_cond_column_styles} }, [$cond, $styles];
 }
 
 #sub clear_cond_column_styles {
 #    my $self = shift;
 #    $self->{_cond_column_styles} = [];
 #}
 
 sub get_eff_column_style {
     my ($self, $col, $style) = @_;
 
     $col = $self->_colnum($col);
 
     # the result of calculation is cached here
     if (defined $self->{_draw}{eff_column_styles}[$col]) {
         return $self->{_draw}{eff_column_styles}[$col]{$style};
     }
 
     my $cols = $self->{columns};
     my %styles;
 
     # apply conditional styles
   COND:
     for my $ei (0..@{ $self->{_cond_column_styles} }-1) {
         my $e = $self->{_cond_column_styles}[$ei];
         local $_ = $col;
         my $res = $e->[0]->(
             $self,
             col     => $col,
             colname => $cols->[$col],
         );
         next COND unless $res;
         if (ref($res) eq 'HASH') {
             $styles{$_} = $res->{$_} for keys %$res;
         }
         $styles{$_} = $e->[1]{$_} for keys %{ $e->[1] };
     }
 
     # apply per-column styles
     my $rss = $self->{_column_styles}[$col];
     if ($rss) {
         $styles{$_} = $rss->{$_} for keys %$rss;
     }
 
     $self->{_draw}{eff_column_styles}[$col] = \%styles;
 
     $styles{$style};
 }
 
 sub get_row_style {
     my ($self, $row, $style) = @_;
 
     $self->{_row_styles}[$row]{$style};
 }
 
 sub set_row_style {
     my $self = shift;
     my $row  = shift;
 
     my %sets = ref($_[0]) eq 'HASH' ? %{$_[0]} : @_;
 
     for my $style (keys %sets) {
         my $val = $sets{$style};
         croak "Unknown per-row style '$style', please use one of [".
             join(", ", @$ROW_STYLES) . "]" unless $style ~~ $ROW_STYLES;
         $self->{_row_styles}[$row]{$style} = $val;
     }
 }
 
 sub get_cond_row_styles {
     my $self = shift;
     $self->{_cond_row_styles};
 }
 
 #sub set_cond_row_style {
 #    my ($self, $styles) = @_;
 #    $self->{_cond_row_styles} = $styles;
 #}
 
 sub add_cond_row_style {
     my $self = shift;
     my $cond = shift;
     if (ref($cond) ne 'CODE') {
         croak "cond must be a coderef";
     }
 
     my $styles;
     if (ref($_[0]) eq 'HASH') {
         $styles = shift;
     } else {
         $styles = { @_ };
     }
 
     for my $style (keys %$styles) {
         croak "Unknown per-row style '$style', please use one of [".
             join(", ", @$ROW_STYLES) . "]" unless $style ~~ $ROW_STYLES;
     }
 
     push @{ $self->{_cond_row_styles} }, [$cond, $styles];
 }
 
 #sub clear_cond_row_styles {
 #    my $self = shift;
 #    $self->{_cond_row_styles} = [];
 #}
 
 sub get_eff_row_style {
     my ($self, $row, $style) = @_;
 
     # the result of calculation is cached here
     if (defined $self->{_draw}{eff_row_styles}[$row]) {
         return $self->{_draw}{eff_row_styles}[$row]{$style};
     }
 
     my $rows = $self->{rows};
     my %styles;
 
     # apply conditional styles
   COND:
     for my $ei (0..@{ $self->{_cond_row_styles} }-1) {
         my $e = $self->{_cond_row_styles}[$ei];
         local $_ = $row;
         my $res = $e->[0]->(
             $self,
             row      => $row,
             row_data => $rows->[$row],
         );
         next COND unless $res;
         if (ref($res) eq 'HASH') {
             $styles{$_} = $res->{$_} for keys %$res;
         }
         $styles{$_} = $e->[1]{$_} for keys %{ $e->[1] };
     }
 
     # apply per-row styles
     my $rss = $self->{_row_styles}[$row];
     if ($rss) {
         $styles{$_} = $rss->{$_} for keys %$rss;
     }
 
     $self->{_draw}{eff_row_styles}[$row] = \%styles;
 
     $styles{$style};
 }
 
 sub get_cell_style {
     my ($self, $row, $col, $style) = @_;
 
     $col = $self->_colnum($col);
     $self->{_cell_styles}[$row][$col]{$style};
 }
 
 sub set_cell_style {
     my $self = shift;
     my $row  = shift;
     my $col  = shift;
 
     $col = $self->_colnum($col);
 
     my %sets = ref($_[0]) eq 'HASH' ? %{$_[0]} : @_;
 
     for my $style (keys %sets) {
         my $val = $sets{$style};
         croak "Unknown per-cell style '$style', please use one of [".
             join(", ", @$CELL_STYLES) . "]" unless $style ~~ $CELL_STYLES;
         $self->{_cell_styles}[$row][$col]{$style} = $val;
     }
 }
 
 sub get_cond_cell_styles {
     my $self = shift;
     $self->{_cond_cell_styles};
 }
 
 #sub set_cond_cell_style {
 #    my ($self, $styles) = @_;
 #    $self->{_cond_cell_styles} = $styles;
 #}
 
 sub add_cond_cell_style {
     my $self = shift;
     my $cond = shift;
     if (ref($cond) ne 'CODE') {
         croak "cond must be a coderef";
     }
 
     my $styles;
     if (ref($_[0]) eq 'HASH') {
         $styles = shift;
     } else {
         $styles = { @_ };
     }
 
     for my $style (keys %$styles) {
         croak "Unknown per-cell style '$style', please use one of [".
             join(", ", @$CELL_STYLES) . "]" unless $style ~~ $CELL_STYLES;
     }
 
     push @{ $self->{_cond_cell_styles} }, [$cond, $styles];
 }
 
 #sub clear_cond_cell_styles {
 #    my $self = shift;
 #    $self->{_cond_cell_styles} = [];
 #}
 
 sub get_eff_cell_style {
     my ($self, $row, $col, $style) = @_;
 
     # the result of calculation is cached here
     if (defined $self->{_draw}{eff_cell_styles}[$row][$col]) {
         return $self->{_draw}{eff_cell_styles}[$row][$col]{$style};
     }
 
     my $rows = $self->{rows};
     my %styles;
 
     # apply conditional styles
   COND:
     for my $ei (0..@{ $self->{_cond_cell_styles} }-1) {
         my $e = $self->{_cond_cell_styles}[$ei];
         local $_ = $rows->[$row][$col];
         my $res = $e->[0]->(
             $self,
             content  => $_,
             col      => $col,
             row      => $row,
             row_data => $rows->[$row],
         );
         next COND unless $res;
         if (ref($res) eq 'HASH') {
             $styles{$_} = $res->{$_} for keys %$res;
         }
         $styles{$_} = $e->[1]{$_} for keys %{ $e->[1] };
     }
 
     # apply per-cell styles
     my $css = $self->{_cell_styles}[$row][$col];
     if ($css) {
         $styles{$_} = $css->{$_} for keys %$css;
     }
 
     $self->{_draw}{eff_cell_styles}[$row][$col] = \%styles;
 
     $styles{$style};
 }
 
 sub apply_style_set {
     my $self = shift;
     my $name = shift;
     $name =~ /\A[A-Za-z0-9_]+(?:::[A-Za-z0-9_]+)*\z/
         or croak "Invalid style set name, please use alphanums only";
     {
         my $name = $name;
         $name =~ s!::!/!g;
         require "Text/ANSITable/StyleSet/$name.pm";
     }
     my %args = ref($_[0]) eq 'HASH' ? %{$_[0]} : @_;
     my $obj = "Text::ANSITable::StyleSet::$name"->new(%args);
     $obj->apply($self);
 }
 
 sub list_style_sets {
     require Module::List;
     require Module::Load;
     require Package::MoreUtil;
 
     my ($self, $detail) = @_;
 
     my $prefix = (ref($self) ? ref($self) : $self ) .
         '::StyleSet'; # XXX allow override
     my $all_sets = $self->{_all_style_sets};
 
     if (!$all_sets) {
         my $mods = Module::List::list_modules("$prefix\::",
                                               {list_modules=>1, recurse=>1});
         $all_sets = {};
         for my $mod (sort keys %$mods) {
             #$log->tracef("Loading style set module '%s' ...", $mod);
             Module::Load::load($mod);
             my $name = $mod; $name =~ s/\A\Q$prefix\:://;
             my $summary = $mod->summary;
             # we don't have meta, so dig it ourselves
             my %ct = Package::MoreUtil::list_package_contents($mod);
             my $args = [sort grep {!/\W/ && !/\A(new|summary|apply)\z/}
                             keys %ct];
             $all_sets->{$name} = {name=>$name, summary=>$summary, args=>$args};
         }
         $self->{_all_style_sets} = $all_sets;
     }
 
     if ($detail) {
         return $all_sets;
     } else {
         return sort keys %$all_sets;
     }
 }
 
 # read environment variables for style, this will only be done once per object
 sub _read_style_envs {
     my $self = shift;
 
     next if $self->{_read_style_envs}++;
 
     if ($ENV{ANSITABLE_COLUMN_STYLES}) {
         require JSON;
         my $ss = JSON::decode_json($ENV{ANSITABLE_COLUMN_STYLES});
         croak "ANSITABLE_COLUMN_STYLES must be a hash"
             unless ref($ss) eq 'HASH';
         for my $col (keys %$ss) {
             my $ci = $self->_colnum($col);
             my $s = $ss->{$col};
             for my $k (keys %$s) {
                 my $v = $s->{$k};
             croak "Unknown column style '$k' (for column $col) in ".
                 "ANSITABLE_COLUMN_STYLES environment, ".
                     "please use one of [".join(", ", @$COLUMN_STYLES)."]"
                         unless $k ~~ $COLUMN_STYLES;
                 $self->{_column_styles}[$ci]{$k} //= $v;
             }
         }
     }
 
     if ($ENV{ANSITABLE_ROW_STYLES}) {
         require JSON;
         my $ss = JSON::decode_json($ENV{ANSITABLE_ROW_STYLES});
         croak "ANSITABLE_ROW_STYLES must be a hash"
             unless ref($ss) eq 'HASH';
         for my $row (keys %$ss) {
             my $s = $ss->{$row};
             for my $k (keys %$s) {
                 my $v = $s->{$k};
             croak "Unknown row style '$k' (for row $row) in ".
                 "ANSITABLE_ROW_STYLES environment, ".
                     "please use one of [".join(", ", @$ROW_STYLES)."]"
                         unless $k ~~ $ROW_STYLES;
                 $self->{_row_styles}[$row]{$k} //= $v;
             }
         }
     }
 
     if ($ENV{ANSITABLE_CELL_STYLES}) {
         require JSON;
         my $ss = JSON::decode_json($ENV{ANSITABLE_CELL_STYLES});
         croak "ANSITABLE_CELL_STYLES must be a hash"
             unless ref($ss) eq 'HASH';
         for my $cell (keys %$ss) {
             croak "Invalid cell specification in ANSITABLE_CELL_STYLES: ".
                 "$cell, please use 'row,col'"
                     unless $cell =~ /^(.+),(.+)$/;
             my $row = $1;
             my $col = $2;
             my $ci = $self->_colnum($col);
             my $s = $ss->{$cell};
             for my $k (keys %$s) {
                 my $v = $s->{$k};
             croak "Unknown cell style '$k' (for cell $row,$col) in ".
                 "ANSITABLE_CELL_STYLES environment, ".
                     "please use one of [".join(", ", @$CELL_STYLES)."]"
                         unless $k ~~ $CELL_STYLES;
                 $self->{_cell_styles}[$row][$ci]{$k} //= $v;
             }
         }
     }
 }
 
 # determine which columns to show (due to column_filter)
 sub _calc_fcols {
     my $self = shift;
 
     my $cols = $self->{columns};
     my $cf   = $self->{column_filter};
 
     my $fcols;
     if (ref($cf) eq 'CODE') {
         $fcols = [grep {$cf->($_)} @$cols];
     } elsif (ref($cf) eq 'ARRAY') {
         $fcols = [grep {defined} map {looks_like_number($_) ?
                                           $cols->[$_] : $_} @$cf];
     } else {
         $fcols = $cols;
     }
     $self->{_draw}{fcols} = $fcols;
 }
 
 # calculate widths/heights of header, store width settings, column [lr]pads
 sub _calc_header_height {
     my $self = shift;
 
     my $cols  = $self->{columns};
     my $fcols = $self->{_draw}{fcols};
 
     my $fcol_widths = []; # index = [colnum]
     my $header_height = 1;
     my $fcol_lpads  = []; # index = [colnum]
     my $fcol_rpads  = []; # ditto
     my $fcol_setwidths  = []; # index = [colnum], from cell_width/col width
     my $frow_setheights = []; # index = [frownum], from cell_height/row height
 
     my %seen;
     my $lpad = $self->{cell_lpad} // $self->{cell_pad}; # tbl-lvl leftp
     my $rpad = $self->{cell_rpad} // $self->{cell_pad}; # tbl-lvl rightp
     for my $i (0..@$cols-1) {
         next unless $cols->[$i] ~~ $fcols;
         next if $seen{$cols->[$i]}++;
 
         $fcol_setwidths->[$i] = $self->get_eff_column_style($i, 'width') //
             $self->{cell_width};
         my $wh = $self->_opt_calc_cell_width_height(undef, $i, $cols->[$i]);
         $fcol_widths->[$i] = $wh->[0];
         $header_height = $wh->[1]
             if !defined($header_height) || $header_height < $wh->[1];
         $fcol_lpads->[$i] = $self->get_eff_column_style($i, 'lpad') //
             $self->get_eff_column_style($i, 'pad') // $lpad;
         $fcol_rpads->[$i] = $self->get_eff_column_style($i, 'rpad') //
             $self->get_eff_column_style($i, 'pad') // $rpad;
     }
 
     $self->{_draw}{header_height}   = $header_height;
     $self->{_draw}{fcol_lpads}      = $fcol_lpads;
     $self->{_draw}{fcol_rpads}      = $fcol_rpads;
     $self->{_draw}{fcol_setwidths}  = $fcol_setwidths;
     $self->{_draw}{frow_setheights} = $frow_setheights;
     $self->{_draw}{fcol_widths}     = $fcol_widths;
 }
 
 # determine which rows to show, calculate vertical paddings of data rows, store
 # height settings
 sub _calc_frows {
     my $self = shift;
 
     my $rows = $self->{rows};
     my $rf   = $self->{row_filter};
     my $frow_setheights = $self->{_draw}{frow_setheights};
 
     my $frow_tpads  = []; # index = [frownum]
     my $frow_bpads  = []; # ditto
     my $frows = [];
     my $frow_separators = [];
     my $frow_orig_indices = []; # needed when accessing original row data
 
     my $tpad = $self->{cell_tpad} // $self->{cell_vpad}; # tbl-lvl top pad
     my $bpad = $self->{cell_bpad} // $self->{cell_vpad}; # tbl-lvl botom pad
     my $i = -1;
     my $j = -1;
     for my $row (@$rows) {
         $i++;
         if (ref($rf) eq 'CODE') {
             next unless $rf->($row, $i);
         } elsif ($rf) {
             next unless $i ~~ $rf;
         }
         $j++;
         push @$frow_setheights, $self->get_eff_row_style($i, 'height') //
             $self->{cell_height};
         push @$frows, [@$row]; # 1-level clone, for storing formatted values
         push @$frow_separators, $j if $i ~~ $self->{_row_separators};
         push @$frow_tpads, $self->get_eff_row_style($i, 'tpad') //
             $self->get_eff_row_style($i, 'vpad') // $tpad;
         push @$frow_bpads, $self->get_eff_row_style($i, 'bpad') //
             $self->get_eff_row_style($i, 'vpad') // $bpad;
         push @$frow_orig_indices, $i;
     }
 
     $self->{_draw}{frows}             = $frows;
     $self->{_draw}{frow_separators}   = $frow_separators;
     $self->{_draw}{frow_tpads}        = $frow_tpads;
     $self->{_draw}{frow_bpads}        = $frow_bpads;
     $self->{_draw}{frow_orig_indices} = $frow_orig_indices;
 }
 
 # detect column type from data/header name. assign default column align, valign,
 # fgcolor, bgcolor, formats.
 sub _detect_column_types {
     my $self = shift;
 
     my $cols = $self->{columns};
     my $rows = $self->{rows};
     my $ct   = $self->{color_theme};
 
     my $fcol_detect = [];
     my %seen;
     for my $i (0..@$cols-1) {
         my $col = $cols->[$i];
         my $res = {};
         $fcol_detect->[$i] = $res;
 
         # optim: skip detecting columns we're not showing
         next unless $col ~~ $self->{_draw}{fcols};
 
         # but detect from all rows, not just ones we're showing
         my $type = $self->get_eff_column_style($col, 'type');
         my $subtype;
       DETECT:
         {
             last DETECT if $type;
             if ($col =~ /^(can|is|has|does)_|\?$/) {
                 $type = 'bool';
                 last DETECT;
             }
 
             require Parse::VarName;
             my @words = map {lc} @{ Parse::VarName::split_varname_words(
                 varname=>$col) };
             for (qw/date time ctime mtime utime atime stime/) {
                 if ($_ ~~ @words) {
                     $type = 'date';
                     last DETECT;
                 }
             }
 
             my $pass = 1;
             for my $j (0..@$rows) {
                 my $v = $rows->[$j][$i];
                 next unless defined($v);
                 do { $pass=0; last } unless looks_like_number($v);
             }
             if ($pass) {
                 $type = 'num';
                 if ($col =~ /(pct|percent(?:age))\b|\%/) {
                     $subtype = 'pct';
                 }
                 last DETECT;
             }
             $type = 'str';
         } # DETECT
 
         $res->{type} = $type;
         if ($type eq 'bool') {
             $res->{align}   = 'center';
             $res->{valign}  = 'center';
             $res->{fgcolor} = $ct->{colors}{bool_data};
             $res->{formats} = [[bool => {style => $self->{use_utf8} ?
                                              "check_cross" : "Y_N"}]];
         } elsif ($type eq 'date') {
             $res->{align}   = 'middle';
             $res->{fgcolor} = $ct->{colors}{date_data};
             $res->{formats} = [['date' => {}]];
         } elsif ($type =~ /\A(num|float|int)\z/) {
             $res->{align}   = 'right';
             $res->{fgcolor} = $ct->{colors}{num_data};
             if (($subtype//"") eq 'pct') {
                 $res->{formats} = [[num => {style=>'percent'}]];
             }
         } else {
             $res->{fgcolor} = $ct->{colors}{str_data};
             $res->{wrap}    = $ENV{WRAP} // 1;
         }
     }
 
     #use Data::Dump; print "D:fcol_detect: "; dd $fcol_detect;
     $self->{_draw}{fcol_detect} = $fcol_detect;
 }
 
 # calculate width and height of a cell, but skip calculating (to save some
 # cycles) if width is already set by frow_setheights / fcol_setwidths.
 sub _opt_calc_cell_width_height {
     my ($self, $frow_num, $col, $text) = @_;
 
     $col = $self->_colnum($col);
     my $setw  = $self->{_draw}{fcol_setwidths}[$col];
     my $calcw = !defined($setw) || $setw < 0;
     my $seth  = defined($frow_num) ?
         $self->{_draw}{frow_setheights}[$frow_num] : undef;
     my $calch = !defined($seth) || $seth < 0;
 
     my $wh;
     if ($calcw) {
         $wh = ta_mbswidth_height($text);
         $wh->[0] = -$setw if defined($setw) && $setw<0 && $wh->[0] < -$setw;
         $wh->[1] = $seth if !$calch;
         $wh->[1] = -$seth if defined($seth) && $seth<0 && $wh->[1] < -$seth;
     } elsif ($calch) {
         my $h = 1; $h++ while $text =~ /\n/go;
         $h = -$seth if defined($seth) && $seth<0 && $h < -$seth;
         $wh = [$setw, $h];
     } else {
         $wh = [$setw, $seth];
     }
     #say "D:_opt_calc_cell_width_height(", $frow_num//"undef", ", $col) = $wh->[0], $wh->[1]";
     $wh;
 }
 
 sub _apply_column_formats {
     my $self = shift;
 
     my $cols  = $self->{columns};
     my $frows = $self->{_draw}{frows};
     my $fcols = $self->{_draw}{fcols};
     my $fcol_detect = $self->{_draw}{fcol_detect};
 
     my %seen;
     for my $i (0..@$cols-1) {
         next unless $cols->[$i] ~~ $fcols;
         next if $seen{$cols->[$i]}++;
         my @fmts = @{ $self->get_eff_column_style($i, 'formats') //
                           $fcol_detect->[$i]{formats} // [] };
         if (@fmts) {
             require Data::Unixish::Apply;
             my $res = Data::Unixish::Apply::apply(
                 in => [map {$frows->[$_][$i]} 0..@$frows-1],
                 functions => \@fmts,
             );
             croak "Can't format column $cols->[$i]: $res->[0] - $res->[1]"
                 unless $res->[0] == 200;
             $res = $res->[2];
             for (0..@$frows-1) { $frows->[$_][$i] = $res->[$_] // "" }
         } else {
             # change null to ''
             for (0..@$frows-1) { $frows->[$_][$i] //= "" }
         }
     }
 }
 
 sub _apply_cell_formats {
     my $self = shift;
 
     my $cols  = $self->{columns};
     my $rows  = $self->{rows};
     my $fcols = $self->{_draw}{fcols};
     my $frows = $self->{_draw}{frows};
     my $frow_orig_indices = $self->{_draw}{frow_orig_indices};
 
     for my $i (0..@$frows-1) {
         my %seen;
         my $origi = $frow_orig_indices->[$i];
         for my $j (0..@$cols-1) {
             next unless $cols->[$j] ~~ $fcols;
             next if $seen{$cols->[$j]}++;
 
             my $fmts = $self->get_eff_cell_style($origi, $j, 'formats');
             if (defined $fmts) {
                 require Data::Unixish::Apply;
                 my $res = Data::Unixish::Apply::apply(
                     in => [ $frows->[$i][$j] ],
                     functions => $fmts,
                 );
                 croak "Can't format cell ($origi, $cols->[$j]): ".
                     "$res->[0] - $res->[1]" unless $res->[0] == 200;
                 $frows->[$i][$j] = $res->[2][0] // "";
             }
         } # col
     }
 }
 
 sub _calc_row_widths_heights {
     my $self = shift;
 
     my $cols  = $self->{columns};
     my $fcols = $self->{_draw}{fcols};
     my $frows = $self->{_draw}{frows};
 
     my $frow_heights = [];
     my $fcol_widths  = $self->{_draw}{fcol_widths};
     my $frow_orig_indices = $self->{_draw}{frow_orig_indices};
 
     my $height = $self->{cell_height};
     my $tpad = $self->{cell_tpad} // $self->{cell_vpad}; # tbl-lvl tpad
     my $bpad = $self->{cell_bpad} // $self->{cell_vpad}; # tbl-lvl bpad
     my $cswidths = [map {$self->get_eff_column_style($_, 'width')} 0..@$cols-1];
     for my $i (0..@$frows-1) {
         my %seen;
         my $origi = $frow_orig_indices->[$i];
         my $rsheight = $self->get_eff_row_style($origi, 'height');
         for my $j (0..@$cols-1) {
             next unless $cols->[$j] ~~ $fcols;
             next if $seen{$cols->[$j]}++;
 
             my $wh = $self->_opt_calc_cell_width_height($i,$j,$frows->[$i][$j]);
 
             $fcol_widths->[$j]  = $wh->[0] if $fcol_widths->[$j] < $wh->[0];
             $frow_heights->[$i] = $wh->[1] if !defined($frow_heights->[$i])
                 || $frow_heights->[$i] < $wh->[1];
         } # col
     }
     $self->{_draw}{frow_heights}  = $frow_heights;
 }
 
 sub _wrap_wrappable_columns {
     my $self = shift;
 
     my $cols  = $self->{columns};
     my $fcols = $self->{_draw}{fcols};
     my $frows = $self->{_draw}{frows};
     my $fcol_detect    = $self->{_draw}{fcol_detect};
     my $fcol_setwidths = $self->{_draw}{fcol_setwidths};
 
     my %seen;
     for my $i (0..@$cols-1) {
         next unless $cols->[$i] ~~ $fcols;
         next if $seen{$cols->[$i]}++;
 
         if (($self->get_eff_column_style($i, 'wrap') // $self->{column_wrap} //
                  $fcol_detect->[$i]{wrap}) &&
                      defined($fcol_setwidths->[$i]) &&
                          $fcol_setwidths->[$i]>0) {
             for (0..@$frows-1) {
                 $frows->[$_][$i] = ta_mbwrap(
                     $frows->[$_][$i], $fcol_setwidths->[$i]);
             }
         }
     }
 }
 
 sub _calc_table_width_height {
     my $self = shift;
 
     my $cols  = $self->{columns};
     my $fcols = $self->{_draw}{fcols};
     my $frows = $self->{_draw}{frows};
     my $fcol_widths  = $self->{_draw}{fcol_widths};
     my $fcol_lpads   = $self->{_draw}{fcol_lpads};
     my $fcol_rpads   = $self->{_draw}{fcol_rpads};
     my $frow_tpads   = $self->{_draw}{frow_tpads};
     my $frow_bpads   = $self->{_draw}{frow_bpads};
     my $frow_heights = $self->{_draw}{frow_heights};
 
     my $w = 0;
     $w += 1 if length($self->get_border_char(3, 0));
     my $has_vsep = length($self->get_border_char(3, 1));
     for my $i (0..@$cols-1) {
         next unless $cols->[$i] ~~ $fcols;
         $w += $fcol_lpads->[$i] + $fcol_widths->[$i] + $fcol_rpads->[$i];
         if ($i < @$cols-1) {
             $w += 1 if $has_vsep;
         }
     }
     $w += 1 if length($self->get_border_char(3, 2));
     $self->{_draw}{table_width}  = $w;
 
     my $h = 0;
     $h += 1 if length($self->get_border_char(0, 0)); # top border line
     $h += $self->{header_tpad} // $self->{header_vpad} //
         $self->{cell_tpad} // $self->{cell_vpad};
     $h += $self->{_draw}{header_height} // 0;
     $h += $self->{header_bpad} // $self->{header_vpad} //
         $self->{cell_bpad} // $self->{cell_vpad};
     $h += 1 if length($self->get_border_char(2, 0));
     for my $i (0..@$frows-1) {
         $h += ($frow_tpads->[$i] // 0) +
             ($frow_heights->[$i] // 0) +
                 ($frow_bpads->[$i] // 0);
         $h += 1 if $self->_should_draw_row_separator($i);
     }
     $h += 1 if length($self->get_border_char(5, 0));
     $self->{_draw}{table_height}  = $h;
 }
 
 # if there are text columns with no width set, and the column width is wider
 # than terminal, try to adjust widths so it fit into the terminal, if possible.
 # return 1 if widths (fcol_widths) adjusted.
 sub _adjust_column_widths {
     my $self = shift;
 
     # try to find wrappable columns that do not have their widths set. currently
     # the algorithm is not proper, it just targets columns which are wider than
     # a hard-coded value (30). it should take into account the longest word in
     # the content/header, but this will require another pass at the text to
     # analyze it.
 
     my $fcols = $self->{_draw}{fcols};
     my $frows = $self->{_draw}{frows};
     my $fcol_setwidths = $self->{_draw}{fcol_setwidths};
     my $fcol_detect    = $self->{_draw}{fcol_detect};
     my $fcol_widths    = $self->{_draw}{fcol_widths};
     my %acols;
     my %origw;
     for my $i (0..@$fcols-1) {
         my $ci = $self->_colnum($fcols->[$i]);
         next if defined($fcol_setwidths->[$ci]) && $fcol_setwidths->[$ci]>0;
         next if $fcol_widths->[$ci] < 30;
         next unless $self->get_eff_column_style($ci, 'wrap') //
             $self->{column_wrap} // $fcol_detect->[$ci]{wrap};
         $acols{$ci}++;
         $origw{$ci} = $fcol_widths->[$ci];
     }
     return 0 unless %acols;
 
     # only do this if table width exceeds terminal width
     my $termw = $self->term_width;
     return 0 unless $termw > 0;
     my $excess = $self->{_draw}{table_width} - $termw;
     return 0 unless $excess > 0;
 
     # reduce text columns proportionally
     my $w = 0; # total width of all to-be-adjusted columns
     $w += $fcol_widths->[$_] for keys %acols;
     return 0 unless $w > 0;
     my $reduced = 0;
   REDUCE:
     while (1) {
         my $has_reduced;
         for my $ci (keys %acols) {
             last REDUCE if $reduced >= $excess;
             if ($fcol_widths->[$ci] > 30) {
                 $fcol_widths->[$ci]--;
                 $reduced++;
                 $has_reduced++;
             }
         }
         last if !$has_reduced;
     }
 
     # reset widths
     for my $ci (keys %acols) {
         $fcol_setwidths->[$ci] = $fcol_widths->[$ci];
         $fcol_widths->[$ci] = 0; # reset
     }
 
     # wrap and set setwidths so it doesn't grow again during recalculate
     for my $ci (keys %acols) {
         next unless $origw{$ci} != $fcol_widths->[$ci];
         for (0..@$frows-1) {
             $frows->[$_][$ci] = ta_mbwrap(
                 $frows->[$_][$ci], $fcol_setwidths->[$ci]);
         }
     }
 
     # recalculate column widths
     $self->_calc_row_widths_heights;
     $self->_calc_table_width_height;
     1;
 }
 
 # filter columns & rows, calculate widths/paddings, format data, put the results
 # in _draw (draw data) attribute.
 sub _prepare_draw {
     my $self = shift;
 
     $self->{_draw} = {};
 
     $self->_read_style_envs;
     $self->_calc_fcols;
     $self->_calc_header_height;
     $self->_calc_frows;
     $self->_detect_column_types;
     $self->_apply_column_formats;
     $self->_apply_cell_formats;
     $self->_wrap_wrappable_columns;
     $self->_calc_row_widths_heights;
     $self->_calc_table_width_height;
     $self->_adjust_column_widths;
 }
 
 # push string into the drawing buffer. also updates "cursor" position.
 sub draw_str {
     my $self = shift;
     # currently x position is not recorded because this involves doing
     # ta_mbswidth() (or ta_mbswidth_height()) for every string, which is rather
     # expensive. so only the y position is recorded by counting newlines.
 
     for (@_) {
         my $num_nl = 0;
         $num_nl++ while /\r?\n/og;
         push @{$self->{_draw}{buf}}, $_;
         $self->{_draw}{y} += $num_nl;
     }
     $self;
 }
 
 sub draw_theme_color {
     my $self = shift;
     my $c = $self->get_theme_color_as_ansi(@_);
     $self->draw_str($c) if length($c);
 }
 
 sub get_color_reset {
     my $self = shift;
     return "" if $self->{color_theme}{no_color};
     "\e[0m";
 }
 
 sub draw_color_reset {
     my $self = shift;
     my $c = $self->get_color_reset;
     $self->draw_str($c) if length($c);
 }
 
 # draw border character(s). drawing border character involves setting border
 # color, setting drawing mode (for boxchar styles), aside from drawing the
 # actual characters themselves. arguments are list of (y, x, n) tuples where y
 # and x are the row and col number of border character, n is the number of
 # characters to print. n defaults to 1 if not specified.
 sub draw_border_char {
     my $self = shift;
     my $args = shift if ref($_[0]) eq 'HASH';
 
     $self->draw_str($self->{_draw}{set_line_draw_mode});
     while (my ($y, $x, $n) = splice @_, 0, 3) {
         $n //= 1;
         if (!$self->{use_color}) {
             # save some CPU cycles
         } elsif ($args) {
             $self->draw_theme_color('border',
                                     {border=>[$y, $x, $n], %$args});
         } else {
             $self->draw_theme_color('border',
                                     {border=>[$y, $x, $n]});
         }
         $self->draw_str($self->get_border_char($y, $x, $n));
         $self->draw_color_reset;
     }
     $self->draw_str($self->{_draw}{reset_line_draw_mode});
 }
 
 sub _should_draw_row_separator {
     my ($self, $i) = @_;
 
     return $i < @{$self->{_draw}{frows}}-1 &&
         (($self->{show_row_separator}==2 && $i~~$self->{_draw}{frow_separators})
              || $self->{show_row_separator}==1);
 }
 
 # apply align/valign, apply padding, apply default fgcolor/bgcolor to text,
 # truncate to specified cell's width & height
 sub _get_cell_lines {
     my $self = shift;
     #say "D: get_cell_lines ".join(", ", map{$_//""} @_);
     my ($text, $width, $height, $align, $valign,
         $lpad, $rpad, $tpad, $bpad, $color) = @_;
 
     my @lines;
     push @lines, "" for 1..$tpad;
     my @dlines = split(/\r?\n/, $text);
     @dlines = ("") unless @dlines;
     my ($la, $lb);
     $valign //= 'top';
     if ($valign =~ /^[Bb]/o) { # bottom
         $la = $height-@dlines;
         $lb = 0;
     } elsif ($valign =~ /^[MmCc]/o) { # middle/center
         $la = int(($height-@dlines)/2);
         $lb = $height-@dlines-$la;
     } else { # top
         $la = 0;
         $lb = $height-@dlines;
     }
     push @lines, "" for 1..$la;
     push @lines, @dlines;
     push @lines, "" for 1..$lb;
     push @lines, "" for 1..$bpad;
 
     $align //= 'left';
     my $pad = $align =~ /^[Ll]/o ? "right" :
         ($align =~ /^[Rr]/o ? "left" : "center");
 
     for (@lines) {
         $_ = (" "x$lpad) . ta_mbpad($_, $width, $pad, " ", 1) . (" "x$rpad);
         if ($self->{use_color}) {
             # add default color
             s/\e\[0m(?=.)/\e[0m$color/g if length($color);
             $_ = $color . $_;
         }
     }
 
     \@lines;
 }
 
 sub _get_header_cell_lines {
     my ($self, $i) = @_;
 
     my $ct = $self->{color_theme};
 
     my $fgcolor;
     if (defined $self->{header_fgcolor}) {
         $fgcolor = $self->theme_color_to_ansi($self->{header_fgcolor});
     } elsif (defined $self->{cell_fgcolor}) {
         $fgcolor = $self->theme_color_to_ansi($self->{cell_fgcolor});
     #} elsif (defined $self->{_draw}{fcol_detect}[$i]{fgcolor}) {
     #    $fgcolor = $self->themecol2ansi($self->{_draw}{fcol_detect}[$i]{fgcolor});
     } elsif (defined $ct->{colors}{header}) {
         $fgcolor = $self->get_theme_color_as_ansi('header');
     } elsif (defined $ct->{colors}{cell}) {
         $fgcolor = $self->get_theme_color_as_ansi('cell');
     } else {
         $fgcolor = "";
     }
 
     my $bgcolor;
     if (defined $self->{header_bgcolor}) {
         $bgcolor = $self->theme_color_to_ansi($self->{header_bgcolor},
                                               undef, 1);
     } elsif (defined $self->{cell_bgcolor}) {
         $bgcolor = $self->theme_color_to_ansi($self->{cell_bgcolor},
                                               undef, 1);
     } elsif (defined $self->{_draw}{fcol_detect}[$i]{bgcolor}) {
         $fgcolor = $self->theme_color_to_ansi($self->{_draw}{fcol_detect}[$i]{bgcolor},
                                               undef, 1);
     } elsif (defined $ct->{colors}{header_bg}) {
         $bgcolor = $self->get_theme_color_as_ansi('header_bg');
     } elsif (defined $ct->{colors}{cell_bg}) {
         $bgcolor = $self->get_theme_color_as_ansi('cell_bg');
     } else {
         $bgcolor = "";
     }
 
     my $align =
         $self->{header_align} //
             $self->{cell_align} //
                 $self->{_draw}{fcol_detect}[$i]{align} //
                     'left';
     my $valign =
         $self->{header_valign} //
             $self->{cell_valign} //
                 $self->{_draw}{fcol_detect}[$i]{valign} //
                     'top';
 
     my $lpad = $self->{_draw}{fcol_lpads}[$i];
     my $rpad = $self->{_draw}{fcol_rpads}[$i];
     my $tpad = $self->{header_tpad} // $self->{header_vpad} // 0;
     my $bpad = $self->{header_bpad} // $self->{header_vpad} // 0;
 
     #use Data::Dump; print "D:header cell: "; dd {i=>$i, col=>$self->{columns}[$i], fgcolor=>$fgcolor, bgcolor=>$bgcolor};
     my $res = $self->_get_cell_lines(
         $self->{columns}[$i],            # text
         $self->{_draw}{fcol_widths}[$i], # width
         $self->{_draw}{header_height},   # height
         $align, $valign,                 # aligns
         $lpad, $rpad, $tpad, $bpad,      # paddings
         $fgcolor . $bgcolor);
     #use Data::Dump; print "D:res: "; dd $res;
     $res;
 }
 
 sub _get_data_cell_lines {
     my ($self, $y, $x) = @_;
 
     my $ct   = $self->{color_theme};
     my $oy   = $self->{_draw}{frow_orig_indices}[$y];
     my $cell = $self->{_draw}{frows}[$y][$x];
     my $args = {row_num=>$y, col_num=>$x, data=>$cell,
                 orig_data=>$self->{rows}[$oy][$x]};
 
     my $tmp;
     my $fgcolor;
     if (defined ($tmp = $self->get_eff_cell_style($oy, $x, 'fgcolor'))) {
         $fgcolor = $self->theme_color_to_ansi($tmp, $args);
     } elsif (defined ($tmp = $self->get_eff_row_style($oy, 'fgcolor'))) {
         $fgcolor = $self->theme_color_to_ansi($tmp, $args);
     } elsif (defined ($tmp = $self->get_eff_column_style($x, 'fgcolor'))) {
         $fgcolor = $self->theme_color_to_ansi($tmp, $args);
     } elsif (defined ($tmp = $self->{cell_fgcolor})) {
         $fgcolor = $self->theme_color_to_ansi($tmp, $args);
     } elsif (defined ($tmp = $self->{_draw}{fcol_detect}[$x]{fgcolor})) {
         $fgcolor = $self->theme_color_to_ansi($tmp, $args);
     } elsif (defined $ct->{colors}{cell}) {
         $fgcolor = $self->get_theme_color_as_ansi('cell', $args);
     } else {
         $fgcolor = "";
     }
 
     my $bgcolor;
     if (defined ($tmp = $self->get_eff_cell_style($oy, $x, 'bgcolor'))) {
         $bgcolor = $self->theme_color_to_ansi($tmp, $args, 1);
     } elsif (defined ($tmp = $self->get_eff_row_style($oy, 'bgcolor'))) {
         $bgcolor = $self->theme_color_to_ansi($tmp, $args, 1);
     } elsif (defined ($tmp = $self->get_eff_column_style($x, 'bgcolor'))) {
         $bgcolor = $self->theme_color_to_ansi($tmp, $args, 1);
     } elsif (defined ($tmp = $self->{cell_bgcolor})) {
         $bgcolor = $self->theme_color_to_ansi($tmp, $args, 1);
     } elsif (defined ($tmp = $self->{_draw}{fcol_detect}[$x]{bgcolor})) {
         $bgcolor = $self->theme_color_to_ansi($tmp, $args, 1);
     } elsif (defined $ct->{colors}{cell_bg}) {
         $bgcolor = $self->get_theme_color_as_ansi('cell_bg', $args);
     } else {
         $bgcolor = "";
     }
 
     my $align =
         $self->get_eff_cell_style($oy, $x, 'align') //
             $self->get_eff_row_style($oy, 'align') //
                 $self->get_eff_column_style($x, 'align') //
                     $self->{cell_align} //
                         $self->{_draw}{fcol_detect}[$x]{align} //
                             'left';
     my $valign =
         $self->get_eff_cell_style($oy, $x, 'valign') //
             $self->get_eff_row_style($oy, 'valign') //
                 $self->get_eff_column_style($x, 'valign') //
                     $self->{cell_valign} //
                         $self->{_draw}{fcol_detect}[$x]{valign} //
                             'top';
     #say "D:y=$y, x=$x, align=$align, valign=$valign";
 
     my $lpad = $self->{_draw}{fcol_lpads}[$x];
     my $rpad = $self->{_draw}{fcol_rpads}[$x];
     my $tpad = $self->{_draw}{frow_tpads}[$y];
     my $bpad = $self->{_draw}{frow_bpads}[$y];
 
     my $res = $self->_get_cell_lines(
         $cell,                            # text
         $self->{_draw}{fcol_widths}[$x],  # width
         $self->{_draw}{frow_heights}[$y], # height
         $align, $valign,                  # aligns
         $lpad, $rpad, $tpad, $bpad,       # paddings
         $fgcolor . $bgcolor);
     $res;
 }
 
 sub draw {
     my ($self) = @_;
 
     $self->_prepare_draw;
 
     $self->{_draw}{buf} = []; # output buffer
     $self->{_draw}{y} = 0; # current line
 
     # ansi codes to set and reset line-drawing mode.
     {
         my $bs = $self->{border_style};
         $self->{_draw}{set_line_draw_mode}   = $bs->{box_chars} ? "\e(0" : "";
         $self->{_draw}{reset_line_draw_mode} = $bs->{box_chars} ? "\e(B" : "";
     }
 
     my $cols  = $self->{columns};
     my $fcols = $self->{_draw}{fcols};
     my $frows = $self->{_draw}{frows};
     my $frow_heights    = $self->{_draw}{frow_heights};
     my $frow_tpads      = $self->{_draw}{frow_tpads};
     my $frow_bpads      = $self->{_draw}{frow_bpads};
     my $fcol_lpads      = $self->{_draw}{fcol_lpads};
     my $fcol_rpads      = $self->{_draw}{fcol_rpads};
     my $fcol_widths     = $self->{_draw}{fcol_widths};
 
     # draw border top line
     {
         last unless length($self->get_border_char(0, 0));
         my @b;
         push @b, 0, 0, 1;
         for my $i (0..@$fcols-1) {
             my $ci = $self->_colnum($fcols->[$i]);
             push @b, 0, 1,
                 $fcol_lpads->[$ci] + $fcol_widths->[$ci] + $fcol_rpads->[$ci];
             push @b, 0, 2, 1 if $i < @$fcols-1;
         }
         push @b, 0, 3, 1;
         $self->draw_border_char(@b);
         $self->draw_str("\n");
     }
 
     # draw header
     if ($self->{show_header}) {
         my %seen;
         my $hcell_lines = []; # index = [fcolnum]
         if (@$fcols) {
             for my $i (0..@$fcols-1) {
                 my $ci = $self->_colnum($fcols->[$i]);
                 if (defined($seen{$i})) {
                     $hcell_lines->[$i] = $hcell_lines->[$seen{$i}];
                 }
                 $seen{$i} = $ci;
                 $hcell_lines->[$i] = $self->_get_header_cell_lines($ci);
             }
         } else {
             # so we can still draw header
             $hcell_lines->[0] = [""];
         }
         #use Data::Dump; print "D:hcell_lines: "; dd $hcell_lines;
         for my $l (0..@{ $hcell_lines->[0] }-1) {
             $self->draw_border_char(1, 0);
             for my $i (0..@$fcols-1) {
                 $self->draw_str($hcell_lines->[$i][$l]);
                 $self->draw_color_reset;
                 $self->draw_border_char(1, 1) unless $i == @$fcols-1;
             }
             $self->draw_border_char(1, 2);
             $self->draw_str("\n");
         }
     }
 
     # draw header-data row separator
     if ($self->{show_header} && length($self->get_border_char(2, 0))) {
         my @b;
         push @b, 2, 0, 1;
         for my $i (0..@$fcols-1) {
             my $ci = $self->_colnum($fcols->[$i]);
             push @b, 2, 1,
                 $fcol_lpads->[$ci] + $fcol_widths->[$ci] + $fcol_rpads->[$ci];
             push @b, 2, 2, 1 unless $i==@$fcols-1;
         }
         push @b, 2, 3, 1;
         $self->draw_border_char(@b);
         $self->draw_str("\n");
     }
 
     # draw data rows
     {
         for my $r (0..@$frows-1) {
             #$self->draw_str("r$r");
             my $dcell_lines = []; # index = [fcolnum]
             my %seen;
             if (@$fcols) {
                 for my $i (0..@$fcols-1) {
                     my $ci = $self->_colnum($fcols->[$i]);
                     if (defined($seen{$i})) {
                         $dcell_lines->[$i] = $dcell_lines->[$seen{$i}];
                     }
                     $seen{$i} = $ci;
                     $dcell_lines->[$i] = $self->_get_data_cell_lines($r, $ci);
                 }
             } else {
                 # so we can still print row
                 $dcell_lines->[0] = [" "];
             }
             #use Data::Dump; print "TMP: dcell_lines: "; dd $dcell_lines;
             for my $l (0..@{ $dcell_lines->[0] }-1) {
                 $self->draw_border_char({row_num=>$r}, 3, 0);
                 for my $i (0..@$fcols-1) {
                     $self->draw_str($dcell_lines->[$i][$l]);
                     $self->draw_color_reset;
                     $self->draw_border_char({row_num=>$r}, 3, 1)
                         unless $i == @$fcols-1;
                 }
                 $self->draw_border_char({row_num=>$r}, 3, 2);
                 $self->draw_str("\n");
             }
 
             # draw separators between row
             if ($self->_should_draw_row_separator($r)) {
                 my @b;
                 push @b, 4, 0, 1;
                 for my $i (0..@$fcols-1) {
                     my $ci = $self->_colnum($fcols->[$i]);
                     push @b, 4, 1,
                         $fcol_lpads->[$ci] + $fcol_widths->[$ci] +
                             $fcol_rpads->[$ci];
                     push @b, 4, $i==@$fcols-1 ? 3:2, 1;
                 }
                 $self->draw_border_char({row_num=>$r}, @b);
                 $self->draw_str("\n");
             }
         } # for frow
     }
 
     # draw border bottom line
     {
         last unless length($self->get_border_char(5, 0));
         my @b;
         push @b, 5, 0, 1;
         for my $i (0..@$fcols-1) {
             my $ci = $self->_colnum($fcols->[$i]);
             push @b, 5, 1,
                 $fcol_lpads->[$ci] + $fcol_widths->[$ci] + $fcol_rpads->[$ci];
             push @b, 5, 2, 1 unless $i == @$fcols-1;
         }
         push @b, 5, 3, 1;
         $self->draw_border_char(@b);
         $self->draw_str("\n");
     }
 
     join "", @{$self->{_draw}{buf}};
 }
 
 1;
 # ABSTRACT: Create nice formatted tables using extended ASCII and ANSI colors
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Text::ANSITable - Create nice formatted tables using extended ASCII and ANSI colors
 
 =head1 VERSION
 
 This document describes version 0.43 of Text::ANSITable (from Perl distribution Text-ANSITable), released on 2015-10-21.
 
 =head1 SYNOPSIS
 
  use 5.010;
  use Text::ANSITable;
 
  # don't forget this if you want to output utf8 characters
  binmode(STDOUT, ":utf8");
 
  my $t = Text::ANSITable->new;
 
  # set styles
  $t->border_style('Default::bold');  # if not, a nice default is picked
  $t->color_theme('Default::sepia');  # if not, a nice default is picked
 
  # fill data
  $t->columns(["name"       , "color" , "price"]);
  $t->add_row(["chiki"      , "yellow",    2000]);
  $t->add_row(["lays"       , "green" ,    7000]);
  $t->add_row(["tao kae noi", "blue"  ,   18500]);
 
  # draw it!
  print $t->draw;
 
 Samples of output:
 
 =head1 DESCRIPTION
 
 This module is yet another text table formatter module like L<Text::ASCIITable>
 or L<Text::SimpleTable>, with the following differences:
 
 =over
 
 =item * Colors and color themes
 
 ANSI color codes will be used by default (even 256 and 24bit colors), but will
 degrade to lower color depth and black/white according to terminal support.
 
 =item * Box-drawing characters
 
 Box-drawing characters will be used by default, but will degrade to using normal
 ASCII characters if terminal does not support them.
 
 =item * Unicode and wide character support
 
 Border styles using Unicode characters (double lines, bold/heavy lines, brick
 style, etc). Columns containing wide characters stay aligned.
 
 =back
 
 Compared to Text::ASCIITable, it uses C<lower_case> method/attr names instead of
 C<CamelCase>, and it uses arrayref for C<columns> and C<add_row>. When
 specifying border styles, the order of characters are slightly different. More
 fine-grained options to customize appearance.
 
 =for Pod::Coverage ^(BUILD|draw_.+|get_color_reset|get_border_char)$
 
 =begin HTML
 
 <p><img src="http://blogs.perl.org/users/steven_haryanto/ansitable1.png" /></p>
 
 <p><img src="http://blogs.perl.org/users/steven_haryanto/ansitable2.png" /></p>
 
 <p><img src="http://blogs.perl.org/users/steven_haryanto/ansitable3.png" /></p>
 
 <p><img src="http://blogs.perl.org/users/steven_haryanto/ansitable4.png" /></p>
 
 <p><img src="http://blogs.perl.org/users/steven_haryanto/ansitable5.png" /></p>
 
 =end HTML
 
 =head1 BORDER STYLES
 
 To list available border styles:
 
  say $_ for $t->list_border_styles;
 
 Or you can also try out borders using the provided
 L<ansitable-list-border-styles> script. Or, you can also view the documentation
 for the C<Text::ANSITable::BorderStyle::*> modules, where border styles are
 searched.
 
 To choose border style, either set the C<border_style> attribute to an available
 border style or a border specification directly.
 
  $t->border_style("Default::singleh_boxchar");
  $t->border_style("Foo::bar");   # dies, no such border style
  $t->border_style({ ... }); # set specification directly
 
 If no border style is selected explicitly, a nice default will be chosen. You
 can also set the C<ANSITABLE_BORDER_STYLE> environment variable to set the
 default.
 
 To create a new border style, create a module under
 C<Text::ANSITable::BorderStyle::>. Please see one of the existing border style
 modules for example, like L<Text::ANSITable::BorderStyle::Default>. For more
 about border styles, refer to L<Border::Style::Role>.
 
 =head1 COLOR THEMES
 
 To list available color themes:
 
  say $_ for $t->list_color_themes;
 
 Or you can also run the provided L<ansitable-list-color-themes> script. Or you
 can view the documentation for the C<Text::ANSITable::ColorTheme::*> modules
 where color themes are searched.
 
 To choose a color theme, either set the C<color_theme> attribute to an available
 color theme or a color theme specification directly.
 
  $t->color_theme("Default::default_nogradation");
  $t->color_theme("Foo::bar");    # dies, no such color theme
  $t->color_theme({ ... });  # set specification directly
 
 If no color theme is selected explicitly, a nice default will be chosen. You can
 also set the C<ANSITABLE_COLOR_THEME> environment variable to set the default.
 
 To create a new color theme, create a module under
 C<Text::ANSITable::ColorTheme::>. Please see one of the existing color theme
 modules for example, like L<Text::ANSITable::ColorTheme::Default>. For more
 about color themes, refer to L<Color::Theme::Role>.
 
 =head1 COLUMN WIDTHS
 
 By default column width is set just so it is enough to show the widest data.
 This can be customized in the following ways (in order of precedence, from
 lowest):
 
 =over
 
 =item * table-level C<cell_width> attribute
 
 This sets width for all columns.
 
 =item * conditional column styles
 
 The example below sets column width to 10 for columns whose names matching
 C</[acm]time/>, else sets the column width to 20.
 
  $t->add_cond_column_style(sub {  /[acm]time/ }, width => 10);
  $t->add_cond_column_style(sub { !/[acm]time/ }, width => 20);
 
 =item * per-column C<width> style
 
  $t->set_column_style('colname', width => 20);
 
 =back
 
 You can use negative number to mean I<minimum> width.
 
 =head1 ROW HEIGHTS
 
 This can be customized in the following ways (in order of precedence, from
 lowest):
 
 =over
 
 =item * table-level C<cell_height> attribute
 
 This sets height for all rows.
 
 =item * conditional row styles
 
 The example below sets row height to 2 for every odd rows, and 1 for even rows.
 
  $t->add_cond_row_style(sub { $_ % 2 == 0 }, height => 2);
  $t->add_cond_row_style(sub { $_ % 2      }, height => 1);
 
 =item * per-row C<height> style
 
  $t->set_row_style(1, height => 2);
 
 =back
 
 You can use negative number to mean I<minimum> height.
 
 =head1 CELL (HORIZONTAL) PADDING
 
 By default cell (horizontal) padding is 1. This can be customized in the
 following ways (in order of precedence, from lowest):
 
 =over
 
 =item * table-level C<cell_pad> attribute
 
 This sets left and right padding for all columns.
 
 =item * table-level C<cell_lpad> and C<cell_rpad> attributes
 
 They set left and right padding for all columns, respectively.
 
 =item * conditional column C<pad> style
 
  $t->add_cond_column_style($cond, pad => 0);
 
 =item * conditional column C<lpad>/C<rpad> style
 
  $t->add_cond_column_style($cond, lpad => 1, rpad => 2);
 
 =item * per-column C<pad> style
 
  $t->set_column_style($colname, pad => 0);
 
 =item * per-column C<lpad>/C<rpad> style
 
  $t->set_column_style($colname, lpad => 1);
  $t->set_column_style($colname, rpad => 2);
 
 =back
 
 =head1 ROW VERTICAL PADDING
 
 Default vertical padding is 0. This can be changed in the following ways (in
 order of precedence, from lowest):
 
 =over
 
 =item * table-level C<cell_vpad> attribute
 
 This sets top and bottom padding for all rows.
 
 =item * table-level C<cell_tpad>/C<cell_bpad> attributes
 
 They set top/bottom padding separately for all rows.
 
 =item * conditional row C<vpad> style
 
 Example:
 
  $t->add_cond_row_style($cond, vpad => 1);
 
 =item * per-row C<vpad> style
 
 Example:
 
  $t->set_row_style($rownum, vpad => 1);
 
 When adding row:
 
  $t->add_row($rownum, {vpad=>1});
 
 =item * per-row C<tpad>/C<bpad> style
 
 Example:
 
  $t->set_row_style($row_num, tpad => 1);
  $t->set_row_style($row_num, bpad => 2);
 
 When adding row:
 
  $t->add_row($row, {tpad=>1, bpad=>2});
 
 =back
 
 =head1 CELL COLORS
 
 By default data format colors are used, e.g. cyan/green for text (using the
 default color scheme, items C<num_data>, C<bool_data>, etc). In absense of that,
 C<cell_fgcolor> and C<cell_bgcolor> from the color scheme are used. You can
 customize colors in the following ways (ordered by precedence, from lowest):
 
 =over
 
 =item * table-level C<cell_fgcolor> and C<cell_bgcolor> attributes
 
 Sets all cells' colors. Color should be specified using 6-hexdigit RGB which
 will be converted to the appropriate terminal color.
 
 Can also be set to a coderef which will receive ($rownum, $colname) and should
 return an RGB color.
 
 =item * conditional column C<fgcolor> and C<bgcolor> style
 
 Example:
 
  $t->add_cond_column_style($cond, fgcolor => 'fa8888', bgcolor => '202020');
 
 =item * per-column C<fgcolor> and C<bgcolor> styles
 
 Example:
 
  $t->set_column_style('colname', fgcolor => 'fa8888');
  $t->set_column_style('colname', bgcolor => '202020');
 
 =item * conditional row C<fgcolor> and C<bgcolor> style
 
 Example:
 
  $t->add_cond_row_style($cond, fgcolor => 'fa8888', bgcolor => '202020');
 
 =item * per-row C<fgcolor> and C<bgcolor> styles
 
 Example:
 
  $t->set_row_style($rownum, {fgcolor => 'fa8888', bgcolor => '202020'});
 
 When adding row/rows:
 
  $t->add_row($row, {fgcolor=>..., bgcolor=>...});
  $t->add_rows($rows, {bgcolor=>...});
 
 =item * conditional cell C<fgcolor> and C<bgcolor> style
 
  $t->add_cond_cell_style($cond, fgcolor=>..., bgcolor=>...);
 
 =item * per-cell C<fgcolor> and C<bgcolor> styles
 
 Example:
 
  $t->set_cell_style($rownum, $colname, fgcolor => 'fa8888');
  $t->set_cell_style($rownum, $colname, bgcolor => '202020');
 
 =back
 
 For flexibility, all colors can be specified as coderef. See L</"COLOR THEMES">
 for more details.
 
 =head1 CELL (HORIZONTAL AND VERTICAL) ALIGNMENT
 
 By default, numbers are right-aligned, dates and bools are centered, and the
 other data types (text including) are left-aligned. All data are top-valigned.
 This can be customized in the following ways (in order of precedence, from
 lowest):
 
 =over
 
 =item * table-level C<cell_align> and C<cell_valign> attribute
 
 =item * conditional column C<align> and <valign> styles
 
  $t->add_cond_column_style($cond, align=>..., valign=>...);
 
 =item * per-column C<align> and C<valign> styles
 
 Example:
 
  $t->set_column_style($colname, align  => 'middle'); # or left, or right
  $t->set_column_style($colname, valign => 'top');    # or bottom, or middle
 
 =item * conditional row C<align> and <valign> styles
 
  $t->add_cond_row_style($cond, align=>..., valign=>...);
 
 =item * per-row C<align> and C<valign> styles
 
 =item * conditional cell C<align> and <valign> styles
 
  $t->add_cond_cell_style($cond, align=>..., valign=>...);
 
 =item * per-cell C<align> and C<valign> styles
 
  $t->set_cell_style($rownum, $colname, align  => 'middle');
  $t->set_cell_style($rownum, $colname, valign => 'top');
 
 =back
 
 =head1 CELL FORMATS
 
 The per-column- and per-cell- C<formats> style regulates how to format data. The
 value for this style setting will be passed to L<Data::Unixish::Apply>'s
 C<apply()>, as the C<functions> argument. So it should be a single string (like
 C<date>) or an array (like C<< ['date', ['centerpad', {width=>20}]] >>).
 
 See L<Data::Unixish> or install L<App::dux> and then run C<dux -l> to see what
 functions are available. Functions of interest to formatting data include:
 C<bool>, C<num>, C<sprintf>, C<sprintfn>, C<wrap>, C<ANSI::*> (in
 L<Data::Unixish::ANSI>), (among others).
 
 =head1 CONDITIONAL STYLES
 
 As an alternative to setting styles for specific {column,row,cell}, you can also
 create conditional styles. You specify a Perl code for the condition, then if
 the condition evaluates to true, the corresponding styles are applied to the
 corresponding {column,row,cell}.
 
 To add a conditional style, use the C<add_cond_{column,row,cell}_style> methods.
 These methods accept condition code as its first argument and one or more styles
 in the subsequent argument(s). For example:
 
  $t->add_cond_row_style(sub { $_ % 2 }, bgcolor=>'202020');
 
 The above example will set row bgcolor for odd rows. You can add more
 conditional styles:
 
  $t->add_cond_row_style(sub { $_ % 2 == 0 }, bgcolor=>'404040');
 
 All the conditions will be evaluated and the applicable styles will be merged
 together. For example, if we add a third conditional row style:
 
  $t->add_cond_row_style(sub { $_ % 10 == 0 }, height=>2, fgcolor=>'ffff00');
 
 then every tenth row will have its height set to 2, fgcolor set to ffff00, and
 bgcolor set to 404040 (from the second conditional).
 
 Condition coderef will be called with these arguments:
 
  ($self, %args)
 
 Available keys in C<%args> for conditional column styles: C<col> (int, column
 index), C<colname> (str, column name). Additionally, C<$_> will be set locally
 to the column index.
 
 Available keys in C<%args> for conditional row styles: C<row> (int, row index),
 C<row_data> (array). Additionally, C<$_> will be set locally to the row index.
 
 Available keys in C<%args> for conditional cell styles: C<content> (str), C<col>
 (int, column index), C<row> (int, row index). Additionally, C<$_> will be set
 locally to the cell content.
 
 Coderef should return boolean indicating whether style should be applied to a
 particular column/row/cell. When returning a true value, coderef can also return
 a hashref to return additional styles that will be merged/applied too.
 
 =head1 STYLE SETS
 
 A style set is just a collection of style settings that can be applied.
 Organizing styles into style sets makes applying the styles simpler and more
 reusable.
 
 More than one style sets can be applied.
 
 Style set module accepts arguments.
 
 For example, the L<Text::ANSITable::StyleSet::AltRow> style set defines this:
 
  has odd_bgcolor  => (is => 'rw');
  has even_bgcolor => (is => 'rw');
  has odd_fgcolor  => (is => 'rw');
  has even_fgcolor => (is => 'rw');
 
  sub apply {
      my ($self, $table) = @_;
 
      $table->add_cond_row_style(sub {
          my ($t, %args) = @_;
          my %styles;
          if ($_ % 2) {
              $styles{bgcolor} = $self->odd_bgcolor
                  if defined $self->odd_bgcolor;
              $styles{fgcolor} = $self->odd_fgcolor
                  if defined $self->odd_bgcolor;
          } else {
              $styles{bgcolor} = $self->even_bgcolor
                  if defined $self->even_bgcolor;
              $styles{fgcolor} = $self->even_fgcolor
                  if defined $self->even_bgcolor;
          }
          \%styles;
      });
  }
 
 To apply this style set:
 
  $t->apply_style_set("AltRow", odd_bgcolor=>"003300", even_bgcolor=>"000000");
 
 To create a new style set, create a module under C<Text::ANSITable::StyleSet::>
 like the above example. Please see the other existing style set modules for more
 examples.
 
 =head1 ATTRIBUTES
 
 =head2 columns => ARRAY OF STR
 
 Store column names. Note that when drawing, you can omit some columns, reorder
 them, or display some more than once (see C<column_filter> attribute).
 
 Caveat: Since, for convenience, a column can be referred to using its name or
 position, weird/unecxpected thing can happen if you name a column with a number
 (e.g. 0, 1, 2, ...). So don't do that.
 
 =head2 rows => ARRAY OF ARRAY OF STR
 
 Store row data. You can set this attribute directly, or add rows incrementally
 using C<add_row()> and C<add_rows()> methods.
 
 =head2 row_filter => CODE|ARRAY OF INT
 
 When drawing, only show rows that match this. Can be an array containing indices
 of rows which should be shown, or a coderef which will be called for each row
 with arguments C<< ($row, $row_num) >> and should return a bool value indicating
 whether that row should be displayed.
 
 Internal note: During drawing, rows will be filtered and put into C<<
 $t->{_draw}{frows} >>.
 
 =head2 column_filter => CODE|ARRAY OF STR
 
 When drawing, only show columns that match this. Can be an array containing
 names of columns that should be displayed (column names can be in different
 order or duplicate, column can also be referred to with its numeric index). Can
 also be a coderef which will be called with C<< ($col_name, $col_num) >> for
 every column and should return a bool value indicating whether that column
 should be displayed. The coderef version is more limited in that it cannot
 reorder the columns or instruct for the same column to be displayed more than
 once.
 
 Internal note: During drawing, column names will be filtered and put into C<<
 $t->{_draw}{fcols} >>.
 
 =head2 column_wrap => BOOL
 
 Set column wrapping for all columns. Can be overriden by per-column C<wrap>
 style. By default column wrapping will only be done for text columns and when
 width is explicitly set to a positive value.
 
 =head2 use_color => BOOL
 
 Whether to output color. Default is taken from C<COLOR> environment variable, or
 detected via C<(-t STDOUT)>. If C<use_color> is set to 0, an attempt to use a
 colored color theme (i.e. anything that is not the C<no_color> theme) will
 result in an exception.
 
 (In the future, setting C<use_color> to 0 might opt the module to use
 normal/plain string routines instead of the slower ta_* functions from
 L<Text::ANSI::Util>; this also means that the module won't handle ANSI escape
 codes in the content text.)
 
 =head2 color_depth => INT
 
 Terminal's color depth. Either 16, 256, or 2**24 (16777216). Default will be
 retrieved from C<COLOR_DEPTH> environment or detected using L<Term::Detect>.
 
 =head2 use_box_chars => BOOL
 
 Whether to use box drawing characters. Drawing box drawing characters can be
 problematic in some places because it uses ANSI escape codes to switch to (and
 back from) line drawing mode (C<"\e(0"> and C<"\e(B">, respectively).
 
 Default is taken from C<BOX_CHARS> environment variable, or 1. If
 C<use_box_chars> is set to 0, an attempt to use a border style that uses box
 drawing chararacters will result in an exception.
 
 =head2 use_utf8 => BOOL
 
 Whether to use Unicode (UTF8) characters. Default is taken from C<UTF8>
 environment variable, or detected using L<Term::Detect>, or guessed via L<LANG>
 environment variable. If C<use_utf8> is set to 0, an attempt to select a border
 style that uses Unicode characters will result in an exception.
 
 (In the future, setting C<use_utf8> to 0 might opt the module to use the
 non-"mb_*" version of functions from L<Text::ANSI::Util>, e.g. C<ta_wrap()>
 instead of C<ta_mbwrap()>, and so on).
 
 =head2 border_style => HASH
 
 Border style specification to use.
 
 You can set this attribute's value with a specification or border style name.
 See L<"/BORDER STYLES"> for more details.
 
 =head2 border_style_args => HASH
 
 Some border styles can accept arguments. You can set it here. See the
 corresponding border style's documentation for information on what arguments it
 accepts.
 
 =head2 color_theme => HASH
 
 Color theme specification to use.
 
 You can set this attribute's value with a specification or color theme name. See
 L<"/COLOR THEMES"> for more details.
 
 =head2 color_theme_args => HASH
 
 Some color themes can accept arguments. You can set it here. See the
 corresponding color theme's documentation for information on what arguments it
 accepts.
 
 =head2 show_header => BOOL (default: 1)
 
 When drawing, whether to show header.
 
 =head2 show_row_separator => INT (default: 2)
 
 When drawing, whether to show separator lines between rows. The default (2) is
 to only show separators drawn using C<add_row_separator()>. If you set this to
 1, lines will be drawn after every data row. If you set this attribute to 0, no
 lines will be drawn whatsoever.
 
 =head2 cell_width => INT
 
 Set width for all cells. Can be overriden by per-column C<width> style.
 
 =head2 cell_height => INT
 
 Set height for all cell. Can be overriden by per-row C<height> style.
 
 =head2 cell_align => STR
 
 Set (horizontal) alignment for all cells. Either C<left>, C<middle>, or
 C<right>. Can be overriden by per-column/per-row/per-cell C<align> style.
 
 =head2 cell_valign => STR
 
 Set (horizontal) alignment for all cells. Either C<top>, C<middle>, or
 C<bottom>. Can be overriden by per-column/per-row/per-cell C<align> style.
 
 =head2 cell_pad => INT
 
 Set (horizontal) padding for all cells. Can be overriden by per-column C<pad>
 style.
 
 =head2 cell_lpad => INT
 
 Set left padding for all cells. Overrides the C<cell_pad> attribute. Can be
 overriden by per-column C<lpad> style.
 
 =head2 cell_rpad => INT
 
 Set right padding for all cells. Overrides the C<cell_pad> attribute. Can be
 overriden by per-column C<rpad> style.
 
 =head2 cell_vpad => INT
 
 Set vertical padding for all cells. Can be overriden by per-row C<vpad> style.
 
 =head2 cell_tpad => INT
 
 Set top padding for all cells. Overrides the C<cell_vpad> attribute. Can be
 overriden by per-row C<tpad> style.
 
 =head2 cell_bpad => INT
 
 Set bottom padding for all cells. Overrides the C<cell_vpad> attribute. Can be
 overriden by per-row C<bpad> style.
 
 =head2 cell_fgcolor => RGB|CODE
 
 Set foreground color for all cells. Value should be 6-hexdigit RGB. Can also be
 a coderef that will receive %args (e.g. row_num, col_name, col_num) and should
 return an RGB color. Can be overriden by per-cell C<fgcolor> style.
 
 =head2 cell_bgcolor => RGB|CODE
 
 Like C<cell_fgcolor> but for background color.
 
 =head2 header_fgcolor => RGB|CODE
 
 Set foreground color for all headers. Overrides C<cell_fgcolor> for headers.
 Value should be a 6-hexdigit RGB. Can also be a coderef that will receive %args
 (e.g. col_name, col_num) and should return an RGB color.
 
 =head2 header_bgcolor => RGB|CODE
 
 Like C<header_fgcolor> but for background color.
 
 =head2 header_align => STR
 
 =head2 header_valign => STR
 
 =head2 header_vpad => INT
 
 =head2 header_tpad => INT
 
 =head2 header_bpad => INT
 
 =head1 METHODS
 
 =head2 $t = Text::ANSITable->new(%attrs) => OBJ
 
 Constructor.
 
 =head2 $t->list_border_styles => LIST
 
 Return the names of available border styles. Border styles will be searched in
 C<Text::ANSITable::BorderStyle::*> modules.
 
 =head2 $t->list_color_themes => LIST
 
 Return the names of available color themes. Color themes will be searched in
 C<Text::ANSITable::ColorTheme::*> modules.
 
 =head2 $t->list_style_sets => LIST
 
 Return the names of available style sets. Style set names are retrieved by
 listing modules under C<Text::ANSITable::StyleSet::*> namespace.
 
 =head2 $t->get_border_style($name) => HASH
 
 Can also be called as a static method: C<<
 Text::ANSITable->get_border_style($name) >>.
 
 =head2 $t->get_color_theme($name) => HASH
 
 Can also be called as a static method: C<<
 Text::ANSITable->get_color_theme($name) >>.
 
 =head2 $t->add_row(\@row[, \%styles]) => OBJ
 
 Add a row. Note that row data is not copied, only referenced.
 
 Can also add per-row styles (which can also be done using C<row_style()>).
 
 =head2 $t->add_rows(\@rows[, \%styles]) => OBJ
 
 Add multiple rows. Note that row data is not copied, only referenced.
 
 Can also add per-row styles (which can also be done using C<row_style()>).
 
 =head2 $t->add_row_separator() => OBJ
 
 Add a row separator line.
 
 =head2 $t->get_cell($row_num, $col) => VAL
 
 Get cell value at row #C<$row_num> (starts from zero) and column named/numbered
 C<$col>.
 
 =head2 $t->set_cell($row_num, $col, $newval) => VAL
 
 Set cell value at row #C<$row_num> (starts from zero) and column named/numbered
 C<$col>. Return old value.
 
 =head2 $t->get_column_style($col, $style) => VAL
 
 Get per-column style for column named/numbered C<$col>.
 
 =head2 $t->set_column_style($col, $style=>$val[, $style2=>$val2, ...])
 
 Set per-column style(s) for column named/numbered C<$col>. Available values for
 C<$style>: C<align>, C<valign>, C<pad>, C<lpad>, C<rpad>, C<width>, C<formats>,
 C<fgcolor>, C<bgcolor>, C<type>, C<wrap>.
 
 =head2 $t->get_cond_column_styles => ARRAY
 
 Get all the conditional column styles set so far.
 
 =head2 $t->add_cond_column_style($cond, $style=>$val[, $style2=>$val2 ...])
 
 Add a new conditional column style. See L</"CONDITIONAL STYLES"> for more
 details on conditional style.
 
 =for comment | =head2 $t->clear_cond_column_styles | Clear all the conditional column styles.
 
 =head2 $t->get_eff_column_style($col, $style) => VAL
 
 Get "effective" column style named C<$style> for a particular column. Effective
 column style is calculated from all the conditional column styles and the
 per-column styles then merged together. This is the per-column style actually
 applied.
 
 =head2 $t->get_row_style($row_num) => VAL
 
 Get per-row style for row numbered C<$row_num>.
 
 =head2 $t->set_row_style($row_num, $style=>$newval[, $style2=>$newval2, ...])
 
 Set per-row style(s) for row numbered C<$row_num>. Available values for
 C<$style>: C<align>, C<valign>, C<height>, C<vpad>, C<tpad>, C<bpad>,
 C<fgcolor>, C<bgcolor>.
 
 =head2 $t->get_cond_row_styles => ARRAY
 
 Get all the conditional row styles set so far.
 
 =head2 $t->add_cond_row_style($cond, $style=>$val[, $style2=>$val2 ...])
 
 Add a new conditional row style. See L</"CONDITIONAL STYLES"> for more details
 on conditional style.
 
 =for comment | =head2 $t->clear_cond_row_styles | Clear all the conditional row styles.
 
 =head2 $t->get_eff_row_style($row_num, $style) => VAL
 
 Get "effective" row style named C<$style> for a particular row. Effective row
 style is calculated from all the conditional row styles and the per-row styles
 then merged together. This is the per-row style actually applied.
 
 =head2 $t->get_cell_style($row_num, $col, $style) => VAL
 
 Get per-cell style named C<$style> for a particular cell. Return undef if there
 is no per-cell style with that name.
 
 =head2 $t->set_cell_style($row_num, $col, $style=>$newval[, $style2=>$newval2, ...])
 
 Set per-cell style(s). Available values for C<$style>: C<align>, C<valign>,
 C<formats>, C<fgcolor>, C<bgcolor>.
 
 =head2 $t->get_cond_cell_styles => ARRAY
 
 Get all the conditional cell styles set so far.
 
 =head2 $t->add_cond_cell_style($cond, $style=>$val[, $style2=>$val2 ...])
 
 Add a new conditional cell style. See L</"CONDITIONAL STYLES"> for more details
 on conditional style.
 
 =for comment | =head2 $t->clear_cond_cell_styles | Clear all the conditional cell styles.
 
 =head2 $t->get_eff_cell_style($row_num, $col, $style) => VAL
 
 Get "effective" cell style named C<$style> for a particular cell. Effective cell
 style is calculated from all the conditional cell styles and the per-cell styles
 then merged together. This is the per-cell style actually applied.
 
 =head2 $t->apply_style_set($name, %args)
 
 Apply a style set. See L</"STYLE SETS"> for more details.
 
 =head2 $t->draw => STR
 
 Render table.
 
 =head1 ENVIRONMENT
 
 =head2 COLOR => BOOL
 
 Can be used to set default value for the C<color> attribute.
 
 =head2 COLOR_DEPTH => INT
 
 Can be used to set default value for the C<color_depth> attribute.
 
 =head2 BOX_CHARS => BOOL
 
 Can be used to set default value for the C<box_chars> attribute.
 
 =head2 UTF8 => BOOL
 
 Can be used to set default value for the C<utf8> attribute.
 
 =head2 COLUMNS => INT
 
 Can be used to override terminal width detection.
 
 =head2 ANSITABLE_BORDER_STYLE => STR
 
 Can be used to set default value for C<border_style> attribute.
 
 =head2 ANSITABLE_COLOR_THEME => STR
 
 Can be used to set default value for C<border_style> attribute.
 
 =head2 ANSITABLE_STYLE => JSON
 
 Can be used to set table's most attributes. Value should be a JSON-encoded hash
 of C<< attr => val >> pairs. Example:
 
  % ANSITABLE_STYLE='{"show_row_separator":1}' ansitable-list-border-styles
 
 will display table with row separator lines after every row.
 
 =head2 WRAP => BOOL
 
 Can be used to set default value for the C<wrap> column style.
 
 =head2 ANSITABLE_COLUMN_STYLES => JSON
 
 Can be used to set per-column styles. Interpreted right before draw(). Value
 should be a JSON-encoded hash of C<< col => {style => val, ...} >> pairs.
 Example:
 
  % ANSITABLE_COLUMN_STYLES='{"2":{"type":"num"},"3":{"type":"str"}}' ansitable-list-border-styles
 
 will display the bool columns as num and str instead.
 
 =head2 ANSITABLE_ROW_STYLES => JSON
 
 Can be used to set per-row styles. Interpreted right before draw(). Value should
 be a JSON-encoded a hash of C<< row_num => {style => val, ...} >> pairs.
 Example:
 
  % ANSITABLE_ROW_STYLES='{"0":{"bgcolor":"000080","vpad":1}}' ansitable-list-border-styles
 
 will display the first row with blue background color and taller height.
 
 =head2 ANSITABLE_CELL_STYLES => JSON
 
 Can be used to set per-cell styles. Interpreted right before draw(). Value
 should be a JSON-encoded a hash of C<< "row_num,col" => {style => val, ...} >>
 pairs. Example:
 
  % ANSITABLE_CELL_STYLES='{"1,1":{"bgcolor":"008000"}}' ansitable-list-border-styles
 
 will display the second-on-the-left, second-on-the-top cell with green
 background color.
 
 =head2 ANSITABLE_STYLE_SETS => JSON
 
 Can be used to apply style sets. Value should be a JSON-encoded array. Each
 element must be a style set name or a 2-element array containing style set name
 and its arguments (C<< [$name, \%args] >>). Example:
 
  % ANSITABLE_STYLE_SETS='[["AltRow",{"odd_bgcolor":"003300"}]]'
 
 will display table with row separator lines after every row.
 
 =head1 FAQ
 
 =head2 General
 
 =head3 Output is too fancy! I just want to generate some plain (Text::ASCIITable-like) output to be copy-pasted to my document.
 
  $t->use_utf8(0);
  $t->use_box_chars(0);
  $t->use_color(0);
  $t->border_style('Default::single_ascii');
 
 and you're good to go. Alternatively you can set environment UTF8=0,
 BOX_CHARS=0, COLOR=0, and ANSITABLE_BORDER_STYLE=Default::single_ascii.
 
 =head3 Why am I getting 'Wide character in print' warning?
 
 You are probably using a utf8 border style, and you haven't done something like
 this to your output:
 
  binmode(STDOUT, ":utf8");
 
 =head3 My table looks garbled when viewed through pager like B<less>!
 
 That's because B<less> by default escapes ANSI color and box_char codes. Try
 using C<-R> option of B<less> to display ANSI color codes raw.
 
 Or, try not using colors and box_char border styles:
 
  $t->use_color(0);
  $t->use_box_chars(0);
 
 Note that as of this writing, B<less -R> does not interpret box_char codes so
 you'll need to avoid using box_char border styles if you want your output to
 display properly under B<less>.
 
 =head3 How do I hide some columns/rows when drawing?
 
 Use the C<column_filter> and C<row_filter> attributes. For example, given this
 table:
 
  my $t = Text::ANSITable->new;
  $t->columns([qw/one two three/]);
  $t->add_row([$_, $_, $_]) for 1..10;
 
 Doing this:
 
  $t->row_filter([0, 1, 4]);
  print $t->draw;
 
 will show:
 
   one | two | three
  -----+-----+-------
     1 |   1 |     1
     2 |   2 |     2
     5 |   5 |     5
 
 Doing this:
 
  $t->row_filter(sub { my ($row, $idx) = @_; $row->[0] % 2 }
 
 will display:
 
   one | two | three
  -----+-----+-------
     1 |   1 |     1
     3 |   3 |     3
     5 |   5 |     5
     7 |   7 |     7
     9 |   9 |     9
 
 Doing this:
 
  $t->column_filter([qw/two one 0/]);
 
 will display:
 
   two | one | one
  -----+-----+-----
     1 |   1 |   1
     2 |   2 |   2
     3 |   3 |   3
     4 |   4 |   4
     5 |   5 |   5
     6 |   6 |   6
     7 |   7 |   7
     8 |   8 |   8
     9 |   9 |   9
    10 |  10 |  10
 
 Doing this:
 
  $t->column_filter(sub { my ($colname, $idx) = @_; $colname =~ /t/ });
 
 will display:
 
   two | three
  -----+-------
     1 |     1
     2 |     2
     3 |     3
     4 |     4
     5 |     5
     6 |     6
     7 |     7
     8 |     8
     9 |     9
    10 |    10
 
 =head2 Formatting data
 
 =head3 How do I format data?
 
 Use the C<formats> per-column style or per-cell style. For example:
 
  $t->set_column_style('available', formats => [[bool=>{style=>'check_cross'}],
                                                [centerpad=>{width=>10}]]);
  $t->set_column_style('amount'   , formats => [[num=>{decimal_digits=>2}]]);
  $t->set_column_style('size'     , formats => [[num=>{style=>'kilo'}]]);
 
 See L<Data::Unixish::Apply> and L<Data::Unixish> for more details on the
 available formatting functions.
 
 =head3 How does the module determine column data type?
 
 Currently: if column name has the word C<date> or C<time> in it, the column is
 assumed to contain B<date> data. If column name has C<?> in it, the column is
 assumed to be B<bool>. If a column contains only numbers (or undefs), it is
 B<num>. Otherwise, it is B<str>.
 
 =head3 How does the module format data types?
 
 Currently: B<num> will be right aligned and applied C<num_data> color (cyan in
 the default theme). B<date> will be centered and applied C<date_data> color
 (gold in the default theme). B<bool> will be centered and formatted as
 check/cross symbol and applied C<bool_data> color (red/green depending on
 whether the data is false/true). B<str> will be applied C<str_data> color (no
 color in the default theme).
 
 Other color themes might use different colors.
 
 =head3 How do I force column to be of a certain data type?
 
 For example, you have a column named C<deleted> but want to display it as
 B<bool>. You can do:
 
  $t->set_column_style(deleted => type => 'bool');
 
 =head3 How do I wrap long text?
 
 The C<wrap> dux function can be used to wrap text (see: L<Data::Unixish::wrap>).
 You'll want to set C<ansi> and C<mb> both to 1 to handle ANSI escape codes and
 wide characters in your text (unless you are sure that your text does not
 contain those):
 
  $t->set_column_style('description', formats=>[[wrap => {width=>60, ansi=>1, mb=>1}]]);
 
 =head3 How do I highlight text with color?
 
 The C<ansi::highlight> dux function can be used to highlight text (see:
 L<Data::Unixish::ANSI::highlight>).
 
  $t->set_column_style(2, formats => [[highlight => {pattern=>$pat}]]);
 
 =head3 I want to change the default bool cross/check sign representation!
 
 By default, bool columns are shown as cross/check sign. This can be changed,
 e.g.:
 
  $t->set_column_style($colname, type    => 'bool',
                                 formats => [[bool => {style=>"Y_N"}]]);
 
 See L<Data::Unixish::bool> for more details.
 
 =head3 How do I do conditional cell formatting?
 
 There are several ways.
 
 First, you can use the C<cond> dux function through C<formats> style. For
 example, if the cell contains the string "Cuti", you want to color the cell
 yellow. Otherwise, you want to color the cell red:
 
  $t->set_column_style($colname, formats => [
      [cond => {
          if   => sub { $_ =~ /Cuti/ },
          then => ["ansi::color", {color=>"yellow"}],
          else => ["ansi::color", {color=>"red"}],
      }]
  ]);
 
 Another way is to use the C<add_cond_{cell,row,column}> methods. See
 L</"CONDITIONAL STYLES"> for more details. An example:
 
  $t->add_cond_row_style(sub {
      my %args = @_;
      $args{colname} =~ /Cuti/ ? {bgcolor=>"ffff00"} : {bgcolor=>"ff0000"};
  });
 
 And another way is to use (or create) style set, which is basically a packaging
 of the above ways. An advantage of using style set is, because you do not
 specify coderef directly, you can specify it from the environment variable. See
 L</"STYLE SETS"> for more details.
 
 =head2 Border
 
 =head3 How to hide borders?
 
 There is currently no C<show_border> attribute. Choose border styles like
 C<Default::space_ascii> or C<Default::none_utf8>:
 
  $t->border_style("Default::none");
 
 =head3 Why are there 'none_ascii' as well 'none_utf8' and 'none_boxchar' border styles?
 
 Because of the row separator, that can still be drawn if C<add_row_separator()>
 is used. See next question.
 
 =head3 I want to hide borders, and I do not want row separators to be shown!
 
 The default is for separator lines to be drawn if drawn using
 C<add_row_separator()>, e.g.:
 
  $t->add_row(['row1']);
  $t->add_row(['row2']);
  $t->add_row_separator;
  $t->add_row(['row3']);
 
 The result will be:
 
    row1
    row2
  --------
    row3
 
 However, if you set C<show_row_separator> to 0, no separator lines will be drawn
 whatsoever:
 
    row1
    row2
    row3
 
 =head3 I want to separate each row with a line!
 
 Set C<show_row_separator> to 1, or alternatively, set
 C<ANSITABLE_STYLE='{"show_row_separator":1}>.
 
 =head2 Color
 
 =head3 How to disable colors?
 
 Set C<use_color> attribute or C<COLOR> environment to 0.
 
 =head3 How to specify colors using names (e.g. red, 'navy blue') instead of RGB?
 
 Use modules like L<Graphics::ColorNames>.
 
 =head3 I'm not seeing colors when output is piped (e.g. to a pager)!
 
 The default is to disable colors when (-t STDOUT) is false. You can force-enable
 colors by setting C<use_color> attribute or C<COLOR> environment to 1.
 
 =head3 How to enable 256 colors? I'm seeing only 16 colors.
 
 Use terminal emulators that support 256 colors, e.g. Konsole, xterm,
 gnome-terminal, PuTTY/pterm (but the last one has minimal Unicode support).
 Better yet, use Konsole or Konsole-based emulators which supports 24bit colors.
 
 =head3 How to enable 24bit colors (true color)?
 
 Currently only B<Konsole> and the Konsole-based B<Yakuake> terminal emulator
 software support 24bit colors.
 
 =head3 How to force lower color depth? (e.g. I use Konsole but want 16 colors)
 
 Set C<COLOR_DEPTH> to 16.
 
 =head3 How to change border gradation color?
 
 The default color theme applies vertical color gradation to borders from white
 (ffffff) to gray (444444). To change this, set C<border1> and C<border2> theme
 arguments:
 
  $t->color_theme_args({border1=>'ff0000', border2=>'00ff00'}); # red to green
 
 =head3 I'm using terminal emulator with white background, the texts are not very visible!
 
 Try using the "*_whitebg" themes, as the other themes are geared towards
 terminal emulators with black background.
 
 =head3 How to set different background colors for odd/even rows?
 
 Aside from doing C<< $t->set_row_style($row_num, bgcolor=>...) >> for each row,
 you can also do this:
 
  $t->cell_bgcolor(sub { my ($self, %args) = @_; $args{row_num} % 2 ? '202020' : undef });
 
 Or, you can use conditional row styles:
 
  $t->add_cond_row_style(sub { $_ % 2 }, {bgcolor=>'202020'});
 
 Or, you can use the L<Text::ANSITable::StyleSet::AltRow> style set:
 
  $t->apply_style_set(AltRow => {even_bgcolor=>'202020'});
 
 =head1 SEE ALSO
 
 =head2 Related to Text::ANSITable family
 
 For collections of border styles, search for C<Text::ANSITable::BorderStyle::*>
 modules.
 
 For collections of color themes, search for C<Text::ANSITable::ColorTheme::*>
 modules.
 
 =head2 Other table-formatting CPAN modules
 
 L<Text::ASCIITable> is one of the most popular table-formatting module. There
 are a couple of "extensions" for Text::ASCIITable: L<Text::ASCIITable::TW>,
 L<Text::ASCIITable::Wrap>; Text::ANSITable can be an alternative for all those
 modules since it can already handle wide-characters, multiline text in cells.
 
 L<Text::TabularDisplay>
 
 L<Text::Table>
 
 L<Text::SimpleTable>
 
 L<Text::UnicodeTable::Simple>
 
 L<Table::Simple>
 
 =head2 Other
 
 Unix command B<column> (e.g. C<column -t>).
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Text-ANSITable>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Text-ANSITable>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Text-ANSITable>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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
### Text/ANSITable/BorderStyle/Default.pm ###
 package Text::ANSITable::BorderStyle::Default;
 
 our $DATE = '2015-10-21'; # DATE
 our $VERSION = '0.43'; # VERSION
 
 use 5.010;
 use strict;
 use utf8;
 use warnings;
 
 our %border_styles = (
 
     # none
 
     none_ascii => {
         summary => 'No border',
         chars => [
             ['','','',''],     # 0
             ['','',''],        # 1
             ['','','',''],     # 2
             ['','',''],        # 3
             [' ','-','-',' '], # 4
             ['','','',''],     # 5
         ],
     },
 
     none_boxchar => {
         summary => 'No border',
         chars => [
             ['','','',''],     # 0
             ['','',''],        # 1
             ['','','',''],     # 2
             ['','',''],        # 3
             ['','q','q',''],   # 4
             ['','','',''],     # 5
         ],
         box_chars => 1,
     },
 
     none_utf8 => {
         summary => 'No border',
         chars => [
             ['','','',''],     # 0
             ['','',''],        # 1
             ['','','',''],     # 2
             ['','',''],        # 3
             ['','─','─',''],   # 4
             ['','','',''],     # 5
         ],
         utf8 => 1,
     },
 
 
     # space
 
     space_ascii => {
         summary => 'Space as border',
         chars => [
             [' ',' ',' ',' '], # 0
             [' ',' ',' '],     # 1
             [' ',' ',' ',' '], # 2
             [' ',' ',' '],     # 3
             [' ','-','-',' '], # 4
             [' ',' ',' ',' '], # 5
         ],
     },
 
     space_boxchar => {
         summary => 'Space as border',
         chars => [
             [' ',' ',' ',' '], # 0
             [' ',' ',' '],     # 1
             [' ',' ',' ',' '], # 2
             [' ',' ',' '],     # 3
             [' ','q','q',' '], # 4
             [' ',' ',' ',' '], # 5
         ],
         box_chars => 1,
     },
 
     space_utf8 => {
         summary => 'Space as border',
         chars => [
             [' ',' ',' ',' '], # 0
             [' ',' ',' '],     # 1
             [' ',' ',' ',' '], # 2
             [' ',' ',' '],     # 3
             [' ','─','─',' '], # 4
             [' ',' ',' ',' '], # 5
         ],
         utf8 => 1,
     },
 
     spacei_ascii => {
         summary => 'Space, inner-only',
         chars => [
             ['','','',''],   # 0
             ['',' ',''],     # 1
             ['',' ',' ',''], # 2
             ['',' ',''],     # 3
             ['','-','-',''], # 4
             ['','','',''],   # 5
         ],
     },
 
     spacei_boxchar => {
         summary => 'Space, inner-only',
         chars => [
             ['','','',''],   # 0
             ['',' ',''],     # 1
             ['',' ',' ',''], # 2
             ['',' ',''],     # 3
             ['','q','q',''], # 4
             ['','','',''],   # 5
         ],
         box_chars => 1,
     },
 
     spacei_utf8 => {
         summary => 'Space, inner-only',
         chars => [
             ['','','',''],   # 0
             ['',' ',''],     # 1
             ['',' ',' ',''], # 2
             ['',' ',''],     # 3
             ['','─','─',''], # 4
             ['','','',''],   # 5
         ],
         utf8 => 1,
     },
 
     # single
 
     single_ascii => {
         summary => 'Single',
         chars => [
             ['.','-','+','.'], # 0
             ['|','|','|'],     # 1
             ['+','-','+','+'], # 2
             ['|','|','|'],     # 3
             ['+','-','+','+'], # 4
             ['`','-','+',"'"], # 5
         ],
     },
 
     single_boxchar => {
         summary => 'Single',
         chars => [
             ['l','q','w','k'], # 0
             ['x','x','x'],     # 1
             ['t','q','n','u'], # 2
             ['x','x','x'],     # 3
             ['t','q','n','u'], # 4
             ['m','q','v','j'], # 5
         ],
         box_chars => 1,
     },
 
     single_utf8 => {
         summary => 'Single',
         chars => [
             ['┌','─','┬','┐'], # 0
             ['│','│','│'],     # 1
             ['├','─','┼','┤'], # 2
             ['│','│','│'],     # 3
             ['├','─','┼','┤'], # 4
             ['└','─','┴','┘'], # 5
         ],
         utf8 => 1,
     },
 
 
     # single, horizontal only
 
     singleh_ascii => {
         summary => 'Single, horizontal only',
         chars => [
             ['-','-','-','-'], # 0
             [' ',' ',' '],     # 1
             ['-','-','-','-'], # 2
             [' ',' ',' '],     # 3
             ['-','-','-','-'], # 4
             ['-','-','-','-'], # 5
         ],
     },
 
     singleh_boxchar => {
         summary => 'Single, horizontal only',
         chars => [
             ['q','q','q','q'], # 0
             [' ',' ',' '],     # 1
             ['q','q','q','q'], # 2
             [' ',' ',' '],     # 3
             ['q','q','q','q'], # 4
             ['q','q','q','q'], # 5
         ],
         box_chars => 1,
     },
 
     singleh_utf8 => {
         summary => 'Single, horizontal only',
         chars => [
             ['─','─','─','─'], # 0
             [' ',' ',' '],     # 1
             ['─','─','─','─'], # 2
             [' ',' ',' '],     # 3
             ['─','─','─','─'], # 4
             ['─','─','─','─'], # 5
         ],
         utf8 => 1,
     },
 
 
     # single, vertical only
 
     singlev_ascii => {
         summary => 'Single border, only vertical',
         chars => [
             ['|',' ','|','|'], # 0
             ['|','|','|'],     # 1
             ['|',' ','|','|'], # 2
             ['|','|','|'],     # 3
             ['|','-','|','|'], # 4
             ['|',' ','|','|'], # 5
         ],
     },
 
     singlev_boxchar => {
         summary => 'Single, vertical only',
         chars => [
             ['x',' ','x','x'], # 0
             ['x','x','x'],     # 1
             ['x',' ','x','x'], # 2
             ['x','x','x'],     # 3
             ['x','q','x','x'], # 4
             ['x',' ','x','x'], # 5
         ],
         box_chars => 1,
     },
 
     singlev_utf8 => {
         summary => 'Single, vertical only',
         chars => [
             ['│',' ','│','│'], # 0
             ['│','│','│'],     # 1
             ['│',' ','│','│'], # 2
             ['│','│','│'],     # 3
             ['│','─','│','│'], # 4
             ['│',' ','│','│'], # 5
         ],
         utf8 => 1,
     },
 
 
     # single, inner only
 
     singlei_ascii => {
         summary => 'Single, inner only (like in psql command-line client)',
         chars => [
             ['','','',''],     # 0
             [' ','|',' '],     # 1
             [' ','-','+',' '], # 2
             [' ','|',' '],     # 3
             [' ','-','+',' '], # 4
             ['','','',''],     # 5
         ],
     },
 
     singlei_boxchar => {
         summary => 'Single, inner only (like in psql command-line client)',
         chars => [
             ['','','',''],     # 0
             [' ','x',' '],     # 1
             [' ','q','n',' '], # 2
             [' ','x',' '],     # 3
             [' ','q','n',' '], # 4
             ['','','',''],     # 5
         ],
         box_chars => 1,
     },
 
     singlei_utf8 => {
         summary => 'Single, inner only (like in psql command-line client)',
         chars => [
             ['','','',''],     # 0
             [' ','│',' '],     # 1
             [' ','─','┼',' '], # 2
             [' ','│',' '],     # 3
             [' ','─','┼',' '], # 4
             ['','','',''],     # 5
         ],
         utf8 => 1,
     },
 
 
     # single, outer only
 
     singleo_ascii => {
         summary => 'Single, outer only',
         chars => [
             ['.','-','-','.'], # 0
             ['|',' ','|'],     # 1
             ['|',' ',' ','|'], # 2
             ['|',' ','|'],     # 3
             ['+','-','-','+'], # 4
             ['`','-','-',"'"], # 5
         ],
     },
 
     singleo_boxchar => {
         summary => 'Single, outer only',
         chars => [
             ['l','q','q','k'], # 0
             ['x',' ','x'],     # 1
             ['x',' ',' ','x'], # 2
             ['x',' ','x'],     # 3
             ['t','q','q','u'], # 4
             ['m','q','q','j'], # 5
         ],
         box_chars => 1,
     },
 
     singleo_utf8 => {
         summary => 'Single, outer only',
         chars => [
             ['┌','─','─','┐'], # 0
             ['│',' ','│'],     # 1
             ['│',' ',' ','│'], # 2
             ['│',' ','│'],     # 3
             ['├','─','─','┤'], # 4
             ['└','─','─','┘'], # 5
         ],
         utf8 => 1,
     },
 
 
     # curved single
 
     csingle => {
         summary => 'Curved single',
         chars => [
             ['╭','─','┬','╮'], # 0
             ['│','│','│'],     # 1
             ['├','─','┼','┤'], # 2
             ['│','│','│'],     # 3
             ['├','─','┼','┤'], # 4
             ['╰','─','┴','╯'], # 5
         ],
         utf8 => 1,
     },
 
 
     # bold single
 
     bold => {
         summary => 'Bold',
         chars => [
             ['┏','━','┳','┓'], # 0
             ['┃','┃','┃'],     # 1
             ['┣','━','╋','┫'], # 2
             ['┃','┃','┃'],     # 3
             ['┣','━','╋','┫'], # 4
             ['┗','━','┻','┛'], # 5
         ],
         utf8 => 1,
     },
 
 
     #boldv => {
     #    summary => 'Vertically-bold',
     #},
 
 
     #boldh => {
     #    summary => 'Horizontally-bold',
     #},
 
 
     # double
 
     double => {
         summary => 'Double',
         chars => [
             ['╔','═','╦','╗'], # 0
             ['║','║','║'],     # 1
             ['╠','═','╬','╣'], # 2
             ['║','║','║'],     # 3
             ['╠','═','╬','╣'], # 4
             ['╚','═','╩','╝'], # 5
         ],
         utf8 => 1,
     },
 
 
     # brick
 
     brick => {
         summary => 'Single, bold on bottom right to give illusion of depth',
         chars => [
             ['┌','─','┬','┒'], # 0
             ['│','│','┃'],     # 1
             ['├','─','┼','┨'], # 2
             ['│','│','┃'],     # 3
             ['├','─','┼','┨'], # 4
             ['┕','━','┷','┛'], # 5
         ],
         utf8 => 1,
     },
 
     bricko => {
         summary => 'Single, outer only, '.
             'bold on bottom right to give illusion of depth',
         chars => [
             ['┌','─','─','┒'], # 0
             ['│',' ','┃'],     # 1
             ['│',' ',' ','┃'], # 2
             ['│',' ','┃'],     # 3
             ['├','─','─','┨'], # 4
             ['┕','━','━','┛'], # 5
         ],
         utf8 => 1,
     },
 
 );
 
 1;
 # ABSTRACT: Default border styles
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Text::ANSITable::BorderStyle::Default - Default border styles
 
 =head1 VERSION
 
 This document describes version 0.43 of Text::ANSITable::BorderStyle::Default (from Perl distribution Text-ANSITable), released on 2015-10-21.
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Text-ANSITable>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Text-ANSITable>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Text-ANSITable>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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 BORDER STYLES
 
 Below are the border styles included in this package:
 
 =head2 Default::bold
 
 Bold (utf8: yes, box_chars: no).
 
  ┏━━━━━━━━━┳━━━━━━━━━┓
  ┃ column1 ┃ column2 ┃
  ┣━━━━━━━━━╋━━━━━━━━━┫
  ┃ row1.1  ┃ row1.2  ┃
  ┃ row2.1  ┃ row3.2  ┃
  ┣━━━━━━━━━╋━━━━━━━━━┫
  ┃ row3.1  ┃ row3.2  ┃
  ┗━━━━━━━━━┻━━━━━━━━━┛
 
 
 =head2 Default::brick
 
 Single, bold on bottom right to give illusion of depth (utf8: yes, box_chars: no).
 
  ┌─────────┬─────────┒
  │ column1 │ column2 ┃
  ├─────────┼─────────┨
  │ row1.1  │ row1.2  ┃
  │ row2.1  │ row3.2  ┃
  ├─────────┼─────────┨
  │ row3.1  │ row3.2  ┃
  ┕━━━━━━━━━┷━━━━━━━━━┛
 
 
 =head2 Default::bricko
 
 Single, outer only, bold on bottom right to give illusion of depth (utf8: yes, box_chars: no).
 
  ┌───────────────────┒
  │ column1   column2 ┃
  │                   ┃
  │ row1.1    row1.2  ┃
  │ row2.1    row3.2  ┃
  ├───────────────────┨
  │ row3.1    row3.2  ┃
  ┕━━━━━━━━━━━━━━━━━━━┛
 
 
 =head2 Default::csingle
 
 Curved single (utf8: yes, box_chars: no).
 
  ╭─────────┬─────────╮
  │ column1 │ column2 │
  ├─────────┼─────────┤
  │ row1.1  │ row1.2  │
  │ row2.1  │ row3.2  │
  ├─────────┼─────────┤
  │ row3.1  │ row3.2  │
  ╰─────────┴─────────╯
 
 
 =head2 Default::double
 
 Double (utf8: yes, box_chars: no).
 
  ╔═════════╦═════════╗
  ║ column1 ║ column2 ║
  ╠═════════╬═════════╣
  ║ row1.1  ║ row1.2  ║
  ║ row2.1  ║ row3.2  ║
  ╠═════════╬═════════╣
  ║ row3.1  ║ row3.2  ║
  ╚═════════╩═════════╝
 
 
 =head2 Default::none_ascii
 
 No border (utf8: no, box_chars: no).
 
   column1  column2 
   row1.1   row1.2  
   row2.1   row3.2  
   ------------------- 
   row3.1   row3.2  
 
 
 =head2 Default::none_boxchar
 
 No border (utf8: no, box_chars: yes).
 
 =head2 Default::none_utf8
 
 No border (utf8: yes, box_chars: no).
 
   column1  column2 
   row1.1   row1.2  
   row2.1   row3.2  
  ───────────────────
   row3.1   row3.2  
 
 
 =head2 Default::single_ascii
 
 Single (utf8: no, box_chars: no).
 
  .---------+---------.
  | column1 | column2 |
  +---------+---------+
  | row1.1  | row1.2  |
  | row2.1  | row3.2  |
  +---------+---------+
  | row3.1  | row3.2  |
  `---------+---------'
 
 
 =head2 Default::single_boxchar
 
 Single (utf8: no, box_chars: yes).
 
 =head2 Default::single_utf8
 
 Single (utf8: yes, box_chars: no).
 
  ┌─────────┬─────────┐
  │ column1 │ column2 │
  ├─────────┼─────────┤
  │ row1.1  │ row1.2  │
  │ row2.1  │ row3.2  │
  ├─────────┼─────────┤
  │ row3.1  │ row3.2  │
  └─────────┴─────────┘
 
 
 =head2 Default::singleh_ascii
 
 Single, horizontal only (utf8: no, box_chars: no).
 
  ---------------------
    column1   column2  
  ---------------------
    row1.1    row1.2   
    row2.1    row3.2   
  ---------------------
    row3.1    row3.2   
  ---------------------
 
 
 =head2 Default::singleh_boxchar
 
 Single, horizontal only (utf8: no, box_chars: yes).
 
 =head2 Default::singleh_utf8
 
 Single, horizontal only (utf8: yes, box_chars: no).
 
  ─────────────────────
    column1   column2  
  ─────────────────────
    row1.1    row1.2   
    row2.1    row3.2   
  ─────────────────────
    row3.1    row3.2   
  ─────────────────────
 
 
 =head2 Default::singlei_ascii
 
 Single, inner only (like in psql command-line client) (utf8: no, box_chars: no).
 
    column1 | column2  
   ---------+--------- 
    row1.1  | row1.2   
    row2.1  | row3.2   
   ---------+--------- 
    row3.1  | row3.2   
 
 
 =head2 Default::singlei_boxchar
 
 Single, inner only (like in psql command-line client) (utf8: no, box_chars: yes).
 
 =head2 Default::singlei_utf8
 
 Single, inner only (like in psql command-line client) (utf8: yes, box_chars: no).
 
    column1 │ column2  
   ─────────┼───────── 
    row1.1  │ row1.2   
    row2.1  │ row3.2   
   ─────────┼───────── 
    row3.1  │ row3.2   
 
 
 =head2 Default::singleo_ascii
 
 Single, outer only (utf8: no, box_chars: no).
 
  .-------------------.
  | column1   column2 |
  |                   |
  | row1.1    row1.2  |
  | row2.1    row3.2  |
  +-------------------+
  | row3.1    row3.2  |
  `-------------------'
 
 
 =head2 Default::singleo_boxchar
 
 Single, outer only (utf8: no, box_chars: yes).
 
 =head2 Default::singleo_utf8
 
 Single, outer only (utf8: yes, box_chars: no).
 
  ┌───────────────────┐
  │ column1   column2 │
  │                   │
  │ row1.1    row1.2  │
  │ row2.1    row3.2  │
  ├───────────────────┤
  │ row3.1    row3.2  │
  └───────────────────┘
 
 
 =head2 Default::singlev_ascii
 
 Single border, only vertical (utf8: no, box_chars: no).
 
  |         |         |
  | column1 | column2 |
  |         |         |
  | row1.1  | row1.2  |
  | row2.1  | row3.2  |
  |---------|---------|
  | row3.1  | row3.2  |
  |         |         |
 
 
 =head2 Default::singlev_boxchar
 
 Single, vertical only (utf8: no, box_chars: yes).
 
 =head2 Default::singlev_utf8
 
 Single, vertical only (utf8: yes, box_chars: no).
 
  │         │         │
  │ column1 │ column2 │
  │         │         │
  │ row1.1  │ row1.2  │
  │ row2.1  │ row3.2  │
  │─────────│─────────│
  │ row3.1  │ row3.2  │
  │         │         │
 
 
 =head2 Default::space_ascii
 
 Space as border (utf8: no, box_chars: no).
 
                       
    column1   column2  
                       
    row1.1    row1.2   
    row2.1    row3.2   
   ------------------- 
    row3.1    row3.2   
                       
 
 
 =head2 Default::space_boxchar
 
 Space as border (utf8: no, box_chars: yes).
 
 =head2 Default::space_utf8
 
 Space as border (utf8: yes, box_chars: no).
 
                       
    column1   column2  
                       
    row1.1    row1.2   
    row2.1    row3.2   
   ─────────────────── 
    row3.1    row3.2   
                       
 
 
 =head2 Default::spacei_ascii
 
 Space, inner-only (utf8: no, box_chars: no).
 
   column1   column2 
   row1.1    row1.2  
   row2.1    row3.2  
  -------------------
   row3.1    row3.2  
 
 
 =head2 Default::spacei_boxchar
 
 Space, inner-only (utf8: no, box_chars: yes).
 
 =head2 Default::spacei_utf8
 
 Space, inner-only (utf8: yes, box_chars: no).
 
   column1   column2 
   row1.1    row1.2  
   row2.1    row3.2  
  ───────────────────
   row3.1    row3.2  
 
 =cut
### Text/ANSITable/ColorTheme/Default.pm ###
 package Text::ANSITable::ColorTheme::Default;
 
 our $DATE = '2015-10-21'; # DATE
 our $VERSION = '0.43'; # VERSION
 
 use 5.010;
 use strict;
 use warnings;
 
 use Color::RGB::Util qw(mix_2_rgb_colors);
 use Function::Fallback::CoreOrPP qw(clone);
 
 our %color_themes = (
 
     no_color => {
         v => 1.1,
         summary => 'Special theme that means no color',
         colors => {
         },
         no_color => 1,
     },
 
     #default_16 => {
     #    v => 1.1,
     #    summary => 'Default for 16-color terminal',
     #    colors => {
     #    },
     #},
 
     #default_256 => {
     default_gradation => {
         v => 1.1,
         summary => 'Default (for terminal with black background)',
         description => <<'_',
 
 Border color has gradation from top to bottom. Accept arguments C<border1> and
 C<border2> to set first (top) and second (bottom) foreground RGB colors. Colors
 will fade from the top color to bottom color. Also accept C<border1_bg> and
 C<border2_bg> to set background RGB colors.
 
 _
         colors => {
             border      => sub {
                 my ($self, %args) = @_;
 
                 my $pct = ($self->{_draw}{y}+1) / $self->{_draw}{table_height};
 
                 my $rgbf1 = $self->{color_theme_args}{border1} // $self->{color_theme}{data}{default_border1} // 'ffffff';
                 my $rgbf2 = $self->{color_theme_args}{border2} // $self->{color_theme}{data}{default_border2} // '444444';
                 my $rgbf  = mix_2_rgb_colors($rgbf1, $rgbf2, $pct);
 
                 my $rgbb1 = $self->{color_theme_args}{border1_bg};
                 my $rgbb2 = $self->{color_theme_args}{border2_bg};
                 my $rgbb;
                 if ($rgbb1 && $rgbb2) {
                     $rgbb = mix_2_rgb_colors($rgbb1, $rgbb2, $pct);
                 }
 
                 #say "D:$rgbf, $rgbb";
                 {fg=>$rgbf, bg=>$rgbb};
             },
 
             header      => '808080',
             header_bg   => undef,
             cell        => undef,
             cell_bg     => undef,
 
             num_data    => '66ffff',
             str_data    => undef,
             date_data   => 'aaaa00',
             bool_data   => sub {
                 my ($self, %args) = @_;
 
                 $args{orig_data} ? '00ff00' : 'ff0000';
             },
         },
     },
 
 );
 
 {
     my $ct = clone($color_themes{default_gradation});
     $ct->{summary} = 'Default (for terminal with white background)';
     $ct->{colors}{header_bg} = 'cccccc';
     $ct->{data}{default_border1} = '000000';
     $ct->{data}{default_border2} = 'cccccc';
     $ct->{colors}{num_data}  = '006666';
     $ct->{colors}{date_data} = '666600';
     $ct->{colors}{bool_data} = sub {
         my ($self, %args) = @_;
         $args{orig_data} ? '00cc00' : 'cc0000';
     };
     $color_themes{default_gradation_whitebg} = $ct;
 }
 
 
 {
     my $ct = clone($color_themes{default_gradation});
     $ct->{colors}{border} = '666666';
     delete $ct->{description};
     $color_themes{default_nogradation} = $ct;
 }
 
 {
     my $ct = clone($color_themes{default_gradation_whitebg});
     $ct->{colors}{border} = '666666';
     delete $ct->{description};
     $color_themes{default_nogradation_whitebg} = $ct;
 }
 
 1;
 # ABSTRACT: Default color themes
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Text::ANSITable::ColorTheme::Default - Default color themes
 
 =head1 VERSION
 
 This document describes version 0.43 of Text::ANSITable::ColorTheme::Default (from Perl distribution Text-ANSITable), released on 2015-10-21.
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Text-ANSITable>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Text-ANSITable>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Text-ANSITable>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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 COLOR THEMES
 
 Below are the color themes included in this package:
 
 =head2 Default::default_gradation
 
 Default (for terminal with black background).
 
 
 Border color has gradation from top to bottom. Accept arguments C<border1> and
 C<border2> to set first (top) and second (bottom) foreground RGB colors. Colors
 will fade from the top color to bottom color. Also accept C<border1_bg> and
 C<border2_bg> to set background RGB colors.
 
 
 
 =head2 Default::default_gradation_whitebg
 
 Default (for terminal with white background).
 
 
 Border color has gradation from top to bottom. Accept arguments C<border1> and
 C<border2> to set first (top) and second (bottom) foreground RGB colors. Colors
 will fade from the top color to bottom color. Also accept C<border1_bg> and
 C<border2_bg> to set background RGB colors.
 
 
 
 =head2 Default::default_nogradation
 
 Default (for terminal with black background).
 
 =head2 Default::default_nogradation_whitebg
 
 Default (for terminal with white background).
 
 =head2 Default::no_color
 
 Special theme that means no color.
 
 =cut
### Text/ANSITable/StyleSet/AltRow.pm ###
 package Text::ANSITable::StyleSet::AltRow;
 
 our $DATE = '2015-10-21'; # DATE
 our $VERSION = '0.43'; # VERSION
 
 use 5.010;
 use Moo;
 use namespace::clean;
 
 has odd_bgcolor  => (is => 'rw');
 has even_bgcolor => (is => 'rw');
 has odd_fgcolor  => (is => 'rw');
 has even_fgcolor => (is => 'rw');
 
 sub summary {
     "Set different foreground and/or background color for odd/even rows";
 }
 
 sub apply {
     my ($self, $table) = @_;
 
     $table->add_cond_row_style(
         sub {
             my ($t, %args) = @_;
             my %styles;
             # because we count from 0
             if ($_ % 2 == 0) {
                 $styles{bgcolor} = $self->odd_bgcolor
                     if defined $self->odd_bgcolor;
                 $styles{fgcolor}=$self->odd_fgcolor
                     if defined $self->odd_fgcolor;
             } else {
                 $styles{bgcolor} = $self->even_bgcolor
                     if defined $self->even_bgcolor;
                 $styles{fgcolor} = $self->even_fgcolor
                     if defined $self->even_fgcolor;
             }
             \%styles;
         },
     );
 }
 
 1;
 
 # ABSTRACT: Set different foreground and/or background color for odd/even rows";
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Text::ANSITable::StyleSet::AltRow - Set different foreground and/or background color for odd/even rows";
 
 =head1 VERSION
 
 This document describes version 0.43 of Text::ANSITable::StyleSet::AltRow (from Perl distribution Text-ANSITable), released on 2015-10-21.
 
 =for Pod::Coverage ^(summary|apply)$
 
 =head1 ATTRIBUTES
 
 =head2 odd_bgcolor
 
 =head2 odd_fgcolor
 
 =head2 even_bgcolor
 
 =head2 even_fgcolor
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Text-ANSITable>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Text-ANSITable>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Text-ANSITable>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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
### Text/Table/Tiny.pm ###
 use strict;
 use warnings;
 package Text::Table::Tiny;
 use List::Util qw();
 
 # ABSTRACT: makes simple tables from two-dimensional arrays, with limited templating options
 
 
 our $COLUMN_SEPARATOR = '|';
 our $ROW_SEPARATOR = '-';
 our $CORNER_MARKER = '+';
 our $HEADER_ROW_SEPARATOR = '=';
 our $HEADER_CORNER_MARKER = 'O';
 
 sub table {
 
     my %params = @_;
     my $rows = $params{rows} or die "Must provide rows!";
 
     # foreach col, get the biggest width
     my $widths = _maxwidths($rows);
     my $max_index = _max_array_index($rows);
 
     # use that to get the field format and separators
     my $format = _get_format($widths);
     my $row_sep = _get_row_separator($widths);
     my $head_row_sep = _get_header_row_separator($widths);
 
     # here we go...
     my @table;
     push @table, $row_sep;
 
     # if the first row's a header:
     my $data_begins = 0;
     if ( $params{header_row} ) {
         my $header_row = $rows->[0];
 	$data_begins++;
         push @table, sprintf(
 	    $format, 
 	    map { defined($header_row->[$_]) ? $header_row->[$_] : '' } (0..$max_index)
 	);
         push @table, $params{separate_rows} ? $head_row_sep : $row_sep;
     }
 
     # then the data
     foreach my $row ( @{ $rows }[$data_begins..$#$rows] ) {
         push @table, sprintf(
 	    $format, 
 	    map { defined($row->[$_]) ? $row->[$_] : '' } (0..$max_index)
 	);
         push @table, $row_sep if $params{separate_rows};
     }
 
     # this will have already done the bottom if called explicitly
     push @table, $row_sep unless $params{separate_rows};
     return join("\n",grep {$_} @table);
 }
 
 sub _get_cols_and_rows ($) {
     my $rows = shift;
     return ( List::Util::max( map { scalar @$_ } @$rows), scalar @$rows);
 }
 
 sub _maxwidths {
     my $rows = shift;
     # what's the longest array in this list of arrays?
     my $max_index = _max_array_index($rows);
     my $widths = [];
     for my $i (0..$max_index) {
         # go through the $i-th element of each array, find the longest
         my $max = List::Util::max(map {defined $$_[$i] ? length($$_[$i]) : 0} @$rows);
         push @$widths, $max;
     }
     return $widths;
 }
 
 # return highest top-index from all rows in case they're different lengths
 sub _max_array_index {
     my $rows = shift;
     return List::Util::max( map { $#$_ } @$rows );
 }
 
 sub _get_format {
     my $widths = shift;
     return "$COLUMN_SEPARATOR ".join(" $COLUMN_SEPARATOR ",map { "%-${_}s" } @$widths)." $COLUMN_SEPARATOR";
 }
 
 sub _get_row_separator {
     my $widths = shift;
     return "$CORNER_MARKER$ROW_SEPARATOR".join("$ROW_SEPARATOR$CORNER_MARKER$ROW_SEPARATOR",map { $ROW_SEPARATOR x $_ } @$widths)."$ROW_SEPARATOR$CORNER_MARKER";
 }
 
 sub _get_header_row_separator {
     my $widths = shift;
     return "$HEADER_CORNER_MARKER$HEADER_ROW_SEPARATOR".join("$HEADER_ROW_SEPARATOR$HEADER_CORNER_MARKER$HEADER_ROW_SEPARATOR",map { $HEADER_ROW_SEPARATOR x $_ } @$widths)."$HEADER_ROW_SEPARATOR$HEADER_CORNER_MARKER";
 }
 
 1;
 
 __END__
 =pod
 
 =head1 NAME
 
 Text::Table::Tiny - makes simple tables from two-dimensional arrays, with limited templating options
 
 =head1 VERSION
 
 version 0.03
 
 =head1 OPTIONS
 
 =over 4
 
 =item *
 
 header_row
 
 true/false, designate first row in $rows as a header row and separate with a line
 
 =item *
 
 separate_rows
 
 true/false put a separator line between rows and use a thicker line for header separator
 
 =back
 
 =head1 SYNOPSIS
 
     use Text::Table::Tiny;
     my $rows = [
         # header row
         ['Name', 'Rank', 'Serial'],
         # rows
         ['alice', 'pvt', '123456'],
         ['bob',   'cpl', '98765321'],
         ['carol', 'brig gen', '8745'],
     ];
     # separate rows puts lines between rows, header_row says that the first row is headers
     print Text::Table::Tiny::table(rows => $rows, separate_rows => 1, header_row => 1);
 
   Example in the synopsis: Text::Table::Tiny::table(rows => $rows);
 
     +-------+----------+----------+
     | Name  | Rank     | Serial   |
     | alice | pvt      | 123456   |
     | bob   | cpl      | 98765321 |
     | carol | brig gen | 8745     |
     +-------+----------+----------+
 
   with header_row: Text::Table::Tiny::table(rows => $rows, header_row => 1);
 
     +-------+----------+----------+
     | Name  | Rank     | Serial   |
     +-------+----------+----------+
     | alice | pvt      | 123456   |
     | bob   | cpl      | 98765321 |
     | carol | brig gen | 8745     |
     +-------+----------+----------+
 
   with header_row and separate_rows: Text::Table::Tiny::table(rows => $rows, header_row => 1, separate_rows => 1);
 
     +-------+----------+----------+
     | Name  | Rank     | Serial   |
     O=======O==========O==========O
     | alice | pvt      | 123456   |
     +-------+----------+----------+
     | bob   | cpl      | 98765321 |
     +-------+----------+----------+
     | carol | brig gen | 8745     |
     +-------+----------+----------+
 
 =head1 FORMAT VARIABLES
 
 =over 4
 
 =item *
 
 $Text::Table::Tiny::COLUMN_SEPARATOR = '|';
 
 =item *
 
 $Text::Table::Tiny::ROW_SEPARATOR = '-';
 
 =item *
 
 $Text::Table::Tiny::CORNER_MARKER = '+';
 
 =item *
 
 $Text::Table::Tiny::HEADER_ROW_SEPARATOR = '=';
 
 =item *
 
 $Text::Table::Tiny::HEADER_CORNER_MARKER = 'O';
 
 =back
 
 =head1 AUTHOR
 
 Creighton Higgins <chiggins@chiggins.com>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2012 by Creighton Higgins.
 
 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
 
### Text/sprintfn.pm ###
 package Text::sprintfn;
 
 use 5.010001;
 use strict;
 use warnings;
 
 require Exporter;
 our @ISA       = qw(Exporter);
 our @EXPORT    = qw(sprintfn printfn);
 
 our $VERSION = '0.08'; # VERSION
 
 our $distance  = 10;
 
 my  $re1   = qr/[^)]+/s;
 my  $re2   = qr{(?<fmt>
                     %
                        (?<pi> \d+\$ | \((?<npi>$re1)\)\$?)?
                        (?<flags> [ +0#-]+)?
                        (?<vflag> \*?[v])?
                        (?<width> -?\d+ |
                            \*\d+\$? |
                            \((?<nwidth>$re1)\))?
                        (?<dot>\.?)
                        (?<prec>
                            (?: \d+ | \* |
                            \((?<nprec>$re1)\) ) ) ?
                        (?<conv> [%csduoxefgXEGbBpniDUOF])
                    )}x;
 our $regex = qr{($re2|%|[^%]+)}s;
 
 # faster version, without using named capture
 if (1) {
     $regex = qr{( #all=1
                     ( #fmt=2
                         %
                         (#pi=3
                             \d+\$ | \(
                             (#npi=4
                                 [^)]+)\)\$?)?
                         (#flags=5
                             [ +0#-]+)?
                         (#vflag=6
                             \*?[v])?
                         (#width=7
                             -?\d+ |
                             \*\d+\$? |
                             \((#nwidth=8
                                 [^)]+)\))?
                         (#dot=9
                             \.?)
                         (#prec=10
                             (?: \d+ | \* |
                                 \((#nprec=11
                                     [^)]+)\) ) ) ?
                         (#conv=12
                             [%csduoxefgXEGbBpniDUOF])
                     ) | % | [^%]+
                 )}xs;
 }
 
 sub sprintfn {
     my ($format, @args) = @_;
 
     my $hash;
     if (ref($args[0]) eq 'HASH') {
         $hash = shift(@args);
     }
     return sprintf($format, @args) if !$hash;
 
     my %indexes; # key = $hash key, value = index for @args
     push @args, (undef) x $distance;
 
     $format =~ s{$regex}{
         my ($all, $fmt, $pi, $npi, $flags,
             $vflag, $width, $nwidth, $dot, $prec,
             $nprec, $conv) =
             ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12);
 
         my $res;
         if ($fmt) {
 
             if (defined $npi) {
                 my $i = $indexes{$npi};
                 if (!$i) {
                     $i = @args + 1;
                     push @args, $hash->{$npi};
                     $indexes{$npi} = $i;
                 }
                 $pi = "${i}\$";
             }
 
             if (defined $nwidth) {
                 $width = $hash->{$nwidth};
             }
 
             if (defined $nprec) {
                 $prec = $hash->{$nprec};
             }
 
             $res = join("",
                 grep {defined} (
                     "%",
                     $pi, $flags, $vflag,
                     $width, $dot, $prec, $conv)
                 );
         } else {
             my $i = @args + 1;
             push @args, $all;
             $res = "\%${i}\$s";
         }
         $res;
     }xego;
 
     # DEBUG
     #use Data::Dump; dd [$format, @args];
 
     sprintf $format, @args;
 }
 
 sub printfn {
     print sprintfn @_;
 }
 
 1;
 # ABSTRACT: Drop-in replacement for sprintf(), with named parameter support
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Text::sprintfn - Drop-in replacement for sprintf(), with named parameter support
 
 =head1 VERSION
 
 This document describes version 0.08 of Text::sprintfn (from Perl distribution Text-sprintfn), released on 2015-09-15.
 
 =head1 SYNOPSIS
 
  use Text::sprintfn; # by default exports sprintfn() and printfn()
 
  # with no hash, behaves just like printf
  printfn '<%04d>', 1, 2; # <0001>
 
  # named parameter
  printfn '<%(v1)-4d>', {v1=>-2}; # <-2  >
 
  # mixed named and positional
  printfn '<%d> <%(v1)d> <%d>', {v1=>1}, 2, 3; # <2> <1> <3>
 
  # named width
  printfn "<%(v1)(v2).1f>", {v1=>3, v2=>4}; # <   3>
 
  # named precision
  printfn "<%(v1)(v2).(v2)f>", {v1=>3, v2=>4}; # <3.0000>
 
 =head1 DESCRIPTION
 
 This module provides sprintfn() and printfn(), which are like sprintf() and
 printf(), with the exception that they support named parameters from a hash.
 
 =head1 FUNCTIONS
 
 =head2 sprintfn $fmt, \%hash, ...
 
 If first argument after format is not a hash, sprintfn() will behave exactly
 like sprintf().
 
 If hash is given, sprintfn() will look for named parameters in argument and
 supply the values from the hash. Named parameters are surrounded with
 parentheses, i.e. "(NAME)". They can occur in format parameter index:
 
  %2$d        # sprintf version, take argument at index 2
  %(two)d     # $ is optional
  %(two)$d    # same
 
 or in width:
 
  %-10d       # sprintf version, use (minimum) width of 10
  %-(width)d  # like sprintf, but use width from hash key 'width'
  %(var)-(width)d  # format hash key 'var' with width from hash key 'width'
 
 or in precision:
 
  %6.2f       # sprintf version, use precision of 2 decimals
  %6.(prec)f  # like sprintf, but use precision from hash key 'prec'
  %(width).(prec)f
  %(var)(width).(prec)f
 
 The existence of formats using hash keys will not affect indexes of the rest of
 the argument, example:
 
  sprintfn "<%(v1)s> <%2$d> <%d>", {v1=>10}, 0, 1, 2; # "<10> <2> <0>"
 
 Like sprintf(), if format is unknown/erroneous, it will be printed as-is.
 
 There is currently no way to escape ")" in named parameter, e.g.:
 
  %(var containing ))s
 
 =head2 printfn $fmt, ...
 
 Equivalent to: print sprintfn($fmt, ...).
 
 =head1 RATIONALE
 
 There exist other CPAN modules for string formatting with named parameter
 support. Two of such modules are L<String::Formatter> and
 L<Text::Sprintf::Named>. This module is far simpler to use and retains all of
 the features of Perl's sprintf() (which we like, or perhaps hate, but
 nevertheless are familiar with).
 
 String::Formatter requires you to create a new formatter function first.
 Text::Sprintf::Named also accordingly requires you to instantiate an object
 first. There is currently no way to mix named and positional parameters. And you
 don't get the full features of sprintf().
 
 =head1 HOW IT WORKS
 
 Text::sprintfn works by converting the format string into sprintf format, i.e.
 replacing the named parameters like C<%(foo)s> to something like C<%11$s>.
 
 =head1 DOWNSIDES
 
 Currently the main downside is speed. C<sprintfn()> is about 2-3 orders of
 magnitude slower than C<sprintf()>. A sample benchmark:
 
                                                 Rate sprintfn("%(a)s%(b)d%(c)f",{..}) 1k sprintfn("%(a)s",{a=>1}) 1k sprintfn("%s",1) 1k sprintf ("%s%d%f",1,2,3) 1k sprintf ("%s",1) 1k
  sprintfn("%(a)s%(b)d%(c)f",{..}) 1k 45.354+-0.084/s                                  --                      -58.7%              -97.3%                      -99.9%              -99.9%
  sprintfn("%(a)s",{a=>1}) 1k          109.82+-0.14/s                       142.13+-0.54%                          --              -93.4%                      -99.7%              -99.7%
  sprintfn("%s",1) 1k                  1672.62+-0.6/s                          3587.9+-7%                  1423.1+-2%                  --                      -96.1%              -96.2%
  sprintf ("%s%d%f",1,2,3) 1k             42658+-12/s                         93950+-180%                  38744+-50%             2450.4%                          --               -2.2%
  sprintf ("%s",1) 1k                     43596+-48/s                         96020+-210%                  39599+-66%          2506.5+-3%                  2.2+-0.12%                  --
 
 =head1 TIPS AND TRICKS
 
 =head2 Common mistake 1
 
 Writing
 
  %(var)
 
 instead of
 
  %(var)s
 
 =head2 Common mistake 2 (a bit more newbish)
 
 Writing
 
  sprintfn $format, %hash, ...;
 
 instead of
 
  sprintfn $format, \%hash, ...;
 
 =head2 Alternative hashes
 
 You have several hashes (%h1, %h2, %h3) which should be consulted for values.
 You can either merge the hash first:
 
  %h = (%h1, %h2, %h3); # or use some hash merging module
  printfn $format, \%h, ...;
 
 or create a tied hash which can consult hashes for you:
 
  tie %h, 'Your::Module', \%h1, \%h2, \%h3;
  printfn $format, \%h, ...;
 
 =head1 SEE ALSO
 
 sprintf() section on L<perlfunc>
 
 L<String::Formatter>
 
 L<Text::Sprintf::Named>
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Text-sprintfn>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/perlancar/perl-Text-sprintfn>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Text-sprintfn>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 perlancar <perlancar@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2015 by perlancar@cpan.org.
 
 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
### Tie/Cache.pm ###
 #!/usr/local/bin/perl -w
 
 package Tie::Cache;
 use strict;
 use vars qw(
  $VERSION $Debug $STRUCT_SIZE $REF_SIZE
  $BEFORE $AFTER $KEY $VALUE $BYTES $DIRTY
 );
 
 $VERSION = .21;
 $Debug = 0; # set to 1 for summary, 2 for debug output
 $STRUCT_SIZE = 240; # per cached elem bytes overhead, approximate
 $REF_SIZE    = 16;
 
 # NODE ARRAY STRUCT
 $KEY    = 0;
 $VALUE  = 1;
 $BYTES  = 2;
 $BEFORE = 3;
 $AFTER  = 4;
 $DIRTY  = 5;
 
 =pod
 
 =head1 NAME
 
 Tie::Cache - LRU Cache in Memory
 
 =head1 SYNOPSIS
 
  use Tie::Cache;
  tie %cache, 'Tie::Cache', 100, { Debug => 1 };   
  tie %cache2, 'Tie::Cache', { MaxCount => 100, MaxBytes => 50000 };
  tie %cache3, 'Tie::Cache', 100, { Debug => 1 , WriteSync => 0};   
 
  # Options ##################################################################
  #
  # Debug =>	 0 - DEFAULT, no debugging output
  #		 1 - prints cache statistics upon destroying
  #		 2 - prints detailed debugging info
  #
  # MaxCount =>	 Maximum entries in cache.
  #
  # MaxBytes =>   Maximum bytes taken in memory for cache based on approximate 
  #               size of total cache structure in memory
  #
  #               There is approximately 240 bytes used per key/value pair in the cache for 
  #               the cache data structures, so a cache of 5000 entries would take
  #               at approximately 1.2M plus the size of the data being cached.
  #
  # MaxSize  =>   Maximum size of each cache entry. Larger entries are not cached.
  #                   This helps prevent much of the cache being flushed when 
  #                   you set an exceptionally large entry.  Defaults to MaxBytes/10
  #
  # WriteSync =>  1 - DEFAULT, write() when data is dirtied for 
  #                   TRUE CACHE (see below)
  #               0 - write() dirty data as late as possible, when leaving 
  #                   cache, or when cache is being DESTROY'd
  #
  ############################################################################
 
  # cache supports normal tied hash functions
  $cache{1} = 2;       # STORE
  print "$cache{1}\n"; # FETCH
 
  # FIRSTKEY, NEXTKEY
  while(($k, $v) = each %cache) { print "$k: $v\n"; } 
  
  delete $cache{1};    # DELETE
  %cache = ();         # CLEAR
 
 =head1 DESCRIPTION
 
 This module implements a least recently used (LRU) cache in memory
 through a tie interface.  Any time data is stored in the tied hash,
 that key/value pair has an entry time associated with it, and 
 as the cache fills up, those members of the cache that are
 the oldest are removed to make room for new entries.
 
 So, the cache only "remembers" the last written entries, up to the 
 size of the cache.  This can be especially useful if you access 
 great amounts of data, but only access a minority of the data a 
 majority of the time. 
 
 The implementation is a hash, for quick lookups, 
 overlaying a doubly linked list for quick insertion and deletion.
 On a WinNT PII 300, writes to the hash were done at a rate 
 3100 per second, and reads from the hash at 6300 per second.   
 Work has been done to optimize refreshing cache entries that are 
 frequently read from, code like $cache{entry}, which moves the 
 entry to the end of the linked list internally.
 
 =cut
 
 # Documentation continues at the end of the module.
 
 sub TIEHASH {
     my($class, $max_count, $options) = @_;
 
     if(ref($max_count)) {
 	$options = $max_count;
 	$max_count = $options->{MaxCount};
     }
 	
     unless($max_count || $options->{MaxBytes}) {
 	die('you must specify cache size with either MaxBytes or MaxCount');
     }
 
     my $sync = exists($options->{WriteSync}) ? $options->{WriteSync} : 1;
 
     my $self = bless 
       { 
        # how many items to cache
        max_count=> $max_count, 
        
        # max bytes to cache
        max_bytes => $options->{MaxBytes},
        
        # max size (in bytes) of an individual cache entry
        max_size => $options->{MaxSize} || ($options->{MaxBytes} ? (int($options->{MaxBytes}/10) + 1) : 0),
        
        # class track, so know if overridden subs should be used
        'class'    => $class,
        'subclass' => $class ne 'Tie::Cache' ? 1 : 0,
        
        # current sizes
        count=>0,
        bytes=>0,
        
        # inner structures
        head=>0, 
        tail=>0, 
        nodes=>{},
        'keys'=>[],
        
        # statistics
        hit => 0,
        miss => 0,
        
        # config
        sync => $sync,
        dbg => $options->{Debug} || $Debug
        
        
       }, $class;
     
     if (($self->{max_bytes} && ! $self->{max_size})) {
 	die("MaxSize must be defined when MaxBytes is");
     }
 
     if($self->{max_bytes} and $self->{max_bytes} < 1000) {
 	die("cannot set MaxBytes to under 1000, each raw entry takes $STRUCT_SIZE bytes alone");
     }
 
     if($self->{max_size} && $self->{max_size} < 3) {
 	die("cannot set MaxSize to under 3 bytes, assuming error in config");
     }
 
     $self;
 }
 
 # override to write data leaving cache
 sub write { undef; }
 # commented this section out for speed
 #    my($self, $key, $value) = @_;
 #    1;
 #}
 
 # override to get data if not in cache, should return $value
 # associated with $key
 sub read { undef; }
 # commented this section out for speed
 #    my($self, $key) = @_;
 #    undef;
 #}
 
 sub FETCH {
     my($self, $key) = @_;
 
     my $node = $self->{nodes}{$key};
     if($node) {
 	# refresh node's entry
 	$self->{hit}++; # if $self->{dbg};
 
 	# we used to call delete then insert, but we streamlined code
 	if(my $after = $node->[$AFTER]) {
 	    $self->{dbg} > 1 and $self->print("update() node $node to tail of list");
 	    # reconnect the nodes
 	    my $before = $after->[$BEFORE] = $node->[$BEFORE];
 	    if($before) {
 		$before->[$AFTER] = $after;
 	    } else {
 		$self->{head} = $after;
 	    }
 
 	    # place at the end
 	    $self->{tail}[$AFTER] = $node;
 	    $node->[$BEFORE] = $self->{tail};
 	    $node->[$AFTER] = undef;
 	    $self->{tail} = $node; # always true after this
 	} else {
 	    # if there is nothing after node, then we are at the end already
 	    # so don't do anything to move the nodes around
 	    die("this node is the tail, so something's wrong") 
 		unless($self->{tail} eq $node);
 	}
 
 	$self->print("FETCH [$key, $node->[$VALUE]]") if ($self->{dbg} > 1);
 	$node->[$VALUE];
     } else {
 	# we have a cache miss here
 	$self->{miss}++; # if $self->{dbg};
 
 	# its fine to always insert a node, even when we have an undef,
 	# because even if we aren't a sub-class, we should assume use
 	# that would then set the entry.  This model works well with
 	# sub-classing and reads() that might want to return undef as
 	# a valid value.
 	my $value;
 	if ($self->{subclass}) {
 	    $self->print("read() for key $key") if $self->{dbg} > 1;
 	    $value = $self->read($key);
 	}
 
 	if(defined $value) {
 	    my $length;
 	    if($self->{max_size}) {
 		# check max size of entry, that it not exceed max size
 		$length = &_get_data_length(\$key, \$value);
 		if($length > $self->{max_size}) {
 		    $self->print("direct read() [$key, $value]") if ($self->{dbg} > 1);
 		    return $value;
 		}
 	    }
 	    # if we get here, we should insert the new node
 	    $node = &create_node($self, \$key, \$value, $length);
 	    &insert($self, $node);
 	    $value;
 	} else {
 	    undef;
 	}
     }
 }
 
 sub STORE {
     my($self, $key, $value) = @_;
     my $node;
 
     $self->print("STORE [$key,$value]") if ($self->{dbg} > 1);
 
     # do not cache undefined values
     defined($value) || return(undef);
 
     # check max size of entry, that it not exceed max size
     my $length;
     if($self->{max_size}) {
 	$length = &_get_data_length(\$key, \$value);
 	if($length > $self->{max_size}) {
 	    if ($self->{subclass}) {
 		$self->print("direct write() [$key, $value]") if ($self->{dbg} > 1);
 		$self->write($key, $value);
 	    }
 	    return $value;
 	}
     }
 
     # do we have node already ?
     if($self->{nodes}{$key}) {
 	$node = &delete($self, $key);
 #	$node = &delete($self, $key);
 #	$node->[$VALUE] = $value;
 #	$node->[$BYTES] = $length || &_get_data_length(\$key, \$value);
     }
 
     # insert new node  
     $node = &create_node($self, \$key, \$value, $length);
 #    $node ||= &create_node($self, \$key, \$value, $length);
     &insert($self, $node);
 
     # if the data is sync'd call write now, otherwise defer the data
     # writing, but mark it dirty so it can be cleanup up at the end
     if ($self->{subclass}) {
 	if($self->{sync}) {
 	    $self->print("sync write() [$key, $value]") if $self->{dbg} > 1;
 	    $self->write($key, $value);
 	} else {
 	    $node->[$DIRTY] = 1;
 	}
     }
 
     $value;
 }
 
 sub DELETE {
     my($self, $key) = @_;
 
     $self->print("DELETE $key") if ($self->{dbg} > 1);
     my $node = $self->delete($key);
     $node ? $node->[$VALUE] : undef;
 }
 
 sub CLEAR {
     my($self) = @_;
 
     $self->print("CLEAR CACHE") if ($self->{dbg} > 1);
 
     if($self->{subclass}) {
 	my $flushed = $self->flush();
 	$self->print("FLUSH COUNT $flushed") if ($self->{dbg} > 1);
     }
 
     my $node;
     while($node = $self->{head}) {
 	$self->delete($self->{head}[$KEY]);
     }
 
     1;
 }
 
 sub EXISTS {
     my($self, $key) = @_;
     exists $self->{nodes}{$key};
 }
     
 # firstkey / nextkey emulate keys() and each() behavior by
 # taking a snapshot of all the nodes at firstkey, and 
 # iterating through the keys with nextkey
 #
 # this method therefore will only supports one each() / keys()
 # happening during any given time.
 #
 sub FIRSTKEY {
     my($self) = @_;
 
     $self->{'keys'} = [];
     my $node = $self->{head};
     while($node) {
 	push(@{$self->{'keys'}}, $node->[$KEY]);
 	$node = $node->[$AFTER];
     }
 
     shift @{$self->{'keys'}};
 }
 
 sub NEXTKEY {
     my($self, $lastkey) = @_;
     shift @{$self->{'keys'}};
 }
 
 sub DESTROY {
     my($self) = @_;
 
     # if debugging, snapshot cache before clearing
     if($self->{dbg}) {
 	if($self->{hit} || $self->{miss}) {
 	    $self->{hit_ratio} = 
 		sprintf("%4.3f", $self->{hit} / ($self->{hit} + $self->{miss})); 
 	}
 	$self->print($self->pretty_self());
 	if($self->{dbg} > 1) {
 	    $self->print($self->pretty_chains());
 	}
     }
     
     $self->print("DESTROYING") if $self->{dbg} > 1;
     $self->CLEAR();
     
     1;
 }
 
 ####PERL##LRU##TIE##CACHE##PERL##LRU##TIE##CACHE##PERL##LRU##TIE##CACHE
 ## Helper Routines
 ####PERL##LRU##TIE##CACHE##PERL##LRU##TIE##CACHE##PERL##LRU##TIE##CACHE
 
 # we use scalar_refs for the data for speed
 sub create_node {
     my($self, $key, $value, $length) = @_;
     (defined($$key) && defined($$value)) 
       || die("need more localized data than $$key and $$value");
     
     # max_size always defined when max_bytes is
     if (($self->{max_size})) {
 	$length = defined $length ? $length : &_get_data_length($key, $value)
     } else {
 	$length = 0;
     }
     
     # ORDER SPECIFIC, see top for NODE ARRAY STRUCT
     my $node = [ $$key, $$value, $length ];
 }
 
 sub _get_data_length {
     my($key, $value) = @_;
     my $length = 0;
     my %refs;
 
     my @data = ($$key, $$value);
     while(my $elem = shift @data) {
 	next if $refs{$elem};
 	$refs{$elem} = 1;
 	if(ref $elem && ref($elem) =~ /^(SCALAR|HASH|ARRAY)$/) {
 	    my $type = $1;
 	    $length += $REF_SIZE; # guess, 16 bytes per ref, probably more
 	    if (($type eq 'SCALAR')) {
 		$length += length($$elem);
 	    } elsif (($type eq 'HASH')) {
 		while (my($k,$v) = each %$elem) {
 		    for my $kv($k,$v) {
 			if ((ref $kv)) {
 			    push(@data, $kv);
 			} else {
 			    $length += length($kv);
 			}
 		    }
 		}
 	    } elsif (($type eq 'ARRAY')) {
 		for my $val (@$elem){
 		    if ((ref $val)) {
 			push(@data, $val);
 		    } else {
 			$length += length($val);
 		    }
 		}
 	    }
 	} else {
 	    $length += length($elem);
 	}
     }
 
     $length;
 }
 
 sub insert {
     my($self, $new_node) = @_;
     
     $new_node->[$AFTER] = 0;
     $new_node->[$BEFORE] = $self->{tail};
     $self->print("insert() [$new_node->[$KEY], $new_node->[$VALUE]]") if ($self->{dbg} > 1);
     
     $self->{nodes}{$new_node->[$KEY]} = $new_node;
 
     # current sizes
     $self->{count}++;
     $self->{bytes} += $new_node->[$BYTES] + $STRUCT_SIZE;
 
     if($self->{tail}) {
 	$self->{tail}[$AFTER] = $new_node;
     } else {
 	$self->{head} = $new_node;
     }
     $self->{tail} = $new_node;
 
     ## if we are too big now, remove head
     while(($self->{max_count} && ($self->{count} > $self->{max_count})) ||
 	  ($self->{max_bytes} && ($self->{bytes} > $self->{max_bytes}))) 
     {
 	if($self->{dbg} > 1) {
 	    $self->print("current/max: ".
 			 "bytes ($self->{bytes}/$self->{max_bytes}) ".
 			 "count ($self->{count}/$self->{max_count}) "
 			 );
 	}
 	my $old_node = $self->delete($self->{head}[$KEY]);
 	if ($self->{subclass}) {
 	    if($old_node->[$DIRTY]) {
 		$self->print("dirty write() [$old_node->[$KEY], $old_node->[$VALUE]]") 
 		  if ($self->{dbg} > 1);
 		$self->write($old_node->[$KEY], $old_node->[$VALUE]);
 	    }
 	}
 #	if($self->{dbg} > 1) {
 #	    $self->print("after delete - bytes $self->{bytes}; count $self->{count}");
 #	}
     }
     
     1;
 }
 
 sub delete {
     my($self, $key) = @_;    
     my $node = $self->{nodes}{$key} || return;
 #    return unless $node;
 
     $self->print("delete() [$key, $node->[$VALUE]]") if ($self->{dbg} > 1);
 
     my $before = $node->[$BEFORE];
     my $after = $node->[$AFTER];
 
     #    my($before, $after) = $node->{before,after};
     if($before) {
 	($before->[$AFTER] = $after);
     } else {
 	$self->{head} = $after;
     }
 
     if($after) {
 	($after->[$BEFORE] = $before);
     } else {
 	$self->{tail} = $before;
     }
 
     delete $self->{nodes}{$key};
     $self->{bytes} -= ($node->[$BYTES] + $STRUCT_SIZE);
     $self->{count}--;
     
     $node;
 }
 
 sub flush {
     my $self = shift;
 
     $self->print("FLUSH CACHE") if ($self->{dbg} > 1);
 
     my $node = $self->{head};
     my $flush_count = 0;
     while($node) {
 	if($node->[$DIRTY]) {
 	    $self->print("flush dirty write() [$node->[$KEY], $node->[$VALUE]]") 
 	      if ($self->{dbg} > 1);
 	    $self->write($node->[$KEY], $node->[$VALUE]);
 	    $node->[$DIRTY] = 0;
 	    $flush_count++;
 	}
 	$node = $node->[$AFTER];
     }
 
     $flush_count;
 }
 
 sub print {
     my($self, $msg) = @_;
     print "$self: $msg\n";
 }
 
 sub pretty_self {
     my($self) = @_;
     
     my(@prints);
     for(sort keys %{$self}) { 
 	next unless defined $self->{$_};
 	push(@prints, "$_=>$self->{$_}"); 
     }
 
     "{ " . join(", ", @prints) . " }";
 }
 
 sub pretty_chains {
     my($self) = @_;
     my($str);
     my $k = $self->FIRSTKEY();
 
     $str .= "[head]->";
     my($curr_node) = $self->{head};
     while($curr_node) {
 	$str .= "[$curr_node->[$KEY],$curr_node->[$VALUE]]->";
 	$curr_node = $curr_node->[$AFTER];
     }
     $str .= "[tail]->";
 
     $curr_node = $self->{tail};
     while($curr_node) {
 	$str .= "[$curr_node->[$KEY],$curr_node->[$VALUE]]->";
 	$curr_node = $curr_node->[$BEFORE];
     }
     $str .= "[head]";
 
     $str;
 }
 
 1;
 
 __END__
 
 =head1 INSTALLATION
 
 Tie::Cache installs easily using the make or nmake commands as
 shown below.  Otherwise, just copy Cache.pm to $PERLLIB/site/Tie
 
 	> perl Makefile.PL
 	> make
         > make test 
 	> make install
 
         * use nmake for win32
         ** you can also just copy Cache.pm to $perllib/Tie
 
 =head1 BENCMARKS
 
 There is another simpler LRU cache implementation in CPAN,
 Tie::Cache::LRU, which has the same basic size limiting 
 functionality, and for this functionality, the exact same 
 interface.
 
 Through healthy competition, Michael G Schwern got 
 Tie::Cache::LRU mostly faster than Tie::Cache on reads & writes:
 
  Cache Size 5000       Tie::Cache 0.17  Tie::Cache::LRU 20110205.00
  10000 Writes             0.63 CPU sec          0.47 CPU sec
  40000 Reads              0.79 CPU sec          0.71 CPU sec
  10000 Deletes            0.23 CPU sec          0.26 CPU sec
 
 Unless you are using TRUE CACHE or MaxBytes functionality,
 using Tie::Cache::LRU could be an easy replacement for Tie::Cache.
 
 OTOH one nice thing about this module is its lack of external module dependencies!
 
 =head1 TRUE CACHE
 
 To use class as a true cache, which acts as the sole interface 
 for some data set, subclass the real cache off Tie::Cache, 
 with @ISA = qw( 'Tie::Cache' ) notation.  Then override
 the read() method for behavior when there is a cache miss,
 and the write() method for behavior when the cache's data 
 changes.
 
 When WriteSync is 1 or TRUE (DEFAULT), write() is called immediately
 when data in the cache is modified.  If set to 0, data that has 
 been modified in the cache gets written out when the entries are deleted or
 during the DESTROY phase of the cache object, usually at the end of
 a script.
 
 To have the dirty data write() periodically while WriteSync is set to 0,
 there is a flush() cache API call that will flush the dirty writes
 in this way.  Just call the flush() API like:
 
   my $write_flush_count = tied(%cache)->flush();
 
 The flush() API was added in the .17 release thanks to Rob Bloodgood.
 
 =head1 TRUE CACHE EXAMPLE
 
  use Tie::Cache;
 
  # personalize the Tie::Cache object, by inheriting from it
  package My::Cache;
  @ISA = qw(Tie::Cache);
 
  # override the read() and write() member functions
  # these tell the cache what to do with a cache miss or flush
  sub read { 
     my($self, $key) = @_; 
     print "cache miss for $key, read() data\n";
     rand() * $key; 
  }
  sub write { 
     my($self, $key, $value) = @_;
     print "flushing [$key, $value] from cache, write() data\n";
  }
 
  my $cache_size   = $ARGV[0] || 2;
  my $num_to_cache = $ARGV[1] || 4;   
  my $Debug = $ARGV[2] || 1;
 
  tie %cache, 'My::Cache', $cache_size, {Debug => $Debug};   
 
  # load the cache with new data, each through its contents,
  # and then reload in reverse order.
  for(1..$num_to_cache) { print "read data $_: $cache{$_}\n" }
  while(my($k, $v) = each %cache) { print "each data $k: $v\n"; }
  for(my $i=$num_to_cache; $i>0; $i--) { print "read data $i: $cache{$i}\n"; }
 
  # flush writes now, trivial use since will happen in DESTROY() anyway
  tied(%cache)->flush(); 
 
  # clear cache in 2 ways, write will flush out to disk
  %cache = ();
  undef %cache;
 
 =head1 NOTES
 
 Many thanks to all those who helped me make this module a reality, 
 including:
 
 	:) Tom Hukins who provided me insight and motivation for
 	   finishing this module.
 	:) Jamie McCarthy, for trying to make Tie::Cache be all
 	   that it can be.
 	:) Rob Fugina who knows how to "TRULY CACHE".
 	:) Rob Bloodgood, for the TRUE CACHE flush() API
 
 =head1 AUTHOR
 
 Please send any questions or comments to Joshua Chamas at chamas@alumni.stanford.org
 
 =head1 COPYRIGHT
 
 Copyright (c) 1999-2012 Joshua Chamas, Chamas Enterprises Inc.  
 Sponsored by development on NodeWorks http://nodeworks.com and Web Test.org http://web-test.org
 
 All rights reserved. This program is free software; you can redistribute it and/or modify it under the same 
 terms as Perl itself. 
 
 =cut
 
 
 
 
 
 
### Tie/IxHash.pm ###
 #
 # Tie/IxHash.pm
 #
 # Indexed hash implementation for Perl
 #
 # See below for documentation.
 #
 
 require 5.005;
 
 package Tie::IxHash;
 use strict;
 use integer;
 require Tie::Hash;
 use vars qw/@ISA $VERSION/;
 @ISA = qw(Tie::Hash);
 
 $VERSION = $VERSION = '1.23';
 
 #
 # standard tie functions
 #
 
 sub TIEHASH {
   my($c) = shift;
   my($s) = [];
   $s->[0] = {};   # hashkey index
   $s->[1] = [];   # array of keys
   $s->[2] = [];   # array of data
   $s->[3] = 0;    # iter count
 
   bless $s, $c;
 
   $s->Push(@_) if @_;
 
   return $s;
 }
 
 #sub DESTROY {}           # costly if there's nothing to do
 
 sub FETCH {
   my($s, $k) = (shift, shift);
   return exists( $s->[0]{$k} ) ? $s->[2][ $s->[0]{$k} ] : undef;
 }
 
 sub STORE {
   my($s, $k, $v) = (shift, shift, shift);
   
   if (exists $s->[0]{$k}) {
     my($i) = $s->[0]{$k};
     $s->[1][$i] = $k;
     $s->[2][$i] = $v;
     $s->[0]{$k} = $i;
   }
   else {
     push(@{$s->[1]}, $k);
     push(@{$s->[2]}, $v);
     $s->[0]{$k} = $#{$s->[1]};
   }
 }
 
 sub DELETE {
   my($s, $k) = (shift, shift);
 
   if (exists $s->[0]{$k}) {
     my($i) = $s->[0]{$k};
     for ($i+1..$#{$s->[1]}) {    # reset higher elt indexes
       $s->[0]{ $s->[1][$_] }--;    # timeconsuming, is there is better way?
     }
     if ( $i == $s->[3]-1 ) {
       $s->[3]--;
     }
     delete $s->[0]{$k};
     splice @{$s->[1]}, $i, 1;
     return (splice(@{$s->[2]}, $i, 1))[0];
   }
   return undef;
 }
 
 sub EXISTS {
   exists $_[0]->[0]{ $_[1] };
 }
 
 sub FIRSTKEY {
   $_[0][3] = 0;
   &NEXTKEY;
 }
 
 sub NEXTKEY {
   return $_[0][1][ $_[0][3]++ ] if ($_[0][3] <= $#{ $_[0][1] } );
   return undef;
 }
 
 
 
 #
 #
 # class functions that provide additional capabilities
 #
 #
 
 sub new { TIEHASH(@_) }
 
 sub Clear {
   my $s = shift;
   $s->[0] = {};   # hashkey index
   $s->[1] = [];   # array of keys
   $s->[2] = [];   # array of data
   $s->[3] = 0;    # iter count
   return;
 }
 
 #
 # add pairs to end of indexed hash
 # note that if a supplied key exists, it will not be reordered
 #
 sub Push {
   my($s) = shift;
   while (@_) {
     $s->STORE(shift, shift);
   }
   return scalar(@{$s->[1]});
 }
 
 sub Push2 {
   my($s) = shift;
   $s->Splice($#{$s->[1]}+1, 0, @_);
   return scalar(@{$s->[1]});
 }
 
 #
 # pop last k-v pair
 #
 sub Pop {
   my($s) = shift;
   my($k, $v, $i);
   $k = pop(@{$s->[1]});
   $v = pop(@{$s->[2]});
   if (defined $k) {
     delete $s->[0]{$k};
     return ($k, $v);
   }
   return undef;
 }
 
 sub Pop2 {
   return $_[0]->Splice(-1);
 }
 
 #
 # shift
 #
 sub Shift {
   my($s) = shift;
   my($k, $v, $i);
   $k = shift(@{$s->[1]});
   $v = shift(@{$s->[2]});
   if (defined $k) {
     delete $s->[0]{$k};
     for (keys %{$s->[0]}) {
       $s->[0]{$_}--;
     }
     return ($k, $v);
   }
   return undef;
 }
 
 sub Shift2 {
   return $_[0]->Splice(0, 1);
 }
 
 #
 # unshift
 # if a supplied key exists, it will not be reordered
 #
 sub Unshift {
   my($s) = shift;
   my($k, $v, @k, @v, $len, $i);
 
   while (@_) {
     ($k, $v) = (shift, shift);
     if (exists $s->[0]{$k}) {
       $i = $s->[0]{$k};
       $s->[1][$i] = $k;
       $s->[2][$i] = $v;
       $s->[0]{$k} = $i;
     }
     else {
       push(@k, $k);
       push(@v, $v);
       $len++;
     }
   }
   if (defined $len) {
     for (keys %{$s->[0]}) {
       $s->[0]{$_} += $len;
     }
     $i = 0;
     for (@k) {
       $s->[0]{$_} = $i++;
     }
     unshift(@{$s->[1]}, @k);
     return unshift(@{$s->[2]}, @v);
   }
   return scalar(@{$s->[1]});
 }
 
 sub Unshift2 {
   my($s) = shift;
   $s->Splice(0,0,@_);
   return scalar(@{$s->[1]});
 }
 
 #
 # splice 
 #
 # any existing hash key order is preserved. the value is replaced for
 # such keys, and the new keys are spliced in the regular fashion.
 #
 # supports -ve offsets but only +ve lengths
 #
 # always assumes a 0 start offset
 #
 sub Splice {
   my($s, $start, $len) = (shift, shift, shift);
   my($k, $v, @k, @v, @r, $i, $siz);
   my($end);                   # inclusive
 
   # XXX  inline this 
   ($start, $end, $len) = $s->_lrange($start, $len);
 
   if (defined $start) {
     if ($len > 0) {
       my(@k) = splice(@{$s->[1]}, $start, $len);
       my(@v) = splice(@{$s->[2]}, $start, $len);
       while (@k) {
         $k = shift(@k);
         delete $s->[0]{$k};
         push(@r, $k, shift(@v));
       }
       for ($start..$#{$s->[1]}) {
         $s->[0]{$s->[1][$_]} -= $len;
       }
     }
     while (@_) {
       ($k, $v) = (shift, shift);
       if (exists $s->[0]{$k}) {
         #      $s->STORE($k, $v);
         $i = $s->[0]{$k};
         $s->[1][$i] = $k;
         $s->[2][$i] = $v;
         $s->[0]{$k} = $i;
       }
       else {
         push(@k, $k);
         push(@v, $v);
         $siz++;
       }
     }
     if (defined $siz) {
       for ($start..$#{$s->[1]}) {
         $s->[0]{$s->[1][$_]} += $siz;
       }
       $i = $start;
       for (@k) {
         $s->[0]{$_} = $i++;
       }
       splice(@{$s->[1]}, $start, 0, @k);
       splice(@{$s->[2]}, $start, 0, @v);
     }
   }
   return @r;
 }
 
 #
 # delete elements specified by key
 # other elements higher than the one deleted "slide" down 
 #
 sub Delete {
   my($s) = shift;
 
   for (@_) {
     #
     # XXX potential optimization: could do $s->DELETE only if $#_ < 4.
     #     otherwise, should reset all the hash indices in one loop
     #
     $s->DELETE($_);
   }
 }
 
 #
 # replace hash element at specified index
 #
 # if the optional key is not supplied the value at index will simply be 
 # replaced without affecting the order.
 #
 # if an element with the supplied key already exists, it will be deleted first.
 #
 # returns the key of replaced value if it succeeds.
 #
 sub Replace {
   my($s) = shift;
   my($i, $v, $k) = (shift, shift, shift);
   if (defined $i and $i <= $#{$s->[1]} and $i >= 0) {
     if (defined $k) {
       delete $s->[0]{ $s->[1][$i] };
       $s->DELETE($k) ; #if exists $s->[0]{$k};
       $s->[1][$i] = $k;
       $s->[2][$i] = $v;
       $s->[0]{$k} = $i;
       return $k;
     }
     else {
       $s->[2][$i] = $v;
       return $s->[1][$i];
     }
   }
   return undef;
 }
 
 #
 # Given an $start and $len, returns a legal start and end (where start <= end)
 # for the current hash. 
 # Legal range is defined as 0 to $#s+1
 # $len defaults to number of elts upto end of list
 #
 #          0   1   2   ...
 #          | X | X | X ... X | X | X |
 #                           -2  -1       (no -0 alas)
 # X's above are the elements 
 #
 sub _lrange {
   my($s) = shift;
   my($offset, $len) = @_;
   my($start, $end);         # both inclusive
   my($size) = $#{$s->[1]}+1;
 
   return undef unless defined $offset;
   if($offset < 0) {
     $start = $offset + $size;
     $start = 0 if $start < 0;
   }
   else {
     ($offset > $size) ? ($start = $size) : ($start = $offset);
   }
 
   if (defined $len) {
     $len = -$len if $len < 0;
     $len = $size - $start if $len > $size - $start;
   }
   else {
     $len = $size - $start;
   }
   $end = $start + $len - 1;
 
   return ($start, $end, $len);
 }
 
 #
 # Return keys at supplied indices
 # Returns all keys if no args.
 #
 sub Keys   { 
   my($s) = shift;
   return ( @_ == 1
 	 ? $s->[1][$_[0]]
 	 : ( @_
 	   ? @{$s->[1]}[@_]
 	   : @{$s->[1]} ) );
 }
 
 #
 # Returns values at supplied indices
 # Returns all values if no args.
 #
 sub Values {
   my($s) = shift;
   return ( @_ == 1
 	 ? $s->[2][$_[0]]
 	 : ( @_
 	   ? @{$s->[2]}[@_]
 	   : @{$s->[2]} ) );
 }
 
 #
 # get indices of specified hash keys
 #
 sub Indices { 
   my($s) = shift;
   return ( @_ == 1 ? $s->[0]{$_[0]} : @{$s->[0]}{@_} );
 }
 
 #
 # number of k-v pairs in the ixhash
 # note that this does not equal the highest index
 # owing to preextended arrays
 #
 sub Length {
  return scalar @{$_[0]->[1]};
 }
 
 #
 # Reorder the hash in the supplied key order
 #
 # warning: any unsupplied keys will be lost from the hash
 # any supplied keys that dont exist in the hash will be ignored
 #
 sub Reorder {
   my($s) = shift;
   my(@k, @v, %x, $i);
   return unless @_;
 
   $i = 0;
   for (@_) {
     if (exists $s->[0]{$_}) {
       push(@k, $_);
       push(@v, $s->[2][ $s->[0]{$_} ] );
       $x{$_} = $i++;
     }
   }
   $s->[1] = \@k;
   $s->[2] = \@v;
   $s->[0] = \%x;
   return $s;
 }
 
 sub SortByKey {
   my($s) = shift;
   $s->Reorder(sort $s->Keys);
 }
 
 sub SortByValue {
   my($s) = shift;
   $s->Reorder(sort { $s->FETCH($a) cmp $s->FETCH($b) } $s->Keys)
 }
 
 1;
 __END__
 
 =head1 NAME
 
 Tie::IxHash - ordered associative arrays for Perl
 
 
 =head1 SYNOPSIS
 
     # simple usage
     use Tie::IxHash;
     tie HASHVARIABLE, 'Tie::IxHash' [, LIST];
 
     # OO interface with more powerful features
     use Tie::IxHash;
     TIEOBJECT = Tie::IxHash->new( [LIST] );
     TIEOBJECT->Splice( OFFSET [, LENGTH [, LIST]] );
     TIEOBJECT->Push( LIST );
     TIEOBJECT->Pop;
     TIEOBJECT->Shift;
     TIEOBJECT->Unshift( LIST );
     TIEOBJECT->Keys( [LIST] );
     TIEOBJECT->Values( [LIST] );
     TIEOBJECT->Indices( LIST );
     TIEOBJECT->Delete( [LIST] );
     TIEOBJECT->Replace( OFFSET, VALUE, [KEY] );
     TIEOBJECT->Reorder( LIST );
     TIEOBJECT->SortByKey;
     TIEOBJECT->SortByValue;
     TIEOBJECT->Length;
 
 
 =head1 DESCRIPTION
 
 This Perl module implements Perl hashes that preserve the order in which the
 hash elements were added.  The order is not affected when values
 corresponding to existing keys in the IxHash are changed.  The elements can
 also be set to any arbitrary supplied order.  The familiar perl array
 operations can also be performed on the IxHash.
 
 
 =head2 Standard C<TIEHASH> Interface
 
 The standard C<TIEHASH> mechanism is available. This interface is 
 recommended for simple uses, since the usage is exactly the same as
 regular Perl hashes after the C<tie> is declared.
 
 
 =head2 Object Interface
 
 This module also provides an extended object-oriented interface that can be
 used for more powerful operations with the IxHash.  The following methods
 are available:
 
 =over 8
 
 =item FETCH, STORE, DELETE, EXISTS
 
 These standard C<TIEHASH> methods mandated by Perl can be used directly.
 See the C<tie> entry in perlfunc(1) for details.
 
 =item Push, Pop, Shift, Unshift, Splice
 
 These additional methods resembling Perl functions are available for
 operating on key-value pairs in the IxHash. The behavior is the same as the
 corresponding perl functions, except when a supplied hash key already exists
 in the hash. In that case, the existing value is updated but its order is
 not affected.  To unconditionally alter the order of a supplied key-value
 pair, first C<DELETE> the IxHash element.
 
 =item Keys
 
 Returns an array of IxHash element keys corresponding to the list of supplied
 indices.  Returns an array of all the keys if called without arguments.
 Note the return value is mostly only useful when used in a list context
 (since perl will convert it to the number of elements in the array when
 used in a scalar context, and that may not be very useful).
 
 If a single argument is given, returns the single key corresponding to
 the index.  This is usable in either scalar or list context.
 
 =item Values
 
 Returns an array of IxHash element values corresponding to the list of supplied
 indices.  Returns an array of all the values if called without arguments.
 Note the return value is mostly only useful when used in a list context
 (since perl will convert it to the number of elements in the array when
 used in a scalar context, and that may not be very useful).
 
 If a single argument is given, returns the single value corresponding to
 the index.  This is usable in either scalar or list context.
 
 =item Indices
 
 Returns an array of indices corresponding to the supplied list of keys.
 Note the return value is mostly only useful when used in a list context
 (since perl will convert it to the number of elements in the array when
 used in a scalar context, and that may not be very useful).
 
 If a single argument is given, returns the single index corresponding to
 the key.  This is usable in either scalar or list context.
 
 =item Delete
 
 Removes elements with the supplied keys from the IxHash.
 
 =item Replace
 
 Substitutes the IxHash element at the specified index with the supplied
 value-key pair.  If a key is not supplied, simply substitutes the value at
 index with the supplied value. If an element with the supplied key already
 exists, it will be removed from the IxHash first.
 
 =item Reorder
 
 This method can be used to manipulate the internal order of the IxHash
 elements by supplying a list of keys in the desired order.  Note however,
 that any IxHash elements whose keys are not in the list will be removed from
 the IxHash.
 
 =item Length
 
 Returns the number of IxHash elements.
 
 =item SortByKey
 
 Reorders the IxHash elements by textual comparison of the keys.
 
 =item SortByValue
 
 Reorders the IxHash elements by textual comparison of the values.
 
 =item Clear
 
 Resets the IxHash to its pristine state: with no elements at all.
 
 =back
 
 
 =head1 EXAMPLE
 
     use Tie::IxHash;
 
     # simple interface
     $t = tie(%myhash, 'Tie::IxHash', 'a' => 1, 'b' => 2);
     %myhash = (first => 1, second => 2, third => 3);
     $myhash{fourth} = 4;
     @keys = keys %myhash;
     @values = values %myhash;
     print("y") if exists $myhash{third};
 
     # OO interface
     $t = Tie::IxHash->new(first => 1, second => 2, third => 3);
     $t->Push(fourth => 4); # same as $myhash{'fourth'} = 4;
     ($k, $v) = $t->Pop;    # $k is 'fourth', $v is 4
     $t->Unshift(neg => -1, zeroth => 0); 
     ($k, $v) = $t->Shift;  # $k is 'neg', $v is -1
     @oneandtwo = $t->Splice(1, 2, foo => 100, bar => 101);
 
     @keys = $t->Keys;
     @values = $t->Values;
     @indices = $t->Indices('foo', 'zeroth');
     @itemkeys = $t->Keys(@indices);
     @itemvals = $t->Values(@indices);
     $t->Replace(2, 0.3, 'other');
     $t->Delete('second', 'zeroth');
     $len = $t->Length;     # number of key-value pairs
 
     $t->Reorder(reverse @keys);
     $t->SortByKey;
     $t->SortByValue;
 
 
 =head1 BUGS
 
 You cannot specify a negative length to C<Splice>. Negative indexes are OK,
 though.
 
 
 =head1 NOTE
 
 Indexing always begins at 0 (despite the current C<$[> setting) for 
 all the functions.
 
 
 =head1 TODO
 
 Addition of elements with keys that already exist to the end of the IxHash
 must be controlled by a switch.
 
 Provide C<TIEARRAY> interface when it stabilizes in Perl.
 
 Rewrite using XSUBs for efficiency.
 
 
 =head1 AUTHOR
 
 Gurusamy Sarathy        gsar@umich.edu
 
 Copyright (c) 1995 Gurusamy Sarathy. All rights reserved.
 This program is free software; you can redistribute it and/or
 modify it under the same terms as Perl itself.
 
 
 =head1 VERSION
 
 Version 1.23
 
 
 =head1 SEE ALSO
 
 perl(1)
 
 =cut
### Time/Duration.pm ###
 package Time::Duration;
 $Time::Duration::VERSION = '1.20';
 use 5.006;
 use strict;
 use warnings;
 use constant DEBUG => 0;
 
 require Exporter;
 
 our @ISA         = ('Exporter');
 our @EXPORT      = qw( later later_exact earlier earlier_exact
                        ago ago_exact from_now from_now_exact
                        duration duration_exact
                        concise
                      );
 our @EXPORT_OK   = ('interval', @EXPORT);
 our $MILLISECOND = 0;
 
 # ALL SUBS ARE PURE FUNCTIONS
 
 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 sub concise ($) {
   my $string = $_[0];
   DEBUG and print "in : $string\n";
   $string =~ tr/,//d;
   $string =~ s/\band\b//;
   $string =~ s/\b(year|day|hour|minute|second)s?\b/substr($1,0,1)/eg;
   $string =~ s/\b(millisecond)s?\b/ms/g;
   $string =~ s/\s*(\d+)\s*/$1/g;
   return $string;
 }
 
 sub later {
   interval(      $_[0], $_[1], ' earlier', ' later', 'right then'); }
 sub later_exact {
   interval_exact($_[0], $_[1], ' earlier', ' later', 'right then'); }
 sub earlier {
   interval(      $_[0], $_[1], ' later', ' earlier', 'right then'); }
 sub earlier_exact {
   interval_exact($_[0], $_[1], ' later', ' earlier', 'right then'); }
 sub ago {
   interval(      $_[0], $_[1], ' from now', ' ago', 'right now'); }
 sub ago_exact {
   interval_exact($_[0], $_[1], ' from now', ' ago', 'right now'); }
 sub from_now {
   interval(      $_[0], $_[1], ' ago', ' from now', 'right now'); }
 sub from_now_exact {
   interval_exact($_[0], $_[1], ' ago', ' from now', 'right now'); }
 
 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 sub duration_exact {
   my $span = $_[0];   # interval in seconds
   my $precision = int($_[1] || 0) || 2;  # precision (default: 2)
   return '0 seconds' unless $span;
   _render('',
           _separate(abs $span));
 }
 
 sub duration {
   my $span = $_[0];   # interval in seconds
   my $precision = int($_[1] || 0) || 2;  # precision (default: 2)
   return '0 seconds' unless $span;
   _render('',
           _approximate($precision,
                        _separate(abs $span)));
 }
 
 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 sub interval_exact {
   my $span = $_[0];                    # interval, in seconds
                                        # precision is ignored
   my $direction = ($span < 0) ? $_[2]  # what a neg number gets
                 : ($span > 0) ? $_[3]  # what a pos number gets
                 : return        $_[4]; # what zero gets
   _render($direction,
           _separate($span));
 }
 
 sub interval {
   my $span = $_[0];                     # interval, in seconds
   my $precision = int($_[1] || 0) || 2; # precision (default: 2)
   my $direction = ($span < 0) ? $_[2]   # what a neg number gets
                 : ($span > 0) ? $_[3]   # what a pos number gets
                 : return        $_[4];  # what zero gets
   _render($direction,
           _approximate($precision,
                        _separate($span)));
 }
 
 #~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#
 #
 # The actual figuring is below here
 
 use constant MINUTE => 60;
 use constant HOUR => 3600;
 use constant DAY  => 24 * HOUR;
 use constant YEAR => 365 * DAY;
 
 sub _separate {
   # Breakdown of seconds into units, starting with the most significant
   
   my $remainder = abs $_[0]; # remainder
   my $this; # scratch
   my @wheel; # retval
   
   # Years:
   $this = int($remainder / (365 * 24 * 60 * 60));
   push @wheel, ['year', $this, 1_000_000_000];
   $remainder -= $this * (365 * 24 * 60 * 60);
     
   # Days:
   $this = int($remainder / (24 * 60 * 60));
   push @wheel, ['day', $this, 365];
   $remainder -= $this * (24 * 60 * 60);
     
   # Hours:
   $this = int($remainder / (60 * 60));
   push @wheel, ['hour', $this, 24];
   $remainder -= $this * (60 * 60);
   
   # Minutes:
   $this = int($remainder / 60);
   push @wheel, ['minute', $this, 60];
   $remainder -= $this * 60;
   
   push @wheel, ['second', int($remainder), 60];
 
 	# Thanks to Steven Haryanto (http://search.cpan.org/~sharyanto/) for the basis of this change.
 	if ($MILLISECOND) {
 		$remainder -= int($remainder);
 		push @wheel, ['millisecond', sprintf("%0.f", $remainder * 1000), 1000];
 	}
 
   return @wheel;
 }
 
 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 sub _approximate {
   # Now nudge the wheels into an acceptably (im)precise configuration
   my($precision, @wheel) = @_;
 
  Fix:
   {
     # Constraints for leaving this block:
     #  1) number of nonzero wheels must be <= $precision
     #  2) no wheels can be improperly expressed (like having "60" for mins)
   
     my $nonzero_count = 0;
     my $improperly_expressed;
 
     DEBUG and print join ' ', '#', (map "${$_}[1] ${$_}[0]",  @wheel), "\n";
     for(my $i = 0; $i < @wheel; $i++) {
       my $this = $wheel[$i];
       next if $this->[1] == 0; # Zeros require no attention.
       ++$nonzero_count;
       next if $i == 0; # the years wheel is never improper or over any limit; skip
       
       if($nonzero_count > $precision) {
         # This is one nonzero wheel too many!
         DEBUG and print '', $this->[0], " is one nonzero too many!\n";
 
         # Incr previous wheel if we're big enough:
         if($this->[1] >= ($this->[-1] / 2)) {
           DEBUG and printf "incrementing %s from %s to %s\n",
            $wheel[$i-1][0], $wheel[$i-1][1], 1 + $wheel[$i-1][1], ;
           ++$wheel[$i-1][1];
         }
 
         # Reset this and subsequent wheels to 0:
         for(my $j = $i; $j < @wheel; $j++) { $wheel[$j][1] = 0 }
         redo Fix; # Start over.
       } elsif($this->[1] >= $this->[-1]) {
         # It's an improperly expressed wheel.  (Like "60" on the mins wheel)
         $improperly_expressed = $i;
         DEBUG and print '', $this->[0], ' (', $this->[1], 
            ") is improper!\n";
       }
     }
     
     if(defined $improperly_expressed) {
       # Only fix the least-significant improperly expressed wheel (at a time).
       DEBUG and printf "incrementing %s from %s to %s\n",
        $wheel[$improperly_expressed-1][0], $wheel[$improperly_expressed-1][1], 
         1 + $wheel[$improperly_expressed-1][1], ;
       ++$wheel[ $improperly_expressed - 1][1];
       $wheel[ $improperly_expressed][1] = 0;
       # We never have a "150" in the minutes slot -- if it's improper,
       #  it's only by having been rounded up to the limit.
       redo Fix; # Start over.
     }
     
     # Otherwise there's not too many nonzero wheels, and there's no
     #  improperly expressed wheels, so fall thru...
   }
 
   return @wheel;
 }
 
 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 sub _render {
   # Make it into English
 
   my $direction = shift @_;
   my @wheel = map
         {;
             (  $_->[1] == 0) ? ()  # zero wheels
             : ($_->[1] == 1) ? "${$_}[1] ${$_}[0]"  # singular
             :                  "${$_}[1] ${$_}[0]s" # plural
         }
         @_
   ;
   return "just now" unless @wheel; # sanity
   $wheel[-1] .= $direction;
   return $wheel[0] if @wheel == 1;
   return "$wheel[0] and $wheel[1]" if @wheel == 2;
   $wheel[-1] = "and $wheel[-1]";
   return join q{, }, @wheel;
 }
 
 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 1;
 
 __END__
 
 so "1y 0d 1h 50m 50s", N=3, so you round at minutes to "1y 0d 1h 51m 0s",
 #That's okay, so fall thru.
 
 so "1y 1d 0h 59m 50s", N=3, so you round at minutes to "1y 1d 0h 60m 0s",
 but that's not improperly expressed, so you loop around and get
 "1y 1d 1h 0m 0s", which is short enough, and is properly expressed.
 
 =head1 NAME
 
 Time::Duration - rounded or exact English expression of durations
 
 =head1 SYNOPSIS
 
 Example use in a program that ends by noting its runtime:
 
   my $start_time = time();
   use Time::Duration;
   
   # then things that take all that time, and then ends:
   print "Runtime ", duration(time() - $start_time), ".\n";
 
 Example use in a program that reports age of a file:
 
   use Time::Duration;
   my $file = 'that_file';
   my $age = $^T - (stat($file))[9];  # 9 = modtime
   print "$file was modified ", ago($age);
 
 =head1 DESCRIPTION
 
 This module provides functions for expressing durations in rounded or exact
 terms.
 
 
 In the first example in the Synopsis, using duration($interval_seconds):
 
 If the C<time() - $start_time> is 3 seconds, this prints
 "Runtime: B<3 seconds>.".  If it's 0 seconds, it's "Runtime: B<0 seconds>.".
 If it's 1 second, it's "Runtime: B<1 second>.".  If it's 125 seconds, you
 get "Runtime: B<2 minutes and 5 seconds>.".  If it's 3820 seconds (which
 is exactly 1h, 3m, 40s), you get it rounded to fit within two expressed
 units: "Runtime: B<1 hour and 4 minutes>.".  Using duration_exact instead
 would return "Runtime: B<1 hour, 3 minutes, and 40 seconds>".
 
 In the second example in the Synopsis, using ago($interval_seconds):
 
 If the $age is 3 seconds, this prints
 "I<file> was modified B<3 seconds ago>".  If it's 0 seconds, it's
 "I<file> was modified B<just now>", as a special case.  If it's 1 second,
 it's "from B<1 second ago>".  If it's 125 seconds, you get "I<file> was
 modified B<2 minutes and 5 seconds ago>".  If it's 3820 seconds (which
 is exactly 1h, 3m, 40s), you get it rounded to fit within two expressed
 units: "I<file> was modified B<1 hour and 4 minutes ago>".  
 Using ago_exact instead
 would return "I<file> was modified B<1 hour, 3 minutes, and 40 seconds
 ago>".  And if the file's
 modtime is, surprisingly, three seconds into the future, $age is -3,
 and you'll get the equally and appropriately surprising
 "I<file> was modified B<3 seconds from now>."
 
 =head1 MILLISECOND MODE
 
 By default, this module assumes input is an integer representing number
 of seconds and only emits results based on the integer part of any
 floating-point values passed to it.  However, if you set the variable
 C<$Time::Duration::MILLISECOND> to any true value, then the methods will
 interpret inputs as floating-point numbers and will emit results containing
 information about the number of milliseconds in the value.
 
 For example, C<duration(1.021)> will return B<1 second and 21 milliseconds>
 in this mode.
 
 Millisecond mode is not enabled by default because this module sees heavy use
 and existing users of it may be relying on its implicit truncation of non-integer
 arguments.
 
 
 =head1 FUNCTIONS
 
 This module provides all the following functions, which are all exported
 by default when you call C<use Time::Duration;>.
 
 
 =over
 
 =item duration($seconds)
 
 =item duration($seconds, $precision)
 
 Returns English text expressing the approximate time duration 
 of abs($seconds), with at most S<C<$precision || 2>> expressed units.
 (That is, duration($seconds) is the same as duration($seconds,2).)
 
 For example, duration(120) or duration(-120) is "2 minutes".  And
 duration(0) is "0 seconds".
 
 The precision figure means that no more than that many units will
 be used in expressing the time duration.  For example,
 31,629,659 seconds is a duration of I<exactly>
 1 year, 1 day, 2 hours, and 59 seconds (assuming 1 year = exactly
 365 days, as we do assume in this module).  However, if you wanted
 an approximation of this to at most two expressed (i.e., nonzero) units, it
 would round it and truncate it to "1 year and 1 day".  Max of 3 expressed
 units would get you "1 year, 1 day, and 2 hours".  Max of 4 expressed
 units would get you "1 year, 1 day, 2 hours, and 59 seconds",
 which happens to be exactly true.  Max of 5 (or more) expressed units
 would get you the same, since there are only four nonzero units possible
 in for that duration.
 
 =item duration_exact($seconds)
 
 Same as duration($seconds), except that the returned value is an exact
 (unrounded) expression of $seconds.  For example, duration_exact(31629659)
 returns "1 year, 1 day, 2 hours, and 59 seconds later",
 which is I<exactly> true.
 
 
 =item ago($seconds)
 
 =item ago($seconds, $precision)
 
 For a positive value of seconds, this prints the same as
 C<duration($seconds, [$precision]) . S<' ago'>>.  For example,
 ago(120) is "2 minutes ago".  For a negative value of seconds,
 this prints the same as
 C<duration($seconds, [$precision]) . S<' from now'>>.  For example,
 ago(-120) is "2 minutes from now".  As a special case, ago(0)
 returns "right now".
 
 =item ago_exact($seconds)
 
 Same as ago($seconds), except that the returned value is an exact
 (unrounded) expression of $seconds.
 
 
 =item from_now($seconds)
 
 =item from_now($seconds, $precision)
 
 =item from_now_exact($seconds)
 
 The same as ago(-$seconds), ago(-$seconds, $precision), 
 ago_exact(-$seconds).  For example, from_now(120) is "2 minutes from now".
 
 
 =item later($seconds)
 
 =item later($seconds, $precision)
 
 For a positive value of seconds, this prints the same as
 C<duration($seconds, [$precision]) . S<' later'>>.  For example,
 ago(120) is "2 minutes later".  For a negative value of seconds,
 this prints the same as
 C<duration($seconds, [$precision]) . S<' earlier'>>.  For example,
 later(-120) is "2 minutes earlier".  As a special case, later(0)
 returns "right then".
 
 =item later_exact($seconds)
 
 Same as later($seconds), except that the returned value is an exact
 (unrounded) expression of $seconds.
 
 =item earlier($seconds)
 
 =item earlier($seconds, $precision)
 
 =item earlier_exact($seconds)
 
 The same as later(-$seconds), later(-$seconds, $precision), 
 later_exact(-$seconds).  For example, earlier(120) is "2 minutes earlier".
 
 
 =item concise( I<function(> ... ) )
 
 Concise takes the string output of one of the above functions and makes
 it more concise.  For example, 
 C<< ago(4567) >> returns "1 hour and 16 minutes ago", but
 C<< concise(ago(4567)) >> returns "1h16m ago".
 
 =back
 
 
 
 =head1 I18N/L10N NOTES
 
 Little of the internals of this module are English-specific.  See source
 and/or contact me if you're interested in making a localized version
 for some other language than English.
 
 
 
 =head1 BACKSTORY
 
 I wrote the basic C<ago()> function for use in Infobot
 (C<http://www.infobot.org>), because I was tired of this sort of
 response from the Purl Infobot:
 
   me> Purl, seen Woozle?
   <Purl> Woozle was last seen on #perl 20 days, 7 hours, 32 minutes
   and 40 seconds ago, saying: Wuzzle!
 
 I figured if it was 20 days ago, I don't care about the seconds.  So
 once I had written C<ago()>, I abstracted the code a bit and got
 all the other functions.
 
 
 =head1 CAVEAT
 
 This module calls a durational "year" an interval of exactly 365
 days of exactly 24 hours each, with no provision for leap years or
 monkey business with 23/25 hour days (much less leap seconds!).  But
 since the main work of this module is approximation, that shouldn't
 be a great problem for most purposes.
 
 
 =head1 SEE ALSO
 
 L<Date::Interval|Date::Interval>, which is similarly named, but does
 something rather different.
 
 I<Star Trek: The Next Generation> (1987-1994), where the character
 Data would express time durations like
 "1 year, 20 days, 22 hours, 59 minutes, and 35 seconds"
 instead of rounding to "1 year and 21 days".  This is because no-one
 ever told him to use Time::Duration.
 
 
 
 =head1 COPYRIGHT AND DISCLAIMER
 
 Copyright 2013, Sean M. Burke C<sburke@cpan.org>; Avi Finkel,
 C<avi@finkel.org>, all rights reserved.  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.
 
 =head1 AUTHOR
 
 Current maintainer Avi Finkel, C<avi@finkel.org>; Original author
 Sean M. Burke, C<sburke@cpan.org>
 
 =cut
 
 
### Try/Tiny.pm ###
 package Try::Tiny;
 BEGIN {
   $Try::Tiny::AUTHORITY = 'cpan:NUFFIN';
 }
 $Try::Tiny::VERSION = '0.22';
 use 5.006;
 # ABSTRACT: minimal try/catch with proper preservation of $@
 
 use strict;
 use warnings;
 
 use Exporter 5.57 'import';
 our @EXPORT = our @EXPORT_OK = qw(try catch finally);
 
 use Carp;
 $Carp::Internal{+__PACKAGE__}++;
 
 BEGIN { eval "use Sub::Name; 1" or *{subname} = sub {1} }
 
 # 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
   my $caller = caller;
   subname("${caller}::try {...} " => $try);
   subname("${caller}::catch {...} " => $catch) if $catch;
   subname("${caller}::finally {...} " => $_) foreach @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 $fail to false
   };
 
   # preserve the current error and reset the original value of $@
   $error = $@;
   $@ = $prev_error;
 
   # set up a scope guard to invoke the finally block at the end
   my @guards =
     map { Try::Tiny::ScopeGuard->_new($_, $failed ? $error : ()) }
     @finally;
 
   # at this point $failed contains a true value if the eval died, even if some
   # destructor overwrote $@ as the eval was unwinding.
   if ( $failed ) {
     # 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;
 
   return (
     bless(\$block, 'Try::Tiny::Catch'),
     @rest,
   );
 }
 
 sub finally (&;@) {
   my ( $block, @rest ) = @_;
 
   croak 'Useless bare finally()' unless wantarray;
 
   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.22
 
 =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
 learnt 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, C<$@> is clobbered at the beginning of the C<eval>, which
 also makes 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 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 SHINY SYNTAX
 
 Using Perl 5.10 you can use L<perlsyn/"Switch statements">.
 
 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
 arglist. 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.
 
 =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 unhygenically 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<considired 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<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 VERSION CONTROL
 
 L<http://github.com/doy/try-tiny/>
 
 =head1 AUTHORS
 
 =over 4
 
 =item *
 
 Yuval Kogman <nothingmuch@woobling.org>
 
 =item *
 
 Jesse Luehrs <doy@tozt.net>
 
 =back
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is Copyright (c) 2014 by Yuval Kogman.
 
 This is free software, licensed under:
 
   The MIT (X11) License
 
 =cut
### URI.pm ###
 package URI;
 
 use strict;
 use warnings;
 
 our $VERSION = "1.69";
 
 our ($ABS_REMOTE_LEADING_DOTS, $ABS_ALLOW_RELATIVE_SCHEME, $DEFAULT_QUERY_FORM_DELIMITER);
 
 my %implements;  # mapping from scheme to implementor class
 
 # Some "official" character classes
 
 our $reserved   = q(;/?:@&=+$,[]);
 our $mark       = q(-_.!~*'());                                    #'; emacs
 our $unreserved = "A-Za-z0-9\Q$mark\E";
 our $uric       = quotemeta($reserved) . $unreserved . "%";
 
 our $scheme_re  = '[a-zA-Z][a-zA-Z0-9.+\-]*';
 
 use Carp ();
 use URI::Escape ();
 
 use overload ('""'     => sub { ${$_[0]} },
               '=='     => sub { _obj_eq(@_) },
               '!='     => sub { !_obj_eq(@_) },
               fallback => 1,
              );
 
 # Check if two objects are the same object
 sub _obj_eq {
     return overload::StrVal($_[0]) eq overload::StrVal($_[1]);
 }
 
 sub new
 {
     my($class, $uri, $scheme) = @_;
 
     $uri = defined ($uri) ? "$uri" : "";   # stringify
     # Get rid of potential wrapping
     $uri =~ s/^<(?:URL:)?(.*)>$/$1/;  # 
     $uri =~ s/^"(.*)"$/$1/;
     $uri =~ s/^\s+//;
     $uri =~ s/\s+$//;
 
     my $impclass;
     if ($uri =~ m/^($scheme_re):/so) {
 	$scheme = $1;
     }
     else {
 	if (($impclass = ref($scheme))) {
 	    $scheme = $scheme->scheme;
 	}
 	elsif ($scheme && $scheme =~ m/^($scheme_re)(?::|$)/o) {
 	    $scheme = $1;
         }
     }
     $impclass ||= implementor($scheme) ||
 	do {
 	    require URI::_foreign;
 	    $impclass = 'URI::_foreign';
 	};
 
     return $impclass->_init($uri, $scheme);
 }
 
 
 sub new_abs
 {
     my($class, $uri, $base) = @_;
     $uri = $class->new($uri, $base);
     $uri->abs($base);
 }
 
 
 sub _init
 {
     my $class = shift;
     my($str, $scheme) = @_;
     # find all funny characters and encode the bytes.
     $str = $class->_uric_escape($str);
     $str = "$scheme:$str" unless $str =~ /^$scheme_re:/o ||
                                  $class->_no_scheme_ok;
     my $self = bless \$str, $class;
     $self;
 }
 
 
 sub _uric_escape
 {
     my($class, $str) = @_;
     $str =~ s*([^$uric\#])* URI::Escape::escape_char($1) *ego;
     utf8::downgrade($str);
     return $str;
 }
 
 
 sub implementor
 {
     my($scheme, $impclass) = @_;
     if (!$scheme || $scheme !~ /\A$scheme_re\z/o) {
 	require URI::_generic;
 	return "URI::_generic";
     }
 
     $scheme = lc($scheme);
 
     if ($impclass) {
 	# Set the implementor class for a given scheme
         my $old = $implements{$scheme};
         $impclass->_init_implementor($scheme);
         $implements{$scheme} = $impclass;
         return $old;
     }
 
     my $ic = $implements{$scheme};
     return $ic if $ic;
 
     # scheme not yet known, look for internal or
     # preloaded (with 'use') implementation
     $ic = "URI::$scheme";  # default location
 
     # turn scheme into a valid perl identifier by a simple transformation...
     $ic =~ s/\+/_P/g;
     $ic =~ s/\./_O/g;
     $ic =~ s/\-/_/g;
 
     no strict 'refs';
     # check we actually have one for the scheme:
     unless (@{"${ic}::ISA"}) {
         # Try to load it
         eval "require $ic";
         die $@ if $@ && $@ !~ /Can\'t locate.*in \@INC/;
         return undef unless @{"${ic}::ISA"};
     }
 
     $ic->_init_implementor($scheme);
     $implements{$scheme} = $ic;
     $ic;
 }
 
 
 sub _init_implementor
 {
     my($class, $scheme) = @_;
     # Remember that one implementor class may actually
     # serve to implement several URI schemes.
 }
 
 
 sub clone
 {
     my $self = shift;
     my $other = $$self;
     bless \$other, ref $self;
 }
 
 sub TO_JSON { ${$_[0]} }
 
 sub _no_scheme_ok { 0 }
 
 sub _scheme
 {
     my $self = shift;
 
     unless (@_) {
 	return undef unless $$self =~ /^($scheme_re):/o;
 	return $1;
     }
 
     my $old;
     my $new = shift;
     if (defined($new) && length($new)) {
 	Carp::croak("Bad scheme '$new'") unless $new =~ /^$scheme_re$/o;
 	$old = $1 if $$self =~ s/^($scheme_re)://o;
 	my $newself = URI->new("$new:$$self");
 	$$self = $$newself; 
 	bless $self, ref($newself);
     }
     else {
 	if ($self->_no_scheme_ok) {
 	    $old = $1 if $$self =~ s/^($scheme_re)://o;
 	    Carp::carp("Oops, opaque part now look like scheme")
 		if $^W && $$self =~ m/^$scheme_re:/o
 	}
 	else {
 	    $old = $1 if $$self =~ m/^($scheme_re):/o;
 	}
     }
 
     return $old;
 }
 
 sub scheme
 {
     my $scheme = shift->_scheme(@_);
     return undef unless defined $scheme;
     lc($scheme);
 }
 
 sub has_recognized_scheme {
     my $self = shift;
     return ref($self) !~ /^URI::_(?:foreign|generic)\z/;
 }
 
 sub opaque
 {
     my $self = shift;
 
     unless (@_) {
 	$$self =~ /^(?:$scheme_re:)?([^\#]*)/o or die;
 	return $1;
     }
 
     $$self =~ /^($scheme_re:)?    # optional scheme
 	        ([^\#]*)          # opaque
                 (\#.*)?           # optional fragment
               $/sx or die;
 
     my $old_scheme = $1;
     my $old_opaque = $2;
     my $old_frag   = $3;
 
     my $new_opaque = shift;
     $new_opaque = "" unless defined $new_opaque;
     $new_opaque =~ s/([^$uric])/ URI::Escape::escape_char($1)/ego;
     utf8::downgrade($new_opaque);
 
     $$self = defined($old_scheme) ? $old_scheme : "";
     $$self .= $new_opaque;
     $$self .= $old_frag if defined $old_frag;
 
     $old_opaque;
 }
 
 sub path { goto &opaque }  # alias
 
 
 sub fragment
 {
     my $self = shift;
     unless (@_) {
 	return undef unless $$self =~ /\#(.*)/s;
 	return $1;
     }
 
     my $old;
     $old = $1 if $$self =~ s/\#(.*)//s;
 
     my $new_frag = shift;
     if (defined $new_frag) {
 	$new_frag =~ s/([^$uric])/ URI::Escape::escape_char($1) /ego;
 	utf8::downgrade($new_frag);
 	$$self .= "#$new_frag";
     }
     $old;
 }
 
 
 sub as_string
 {
     my $self = shift;
     $$self;
 }
 
 
 sub as_iri
 {
     my $self = shift;
     my $str = $$self;
     if ($str =~ s/%([89a-fA-F][0-9a-fA-F])/chr(hex($1))/eg) {
 	# All this crap because the more obvious:
 	#
 	#   Encode::decode("UTF-8", $str, sub { sprintf "%%%02X", shift })
 	#
 	# doesn't work before Encode 2.39.  Wait for a standard release
 	# to bundle that version.
 
 	require Encode;
 	my $enc = Encode::find_encoding("UTF-8");
 	my $u = "";
 	while (length $str) {
 	    $u .= $enc->decode($str, Encode::FB_QUIET());
 	    if (length $str) {
 		# escape next char
 		$u .= URI::Escape::escape_char(substr($str, 0, 1, ""));
 	    }
 	}
 	$str = $u;
     }
     return $str;
 }
 
 
 sub canonical
 {
     # Make sure scheme is lowercased, that we don't escape unreserved chars,
     # and that we use upcase escape sequences.
 
     my $self = shift;
     my $scheme = $self->_scheme || "";
     my $uc_scheme = $scheme =~ /[A-Z]/;
     my $esc = $$self =~ /%[a-fA-F0-9]{2}/;
     return $self unless $uc_scheme || $esc;
 
     my $other = $self->clone;
     if ($uc_scheme) {
 	$other->_scheme(lc $scheme);
     }
     if ($esc) {
 	$$other =~ s{%([0-9a-fA-F]{2})}
 	            { my $a = chr(hex($1));
                       $a =~ /^[$unreserved]\z/o ? $a : "%\U$1"
                     }ge;
     }
     return $other;
 }
 
 # Compare two URIs, subclasses will provide a more correct implementation
 sub eq {
     my($self, $other) = @_;
     $self  = URI->new($self, $other) unless ref $self;
     $other = URI->new($other, $self) unless ref $other;
     ref($self) eq ref($other) &&                # same class
 	$self->canonical->as_string eq $other->canonical->as_string;
 }
 
 # generic-URI transformation methods
 sub abs { $_[0]; }
 sub rel { $_[0]; }
 
 sub secure { 0 }
 
 # help out Storable
 sub STORABLE_freeze {
        my($self, $cloning) = @_;
        return $$self;
 }
 
 sub STORABLE_thaw {
        my($self, $cloning, $str) = @_;
        $$self = $str;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 URI - Uniform Resource Identifiers (absolute and relative)
 
 =head1 SYNOPSIS
 
  $u1 = URI->new("http://www.perl.com");
  $u2 = URI->new("foo", "http");
  $u3 = $u2->abs($u1);
  $u4 = $u3->clone;
  $u5 = URI->new("HTTP://WWW.perl.com:80")->canonical;
 
  $str = $u->as_string;
  $str = "$u";
 
  $scheme = $u->scheme;
  $opaque = $u->opaque;
  $path   = $u->path;
  $frag   = $u->fragment;
 
  $u->scheme("ftp");
  $u->host("ftp.perl.com");
  $u->path("cpan/");
 
 =head1 DESCRIPTION
 
 This module implements the C<URI> class.  Objects of this class
 represent "Uniform Resource Identifier references" as specified in RFC
 2396 (and updated by RFC 2732).
 
 A Uniform Resource Identifier is a compact string of characters that
 identifies an abstract or physical resource.  A Uniform Resource
 Identifier can be further classified as either a Uniform Resource Locator
 (URL) or a Uniform Resource Name (URN).  The distinction between URL
 and URN does not matter to the C<URI> class interface. A
 "URI-reference" is a URI that may have additional information attached
 in the form of a fragment identifier.
 
 An absolute URI reference consists of three parts:  a I<scheme>, a
 I<scheme-specific part> and a I<fragment> identifier.  A subset of URI
 references share a common syntax for hierarchical namespaces.  For
 these, the scheme-specific part is further broken down into
 I<authority>, I<path> and I<query> components.  These URIs can also
 take the form of relative URI references, where the scheme (and
 usually also the authority) component is missing, but implied by the
 context of the URI reference.  The three forms of URI reference
 syntax are summarized as follows:
 
   <scheme>:<scheme-specific-part>#<fragment>
   <scheme>://<authority><path>?<query>#<fragment>
   <path>?<query>#<fragment>
 
 The components into which a URI reference can be divided depend on the
 I<scheme>.  The C<URI> class provides methods to get and set the
 individual components.  The methods available for a specific
 C<URI> object depend on the scheme.
 
 =head1 CONSTRUCTORS
 
 The following methods construct new C<URI> objects:
 
 =over 4
 
 =item $uri = URI->new( $str )
 
 =item $uri = URI->new( $str, $scheme )
 
 Constructs a new URI object.  The string
 representation of a URI is given as argument, together with an optional
 scheme specification.  Common URI wrappers like "" and <>, as well as
 leading and trailing white space, are automatically removed from
 the $str argument before it is processed further.
 
 The constructor determines the scheme, maps this to an appropriate
 URI subclass, constructs a new object of that class and returns it.
 
 If the scheme isn't one of those that URI recognizes, you still get
 an URI object back that you can access the generic methods on.  The
 C<< $uri->has_recognized_scheme >> method can be used to test for
 this.
 
 The $scheme argument is only used when $str is a
 relative URI.  It can be either a simple string that
 denotes the scheme, a string containing an absolute URI reference, or
 an absolute C<URI> object.  If no $scheme is specified for a relative
 URI $str, then $str is simply treated as a generic URI (no scheme-specific
 methods available).
 
 The set of characters available for building URI references is
 restricted (see L<URI::Escape>).  Characters outside this set are
 automatically escaped by the URI constructor.
 
 =item $uri = URI->new_abs( $str, $base_uri )
 
 Constructs a new absolute URI object.  The $str argument can
 denote a relative or absolute URI.  If relative, then it is
 absolutized using $base_uri as base. The $base_uri must be an absolute
 URI.
 
 =item $uri = URI::file->new( $filename )
 
 =item $uri = URI::file->new( $filename, $os )
 
 Constructs a new I<file> URI from a file name.  See L<URI::file>.
 
 =item $uri = URI::file->new_abs( $filename )
 
 =item $uri = URI::file->new_abs( $filename, $os )
 
 Constructs a new absolute I<file> URI from a file name.  See
 L<URI::file>.
 
 =item $uri = URI::file->cwd
 
 Returns the current working directory as a I<file> URI.  See
 L<URI::file>.
 
 =item $uri->clone
 
 Returns a copy of the $uri.
 
 =back
 
 =head1 COMMON METHODS
 
 The methods described in this section are available for all C<URI>
 objects.
 
 Methods that give access to components of a URI always return the
 old value of the component.  The value returned is C<undef> if the
 component was not present.  There is generally a difference between a
 component that is empty (represented as C<"">) and a component that is
 missing (represented as C<undef>).  If an accessor method is given an
 argument, it updates the corresponding component in addition to
 returning the old value of the component.  Passing an undefined
 argument removes the component (if possible).  The description of
 each accessor method indicates whether the component is passed as
 an escaped (percent-encoded) or an unescaped string.  A component that can be further
 divided into sub-parts are usually passed escaped, as unescaping might
 change its semantics.
 
 The common methods available for all URI are:
 
 =over 4
 
 =item $uri->scheme
 
 =item $uri->scheme( $new_scheme )
 
 Sets and returns the scheme part of the $uri.  If the $uri is
 relative, then $uri->scheme returns C<undef>.  If called with an
 argument, it updates the scheme of $uri, possibly changing the
 class of $uri, and returns the old scheme value.  The method croaks
 if the new scheme name is illegal; a scheme name must begin with a
 letter and must consist of only US-ASCII letters, numbers, and a few
 special marks: ".", "+", "-".  This restriction effectively means
 that the scheme must be passed unescaped.  Passing an undefined
 argument to the scheme method makes the URI relative (if possible).
 
 Letter case does not matter for scheme names.  The string
 returned by $uri->scheme is always lowercase.  If you want the scheme
 just as it was written in the URI in its original case,
 you can use the $uri->_scheme method instead.
 
 =item $uri->has_recognized_scheme
 
 Returns TRUE if the URI scheme is one that URI recognizes.
 
 It will also be TRUE for relative URLs where a recognized
 scheme was provided to the constructor, even if C<< $uri->scheme >>
 returns C<undef> for these.
 
 =item $uri->opaque
 
 =item $uri->opaque( $new_opaque )
 
 Sets and returns the scheme-specific part of the $uri
 (everything between the scheme and the fragment)
 as an escaped string.
 
 =item $uri->path
 
 =item $uri->path( $new_path )
 
 Sets and returns the same value as $uri->opaque unless the URI
 supports the generic syntax for hierarchical namespaces.
 In that case the generic method is overridden to set and return
 the part of the URI between the I<host name> and the I<fragment>.
 
 =item $uri->fragment
 
 =item $uri->fragment( $new_frag )
 
 Returns the fragment identifier of a URI reference
 as an escaped string.
 
 =item $uri->as_string
 
 Returns a URI object to a plain ASCII string.  URI objects are
 also converted to plain strings automatically by overloading.  This
 means that $uri objects can be used as plain strings in most Perl
 constructs.
 
 =item $uri->as_iri
 
 Returns a Unicode string representing the URI.  Escaped UTF-8 sequences
 representing non-ASCII characters are turned into their corresponding Unicode
 code point.
 
 =item $uri->canonical
 
 Returns a normalized version of the URI.  The rules
 for normalization are scheme-dependent.  They usually involve
 lowercasing the scheme and Internet host name components,
 removing the explicit port specification if it matches the default port,
 uppercasing all escape sequences, and unescaping octets that can be
 better represented as plain characters.
 
 For efficiency reasons, if the $uri is already in normalized form,
 then a reference to it is returned instead of a copy.
 
 =item $uri->eq( $other_uri )
 
 =item URI::eq( $first_uri, $other_uri )
 
 Tests whether two URI references are equal.  URI references
 that normalize to the same string are considered equal.  The method
 can also be used as a plain function which can also test two string
 arguments.
 
 If you need to test whether two C<URI> object references denote the
 same object, use the '==' operator.
 
 =item $uri->abs( $base_uri )
 
 Returns an absolute URI reference.  If $uri is already
 absolute, then a reference to it is simply returned.  If the $uri
 is relative, then a new absolute URI is constructed by combining the
 $uri and the $base_uri, and returned.
 
 =item $uri->rel( $base_uri )
 
 Returns a relative URI reference if it is possible to
 make one that denotes the same resource relative to $base_uri.
 If not, then $uri is simply returned.
 
 =item $uri->secure
 
 Returns a TRUE value if the URI is considered to point to a resource on
 a secure channel, such as an SSL or TLS encrypted one.
 
 =back
 
 =head1 GENERIC METHODS
 
 The following methods are available to schemes that use the
 common/generic syntax for hierarchical namespaces.  The descriptions of
 schemes below indicate which these are.  Unrecognized schemes are
 assumed to support the generic syntax, and therefore the following
 methods:
 
 =over 4
 
 =item $uri->authority
 
 =item $uri->authority( $new_authority )
 
 Sets and returns the escaped authority component
 of the $uri.
 
 =item $uri->path
 
 =item $uri->path( $new_path )
 
 Sets and returns the escaped path component of
 the $uri (the part between the host name and the query or fragment).
 The path can never be undefined, but it can be the empty string.
 
 =item $uri->path_query
 
 =item $uri->path_query( $new_path_query )
 
 Sets and returns the escaped path and query
 components as a single entity.  The path and the query are
 separated by a "?" character, but the query can itself contain "?".
 
 =item $uri->path_segments
 
 =item $uri->path_segments( $segment, ... )
 
 Sets and returns the path.  In a scalar context, it returns
 the same value as $uri->path.  In a list context, it returns the
 unescaped path segments that make up the path.  Path segments that
 have parameters are returned as an anonymous array.  The first element
 is the unescaped path segment proper;  subsequent elements are escaped
 parameter strings.  Such an anonymous array uses overloading so it can
 be treated as a string too, but this string does not include the
 parameters.
 
 Note that absolute paths have the empty string as their first
 I<path_segment>, i.e. the I<path> C</foo/bar> have 3
 I<path_segments>; "", "foo" and "bar".
 
 =item $uri->query
 
 =item $uri->query( $new_query )
 
 Sets and returns the escaped query component of
 the $uri.
 
 =item $uri->query_form
 
 =item $uri->query_form( $key1 => $val1, $key2 => $val2, ... )
 
 =item $uri->query_form( $key1 => $val1, $key2 => $val2, ..., $delim )
 
 =item $uri->query_form( \@key_value_pairs )
 
 =item $uri->query_form( \@key_value_pairs, $delim )
 
 =item $uri->query_form( \%hash )
 
 =item $uri->query_form( \%hash, $delim )
 
 Sets and returns query components that use the
 I<application/x-www-form-urlencoded> format.  Key/value pairs are
 separated by "&", and the key is separated from the value by a "="
 character.
 
 The form can be set either by passing separate key/value pairs, or via
 an array or hash reference.  Passing an empty array or an empty hash
 removes the query component, whereas passing no arguments at all leaves
 the component unchanged.  The order of keys is undefined if a hash
 reference is passed.  The old value is always returned as a list of
 separate key/value pairs.  Assigning this list to a hash is unwise as
 the keys returned might repeat.
 
 The values passed when setting the form can be plain strings or
 references to arrays of strings.  Passing an array of values has the
 same effect as passing the key repeatedly with one value at a time.
 All the following statements have the same effect:
 
     $uri->query_form(foo => 1, foo => 2);
     $uri->query_form(foo => [1, 2]);
     $uri->query_form([ foo => 1, foo => 2 ]);
     $uri->query_form([ foo => [1, 2] ]);
     $uri->query_form({ foo => [1, 2] });
 
 The $delim parameter can be passed as ";" to force the key/value pairs
 to be delimited by ";" instead of "&" in the query string.  This
 practice is often recommended for URLs embedded in HTML or XML
 documents as this avoids the trouble of escaping the "&" character.
 You might also set the $URI::DEFAULT_QUERY_FORM_DELIMITER variable to
 ";" for the same global effect.
 
 The C<URI::QueryParam> module can be loaded to add further methods to
 manipulate the form of a URI.  See L<URI::QueryParam> for details.
 
 =item $uri->query_keywords
 
 =item $uri->query_keywords( $keywords, ... )
 
 =item $uri->query_keywords( \@keywords )
 
 Sets and returns query components that use the
 keywords separated by "+" format.
 
 The keywords can be set either by passing separate keywords directly
 or by passing a reference to an array of keywords.  Passing an empty
 array removes the query component, whereas passing no arguments at
 all leaves the component unchanged.  The old value is always returned
 as a list of separate words.
 
 =back
 
 =head1 SERVER METHODS
 
 For schemes where the I<authority> component denotes an Internet host,
 the following methods are available in addition to the generic
 methods.
 
 =over 4
 
 =item $uri->userinfo
 
 =item $uri->userinfo( $new_userinfo )
 
 Sets and returns the escaped userinfo part of the
 authority component.
 
 For some schemes this is a user name and a password separated by
 a colon.  This practice is not recommended. Embedding passwords in
 clear text (such as URI) has proven to be a security risk in almost
 every case where it has been used.
 
 =item $uri->host
 
 =item $uri->host( $new_host )
 
 Sets and returns the unescaped hostname.
 
 If the $new_host string ends with a colon and a number, then this
 number also sets the port.
 
 For IPv6 addresses the brackets around the raw address is removed in the return
 value from $uri->host.  When setting the host attribute to an IPv6 address you
 can use a raw address or one enclosed in brackets.  The address needs to be
 enclosed in brackets if you want to pass in a new port value as well.
 
 =item $uri->ihost
 
 Returns the host in Unicode form.  Any IDNA A-labels are turned into U-labels.
 
 =item $uri->port
 
 =item $uri->port( $new_port )
 
 Sets and returns the port.  The port is a simple integer
 that should be greater than 0.
 
 If a port is not specified explicitly in the URI, then the URI scheme's default port
 is returned. If you don't want the default port
 substituted, then you can use the $uri->_port method instead.
 
 =item $uri->host_port
 
 =item $uri->host_port( $new_host_port )
 
 Sets and returns the host and port as a single
 unit.  The returned value includes a port, even if it matches the
 default port.  The host part and the port part are separated by a
 colon: ":".
 
 For IPv6 addresses the bracketing is preserved; thus
 URI->new("http://[::1]/")->host_port returns "[::1]:80".  Contrast this with
 $uri->host which will remove the brackets.
 
 =item $uri->default_port
 
 Returns the default port of the URI scheme to which $uri
 belongs.  For I<http> this is the number 80, for I<ftp> this
 is the number 21, etc.  The default port for a scheme can not be
 changed.
 
 =back
 
 =head1 SCHEME-SPECIFIC SUPPORT
 
 Scheme-specific support is provided for the following URI schemes.  For C<URI>
 objects that do not belong to one of these, you can only use the common and
 generic methods.
 
 =over 4
 
 =item B<data>:
 
 The I<data> URI scheme is specified in RFC 2397.  It allows inclusion
 of small data items as "immediate" data, as if it had been included
 externally.
 
 C<URI> objects belonging to the data scheme support the common methods
 and two new methods to access their scheme-specific components:
 $uri->media_type and $uri->data.  See L<URI::data> for details.
 
 =item B<file>:
 
 An old specification of the I<file> URI scheme is found in RFC 1738.
 A new RFC 2396 based specification in not available yet, but file URI
 references are in common use.
 
 C<URI> objects belonging to the file scheme support the common and
 generic methods.  In addition, they provide two methods for mapping file URIs
 back to local file names; $uri->file and $uri->dir.  See L<URI::file>
 for details.
 
 =item B<ftp>:
 
 An old specification of the I<ftp> URI scheme is found in RFC 1738.  A
 new RFC 2396 based specification in not available yet, but ftp URI
 references are in common use.
 
 C<URI> objects belonging to the ftp scheme support the common,
 generic and server methods.  In addition, they provide two methods for
 accessing the userinfo sub-components: $uri->user and $uri->password.
 
 =item B<gopher>:
 
 The I<gopher> URI scheme is specified in
 <draft-murali-url-gopher-1996-12-04> and will hopefully be available
 as a RFC 2396 based specification.
 
 C<URI> objects belonging to the gopher scheme support the common,
 generic and server methods. In addition, they support some methods for
 accessing gopher-specific path components: $uri->gopher_type,
 $uri->selector, $uri->search, $uri->string.
 
 =item B<http>:
 
 The I<http> URI scheme is specified in RFC 2616.
 The scheme is used to reference resources hosted by HTTP servers.
 
 C<URI> objects belonging to the http scheme support the common,
 generic and server methods.
 
 =item B<https>:
 
 The I<https> URI scheme is a Netscape invention which is commonly
 implemented.  The scheme is used to reference HTTP servers through SSL
 connections.  Its syntax is the same as http, but the default
 port is different.
 
 =item B<ldap>:
 
 The I<ldap> URI scheme is specified in RFC 2255.  LDAP is the
 Lightweight Directory Access Protocol.  An ldap URI describes an LDAP
 search operation to perform to retrieve information from an LDAP
 directory.
 
 C<URI> objects belonging to the ldap scheme support the common,
 generic and server methods as well as ldap-specific methods: $uri->dn,
 $uri->attributes, $uri->scope, $uri->filter, $uri->extensions.  See
 L<URI::ldap> for details.
 
 =item B<ldapi>:
 
 Like the I<ldap> URI scheme, but uses a UNIX domain socket.  The
 server methods are not supported, and the local socket path is
 available as $uri->un_path.  The I<ldapi> scheme is used by the
 OpenLDAP package.  There is no real specification for it, but it is
 mentioned in various OpenLDAP manual pages.
 
 =item B<ldaps>:
 
 Like the I<ldap> URI scheme, but uses an SSL connection.  This
 scheme is deprecated, as the preferred way is to use the I<start_tls>
 mechanism.
 
 =item B<mailto>:
 
 The I<mailto> URI scheme is specified in RFC 2368.  The scheme was
 originally used to designate the Internet mailing address of an
 individual or service.  It has (in RFC 2368) been extended to allow
 setting of other mail header fields and the message body.
 
 C<URI> objects belonging to the mailto scheme support the common
 methods and the generic query methods.  In addition, they support the
 following mailto-specific methods: $uri->to, $uri->headers.
 
 Note that the "foo@example.com" part of a mailto is I<not> the
 C<userinfo> and C<host> but instead the C<path>.  This allows a
 mailto URI to contain multiple comma separated email addresses.
 
 =item B<mms>:
 
 The I<mms> URL specification can be found at L<http://sdp.ppona.com/>.
 C<URI> objects belonging to the mms scheme support the common,
 generic, and server methods, with the exception of userinfo and
 query-related sub-components.
 
 =item B<news>:
 
 The I<news>, I<nntp> and I<snews> URI schemes are specified in
 <draft-gilman-news-url-01> and will hopefully be available as an RFC
 2396 based specification soon.
 
 C<URI> objects belonging to the news scheme support the common,
 generic and server methods.  In addition, they provide some methods to
 access the path: $uri->group and $uri->message.
 
 =item B<nntp>:
 
 See I<news> scheme.
 
 =item B<pop>:
 
 The I<pop> URI scheme is specified in RFC 2384. The scheme is used to
 reference a POP3 mailbox.
 
 C<URI> objects belonging to the pop scheme support the common, generic
 and server methods.  In addition, they provide two methods to access the
 userinfo components: $uri->user and $uri->auth
 
 =item B<rlogin>:
 
 An old specification of the I<rlogin> URI scheme is found in RFC
 1738. C<URI> objects belonging to the rlogin scheme support the
 common, generic and server methods.
 
 =item B<rtsp>:
 
 The I<rtsp> URL specification can be found in section 3.2 of RFC 2326.
 C<URI> objects belonging to the rtsp scheme support the common,
 generic, and server methods, with the exception of userinfo and
 query-related sub-components.
 
 =item B<rtspu>:
 
 The I<rtspu> URI scheme is used to talk to RTSP servers over UDP
 instead of TCP.  The syntax is the same as rtsp.
 
 =item B<rsync>:
 
 Information about rsync is available from L<http://rsync.samba.org/>.
 C<URI> objects belonging to the rsync scheme support the common,
 generic and server methods.  In addition, they provide methods to
 access the userinfo sub-components: $uri->user and $uri->password.
 
 =item B<sip>:
 
 The I<sip> URI specification is described in sections 19.1 and 25
 of RFC 3261.  C<URI> objects belonging to the sip scheme support the
 common, generic, and server methods with the exception of path related
 sub-components.  In addition, they provide two methods to get and set
 I<sip> parameters: $uri->params_form and $uri->params.
 
 =item B<sips>:
 
 See I<sip> scheme.  Its syntax is the same as sip, but the default
 port is different.
 
 =item B<snews>:
 
 See I<news> scheme.  Its syntax is the same as news, but the default
 port is different.
 
 =item B<telnet>:
 
 An old specification of the I<telnet> URI scheme is found in RFC
 1738. C<URI> objects belonging to the telnet scheme support the
 common, generic and server methods.
 
 =item B<tn3270>:
 
 These URIs are used like I<telnet> URIs but for connections to IBM
 mainframes.  C<URI> objects belonging to the tn3270 scheme support the
 common, generic and server methods.
 
 =item B<ssh>:
 
 Information about ssh is available at L<http://www.openssh.com/>.
 C<URI> objects belonging to the ssh scheme support the common,
 generic and server methods. In addition, they provide methods to
 access the userinfo sub-components: $uri->user and $uri->password.
 
 =item B<sftp>:
 
 C<URI> objects belonging to the sftp scheme support the common,
 generic and server methods. In addition, they provide methods to
 access the userinfo sub-components: $uri->user and $uri->password.
 
 =item B<urn>:
 
 The syntax of Uniform Resource Names is specified in RFC 2141.  C<URI>
 objects belonging to the urn scheme provide the common methods, and also the
 methods $uri->nid and $uri->nss, which return the Namespace Identifier
 and the Namespace-Specific String respectively.
 
 The Namespace Identifier basically works like the Scheme identifier of
 URIs, and further divides the URN namespace.  Namespace Identifier
 assignments are maintained at
 L<http://www.iana.org/assignments/urn-namespaces>.
 
 Letter case is not significant for the Namespace Identifier.  It is
 always returned in lower case by the $uri->nid method.  The $uri->_nid
 method can be used if you want it in its original case.
 
 =item B<urn>:B<isbn>:
 
 The C<urn:isbn:> namespace contains International Standard Book
 Numbers (ISBNs) and is described in RFC 3187.  A C<URI> object belonging
 to this namespace has the following extra methods (if the
 Business::ISBN module is available): $uri->isbn,
 $uri->isbn_publisher_code, $uri->isbn_group_code (formerly isbn_country_code,
 which is still supported by issues a deprecation warning), $uri->isbn_as_ean.
 
 =item B<urn>:B<oid>:
 
 The C<urn:oid:> namespace contains Object Identifiers (OIDs) and is
 described in RFC 3061.  An object identifier consists of sequences of digits
 separated by dots.  A C<URI> object belonging to this namespace has an
 additional method called $uri->oid that can be used to get/set the oid
 value.  In a list context, oid numbers are returned as separate elements.
 
 =back
 
 =head1 CONFIGURATION VARIABLES
 
 The following configuration variables influence how the class and its
 methods behave:
 
 =over 4
 
 =item $URI::ABS_ALLOW_RELATIVE_SCHEME
 
 Some older parsers used to allow the scheme name to be present in the
 relative URL if it was the same as the base URL scheme.  RFC 2396 says
 that this should be avoided, but you can enable this old behaviour by
 setting the $URI::ABS_ALLOW_RELATIVE_SCHEME variable to a TRUE value.
 The difference is demonstrated by the following examples:
 
   URI->new("http:foo")->abs("http://host/a/b")
       ==>  "http:foo"
 
   local $URI::ABS_ALLOW_RELATIVE_SCHEME = 1;
   URI->new("http:foo")->abs("http://host/a/b")
       ==>  "http:/host/a/foo"
 
 
 =item $URI::ABS_REMOTE_LEADING_DOTS
 
 You can also have the abs() method ignore excess ".."
 segments in the relative URI by setting $URI::ABS_REMOTE_LEADING_DOTS
 to a TRUE value.  The difference is demonstrated by the following
 examples:
 
   URI->new("../../../foo")->abs("http://host/a/b")
       ==> "http://host/../../foo"
 
   local $URI::ABS_REMOTE_LEADING_DOTS = 1;
   URI->new("../../../foo")->abs("http://host/a/b")
       ==> "http://host/foo"
 
 =item $URI::DEFAULT_QUERY_FORM_DELIMITER
 
 This value can be set to ";" to have the query form C<key=value> pairs
 delimited by ";" instead of "&" which is the default.
 
 =back
 
 =head1 BUGS
 
 There are some things that are not quite right:
 
 =over
 
 =item *
 
 Using regexp variables like $1 directly as arguments to the URI accessor methods
 does not work too well with current perl implementations.  I would argue
 that this is actually a bug in perl.  The workaround is to quote
 them. Example:
 
    /(...)/ || die;
    $u->query("$1");
 
 
 =item *
 
 The escaping (percent encoding) of chars in the 128 .. 255 range passed to the
 URI constructor or when setting URI parts using the accessor methods depend on
 the state of the internal UTF8 flag (see utf8::is_utf8) of the string passed.
 If the UTF8 flag is set the UTF-8 encoded version of the character is percent
 encoded.  If the UTF8 flag isn't set the Latin-1 version (byte) of the
 character is percent encoded.  This basically exposes the internal encoding of
 Perl strings.
 
 =back
 
 =head1 PARSING URIs WITH REGEXP
 
 As an alternative to this module, the following (official) regular
 expression can be used to decode a URI:
 
   my($scheme, $authority, $path, $query, $fragment) =
   $uri =~ m|(?:([^:/?#]+):)?(?://([^/?#]*))?([^?#]*)(?:\?([^#]*))?(?:#(.*))?|;
 
 The C<URI::Split> module provides the function uri_split() as a
 readable alternative.
 
 =head1 SEE ALSO
 
 L<URI::file>, L<URI::WithBase>, L<URI::QueryParam>, L<URI::Escape>,
 L<URI::Split>, L<URI::Heuristic>
 
 RFC 2396: "Uniform Resource Identifiers (URI): Generic Syntax",
 Berners-Lee, Fielding, Masinter, August 1998.
 
 L<http://www.iana.org/assignments/uri-schemes>
 
 L<http://www.iana.org/assignments/urn-namespaces>
 
 L<http://www.w3.org/Addressing/>
 
 =head1 COPYRIGHT
 
 Copyright 1995-2009 Gisle Aas.
 
 Copyright 1995 Martijn Koster.
 
 This program is free software; you can redistribute it and/or modify
 it under the same terms as Perl itself.
 
 =head1 AUTHORS / ACKNOWLEDGMENTS
 
 This module is based on the C<URI::URL> module, which in turn was
 (distantly) based on the C<wwwurl.pl> code in the libwww-perl for
 perl4 developed by Roy Fielding, as part of the Arcadia project at the
 University of California, Irvine, with contributions from Brooks
 Cutter.
 
 C<URI::URL> was developed by Gisle Aas, Tim Bunce, Roy Fielding and
 Martijn Koster with input from other people on the libwww-perl mailing
 list.
 
 C<URI> and related subclasses was developed by Gisle Aas.
 
 =cut
### URI/Escape.pm ###
 package URI::Escape;
 
 use strict;
 use warnings;
 
 =head1 NAME
 
 URI::Escape - Percent-encode and percent-decode unsafe characters
 
 =head1 SYNOPSIS
 
  use URI::Escape;
  $safe = uri_escape("10% is enough\n");
  $verysafe = uri_escape("foo", "\0-\377");
  $str  = uri_unescape($safe);
 
 =head1 DESCRIPTION
 
 This module provides functions to percent-encode and percent-decode URI strings as
 defined by RFC 3986. Percent-encoding URI's is informally called "URI escaping".
 This is the terminology used by this module, which predates the formalization of the
 terms by the RFC by several years.
 
 A URI consists of a restricted set of characters.  The restricted set
 of characters consists of digits, letters, and a few graphic symbols
 chosen from those common to most of the character encodings and input
 facilities available to Internet users.  They are made up of the
 "unreserved" and "reserved" character sets as defined in RFC 3986.
 
    unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
    reserved      = ":" / "/" / "?" / "#" / "[" / "]" / "@"
                    "!" / "$" / "&" / "'" / "(" / ")"
                  / "*" / "+" / "," / ";" / "="
 
 In addition, any byte (octet) can be represented in a URI by an escape
 sequence: a triplet consisting of the character "%" followed by two
 hexadecimal digits.  A byte can also be represented directly by a
 character, using the US-ASCII character for that octet.
 
 Some of the characters are I<reserved> for use as delimiters or as
 part of certain URI components.  These must be escaped if they are to
 be treated as ordinary data.  Read RFC 3986 for further details.
 
 The functions provided (and exported by default) from this module are:
 
 =over 4
 
 =item uri_escape( $string )
 
 =item uri_escape( $string, $unsafe )
 
 Replaces each unsafe character in the $string with the corresponding
 escape sequence and returns the result.  The $string argument should
 be a string of bytes.  The uri_escape() function will croak if given a
 characters with code above 255.  Use uri_escape_utf8() if you know you
 have such chars or/and want chars in the 128 .. 255 range treated as
 UTF-8.
 
 The uri_escape() function takes an optional second argument that
 overrides the set of characters that are to be escaped.  The set is
 specified as a string that can be used in a regular expression
 character class (between [ ]).  E.g.:
 
   "\x00-\x1f\x7f-\xff"          # all control and hi-bit characters
   "a-z"                         # all lower case characters
   "^A-Za-z"                     # everything not a letter
 
 The default set of characters to be escaped is all those which are
 I<not> part of the C<unreserved> character class shown above as well
 as the reserved characters.  I.e. the default is:
 
     "^A-Za-z0-9\-\._~"
 
 =item uri_escape_utf8( $string )
 
 =item uri_escape_utf8( $string, $unsafe )
 
 Works like uri_escape(), but will encode chars as UTF-8 before
 escaping them.  This makes this function able to deal with characters
 with code above 255 in $string.  Note that chars in the 128 .. 255
 range will be escaped differently by this function compared to what
 uri_escape() would.  For chars in the 0 .. 127 range there is no
 difference.
 
 Equivalent to:
 
     utf8::encode($string);
     my $uri = uri_escape($string);
 
 Note: JavaScript has a function called escape() that produces the
 sequence "%uXXXX" for chars in the 256 .. 65535 range.  This function
 has really nothing to do with URI escaping but some folks got confused
 since it "does the right thing" in the 0 .. 255 range.  Because of
 this you sometimes see "URIs" with these kind of escapes.  The
 JavaScript encodeURIComponent() function is similar to uri_escape_utf8().
 
 =item uri_unescape($string,...)
 
 Returns a string with each %XX sequence replaced with the actual byte
 (octet).
 
 This does the same as:
 
    $string =~ s/%([0-9A-Fa-f]{2})/chr(hex($1))/eg;
 
 but does not modify the string in-place as this RE would.  Using the
 uri_unescape() function instead of the RE might make the code look
 cleaner and is a few characters less to type.
 
 In a simple benchmark test I did,
 calling the function (instead of the inline RE above) if a few chars
 were unescaped was something like 40% slower, and something like 700% slower if none were.  If
 you are going to unescape a lot of times it might be a good idea to
 inline the RE.
 
 If the uri_unescape() function is passed multiple strings, then each
 one is returned unescaped.
 
 =back
 
 The module can also export the C<%escapes> hash, which contains the
 mapping from all 256 bytes to the corresponding escape codes.  Lookup
 in this hash is faster than evaluating C<sprintf("%%%02X", ord($byte))>
 each time.
 
 =head1 SEE ALSO
 
 L<URI>
 
 
 =head1 COPYRIGHT
 
 Copyright 1995-2004 Gisle Aas.
 
 This program is free software; you can redistribute it and/or modify
 it under the same terms as Perl itself.
 
 =cut
 
 use Exporter 5.57 'import';
 our %escapes;
 our @EXPORT = qw(uri_escape uri_unescape uri_escape_utf8);
 our @EXPORT_OK = qw(%escapes);
 our $VERSION = "3.31";
 
 use Carp ();
 
 # Build a char->hex map
 for (0..255) {
     $escapes{chr($_)} = sprintf("%%%02X", $_);
 }
 
 my %subst;  # compiled patterns
 
 my %Unsafe = (
     RFC2732 => qr/[^A-Za-z0-9\-_.!~*'()]/,
     RFC3986 => qr/[^A-Za-z0-9\-\._~]/,
 );
 
 sub uri_escape {
     my($text, $patn) = @_;
     return undef unless defined $text;
     if (defined $patn){
         unless (exists  $subst{$patn}) {
             # Because we can't compile the regex we fake it with a cached sub
             (my $tmp = $patn) =~ s,/,\\/,g;
             eval "\$subst{\$patn} = sub {\$_[0] =~ s/([$tmp])/\$escapes{\$1} || _fail_hi(\$1)/ge; }";
             Carp::croak("uri_escape: $@") if $@;
         }
         &{$subst{$patn}}($text);
     } else {
         $text =~ s/($Unsafe{RFC3986})/$escapes{$1} || _fail_hi($1)/ge;
     }
     $text;
 }
 
 sub _fail_hi {
     my $chr = shift;
     Carp::croak(sprintf "Can't escape \\x{%04X}, try uri_escape_utf8() instead", ord($chr));
 }
 
 sub uri_escape_utf8 {
     my $text = shift;
     utf8::encode($text);
     return uri_escape($text, @_);
 }
 
 sub uri_unescape {
     # Note from RFC1630:  "Sequences which start with a percent sign
     # but are not followed by two hexadecimal characters are reserved
     # for future extension"
     my $str = shift;
     if (@_ && wantarray) {
         # not executed for the common case of a single argument
         my @str = ($str, @_);  # need to copy
         for (@str) {
             s/%([0-9A-Fa-f]{2})/chr(hex($1))/eg;
         }
         return @str;
     }
     $str =~ s/%([0-9A-Fa-f]{2})/chr(hex($1))/eg if defined $str;
     $str;
 }
 
 # XXX FIXME escape_char is buggy as it assigns meaning to the string's storage format.
 sub escape_char {
     # Old versions of utf8::is_utf8() didn't properly handle magical vars (e.g. $1).
     # The following forces a fetch to occur beforehand.
     my $dummy = substr($_[0], 0, 0);
 
     if (utf8::is_utf8($_[0])) {
         my $s = shift;
         utf8::encode($s);
         unshift(@_, $s);
     }
 
     return join '', @URI::Escape::escapes{split //, $_[0]};
 }
 
 1;
### URI/Find.pm ###
 # Copyright (c) 2000, 2009 Michael G. Schwern.  All rights reserved.
 # This program is free software; you can redistribute it and/or modify
 # it under the same terms as Perl itself.
 
 package URI::Find;
 
 require 5.006;
 
 use strict;
 use base qw(Exporter);
 use vars qw($VERSION @EXPORT);
 
 $VERSION        = 20140709;
 @EXPORT         = qw(find_uris);
 
 use constant YES => (1==1);
 use constant NO  => !YES;
 
 use Carp        qw(croak);
 
 require URI;
 
 my $reserved   = q(;/?:@&=+$,[]);
 my $mark       = q(-_.!~*'());
 my $unreserved = "A-Za-z0-9\Q$mark\E";
 my $uric       = quotemeta($reserved) . '\p{isAlpha}' . $unreserved . "%";
 
 # URI scheme pattern without the non-alpha numerics.
 # Those are extremely uncommon and interfere with the match.
 my($schemeRe) = qr/[a-zA-Z][a-zA-Z0-9\+]*/;
 my($uricSet)  = $uric; # use new set
 
 # Some schemes which URI.pm does not explicitly support.
 my $extraSchemesRe = qr{^(?:git|svn|ssh|svn\+ssh)$};
 
 # We need to avoid picking up 'HTTP::Request::Common' so we have a
 # subset of uric without a colon ("I have no colon and yet I must poop")
 my($uricCheat) = __PACKAGE__->uric_set;
 $uricCheat =~ tr/://d;
 
 # Identifying characters accidentally picked up with a URI.
 my($cruftSet) = q{])\},.'";}; #'#
 
 
 =head1 NAME
 
 URI::Find - Find URIs in arbitrary text
 
 =head1 SYNOPSIS
 
   require URI::Find;
 
   my $finder = URI::Find->new(\&callback);
 
   $how_many_found = $finder->find(\$text);
 
 =head1 DESCRIPTION
 
 This module does one thing: Finds URIs and URLs in plain text.  It
 finds them quickly and it finds them B<all> (or what URI.pm considers
 a URI to be.)  It only finds URIs which include a scheme (http:// or
 the like), for something a bit less strict have a look at
 L<URI::Find::Schemeless|URI::Find::Schemeless>.
 
 For a command-line interface, L<urifind> is provided.
 
 =head2 Public Methods
 
 =over 4
 
 =item B<new>
 
   my $finder = URI::Find->new(\&callback);
 
 Creates a new URI::Find object.
 
 &callback is a function which is called on each URI found.  It is
 passed two arguments, the first is a URI object representing the URI
 found.  The second is the original text of the URI found.  The return
 value of the callback will replace the original URI in the text.
 
 =cut
 
 sub new {
     @_ == 2 || __PACKAGE__->badinvo;
     my($proto, $callback) = @_;
     my($class) = ref $proto || $proto;
     my $self = bless {}, $class;
 
     $self->{callback} = $callback;
 
     return $self;
 }
 
 =item B<find>
 
   my $how_many_found = $finder->find(\$text);
 
 $text is a string to search and possibly modify with your callback.
 
 Alternatively, C<find> can be called with a replacement function for
 the rest of the text:
 
   use CGI qw(escapeHTML);
   # ...
   my $how_many_found = $finder->find(\$text, \&escapeHTML);
 
 will not only call the callback function for every URL found (and
 perform the replacement instructions therein), but also run the rest
 of the text through C<escapeHTML()>. This makes it easier to turn
 plain text which contains URLs into HTML (see example below).
 
 =cut
 
 sub find {
     @_ == 2 || @_ == 3 || __PACKAGE__->badinvo;
     my($self, $r_text, $escape_func) = @_;
 
     # Might be slower, but it makes the code simpler
     $escape_func ||= sub { return $_[0] };
 
     # Store the escape func in the object temporarily for use
     # by other methods.
     local $self->{escape_func} = $escape_func;
 
     $self->{_uris_found} = 0;
 
     # Yes, evil.  Basically, look for something vaguely resembling a URL,
     # then hand it off to URI for examination.  If it passes, throw
     # it to a callback and put the result in its place.
     local $SIG{__DIE__} = 'DEFAULT';
     my $uri_cand;
     my $uri;
 
     my $uriRe = sprintf '(?:%s|%s)', $self->uri_re, $self->schemeless_uri_re;
 
     $$r_text =~ s{ (.*?) (?:(<(?:URL:)?)(.+?)(>)|($uriRe)) | (.+?)$ }{
         my $replace = '';
         if( defined $6 ) {
             $replace = $escape_func->($6);
         }
         else {
             my $maybe_uri = '';
 
             $replace = $escape_func->($1) if length $1;
 
             if( defined $2 ) {
                 $maybe_uri = $3;
                 my $is_uri = do {  # Don't alter $1...
                     $maybe_uri =~ s/\s+//g;
                     $maybe_uri =~ /^$uriRe/;
                 };
 
                 if( $is_uri ) {
                     $replace .= $escape_func->($2);
                     $replace .= $self->_uri_filter($maybe_uri);
                     $replace .= $escape_func->($4);
                 }
                 else {
                     # the whole text inside of the <...> was not a url, but
                     # maybe it has a url (like an HTML <a> link)
                     my $has_uri = do { # Don't alter $1...
                         $maybe_uri = $3;
                         $maybe_uri =~ /$uriRe/;
                     };
                     if( $has_uri ) {
                         my $pre = $2;
                         my $post = $4;
                         do { $self->find(\$maybe_uri, $escape_func) };
                         $replace .= $escape_func->($pre);
                         $replace .= $maybe_uri;  # already escaped by find()
                         $replace .= $escape_func->($post);
                     }
                     else {
                         $replace .= $escape_func->($2.$3.$4);
                     }
                 }
             }
             else {
                 $replace .= $self->_uri_filter($5);
             }
         }
 
         $replace;
     }gsex;
 
     return $self->{_uris_found};
 }
 
 
 sub _uri_filter {
     my($self, $orig_match) = @_;
 
     # A heuristic.  Often you'll see things like:
     # "I saw this site, http://www.foo.com, and its really neat!"
     # or "Foo Industries (at http://www.foo.com)"
     # We want to avoid picking up the trailing paren, period or comma.
     # Of course, this might wreck a perfectly valid URI, more often than
     # not it corrects a parse mistake.
     $orig_match = $self->decruft($orig_match);
 
     my $replacement = '';
     if( my $uri = $self->_is_uri(\$orig_match) ) {
         # It's a URI
         $self->{_uris_found}++;
         $replacement = $self->{callback}->($uri, $orig_match);
     }
     else {
         # False alarm
         $replacement = $self->{escape_func}->($orig_match);
     }
 
     # Return recrufted replacement
     return $self->recruft($replacement);
 }
 
 
 =back
 
 =head2 Protected Methods
 
 I got a bunch of mail from people asking if I'd add certain features
 to URI::Find.  Most wanted the search to be less restrictive, do more
 heuristics, etc...  Since many of the requests were contradictory, I'm
 letting people create their own custom subclasses to do what they
 want.
 
 The following are methods internal to URI::Find which a subclass can
 override to change the way URI::Find acts.  They are only to be called
 B<inside> a URI::Find subclass.  Users of this module are NOT to use
 these methods.
 
 =over
 
 =item B<uri_re>
 
   my $uri_re = $self->uri_re;
 
 Returns the regex for finding absolute, schemed URIs
 (http://www.foo.com and such).  This, combined with
 schemeless_uri_re() is what finds candidate URIs.
 
 Usually this method does not have to be overridden.
 
 =cut
 
 sub uri_re {
     @_ == 1 || __PACKAGE__->badinvo;
     my($self) = shift;
     return sprintf '%s:[%s][%s#]*', $schemeRe,
                                     $uricCheat,
                                     $self->uric_set;
 }
 
 =item B<schemeless_uri_re>
 
   my $schemeless_re = $self->schemeless_uri_re;
 
 Returns the regex for finding schemeless URIs (www.foo.com and such) and
 other things which might be URIs.  By default this will match nothing
 (though it used to try to find schemeless URIs which started with C<www>
 and C<ftp>).
 
 Many people will want to override this method.  See L<URI::Find::Schemeless>
 for a subclass does a reasonable job of finding URIs which might be missing
 the scheme.
 
 =cut
 
 sub schemeless_uri_re {
     @_ == 1 || __PACKAGE__->badinvo;
     my($self) = shift;
     return qr/\b\B/; # match nothing
 }
 
 =item B<uric_set>
 
   my $uric_set = $self->uric_set;
 
 Returns a set matching the 'uric' set defined in RFC 2396 suitable for
 putting into a character set ([]) in a regex.
 
 You almost never have to override this.
 
 =cut
 
 sub uric_set {
     @_ == 1 || __PACKAGE__->badinvo;
     return $uricSet;
 }
 
 =item B<cruft_set>
 
   my $cruft_set = $self->cruft_set;
 
 Returns a set of characters which are considered garbage.  Used by
 decruft().
 
 =cut
 
 sub cruft_set {
     @_ == 1 || __PACKAGE__->badinvo;
     return $cruftSet;
 }
 
 =item B<decruft>
 
   my $uri = $self->decruft($uri);
 
 Sometimes garbage characters like periods and parenthesis get
 accidentally matched along with the URI.  In order for the URI to be
 properly identified, it must sometimes be "decrufted", the garbage
 characters stripped.
 
 This method takes a candidate URI and strips off any cruft it finds.
 
 =cut
 
 my %balanced_cruft = (
     '('         => ')',
     '{'         => '}',
     '['         => ']',
     '"'         => '"',
     q[']        => q['],
 );
 
 sub decruft {
     @_ == 2 || __PACKAGE__->badinvo;
     my($self, $orig_match) = @_;
 
     $self->{start_cruft} = '';
     $self->{end_cruft} = '';
 
     if( $orig_match =~ s/([\Q$cruftSet\E]+)$// ) {
         # urls can end with HTML entities if found in HTML so let's put back semicolons
         # if this looks like the case
         my $cruft = $1;
         if( $cruft =~ /^;/ && $orig_match =~ /\&(\#[1-9]\d{1,3}|[a-zA-Z]{2,8})$/) {
             $orig_match .= ';';
             $cruft =~ s/^;//;
         }
 
         while( my($open, $close) = each %balanced_cruft ) {
             $self->recruft_balanced(\$orig_match, \$cruft, $open, $close);
         }
 
         $self->{end_cruft} = $cruft if $cruft;
     }
 
     return $orig_match;
 }
 
 
 sub recruft_balanced {
     my $self = shift;
     my($orig_match, $cruft, $open, $close) = @_;
 
     my $open_count  = () = $$orig_match =~ m{\Q$open}g;
     my $close_count = () = $$orig_match =~ m{\Q$close}g;
 
     if ( $$cruft =~ /\Q$close\E$/ && $open_count == ( $close_count + 1 ) ) {
         $$orig_match .= $close;
         $$cruft =~ s/\Q$close\E$//;
     }
 
     return;
 }
 
 
 =item B<recruft>
 
   my $uri = $self->recruft($uri);
 
 This method puts back the cruft taken off with decruft().  This is necessary
 because the cruft is destructively removed from the string before invoking
 the user's callback, so it has to be put back afterwards.
 
 =cut
 
 #'#
 
 sub recruft {
     @_ == 2 || __PACKAGE__->badinvo;
     my($self, $uri) = @_;
 
     return $self->{start_cruft} . $uri . $self->{end_cruft};
 }
 
 =item B<schemeless_to_schemed>
 
   my $schemed_uri = $self->schemeless_to_schemed($schemeless_uri);
 
 This takes a schemeless URI and returns an absolute, schemed URI.  The
 standard implementation supplies ftp:// for URIs which start with ftp.,
 and http:// otherwise.
 
 =cut
 
 sub schemeless_to_schemed {
     @_ == 2 || __PACKAGE__->badinvo;
     my($self, $uri_cand) = @_;
 
     $uri_cand =~ s|^(<?)ftp\.|$1ftp://ftp\.|
         or $uri_cand =~ s|^(<?)|${1}http://|;
 
     return $uri_cand;
 }
 
 =item B<is_schemed>
 
   $obj->is_schemed($uri);
 
 Returns whether or not the given URI is schemed or schemeless.  True for
 schemed, false for schemeless.
 
 =cut
 
 sub is_schemed {
     @_ == 2 || __PACKAGE__->badinvo;
     my($self, $uri) = @_;
     return scalar $uri =~ /^<?$schemeRe:/;
 }
 
 =item I<badinvo>
 
   __PACKAGE__->badinvo($extra_levels, $msg)
 
 This is used to complain about bogus subroutine/method invocations.
 The args are optional.
 
 =cut
 
 sub badinvo {
     my $package = shift;
     my $level   = @_ ? shift : 0;
     my $msg     = @_ ? " (" . shift() . ")" : '';
     my $subname = (caller $level + 1)[3];
     croak "Bogus invocation of $subname$msg";
 }
 
 =back
 
 =head2 Old Functions
 
 The old find_uri() function is still around and it works, but its
 deprecated.
 
 =cut
 
 # Old interface.
 sub find_uris (\$&) {
     @_ == 2 || __PACKAGE__->badinvo;
     my($r_text, $callback) = @_;
 
     my $self = __PACKAGE__->new($callback);
     return $self->find($r_text);
 }
 
 
 =head1 EXAMPLES
 
 Store a list of all URIs (normalized) in the document.
 
   my @uris;
   my $finder = URI::Find->new(sub {
       my($uri) = shift;
       push @uris, $uri;
   });
   $finder->find(\$text);
 
 Print the original URI text found and the normalized representation.
 
   my $finder = URI::Find->new(sub {
       my($uri, $orig_uri) = @_;
       print "The text '$orig_uri' represents '$uri'\n";
       return $orig_uri;
   });
   $finder->find(\$text);
 
 Check each URI in document to see if it exists.
 
   use LWP::Simple;
 
   my $finder = URI::Find->new(sub {
       my($uri, $orig_uri) = @_;
       if( head $uri ) {
           print "$orig_uri is okay\n";
       }
       else {
           print "$orig_uri cannot be found\n";
       }
       return $orig_uri;
   });
   $finder->find(\$text);
 
 
 Turn plain text into HTML, with each URI found wrapped in an HTML anchor.
 
   use CGI qw(escapeHTML);
   use URI::Find;
 
   my $finder = URI::Find->new(sub {
       my($uri, $orig_uri) = @_;
       return qq|<a href="$uri">$orig_uri</a>|;
   });
   $finder->find(\$text, \&escapeHTML);
   print "<pre>$text</pre>";
 
 =cut
 
 
 sub _is_uri {
     @_ == 2 || __PACKAGE__->badinvo;
     my($self, $r_uri_cand) = @_;
 
     my $uri = $$r_uri_cand;
 
     # Translate schemeless to schemed if necessary.
     $uri = $self->schemeless_to_schemed($uri) if
       $uri =~ $self->schemeless_uri_re   and
       $uri !~ /^<?$schemeRe:/;
 
     eval {
         $uri = URI->new($uri);
 
         # Throw out anything with an invalid scheme.
         my $has_invalid_scheme = $uri->isa("URI::_foreign") &&
                                  $uri->scheme !~ $extraSchemesRe;
 
         # Toss out things like http:// but keep file:///
         my $is_empty = $uri =~ m{^$schemeRe://$};
 
         undef $uri if $has_invalid_scheme || $is_empty;
     };
 
     if($@ || !defined $uri) {   # leave everything untouched, its not a URI.
         return NO;
     }
     else {                      # Its a URI.
         return $uri;
     }
 }
 
 
 =head1 NOTES
 
 Will not find URLs with Internationalized Domain Names or pretty much
 any non-ascii stuff in them.  See
 L<http://rt.cpan.org/Ticket/Display.html?id=44226>
 
 
 =head1 AUTHOR
 
 Michael G Schwern <schwern@pobox.com> with insight from Uri Gutman,
 Greg Bacon, Jeff Pinyan, Roderick Schertler and others.
 
 Roderick Schertler <roderick@argon.org> maintained versions 0.11 to 0.16.
 
 Darren Chamberlain wrote urifind.
 
 
 =head1 LICENSE
 
 Copyright 2000, 2009-2010 by Michael G Schwern E<lt>schwern@pobox.comE<gt>.
 
 This program is free software; you can redistribute it and/or 
 modify it under the same terms as Perl itself.
 
 See F<http://www.perlfoundation.org/artistic_license_1_0>
 
 =head1 SEE ALSO
 
 L<urifind>, L<URI::Find::Schemeless>, L<URI>, RFC 3986 Appendix C
 
 =cut
 
 1;
### URI/Find/Schemeless.pm ###
 # Copyright (c) 2000, 2009 Michael G. Schwern.  All rights reserved.
 # This program is free software; you can redistribute it and/or modify
 # it under the same terms as Perl itself.
 
 package URI::Find::Schemeless;
 
 use strict;
 use base qw(URI::Find);
 
 # base.pm error in 5.005_03 prevents it from loading URI::Find if I'm
 # required first.
 use URI::Find ();
 
 use vars qw($VERSION);
 $VERSION = 20140709;
 
 my($dnsSet) = '\p{isAlpha}A-Za-z0-9-'; # extended for IDNA domains
 
 my($cruftSet) = __PACKAGE__->cruft_set . '<>?}';
 
 my($tldRe) = __PACKAGE__->top_level_domain_re;
 
 my($uricSet) = __PACKAGE__->uric_set;
 
 =head1 NAME
 
 URI::Find::Schemeless - Find schemeless URIs in arbitrary text.
 
 
 =head1 SYNOPSIS
 
   require URI::Find::Schemeless;
 
   my $finder = URI::Find::Schemeless->new(\&callback);
 
   The rest is the same as URI::Find.
 
 
 =head1 DESCRIPTION
 
 URI::Find finds absolute URIs in plain text with some weak heuristics
 for finding schemeless URIs.  This subclass is for finding things
 which might be URIs in free text.  Things like "www.foo.com" and
 "lifes.a.bitch.if.you.aint.got.net".
 
 The heuristics are such that it hopefully finds a minimum of false
 positives, but there's no easy way for it know if "COMMAND.COM" refers
 to a web site or a file.
 
 =cut
 
 sub schemeless_uri_re {
     @_ == 1 || __PACKAGE__->badinvo;
     return qr{
               # Originally I constrained what couldn't be before the match
               # like this:  don't match email addresses, and don't start
               # anywhere but at the beginning of a host name
               #    (?<![\@.$dnsSet])
               # but I switched to saying what can be there after seeing a
               # false match of "Lite.pm" via "MIME/Lite.pm".
               (?: ^ | (?<=[\s<>()\{\}\[\]]) )
               # hostname
               (?: [$dnsSet]+(?:\.[$dnsSet]+)*\.$tldRe
                   | (?:\d{1,3}\.){3}\d{1,3} ) # not inet_aton() complete
               (?:
                   (?=[\s\Q$cruftSet\E]) # followed by unrelated thing
                   (?!\.\w)              #   but don't stop mid foo.xx.bar
                       (?<!\.p[ml])      #   but exclude Foo.pm and Foo.pl
                   |$                    # or end of line
                       (?<!\.p[ml])      #   but exclude Foo.pm and Foo.pl
                   |/[$uricSet#]*        # or slash and URI chars
               )
            }x;
 }
 
 =head3 top_level_domain_re
 
   my $tld_re = $self->top_level_domain_re;
 
 Returns the regex for matching top level DNS domains.  The regex shouldn't
 be anchored, it shouldn't do any capturing matches, and it should make
 itself ignore case.
 
 =cut
 
 sub top_level_domain_re {
     @_ == 1 || __PACKAGE__->badinvo;
     my($self) = shift;
 
     use utf8;
     # Updated from http://www.iana.org/domains/root/db/ with new TLDs
     my $plain = join '|', qw(
         AERO
         ARPA
         ASIA
         BIZ
         CAT
         COM
         COOP
         EDU
         GOV
         INFO
         INT
         JOBS
         MIL
         MOBI
         MUSEUM
         NAME
         NET
         ORG
         PRO
         TEL
         TRAVEL
         ac
         academy
         accountants
         active
         actor
         ad
         ae
         aero
         af
         ag
         agency
         ai
         airforce
         al
         am
         an
         ao
         aq
         ar
         archi
         army
         arpa
         as
         asia
         associates
         at
         attorney
         au
         audio
         autos
         aw
         ax
         axa
         az
         ba
         bar
         bargains
         bayern
         bb
         bd
         be
         beer
         berlin
         best
         bf
         bg
         bh
         bi
         bid
         bike
         bio
         biz
         bj
         bl
         black
         blackfriday
         blue
         bm
         bmw
         bn
         bo
         boutique
         bq
         br
         brussels
         bs
         bt
         build
         builders
         buzz
         bv
         bw
         by
         bz
         bzh
         ca
         cab
         camera
         camp
         capetown
         capital
         cards
         care
         career
         careers
         cash
         cat
         catering
         cc
         cd
         center
         ceo
         cf
         cg
         ch
         cheap
         christmas
         church
         ci
         citic
         ck
         cl
         claims
         cleaning
         clinic
         clothing
         club
         cm
         cn
         co
         codes
         coffee
         college
         cologne
         com
         community
         company
         computer
         condos
         construction
         consulting
         contractors
         cooking
         cool
         coop
         country
         cr
         credit
         creditcard
         cruises
         cu
         cv
         cw
         cx
         cy
         cz
         dance
         dating
         de
         degree
         democrat
         dental
         dentist
         desi
         diamonds
         digital
         directory
         discount
         dj
         dk
         dm
         dnp
         do
         domains
         durban
         dz
         ec
         edu
         education
         ee
         eg
         eh
         email
         engineer
         engineering
         enterprises
         equipment
         er
         es
         estate
         et
         eu
         eus
         events
         exchange
         expert
         exposed
         fail
         farm
         feedback
         fi
         finance
         financial
         fish
         fishing
         fitness
         fj
         fk
         flights
         florist
         fm
         fo
         foo
         foundation
         fr
         frogans
         fund
         furniture
         futbol
         ga
         gal
         gallery
         gb
         gd
         ge
         gf
         gg
         gh
         gi
         gift
         gives
         gl
         glass
         global
         globo
         gm
         gmo
         gn
         gop
         gov
         gp
         gq
         gr
         graphics
         gratis
         green
         gripe
         gs
         gt
         gu
         guide
         guitars
         guru
         gw
         gy
         hamburg
         haus
         hiphop
         hiv
         hk
         hm
         hn
         holdings
         holiday
         homes
         horse
         host
         house
         hr
         ht
         hu
         id
         ie
         il
         im
         immobilien
         in
         industries
         info
         ink
         institute
         insure
         int
         international
         investments
         io
         iq
         ir
         is
         it
         je
         jetzt
         jm
         jo
         jobs
         joburg
         jp
         juegos
         kaufen
         ke
         kg
         kh
         ki
         kim
         kitchen
         kiwi
         km
         kn
         koeln
         kp
         kr
         kred
         kw
         ky
         kz
         la
         land
         lawyer
         lb
         lc
         lease
         li
         life
         lighting
         limited
         limo
         link
         lk
         loans
         london
         lotto
         lr
         ls
         lt
         lu
         luxe
         luxury
         lv
         ly
         ma
         maison
         management
         mango
         market
         marketing
         mc
         md
         me
         media
         meet
         menu
         mf
         mg
         mh
         miami
         mil
         mini
         mk
         ml
         mm
         mn
         mo
         mobi
         moda
         moe
         monash
         mortgage
         moscow
         motorcycles
         mp
         mq
         mr
         ms
         mt
         mu
         museum
         mv
         mw
         mx
         my
         mz
         na
         nagoya
         name
         navy
         nc
         ne
         net
         neustar
         nf
         ng
         nhk
         ni
         ninja
         nl
         no
         np
         nr
         nu
         nyc
         nz
         okinawa
         om
         onl
         org
         organic
         ovh
         pa
         paris
         partners
         parts
         pe
         pf
         pg
         ph
         photo
         photography
         photos
         physio
         pics
         pictures
         pink
         pk
         pl
         plumbing
         pm
         pn
         post
         pr
         press
         pro
         productions
         properties
         ps
         pt
         pub
         pw
         py
         qa
         qpon
         quebec
         re
         recipes
         red
         rehab
         reise
         reisen
         ren
         rentals
         repair
         report
         republican
         rest
         reviews
         rich
         rio
         ro
         rocks
         rodeo
         rs
         ru
         ruhr
         rw
         ryukyu
         sa
         saarland
         sb
         sc
         schule
         scot
         sd
         se
         services
         sexy
         sg
         sh
         shiksha
         shoes
         si
         singles
         sj
         sk
         sl
         sm
         sn
         so
         social
         software
         sohu
         solar
         solutions
         soy
         space
         sr
         ss
         st
         su
         supplies
         supply
         support
         surf
         surgery
         sv
         sx
         sy
         systems
         sz
         tattoo
         tax
         tc
         td
         technology
         tel
         tf
         tg
         th
         tienda
         tips
         tirol
         tj
         tk
         tl
         tm
         tn
         to
         today
         tokyo
         tools
         town
         toys
         tp
         tr
         trade
         training
         travel
         tt
         tv
         tw
         tz
         ua
         ug
         uk
         um
         university
         uno
         us
         uy
         uz
         va
         vacations
         vc
         ve
         vegas
         ventures
         versicherung
         vet
         vg
         vi
         viajes
         villas
         vision
         vlaanderen
         vn
         vodka
         vote
         voting
         voto
         voyage
         vu
         wang
         watch
         webcam
         website
         wed
         wf
         wien
         wiki
         works
         ws
         wtc
         wtf
         测试
            परीक्षा
         集团
         在线
         한국
          ভারত
         موقع
          বাংলা
         公益
         公司
         移动
         我爱你
         москва
         испытание
         қаз
         онлайн
         сайт
         срб
         테스트
         орг
         삼성
           சிங்கப்பூர்
         商标
         商城
         дети
         мкд
         טעסט
         中文网
         中信
         中国
         中國
                      భారత్
                ලංකා
         測試
                 ભારત
            भारत
         آزمایشی
            பரிட்சை
            संगठन
         网络
         укр
         香港
         δοκιμή
         إختبار
         台湾
         台灣
         мон
         الجزائر
         عمان
         ایران
         امارات
         بازار
         پاکستان
         الاردن
         بھارت
         المغرب
         السعودية
         سودان
         مليسيا
         شبكة
         გე
         机构
         组织机构
                      ไทย
         سورية
         рф
         تونس
         みんな
         世界
                      ਭਾਰਤ
         网址
         游戏
         مصر
         قطر
           இலங்கை
           இந்தியா
         新加坡
         فلسطين
         テスト
         政务
         xxx
         xyz
         yachts
         ye
         yokohama
         yt
         za
         zm
         zone
         zw
     );
     
     return qr/(?:$plain)/i;
 }
 
 =head1 AUTHOR
 
 Original code by Roderick Schertler <roderick@argon.org>, adapted by
 Michael G Schwern <schwern@pobox.com>.
 
 Currently maintained by Roderick Schertler <roderick@argon.org>.
 
 =head1 SEE ALSO
 
   L<URI::Find>
 
 =cut
 
 1;
### URI/Heuristic.pm ###
 package URI::Heuristic;
 
 =head1 NAME
 
 URI::Heuristic - Expand URI using heuristics
 
 =head1 SYNOPSIS
 
  use URI::Heuristic qw(uf_uristr);
  $u = uf_uristr("perl");             # http://www.perl.com
  $u = uf_uristr("www.sol.no/sol");   # http://www.sol.no/sol
  $u = uf_uristr("aas");              # http://www.aas.no
  $u = uf_uristr("ftp.funet.fi");     # ftp://ftp.funet.fi
  $u = uf_uristr("/etc/passwd");      # file:/etc/passwd
 
 =head1 DESCRIPTION
 
 This module provides functions that expand strings into real absolute
 URIs using some built-in heuristics.  Strings that already represent
 absolute URIs (i.e. that start with a C<scheme:> part) are never modified
 and are returned unchanged.  The main use of these functions is to
 allow abbreviated URIs similar to what many web browsers allow for URIs
 typed in by the user.
 
 The following functions are provided:
 
 =over 4
 
 =item uf_uristr($str)
 
 Tries to make the argument string
 into a proper absolute URI string.  The "uf_" prefix stands for "User 
 Friendly".  Under MacOS, it assumes that any string with a common URL 
 scheme (http, ftp, etc.) is a URL rather than a local path.  So don't name 
 your volumes after common URL schemes and expect uf_uristr() to construct 
 valid file: URL's on those volumes for you, because it won't.
 
 =item uf_uri($str)
 
 Works the same way as uf_uristr() but
 returns a C<URI> object.
 
 =back
 
 =head1 ENVIRONMENT
 
 If the hostname portion of a URI does not contain any dots, then
 certain qualified guesses are made.  These guesses are governed by
 the following environment variables:
 
 =over 10
 
 =item COUNTRY
 
 The two-letter country code (ISO 3166) for your location.  If
 the domain name of your host ends with two letters, then it is taken
 to be the default country. See also L<Locale::Country>.
 
 =item HTTP_ACCEPT_LANGUAGE, LC_ALL, LANG
 
 If COUNTRY is not set, these standard environment variables are
 examined and country (not language) information possibly found in them
 is used as the default country.
 
 =item URL_GUESS_PATTERN
 
 Contains a space-separated list of URL patterns to try.  The string
 "ACME" is for some reason used as a placeholder for the host name in
 the URL provided.  Example:
 
  URL_GUESS_PATTERN="www.ACME.no www.ACME.se www.ACME.com"
  export URL_GUESS_PATTERN
 
 Specifying URL_GUESS_PATTERN disables any guessing rules based on
 country.  An empty URL_GUESS_PATTERN disables any guessing that
 involves host name lookups.
 
 =back
 
 =head1 COPYRIGHT
 
 Copyright 1997-1998, Gisle Aas
 
 This library is free software; you can redistribute it and/or
 modify it under the same terms as Perl itself.
 
 =cut
 
 use strict;
 use warnings;
 
 use Exporter 5.57 'import';
 our @EXPORT_OK = qw(uf_uri uf_uristr uf_url uf_urlstr);
 our $VERSION = "4.20";
 
 our ($MY_COUNTRY, $DEBUG);
 
 sub MY_COUNTRY() {
     for ($MY_COUNTRY) {
 	return $_ if defined;
 
 	# First try the environment.
 	$_ = $ENV{COUNTRY};
 	return $_ if defined;
 
 	# Try the country part of LC_ALL and LANG from environment
 	my @srcs = ($ENV{LC_ALL}, $ENV{LANG});
 	# ...and HTTP_ACCEPT_LANGUAGE before those if present
 	if (my $httplang = $ENV{HTTP_ACCEPT_LANGUAGE}) {
 	    # TODO: q-value processing/ordering
 	    for $httplang (split(/\s*,\s*/, $httplang)) {
 		if ($httplang =~ /^\s*([a-zA-Z]+)[_-]([a-zA-Z]{2})\s*$/) {
 		    unshift(@srcs, "${1}_${2}");
 		    last;
 		}
 	    }
 	}
 	for (@srcs) {
 	    next unless defined;
 	    return lc($1) if /^[a-zA-Z]+_([a-zA-Z]{2})(?:[.@]|$)/;
 	}
 
 	# Last bit of domain name.  This may access the network.
 	require Net::Domain;
 	my $fqdn = Net::Domain::hostfqdn();
 	$_ = lc($1) if $fqdn =~ /\.([a-zA-Z]{2})$/;
 	return $_ if defined;
 
 	# Give up.  Defined but false.
 	return ($_ = 0);
     }
 }
 
 our %LOCAL_GUESSING =
 (
  'us' => [qw(www.ACME.gov www.ACME.mil)],
  'gb' => [qw(www.ACME.co.uk www.ACME.org.uk www.ACME.ac.uk)],
  'au' => [qw(www.ACME.com.au www.ACME.org.au www.ACME.edu.au)],
  'il' => [qw(www.ACME.co.il www.ACME.org.il www.ACME.net.il)],
  # send corrections and new entries to <gisle@aas.no>
 );
 # Backwards compatibility; uk != United Kingdom in ISO 3166
 $LOCAL_GUESSING{uk} = $LOCAL_GUESSING{gb};
 
 
 sub uf_uristr ($)
 {
     local($_) = @_;
     print STDERR "uf_uristr: resolving $_\n" if $DEBUG;
     return unless defined;
 
     s/^\s+//;
     s/\s+$//;
 
     if (/^(www|web|home)[a-z0-9-]*(?:\.|$)/i) {
 	$_ = "http://$_";
 
     } elsif (/^(ftp|gopher|news|wais|https|http)[a-z0-9-]*(?:\.|$)/i) {
 	$_ = lc($1) . "://$_";
 
     } elsif ($^O ne "MacOS" && 
 	    (m,^/,      ||          # absolute file name
 	     m,^\.\.?/, ||          # relative file name
 	     m,^[a-zA-Z]:[/\\],)    # dosish file name
 	    )
     {
 	$_ = "file:$_";
 
     } elsif ($^O eq "MacOS" && m/:/) {
         # potential MacOS file name
 	unless (m/^(ftp|gopher|news|wais|http|https|mailto):/) {
 	    require URI::file;
 	    my $a = URI::file->new($_)->as_string;
 	    $_ = ($a =~ m/^file:/) ? $a : "file:$a";
 	}
     } elsif (/^\w+([\.\-]\w+)*\@(\w+\.)+\w{2,3}$/) {
 	$_ = "mailto:$_";
 
     } elsif (!/^[a-zA-Z][a-zA-Z0-9.+\-]*:/) {      # no scheme specified
 	if (s/^([-\w]+(?:\.[-\w]+)*)([\/:\?\#]|$)/$2/) {
 	    my $host = $1;
 
 	    my $scheme = "http";
 	    if (/^:(\d+)\b/) {
 		# Some more or less well known ports
 		if ($1 =~ /^[56789]?443$/) {
 		    $scheme = "https";
 		} elsif ($1 eq "21") {
 		    $scheme = "ftp";
 		}
 	    }
 
 	    if ($host !~ /\./ && $host ne "localhost") {
 		my @guess;
 		if (exists $ENV{URL_GUESS_PATTERN}) {
 		    @guess = map { s/\bACME\b/$host/; $_ }
 		             split(' ', $ENV{URL_GUESS_PATTERN});
 		} else {
 		    if (MY_COUNTRY()) {
 			my $special = $LOCAL_GUESSING{MY_COUNTRY()};
 			if ($special) {
 			    my @special = @$special;
 			    push(@guess, map { s/\bACME\b/$host/; $_ }
                                                @special);
 			} else {
 			    push(@guess, "www.$host." . MY_COUNTRY());
 			}
 		    }
 		    push(@guess, map "www.$host.$_",
 			             "com", "org", "net", "edu", "int");
 		}
 
 
 		my $guess;
 		for $guess (@guess) {
 		    print STDERR "uf_uristr: gethostbyname('$guess.')..."
 		      if $DEBUG;
 		    if (gethostbyname("$guess.")) {
 			print STDERR "yes\n" if $DEBUG;
 			$host = $guess;
 			last;
 		    }
 		    print STDERR "no\n" if $DEBUG;
 		}
 	    }
 	    $_ = "$scheme://$host$_";
 
 	} else {
 	    # pure junk, just return it unchanged...
 
 	}
     }
     print STDERR "uf_uristr: ==> $_\n" if $DEBUG;
 
     $_;
 }
 
 sub uf_uri ($)
 {
     require URI;
     URI->new(uf_uristr($_[0]));
 }
 
 # legacy
 *uf_urlstr = \*uf_uristr;
 
 sub uf_url ($)
 {
     require URI::URL;
     URI::URL->new(uf_uristr($_[0]));
 }
 
 1;
### URI/IRI.pm ###
 package URI::IRI;
 
 # Experimental
 
 use strict;
 use warnings;
 use URI ();
 
 use overload '""' => sub { shift->as_string };
 
 our $VERSION = "1.69";
 
 sub new {
     my($class, $uri, $scheme) = @_;
     utf8::upgrade($uri);
     return bless {
 	uri => URI->new($uri, $scheme),
     }, $class;
 }
 
 sub clone {
     my $self = shift;
     return bless {
 	uri => $self->{uri}->clone,
     }, ref($self);
 }
 
 sub as_string {
     my $self = shift;
     return $self->{uri}->as_iri;
 }
 
 our $AUTOLOAD;
 sub AUTOLOAD
 {
     my $method = substr($AUTOLOAD, rindex($AUTOLOAD, '::')+2);
 
     # We create the function here so that it will not need to be
     # autoloaded the next time.
     no strict 'refs';
     *$method = sub { shift->{uri}->$method(@_) };
     goto &$method;
 }
 
 sub DESTROY {}   # avoid AUTOLOADing it
 
 1;
### URI/QueryParam.pm ###
 package URI::QueryParam;
 
 use strict;
 use warnings;
 
 our $VERSION = "1.69";
 
 sub URI::_query::query_param {
     my $self = shift;
     my @old = $self->query_form;
 
     if (@_ == 0) {
 	# get keys
 	my (%seen, $i);
 	return grep !($i++ % 2 || $seen{$_}++), @old;
     }
 
     my $key = shift;
     my @i = grep $_ % 2 == 0 && $old[$_] eq $key, 0 .. $#old;
 
     if (@_) {
 	my @new = @old;
 	my @new_i = @i;
 	my @vals = map { ref($_) eq 'ARRAY' ? @$_ : $_ } @_;
 
 	while (@new_i > @vals) {
 	    splice @new, pop @new_i, 2;
 	}
 	if (@vals > @new_i) {
 	    my $i = @new_i ? $new_i[-1] + 2 : @new;
 	    my @splice = splice @vals, @new_i, @vals - @new_i;
 
 	    splice @new, $i, 0, map { $key => $_ } @splice;
 	}
 	if (@vals) {
 	    #print "SET $new_i[0]\n";
 	    @new[ map $_ + 1, @new_i ] = @vals;
 	}
 
 	$self->query_form(\@new);
     }
 
     return wantarray ? @old[map $_+1, @i] : @i ? $old[$i[0]+1] : undef;
 }
 
 sub URI::_query::query_param_append {
     my $self = shift;
     my $key = shift;
     my @vals = map { ref $_ eq 'ARRAY' ? @$_ : $_ } @_;
     $self->query_form($self->query_form, $key => \@vals);  # XXX
     return;
 }
 
 sub URI::_query::query_param_delete {
     my $self = shift;
     my $key = shift;
     my @old = $self->query_form;
     my @vals;
 
     for (my $i = @old - 2; $i >= 0; $i -= 2) {
 	next if $old[$i] ne $key;
 	push(@vals, (splice(@old, $i, 2))[1]);
     }
     $self->query_form(\@old) if @vals;
     return wantarray ? reverse @vals : $vals[-1];
 }
 
 sub URI::_query::query_form_hash {
     my $self = shift;
     my @old = $self->query_form;
     if (@_) {
 	$self->query_form(@_ == 1 ? %{shift(@_)} : @_);
     }
     my %hash;
     while (my($k, $v) = splice(@old, 0, 2)) {
 	if (exists $hash{$k}) {
 	    for ($hash{$k}) {
 		$_ = [$_] unless ref($_) eq "ARRAY";
 		push(@$_, $v);
 	    }
 	}
 	else {
 	    $hash{$k} = $v;
 	}
     }
     return \%hash;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 URI::QueryParam - Additional query methods for URIs
 
 =head1 SYNOPSIS
 
   use URI;
   use URI::QueryParam;
 
   $u = URI->new("", "http");
   $u->query_param(foo => 1, 2, 3);
   print $u->query;    # prints foo=1&foo=2&foo=3
 
   for my $key ($u->query_param) {
       print "$key: ", join(", ", $u->query_param($key)), "\n";
   }
 
 =head1 DESCRIPTION
 
 Loading the C<URI::QueryParam> module adds some extra methods to
 URIs that support query methods.  These methods provide an alternative
 interface to the $u->query_form data.
 
 The query_param_* methods have deliberately been made identical to the
 interface of the corresponding C<CGI.pm> methods.
 
 The following additional methods are made available:
 
 =over
 
 =item @keys = $u->query_param
 
 =item @values = $u->query_param( $key )
 
 =item $first_value = $u->query_param( $key )
 
 =item $u->query_param( $key, $value,... )
 
 If $u->query_param is called with no arguments, it returns all the
 distinct parameter keys of the URI.  In a scalar context it returns the
 number of distinct keys.
 
 When a $key argument is given, the method returns the parameter values with the
 given key.  In a scalar context, only the first parameter value is
 returned.
 
 If additional arguments are given, they are used to update successive
 parameters with the given key.  If any of the values provided are
 array references, then the array is dereferenced to get the actual
 values.
 
 Please note that you can supply multiple values to this method, but you cannot
 supply multiple keys.
 
 Do this:
 
     $uri->query_param( widget_id => 1, 5, 9 );
 
 Do NOT do this:
 
     $uri->query_param( widget_id => 1, frobnicator_id => 99 );
 
 =item $u->query_param_append($key, $value,...)
 
 Adds new parameters with the given
 key without touching any old parameters with the same key.  It
 can be explained as a more efficient version of:
 
    $u->query_param($key,
                    $u->query_param($key),
                    $value,...);
 
 One difference is that this expression would return the old values
 of $key, whereas the query_param_append() method does not.
 
 =item @values = $u->query_param_delete($key)
 
 =item $first_value = $u->query_param_delete($key)
 
 Deletes all key/value pairs with the given key.
 The old values are returned.  In a scalar context, only the first value
 is returned.
 
 Using the query_param_delete() method is slightly more efficient than
 the equivalent:
 
    $u->query_param($key, []);
 
 =item $hashref = $u->query_form_hash
 
 =item $u->query_form_hash( \%new_form )
 
 Returns a reference to a hash that represents the
 query form's key/value pairs.  If a key occurs multiple times, then the hash
 value becomes an array reference.
 
 Note that sequence information is lost.  This means that:
 
    $u->query_form_hash($u->query_form_hash);
 
 is not necessarily a no-op, as it may reorder the key/value pairs.
 The values returned by the query_param() method should stay the same
 though.
 
 =back
 
 =head1 SEE ALSO
 
 L<URI>, L<CGI>
 
 =head1 COPYRIGHT
 
 Copyright 2002 Gisle Aas.
 
 =cut
### URI/Split.pm ###
 package URI::Split;
 
 use strict;
 use warnings;
 
 our $VERSION = "1.69";
 
 use Exporter 5.57 'import';
 our @EXPORT_OK = qw(uri_split uri_join);
 
 use URI::Escape ();
 
 sub uri_split {
      return $_[0] =~ m,(?:([^:/?#]+):)?(?://([^/?#]*))?([^?#]*)(?:\?([^#]*))?(?:#(.*))?,;
 }
 
 sub uri_join {
     my($scheme, $auth, $path, $query, $frag) = @_;
     my $uri = defined($scheme) ? "$scheme:" : "";
     $path = "" unless defined $path;
     if (defined $auth) {
 	$auth =~ s,([/?\#]), URI::Escape::escape_char($1),eg;
 	$uri .= "//$auth";
 	$path = "/$path" if length($path) && $path !~ m,^/,;
     }
     elsif ($path =~ m,^//,) {
 	$uri .= "//";  # XXX force empty auth
     }
     unless (length $uri) {
 	$path =~ s,(:), URI::Escape::escape_char($1),e while $path =~ m,^[^:/?\#]+:,;
     }
     $path =~ s,([?\#]), URI::Escape::escape_char($1),eg;
     $uri .= $path;
     if (defined $query) {
 	$query =~ s,(\#), URI::Escape::escape_char($1),eg;
 	$uri .= "?$query";
     }
     $uri .= "#$frag" if defined $frag;
     $uri;
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 URI::Split - Parse and compose URI strings
 
 =head1 SYNOPSIS
 
  use URI::Split qw(uri_split uri_join);
  ($scheme, $auth, $path, $query, $frag) = uri_split($uri);
  $uri = uri_join($scheme, $auth, $path, $query, $frag);
 
 =head1 DESCRIPTION
 
 Provides functions to parse and compose URI
 strings.  The following functions are provided:
 
 =over
 
 =item ($scheme, $auth, $path, $query, $frag) = uri_split($uri)
 
 Breaks up a URI string into its component
 parts.  An C<undef> value is returned for those parts that are not
 present.  The $path part is always present (but can be the empty
 string) and is thus never returned as C<undef>.
 
 No sensible value is returned if this function is called in a scalar
 context.
 
 =item $uri = uri_join($scheme, $auth, $path, $query, $frag)
 
 Puts together a URI string from its parts.
 Missing parts are signaled by passing C<undef> for the corresponding
 argument.
 
 Minimal escaping is applied to parts that contain reserved chars
 that would confuse a parser.  For instance, any occurrence of '?' or '#'
 in $path is always escaped, as it would otherwise be parsed back
 as a query or fragment.
 
 =back
 
 =head1 SEE ALSO
 
 L<URI>, L<URI::Escape>
 
 =head1 COPYRIGHT
 
 Copyright 2003, Gisle Aas
 
 This library is free software; you can redistribute it and/or
 modify it under the same terms as Perl itself.
 
 =cut
### URI/URL.pm ###
 package URI::URL;
 
 use strict;
 use warnings;
 
 use parent 'URI::WithBase';
 
 our $VERSION = "5.04";
 
 # Provide as much as possible of the old URI::URL interface for backwards
 # compatibility...
 
 use Exporter 5.57 'import';
 our @EXPORT = qw(url);
 
 # Easy to use constructor
 sub url ($;$) { URI::URL->new(@_); }
 
 use URI::Escape qw(uri_unescape);
 
 sub new
 {
     my $class = shift;
     my $self = $class->SUPER::new(@_);
     $self->[0] = $self->[0]->canonical;
     $self;
 }
 
 sub newlocal
 {
     my $class = shift;
     require URI::file;
     bless [URI::file->new_abs(shift)], $class;
 }
 
 {package URI::_foreign;
     sub _init  # hope it is not defined
     {
 	my $class = shift;
 	die "Unknown URI::URL scheme $_[1]:" if $URI::URL::STRICT;
 	$class->SUPER::_init(@_);
     }
 }
 
 sub strict
 {
     my $old = $URI::URL::STRICT;
     $URI::URL::STRICT = shift if @_;
     $old;
 }
 
 sub print_on
 {
     my $self = shift;
     require Data::Dumper;
     print STDERR Data::Dumper::Dumper($self);
 }
 
 sub _try
 {
     my $self = shift;
     my $method = shift;
     scalar(eval { $self->$method(@_) });
 }
 
 sub crack
 {
     # should be overridden by subclasses
     my $self = shift;
     (scalar($self->scheme),
      $self->_try("user"),
      $self->_try("password"),
      $self->_try("host"),
      $self->_try("port"),
      $self->_try("path"),
      $self->_try("params"),
      $self->_try("query"),
      scalar($self->fragment),
     )
 }
 
 sub full_path
 {
     my $self = shift;
     my $path = $self->path_query;
     $path = "/" unless length $path;
     $path;
 }
 
 sub netloc
 {
     shift->authority(@_);
 }
 
 sub epath
 {
     my $path = shift->SUPER::path(@_);
     $path =~ s/;.*//;
     $path;
 }
 
 sub eparams
 {
     my $self = shift;
     my @p = $self->path_segments;
     return undef unless ref($p[-1]);
     @p = @{$p[-1]};
     shift @p;
     join(";", @p);
 }
 
 sub params { shift->eparams(@_); }
 
 sub path {
     my $self = shift;
     my $old = $self->epath(@_);
     return unless defined wantarray;
     return '/' if !defined($old) || !length($old);
     Carp::croak("Path components contain '/' (you must call epath)")
 	if $old =~ /%2[fF]/ and !@_;
     $old = "/$old" if $old !~ m|^/| && defined $self->netloc;
     return uri_unescape($old);
 }
 
 sub path_components {
     shift->path_segments(@_);
 }
 
 sub query {
     my $self = shift;
     my $old = $self->equery(@_);
     if (defined(wantarray) && defined($old)) {
 	if ($old =~ /%(?:26|2[bB]|3[dD])/) {  # contains escaped '=' '&' or '+'
 	    my $mess;
 	    for ($old) {
 		$mess = "Query contains both '+' and '%2B'"
 		  if /\+/ && /%2[bB]/;
 		$mess = "Form query contains escaped '=' or '&'"
 		  if /=/  && /%(?:3[dD]|26)/;
 	    }
 	    if ($mess) {
 		Carp::croak("$mess (you must call equery)");
 	    }
 	}
 	# Now it should be safe to unescape the string without losing
 	# information
 	return uri_unescape($old);
     }
     undef;
 
 }
 
 sub abs
 {
     my $self = shift;
     my $base = shift;
     my $allow_scheme = shift;
     $allow_scheme = $URI::URL::ABS_ALLOW_RELATIVE_SCHEME
 	unless defined $allow_scheme;
     local $URI::ABS_ALLOW_RELATIVE_SCHEME = $allow_scheme;
     local $URI::ABS_REMOTE_LEADING_DOTS = $URI::URL::ABS_REMOTE_LEADING_DOTS;
     $self->SUPER::abs($base);
 }
 
 sub frag { shift->fragment(@_); }
 sub keywords { shift->query_keywords(@_); }
 
 # file:
 sub local_path { shift->file; }
 sub unix_path  { shift->file("unix"); }
 sub dos_path   { shift->file("dos");  }
 sub mac_path   { shift->file("mac");  }
 sub vms_path   { shift->file("vms");  }
 
 # mailto:
 sub address { shift->to(@_); }
 sub encoded822addr { shift->to(@_); }
 sub URI::mailto::authority { shift->to(@_); }  # make 'netloc' method work
 
 # news:
 sub groupart { shift->_group(@_); }
 sub article  { shift->message(@_); }
 
 1;
 
 __END__
 
 =head1 NAME
 
 URI::URL - Uniform Resource Locators
 
 =head1 SYNOPSIS
 
  $u1 = URI::URL->new($str, $base);
  $u2 = $u1->abs;
 
 =head1 DESCRIPTION
 
 This module is provided for backwards compatibility with modules that
 depend on the interface provided by the C<URI::URL> class that used to
 be distributed with the libwww-perl library.
 
 The following differences exist compared to the C<URI> class interface:
 
 =over 3
 
 =item *
 
 The URI::URL module exports the url() function as an alternate
 constructor interface.
 
 =item *
 
 The constructor takes an optional $base argument.  The C<URI::URL>
 class is a subclass of C<URI::WithBase>.
 
 =item *
 
 The URI::URL->newlocal class method is the same as URI::file->new_abs.
 
 =item *
 
 URI::URL::strict(1)
 
 =item *
 
 $url->print_on method
 
 =item *
 
 $url->crack method
 
 =item *
 
 $url->full_path: same as ($uri->abs_path || "/")
 
 =item *
 
 $url->netloc: same as $uri->authority
 
 =item *
 
 $url->epath, $url->equery: same as $uri->path, $uri->query
 
 =item *
 
 $url->path and $url->query pass unescaped strings.
 
 =item *
 
 $url->path_components: same as $uri->path_segments (if you don't
 consider path segment parameters)
 
 =item *
 
 $url->params and $url->eparams methods
 
 =item *
 
 $url->base method.  See L<URI::WithBase>.
 
 =item *
 
 $url->abs and $url->rel have an optional $base argument.  See
 L<URI::WithBase>.
 
 =item *
 
 $url->frag: same as $uri->fragment
 
 =item *
 
 $url->keywords: same as $uri->query_keywords
 
 =item *
 
 $url->localpath and friends map to $uri->file.
 
 =item *
 
 $url->address and $url->encoded822addr: same as $uri->to for mailto URI
 
 =item *
 
 $url->groupart method for news URI
 
 =item *
 
 $url->article: same as $uri->message
 
 =back
 
 
 
 =head1 SEE ALSO
 
 L<URI>, L<URI::WithBase>
 
 =head1 COPYRIGHT
 
 Copyright 1998-2000 Gisle Aas.
 
 =cut
### URI/WithBase.pm ###
 package URI::WithBase;
 
 use strict;
 use warnings;
 
 use URI;
 use Scalar::Util 'blessed';
 
 our $VERSION = "2.20";
 
 use overload '""' => "as_string", fallback => 1;
 
 sub as_string;  # help overload find it
 
 sub new
 {
     my($class, $uri, $base) = @_;
     my $ibase = $base;
     if ($base && blessed($base) && $base->isa(__PACKAGE__)) {
 	$base = $base->abs;
 	$ibase = $base->[0];
     }
     bless [URI->new($uri, $ibase), $base], $class;
 }
 
 sub new_abs
 {
     my $class = shift;
     my $self = $class->new(@_);
     $self->abs;
 }
 
 sub _init
 {
     my $class = shift;
     my($str, $scheme) = @_;
     bless [URI->new($str, $scheme), undef], $class;
 }
 
 sub eq
 {
     my($self, $other) = @_;
     $other = $other->[0] if blessed($other) and $other->isa(__PACKAGE__);
     $self->[0]->eq($other);
 }
 
 our $AUTOLOAD;
 sub AUTOLOAD
 {
     my $self = shift;
     my $method = substr($AUTOLOAD, rindex($AUTOLOAD, '::')+2);
     return if $method eq "DESTROY";
     $self->[0]->$method(@_);
 }
 
 sub can {                                  # override UNIVERSAL::can
     my $self = shift;
     $self->SUPER::can(@_) || (
       ref($self)
       ? $self->[0]->can(@_)
       : undef
     )
 }
 
 sub base {
     my $self = shift;
     my $base  = $self->[1];
 
     if (@_) { # set
 	my $new_base = shift;
 	# ensure absoluteness
 	$new_base = $new_base->abs if ref($new_base) && $new_base->isa(__PACKAGE__);
 	$self->[1] = $new_base;
     }
     return unless defined wantarray;
 
     # The base attribute supports 'lazy' conversion from URL strings
     # to URL objects. Strings may be stored but when a string is
     # fetched it will automatically be converted to a URL object.
     # The main benefit is to make it much cheaper to say:
     #   URI::WithBase->new($random_url_string, 'http:')
     if (defined($base) && !ref($base)) {
 	$base = ref($self)->new($base);
 	$self->[1] = $base unless @_;
     }
     $base;
 }
 
 sub clone
 {
     my $self = shift;
     my $base = $self->[1];
     $base = $base->clone if ref($base);
     bless [$self->[0]->clone, $base], ref($self);
 }
 
 sub abs
 {
     my $self = shift;
     my $base = shift || $self->base || return $self->clone;
     $base = $base->as_string if ref($base);
     bless [$self->[0]->abs($base, @_), $base], ref($self);
 }
 
 sub rel
 {
     my $self = shift;
     my $base = shift || $self->base || return $self->clone;
     $base = $base->as_string if ref($base);
     bless [$self->[0]->rel($base, @_), $base], ref($self);
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 URI::WithBase - URIs which remember their base
 
 =head1 SYNOPSIS
 
  $u1 = URI::WithBase->new($str, $base);
  $u2 = $u1->abs;
 
  $base = $u1->base;
  $u1->base( $new_base )
 
 =head1 DESCRIPTION
 
 This module provides the C<URI::WithBase> class.  Objects of this class
 are like C<URI> objects, but can keep their base too.  The base
 represents the context where this URI was found and can be used to
 absolutize or relativize the URI.  All the methods described in L<URI>
 are supported for C<URI::WithBase> objects.
 
 The methods provided in addition to or modified from those of C<URI> are:
 
 =over 4
 
 =item $uri = URI::WithBase->new($str, [$base])
 
 The constructor takes an optional base URI as the second argument.
 If provided, this argument initializes the base attribute.
 
 =item $uri->base( [$new_base] )
 
 Can be used to get or set the value of the base attribute.
 The return value, which is the old value, is a URI object or C<undef>.
 
 =item $uri->abs( [$base_uri] )
 
 The $base_uri argument is now made optional as the object carries its
 base with it.  A new object is returned even if $uri is already
 absolute (while plain URI objects simply return themselves in
 that case).
 
 =item $uri->rel( [$base_uri] )
 
 The $base_uri argument is now made optional as the object carries its
 base with it.  A new object is always returned.
 
 =back
 
 
 =head1 SEE ALSO
 
 L<URI>
 
 =head1 COPYRIGHT
 
 Copyright 1998-2002 Gisle Aas.
 
 =cut
### URI/_foreign.pm ###
 package URI::_foreign;
 
 use strict;
 use warnings;
 
 use parent 'URI::_generic';
 
 our $VERSION = "1.69";
 
 1;
### URI/_generic.pm ###
 package URI::_generic;
 
 use strict;
 use warnings;
 
 use parent qw(URI URI::_query);
 
 use URI::Escape qw(uri_unescape);
 use Carp ();
 
 our $VERSION = "1.69";
 
 my $ACHAR = $URI::uric;  $ACHAR =~ s,\\[/?],,g;
 my $PCHAR = $URI::uric;  $PCHAR =~ s,\\[?],,g;
 
 sub _no_scheme_ok { 1 }
 
 sub authority
 {
     my $self = shift;
     $$self =~ m,^((?:$URI::scheme_re:)?)(?://([^/?\#]*))?(.*)$,os or die;
 
     if (@_) {
 	my $auth = shift;
 	$$self = $1;
 	my $rest = $3;
 	if (defined $auth) {
 	    $auth =~ s/([^$ACHAR])/ URI::Escape::escape_char($1)/ego;
 	    utf8::downgrade($auth);
 	    $$self .= "//$auth";
 	}
 	_check_path($rest, $$self);
 	$$self .= $rest;
     }
     $2;
 }
 
 sub path
 {
     my $self = shift;
     $$self =~ m,^((?:[^:/?\#]+:)?(?://[^/?\#]*)?)([^?\#]*)(.*)$,s or die;
 
     if (@_) {
 	$$self = $1;
 	my $rest = $3;
 	my $new_path = shift;
 	$new_path = "" unless defined $new_path;
 	$new_path =~ s/([^$PCHAR])/ URI::Escape::escape_char($1)/ego;
 	utf8::downgrade($new_path);
 	_check_path($new_path, $$self);
 	$$self .= $new_path . $rest;
     }
     $2;
 }
 
 sub path_query
 {
     my $self = shift;
     $$self =~ m,^((?:[^:/?\#]+:)?(?://[^/?\#]*)?)([^\#]*)(.*)$,s or die;
 
     if (@_) {
 	$$self = $1;
 	my $rest = $3;
 	my $new_path = shift;
 	$new_path = "" unless defined $new_path;
 	$new_path =~ s/([^$URI::uric])/ URI::Escape::escape_char($1)/ego;
 	utf8::downgrade($new_path);
 	_check_path($new_path, $$self);
 	$$self .= $new_path . $rest;
     }
     $2;
 }
 
 sub _check_path
 {
     my($path, $pre) = @_;
     my $prefix;
     if ($pre =~ m,/,) {  # authority present
 	$prefix = "/" if length($path) && $path !~ m,^[/?\#],;
     }
     else {
 	if ($path =~ m,^//,) {
 	    Carp::carp("Path starting with double slash is confusing")
 		if $^W;
 	}
 	elsif (!length($pre) && $path =~ m,^[^:/?\#]+:,) {
 	    Carp::carp("Path might look like scheme, './' prepended")
 		if $^W;
 	    $prefix = "./";
 	}
     }
     substr($_[0], 0, 0) = $prefix if defined $prefix;
 }
 
 sub path_segments
 {
     my $self = shift;
     my $path = $self->path;
     if (@_) {
 	my @arg = @_;  # make a copy
 	for (@arg) {
 	    if (ref($_)) {
 		my @seg = @$_;
 		$seg[0] =~ s/%/%25/g;
 		for (@seg) { s/;/%3B/g; }
 		$_ = join(";", @seg);
 	    }
 	    else {
 		 s/%/%25/g; s/;/%3B/g;
 	    }
 	    s,/,%2F,g;
 	}
 	$self->path(join("/", @arg));
     }
     return $path unless wantarray;
     map {/;/ ? $self->_split_segment($_)
              : uri_unescape($_) }
         split('/', $path, -1);
 }
 
 
 sub _split_segment
 {
     my $self = shift;
     require URI::_segment;
     URI::_segment->new(@_);
 }
 
 
 sub abs
 {
     my $self = shift;
     my $base = shift || Carp::croak("Missing base argument");
 
     if (my $scheme = $self->scheme) {
 	return $self unless $URI::ABS_ALLOW_RELATIVE_SCHEME;
 	$base = URI->new($base) unless ref $base;
 	return $self unless $scheme eq $base->scheme;
     }
 
     $base = URI->new($base) unless ref $base;
     my $abs = $self->clone;
     $abs->scheme($base->scheme);
     return $abs if $$self =~ m,^(?:$URI::scheme_re:)?//,o;
     $abs->authority($base->authority);
 
     my $path = $self->path;
     return $abs if $path =~ m,^/,;
 
     if (!length($path)) {
 	my $abs = $base->clone;
 	my $query = $self->query;
 	$abs->query($query) if defined $query;
 	my $fragment = $self->fragment;
 	$abs->fragment($fragment) if defined $fragment;
 	return $abs;
     }
 
     my $p = $base->path;
     $p =~ s,[^/]+$,,;
     $p .= $path;
     my @p = split('/', $p, -1);
     shift(@p) if @p && !length($p[0]);
     my $i = 1;
     while ($i < @p) {
 	#print "$i ", join("/", @p), " ($p[$i])\n";
 	if ($p[$i-1] eq ".") {
 	    splice(@p, $i-1, 1);
 	    $i-- if $i > 1;
 	}
 	elsif ($p[$i] eq ".." && $p[$i-1] ne "..") {
 	    splice(@p, $i-1, 2);
 	    if ($i > 1) {
 		$i--;
 		push(@p, "") if $i == @p;
 	    }
 	}
 	else {
 	    $i++;
 	}
     }
     $p[-1] = "" if @p && $p[-1] eq ".";  # trailing "/."
     if ($URI::ABS_REMOTE_LEADING_DOTS) {
         shift @p while @p && $p[0] =~ /^\.\.?$/;
     }
     $abs->path("/" . join("/", @p));
     $abs;
 }
 
 # The opposite of $url->abs.  Return a URI which is as relative as possible
 sub rel {
     my $self = shift;
     my $base = shift || Carp::croak("Missing base argument");
     my $rel = $self->clone;
     $base = URI->new($base) unless ref $base;
 
     #my($scheme, $auth, $path) = @{$rel}{qw(scheme authority path)};
     my $scheme = $rel->scheme;
     my $auth   = $rel->canonical->authority;
     my $path   = $rel->path;
 
     if (!defined($scheme) && !defined($auth)) {
 	# it is already relative
 	return $rel;
     }
 
     #my($bscheme, $bauth, $bpath) = @{$base}{qw(scheme authority path)};
     my $bscheme = $base->scheme;
     my $bauth   = $base->canonical->authority;
     my $bpath   = $base->path;
 
     for ($bscheme, $bauth, $auth) {
 	$_ = '' unless defined
     }
 
     unless ($scheme eq $bscheme && $auth eq $bauth) {
 	# different location, can't make it relative
 	return $rel;
     }
 
     for ($path, $bpath) {  $_ = "/$_" unless m,^/,; }
 
     # Make it relative by eliminating scheme and authority
     $rel->scheme(undef);
     $rel->authority(undef);
 
     # This loop is based on code from Nicolai Langfeldt <janl@ifi.uio.no>.
     # First we calculate common initial path components length ($li).
     my $li = 1;
     while (1) {
 	my $i = index($path, '/', $li);
 	last if $i < 0 ||
                 $i != index($bpath, '/', $li) ||
 	        substr($path,$li,$i-$li) ne substr($bpath,$li,$i-$li);
 	$li=$i+1;
     }
     # then we nuke it from both paths
     substr($path, 0,$li) = '';
     substr($bpath,0,$li) = '';
 
     if ($path eq $bpath &&
         defined($rel->fragment) &&
         !defined($rel->query)) {
         $rel->path("");
     }
     else {
         # Add one "../" for each path component left in the base path
         $path = ('../' x $bpath =~ tr|/|/|) . $path;
 	$path = "./" if $path eq "";
         $rel->path($path);
     }
 
     $rel;
 }
 
 1;
### URI/_idna.pm ###
 package URI::_idna;
 
 # This module implements the RFCs 3490 (IDNA) and 3491 (Nameprep)
 # based on Python-2.6.4/Lib/encodings/idna.py
 
 use strict;
 use warnings;
 
 use URI::_punycode qw(encode_punycode decode_punycode);
 use Carp qw(croak);
 
 our $VERSION = "1.69";
 
 BEGIN {
   *URI::_idna::_ENV_::JOIN_LEAKS_UTF8_FLAGS = $] < 5.008_003
     ? sub () { 1 }
     : sub () { 0 }
   ;
 }
 
 my $ASCII = qr/^[\x00-\x7F]*\z/;
 
 sub encode {
     my $idomain = shift;
     my @labels = split(/\./, $idomain, -1);
     my @last_empty;
     push(@last_empty, pop @labels) if @labels > 1 && $labels[-1] eq "";
     for (@labels) {
 	$_ = ToASCII($_);
     }
 
     return eval 'join(".", @labels, @last_empty)' if URI::_idna::_ENV_::JOIN_LEAKS_UTF8_FLAGS;
     return join(".", @labels, @last_empty);
 }
 
 sub decode {
     my $domain = shift;
     return join(".", map ToUnicode($_), split(/\./, $domain, -1))
 }
 
 sub nameprep { # XXX real implementation missing
     my $label = shift;
     $label = lc($label);
     return $label;
 }
 
 sub check_size {
     my $label = shift;
     croak "Label empty" if $label eq "";
     croak "Label too long" if length($label) > 63;
     return $label;
 }
 
 sub ToASCII {
     my $label = shift;
     return check_size($label) if $label =~ $ASCII;
 
     # Step 2: nameprep
     $label = nameprep($label);
     # Step 3: UseSTD3ASCIIRules is false
     # Step 4: try ASCII again
     return check_size($label) if $label =~ $ASCII;
 
     # Step 5: Check ACE prefix
     if ($label =~ /^xn--/) {
         croak "Label starts with ACE prefix";
     }
 
     # Step 6: Encode with PUNYCODE
     $label = encode_punycode($label);
 
     # Step 7: Prepend ACE prefix
     $label = "xn--$label";
 
     # Step 8: Check size
     return check_size($label);
 }
 
 sub ToUnicode {
     my $label = shift;
     $label = nameprep($label) unless $label =~ $ASCII;
     return $label unless $label =~ /^xn--/;
     my $result = decode_punycode(substr($label, 4));
     my $label2 = ToASCII($result);
     if (lc($label) ne $label2) {
 	croak "IDNA does not round-trip: '\L$label\E' vs '$label2'";
     }
     return $result;
 }
 
 1;
### URI/_ldap.pm ###
 # Copyright (c) 1998 Graham Barr <gbarr@pobox.com>. All rights reserved.
 # This program is free software; you can redistribute it and/or
 # modify it under the same terms as Perl itself.
 
 package URI::_ldap;
 
 use strict;
 use warnings;
 
 our $VERSION = "1.69";
 
 use URI::Escape qw(uri_unescape);
 
 sub _ldap_elem {
   my $self  = shift;
   my $elem  = shift;
   my $query = $self->query;
   my @bits  = (split(/\?/,defined($query) ? $query : ""),("")x4);
   my $old   = $bits[$elem];
 
   if (@_) {
     my $new = shift;
     $new =~ s/\?/%3F/g;
     $bits[$elem] = $new;
     $query = join("?",@bits);
     $query =~ s/\?+$//;
     $query = undef unless length($query);
     $self->query($query);
   }
 
   $old;
 }
 
 sub dn {
   my $old = shift->path(@_);
   $old =~ s:^/::;
   uri_unescape($old);
 }
 
 sub attributes {
   my $self = shift;
   my $old = _ldap_elem($self,0, @_ ? join(",", map { my $tmp = $_; $tmp =~ s/,/%2C/g; $tmp } @_) : ());
   return $old unless wantarray;
   map { uri_unescape($_) } split(/,/,$old);
 }
 
 sub _scope {
   my $self = shift;
   my $old = _ldap_elem($self,1, @_);
   return undef unless defined wantarray && defined $old;
   uri_unescape($old);
 }
 
 sub scope {
   my $old = &_scope;
   $old = "base" unless length $old;
   $old;
 }
 
 sub _filter {
   my $self = shift;
   my $old = _ldap_elem($self,2, @_);
   return undef unless defined wantarray && defined $old;
   uri_unescape($old); # || "(objectClass=*)";
 }
 
 sub filter {
   my $old = &_filter;
   $old = "(objectClass=*)" unless length $old;
   $old;
 }
 
 sub extensions {
   my $self = shift;
   my @ext;
   while (@_) {
     my $key = shift;
     my $value = shift;
     push(@ext, join("=", map { $_="" unless defined; s/,/%2C/g; $_ } $key, $value));
   }
   @ext = join(",", @ext) if @ext;
   my $old = _ldap_elem($self,3, @ext);
   return $old unless wantarray;
   map { uri_unescape($_) } map { /^([^=]+)=(.*)$/ } split(/,/,$old);
 }
 
 sub canonical
 {
     my $self = shift;
     my $other = $self->_nonldap_canonical;
 
     # The stuff below is not as efficient as one might hope...
 
     $other = $other->clone if $other == $self;
 
     $other->dn(_normalize_dn($other->dn));
 
     # Should really know about mixed case "postalAddress", etc...
     $other->attributes(map lc, $other->attributes);
 
     # Lowercase scope, remove default
     my $old_scope = $other->scope;
     my $new_scope = lc($old_scope);
     $new_scope = "" if $new_scope eq "base";
     $other->scope($new_scope) if $new_scope ne $old_scope;
 
     # Remove filter if default
     my $old_filter = $other->filter;
     $other->filter("") if lc($old_filter) eq "(objectclass=*)" ||
 	                  lc($old_filter) eq "objectclass=*";
 
     # Lowercase extensions types and deal with known extension values
     my @ext = $other->extensions;
     for (my $i = 0; $i < @ext; $i += 2) {
 	my $etype = $ext[$i] = lc($ext[$i]);
 	if ($etype =~ /^!?bindname$/) {
 	    $ext[$i+1] = _normalize_dn($ext[$i+1]);
 	}
     }
     $other->extensions(@ext) if @ext;
     
     $other;
 }
 
 sub _normalize_dn  # RFC 2253
 {
     my $dn = shift;
 
     return $dn;
     # The code below will fail if the "+" or "," is embedding in a quoted
     # string or simply escaped...
 
     my @dn = split(/([+,])/, $dn);
     for (@dn) {
 	s/^([a-zA-Z]+=)/lc($1)/e;
     }
     join("", @dn);
 }
 
 1;
### URI/_login.pm ###
 package URI::_login;
 
 use strict;
 use warnings;
 
 use parent qw(URI::_server URI::_userpass);
 
 our $VERSION = "1.69";
 
 # Generic terminal logins.  This is used as a base class for 'telnet',
 # 'tn3270', and 'rlogin' URL schemes.
 
 1;
### URI/_punycode.pm ###
 package URI::_punycode;
 
 use strict;
 use warnings;
 
 our $VERSION = "1.69";
 
 use Exporter 'import';
 our @EXPORT = qw(encode_punycode decode_punycode);
 
 use integer;
 
 our $DEBUG = 0;
 
 use constant BASE => 36;
 use constant TMIN => 1;
 use constant TMAX => 26;
 use constant SKEW => 38;
 use constant DAMP => 700;
 use constant INITIAL_BIAS => 72;
 use constant INITIAL_N => 128;
 
 my $Delimiter = chr 0x2D;
 my $BasicRE   = qr/[\x00-\x7f]/;
 
 sub _croak { require Carp; Carp::croak(@_); }
 
 sub digit_value {
     my $code = shift;
     return ord($code) - ord("A") if $code =~ /[A-Z]/;
     return ord($code) - ord("a") if $code =~ /[a-z]/;
     return ord($code) - ord("0") + 26 if $code =~ /[0-9]/;
     return;
 }
 
 sub code_point {
     my $digit = shift;
     return $digit + ord('a') if 0 <= $digit && $digit <= 25;
     return $digit + ord('0') - 26 if 26 <= $digit && $digit <= 36;
     die 'NOT COME HERE';
 }
 
 sub adapt {
     my($delta, $numpoints, $firsttime) = @_;
     $delta = $firsttime ? $delta / DAMP : $delta / 2;
     $delta += $delta / $numpoints;
     my $k = 0;
     while ($delta > ((BASE - TMIN) * TMAX) / 2) {
 	$delta /= BASE - TMIN;
 	$k += BASE;
     }
     return $k + (((BASE - TMIN + 1) * $delta) / ($delta + SKEW));
 }
 
 sub decode_punycode {
     my $code = shift;
 
     my $n      = INITIAL_N;
     my $i      = 0;
     my $bias   = INITIAL_BIAS;
     my @output;
 
     if ($code =~ s/(.*)$Delimiter//o) {
 	push @output, map ord, split //, $1;
 	return _croak('non-basic code point') unless $1 =~ /^$BasicRE*$/o;
     }
 
     while ($code) {
 	my $oldi = $i;
 	my $w    = 1;
     LOOP:
 	for (my $k = BASE; 1; $k += BASE) {
 	    my $cp = substr($code, 0, 1, '');
 	    my $digit = digit_value($cp);
 	    defined $digit or return _croak("invalid punycode input");
 	    $i += $digit * $w;
 	    my $t = ($k <= $bias) ? TMIN
 		: ($k >= $bias + TMAX) ? TMAX : $k - $bias;
 	    last LOOP if $digit < $t;
 	    $w *= (BASE - $t);
 	}
 	$bias = adapt($i - $oldi, @output + 1, $oldi == 0);
 	warn "bias becomes $bias" if $DEBUG;
 	$n += $i / (@output + 1);
 	$i = $i % (@output + 1);
 	splice(@output, $i, 0, $n);
 	warn join " ", map sprintf('%04x', $_), @output if $DEBUG;
 	$i++;
     }
     return join '', map chr, @output;
 }
 
 sub encode_punycode {
     my $input = shift;
     my @input = split //, $input;
 
     my $n     = INITIAL_N;
     my $delta = 0;
     my $bias  = INITIAL_BIAS;
 
     my @output;
     my @basic = grep /$BasicRE/, @input;
     my $h = my $b = @basic;
     push @output, @basic;
     push @output, $Delimiter if $b && $h < @input;
     warn "basic codepoints: (@output)" if $DEBUG;
 
     while ($h < @input) {
 	my $m = min(grep { $_ >= $n } map ord, @input);
 	warn sprintf "next code point to insert is %04x", $m if $DEBUG;
 	$delta += ($m - $n) * ($h + 1);
 	$n = $m;
 	for my $i (@input) {
 	    my $c = ord($i);
 	    $delta++ if $c < $n;
 	    if ($c == $n) {
 		my $q = $delta;
 	    LOOP:
 		for (my $k = BASE; 1; $k += BASE) {
 		    my $t = ($k <= $bias) ? TMIN :
 			($k >= $bias + TMAX) ? TMAX : $k - $bias;
 		    last LOOP if $q < $t;
 		    my $cp = code_point($t + (($q - $t) % (BASE - $t)));
 		    push @output, chr($cp);
 		    $q = ($q - $t) / (BASE - $t);
 		}
 		push @output, chr(code_point($q));
 		$bias = adapt($delta, $h + 1, $h == $b);
 		warn "bias becomes $bias" if $DEBUG;
 		$delta = 0;
 		$h++;
 	    }
 	}
 	$delta++;
 	$n++;
     }
     return join '', @output;
 }
 
 sub min {
     my $min = shift;
     for (@_) { $min = $_ if $_ <= $min }
     return $min;
 }
 
 1;
 __END__
 
 =head1 NAME
 
 URI::_punycode - encodes Unicode string in Punycode
 
 =head1 SYNOPSIS
 
   use URI::_punycode;
   $punycode = encode_punycode($unicode);
   $unicode  = decode_punycode($punycode);
 
 =head1 DESCRIPTION
 
 URI::_punycode is a module to encode / decode Unicode strings into
 Punycode, an efficient encoding of Unicode for use with IDNA.
 
 This module requires Perl 5.6.0 or over to handle UTF8 flagged Unicode
 strings.
 
 =head1 FUNCTIONS
 
 This module exports following functions by default.
 
 =over 4
 
 =item encode_punycode
 
   $punycode = encode_punycode($unicode);
 
 takes Unicode string (UTF8-flagged variable) and returns Punycode
 encoding for it.
 
 =item decode_punycode
 
   $unicode = decode_punycode($punycode)
 
 takes Punycode encoding and returns original Unicode string.
 
 =back
 
 These functions throw exceptions on failure. You can catch 'em via
 C<eval>.
 
 =head1 AUTHOR
 
 Tatsuhiko Miyagawa E<lt>miyagawa@bulknews.netE<gt> is the author of
 IDNA::Punycode v0.02 which was the basis for this module.
 
 This library is free software; you can redistribute it and/or modify
 it under the same terms as Perl itself.
 
 =head1 SEE ALSO
 
 L<IDNA::Punycode>, RFC 3492
 
 =cut
### URI/_query.pm ###
 package URI::_query;
 
 use strict;
 use warnings;
 
 use URI ();
 use URI::Escape qw(uri_unescape);
 
 our $VERSION = "1.69";
 
 sub query
 {
     my $self = shift;
     $$self =~ m,^([^?\#]*)(?:\?([^\#]*))?(.*)$,s or die;
 
     if (@_) {
 	my $q = shift;
 	$$self = $1;
 	if (defined $q) {
 	    $q =~ s/([^$URI::uric])/ URI::Escape::escape_char($1)/ego;
 	    utf8::downgrade($q);
 	    $$self .= "?$q";
 	}
 	$$self .= $3;
     }
     $2;
 }
 
 # Handle ...?foo=bar&bar=foo type of query
 sub query_form {
     my $self = shift;
     my $old = $self->query;
     if (@_) {
         # Try to set query string
         my $delim;
         my $r = $_[0];
         if (ref($r) eq "ARRAY") {
             $delim = $_[1];
             @_ = @$r;
         }
         elsif (ref($r) eq "HASH") {
             $delim = $_[1];
             @_ = map { $_ => $r->{$_} } sort keys %$r;
         }
         $delim = pop if @_ % 2;
 
         my @query;
         while (my($key,$vals) = splice(@_, 0, 2)) {
             $key = '' unless defined $key;
 	    $key =~ s/([;\/?:@&=+,\$\[\]%])/ URI::Escape::escape_char($1)/eg;
 	    $key =~ s/ /+/g;
 	    $vals = [ref($vals) eq "ARRAY" ? @$vals : $vals];
             for my $val (@$vals) {
                 $val = '' unless defined $val;
 		$val =~ s/([;\/?:@&=+,\$\[\]%])/ URI::Escape::escape_char($1)/eg;
                 $val =~ s/ /+/g;
                 push(@query, "$key=$val");
             }
         }
         if (@query) {
             unless ($delim) {
                 $delim = $1 if $old && $old =~ /([&;])/;
                 $delim ||= $URI::DEFAULT_QUERY_FORM_DELIMITER || "&";
             }
             $self->query(join($delim, @query));
         }
         else {
             $self->query(undef);
         }
     }
     return if !defined($old) || !length($old) || !defined(wantarray);
     return unless $old =~ /=/; # not a form
     map { s/\+/ /g; uri_unescape($_) }
          map { /=/ ? split(/=/, $_, 2) : ($_ => '')} split(/[&;]/, $old);
 }
 
 # Handle ...?dog+bones type of query
 sub query_keywords
 {
     my $self = shift;
     my $old = $self->query;
     if (@_) {
         # Try to set query string
 	my @copy = @_;
 	@copy = @{$copy[0]} if @copy == 1 && ref($copy[0]) eq "ARRAY";
 	for (@copy) { s/([;\/?:@&=+,\$\[\]%])/ URI::Escape::escape_char($1)/eg; }
 	$self->query(@copy ? join('+', @copy) : undef);
     }
     return if !defined($old) || !defined(wantarray);
     return if $old =~ /=/;  # not keywords, but a form
     map { uri_unescape($_) } split(/\+/, $old, -1);
 }
 
 # Some URI::URL compatibility stuff
 sub equery { goto &query }
 
 1;
### URI/_segment.pm ###
 package URI::_segment;
 
 # Represents a generic path_segment so that it can be treated as
 # a string too.
 
 use strict;
 use warnings;
 
 use URI::Escape qw(uri_unescape);
 
 use overload '""' => sub { $_[0]->[0] },
              fallback => 1;
 
 our $VERSION = "1.69";
 
 sub new
 {
     my $class = shift;
     my @segment = split(';', shift, -1);
     $segment[0] = uri_unescape($segment[0]);
     bless \@segment, $class;
 }
 
 1;
### URI/_server.pm ###
 package URI::_server;
 
 use strict;
 use warnings;
 
 use parent 'URI::_generic';
 
 use URI::Escape qw(uri_unescape);
 
 our $VERSION = "1.69";
 
 sub _uric_escape {
     my($class, $str) = @_;
     if ($str =~ m,^((?:$URI::scheme_re:)?)//([^/?\#]*)(.*)$,os) {
 	my($scheme, $host, $rest) = ($1, $2, $3);
 	my $ui = $host =~ s/(.*@)// ? $1 : "";
 	my $port = $host =~ s/(:\d+)\z// ? $1 : "";
 	if (_host_escape($host)) {
 	    $str = "$scheme//$ui$host$port$rest";
 	}
     }
     return $class->SUPER::_uric_escape($str);
 }
 
 sub _host_escape {
     return unless $_[0] =~ /[^$URI::uric]/;
     eval {
 	require URI::_idna;
 	$_[0] = URI::_idna::encode($_[0]);
     };
     return 0 if $@;
     return 1;
 }
 
 sub as_iri {
     my $self = shift;
     my $str = $self->SUPER::as_iri;
     if ($str =~ /\bxn--/) {
 	if ($str =~ m,^((?:$URI::scheme_re:)?)//([^/?\#]*)(.*)$,os) {
 	    my($scheme, $host, $rest) = ($1, $2, $3);
 	    my $ui = $host =~ s/(.*@)// ? $1 : "";
 	    my $port = $host =~ s/(:\d+)\z// ? $1 : "";
 	    require URI::_idna;
 	    $host = URI::_idna::decode($host);
 	    $str = "$scheme//$ui$host$port$rest";
 	}
     }
     return $str;
 }
 
 sub userinfo
 {
     my $self = shift;
     my $old = $self->authority;
 
     if (@_) {
 	my $new = $old;
 	$new = "" unless defined $new;
 	$new =~ s/.*@//;  # remove old stuff
 	my $ui = shift;
 	if (defined $ui) {
 	    $ui =~ s/@/%40/g;   # protect @
 	    $new = "$ui\@$new";
 	}
 	$self->authority($new);
     }
     return undef if !defined($old) || $old !~ /(.*)@/;
     return $1;
 }
 
 sub host
 {
     my $self = shift;
     my $old = $self->authority;
     if (@_) {
 	my $tmp = $old;
 	$tmp = "" unless defined $tmp;
 	my $ui = ($tmp =~ /(.*@)/) ? $1 : "";
 	my $port = ($tmp =~ /(:\d+)$/) ? $1 : "";
 	my $new = shift;
 	$new = "" unless defined $new;
 	if (length $new) {
 	    $new =~ s/[@]/%40/g;   # protect @
 	    if ($new =~ /^[^:]*:\d*\z/ || $new =~ /]:\d*\z/) {
 		$new =~ s/(:\d*)\z// || die "Assert";
 		$port = $1;
 	    }
 	    $new = "[$new]" if $new =~ /:/ && $new !~ /^\[/; # IPv6 address
 	    _host_escape($new);
 	}
 	$self->authority("$ui$new$port");
     }
     return undef unless defined $old;
     $old =~ s/.*@//;
     $old =~ s/:\d+$//;          # remove the port
     $old =~ s{^\[(.*)\]$}{$1};  # remove brackets around IPv6 (RFC 3986 3.2.2)
     return uri_unescape($old);
 }
 
 sub ihost
 {
     my $self = shift;
     my $old = $self->host(@_);
     if ($old =~ /(^|\.)xn--/) {
 	require URI::_idna;
 	$old = URI::_idna::decode($old);
     }
     return $old;
 }
 
 sub _port
 {
     my $self = shift;
     my $old = $self->authority;
     if (@_) {
 	my $new = $old;
 	$new =~ s/:\d*$//;
 	my $port = shift;
 	$new .= ":$port" if defined $port;
 	$self->authority($new);
     }
     return $1 if defined($old) && $old =~ /:(\d*)$/;
     return;
 }
 
 sub port
 {
     my $self = shift;
     my $port = $self->_port(@_);
     $port = $self->default_port if !defined($port) || $port eq "";
     $port;
 }
 
 sub host_port
 {
     my $self = shift;
     my $old = $self->authority;
     $self->host(shift) if @_;
     return undef unless defined $old;
     $old =~ s/.*@//;        # zap userinfo
     $old =~ s/:$//;         # empty port should be treated the same a no port
     $old .= ":" . $self->port unless $old =~ /:\d+$/;
     $old;
 }
 
 
 sub default_port { undef }
 
 sub canonical
 {
     my $self = shift;
     my $other = $self->SUPER::canonical;
     my $host = $other->host || "";
     my $port = $other->_port;
     my $uc_host = $host =~ /[A-Z]/;
     my $def_port = defined($port) && ($port eq "" ||
                                       $port == $self->default_port);
     if ($uc_host || $def_port) {
 	$other = $other->clone if $other == $self;
 	$other->host(lc $host) if $uc_host;
 	$other->port(undef)    if $def_port;
     }
     $other;
 }
 
 1;
### URI/_userpass.pm ###
 package URI::_userpass;
 
 use strict;
 use warnings;
 
 use URI::Escape qw(uri_unescape);
 
 our $VERSION = "1.69";
 
 sub user
 {
     my $self = shift;
     my $info = $self->userinfo;
     if (@_) {
 	my $new = shift;
 	my $pass = defined($info) ? $info : "";
 	$pass =~ s/^[^:]*//;
 
 	if (!defined($new) && !length($pass)) {
 	    $self->userinfo(undef);
 	} else {
 	    $new = "" unless defined($new);
 	    $new =~ s/%/%25/g;
 	    $new =~ s/:/%3A/g;
 	    $self->userinfo("$new$pass");
 	}
     }
     return undef unless defined $info;
     $info =~ s/:.*//;
     uri_unescape($info);
 }
 
 sub password
 {
     my $self = shift;
     my $info = $self->userinfo;
     if (@_) {
 	my $new = shift;
 	my $user = defined($info) ? $info : "";
 	$user =~ s/:.*//;
 
 	if (!defined($new) && !length($user)) {
 	    $self->userinfo(undef);
 	} else {
 	    $new = "" unless defined($new);
 	    $new =~ s/%/%25/g;
 	    $self->userinfo("$user:$new");
 	}
     }
     return undef unless defined $info;
     return undef unless $info =~ s/^[^:]*://;
     uri_unescape($info);
 }
 
 1;
### URI/data.pm ###
 package URI::data;  # RFC 2397
 
 use strict;
 use warnings;
 
 use parent 'URI';
 
 our $VERSION = '1.69';
 
 use MIME::Base64 qw(encode_base64 decode_base64);
 use URI::Escape  qw(uri_unescape);
 
 sub media_type
 {
     my $self = shift;
     my $opaque = $self->opaque;
     $opaque =~ /^([^,]*),?/ or die;
     my $old = $1;
     my $base64;
     $base64 = $1 if $old =~ s/(;base64)$//i;
     if (@_) {
 	my $new = shift;
 	$new = "" unless defined $new;
 	$new =~ s/%/%25/g;
 	$new =~ s/,/%2C/g;
 	$base64 = "" unless defined $base64;
 	$opaque =~ s/^[^,]*,?/$new$base64,/;
 	$self->opaque($opaque);
     }
     return uri_unescape($old) if $old;  # media_type can't really be "0"
     "text/plain;charset=US-ASCII";      # default type
 }
 
 sub data
 {
     my $self = shift;
     my($enc, $data) = split(",", $self->opaque, 2);
     unless (defined $data) {
 	$data = "";
 	$enc  = "" unless defined $enc;
     }
     my $base64 = ($enc =~ /;base64$/i);
     if (@_) {
 	$enc =~ s/;base64$//i if $base64;
 	my $new = shift;
 	$new = "" unless defined $new;
 	my $uric_count = _uric_count($new);
 	my $urienc_len = $uric_count + (length($new) - $uric_count) * 3;
 	my $base64_len = int((length($new)+2) / 3) * 4;
 	$base64_len += 7;  # because of ";base64" marker
 	if ($base64_len < $urienc_len || $_[0]) {
 	    $enc .= ";base64";
 	    $new = encode_base64($new, "");
 	} else {
 	    $new =~ s/%/%25/g;
 	}
 	$self->opaque("$enc,$new");
     }
     return unless defined wantarray;
     $data = uri_unescape($data);
     return $base64 ? decode_base64($data) : $data;
 }
 
 # I could not find a better way to interpolate the tr/// chars from
 # a variable.
 my $ENC = $URI::uric;
 $ENC =~ s/%//;
 
 eval <<EOT; die $@ if $@;
 sub _uric_count
 {
     \$_[0] =~ tr/$ENC//;
 }
 EOT
 
 1;
 
 __END__
 
 =head1 NAME
 
 URI::data - URI that contains immediate data
 
 =head1 SYNOPSIS
 
  use URI;
 
  $u = URI->new("data:");
  $u->media_type("image/gif");
  $u->data(scalar(`cat camel.gif`));
  print "$u\n";
  open(XV, "|xv -") and print XV $u->data;
 
 =head1 DESCRIPTION
 
 The C<URI::data> class supports C<URI> objects belonging to the I<data>
 URI scheme.  The I<data> URI scheme is specified in RFC 2397.  It
 allows inclusion of small data items as "immediate" data, as if it had
 been included externally.  Examples:
 
   data:,Perl%20is%20good
 
   data:image/gif;base64,R0lGODdhIAAgAIAAAAAAAPj8+CwAAAAAI
     AAgAAAClYyPqcu9AJyCjtIKc5w5xP14xgeO2tlY3nWcajmZZdeJcG
     Kxrmimms1KMTa1Wg8UROx4MNUq1HrycMjHT9b6xKxaFLM6VRKzI+p
     KS9XtXpcbdun6uWVxJXA8pNPkdkkxhxc21LZHFOgD2KMoQXa2KMWI
     JtnE2KizVUkYJVZZ1nczBxXlFopZBtoJ2diXGdNUymmJdFMAADs=
 
 
 
 C<URI> objects belonging to the data scheme support the common methods
 (described in L<URI>) and the following two scheme-specific methods:
 
 =over 4
 
 =item $uri->media_type( [$new_media_type] )
 
 Can be used to get or set the media type specified in the
 URI.  If no media type is specified, then the default
 C<"text/plain;charset=US-ASCII"> is returned.
 
 =item $uri->data( [$new_data] )
 
 Can be used to get or set the data contained in the URI.
 The data is passed unescaped (in binary form).  The decision about
 whether to base64 encode the data in the URI is taken automatically,
 based on the encoding that produces the shorter URI string.
 
 =back
 
 =head1 SEE ALSO
 
 L<URI>
 
 =head1 COPYRIGHT
 
 Copyright 1995-1998 Gisle Aas.
 
 This library is free software; you can redistribute it and/or
 modify it under the same terms as Perl itself.
 
 =cut
### URI/file.pm ###
 package URI::file;
 
 use strict;
 use warnings;
 
 use parent 'URI::_generic';
 our $VERSION = "4.21";
 
 use URI::Escape qw(uri_unescape);
 
 our $DEFAULT_AUTHORITY = "";
 
 # Map from $^O values to implementation classes.  The Unix
 # class is the default.
 our %OS_CLASS = (
      os2     => "OS2",
      mac     => "Mac",
      MacOS   => "Mac",
      MSWin32 => "Win32",
      win32   => "Win32",
      msdos   => "FAT",
      dos     => "FAT",
      qnx     => "QNX",
 );
 
 sub os_class
 {
     my($OS) = shift || $^O;
 
     my $class = "URI::file::" . ($OS_CLASS{$OS} || "Unix");
     no strict 'refs';
     unless (%{"$class\::"}) {
 	eval "require $class";
 	die $@ if $@;
     }
     $class;
 }
 
 sub host { uri_unescape(shift->authority(@_)) }
 
 sub new
 {
     my($class, $path, $os) = @_;
     os_class($os)->new($path);
 }
 
 sub new_abs
 {
     my $class = shift;
     my $file = $class->new(@_);
     return $file->abs($class->cwd) unless $$file =~ /^file:/;
     $file;
 }
 
 sub cwd
 {
     my $class = shift;
     require Cwd;
     my $cwd = Cwd::cwd();
     $cwd = VMS::Filespec::unixpath($cwd) if $^O eq 'VMS';
     $cwd = $class->new($cwd);
     $cwd .= "/" unless substr($cwd, -1, 1) eq "/";
     $cwd;
 }
 
 sub canonical {
     my $self = shift;
     my $other = $self->SUPER::canonical;
 
     my $scheme = $other->scheme;
     my $auth = $other->authority;
     return $other if !defined($scheme) && !defined($auth);  # relative
 
     if (!defined($auth) ||
 	$auth eq "" ||
 	lc($auth) eq "localhost" ||
 	(defined($DEFAULT_AUTHORITY) && lc($auth) eq lc($DEFAULT_AUTHORITY))
        )
     {
 	# avoid cloning if $auth already match
 	if ((defined($auth) || defined($DEFAULT_AUTHORITY)) &&
 	    (!defined($auth) || !defined($DEFAULT_AUTHORITY) || $auth ne $DEFAULT_AUTHORITY)
 	   )
 	{
 	    $other = $other->clone if $self == $other;
 	    $other->authority($DEFAULT_AUTHORITY);
         }
     }
 
     $other;
 }
 
 sub file
 {
     my($self, $os) = @_;
     os_class($os)->file($self);
 }
 
 sub dir
 {
     my($self, $os) = @_;
     os_class($os)->dir($self);
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 URI::file - URI that maps to local file names
 
 =head1 SYNOPSIS
 
  use URI::file;
  
  $u1 = URI->new("file:/foo/bar");
  $u2 = URI->new("foo/bar", "file");
  
  $u3 = URI::file->new($path);
  $u4 = URI::file->new("c:\\windows\\", "win32");
  
  $u1->file;
  $u1->file("mac");
 
 =head1 DESCRIPTION
 
 The C<URI::file> class supports C<URI> objects belonging to the I<file>
 URI scheme.  This scheme allows us to map the conventional file names
 found on various computer systems to the URI name space.  An old
 specification of the I<file> URI scheme is found in RFC 1738.  Some
 older background information is also in RFC 1630. There are no newer
 specifications as far as I know.
 
 If you simply want to construct I<file> URI objects from URI strings,
 use the normal C<URI> constructor.  If you want to construct I<file>
 URI objects from the actual file names used by various systems, then
 use one of the following C<URI::file> constructors:
 
 =over 4
 
 =item $u = URI::file->new( $filename, [$os] )
 
 Maps a file name to the I<file:> URI name space, creates a URI object
 and returns it.  The $filename is interpreted as belonging to the
 indicated operating system ($os), which defaults to the value of the
 $^O variable.  The $filename can be either absolute or relative, and
 the corresponding type of URI object for $os is returned.
 
 =item $u = URI::file->new_abs( $filename, [$os] )
 
 Same as URI::file->new, but makes sure that the URI returned
 represents an absolute file name.  If the $filename argument is
 relative, then the name is resolved relative to the current directory,
 i.e. this constructor is really the same as:
 
   URI::file->new($filename)->abs(URI::file->cwd);
 
 =item $u = URI::file->cwd
 
 Returns a I<file> URI that represents the current working directory.
 See L<Cwd>.
 
 =back
 
 The following methods are supported for I<file> URI (in addition to
 the common and generic methods described in L<URI>):
 
 =over 4
 
 =item $u->file( [$os] )
 
 Returns a file name.  It maps from the URI name space
 to the file name space of the indicated operating system.
 
 It might return C<undef> if the name can not be represented in the
 indicated file system.
 
 =item $u->dir( [$os] )
 
 Some systems use a different form for names of directories than for plain
 files.  Use this method if you know you want to use the name for
 a directory.
 
 =back
 
 The C<URI::file> module can be used to map generic file names to names
 suitable for the current system.  As such, it can work as a nice
 replacement for the C<File::Spec> module.  For instance, the following
 code translates the UNIX-style file name F<Foo/Bar.pm> to a name
 suitable for the local system:
 
   $file = URI::file->new("Foo/Bar.pm", "unix")->file;
   die "Can't map filename Foo/Bar.pm for $^O" unless defined $file;
   open(FILE, $file) || die "Can't open '$file': $!";
   # do something with FILE
 
 =head1 MAPPING NOTES
 
 Most computer systems today have hierarchically organized file systems.
 Mapping the names used in these systems to the generic URI syntax
 allows us to work with relative file URIs that behave as they should
 when resolved using the generic algorithm for URIs (specified in RFC
 2396).  Mapping a file name to the generic URI syntax involves mapping
 the path separator character to "/" and encoding any reserved
 characters that appear in the path segments of the file name.  If
 path segments consisting of the strings "." or ".." have a
 different meaning than what is specified for generic URIs, then these
 must be encoded as well.
 
 If the file system has device, volume or drive specifications as
 the root of the name space, then it makes sense to map them to the
 authority field of the generic URI syntax.  This makes sure that
 relative URIs can not be resolved "above" them, i.e. generally how
 relative file names work in those systems.
 
 Another common use of the authority field is to encode the host on which
 this file name is valid.  The host name "localhost" is special and
 generally has the same meaning as a missing or empty authority
 field.  This use is in conflict with using it as a device
 specification, but can often be resolved for device specifications
 having characters not legal in plain host names.
 
 File name to URI mapping in normally not one-to-one.  There are
 usually many URIs that map to any given file name.  For instance, an
 authority of "localhost" maps the same as a URI with a missing or empty
 authority.
 
 Example 1: The Mac classic (Mac OS 9 and earlier) used ":" as path separator,
 but not in the same way as a generic URI. ":foo" was a relative name.  "foo:bar"
 was an absolute name.  Also, path segments could contain the "/" character as well
 as the literal "." or "..".  So the mapping looks like this:
 
   Mac classic           URI
   ----------            -------------------
   :foo:bar     <==>     foo/bar
   :            <==>     ./
   ::foo:bar    <==>     ../foo/bar
   :::          <==>     ../../
   foo:bar      <==>     file:/foo/bar
   foo:bar:     <==>     file:/foo/bar/
   ..           <==>     %2E%2E
   <undef>      <==      /
   foo/         <==      file:/foo%2F
   ./foo.txt    <==      file:/.%2Ffoo.txt
 
 Note that if you want a relative URL, you *must* begin the path with a :.  Any
 path that begins with [^:] is treated as absolute.
 
 Example 2: The UNIX file system is easy to map, as it uses the same path
 separator as URIs, has a single root, and segments of "." and ".."
 have the same meaning.  URIs that have the character "\0" or "/" as
 part of any path segment can not be turned into valid UNIX file names.
 
   UNIX                  URI
   ----------            ------------------
   foo/bar      <==>     foo/bar
   /foo/bar     <==>     file:/foo/bar
   /foo/bar     <==      file://localhost/foo/bar
   file:         ==>     ./file:
   <undef>      <==      file:/fo%00/bar
   /            <==>     file:/
 
 =cut
 
 
 RFC 1630
 
    [...]
 
    There is clearly a danger of confusion that a link made to a local
    file should be followed by someone on a different system, with
    unexpected and possibly harmful results.  Therefore, the convention
    is that even a "file" URL is provided with a host part.  This allows
    a client on another system to know that it cannot access the file
    system, or perhaps to use some other local mechanism to access the
    file.
 
    The special value "localhost" is used in the host field to indicate
    that the filename should really be used on whatever host one is.
    This for example allows links to be made to files which are
    distributed on many machines, or to "your unix local password file"
    subject of course to consistency across the users of the data.
 
    A void host field is equivalent to "localhost".
 
 =head1 CONFIGURATION VARIABLES
 
 The following configuration variables influence how the class and its
 methods behave:
 
 =over
 
 =item %URI::file::OS_CLASS
 
 This hash maps OS identifiers to implementation classes.  You might
 want to add or modify this if you want to plug in your own file
 handler class.  Normally the keys should match the $^O values in use.
 
 If there is no mapping then the "Unix" implementation is used.
 
 =item $URI::file::DEFAULT_AUTHORITY
 
 This determine what "authority" string to include in absolute file
 URIs.  It defaults to "".  If you prefer verbose URIs you might set it
 to be "localhost".
 
 Setting this value to C<undef> force behaviour compatible to URI v1.31
 and earlier.  In this mode host names in UNC paths and drive letters
 are mapped to the authority component on Windows, while we produce
 authority-less URIs on Unix.
 
 =back
 
 
 =head1 SEE ALSO
 
 L<URI>, L<File::Spec>, L<perlport>
 
 =head1 COPYRIGHT
 
 Copyright 1995-1998,2004 Gisle Aas.
 
 This library is free software; you can redistribute it and/or
 modify it under the same terms as Perl itself.
 
 =cut
### URI/file/Base.pm ###
 package URI::file::Base;
 
 use strict;
 use warnings;
 
 use URI::Escape qw();
 
 our $VERSION = "1.69";
 
 sub new
 {
     my $class = shift;
     my $path  = shift;
     $path = "" unless defined $path;
 
     my($auth, $escaped_auth, $escaped_path);
 
     ($auth, $escaped_auth) = $class->_file_extract_authority($path);
     ($path, $escaped_path) = $class->_file_extract_path($path);
 
     if (defined $auth) {
 	$auth =~ s,%,%25,g unless $escaped_auth;
 	$auth =~ s,([/?\#]), URI::Escape::escape_char($1),eg;
 	$auth = "//$auth";
 	if (defined $path) {
 	    $path = "/$path" unless substr($path, 0, 1) eq "/";
 	} else {
 	    $path = "";
 	}
     } else {
 	return undef unless defined $path;
 	$auth = "";
     }
 
     $path =~ s,([%;?]), URI::Escape::escape_char($1),eg unless $escaped_path;
     $path =~ s/\#/%23/g;
 
     my $uri = $auth . $path;
     $uri = "file:$uri" if substr($uri, 0, 1) eq "/";
 
     URI->new($uri, "file");
 }
 
 sub _file_extract_authority
 {
     my($class, $path) = @_;
     return undef unless $class->_file_is_absolute($path);
     return $URI::file::DEFAULT_AUTHORITY;
 }
 
 sub _file_extract_path
 {
     return undef;
 }
 
 sub _file_is_absolute
 {
     return 0;
 }
 
 sub _file_is_localhost
 {
     shift; # class
     my $host = lc(shift);
     return 1 if $host eq "localhost";
     eval {
 	require Net::Domain;
 	lc(Net::Domain::hostfqdn()) eq $host ||
 	lc(Net::Domain::hostname()) eq $host;
     };
 }
 
 sub file
 {
     undef;
 }
 
 sub dir
 {
     my $self = shift;
     $self->file(@_);
 }
 
 1;
### URI/file/FAT.pm ###
 package URI::file::FAT;
 
 use strict;
 use warnings;
 
 use parent 'URI::file::Win32';
 
 our $VERSION = "1.69";
 
 sub fix_path
 {
     shift; # class
     for (@_) {
 	# turn it into 8.3 names
 	my @p = map uc, split(/\./, $_, -1);
 	return if @p > 2;     # more than 1 dot is not allowed
 	@p = ("") unless @p;  # split bug? (returns nothing when splitting "")
 	$_ = substr($p[0], 0, 8);
         if (@p > 1) {
 	    my $ext = substr($p[1], 0, 3);
 	    $_ .= ".$ext" if length $ext;
 	}
     }
     1;  # ok
 }
 
 1;
### URI/file/Mac.pm ###
 package URI::file::Mac;
 
 use strict;
 use warnings;
 
 use parent 'URI::file::Base';
 
 use URI::Escape qw(uri_unescape);
 
 our $VERSION = "1.69";
 
 sub _file_extract_path
 {
     my $class = shift;
     my $path = shift;
 
     my @pre;
     if ($path =~ s/^(:+)//) {
 	if (length($1) == 1) {
 	    @pre = (".") unless length($path);
 	} else {
 	    @pre = ("..") x (length($1) - 1);
 	}
     } else { #absolute
 	$pre[0] = "";
     }
 
     my $isdir = ($path =~ s/:$//);
     $path =~ s,([%/;]), URI::Escape::escape_char($1),eg;
 
     my @path = split(/:/, $path, -1);
     for (@path) {
 	if ($_ eq "." || $_ eq "..") {
 	    $_ = "%2E" x length($_);
 	}
 	$_ = ".." unless length($_);
     }
     push (@path,"") if $isdir;
     (join("/", @pre, @path), 1);
 }
 
 
 sub file
 {
     my $class = shift;
     my $uri = shift;
     my @path;
 
     my $auth = $uri->authority;
     if (defined $auth) {
 	if (lc($auth) ne "localhost" && $auth ne "") {
 	    my $u_auth = uri_unescape($auth);
 	    if (!$class->_file_is_localhost($u_auth)) {
 		# some other host (use it as volume name)
 		@path = ("", $auth);
 		# XXX or just return to make it illegal;
 	    }
 	}
     }
     my @ps = split("/", $uri->path, -1);
     shift @ps if @path;
     push(@path, @ps);
 
     my $pre = "";
     if (!@path) {
 	return;  # empty path; XXX return ":" instead?
     } elsif ($path[0] eq "") {
 	# absolute
 	shift(@path);
 	if (@path == 1) {
 	    return if $path[0] eq "";  # not root directory
 	    push(@path, "");           # volume only, effectively append ":"
 	}
 	@ps = @path;
 	@path = ();
         my $part;
 	for (@ps) {  #fix up "." and "..", including interior, in relatives
 	    next if $_ eq ".";
 	    $part = $_ eq ".." ? "" : $_;
 	    push(@path,$part);
 	}
 	if ($ps[-1] eq "..") {  #if this happens, we need another :
 	    push(@path,"");
 	}
 	
     } else {
 	$pre = ":";
 	@ps = @path;
 	@path = ();
         my $part;
 	for (@ps) {  #fix up "." and "..", including interior, in relatives
 	    next if $_ eq ".";
 	    $part = $_ eq ".." ? "" : $_;
 	    push(@path,$part);
 	}
 	if ($ps[-1] eq "..") {  #if this happens, we need another :
 	    push(@path,"");
 	}
 	
     }
     return unless $pre || @path;
     for (@path) {
 	s/;.*//;  # get rid of parameters
 	#return unless length; # XXX
 	$_ = uri_unescape($_);
 	return if /\0/;
 	return if /:/;  # Should we?
     }
     $pre . join(":", @path);
 }
 
 sub dir
 {
     my $class = shift;
     my $path = $class->file(@_);
     return unless defined $path;
     $path .= ":" unless $path =~ /:$/;
     $path;
 }
 
 1;
### URI/file/OS2.pm ###
 package URI::file::OS2;
 
 use strict;
 use warnings;
 
 use parent 'URI::file::Win32';
 
 our $VERSION = "1.69";
 
 # The Win32 version translates k:/foo to file://k:/foo  (?!)
 # We add an empty host
 
 sub _file_extract_authority
 {
     my $class = shift;
     return $1 if $_[0] =~ s,^\\\\([^\\]+),,;  # UNC
     return $1 if $_[0] =~ s,^//([^/]+),,;     # UNC too?
 
     if ($_[0] =~ m#^[a-zA-Z]{1,2}:#) {	      # allow for ab: drives
 	return "";
     }
     return;
 }
 
 sub file {
   my $p = &URI::file::Win32::file;
   return unless defined $p;
   $p =~ s,\\,/,g;
   $p;
 }
 
 1;
### URI/file/QNX.pm ###
 package URI::file::QNX;
 
 use strict;
 use warnings;
 
 use parent 'URI::file::Unix';
 
 our $VERSION = "1.69";
 
 sub _file_extract_path
 {
     my($class, $path) = @_;
     # tidy path
     $path =~ s,(.)//+,$1/,g; # ^// is correct
     $path =~ s,(/\.)+/,/,g;
     $path = "./$path" if $path =~ m,^[^:/]+:,,; # look like "scheme:"
     $path;
 }
 
 1;
### URI/file/Unix.pm ###
 package URI::file::Unix;
 
 use strict;
 use warnings;
 
 use parent 'URI::file::Base';
 
 use URI::Escape qw(uri_unescape);
 
 our $VERSION = "1.69";
 
 sub _file_extract_path
 {
     my($class, $path) = @_;
 
     # tidy path
     $path =~ s,//+,/,g;
     $path =~ s,(/\.)+/,/,g;
     $path = "./$path" if $path =~ m,^[^:/]+:,,; # look like "scheme:"
 
     return $path;
 }
 
 sub _file_is_absolute {
     my($class, $path) = @_;
     return $path =~ m,^/,;
 }
 
 sub file
 {
     my $class = shift;
     my $uri = shift;
     my @path;
 
     my $auth = $uri->authority;
     if (defined($auth)) {
 	if (lc($auth) ne "localhost" && $auth ne "") {
 	    $auth = uri_unescape($auth);
 	    unless ($class->_file_is_localhost($auth)) {
 		push(@path, "", "", $auth);
 	    }
 	}
     }
 
     my @ps = $uri->path_segments;
     shift @ps if @path;
     push(@path, @ps);
 
     for (@path) {
 	# Unix file/directory names are not allowed to contain '\0' or '/'
 	return undef if /\0/;
 	return undef if /\//;  # should we really?
     }
 
     return join("/", @path);
 }
 
 1;
### URI/file/Win32.pm ###
 package URI::file::Win32;
 
 use strict;
 use warnings;
 
 use parent 'URI::file::Base';
 
 use URI::Escape qw(uri_unescape);
 
 our $VERSION = "1.69";
 
 sub _file_extract_authority
 {
     my $class = shift;
 
     return $class->SUPER::_file_extract_authority($_[0])
 	if defined $URI::file::DEFAULT_AUTHORITY;
 
     return $1 if $_[0] =~ s,^\\\\([^\\]+),,;  # UNC
     return $1 if $_[0] =~ s,^//([^/]+),,;     # UNC too?
 
     if ($_[0] =~ s,^([a-zA-Z]:),,) {
 	my $auth = $1;
 	$auth .= "relative" if $_[0] !~ m,^[\\/],;
 	return $auth;
     }
     return undef;
 }
 
 sub _file_extract_path
 {
     my($class, $path) = @_;
     $path =~ s,\\,/,g;
     #$path =~ s,//+,/,g;
     $path =~ s,(/\.)+/,/,g;
 
     if (defined $URI::file::DEFAULT_AUTHORITY) {
 	$path =~ s,^([a-zA-Z]:),/$1,;
     }
 
     return $path;
 }
 
 sub _file_is_absolute {
     my($class, $path) = @_;
     return $path =~ m,^[a-zA-Z]:, || $path =~ m,^[/\\],;
 }
 
 sub file
 {
     my $class = shift;
     my $uri = shift;
     my $auth = $uri->authority;
     my $rel; # is filename relative to drive specified in authority
     if (defined $auth) {
         $auth = uri_unescape($auth);
 	if ($auth =~ /^([a-zA-Z])[:|](relative)?/) {
 	    $auth = uc($1) . ":";
 	    $rel++ if $2;
 	} elsif (lc($auth) eq "localhost") {
 	    $auth = "";
 	} elsif (length $auth) {
 	    $auth = "\\\\" . $auth;  # UNC
 	}
     } else {
 	$auth = "";
     }
 
     my @path = $uri->path_segments;
     for (@path) {
 	return undef if /\0/;
 	return undef if /\//;
 	#return undef if /\\/;        # URLs with "\" is not uncommon
     }
     return undef unless $class->fix_path(@path);
 
     my $path = join("\\", @path);
     $path =~ s/^\\// if $rel;
     $path = $auth . $path;
     $path =~ s,^\\([a-zA-Z])[:|],\u$1:,;
 
     return $path;
 }
 
 sub fix_path { 1; }
 
 1;
### URI/ftp.pm ###
 package URI::ftp;
 
 use strict;
 use warnings;
 
 our $VERSION = "1.69";
 
 use parent qw(URI::_server URI::_userpass);
 
 sub default_port { 21 }
 
 sub path { shift->path_query(@_) }  # XXX
 
 sub _user     { shift->SUPER::user(@_);     }
 sub _password { shift->SUPER::password(@_); }
 
 sub user
 {
     my $self = shift;
     my $user = $self->_user(@_);
     $user = "anonymous" unless defined $user;
     $user;
 }
 
 sub password
 {
     my $self = shift;
     my $pass = $self->_password(@_);
     unless (defined $pass) {
 	my $user = $self->user;
 	if ($user eq 'anonymous' || $user eq 'ftp') {
 	    # anonymous ftp login password
             # If there is no ftp anonymous password specified
             # then we'll just use 'anonymous@'
             # We don't try to send the read e-mail address because:
             # - We want to remain anonymous
             # - We want to stop SPAM
             # - We don't want to let ftp sites to discriminate by the user,
             #   host, country or ftp client being used.
 	    $pass = 'anonymous@';
 	}
     }
     $pass;
 }
 
 1;
### URI/gopher.pm ###
 package URI::gopher;  # <draft-murali-url-gopher>, Dec 4, 1996
 
 use strict;
 use warnings;
 
 our $VERSION = "1.69";
 
 use parent 'URI::_server';
 
 use URI::Escape qw(uri_unescape);
 
 #  A Gopher URL follows the common internet scheme syntax as defined in 
 #  section 4.3 of [RFC-URL-SYNTAX]:
 #
 #        gopher://<host>[:<port>]/<gopher-path>
 #
 #  where
 #
 #        <gopher-path> :=  <gopher-type><selector> | 
 #                          <gopher-type><selector>%09<search> |
 #                          <gopher-type><selector>%09<search>%09<gopher+_string>
 #
 #        <gopher-type> := '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7'
 #                         '8' | '9' | '+' | 'I' | 'g' | 'T'
 #
 #        <selector>    := *pchar     Refer to RFC 1808 [4]
 #        <search>      := *pchar
 #        <gopher+_string> := *uchar  Refer to RFC 1738 [3]
 #        
 #  If the optional port is omitted, the port defaults to 70. 
 
 sub default_port { 70 }
 
 sub _gopher_type
 {
     my $self = shift;
     my $path = $self->path_query;
     $path =~ s,^/,,;
     my $gtype = $1 if $path =~ s/^(.)//s;
     if (@_) {
 	my $new_type = shift;
 	if (defined($new_type)) {
 	    Carp::croak("Bad gopher type '$new_type'")
                unless length($new_type) == 1;
 	    substr($path, 0, 0) = $new_type;
 	    $self->path_query($path);
 	} else {
 	    Carp::croak("Can't delete gopher type when selector is present")
 		if length($path);
 	    $self->path_query(undef);
 	}
     }
     return $gtype;
 }
 
 sub gopher_type
 {
     my $self = shift;
     my $gtype = $self->_gopher_type(@_);
     $gtype = "1" unless defined $gtype;
     $gtype;
 }
 
 sub gtype { goto &gopher_type }  # URI::URL compatibility
 
 sub selector { shift->_gfield(0, @_) }
 sub search   { shift->_gfield(1, @_) }
 sub string   { shift->_gfield(2, @_) }
 
 sub _gfield
 {
     my $self = shift;
     my $fno  = shift;
     my $path = $self->path_query;
 
     # not according to spec., but many popular browsers accept
     # gopher URLs with a '?' before the search string.
     $path =~ s/\?/\t/;
     $path = uri_unescape($path);
     $path =~ s,^/,,;
     my $gtype = $1 if $path =~ s,^(.),,s;
     my @path = split(/\t/, $path, 3);
     if (@_) {
 	# modify
 	my $new = shift;
 	$path[$fno] = $new;
 	pop(@path) while @path && !defined($path[-1]);
 	for (@path) { $_="" unless defined }
 	$path = $gtype;
 	$path = "1" unless defined $path;
 	$path .= join("\t", @path);
 	$self->path_query($path);
     }
     $path[$fno];
 }
 
 1;
### URI/http.pm ###
 package URI::http;
 
 use strict;
 use warnings;
 
 our $VERSION = "1.69";
 
 use parent 'URI::_server';
 
 sub default_port { 80 }
 
 sub canonical
 {
     my $self = shift;
     my $other = $self->SUPER::canonical;
 
     my $slash_path = defined($other->authority) &&
         !length($other->path) && !defined($other->query);
 
     if ($slash_path) {
 	$other = $other->clone if $other == $self;
 	$other->path("/");
     }
     $other;
 }
 
 1;
### URI/https.pm ###
 package URI::https;
 
 use strict;
 use warnings;
 
 our $VERSION = "1.69";
 
 use parent 'URI::http';
 
 sub default_port { 443 }
 
 sub secure { 1 }
 
 1;
### URI/ldap.pm ###
 # Copyright (c) 1998 Graham Barr <gbarr@pobox.com>. All rights reserved.
 # This program is free software; you can redistribute it and/or
 # modify it under the same terms as Perl itself.
 
 package URI::ldap;
 
 use strict;
 use warnings;
 
 our $VERSION = "1.69";
 
 use parent qw(URI::_ldap URI::_server);
 
 sub default_port { 389 }
 
 sub _nonldap_canonical {
     my $self = shift;
     $self->URI::_server::canonical(@_);
 }
 
 1;
 
 __END__
 
 =head1 NAME
 
 URI::ldap - LDAP Uniform Resource Locators
 
 =head1 SYNOPSIS
 
   use URI;
 
   $uri = URI->new("ldap:$uri_string");
   $dn     = $uri->dn;
   $filter = $uri->filter;
   @attr   = $uri->attributes;
   $scope  = $uri->scope;
   %extn   = $uri->extensions;
   
   $uri = URI->new("ldap:");  # start empty
   $uri->host("ldap.itd.umich.edu");
   $uri->dn("o=University of Michigan,c=US");
   $uri->attributes(qw(postalAddress));
   $uri->scope('sub');
   $uri->filter('(cn=Babs Jensen)');
   print $uri->as_string,"\n";
 
 =head1 DESCRIPTION
 
 C<URI::ldap> provides an interface to parse an LDAP URI into its
 constituent parts and also to build a URI as described in
 RFC 2255.
 
 =head1 METHODS
 
 C<URI::ldap> supports all the generic and server methods defined by
 L<URI>, plus the following.
 
 Each of the following methods can be used to set or get the value in
 the URI. The values are passed in unescaped form.  None of these
 return undefined values, but elements without a default can be empty.
 If arguments are given, then a new value is set for the given part
 of the URI.
 
 =over 4
 
 =item $uri->dn( [$new_dn] )
 
 Sets or gets the I<Distinguished Name> part of the URI.  The DN
 identifies the base object of the LDAP search.
 
 =item $uri->attributes( [@new_attrs] )
 
 Sets or gets the list of attribute names which are
 returned by the search.
 
 =item $uri->scope( [$new_scope] )
 
 Sets or gets the scope to be used by the search. The value can be one of
 C<"base">, C<"one"> or C<"sub">. If none is given in the URI then the
 return value defaults to C<"base">.
 
 =item $uri->_scope( [$new_scope] )
 
 Same as scope(), but does not default to anything.
 
 =item $uri->filter( [$new_filter] )
 
 Sets or gets the filter to be used by the search. If none is given in
 the URI then the return value defaults to C<"(objectClass=*)">.
 
 =item $uri->_filter( [$new_filter] )
 
 Same as filter(), but does not default to anything.
 
 =item $uri->extensions( [$etype => $evalue,...] )
 
 Sets or gets the extensions used for the search. The list passed should
 be in the form etype1 => evalue1, etype2 => evalue2,... This is also
 the form of list that is returned.
 
 =back
 
 =head1 SEE ALSO
 
 L<http://tools.ietf.org/html/rfc2255>
 
 =head1 AUTHOR
 
 Graham Barr E<lt>F<gbarr@pobox.com>E<gt>
 
 Slightly modified by Gisle Aas to fit into the URI distribution.
 
 =head1 COPYRIGHT
 
 Copyright (c) 1998 Graham Barr. All rights reserved. This program is
 free software; you can redistribute it and/or modify it under the same
 terms as Perl itself.
 
 =cut
### URI/ldapi.pm ###
 package URI::ldapi;
 
 use strict;
 use warnings;
 
 our $VERSION = "1.69";
 
 use parent qw(URI::_ldap URI::_generic);
 
 require URI::Escape;
 
 sub un_path {
     my $self = shift;
     my $old = URI::Escape::uri_unescape($self->authority);
     if (@_) {
 	my $p = shift;
 	$p =~ s/:/%3A/g;
 	$p =~ s/\@/%40/g;
 	$self->authority($p);
     }
     return $old;
 }
 
 sub _nonldap_canonical {
     my $self = shift;
     $self->URI::_generic::canonical(@_);
 }
 
 1;
### URI/ldaps.pm ###
 package URI::ldaps;
 
 use strict;
 use warnings;
 
 our $VERSION = "1.69";
 
 use parent 'URI::ldap';
 
 sub default_port { 636 }
 
 sub secure { 1 }
 
 1;
### URI/mailto.pm ###
 package URI::mailto;  # RFC 2368
 
 use strict;
 use warnings;
 
 our $VERSION = "1.69";
 
 use parent qw(URI URI::_query);
 
 sub to
 {
     my $self = shift;
     my @old = $self->headers;
     if (@_) {
 	my @new = @old;
 	# get rid of any other to: fields
 	for (my $i = 0; $i < @new; $i += 2) {
 	    if (lc($new[$i] || '') eq "to") {
 		splice(@new, $i, 2);
 		redo;
 	    }
 	}
 
 	my $to = shift;
 	$to = "" unless defined $to;
 	unshift(@new, "to" => $to);
 	$self->headers(@new);
     }
     return unless defined wantarray;
 
     my @to;
     while (@old) {
 	my $h = shift @old;
 	my $v = shift @old;
 	push(@to, $v) if lc($h) eq "to";
     }
     join(",", @to);
 }
 
 
 sub headers
 {
     my $self = shift;
 
     # The trick is to just treat everything as the query string...
     my $opaque = "to=" . $self->opaque;
     $opaque =~ s/\?/&/;
 
     if (@_) {
 	my @new = @_;
 
 	# strip out any "to" fields
 	my @to;
 	for (my $i=0; $i < @new; $i += 2) {
 	    if (lc($new[$i] || '') eq "to") {
 		push(@to, (splice(@new, $i, 2))[1]);  # remove header
 		redo;
 	    }
 	}
 
 	my $new = join(",",@to);
 	$new =~ s/%/%25/g;
 	$new =~ s/\?/%3F/g;
 	$self->opaque($new);
 	$self->query_form(@new) if @new;
     }
     return unless defined wantarray;
 
     # I am lazy today...
     URI->new("mailto:?$opaque")->query_form;
 }
 
 1;
### URI/mms.pm ###
 package URI::mms;
 
 use strict;
 use warnings;
 
 our $VERSION = "1.69";
 
 use parent 'URI::http';
 
 sub default_port { 1755 }
 
 1;
### URI/news.pm ###
 package URI::news;  # draft-gilman-news-url-01
 
 use strict;
 use warnings;
 
 our $VERSION = "1.69";
 
 use parent 'URI::_server';
 
 use URI::Escape qw(uri_unescape);
 use Carp ();
 
 sub default_port { 119 }
 
 #   newsURL      =  scheme ":" [ news-server ] [ refbygroup | message ]
 #   scheme       =  "news" | "snews" | "nntp"
 #   news-server  =  "//" server "/"
 #   refbygroup   = group [ "/" messageno [ "-" messageno ] ]
 #   message      = local-part "@" domain
 
 sub _group
 {
     my $self = shift;
     my $old = $self->path;
     if (@_) {
 	my($group,$from,$to) = @_;
 	if ($group =~ /\@/) {
             $group =~ s/^<(.*)>$/$1/;  # "<" and ">" should not be part of it
 	}
 	$group =~ s,%,%25,g;
 	$group =~ s,/,%2F,g;
 	my $path = $group;
 	if (defined $from) {
 	    $path .= "/$from";
 	    $path .= "-$to" if defined $to;
 	}
 	$self->path($path);
     }
 
     $old =~ s,^/,,;
     if ($old !~ /\@/ && $old =~ s,/(.*),, && wantarray) {
 	my $extra = $1;
 	return (uri_unescape($old), split(/-/, $extra));
     }
     uri_unescape($old);
 }
 
 
 sub group
 {
     my $self = shift;
     if (@_) {
 	Carp::croak("Group name can't contain '\@'") if $_[0] =~ /\@/;
     }
     my @old = $self->_group(@_);
     return if $old[0] =~ /\@/;
     wantarray ? @old : $old[0];
 }
 
 sub message
 {
     my $self = shift;
     if (@_) {
 	Carp::croak("Message must contain '\@'") unless $_[0] =~ /\@/;
     }
     my $old = $self->_group(@_);
     return undef unless $old =~ /\@/;
     return $old;
 }
 
 1;
### URI/nntp.pm ###
 package URI::nntp;  # draft-gilman-news-url-01
 
 use strict;
 use warnings;
 
 our $VERSION = "1.69";
 
 use parent 'URI::news';
 
 1;
### URI/pop.pm ###
 package URI::pop;   # RFC 2384
 
 use strict;
 use warnings;
 
 our $VERSION = "1.69";
 
 use parent 'URI::_server';
 
 use URI::Escape qw(uri_unescape);
 
 sub default_port { 110 }
 
 #pop://<user>;auth=<auth>@<host>:<port>
 
 sub user
 {
     my $self = shift;
     my $old = $self->userinfo;
 
     if (@_) {
 	my $new_info = $old;
 	$new_info = "" unless defined $new_info;
 	$new_info =~ s/^[^;]*//;
 
 	my $new = shift;
 	if (!defined($new) && !length($new_info)) {
 	    $self->userinfo(undef);
 	} else {
 	    $new = "" unless defined $new;
 	    $new =~ s/%/%25/g;
 	    $new =~ s/;/%3B/g;
 	    $self->userinfo("$new$new_info");
 	}
     }
 
     return undef unless defined $old;
     $old =~ s/;.*//;
     return uri_unescape($old);
 }
 
 sub auth
 {
     my $self = shift;
     my $old = $self->userinfo;
 
     if (@_) {
 	my $new = $old;
 	$new = "" unless defined $new;
 	$new =~ s/(^[^;]*)//;
 	my $user = $1;
 	$new =~ s/;auth=[^;]*//i;
 
 	
 	my $auth = shift;
 	if (defined $auth) {
 	    $auth =~ s/%/%25/g;
 	    $auth =~ s/;/%3B/g;
 	    $new = ";AUTH=$auth$new";
 	}
 	$self->userinfo("$user$new");
 	
     }
 
     return undef unless defined $old;
     $old =~ s/^[^;]*//;
     return uri_unescape($1) if $old =~ /;auth=(.*)/i;
     return;
 }
 
 1;
### URI/rlogin.pm ###
 package URI::rlogin;
 
 use strict;
 use warnings;
 
 our $VERSION = "1.69";
 
 use parent 'URI::_login';
 
 sub default_port { 513 }
 
 1;
### URI/rsync.pm ###
 package URI::rsync;  # http://rsync.samba.org/
 
 # rsync://[USER@]HOST[:PORT]/SRC
 
 use strict;
 use warnings;
 
 our $VERSION = "1.69";
 
 use parent qw(URI::_server URI::_userpass);
 
 sub default_port { 873 }
 
 1;
### URI/rtsp.pm ###
 package URI::rtsp;
 
 use strict;
 use warnings;
 
 our $VERSION = "1.69";
 
 use parent 'URI::http';
 
 sub default_port { 554 }
 
 1;
### URI/rtspu.pm ###
 package URI::rtspu;
 
 use strict;
 use warnings;
 
 our $VERSION = "1.69";
 
 use parent 'URI::rtsp';
 
 sub default_port { 554 }
 
 1;
### URI/sftp.pm ###
 package URI::sftp;
 
 use strict;
 use warnings;
 
 use parent 'URI::ssh';
 
 our $VERSION = "1.69";
 
 1;
### URI/sip.pm ###
 #
 # Written by Ryan Kereliuk <ryker@ryker.org>.  This file may be
 # distributed under the same terms as Perl itself.
 #
 # The RFC 3261 sip URI is <scheme>:<authority>;<params>?<query>.
 #
 
 package URI::sip;
 
 use strict;
 use warnings;
 
 use parent qw(URI::_server URI::_userpass);
 
 use URI::Escape qw(uri_unescape);
 
 our $VERSION = "1.69";
 
 sub default_port { 5060 }
 
 sub authority
 {
     my $self = shift;
     $$self =~ m,^($URI::scheme_re:)?([^;?]*)(.*)$,os or die;
     my $old = $2;
 
     if (@_) {
         my $auth = shift;
         $$self = defined($1) ? $1 : "";
         my $rest = $3;
         if (defined $auth) {
             $auth =~ s/([^$URI::uric])/ URI::Escape::escape_char($1)/ego;
             $$self .= "$auth";
         }
         $$self .= $rest;
     }
     $old;
 }
 
 sub params_form
 {
     my $self = shift;
     $$self =~ m,^((?:$URI::scheme_re:)?)(?:([^;?]*))?(;[^?]*)?(.*)$,os or die;
     my $paramstr = $3;
 
     if (@_) {
     	my @args = @_; 
         $$self = $1 . $2;
         my $rest = $4;
 	my @new;
 	for (my $i=0; $i < @args; $i += 2) {
 	    push(@new, "$args[$i]=$args[$i+1]");
 	}
 	$paramstr = join(";", @new);
 	$$self .= ";" . $paramstr . $rest;
     }
     $paramstr =~ s/^;//o;
     return split(/[;=]/, $paramstr);
 }
 
 sub params
 {
     my $self = shift;
     $$self =~ m,^((?:$URI::scheme_re:)?)(?:([^;?]*))?(;[^?]*)?(.*)$,os or die;
     my $paramstr = $3;
 
     if (@_) {
     	my $new = shift; 
         $$self = $1 . $2;
         my $rest = $4;
 	$$self .= $paramstr . $rest;
     }
     $paramstr =~ s/^;//o;
     return $paramstr;
 }
 
 # Inherited methods that make no sense for a SIP URI.
 sub path {}
 sub path_query {}
 sub path_segments {}
 sub abs { shift }
 sub rel { shift }
 sub query_keywords {}
 
 1;
### URI/sips.pm ###
 package URI::sips;
 
 use strict;
 use warnings;
 
 our $VERSION = "1.69";
 
 use parent 'URI::sip';
 
 sub default_port { 5061 }
 
 sub secure { 1 }
 
 1;
### URI/snews.pm ###
 package URI::snews;  # draft-gilman-news-url-01
 
 use strict;
 use warnings;
 
 our $VERSION = "1.69";
 
 use parent 'URI::news';
 
 sub default_port { 563 }
 
 sub secure { 1 }
 
 1;
### URI/ssh.pm ###
 package URI::ssh;
 
 use strict;
 use warnings;
 
 our $VERSION = "1.69";
 
 use parent 'URI::_login';
 
 # ssh://[USER@]HOST[:PORT]/SRC
 
 sub default_port { 22 }
 
 sub secure { 1 }
 
 1;
### URI/telnet.pm ###
 package URI::telnet;
 
 use strict;
 use warnings;
 
 our $VERSION = "1.69";
 
 use parent 'URI::_login';
 
 sub default_port { 23 }
 
 1;
### URI/tn3270.pm ###
 package URI::tn3270;
 
 use strict;
 use warnings;
 
 our $VERSION = "1.69";
 
 use parent 'URI::_login';
 
 sub default_port { 23 }
 
 1;
### URI/urn.pm ###
 package URI::urn;  # RFC 2141
 
 use strict;
 use warnings;
 
 our $VERSION = "1.69";
 
 use parent 'URI';
 
 use Carp qw(carp);
 
 my %implementor;
 
 sub _init {
     my $class = shift;
     my $self = $class->SUPER::_init(@_);
     my $nid = $self->nid;
 
     my $impclass = $implementor{$nid};
     return $impclass->_urn_init($self, $nid) if $impclass;
 
     $impclass = "URI::urn";
     if ($nid =~ /^[A-Za-z\d][A-Za-z\d\-]*\z/) {
 	my $id = $nid;
 	# make it a legal perl identifier
 	$id =~ s/-/_/g;
 	$id = "_$id" if $id =~ /^\d/;
 
 	$impclass = "URI::urn::$id";
 	no strict 'refs';
 	unless (@{"${impclass}::ISA"}) {
 	    # Try to load it
 	    eval "require $impclass";
 	    die $@ if $@ && $@ !~ /Can\'t locate.*in \@INC/;
 	    $impclass = "URI::urn" unless @{"${impclass}::ISA"};
 	}
     }
     else {
 	carp("Illegal namespace identifier '$nid' for URN '$self'") if $^W;
     }
     $implementor{$nid} = $impclass;
 
     return $impclass->_urn_init($self, $nid);
 }
 
 sub _urn_init {
     my($class, $self, $nid) = @_;
     bless $self, $class;
 }
 
 sub _nid {
     my $self = shift;
     my $opaque = $self->opaque;
     if (@_) {
 	my $v = $opaque;
 	my $new = shift;
 	$v =~ s/[^:]*/$new/;
 	$self->opaque($v);
 	# XXX possible rebless
     }
     $opaque =~ s/:.*//s;
     return $opaque;
 }
 
 sub nid {  # namespace identifier
     my $self = shift;
     my $nid = $self->_nid(@_);
     $nid = lc($nid) if defined($nid);
     return $nid;
 }
 
 sub nss {  # namespace specific string
     my $self = shift;
     my $opaque = $self->opaque;
     if (@_) {
 	my $v = $opaque;
 	my $new = shift;
 	if (defined $new) {
 	    $v =~ s/(:|\z).*/:$new/;
 	}
 	else {
 	    $v =~ s/:.*//s;
 	}
 	$self->opaque($v);
     }
     return undef unless $opaque =~ s/^[^:]*://;
     return $opaque;
 }
 
 sub canonical {
     my $self = shift;
     my $nid = $self->_nid;
     my $new = $self->SUPER::canonical;
     return $new if $nid !~ /[A-Z]/ || $nid =~ /%/;
     $new = $new->clone if $new == $self;
     $new->nid(lc($nid));
     return $new;
 }
 
 1;
### URI/urn/isbn.pm ###
 package URI::urn::isbn;  # RFC 3187
 
 use strict;
 use warnings;
 
 use parent 'URI::urn';
 
 use Carp qw(carp);
 
 BEGIN {
     require Business::ISBN;
     
     local $^W = 0; # don't warn about dev versions, perl5.004 style
     warn "Using Business::ISBN version " . Business::ISBN->VERSION . 
         " which is deprecated.\nUpgrade to Business::ISBN version 2\n"
         if Business::ISBN->VERSION < 2;
     }
     
 sub _isbn {
     my $nss = shift;
     $nss = $nss->nss if ref($nss);
     my $isbn = Business::ISBN->new($nss);
     $isbn = undef if $isbn && !$isbn->is_valid;
     return $isbn;
 }
 
 sub _nss_isbn {
     my $self = shift;
     my $nss = $self->nss(@_);
     my $isbn = _isbn($nss);
     $isbn = $isbn->as_string if $isbn;
     return($nss, $isbn);
 }
 
 sub isbn {
     my $self = shift;
     my $isbn;
     (undef, $isbn) = $self->_nss_isbn(@_);
     return $isbn;
 }
 
 sub isbn_publisher_code {
     my $isbn = shift->_isbn || return undef;
     return $isbn->publisher_code;
 }
 
 BEGIN {
 my $group_method = do {
     local $^W = 0; # don't warn about dev versions, perl5.004 style
     Business::ISBN->VERSION >= 2 ? 'group_code' : 'country_code';
     };
 
 sub isbn_group_code {
     my $isbn = shift->_isbn || return undef;
     return $isbn->$group_method;
 }
 }
 
 sub isbn_country_code {
     my $name = (caller(0))[3]; $name =~ s/.*:://;
     carp "$name is DEPRECATED. Use isbn_group_code instead";
     
     no strict 'refs';
     &isbn_group_code;
 }
 
 BEGIN {
 my $isbn13_method = do {
     local $^W = 0; # don't warn about dev versions, perl5.004 style
     Business::ISBN->VERSION >= 2 ? 'as_isbn13' : 'as_ean';
     };
 
 sub isbn13 {
     my $isbn = shift->_isbn || return undef;
     
     # Business::ISBN 1.x didn't put hyphens in the EAN, and it was just a string
     # Business::ISBN 2.0 doesn't do EAN, but it does ISBN-13 objects
     #   and it uses the hyphens, so call as_string with an empty anon array
     # or, adjust the test and features to say that it comes out with hyphens.
     my $thingy = $isbn->$isbn13_method;
     return eval { $thingy->can( 'as_string' ) } ? $thingy->as_string([]) : $thingy;
 }
 }
 
 sub isbn_as_ean {
     my $name = (caller(0))[3]; $name =~ s/.*:://;
     carp "$name is DEPRECATED. Use isbn13 instead";
 
     no strict 'refs';
     &isbn13;
 }
 
 sub canonical {
     my $self = shift;
     my($nss, $isbn) = $self->_nss_isbn;
     my $new = $self->SUPER::canonical;
     return $new unless $nss && $isbn && $nss ne $isbn;
     $new = $new->clone if $new == $self;
     $new->nss($isbn);
     return $new;
 }
 
 1;
### URI/urn/oid.pm ###
 package URI::urn::oid;  # RFC 2061
 
 use strict;
 use warnings;
 
 our $VERSION = "1.69";
 
 use parent 'URI::urn';
 
 sub oid {
     my $self = shift;
     my $old = $self->nss;
     if (@_) {
 	$self->nss(join(".", @_));
     }
     return split(/\./, $old) if wantarray;
     return $old;
 }
 
 1;
### UUID/Random.pm ###
 package UUID::Random;
 
 require 5.006_001;
 use strict;
 use warnings;
 
 
 our $VERSION = '0.04';
 
 sub generate {
   my @chars = ('a'..'f',0..9);
   my @string;
   push(@string, $chars[int(rand(16))]) for(1..32);
   splice(@string,8,0,'-');
   splice(@string,13,0,'-');
   splice(@string,18,0,'-');
   splice(@string,23,0,'-');
   return join('', @string);
 }
 
 1;
 __END__
 
 =head1 NAME
 
 UUID::Random - Generate random uuid strings
 
 =head1 SYNOPSIS
 
   use UUID::Random;
   my $uuid = UUID::Random::generate;
 
 =head1 DESCRIPTION
 
 This module generates random uuid strings. It does not satisfy any of the points listed in RFC 4122 (L<http://tools.ietf.org/html/rfc4122>) but the default format.
 
 
 
 =head1 SEE ALSO
 
 If you need RFC compliant UUID strings have a look at L<Data::UUID>
 
 =head1 AUTHOR
 
 Moritz Onken, E<lt>onken@houseofdesign.deE<gt>
 
 =head1 COPYRIGHT AND LICENSE
 
 Copyright (C) 2008 by Moritz Onken
 
 This library is free software; you can redistribute it and/or modify
 it under the same terms as Perl itself, either Perl version 5.8.8 or,
 at your option, any later version of Perl 5 you may have available.
 
 
 =cut
### Version/Util.pm ###
 package Version::Util;
 
 use 5.010001;
 use strict;
 use version 0.77;
 use warnings;
 
 require Exporter;
 our @ISA = qw(Exporter);
 our @EXPORT_OK = qw(
                        cmp_version
                        version_eq version_ne
                        version_lt version_le version_gt version_ge
                        version_between version_in
                );
 
 our $VERSION = '0.71'; # VERSION
 
 sub cmp_version {
     version->parse($_[0]) <=> version->parse($_[1]);
 }
 
 sub version_eq {
     version->parse($_[0]) == version->parse($_[1]);
 }
 
 sub version_ne {
     version->parse($_[0]) != version->parse($_[1]);
 }
 
 sub version_lt {
     version->parse($_[0]) <  version->parse($_[1]);
 }
 
 sub version_le {
     version->parse($_[0]) <= version->parse($_[1]);
 }
 
 sub version_gt {
     version->parse($_[0]) >  version->parse($_[1]);
 }
 
 sub version_ge {
     version->parse($_[0]) >= version->parse($_[1]);
 }
 
 sub version_between {
     my $v = version->parse(shift);
     while (@_) {
         my $v1 = shift;
         my $v2 = shift;
         return 1 if $v >= version->parse($v1) && $v <= version->parse($v2);
     }
     0;
 }
 
 sub version_in {
     my $v = version->parse(shift);
     for (@_) {
         return 1 if $v == version->parse($_);
     }
     0;
 }
 
 1;
 # ABSTRACT: Version-number utilities
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 Version::Util - Version-number utilities
 
 =head1 VERSION
 
 version 0.71
 
 =head1 DESCRIPTION
 
 This module provides several convenient functions related to version numbers,
 e.g. for comparing them.
 
 =head1 FUNCTIONS
 
 =head2 cmp_version($v1, $v2) => -1|0|1
 
 Equivalent to:
 
  version->parse($v1) <=> version->parse($v2)
 
 =head2 version_eq($v1, $v2) => BOOL
 
 =head2 version_ne($v1, $v2) => BOOL
 
 =head2 version_lt($v1, $v2) => BOOL
 
 =head2 version_le($v1, $v2) => BOOL
 
 =head2 version_gt($v1, $v2) => BOOL
 
 =head2 version_ge($v1, $v2) => BOOL
 
 =head2 version_between($v, $v1, $v2[, $v1b, $v2b, ...]) => BOOL
 
 =head2 version_in($v, $v1[, $v2, ...]) => BOOL
 
 =head1 SEE ALSO
 
 L<version>
 
 =head1 HOMEPAGE
 
 Please visit the project's homepage at L<https://metacpan.org/release/Version-Util>.
 
 =head1 SOURCE
 
 Source repository is at L<https://github.com/sharyanto/perl-Version-Util>.
 
 =head1 BUGS
 
 Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Version-Util>
 
 When submitting a bug or request, please include a test-file or a
 patch to an existing test-file that illustrates the bug or desired
 feature.
 
 =head1 AUTHOR
 
 Steven Haryanto <stevenharyanto@gmail.com>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2014 by Steven Haryanto.
 
 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
### YAML.pm ###
 package YAML;
 our $VERSION = '1.15';
 
 use YAML::Mo;
 
 use Exporter;
 push @YAML::ISA, 'Exporter';
 our @EXPORT = qw{ Dump Load };
 our @EXPORT_OK = qw{ freeze thaw DumpFile LoadFile Bless Blessed };
 
 use YAML::Node; # XXX This is a temp fix for Module::Build
 
 # XXX This VALUE nonsense needs to go.
 use constant VALUE => "\x07YAML\x07VALUE\x07";
 
 # YAML Object Properties
 has dumper_class => default => sub {'YAML::Dumper'};
 has loader_class => default => sub {'YAML::Loader'};
 has dumper_object => default => sub {$_[0]->init_action_object("dumper")};
 has loader_object => default => sub {$_[0]->init_action_object("loader")};
 
 sub Dump {
     my $yaml = YAML->new;
     $yaml->dumper_class($YAML::DumperClass)
         if $YAML::DumperClass;
     return $yaml->dumper_object->dump(@_);
 }
 
 sub Load {
     my $yaml = YAML->new;
     $yaml->loader_class($YAML::LoaderClass)
         if $YAML::LoaderClass;
     return $yaml->loader_object->load(@_);
 }
 
 {
     no warnings 'once';
     # freeze/thaw is the API for Storable string serialization. Some
     # modules make use of serializing packages on if they use freeze/thaw.
     *freeze = \ &Dump;
     *thaw   = \ &Load;
 }
 
 sub DumpFile {
     my $OUT;
     my $filename = shift;
     if (ref $filename eq 'GLOB') {
         $OUT = $filename;
     }
     else {
         my $mode = '>';
         if ($filename =~ /^\s*(>{1,2})\s*(.*)$/) {
             ($mode, $filename) = ($1, $2);
         }
         open $OUT, $mode, $filename
           or YAML::Mo::Object->die('YAML_DUMP_ERR_FILE_OUTPUT', $filename, $!);
     }
     binmode $OUT, ':utf8';  # if $Config{useperlio} eq 'define';
     local $/ = "\n"; # reset special to "sane"
     print $OUT Dump(@_);
 }
 
 sub LoadFile {
     my $IN;
     my $filename = shift;
     if (ref $filename eq 'GLOB') {
         $IN = $filename;
     }
     else {
         open $IN, '<', $filename
           or YAML::Mo::Object->die('YAML_LOAD_ERR_FILE_INPUT', $filename, $!);
     }
     binmode $IN, ':utf8';  # if $Config{useperlio} eq 'define';
     return Load(do { local $/; <$IN> });
 }
 
 sub init_action_object {
     my $self = shift;
     my $object_class = (shift) . '_class';
     my $module_name = $self->$object_class;
     eval "require $module_name";
     $self->die("Error in require $module_name - $@")
         if $@ and "$@" !~ /Can't locate/;
     my $object = $self->$object_class->new;
     $object->set_global_options;
     return $object;
 }
 
 my $global = {};
 sub Bless {
     require YAML::Dumper::Base;
     YAML::Dumper::Base::bless($global, @_)
 }
 sub Blessed {
     require YAML::Dumper::Base;
     YAML::Dumper::Base::blessed($global, @_)
 }
 sub global_object { $global }
 
 1;
### YAML/Any.pm ###
 use strict; use warnings;
 package YAML::Any;
 our $VERSION = '1.15';
 
 use Exporter ();
 
 @YAML::Any::ISA       = 'Exporter';
 @YAML::Any::EXPORT    = qw(Dump Load);
 @YAML::Any::EXPORT_OK = qw(DumpFile LoadFile);
 
 my @dump_options = qw(
     UseCode
     DumpCode
     SpecVersion
     Indent
     UseHeader
     UseVersion
     SortKeys
     AnchorPrefix
     UseBlock
     UseFold
     CompressSeries
     InlineSeries
     UseAliases
     Purity
     Stringify
 );
 
 my @load_options = qw(
     UseCode
     LoadCode
 );
 
 my @implementations = qw(
     YAML::XS
     YAML::Syck
     YAML::Old
     YAML
     YAML::Tiny
 );
 
 sub import {
     __PACKAGE__->implementation;
     goto &Exporter::import;
 }
 
 sub Dump {
     no strict 'refs';
     no warnings 'once';
     my $implementation = __PACKAGE__->implementation;
     for my $option (@dump_options) {
         my $var = "$implementation\::$option";
         my $value = $$var;
         local $$var;
         $$var = defined $value ? $value : ${"YAML::$option"};
     }
     return &{"$implementation\::Dump"}(@_);
 }
 
 sub DumpFile {
     no strict 'refs';
     no warnings 'once';
     my $implementation = __PACKAGE__->implementation;
     for my $option (@dump_options) {
         my $var = "$implementation\::$option";
         my $value = $$var;
         local $$var;
         $$var = defined $value ? $value : ${"YAML::$option"};
     }
     return &{"$implementation\::DumpFile"}(@_);
 }
 
 sub Load {
     no strict 'refs';
     no warnings 'once';
     my $implementation = __PACKAGE__->implementation;
     for my $option (@load_options) {
         my $var = "$implementation\::$option";
         my $value = $$var;
         local $$var;
         $$var = defined $value ? $value : ${"YAML::$option"};
     }
     return &{"$implementation\::Load"}(@_);
 }
 
 sub LoadFile {
     no strict 'refs';
     no warnings 'once';
     my $implementation = __PACKAGE__->implementation;
     for my $option (@load_options) {
         my $var = "$implementation\::$option";
         my $value = $$var;
         local $$var;
         $$var = defined $value ? $value : ${"YAML::$option"};
     }
     return &{"$implementation\::LoadFile"}(@_);
 }
 
 sub order {
     return @YAML::Any::_TEST_ORDER
         if @YAML::Any::_TEST_ORDER;
     return @implementations;
 }
 
 sub implementation {
     my @order = __PACKAGE__->order;
     for my $module (@order) {
         my $path = $module;
         $path =~ s/::/\//g;
         $path .= '.pm';
         return $module if exists $INC{$path};
         eval "require $module; 1" and return $module;
     }
     croak("YAML::Any couldn't find any of these YAML implementations: @order");
 }
 
 sub croak {
     require Carp;
     Carp::croak(@_);
 }
 
 1;
### YAML/Dumper.pm ###
 package YAML::Dumper;
 
 use YAML::Mo;
 extends 'YAML::Dumper::Base';
 
 use YAML::Dumper::Base;
 use YAML::Node;
 use YAML::Types;
 use Scalar::Util qw();
 
 # Context constants
 use constant KEY       => 3;
 use constant BLESSED   => 4;
 use constant FROMARRAY => 5;
 use constant VALUE     => "\x07YAML\x07VALUE\x07";
 
 # Common YAML character sets
 my $ESCAPE_CHAR = '[\\x00-\\x08\\x0b-\\x0d\\x0e-\\x1f]';
 my $LIT_CHAR    = '|';
 
 #==============================================================================
 # OO version of Dump. YAML->new->dump($foo);
 sub dump {
     my $self = shift;
     $self->stream('');
     $self->document(0);
     for my $document (@_) {
         $self->{document}++;
         $self->transferred({});
         $self->id_refcnt({});
         $self->id_anchor({});
         $self->anchor(1);
         $self->level(0);
         $self->offset->[0] = 0 - $self->indent_width;
         $self->_prewalk($document);
         $self->_emit_header($document);
         $self->_emit_node($document);
     }
     return $self->stream;
 }
 
 # Every YAML document in the stream must begin with a YAML header, unless
 # there is only a single document and the user requests "no header".
 sub _emit_header {
     my $self = shift;
     my ($node) = @_;
     if (not $self->use_header and
         $self->document == 1
        ) {
         $self->die('YAML_DUMP_ERR_NO_HEADER')
           unless ref($node) =~ /^(HASH|ARRAY)$/;
         $self->die('YAML_DUMP_ERR_NO_HEADER')
           if ref($node) eq 'HASH' and keys(%$node) == 0;
         $self->die('YAML_DUMP_ERR_NO_HEADER')
           if ref($node) eq 'ARRAY' and @$node == 0;
         # XXX Also croak if aliased, blessed, or ynode
         $self->headless(1);
         return;
     }
     $self->{stream} .= '---';
 # XXX Consider switching to 1.1 style
     if ($self->use_version) {
 #         $self->{stream} .= " #YAML:1.0";
     }
 }
 
 # Walk the tree to be dumped and keep track of its reference counts.
 # This function is where the Dumper does all its work. All type
 # transfers happen here.
 sub _prewalk {
     my $self = shift;
     my $stringify = $self->stringify;
     my ($class, $type, $node_id) = $self->node_info(\$_[0], $stringify);
 
     # Handle typeglobs
     if ($type eq 'GLOB') {
         $self->transferred->{$node_id} =
           YAML::Type::glob->yaml_dump($_[0]);
         $self->_prewalk($self->transferred->{$node_id});
         return;
     }
 
     # Handle regexps
     if (ref($_[0]) eq 'Regexp') {
         return;
     }
 
     # Handle Purity for scalars.
     # XXX can't find a use case yet. Might be YAGNI.
     if (not ref $_[0]) {
         $self->{id_refcnt}{$node_id}++ if $self->purity;
         return;
     }
 
     # Make a copy of original
     my $value = $_[0];
     ($class, $type, $node_id) = $self->node_info($value, $stringify);
 
     # Must be a stringified object.
     return if (ref($value) and not $type);
 
     # Look for things already transferred.
     if ($self->transferred->{$node_id}) {
         (undef, undef, $node_id) = (ref $self->transferred->{$node_id})
           ? $self->node_info($self->transferred->{$node_id}, $stringify)
           : $self->node_info(\ $self->transferred->{$node_id}, $stringify);
         $self->{id_refcnt}{$node_id}++;
         return;
     }
 
     # Handle code refs
     if ($type eq 'CODE') {
         $self->transferred->{$node_id} = 'placeholder';
         YAML::Type::code->yaml_dump(
             $self->dump_code,
             $_[0],
             $self->transferred->{$node_id}
         );
         ($class, $type, $node_id) =
           $self->node_info(\ $self->transferred->{$node_id}, $stringify);
         $self->{id_refcnt}{$node_id}++;
         return;
     }
 
     # Handle blessed things
     if (defined $class) {
         if ($value->can('yaml_dump')) {
             $value = $value->yaml_dump;
         }
         elsif ($type eq 'SCALAR') {
             $self->transferred->{$node_id} = 'placeholder';
             YAML::Type::blessed->yaml_dump
               ($_[0], $self->transferred->{$node_id});
             ($class, $type, $node_id) =
               $self->node_info(\ $self->transferred->{$node_id}, $stringify);
             $self->{id_refcnt}{$node_id}++;
             return;
         }
         else {
             $value = YAML::Type::blessed->yaml_dump($value);
         }
         $self->transferred->{$node_id} = $value;
         (undef, $type, $node_id) = $self->node_info($value, $stringify);
     }
 
     # Handle YAML Blessed things
     require YAML;
     if (defined YAML->global_object()->{blessed_map}{$node_id}) {
         $value = YAML->global_object()->{blessed_map}{$node_id};
         $self->transferred->{$node_id} = $value;
         ($class, $type, $node_id) = $self->node_info($value, $stringify);
         $self->_prewalk($value);
         return;
     }
 
     # Handle hard refs
     if ($type eq 'REF' or $type eq 'SCALAR') {
         $value = YAML::Type::ref->yaml_dump($value);
         $self->transferred->{$node_id} = $value;
         (undef, $type, $node_id) = $self->node_info($value, $stringify);
     }
 
     # Handle ref-to-glob's
     elsif ($type eq 'GLOB') {
         my $ref_ynode = $self->transferred->{$node_id} =
           YAML::Type::ref->yaml_dump($value);
 
         my $glob_ynode = $ref_ynode->{&VALUE} =
           YAML::Type::glob->yaml_dump($$value);
 
         (undef, undef, $node_id) = $self->node_info($glob_ynode, $stringify);
         $self->transferred->{$node_id} = $glob_ynode;
         $self->_prewalk($glob_ynode);
         return;
     }
 
     # Increment ref count for node
     return if ++($self->{id_refcnt}{$node_id}) > 1;
 
     # Keep on walking
     if ($type eq 'HASH') {
         $self->_prewalk($value->{$_})
             for keys %{$value};
         return;
     }
     elsif ($type eq 'ARRAY') {
         $self->_prewalk($_)
             for @{$value};
         return;
     }
 
     # Unknown type. Need to know about it.
     $self->warn(<<"...");
 YAML::Dumper can't handle dumping this type of data.
 Please report this to the author.
 
 id:    $node_id
 type:  $type
 class: $class
 value: $value
 
 ...
 
     return;
 }
 
 # Every data element and sub data element is a node.
 # Everything emitted goes through this function.
 sub _emit_node {
     my $self = shift;
     my ($type, $node_id);
     my $ref = ref($_[0]);
     if ($ref) {
         if ($ref eq 'Regexp') {
             $self->_emit(' !!perl/regexp');
             $self->_emit_str("$_[0]");
             return;
         }
         (undef, $type, $node_id) = $self->node_info($_[0], $self->stringify);
     }
     else {
         $type = $ref || 'SCALAR';
         (undef, undef, $node_id) = $self->node_info(\$_[0], $self->stringify);
     }
 
     my ($ynode, $tag) = ('') x 2;
     my ($value, $context) = (@_, 0);
 
     if (defined $self->transferred->{$node_id}) {
         $value = $self->transferred->{$node_id};
         $ynode = ynode($value);
         if (ref $value) {
             $tag = defined $ynode ? $ynode->tag->short : '';
             (undef, $type, $node_id) =
               $self->node_info($value, $self->stringify);
         }
         else {
             $ynode = ynode($self->transferred->{$node_id});
             $tag = defined $ynode ? $ynode->tag->short : '';
             $type = 'SCALAR';
             (undef, undef, $node_id) =
               $self->node_info(
                   \ $self->transferred->{$node_id},
                   $self->stringify
               );
         }
     }
     elsif ($ynode = ynode($value)) {
         $tag = $ynode->tag->short;
     }
 
     if ($self->use_aliases) {
         $self->{id_refcnt}{$node_id} ||= 0;
         if ($self->{id_refcnt}{$node_id} > 1) {
             if (defined $self->{id_anchor}{$node_id}) {
                 $self->{stream} .= ' *' . $self->{id_anchor}{$node_id} . "\n";
                 return;
             }
             my $anchor = $self->anchor_prefix . $self->{anchor}++;
             $self->{stream} .= ' &' . $anchor;
             $self->{id_anchor}{$node_id} = $anchor;
         }
     }
 
     return $self->_emit_str("$value")   # Stringified object
       if ref($value) and not $type;
     return $self->_emit_scalar($value, $tag)
       if $type eq 'SCALAR' and $tag;
     return $self->_emit_str($value)
       if $type eq 'SCALAR';
     return $self->_emit_mapping($value, $tag, $node_id, $context)
       if $type eq 'HASH';
     return $self->_emit_sequence($value, $tag)
       if $type eq 'ARRAY';
     $self->warn('YAML_DUMP_WARN_BAD_NODE_TYPE', $type);
     return $self->_emit_str("$value");
 }
 
 # A YAML mapping is akin to a Perl hash.
 sub _emit_mapping {
     my $self = shift;
     my ($value, $tag, $node_id, $context) = @_;
     $self->{stream} .= " !$tag" if $tag;
 
     # Sometimes 'keys' fails. Like on a bad tie implementation.
     my $empty_hash = not(eval {keys %$value});
     $self->warn('YAML_EMIT_WARN_KEYS', $@) if $@;
     return ($self->{stream} .= " {}\n") if $empty_hash;
 
     # If CompressSeries is on (default) and legal is this context, then
     # use it and make the indent level be 2 for this node.
     if ($context == FROMARRAY and
         $self->compress_series and
         not (defined $self->{id_anchor}{$node_id} or $tag or $empty_hash)
        ) {
         $self->{stream} .= ' ';
         $self->offset->[$self->level+1] = $self->offset->[$self->level] + 2;
     }
     else {
         $context = 0;
         $self->{stream} .= "\n"
           unless $self->headless && not($self->headless(0));
         $self->offset->[$self->level+1] =
           $self->offset->[$self->level] + $self->indent_width;
     }
 
     $self->{level}++;
     my @keys;
     if ($self->sort_keys == 1) {
         if (ynode($value)) {
             @keys = keys %$value;
         }
         else {
             @keys = sort keys %$value;
         }
     }
     elsif ($self->sort_keys == 2) {
         @keys = sort keys %$value;
     }
     # XXX This is hackish but sometimes handy. Not sure whether to leave it in.
     elsif (ref($self->sort_keys) eq 'ARRAY') {
         my $i = 1;
         my %order = map { ($_, $i++) } @{$self->sort_keys};
         @keys = sort {
             (defined $order{$a} and defined $order{$b})
               ? ($order{$a} <=> $order{$b})
               : ($a cmp $b);
         } keys %$value;
     }
     else {
         @keys = keys %$value;
     }
     # Force the YAML::VALUE ('=') key to sort last.
     if (exists $value->{&VALUE}) {
         for (my $i = 0; $i < @keys; $i++) {
             if ($keys[$i] eq &VALUE) {
                 splice(@keys, $i, 1);
                 push @keys, &VALUE;
                 last;
             }
         }
     }
 
     for my $key (@keys) {
         $self->_emit_key($key, $context);
         $context = 0;
         $self->{stream} .= ':';
         $self->_emit_node($value->{$key});
     }
     $self->{level}--;
 }
 
 # A YAML series is akin to a Perl array.
 sub _emit_sequence {
     my $self = shift;
     my ($value, $tag) = @_;
     $self->{stream} .= " !$tag" if $tag;
 
     return ($self->{stream} .= " []\n") if @$value == 0;
 
     $self->{stream} .= "\n"
       unless $self->headless && not($self->headless(0));
 
     # XXX Really crufty feature. Better implemented by ynodes.
     if ($self->inline_series and
         @$value <= $self->inline_series and
         not (scalar grep {ref or /\n/} @$value)
        ) {
         $self->{stream} =~ s/\n\Z/ /;
         $self->{stream} .= '[';
         for (my $i = 0; $i < @$value; $i++) {
             $self->_emit_str($value->[$i], KEY);
             last if $i == $#{$value};
             $self->{stream} .= ', ';
         }
         $self->{stream} .= "]\n";
         return;
     }
 
     $self->offset->[$self->level + 1] =
       $self->offset->[$self->level] + $self->indent_width;
     $self->{level}++;
     for my $val (@$value) {
         $self->{stream} .= ' ' x $self->offset->[$self->level];
         $self->{stream} .= '-';
         $self->_emit_node($val, FROMARRAY);
     }
     $self->{level}--;
 }
 
 # Emit a mapping key
 sub _emit_key {
     my $self = shift;
     my ($value, $context) = @_;
     $self->{stream} .= ' ' x $self->offset->[$self->level]
       unless $context == FROMARRAY;
     $self->_emit_str($value, KEY);
 }
 
 # Emit a blessed SCALAR
 sub _emit_scalar {
     my $self = shift;
     my ($value, $tag) = @_;
     $self->{stream} .= " !$tag";
     $self->_emit_str($value, BLESSED);
 }
 
 sub _emit {
     my $self = shift;
     $self->{stream} .= join '', @_;
 }
 
 # Emit a string value. YAML has many scalar styles. This routine attempts to
 # guess the best style for the text.
 sub _emit_str {
     my $self = shift;
     my $type = $_[1] || 0;
 
     # Use heuristics to find the best scalar emission style.
     $self->offset->[$self->level + 1] =
       $self->offset->[$self->level] + $self->indent_width;
     $self->{level}++;
 
     my $sf = $type == KEY ? '' : ' ';
     my $sb = $type == KEY ? '? ' : ' ';
     my $ef = $type == KEY ? '' : "\n";
     my $eb = "\n";
 
     while (1) {
         $self->_emit($sf),
         $self->_emit_plain($_[0]),
         $self->_emit($ef), last
           if not defined $_[0];
         $self->_emit($sf, '=', $ef), last
           if $_[0] eq VALUE;
         $self->_emit($sf),
         $self->_emit_double($_[0]),
         $self->_emit($ef), last
           if $_[0] =~ /$ESCAPE_CHAR/;
         if ($_[0] =~ /\n/) {
             $self->_emit($sb),
             $self->_emit_block($LIT_CHAR, $_[0]),
             $self->_emit($eb), last
               if $self->use_block;
               Carp::cluck "[YAML] \$UseFold is no longer supported"
               if $self->use_fold;
             $self->_emit($sf),
             $self->_emit_double($_[0]),
             $self->_emit($ef), last
               if length $_[0] <= 30;
             $self->_emit($sf),
             $self->_emit_double($_[0]),
             $self->_emit($ef), last
               if $_[0] !~ /\n\s*\S/;
             $self->_emit($sb),
             $self->_emit_block($LIT_CHAR, $_[0]),
             $self->_emit($eb), last;
         }
         $self->_emit($sf),
         $self->_emit_number($_[0]),
         $self->_emit($ef), last
           if $self->is_literal_number($_[0]);
         $self->_emit($sf),
         $self->_emit_plain($_[0]),
         $self->_emit($ef), last
           if $self->is_valid_plain($_[0]);
         $self->_emit($sf),
         $self->_emit_double($_[0]),
         $self->_emit($ef), last
           if $_[0] =~ /'/;
         $self->_emit($sf),
         $self->_emit_single($_[0]),
         $self->_emit($ef);
         last;
     }
 
     $self->{level}--;
 
     return;
 }
 
 sub is_literal_number {
     my $self = shift;
     # Stolen from JSON::Tiny
     return B::svref_2object(\$_[0])->FLAGS & (B::SVp_IOK | B::SVp_NOK)
             && 0 + $_[0] eq $_[0];
 }
 
 sub _emit_number {
     my $self = shift;
     return $self->_emit_plain($_[0]);
 }
 
 # Check whether or not a scalar should be emitted as an plain scalar.
 sub is_valid_plain {
     my $self = shift;
     return 0 unless length $_[0];
     return 0 if $self->quote_numeric_strings and Scalar::Util::looks_like_number($_[0]);
     # refer to YAML::Loader::parse_inline_simple()
     return 0 if $_[0] =~ /^[\s\{\[\~\`\'\"\!\@\#\>\|\%\&\?\*\^]/;
     return 0 if $_[0] =~ /[\{\[\]\},]/;
     return 0 if $_[0] =~ /[:\-\?]\s/;
     return 0 if $_[0] =~ /\s#/;
     return 0 if $_[0] =~ /\:(\s|$)/;
     return 0 if $_[0] =~ /[\s\|\>]$/;
     return 0 if $_[0] eq '-';
     return 1;
 }
 
 sub _emit_block {
     my $self = shift;
     my ($indicator, $value) = @_;
     $self->{stream} .= $indicator;
     $value =~ /(\n*)\Z/;
     my $chomp = length $1 ? (length $1 > 1) ? '+' : '' : '-';
     $value = '~' if not defined $value;
     $self->{stream} .= $chomp;
     $self->{stream} .= $self->indent_width if $value =~ /^\s/;
     $self->{stream} .= $self->indent($value);
 }
 
 # Plain means that the scalar is unquoted.
 sub _emit_plain {
     my $self = shift;
     $self->{stream} .= defined $_[0] ? $_[0] : '~';
 }
 
 # Double quoting is for single lined escaped strings.
 sub _emit_double {
     my $self = shift;
     (my $escaped = $self->escape($_[0])) =~ s/"/\\"/g;
     $self->{stream} .= qq{"$escaped"};
 }
 
 # Single quoting is for single lined unescaped strings.
 sub _emit_single {
     my $self = shift;
     my $item = shift;
     $item =~ s{'}{''}g;
     $self->{stream} .= "'$item'";
 }
 
 #==============================================================================
 # Utility subroutines.
 #==============================================================================
 
 # Indent a scalar to the current indentation level.
 sub indent {
     my $self = shift;
     my ($text) = @_;
     return $text unless length $text;
     $text =~ s/\n\Z//;
     my $indent = ' ' x $self->offset->[$self->level];
     $text =~ s/^/$indent/gm;
     $text = "\n$text";
     return $text;
 }
 
 # Escapes for unprintable characters
 my @escapes = qw(\0   \x01 \x02 \x03 \x04 \x05 \x06 \a
                  \x08 \t   \n   \v   \f   \r   \x0e \x0f
                  \x10 \x11 \x12 \x13 \x14 \x15 \x16 \x17
                  \x18 \x19 \x1a \e   \x1c \x1d \x1e \x1f
                 );
 
 # Escape the unprintable characters
 sub escape {
     my $self = shift;
     my ($text) = @_;
     $text =~ s/\\/\\\\/g;
     $text =~ s/([\x00-\x1f])/$escapes[ord($1)]/ge;
     return $text;
 }
 
 1;
### YAML/Dumper/Base.pm ###
 package YAML::Dumper::Base;
 
 use YAML::Mo;
 
 use YAML::Node;
 
 # YAML Dumping options
 has spec_version    => default => sub {'1.0'};
 has indent_width    => default => sub {2};
 has use_header      => default => sub {1};
 has use_version     => default => sub {0};
 has sort_keys       => default => sub {1};
 has anchor_prefix   => default => sub {''};
 has dump_code       => default => sub {0};
 has use_block       => default => sub {0};
 has use_fold        => default => sub {0};
 has compress_series => default => sub {1};
 has inline_series   => default => sub {0};
 has use_aliases     => default => sub {1};
 has purity          => default => sub {0};
 has stringify       => default => sub {0};
 has quote_numeric_strings => default => sub {0};
 
 # Properties
 has stream      => default => sub {''};
 has document    => default => sub {0};
 has transferred => default => sub {{}};
 has id_refcnt   => default => sub {{}};
 has id_anchor   => default => sub {{}};
 has anchor      => default => sub {1};
 has level       => default => sub {0};
 has offset      => default => sub {[]};
 has headless    => default => sub {0};
 has blessed_map => default => sub {{}};
 
 # Global Options are an idea taken from Data::Dumper. Really they are just
 # sugar on top of real OO properties. They make the simple Dump/Load API
 # easy to configure.
 sub set_global_options {
     my $self = shift;
     $self->spec_version($YAML::SpecVersion)
       if defined $YAML::SpecVersion;
     $self->indent_width($YAML::Indent)
       if defined $YAML::Indent;
     $self->use_header($YAML::UseHeader)
       if defined $YAML::UseHeader;
     $self->use_version($YAML::UseVersion)
       if defined $YAML::UseVersion;
     $self->sort_keys($YAML::SortKeys)
       if defined $YAML::SortKeys;
     $self->anchor_prefix($YAML::AnchorPrefix)
       if defined $YAML::AnchorPrefix;
     $self->dump_code($YAML::DumpCode || $YAML::UseCode)
       if defined $YAML::DumpCode or defined $YAML::UseCode;
     $self->use_block($YAML::UseBlock)
       if defined $YAML::UseBlock;
     $self->use_fold($YAML::UseFold)
       if defined $YAML::UseFold;
     $self->compress_series($YAML::CompressSeries)
       if defined $YAML::CompressSeries;
     $self->inline_series($YAML::InlineSeries)
       if defined $YAML::InlineSeries;
     $self->use_aliases($YAML::UseAliases)
       if defined $YAML::UseAliases;
     $self->purity($YAML::Purity)
       if defined $YAML::Purity;
     $self->stringify($YAML::Stringify)
       if defined $YAML::Stringify;
     $self->quote_numeric_strings($YAML::QuoteNumericStrings)
       if defined $YAML::QuoteNumericStrings;
 }
 
 sub dump {
     my $self = shift;
     $self->die('dump() not implemented in this class.');
 }
 
 sub blessed {
     my $self = shift;
     my ($ref) = @_;
     $ref = \$_[0] unless ref $ref;
     my (undef, undef, $node_id) = YAML::Mo::Object->node_info($ref);
     $self->{blessed_map}->{$node_id};
 }
 
 sub bless {
     my $self = shift;
     my ($ref, $blessing) = @_;
     my $ynode;
     $ref = \$_[0] unless ref $ref;
     my (undef, undef, $node_id) = YAML::Mo::Object->node_info($ref);
     if (not defined $blessing) {
         $ynode = YAML::Node->new($ref);
     }
     elsif (ref $blessing) {
         $self->die() unless ynode($blessing);
         $ynode = $blessing;
     }
     else {
         no strict 'refs';
         my $transfer = $blessing . "::yaml_dump";
         $self->die() unless defined &{$transfer};
         $ynode = &{$transfer}($ref);
         $self->die() unless ynode($ynode);
     }
     $self->{blessed_map}->{$node_id} = $ynode;
     my $object = ynode($ynode) or $self->die();
     return $object;
 }
 
 1;
### YAML/Error.pm ###
 package YAML::Error;
 
 use YAML::Mo;
 
 has 'code';
 has 'type' => default => sub {'Error'};
 has 'line';
 has 'document';
 has 'arguments' => default => sub {[]};
 
 my ($error_messages, %line_adjust);
 
 sub format_message {
     my $self = shift;
     my $output = 'YAML ' . $self->type . ': ';
     my $code = $self->code;
     if ($error_messages->{$code}) {
         $code = sprintf($error_messages->{$code}, @{$self->arguments});
     }
     $output .= $code . "\n";
 
     $output .= '   Code: ' . $self->code . "\n"
         if defined $self->code;
     $output .= '   Line: ' . $self->line . "\n"
         if defined $self->line;
     $output .= '   Document: ' . $self->document . "\n"
         if defined $self->document;
     return $output;
 }
 
 sub error_messages {
     $error_messages;
 }
 
 %$error_messages = map {s/^\s+//;$_} split "\n", <<'...';
 YAML_PARSE_ERR_BAD_CHARS
   Invalid characters in stream. This parser only supports printable ASCII
 YAML_PARSE_ERR_BAD_MAJOR_VERSION
   Can't parse a %s document with a 1.0 parser
 YAML_PARSE_WARN_BAD_MINOR_VERSION
   Parsing a %s document with a 1.0 parser
 YAML_PARSE_WARN_MULTIPLE_DIRECTIVES
   '%s directive used more than once'
 YAML_PARSE_ERR_TEXT_AFTER_INDICATOR
   No text allowed after indicator
 YAML_PARSE_ERR_NO_ANCHOR
   No anchor for alias '*%s'
 YAML_PARSE_ERR_NO_SEPARATOR
   Expected separator '---'
 YAML_PARSE_ERR_SINGLE_LINE
   Couldn't parse single line value
 YAML_PARSE_ERR_BAD_ANCHOR
   Invalid anchor
 YAML_DUMP_ERR_INVALID_INDENT
   Invalid Indent width specified: '%s'
 YAML_LOAD_USAGE
   usage: YAML::Load($yaml_stream_scalar)
 YAML_PARSE_ERR_BAD_NODE
   Can't parse node
 YAML_PARSE_ERR_BAD_EXPLICIT
   Unsupported explicit transfer: '%s'
 YAML_DUMP_USAGE_DUMPCODE
   Invalid value for DumpCode: '%s'
 YAML_LOAD_ERR_FILE_INPUT
   Couldn't open %s for input:\n%s
 YAML_DUMP_ERR_FILE_CONCATENATE
   Can't concatenate to YAML file %s
 YAML_DUMP_ERR_FILE_OUTPUT
   Couldn't open %s for output:\n%s
 YAML_DUMP_ERR_NO_HEADER
   With UseHeader=0, the node must be a plain hash or array
 YAML_DUMP_WARN_BAD_NODE_TYPE
   Can't perform serialization for node type: '%s'
 YAML_EMIT_WARN_KEYS
   Encountered a problem with 'keys':\n%s
 YAML_DUMP_WARN_DEPARSE_FAILED
   Deparse failed for CODE reference
 YAML_DUMP_WARN_CODE_DUMMY
   Emitting dummy subroutine for CODE reference
 YAML_PARSE_ERR_MANY_EXPLICIT
   More than one explicit transfer
 YAML_PARSE_ERR_MANY_IMPLICIT
   More than one implicit request
 YAML_PARSE_ERR_MANY_ANCHOR
   More than one anchor
 YAML_PARSE_ERR_ANCHOR_ALIAS
   Can't define both an anchor and an alias
 YAML_PARSE_ERR_BAD_ALIAS
   Invalid alias
 YAML_PARSE_ERR_MANY_ALIAS
   More than one alias
 YAML_LOAD_ERR_NO_CONVERT
   Can't convert implicit '%s' node to explicit '%s' node
 YAML_LOAD_ERR_NO_DEFAULT_VALUE
   No default value for '%s' explicit transfer
 YAML_LOAD_ERR_NON_EMPTY_STRING
   Only the empty string can be converted to a '%s'
 YAML_LOAD_ERR_BAD_MAP_TO_SEQ
   Can't transfer map as sequence. Non numeric key '%s' encountered.
 YAML_DUMP_ERR_BAD_GLOB
   '%s' is an invalid value for Perl glob
 YAML_DUMP_ERR_BAD_REGEXP
   '%s' is an invalid value for Perl Regexp
 YAML_LOAD_ERR_BAD_MAP_ELEMENT
   Invalid element in map
 YAML_LOAD_WARN_DUPLICATE_KEY
   Duplicate map key found. Ignoring.
 YAML_LOAD_ERR_BAD_SEQ_ELEMENT
   Invalid element in sequence
 YAML_PARSE_ERR_INLINE_MAP
   Can't parse inline map
 YAML_PARSE_ERR_INLINE_SEQUENCE
   Can't parse inline sequence
 YAML_PARSE_ERR_BAD_DOUBLE
   Can't parse double quoted string
 YAML_PARSE_ERR_BAD_SINGLE
   Can't parse single quoted string
 YAML_PARSE_ERR_BAD_INLINE_IMPLICIT
   Can't parse inline implicit value '%s'
 YAML_PARSE_ERR_BAD_IMPLICIT
   Unrecognized implicit value '%s'
 YAML_PARSE_ERR_INDENTATION
   Error. Invalid indentation level
 YAML_PARSE_ERR_INCONSISTENT_INDENTATION
   Inconsistent indentation level
 YAML_LOAD_WARN_UNRESOLVED_ALIAS
   Can't resolve alias *%s
 YAML_LOAD_WARN_NO_REGEXP_IN_REGEXP
   No 'REGEXP' element for Perl regexp
 YAML_LOAD_WARN_BAD_REGEXP_ELEM
   Unknown element '%s' in Perl regexp
 YAML_LOAD_WARN_GLOB_NAME
   No 'NAME' element for Perl glob
 YAML_LOAD_WARN_PARSE_CODE
   Couldn't parse Perl code scalar: %s
 YAML_LOAD_WARN_CODE_DEPARSE
   Won't parse Perl code unless $YAML::LoadCode is set
 YAML_EMIT_ERR_BAD_LEVEL
   Internal Error: Bad level detected
 YAML_PARSE_WARN_AMBIGUOUS_TAB
   Amibiguous tab converted to spaces
 YAML_LOAD_WARN_BAD_GLOB_ELEM
   Unknown element '%s' in Perl glob
 YAML_PARSE_ERR_ZERO_INDENT
   Can't use zero as an indentation width
 YAML_LOAD_WARN_GLOB_IO
   Can't load an IO filehandle. Yet!!!
 ...
 
 %line_adjust = map {($_, 1)}
   qw(YAML_PARSE_ERR_BAD_MAJOR_VERSION
      YAML_PARSE_WARN_BAD_MINOR_VERSION
      YAML_PARSE_ERR_TEXT_AFTER_INDICATOR
      YAML_PARSE_ERR_NO_ANCHOR
      YAML_PARSE_ERR_MANY_EXPLICIT
      YAML_PARSE_ERR_MANY_IMPLICIT
      YAML_PARSE_ERR_MANY_ANCHOR
      YAML_PARSE_ERR_ANCHOR_ALIAS
      YAML_PARSE_ERR_BAD_ALIAS
      YAML_PARSE_ERR_MANY_ALIAS
      YAML_LOAD_ERR_NO_CONVERT
      YAML_LOAD_ERR_NO_DEFAULT_VALUE
      YAML_LOAD_ERR_NON_EMPTY_STRING
      YAML_LOAD_ERR_BAD_MAP_TO_SEQ
      YAML_LOAD_ERR_BAD_STR_TO_INT
      YAML_LOAD_ERR_BAD_STR_TO_DATE
      YAML_LOAD_ERR_BAD_STR_TO_TIME
      YAML_LOAD_WARN_DUPLICATE_KEY
      YAML_PARSE_ERR_INLINE_MAP
      YAML_PARSE_ERR_INLINE_SEQUENCE
      YAML_PARSE_ERR_BAD_DOUBLE
      YAML_PARSE_ERR_BAD_SINGLE
      YAML_PARSE_ERR_BAD_INLINE_IMPLICIT
      YAML_PARSE_ERR_BAD_IMPLICIT
      YAML_LOAD_WARN_NO_REGEXP_IN_REGEXP
      YAML_LOAD_WARN_BAD_REGEXP_ELEM
      YAML_LOAD_WARN_REGEXP_CREATE
      YAML_LOAD_WARN_GLOB_NAME
      YAML_LOAD_WARN_PARSE_CODE
      YAML_LOAD_WARN_CODE_DEPARSE
      YAML_LOAD_WARN_BAD_GLOB_ELEM
      YAML_PARSE_ERR_ZERO_INDENT
     );
 
 package YAML::Warning;
 
 our @ISA = 'YAML::Error';
 
 1;
### YAML/Loader.pm ###
 package YAML::Loader;
 
 use YAML::Mo;
 extends 'YAML::Loader::Base';
 
 use YAML::Loader::Base;
 use YAML::Types;
 
 # Context constants
 use constant LEAF       => 1;
 use constant COLLECTION => 2;
 use constant VALUE      => "\x07YAML\x07VALUE\x07";
 use constant COMMENT    => "\x07YAML\x07COMMENT\x07";
 
 # Common YAML character sets
 my $ESCAPE_CHAR = '[\\x00-\\x08\\x0b-\\x0d\\x0e-\\x1f]';
 my $FOLD_CHAR   = '>';
 my $LIT_CHAR    = '|';
 my $LIT_CHAR_RX = "\\$LIT_CHAR";
 
 sub load {
     my $self = shift;
     $self->stream($_[0] || '');
     return $self->_parse();
 }
 
 # Top level function for parsing. Parse each document in order and
 # handle processing for YAML headers.
 sub _parse {
     my $self = shift;
     my (%directives, $preface);
     $self->{stream} =~ s|\015\012|\012|g;
     $self->{stream} =~ s|\015|\012|g;
     $self->line(0);
     $self->die('YAML_PARSE_ERR_BAD_CHARS')
       if $self->stream =~ /$ESCAPE_CHAR/;
     $self->{stream} =~ s/(.)\n\Z/$1/s;
     $self->lines([split /\x0a/, $self->stream, -1]);
     $self->line(1);
     # Throw away any comments or blanks before the header (or start of
     # content for headerless streams)
     $self->_parse_throwaway_comments();
     $self->document(0);
     $self->documents([]);
     # Add an "assumed" header if there is no header and the stream is
     # not empty (after initial throwaways).
     if (not $self->eos) {
         if ($self->lines->[0] !~ /^---(\s|$)/) {
             unshift @{$self->lines}, '---';
             $self->{line}--;
         }
     }
 
     # Main Loop. Parse out all the top level nodes and return them.
     while (not $self->eos) {
         $self->anchor2node({});
         $self->{document}++;
         $self->done(0);
         $self->level(0);
         $self->offset->[0] = -1;
 
         if ($self->lines->[0] =~ /^---\s*(.*)$/) {
             my @words = split /\s+/, $1;
             %directives = ();
             while (@words && $words[0] =~ /^#(\w+):(\S.*)$/) {
                 my ($key, $value) = ($1, $2);
                 shift(@words);
                 if (defined $directives{$key}) {
                     $self->warn('YAML_PARSE_WARN_MULTIPLE_DIRECTIVES',
                       $key, $self->document);
                     next;
                 }
                 $directives{$key} = $value;
             }
             $self->preface(join ' ', @words);
         }
         else {
             $self->die('YAML_PARSE_ERR_NO_SEPARATOR');
         }
 
         if (not $self->done) {
             $self->_parse_next_line(COLLECTION);
         }
         if ($self->done) {
             $self->{indent} = -1;
             $self->content('');
         }
 
         $directives{YAML} ||= '1.0';
         $directives{TAB} ||= 'NONE';
         ($self->{major_version}, $self->{minor_version}) =
           split /\./, $directives{YAML}, 2;
         $self->die('YAML_PARSE_ERR_BAD_MAJOR_VERSION', $directives{YAML})
           if $self->major_version ne '1';
         $self->warn('YAML_PARSE_WARN_BAD_MINOR_VERSION', $directives{YAML})
           if $self->minor_version ne '0';
         $self->die('Unrecognized TAB policy')
           unless $directives{TAB} =~ /^(NONE|\d+)(:HARD)?$/;
 
         push @{$self->documents}, $self->_parse_node();
     }
     return wantarray ? @{$self->documents} : $self->documents->[-1];
 }
 
 # This function is the dispatcher for parsing each node. Every node
 # recurses back through here. (Inlines are an exception as they have
 # their own sub-parser.)
 sub _parse_node {
     my $self = shift;
     my $preface = $self->preface;
     $self->preface('');
     my ($node, $type, $indicator, $escape, $chomp) = ('') x 5;
     my ($anchor, $alias, $explicit, $implicit, $class) = ('') x 5;
     ($anchor, $alias, $explicit, $implicit, $preface) =
       $self->_parse_qualifiers($preface);
     if ($anchor) {
         $self->anchor2node->{$anchor} = CORE::bless [], 'YAML-anchor2node';
     }
     $self->inline('');
     while (length $preface) {
         my $line = $self->line - 1;
         if ($preface =~ s/^($FOLD_CHAR|$LIT_CHAR_RX)(-|\+)?\d*\s*//) {
             $indicator = $1;
             $chomp = $2 if defined($2);
         }
         else {
             $self->die('YAML_PARSE_ERR_TEXT_AFTER_INDICATOR') if $indicator;
             $self->inline($preface);
             $preface = '';
         }
     }
     if ($alias) {
         $self->die('YAML_PARSE_ERR_NO_ANCHOR', $alias)
           unless defined $self->anchor2node->{$alias};
         if (ref($self->anchor2node->{$alias}) ne 'YAML-anchor2node') {
             $node = $self->anchor2node->{$alias};
         }
         else {
             $node = do {my $sv = "*$alias"};
             push @{$self->anchor2node->{$alias}}, [\$node, $self->line];
         }
     }
     elsif (length $self->inline) {
         $node = $self->_parse_inline(1, $implicit, $explicit);
         if (length $self->inline) {
             $self->die('YAML_PARSE_ERR_SINGLE_LINE');
         }
     }
     elsif ($indicator eq $LIT_CHAR) {
         $self->{level}++;
         $node = $self->_parse_block($chomp);
         $node = $self->_parse_implicit($node) if $implicit;
         $self->{level}--;
     }
     elsif ($indicator eq $FOLD_CHAR) {
         $self->{level}++;
         $node = $self->_parse_unfold($chomp);
         $node = $self->_parse_implicit($node) if $implicit;
         $self->{level}--;
     }
     else {
         $self->{level}++;
         $self->offset->[$self->level] ||= 0;
         if ($self->indent == $self->offset->[$self->level]) {
             if ($self->content =~ /^-( |$)/) {
                 $node = $self->_parse_seq($anchor);
             }
             elsif ($self->content =~ /(^\?|\:( |$))/) {
                 $node = $self->_parse_mapping($anchor);
             }
             elsif ($preface =~ /^\s*$/) {
                 $node = $self->_parse_implicit('');
             }
             else {
                 $self->die('YAML_PARSE_ERR_BAD_NODE');
             }
         }
         else {
             $node = undef;
         }
         $self->{level}--;
     }
     $#{$self->offset} = $self->level;
 
     if ($explicit) {
         if ($class) {
             if (not ref $node) {
                 my $copy = $node;
                 undef $node;
                 $node = \$copy;
             }
             CORE::bless $node, $class;
         }
         else {
             $node = $self->_parse_explicit($node, $explicit);
         }
     }
     if ($anchor) {
         if (ref($self->anchor2node->{$anchor}) eq 'YAML-anchor2node') {
             # XXX Can't remember what this code actually does
             for my $ref (@{$self->anchor2node->{$anchor}}) {
                 ${$ref->[0]} = $node;
                 $self->warn('YAML_LOAD_WARN_UNRESOLVED_ALIAS',
                     $anchor, $ref->[1]);
             }
         }
         $self->anchor2node->{$anchor} = $node;
     }
     return $node;
 }
 
 # Preprocess the qualifiers that may be attached to any node.
 sub _parse_qualifiers {
     my $self = shift;
     my ($preface) = @_;
     my ($anchor, $alias, $explicit, $implicit, $token) = ('') x 5;
     $self->inline('');
     while ($preface =~ /^[&*!]/) {
         my $line = $self->line - 1;
         if ($preface =~ s/^\!(\S+)\s*//) {
             $self->die('YAML_PARSE_ERR_MANY_EXPLICIT') if $explicit;
             $explicit = $1;
         }
         elsif ($preface =~ s/^\!\s*//) {
             $self->die('YAML_PARSE_ERR_MANY_IMPLICIT') if $implicit;
             $implicit = 1;
         }
         elsif ($preface =~ s/^\&([^ ,:]+)\s*//) {
             $token = $1;
             $self->die('YAML_PARSE_ERR_BAD_ANCHOR')
               unless $token =~ /^[a-zA-Z0-9]+$/;
             $self->die('YAML_PARSE_ERR_MANY_ANCHOR') if $anchor;
             $self->die('YAML_PARSE_ERR_ANCHOR_ALIAS') if $alias;
             $anchor = $token;
         }
         elsif ($preface =~ s/^\*([^ ,:]+)\s*//) {
             $token = $1;
             $self->die('YAML_PARSE_ERR_BAD_ALIAS')
               unless $token =~ /^[a-zA-Z0-9]+$/;
             $self->die('YAML_PARSE_ERR_MANY_ALIAS') if $alias;
             $self->die('YAML_PARSE_ERR_ANCHOR_ALIAS') if $anchor;
             $alias = $token;
         }
     }
     return ($anchor, $alias, $explicit, $implicit, $preface);
 }
 
 # Morph a node to it's explicit type
 sub _parse_explicit {
     my $self = shift;
     my ($node, $explicit) = @_;
     my ($type, $class);
     if ($explicit =~ /^\!?perl\/(hash|array|ref|scalar)(?:\:(\w(\w|\:\:)*)?)?$/) {
         ($type, $class) = (($1 || ''), ($2 || ''));
 
         # FIXME # die unless uc($type) eq ref($node) ?
 
         if ( $type eq "ref" ) {
             $self->die('YAML_LOAD_ERR_NO_DEFAULT_VALUE', 'XXX', $explicit)
             unless exists $node->{VALUE()} and scalar(keys %$node) == 1;
 
             my $value = $node->{VALUE()};
             $node = \$value;
         }
 
         if ( $type eq "scalar" and length($class) and !ref($node) ) {
             my $value = $node;
             $node = \$value;
         }
 
         if ( length($class) ) {
             CORE::bless($node, $class);
         }
 
         return $node;
     }
     if ($explicit =~ m{^!?perl/(glob|regexp|code)(?:\:(\w(\w|\:\:)*)?)?$}) {
         ($type, $class) = (($1 || ''), ($2 || ''));
         my $type_class = "YAML::Type::$type";
         no strict 'refs';
         if ($type_class->can('yaml_load')) {
             return $type_class->yaml_load($node, $class, $self);
         }
         else {
             $self->die('YAML_LOAD_ERR_NO_CONVERT', 'XXX', $explicit);
         }
     }
     # This !perl/@Foo and !perl/$Foo are deprecated but still parsed
     elsif ($YAML::TagClass->{$explicit} ||
            $explicit =~ m{^perl/(\@|\$)?([a-zA-Z](\w|::)+)$}
           ) {
         $class = $YAML::TagClass->{$explicit} || $2;
         if ($class->can('yaml_load')) {
             require YAML::Node;
             return $class->yaml_load(YAML::Node->new($node, $explicit));
         }
         else {
             if (ref $node) {
                 return CORE::bless $node, $class;
             }
             else {
                 return CORE::bless \$node, $class;
             }
         }
     }
     elsif (ref $node) {
         require YAML::Node;
         return YAML::Node->new($node, $explicit);
     }
     else {
         # XXX This is likely wrong. Failing test:
         # --- !unknown 'scalar value'
         return $node;
     }
 }
 
 # Parse a YAML mapping into a Perl hash
 sub _parse_mapping {
     my $self = shift;
     my ($anchor) = @_;
     my $mapping = {};
     $self->anchor2node->{$anchor} = $mapping;
     my $key;
     while (not $self->done and $self->indent == $self->offset->[$self->level]) {
         # If structured key:
         if ($self->{content} =~ s/^\?\s*//) {
             $self->preface($self->content);
             $self->_parse_next_line(COLLECTION);
             $key = $self->_parse_node();
             $key = "$key";
         }
         # If "default" key (equals sign)
         elsif ($self->{content} =~ s/^\=\s*//) {
             $key = VALUE;
         }
         # If "comment" key (slash slash)
         elsif ($self->{content} =~ s/^\=\s*//) {
             $key = COMMENT;
         }
         # Regular scalar key:
         else {
             $self->inline($self->content);
             $key = $self->_parse_inline();
             $key = "$key";
             $self->content($self->inline);
             $self->inline('');
         }
 
         unless ($self->{content} =~ s/^:\s*//) {
             $self->die('YAML_LOAD_ERR_BAD_MAP_ELEMENT');
         }
         $self->preface($self->content);
         my $line = $self->line;
         $self->_parse_next_line(COLLECTION);
         my $value = $self->_parse_node();
         if (exists $mapping->{$key}) {
             $self->warn('YAML_LOAD_WARN_DUPLICATE_KEY');
         }
         else {
             $mapping->{$key} = $value;
         }
     }
     return $mapping;
 }
 
 # Parse a YAML sequence into a Perl array
 sub _parse_seq {
     my $self = shift;
     my ($anchor) = @_;
     my $seq = [];
     $self->anchor2node->{$anchor} = $seq;
     while (not $self->done and $self->indent == $self->offset->[$self->level]) {
         if ($self->content =~ /^-(?: (.*))?$/) {
             $self->preface(defined($1) ? $1 : '');
         }
         else {
             $self->die('YAML_LOAD_ERR_BAD_SEQ_ELEMENT');
         }
         if ($self->preface =~ /^(\s*)(\w.*\:(?: |$).*)$/) {
             $self->indent($self->offset->[$self->level] + 2 + length($1));
             $self->content($2);
             $self->level($self->level + 1);
             $self->offset->[$self->level] = $self->indent;
             $self->preface('');
             push @$seq, $self->_parse_mapping('');
             $self->{level}--;
             $#{$self->offset} = $self->level;
         }
         else {
             $self->_parse_next_line(COLLECTION);
             push @$seq, $self->_parse_node();
         }
     }
     return $seq;
 }
 
 # Parse an inline value. Since YAML supports inline collections, this is
 # the top level of a sub parsing.
 sub _parse_inline {
     my $self = shift;
     my ($top, $top_implicit, $top_explicit) = (@_, '', '', '');
     $self->{inline} =~ s/^\s*(.*)\s*$/$1/; # OUCH - mugwump
     my ($node, $anchor, $alias, $explicit, $implicit) = ('') x 5;
     ($anchor, $alias, $explicit, $implicit, $self->{inline}) =
       $self->_parse_qualifiers($self->inline);
     if ($anchor) {
         $self->anchor2node->{$anchor} = CORE::bless [], 'YAML-anchor2node';
     }
     $implicit ||= $top_implicit;
     $explicit ||= $top_explicit;
     ($top_implicit, $top_explicit) = ('', '');
     if ($alias) {
         $self->die('YAML_PARSE_ERR_NO_ANCHOR', $alias)
           unless defined $self->anchor2node->{$alias};
         if (ref($self->anchor2node->{$alias}) ne 'YAML-anchor2node') {
             $node = $self->anchor2node->{$alias};
         }
         else {
             $node = do {my $sv = "*$alias"};
             push @{$self->anchor2node->{$alias}}, [\$node, $self->line];
         }
     }
     elsif ($self->inline =~ /^\{/) {
         $node = $self->_parse_inline_mapping($anchor);
     }
     elsif ($self->inline =~ /^\[/) {
         $node = $self->_parse_inline_seq($anchor);
     }
     elsif ($self->inline =~ /^"/) {
         $node = $self->_parse_inline_double_quoted();
         $node = $self->_unescape($node);
         $node = $self->_parse_implicit($node) if $implicit;
     }
     elsif ($self->inline =~ /^'/) {
         $node = $self->_parse_inline_single_quoted();
         $node = $self->_parse_implicit($node) if $implicit;
     }
     else {
         if ($top) {
             $node = $self->inline;
             $self->inline('');
         }
         else {
             $node = $self->_parse_inline_simple();
         }
         $node = $self->_parse_implicit($node) unless $explicit;
     }
     if ($explicit) {
         $node = $self->_parse_explicit($node, $explicit);
     }
     if ($anchor) {
         if (ref($self->anchor2node->{$anchor}) eq 'YAML-anchor2node') {
             for my $ref (@{$self->anchor2node->{$anchor}}) {
                 ${$ref->[0]} = $node;
                 $self->warn('YAML_LOAD_WARN_UNRESOLVED_ALIAS',
                     $anchor, $ref->[1]);
             }
         }
         $self->anchor2node->{$anchor} = $node;
     }
     return $node;
 }
 
 # Parse the inline YAML mapping into a Perl hash
 sub _parse_inline_mapping {
     my $self = shift;
     my ($anchor) = @_;
     my $node = {};
     $self->anchor2node->{$anchor} = $node;
 
     $self->die('YAML_PARSE_ERR_INLINE_MAP')
       unless $self->{inline} =~ s/^\{\s*//;
     while (not $self->{inline} =~ s/^\s*\}//) {
         my $key = $self->_parse_inline();
         $self->die('YAML_PARSE_ERR_INLINE_MAP')
           unless $self->{inline} =~ s/^\: \s*//;
         my $value = $self->_parse_inline();
         if (exists $node->{$key}) {
             $self->warn('YAML_LOAD_WARN_DUPLICATE_KEY');
         }
         else {
             $node->{$key} = $value;
         }
         next if $self->inline =~ /^\s*\}/;
         $self->die('YAML_PARSE_ERR_INLINE_MAP')
           unless $self->{inline} =~ s/^\,\s*//;
     }
     return $node;
 }
 
 # Parse the inline YAML sequence into a Perl array
 sub _parse_inline_seq {
     my $self = shift;
     my ($anchor) = @_;
     my $node = [];
     $self->anchor2node->{$anchor} = $node;
 
     $self->die('YAML_PARSE_ERR_INLINE_SEQUENCE')
       unless $self->{inline} =~ s/^\[\s*//;
     while (not $self->{inline} =~ s/^\s*\]//) {
         my $value = $self->_parse_inline();
         push @$node, $value;
         next if $self->inline =~ /^\s*\]/;
         $self->die('YAML_PARSE_ERR_INLINE_SEQUENCE')
           unless $self->{inline} =~ s/^\,\s*//;
     }
     return $node;
 }
 
 # Parse the inline double quoted string.
 sub _parse_inline_double_quoted {
     my $self = shift;
     my $node;
     # https://rt.cpan.org/Public/Bug/Display.html?id=90593
     if ($self->inline =~ /^"((?:(?:\\"|[^"]){0,32766}){0,32766})"\s*(.*)$/) {
         $node = $1;
         $self->inline($2);
         $node =~ s/\\"/"/g;
     }
     else {
         $self->die('YAML_PARSE_ERR_BAD_DOUBLE');
     }
     return $node;
 }
 
 
 # Parse the inline single quoted string.
 sub _parse_inline_single_quoted {
     my $self = shift;
     my $node;
     if ($self->inline =~ /^'((?:(?:''|[^']){0,32766}){0,32766})'\s*(.*)$/) {
         $node = $1;
         $self->inline($2);
         $node =~ s/''/'/g;
     }
     else {
         $self->die('YAML_PARSE_ERR_BAD_SINGLE');
     }
     return $node;
 }
 
 # Parse the inline unquoted string and do implicit typing.
 sub _parse_inline_simple {
     my $self = shift;
     my $value;
     if ($self->inline =~ /^(|[^!@#%^&*].*?)(?=[\[\]\{\},]|, |: |- |:\s*$|$)/) {
         $value = $1;
         substr($self->{inline}, 0, length($1)) = '';
     }
     else {
         $self->die('YAML_PARSE_ERR_BAD_INLINE_IMPLICIT', $value);
     }
     return $value;
 }
 
 sub _parse_implicit {
     my $self = shift;
     my ($value) = @_;
     $value =~ s/\s*$//;
     return $value if $value eq '';
     return undef if $value =~ /^~$/;
     return $value
       unless $value =~ /^[\@\`]/ or
              $value =~ /^[\-\?]\s/;
     $self->die('YAML_PARSE_ERR_BAD_IMPLICIT', $value);
 }
 
 # Unfold a YAML multiline scalar into a single string.
 sub _parse_unfold {
     my $self = shift;
     my ($chomp) = @_;
     my $node = '';
     my $space = 0;
     while (not $self->done and $self->indent == $self->offset->[$self->level]) {
         $node .= $self->content. "\n";
         $self->_parse_next_line(LEAF);
     }
     $node =~ s/^(\S.*)\n(?=\S)/$1 /gm;
     $node =~ s/^(\S.*)\n(\n+\S)/$1$2/gm;
     $node =~ s/\n*\Z// unless $chomp eq '+';
     $node .= "\n" unless $chomp;
     return $node;
 }
 
 # Parse a YAML block style scalar. This is like a Perl here-document.
 sub _parse_block {
     my $self = shift;
     my ($chomp) = @_;
     my $node = '';
     while (not $self->done and $self->indent == $self->offset->[$self->level]) {
         $node .= $self->content . "\n";
         $self->_parse_next_line(LEAF);
     }
     return $node if '+' eq $chomp;
     $node =~ s/\n*\Z/\n/;
     $node =~ s/\n\Z// if $chomp eq '-';
     return $node;
 }
 
 # Handle Perl style '#' comments. Comments must be at the same indentation
 # level as the collection line following them.
 sub _parse_throwaway_comments {
     my $self = shift;
     while (@{$self->lines} and
            $self->lines->[0] =~ m{^\s*(\#|$)}
           ) {
         shift @{$self->lines};
         $self->{line}++;
     }
     $self->eos($self->{done} = not @{$self->lines});
 }
 
 # This is the routine that controls what line is being parsed. It gets called
 # once for each line in the YAML stream.
 #
 # This routine must:
 # 1) Skip past the current line
 # 2) Determine the indentation offset for a new level
 # 3) Find the next _content_ line
 #   A) Skip over any throwaways (Comments/blanks)
 #   B) Set $self->indent, $self->content, $self->line
 # 4) Expand tabs appropriately
 sub _parse_next_line {
     my $self = shift;
     my ($type) = @_;
     my $level = $self->level;
     my $offset = $self->offset->[$level];
     $self->die('YAML_EMIT_ERR_BAD_LEVEL') unless defined $offset;
     shift @{$self->lines};
     $self->eos($self->{done} = not @{$self->lines});
     return if $self->eos;
     $self->{line}++;
 
     # Determine the offset for a new leaf node
     if ($self->preface =~
         qr/(?:^|\s)(?:$FOLD_CHAR|$LIT_CHAR_RX)(?:-|\+)?(\d*)\s*$/
        ) {
         $self->die('YAML_PARSE_ERR_ZERO_INDENT')
           if length($1) and $1 == 0;
         $type = LEAF;
         if (length($1)) {
             $self->offset->[$level + 1] = $offset + $1;
         }
         else {
             # First get rid of any comments.
             while (@{$self->lines} && ($self->lines->[0] =~ /^\s*#/)) {
                 $self->lines->[0] =~ /^( *)/;
                 last unless length($1) <= $offset;
                 shift @{$self->lines};
                 $self->{line}++;
             }
             $self->eos($self->{done} = not @{$self->lines});
             return if $self->eos;
             if ($self->lines->[0] =~ /^( *)\S/ and length($1) > $offset) {
                 $self->offset->[$level+1] = length($1);
             }
             else {
                 $self->offset->[$level+1] = $offset + 1;
             }
         }
         $offset = $self->offset->[++$level];
     }
     # Determine the offset for a new collection level
     elsif ($type == COLLECTION and
            $self->preface =~ /^(\s*(\!\S*|\&\S+))*\s*$/) {
         $self->_parse_throwaway_comments();
         if ($self->eos) {
             $self->offset->[$level+1] = $offset + 1;
             return;
         }
         else {
             $self->lines->[0] =~ /^( *)\S/ or
                 $self->die('YAML_PARSE_ERR_NONSPACE_INDENTATION');
             if (length($1) > $offset) {
                 $self->offset->[$level+1] = length($1);
             }
             else {
                 $self->offset->[$level+1] = $offset + 1;
             }
         }
         $offset = $self->offset->[++$level];
     }
 
     if ($type == LEAF) {
         while (@{$self->lines} and
                $self->lines->[0] =~ m{^( *)(\#)} and
                length($1) < $offset
               ) {
             shift @{$self->lines};
             $self->{line}++;
         }
         $self->eos($self->{done} = not @{$self->lines});
     }
     else {
         $self->_parse_throwaway_comments();
     }
     return if $self->eos;
 
     if ($self->lines->[0] =~ /^---(\s|$)/) {
         $self->done(1);
         return;
     }
     if ($type == LEAF and
         $self->lines->[0] =~ /^ {$offset}(.*)$/
        ) {
         $self->indent($offset);
         $self->content($1);
     }
     elsif ($self->lines->[0] =~ /^\s*$/) {
         $self->indent($offset);
         $self->content('');
     }
     else {
         $self->lines->[0] =~ /^( *)(\S.*)$/;
         while ($self->offset->[$level] > length($1)) {
             $level--;
         }
         $self->die('YAML_PARSE_ERR_INCONSISTENT_INDENTATION')
           if $self->offset->[$level] != length($1);
         $self->indent(length($1));
         $self->content($2);
     }
     $self->die('YAML_PARSE_ERR_INDENTATION')
       if $self->indent - $offset > 1;
 }
 
 #==============================================================================
 # Utility subroutines.
 #==============================================================================
 
 # Printable characters for escapes
 my %unescapes = (
    0 => "\x00",
    a => "\x07",
    t => "\x09",
    n => "\x0a",
    'v' => "\x0b", # Potential v-string error on 5.6.2 if not quoted
    f => "\x0c",
    r => "\x0d",
    e => "\x1b",
    '\\' => '\\',
   );
 
 # Transform all the backslash style escape characters to their literal meaning
 sub _unescape {
     my $self = shift;
     my ($node) = @_;
     $node =~ s/\\([never\\fart0]|x([0-9a-fA-F]{2}))/
               (length($1)>1)?pack("H2",$2):$unescapes{$1}/gex;
     return $node;
 }
 
 1;
### YAML/Loader/Base.pm ###
 package YAML::Loader::Base;
 
 use YAML::Mo;
 
 has load_code     => default => sub {0};
 has stream        => default => sub {''};
 has document      => default => sub {0};
 has line          => default => sub {0};
 has documents     => default => sub {[]};
 has lines         => default => sub {[]};
 has eos           => default => sub {0};
 has done          => default => sub {0};
 has anchor2node   => default => sub {{}};
 has level         => default => sub {0};
 has offset        => default => sub {[]};
 has preface       => default => sub {''};
 has content       => default => sub {''};
 has indent        => default => sub {0};
 has major_version => default => sub {0};
 has minor_version => default => sub {0};
 has inline        => default => sub {''};
 
 sub set_global_options {
     my $self = shift;
     $self->load_code($YAML::LoadCode || $YAML::UseCode)
       if defined $YAML::LoadCode or defined $YAML::UseCode;
 }
 
 sub load {
     die 'load() not implemented in this class.';
 }
 
 1;
### YAML/Marshall.pm ###
 use strict; use warnings;
 package YAML::Marshall;
 
 use YAML::Node ();
 
 sub import {
     my $class = shift;
     no strict 'refs';
     my $package = caller;
     unless (grep { $_ eq $class} @{$package . '::ISA'}) {
         push @{$package . '::ISA'}, $class;
     }
 
     my $tag = shift;
     if ( $tag ) {
         no warnings 'once';
         $YAML::TagClass->{$tag} = $package;
         ${$package . "::YamlTag"} = $tag;
     }
 }
 
 sub yaml_dump {
     my $self = shift;
     no strict 'refs';
     my $tag = ${ref($self) . "::YamlTag"} || 'perl/' . ref($self);
     $self->yaml_node($self, $tag);
 }
 
 sub yaml_load {
     my ($class, $node) = @_;
     if (my $ynode = $class->yaml_ynode($node)) {
         $node = $ynode->{NODE};
     }
     bless $node, $class;
 }
 
 sub yaml_node {
     shift;
     YAML::Node->new(@_);
 }
 
 sub yaml_ynode {
     shift;
     YAML::Node::ynode(@_);
 }
 
 1;
### YAML/Mo.pm ###
 package YAML::Mo; $VERSION = '0.88';
 # use Mo qw[builder default import];
 #   The following line of code was produced from the previous line by
 #   Mo::Inline version 0.31
 no warnings;my$M=__PACKAGE__.'::';*{$M.Object::new}=sub{bless{@_[1..$#_]},$_[0]};*{$M.import}=sub{import warnings;$^H|=1538;my($P,%e,%o)=caller.'::';shift;eval"no Mo::$_",&{$M.$_.::e}($P,\%e,\%o,\@_)for@_;return if$e{M};%e=(extends,sub{eval"no $_[0]()";@{$P.ISA}=$_[0]},has,sub{my$n=shift;my$m=sub{$#_?$_[0]{$n}=$_[1]:$_[0]{$n}};$m=$o{$_}->($m,$n,@_)for sort keys%o;*{$P.$n}=$m},%e,);*{$P.$_}=$e{$_}for keys%e;@{$P.ISA}=$M.Object};*{$M.'builder::e'}=sub{my($P,$e,$o)=@_;$o->{builder}=sub{my($m,$n,%a)=@_;my$b=$a{builder}or return$m;sub{$#_?$m->(@_):!exists$_[0]{$n}?$_[0]{$n}=$_[0]->$b:$m->(@_)}}};*{$M.'default::e'}=sub{my($P,$e,$o)=@_;$o->{default}=sub{my($m,$n,%a)=@_;$a{default}or return$m;sub{$#_?$m->(@_):!exists$_[0]{$n}?$_[0]{$n}=$a{default}->(@_):$m->(@_)}}};my$i=\&import;*{$M.import}=sub{(@_==2 and not $_[1])?pop@_:@_==1?push@_,grep!/import/,@f:();goto&$i};@f=qw[builder default import];use strict;use warnings;
 
 our $DumperModule = 'Data::Dumper';
 
 my ($_new_error, $_info, $_scalar_info);
 
 no strict 'refs';
 *{$M.'Object::die'} = sub {
     my $self = shift;
     my $error = $self->$_new_error(@_);
     $error->type('Error');
     Carp::croak($error->format_message);
 };
 
 *{$M.'Object::warn'} = sub {
     my $self = shift;
     return unless $^W;
     my $error = $self->$_new_error(@_);
     $error->type('Warning');
     Carp::cluck($error->format_message);
 };
 
 # This code needs to be refactored to be simpler and more precise, and no,
 # Scalar::Util doesn't DWIM.
 #
 # Can't handle:
 # * blessed regexp
 *{$M.'Object::node_info'} = sub {
     my $self = shift;
     my $stringify = $_[1] || 0;
     my ($class, $type, $id) =
         ref($_[0])
         ? $stringify
           ? &$_info("$_[0]")
           : do {
               require overload;
               my @info = &$_info(overload::StrVal($_[0]));
               if (ref($_[0]) eq 'Regexp') {
                   @info[0, 1] = (undef, 'REGEXP');
               }
               @info;
           }
         : &$_scalar_info($_[0]);
     ($class, $type, $id) = &$_scalar_info("$_[0]")
         unless $id;
     return wantarray ? ($class, $type, $id) : $id;
 };
 
 #-------------------------------------------------------------------------------
 $_info = sub {
     return (($_[0]) =~ qr{^(?:(.*)\=)?([^=]*)\(([^\(]*)\)$}o);
 };
 
 $_scalar_info = sub {
     my $id = 'undef';
     if (defined $_[0]) {
         \$_[0] =~ /\((\w+)\)$/o or CORE::die();
         $id = "$1-S";
     }
     return (undef, undef, $id);
 };
 
 $_new_error = sub {
     require Carp;
     my $self = shift;
     require YAML::Error;
 
     my $code = shift || 'unknown error';
     my $error = YAML::Error->new(code => $code);
     $error->line($self->line) if $self->can('line');
     $error->document($self->document) if $self->can('document');
     $error->arguments([@_]);
     return $error;
 };
 
 1;
### YAML/Node.pm ###
 use strict; use warnings;
 package YAML::Node;
 
 use YAML::Tag;
 require YAML::Mo;
 
 use Exporter;
 our @ISA     = qw(Exporter YAML::Mo::Object);
 our @EXPORT  = qw(ynode);
 
 sub ynode {
     my $self;
     if (ref($_[0]) eq 'HASH') {
         $self = tied(%{$_[0]});
     }
     elsif (ref($_[0]) eq 'ARRAY') {
         $self = tied(@{$_[0]});
     }
     elsif (ref(\$_[0]) eq 'GLOB') {
         $self = tied(*{$_[0]});
     }
     else {
         $self = tied($_[0]);
     }
     return (ref($self) =~ /^yaml_/) ? $self : undef;
 }
 
 sub new {
     my ($class, $node, $tag) = @_;
     my $self;
     $self->{NODE} = $node;
     my (undef, $type) = YAML::Mo::Object->node_info($node);
     $self->{KIND} = (not defined $type) ? 'scalar' :
                     ($type eq 'ARRAY') ? 'sequence' :
                     ($type eq 'HASH') ? 'mapping' :
                     $class->die("Can't create YAML::Node from '$type'");
     tag($self, ($tag || ''));
     if ($self->{KIND} eq 'scalar') {
         yaml_scalar->new($self, $_[1]);
         return \ $_[1];
     }
     my $package = "yaml_" . $self->{KIND};
     $package->new($self)
 }
 
 sub node { $_->{NODE} }
 sub kind { $_->{KIND} }
 sub tag {
     my ($self, $value) = @_;
     if (defined $value) {
                $self->{TAG} = YAML::Tag->new($value);
         return $self;
     }
     else {
        return $self->{TAG};
     }
 }
 sub keys {
     my ($self, $value) = @_;
     if (defined $value) {
                $self->{KEYS} = $value;
         return $self;
     }
     else {
        return $self->{KEYS};
     }
 }
 
 #==============================================================================
 package yaml_scalar;
 
 @yaml_scalar::ISA = qw(YAML::Node);
 
 sub new {
     my ($class, $self) = @_;
     tie $_[2], $class, $self;
 }
 
 sub TIESCALAR {
     my ($class, $self) = @_;
     bless $self, $class;
     $self
 }
 
 sub FETCH {
     my ($self) = @_;
     $self->{NODE}
 }
 
 sub STORE {
     my ($self, $value) = @_;
     $self->{NODE} = $value
 }
 
 #==============================================================================
 package yaml_sequence;
 
 @yaml_sequence::ISA = qw(YAML::Node);
 
 sub new {
     my ($class, $self) = @_;
     my $new;
     tie @$new, $class, $self;
     $new
 }
 
 sub TIEARRAY {
     my ($class, $self) = @_;
     bless $self, $class
 }
 
 sub FETCHSIZE {
     my ($self) = @_;
     scalar @{$self->{NODE}};
 }
 
 sub FETCH {
     my ($self, $index) = @_;
     $self->{NODE}[$index]
 }
 
 sub STORE {
     my ($self, $index, $value) = @_;
     $self->{NODE}[$index] = $value
 }
 
 sub undone {
     die "Not implemented yet"; # XXX
 }
 
 *STORESIZE = *POP = *PUSH = *SHIFT = *UNSHIFT = *SPLICE = *DELETE = *EXISTS =
 *STORESIZE = *POP = *PUSH = *SHIFT = *UNSHIFT = *SPLICE = *DELETE = *EXISTS =
 *undone; # XXX Must implement before release
 
 #==============================================================================
 package yaml_mapping;
 
 @yaml_mapping::ISA = qw(YAML::Node);
 
 sub new {
     my ($class, $self) = @_;
     @{$self->{KEYS}} = sort keys %{$self->{NODE}};
     my $new;
     tie %$new, $class, $self;
     $new
 }
 
 sub TIEHASH {
     my ($class, $self) = @_;
     bless $self, $class
 }
 
 sub FETCH {
     my ($self, $key) = @_;
     if (exists $self->{NODE}{$key}) {
         return (grep {$_ eq $key} @{$self->{KEYS}})
                ? $self->{NODE}{$key} : undef;
     }
     return $self->{HASH}{$key};
 }
 
 sub STORE {
     my ($self, $key, $value) = @_;
     if (exists $self->{NODE}{$key}) {
         $self->{NODE}{$key} = $value;
     }
     elsif (exists $self->{HASH}{$key}) {
         $self->{HASH}{$key} = $value;
     }
     else {
         if (not grep {$_ eq $key} @{$self->{KEYS}}) {
             push(@{$self->{KEYS}}, $key);
         }
         $self->{HASH}{$key} = $value;
     }
     $value
 }
 
 sub DELETE {
     my ($self, $key) = @_;
     my $return;
     if (exists $self->{NODE}{$key}) {
         $return = $self->{NODE}{$key};
     }
     elsif (exists $self->{HASH}{$key}) {
         $return = delete $self->{NODE}{$key};
     }
     for (my $i = 0; $i < @{$self->{KEYS}}; $i++) {
         if ($self->{KEYS}[$i] eq $key) {
             splice(@{$self->{KEYS}}, $i, 1);
         }
     }
     return $return;
 }
 
 sub CLEAR {
     my ($self) = @_;
     @{$self->{KEYS}} = ();
     %{$self->{HASH}} = ();
 }
 
 sub FIRSTKEY {
     my ($self) = @_;
     $self->{ITER} = 0;
     $self->{KEYS}[0]
 }
 
 sub NEXTKEY {
     my ($self) = @_;
     $self->{KEYS}[++$self->{ITER}]
 }
 
 sub EXISTS {
     my ($self, $key) = @_;
     exists $self->{NODE}{$key}
 }
 
 1;
### YAML/Tag.pm ###
 use strict; use warnings;
 package YAML::Tag;
 
 use overload '""' => sub { ${$_[0]} };
 
 sub new {
     my ($class, $self) = @_;
     bless \$self, $class
 }
 
 sub short {
     ${$_[0]}
 }
 
 sub canonical {
     ${$_[0]}
 }
 
 1;
### YAML/Types.pm ###
 package YAML::Types;
 
 use YAML::Mo;
 use YAML::Node;
 
 # XXX These classes and their APIs could still use some refactoring,
 # but at least they work for now.
 #-------------------------------------------------------------------------------
 package YAML::Type::blessed;
 
 use YAML::Mo; # XXX
 
 sub yaml_dump {
     my $self = shift;
     my ($value) = @_;
     my ($class, $type) = YAML::Mo::Object->node_info($value);
     no strict 'refs';
     my $kind = lc($type) . ':';
     my $tag = ${$class . '::ClassTag'} ||
               "!perl/$kind$class";
     if ($type eq 'REF') {
         YAML::Node->new(
             {(&YAML::VALUE, ${$_[0]})}, $tag
         );
     }
     elsif ($type eq 'SCALAR') {
         $_[1] = $$value;
         YAML::Node->new($_[1], $tag);
     }
     elsif ($type eq 'GLOB') {
         # blessed glob support is minimal, and will not round-trip
         # initial aim: to not cause an error
         return YAML::Type::glob->yaml_dump($value, $tag);
     } else {
         YAML::Node->new($value, $tag);
     }
 }
 
 #-------------------------------------------------------------------------------
 package YAML::Type::undef;
 
 sub yaml_dump {
     my $self = shift;
 }
 
 sub yaml_load {
     my $self = shift;
 }
 
 #-------------------------------------------------------------------------------
 package YAML::Type::glob;
 
 sub yaml_dump {
     my $self = shift;
     # $_[0] remains as the glob
     my $tag = pop @_ if 2==@_;
 
     $tag = '!perl/glob:' unless defined $tag;
     my $ynode = YAML::Node->new({}, $tag);
     for my $type (qw(PACKAGE NAME SCALAR ARRAY HASH CODE IO)) {
         my $value = *{$_[0]}{$type};
         $value = $$value if $type eq 'SCALAR';
         if (defined $value) {
             if ($type eq 'IO') {
                 my @stats = qw(device inode mode links uid gid rdev size
                                atime mtime ctime blksize blocks);
                 undef $value;
                 $value->{stat} = YAML::Node->new({});
                 if ($value->{fileno} = fileno(*{$_[0]})) {
                     local $^W;
                     map {$value->{stat}{shift @stats} = $_} stat(*{$_[0]});
                     $value->{tell} = tell(*{$_[0]});
                 }
             }
             $ynode->{$type} = $value;
         }
     }
     return $ynode;
 }
 
 sub yaml_load {
     my $self = shift;
     my ($node, $class, $loader) = @_;
     my ($name, $package);
     if (defined $node->{NAME}) {
         $name = $node->{NAME};
         delete $node->{NAME};
     }
     else {
         $loader->warn('YAML_LOAD_WARN_GLOB_NAME');
         return undef;
     }
     if (defined $node->{PACKAGE}) {
         $package = $node->{PACKAGE};
         delete $node->{PACKAGE};
     }
     else {
         $package = 'main';
     }
     no strict 'refs';
     if (exists $node->{SCALAR}) {
         *{"${package}::$name"} = \$node->{SCALAR};
         delete $node->{SCALAR};
     }
     for my $elem (qw(ARRAY HASH CODE IO)) {
         if (exists $node->{$elem}) {
             if ($elem eq 'IO') {
                 $loader->warn('YAML_LOAD_WARN_GLOB_IO');
                 delete $node->{IO};
                 next;
             }
             *{"${package}::$name"} = $node->{$elem};
             delete $node->{$elem};
         }
     }
     for my $elem (sort keys %$node) {
         $loader->warn('YAML_LOAD_WARN_BAD_GLOB_ELEM', $elem);
     }
     return *{"${package}::$name"};
 }
 
 #-------------------------------------------------------------------------------
 package YAML::Type::code;
 
 my $dummy_warned = 0;
 my $default = '{ "DUMMY" }';
 
 sub yaml_dump {
     my $self = shift;
     my $code;
     my ($dumpflag, $value) = @_;
     my ($class, $type) = YAML::Mo::Object->node_info($value);
     my $tag = "!perl/code";
     $tag .= ":$class" if defined $class;
     if (not $dumpflag) {
         $code = $default;
     }
     else {
         bless $value, "CODE" if $class;
         eval { use B::Deparse };
         return if $@;
         my $deparse = B::Deparse->new();
         eval {
             local $^W = 0;
             $code = $deparse->coderef2text($value);
         };
         if ($@) {
             warn YAML::YAML_DUMP_WARN_DEPARSE_FAILED() if $^W;
             $code = $default;
         }
         bless $value, $class if $class;
         chomp $code;
         $code .= "\n";
     }
     $_[2] = $code;
     YAML::Node->new($_[2], $tag);
 }
 
 sub yaml_load {
     my $self = shift;
     my ($node, $class, $loader) = @_;
     if ($loader->load_code) {
         my $code = eval "package main; sub $node";
         if ($@) {
             $loader->warn('YAML_LOAD_WARN_PARSE_CODE', $@);
             return sub {};
         }
         else {
             CORE::bless $code, $class if $class;
             return $code;
         }
     }
     else {
         return CORE::bless sub {}, $class if $class;
         return sub {};
     }
 }
 
 #-------------------------------------------------------------------------------
 package YAML::Type::ref;
 
 sub yaml_dump {
     my $self = shift;
     YAML::Node->new({(&YAML::VALUE, ${$_[0]})}, '!perl/ref')
 }
 
 sub yaml_load {
     my $self = shift;
     my ($node, $class, $loader) = @_;
     $loader->die('YAML_LOAD_ERR_NO_DEFAULT_VALUE', 'ptr')
       unless exists $node->{&YAML::VALUE};
     return \$node->{&YAML::VALUE};
 }
 
 #-------------------------------------------------------------------------------
 package YAML::Type::regexp;
 
 # XXX Be sure to handle blessed regexps (if possible)
 sub yaml_dump {
     die "YAML::Type::regexp::yaml_dump not currently implemented";
 }
 
 use constant _QR_TYPES => {
     '' => sub { qr{$_[0]} },
     x => sub { qr{$_[0]}x },
     i => sub { qr{$_[0]}i },
     s => sub { qr{$_[0]}s },
     m => sub { qr{$_[0]}m },
     ix => sub { qr{$_[0]}ix },
     sx => sub { qr{$_[0]}sx },
     mx => sub { qr{$_[0]}mx },
     si => sub { qr{$_[0]}si },
     mi => sub { qr{$_[0]}mi },
     ms => sub { qr{$_[0]}sm },
     six => sub { qr{$_[0]}six },
     mix => sub { qr{$_[0]}mix },
     msx => sub { qr{$_[0]}msx },
     msi => sub { qr{$_[0]}msi },
     msix => sub { qr{$_[0]}msix },
 };
 
 sub yaml_load {
     my $self = shift;
     my ($node, $class) = @_;
     return qr{$node} unless $node =~ /^\(\?([\^\-xism]*):(.*)\)\z/s;
     my ($flags, $re) = ($1, $2);
     $flags =~ s/-.*//;
     $flags =~ s/^\^//;
     my $sub = _QR_TYPES->{$flags} || sub { qr{$_[0]} };
     my $qr = &$sub($re);
     bless $qr, $class if length $class;
     return $qr;
 }
 
 1;
### experimental.pm ###
 package experimental;
 $experimental::VERSION = '0.013';
 use strict;
 use warnings;
 use version ();
 
 use feature ();
 use Carp qw/croak carp/;
 
 my %warnings = map { $_ => 1 } grep { /^experimental::/ } keys %warnings::Offsets;
 my %features = map { $_ => 1 } $] > 5.015006 ? keys %feature::feature : do {
 	my @features;
 	if ($] >= 5.010) {
 		push @features, qw/switch say state/;
 		push @features, 'unicode_strings' if $] > 5.011002;
 	}
 	@features;
 };
 
 my %min_version = (
 	array_base      => '5',
 	autoderef       => '5.14.0',
 	current_sub     => '5.16.0',
 	evalbytes       => '5.16.0',
 	fc              => '5.16.0',
 	lexical_topic   => '5.10.0',
 	lexical_subs    => '5.18.0',
 	postderef       => '5.20.0',
 	postderef_qq    => '5.20.0',
 	refaliasing     => '5.21.5',
 	regex_sets      => '5.18.0',
 	say             => '5.10.0',
 	smartmatch      => '5.10.0',
 	signatures      => '5.20.0',
 	state           => '5.10.0',
 	switch          => '5.10.0',
 	unicode_eval    => '5.16.0',
 	unicode_strings => '5.12.0',
 );
 $_ = version->new($_) for values %min_version;
 
 my %additional = (
 	postderef  => ['postderef_qq'],
 	switch     => ['smartmatch'],
 );
 
 sub _enable {
 	my $pragma = shift;
 	if ($warnings{"experimental::$pragma"}) {
 		warnings->unimport("experimental::$pragma");
 		feature->import($pragma) if exists $features{$pragma};
 		_enable(@{ $additional{$pragma} }) if $additional{$pragma};
 	}
 	elsif ($features{$pragma}) {
 		feature->import($pragma);
 		_enable(@{ $additional{$pragma} }) if $additional{$pragma};
 	}
 	elsif (not exists $min_version{$pragma}) {
 		croak "Can't enable unknown feature $pragma";
 	}
 	elsif ($min_version{$pragma} > $]) {
 		my $stable = $min_version{$pragma};
 		if ($stable->{version}[1] % 2) {
 			$stable = version->new(
 				"5.".($stable->{version}[1]+1).'.0'
 			);
 		}
 		croak "Need perl $stable or later for feature $pragma";
 	}
 }
 
 sub import {
 	my ($self, @pragmas) = @_;
 
 	for my $pragma (@pragmas) {
 		_enable($pragma);
 	}
 	return;
 }
 
 sub _disable {
 	my $pragma = shift;
 	if ($warnings{"experimental::$pragma"}) {
 		warnings->import("experimental::$pragma");
 		feature->unimport($pragma) if exists $features{$pragma};
 		_disable(@{ $additional{$pragma} }) if $additional{$pragma};
 	}
 	elsif ($features{$pragma}) {
 		feature->unimport($pragma);
 		_disable(@{ $additional{$pragma} }) if $additional{$pragma};
 	}
 	elsif (not exists $min_version{$pragma}) {
 		carp "Can't disable unknown feature $pragma, ignoring";
 	}
 }
 
 sub unimport {
 	my ($self, @pragmas) = @_;
 
 	for my $pragma (@pragmas) {
 		_disable($pragma);
 	}
 	return;
 }
 
 1;
 
 #ABSTRACT: Experimental features made easy
 
 __END__
 
 =pod
 
 =encoding UTF-8
 
 =head1 NAME
 
 experimental - Experimental features made easy
 
 =head1 VERSION
 
 version 0.013
 
 =head1 SYNOPSIS
 
  use experimental 'lexical_subs', 'smartmatch';
  my sub foo { $_[0] ~~ 1 }
 
 =head1 DESCRIPTION
 
 This pragma provides an easy and convenient way to enable or disable
 experimental features.
 
 Every version of perl has some number of features present but considered
 "experimental."  For much of the life of Perl 5, this was only a designation
 found in the documentation.  Starting in Perl v5.10.0, and more aggressively in
 v5.18.0, experimental features were placed behind pragmata used to enable the
 feature and disable associated warnings.
 
 The C<experimental> pragma exists to combine the required incantations into a
 single interface stable across releases of perl.  For every experimental
 feature, this should enable the feature and silence warnings for the enclosing
 lexical scope:
 
   use experimental 'feature-name';
 
 To disable the feature and, if applicable, re-enable any warnings, use:
 
   no experimental 'feature-name';
 
 The supported features, documented further below, are:
 
 	array_base    - allow the use of $[ to change the starting index of @array
 	autoderef     - allow push, each, keys, and other built-ins on references
 	lexical_topic - allow the use of lexical $_ via "my $_"
 	postderef     - allow the use of postfix dereferencing expressions, including
 	                in interpolating strings
 	refaliasing   - allow aliasing via \$x = \$y
 	regex_sets    - allow extended bracketed character classes in regexps
 	signatures    - allow subroutine signatures (for named arguments)
 	smartmatch    - allow the use of ~~
 	switch        - allow the use of ~~, given, and when
 
 =head2 Ordering matters
 
 Using this pragma to 'enable an experimental feature' is another way of saying
 that this pragma will disable the warnings which would result from using that
 feature.  Therefore, the order in which pragmas are applied is important.  In
 particular, you probably want to enable experimental features I<after> you
 enable warnings:
 
   use warnings;
   use experimental 'smartmatch';
 
 You also need to take care with modules that enable warnings for you.  A common
 example being Moose.  In this example, warnings for the 'smartmatch' feature are
 first turned on by the warnings pragma, off by the experimental pragma and back
 on again by the Moose module (fix is to switch the last two lines):
 
   use warnings;
   use experimental 'smartmatch';
   use Moose;
 
 =head2 Disclaimer
 
 Because of the nature of the features it enables, forward compatibility can not
 be guaranteed in any way.
 
 =head1 AUTHOR
 
 Leon Timmermans <leont@cpan.org>
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2013 by Leon Timmermans.
 
 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
### namespace/clean.pm ###
 package namespace::clean;
 
 use warnings;
 use strict;
 
 our $VERSION = '0.26';
 $VERSION = eval $VERSION if $VERSION =~ /_/; # numify for warning-free dev releases
 
 our $STORAGE_VAR = '__NAMESPACE_CLEAN_STORAGE';
 
 use B::Hooks::EndOfScope 'on_scope_end';
 
 # FIXME This is a crock of shit, needs to go away
 # currently here to work around https://rt.cpan.org/Ticket/Display.html?id=74151
 # kill with fire when PS::XS is *finally* fixed
 BEGIN {
   my $provider;
 
   if ( $] < 5.008007 ) {
     require Package::Stash::PP;
     $provider = 'Package::Stash::PP';
   }
   else {
     require Package::Stash;
     $provider = 'Package::Stash';
   }
   eval <<"EOS" or die $@;
 
 sub stash_for (\$) {
   $provider->new(\$_[0]);
 }
 
 1;
 
 EOS
 }
 
 use namespace::clean::_Util qw( DEBUGGER_NEEDS_CV_RENAME DEBUGGER_NEEDS_CV_PIVOT );
 
 # Built-in debugger CV-retrieval fixups necessary before perl 5.15.5:
 # since we are deleting the glob where the subroutine was originally
 # defined, the assumptions below no longer hold.
 #
 # In 5.8.9 ~ 5.13.5 (inclusive) the debugger assumes that a CV can
 # always be found under sub_fullname($sub)
 # Workaround: use sub naming to properly name the sub hidden in the package's
 # deleted-stash
 #
 # In the rest of the range ( ... ~ 5.8.8 and 5.13.6 ~ 5.15.4 ) the debugger
 # assumes the name of the glob passed to entersub can be used to find the CV
 # Workaround: realias the original glob to the deleted-stash slot
 #
 # Can not tie constants to the current value of $^P directly,
 # as the debugger can be enabled during runtime (kinda dubious)
 #
 
 my $RemoveSubs = sub {
     my $cleanee = shift;
     my $store   = shift;
     my $cleanee_stash = stash_for($cleanee);
     my $deleted_stash;
 
   SYMBOL:
     for my $f (@_) {
 
         # ignore already removed symbols
         next SYMBOL if $store->{exclude}{ $f };
 
         my $sub = $cleanee_stash->get_symbol("&$f")
           or next SYMBOL;
 
         my $need_debugger_fixup =
           ( DEBUGGER_NEEDS_CV_RENAME or DEBUGGER_NEEDS_CV_PIVOT )
             &&
           $^P
             &&
           ref(my $globref = \$cleanee_stash->namespace->{$f}) eq 'GLOB'
             &&
          ( $deleted_stash ||= stash_for("namespace::clean::deleted::$cleanee") )
         ;
 
         # convince the Perl debugger to work
         # see the comment on top
         if ( DEBUGGER_NEEDS_CV_RENAME and $need_debugger_fixup ) {
           #
           # Note - both get_subname and set_subname are only compiled when CV_RENAME
           # is true ( the 5.8.9 ~ 5.12 range ). On other perls this entire block is
           # constant folded away, and so are the definitions in ::_Util
           #
           # Do not be surprised that they are missing without DEBUGGER_NEEDS_CV_RENAME
           #
           namespace::clean::_Util::get_subname( $sub ) eq  ( $cleanee_stash->name . "::$f" )
             and
           $deleted_stash->add_symbol(
             "&$f",
             namespace::clean::_Util::set_subname( $deleted_stash->name . "::$f", $sub ),
           );
         }
         elsif ( DEBUGGER_NEEDS_CV_PIVOT and $need_debugger_fixup ) {
           $deleted_stash->add_symbol("&$f", $sub);
         }
 
         my @symbols = map {
             my $name = $_ . $f;
             my $def = $cleanee_stash->get_symbol($name);
             defined($def) ? [$name, $def] : ()
         } '$', '@', '%', '';
 
         $cleanee_stash->remove_glob($f);
 
         # if this perl needs no renaming trick we need to
         # rename the original glob after the fact
         DEBUGGER_NEEDS_CV_PIVOT
           and
         $need_debugger_fixup
           and
         *$globref = $deleted_stash->namespace->{$f};
 
         $cleanee_stash->add_symbol(@$_) for @symbols;
     }
 };
 
 sub clean_subroutines {
     my ($nc, $cleanee, @subs) = @_;
     $RemoveSubs->($cleanee, {}, @subs);
 }
 
 sub import {
     my ($pragma, @args) = @_;
 
     my (%args, $is_explicit);
 
   ARG:
     while (@args) {
 
         if ($args[0] =~ /^\-/) {
             my $key = shift @args;
             my $value = shift @args;
             $args{ $key } = $value;
         }
         else {
             $is_explicit++;
             last ARG;
         }
     }
 
     my $cleanee = exists $args{ -cleanee } ? $args{ -cleanee } : scalar caller;
     if ($is_explicit) {
         on_scope_end {
             $RemoveSubs->($cleanee, {}, @args);
         };
     }
     else {
 
         # calling class, all current functions and our storage
         my $functions = $pragma->get_functions($cleanee);
         my $store     = $pragma->get_class_store($cleanee);
         my $stash     = stash_for($cleanee);
 
         # except parameter can be array ref or single value
         my %except = map {( $_ => 1 )} (
             $args{ -except }
             ? ( ref $args{ -except } eq 'ARRAY' ? @{ $args{ -except } } : $args{ -except } )
             : ()
         );
 
         # register symbols for removal, if they have a CODE entry
         for my $f (keys %$functions) {
             next if     $except{ $f };
             next unless $stash->has_symbol("&$f");
             $store->{remove}{ $f } = 1;
         }
 
         # register EOF handler on first call to import
         unless ($store->{handler_is_installed}) {
             on_scope_end {
                 $RemoveSubs->($cleanee, $store, keys %{ $store->{remove} });
             };
             $store->{handler_is_installed} = 1;
         }
 
         return 1;
     }
 }
 
 sub unimport {
     my ($pragma, %args) = @_;
 
     # the calling class, the current functions and our storage
     my $cleanee   = exists $args{ -cleanee } ? $args{ -cleanee } : scalar caller;
     my $functions = $pragma->get_functions($cleanee);
     my $store     = $pragma->get_class_store($cleanee);
 
     # register all unknown previous functions as excluded
     for my $f (keys %$functions) {
         next if $store->{remove}{ $f }
              or $store->{exclude}{ $f };
         $store->{exclude}{ $f } = 1;
     }
 
     return 1;
 }
 
 sub get_class_store {
     my ($pragma, $class) = @_;
     my $stash = stash_for($class);
     my $var = "%$STORAGE_VAR";
     $stash->add_symbol($var, {})
         unless $stash->has_symbol($var);
     return $stash->get_symbol($var);
 }
 
 sub get_functions {
     my ($pragma, $class) = @_;
 
     my $stash = stash_for($class);
     return {
         map { $_ => $stash->get_symbol("&$_") }
             $stash->list_all_symbols('CODE')
     };
 }
 
 'Danger! Laws of Thermodynamics may not apply.'
 
 __END__
 
 =head1 NAME
 
 namespace::clean - Keep imports and functions out of your namespace
 
 =head1 SYNOPSIS
 
   package Foo;
   use warnings;
   use strict;
 
   use Carp qw(croak);   # 'croak' will be removed
 
   sub bar { 23 }        # 'bar' will be removed
 
   # remove all previously defined functions
   use namespace::clean;
 
   sub baz { bar() }     # 'baz' still defined, 'bar' still bound
 
   # begin to collection function names from here again
   no namespace::clean;
 
   sub quux { baz() }    # 'quux' will be removed
 
   # remove all functions defined after the 'no' unimport
   use namespace::clean;
 
   # Will print: 'No', 'No', 'Yes' and 'No'
   print +(__PACKAGE__->can('croak') ? 'Yes' : 'No'), "\n";
   print +(__PACKAGE__->can('bar')   ? 'Yes' : 'No'), "\n";
   print +(__PACKAGE__->can('baz')   ? 'Yes' : 'No'), "\n";
   print +(__PACKAGE__->can('quux')  ? 'Yes' : 'No'), "\n";
 
   1;
 
 =head1 DESCRIPTION
 
 =head2 Keeping packages clean
 
 When you define a function, or import one, into a Perl package, it will
 naturally also be available as a method. This does not per se cause
 problems, but it can complicate subclassing and, for example, plugin
 classes that are included via multiple inheritance by loading them as
 base classes.
 
 The C<namespace::clean> pragma will remove all previously declared or
 imported symbols at the end of the current package's compile cycle.
 Functions called in the package itself will still be bound by their
 name, but they won't show up as methods on your class or instances.
 
 By unimporting via C<no> you can tell C<namespace::clean> to start
 collecting functions for the next C<use namespace::clean;> specification.
 
 You can use the C<-except> flag to tell C<namespace::clean> that you
 don't want it to remove a certain function or method. A common use would
 be a module exporting an C<import> method along with some functions:
 
   use ModuleExportingImport;
   use namespace::clean -except => [qw( import )];
 
 If you just want to C<-except> a single sub, you can pass it directly.
 For more than one value you have to use an array reference.
 
 =head3 Late binding caveat
 
 Note that the L<technique used by this module|/IMPLEMENTATION DETAILS> relies
 on perl having resolved all names to actual code references during the
 compilation of a scope. While this is almost always what the interpreter does,
 there are some exceptions, notably the L<sort SUBNAME|perlfunc/sort> style of
 the C<sort> built-in invocation. The following example will not work, because
 C<sort> does not try to resolve the function name to an actual code reference
 until B<runtime>.
 
  use MyApp::Utils 'my_sorter';
  use namespace::clean;
 
  my @sorted = sort my_sorter @list;
 
 You need to work around this by forcing a compile-time resolution like so:
 
  use MyApp::Utils 'sorter';
  use namespace::clean;
 
  my $my_sorter_cref = \&sorter;
 
  my @sorted = sort $my_sorter_cref @list;
 
 =head2 Explicitly removing functions when your scope is compiled
 
 It is also possible to explicitly tell C<namespace::clean> what packages
 to remove when the surrounding scope has finished compiling. Here is an
 example:
 
   package Foo;
   use strict;
 
   # blessed NOT available
 
   sub my_class {
       use Scalar::Util qw( blessed );
       use namespace::clean qw( blessed );
 
       # blessed available
       return blessed shift;
   }
 
   # blessed NOT available
 
 =head2 Moose
 
 When using C<namespace::clean> together with L<Moose> you want to keep
 the installed C<meta> method. So your classes should look like:
 
   package Foo;
   use Moose;
   use namespace::clean -except => 'meta';
   ...
 
 Same goes for L<Moose::Role>.
 
 =head2 Cleaning other packages
 
 You can tell C<namespace::clean> that you want to clean up another package
 instead of the one importing. To do this you have to pass in the C<-cleanee>
 option like this:
 
   package My::MooseX::namespace::clean;
   use strict;
 
   use namespace::clean (); # no cleanup, just load
 
   sub import {
       namespace::clean->import(
         -cleanee => scalar(caller),
         -except  => 'meta',
       );
   }
 
 If you don't care about C<namespace::clean>s discover-and-C<-except> logic, and
 just want to remove subroutines, try L</clean_subroutines>.
 
 =head1 METHODS
 
 =head2 clean_subroutines
 
 This exposes the actual subroutine-removal logic.
 
   namespace::clean->clean_subroutines($cleanee, qw( subA subB ));
 
 will remove C<subA> and C<subB> from C<$cleanee>. Note that this will remove the
 subroutines B<immediately> and not wait for scope end. If you want to have this
 effect at a specific time (e.g. C<namespace::clean> acts on scope compile end)
 it is your responsibility to make sure it runs at that time.
 
 =head2 import
 
 Makes a snapshot of the current defined functions and installs a
 L<B::Hooks::EndOfScope> hook in the current scope to invoke the cleanups.
 
 
 =head2 unimport
 
 This method will be called when you do a
 
   no namespace::clean;
 
 It will start a new section of code that defines functions to clean up.
 
 =head2 get_class_store
 
 This returns a reference to a hash in a passed package containing
 information about function names included and excluded from removal.
 
 =head2 get_functions
 
 Takes a class as argument and returns all currently defined functions
 in it as a hash reference with the function name as key and a typeglob
 reference to the symbol as value.
 
 =head1 IMPLEMENTATION DETAILS
 
 This module works through the effect that a
 
   delete $SomePackage::{foo};
 
 will remove the C<foo> symbol from C<$SomePackage> for run time lookups
 (e.g., method calls) but will leave the entry alive to be called by
 already resolved names in the package itself. C<namespace::clean> will
 restore and therefor in effect keep all glob slots that aren't C<CODE>.
 
 A test file has been added to the perl core to ensure that this behaviour
 will be stable in future releases.
 
 Just for completeness sake, if you want to remove the symbol completely,
 use C<undef> instead.
 
 =head1 SEE ALSO
 
 L<B::Hooks::EndOfScope>
 
 =head1 THANKS
 
 Many thanks to Matt S Trout for the inspiration on the whole idea.
 
 =head1 AUTHORS
 
 =over
 
 =item *
 
 Robert 'phaylon' Sedlacek <rs@474.at>
 
 =item *
 
 Florian Ragwitz <rafl@debian.org>
 
 =item *
 
 Jesse Luehrs <doy@tozt.net>
 
 =item *
 
 Peter Rabbitson <ribasushi@cpan.org>
 
 =item *
 
 Father Chrysostomos <sprout@cpan.org>
 
 =back
 
 =head1 COPYRIGHT AND LICENSE
 
 This software is copyright (c) 2011 by L</AUTHORS>
 
 This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.
### oo.pm ###
 package oo;
 
 use Moo::_strictures;
 use Moo::_Utils;
 
 sub moo {
   print <<'EOMOO';
  ______
 < Moo! >
  ------
         \   ^__^
          \  (oo)\_______
             (__)\       )\/\
                 ||----w |
                 ||     ||
 EOMOO
   exit 0;
 }
 
 BEGIN {
     my $package;
     sub import {
         moo() if $0 eq '-';
         $package = $_[1] || 'Class';
         if ($package =~ /^\+/) {
             $package =~ s/^\+//;
             _load_module($package);
         }
     }
     use Filter::Simple sub { s/^/package $package;\nuse Moo;\n/; }
 }
 
 1;
 __END__
 
 =head1 NAME
 
 oo - syntactic sugar for Moo oneliners
 
 =head1 SYNOPSIS
 
   perl -Moo=Foo -e 'has bar => ( is => q[ro], default => q[baz] ); print Foo->new->bar'
 
   # loads an existing class and re-"opens" the package definition
   perl -Moo=+My::Class -e 'print __PACKAGE__->new->bar'
 
 =head1 DESCRIPTION
 
 oo.pm is a simple source filter that adds C<package $name; use Moo;> to the
 beginning of your script, intended for use on the command line via the -M
 option.
 
 =head1 SUPPORT
 
 See L<Moo> for support and contact information.
 
 =head1 AUTHORS
 
 See L<Moo> for authors.
 
 =head1 COPYRIGHT AND LICENSE
 
 See L<Moo> for the copyright and license.
 
 =cut
